Merhaba,
>void example.loop1(): 203 - 127 = 76 satır
void example.loop2(): 237 - 203 = 34 satır
void example.loop3(): 285 - 237 = 48 satır
void example.loop4(): 330 - 285 = 45 satır
void example.loop5(): 386 - 330 = 56 satır
GodBolt bağlantısına bakılırsa DMD'nin çok az sayıda (binden az) satır assembly kodu ürettiği sonucu çıkıyor. Bunun sebebi belki de LDC'nin (2 bini aşkın satır!) gereksiz label&jump oluşturması. Örneğin loop1'de sadece 2 tane olan D'nin kendi etiketlemesini (D label statement) kullandığımızda ekstradan en az 5 tane daha oluşturuyor. Oysa tün döngü iki etiket (.LBB0_1 <- .LBB0_7) arasında gerçekleşiyor. Aradaki if/else için de etiket, jmp komutunun yazıldığı satırlar için bile başka etiketler...
Özetle bu testte, hem GDC (neredeyse 2 bin satır) hem de LDC'nin ürettiği sonuçlar kullanılmadı. Döngünün ürettiği sonucu doğrudan diziye yazdığı ve dizi üzerinde gezindiği için testin galibi foreach döngüsü (loop2), sonra while döngüsü (loop4x) geliyor.
Aslında test şartlarının tüm işlevler için eşit olması için global bir n dizisi kullanıldı ve ekrana yazmaktan kaçınıldı. Aynı sonucu veremediği için loop4x tasnif dışıdır, belki loop2 de öyle olabilir. Çünkü zaten o sırada dizide geziniyorken içeriğini değiştirmesi kolay olacaktır! 😀
Neyse, zaten temelde tek başına while ile do/while aynı şeylerdir. Ama bazı durumlar için ötekini diğerine tercih ederiz. Ancak testin 2. galibinin bir eksiği var: O da işaretli sayılarda çalışamaması. Çünkü kısa olması için döngüyü devam ettiren pozitiflik (0'dan büyük olma == true) kavramından yararlanıldı. Yani bir int dizimiz olsaydı ve döngüler eksili bir sayıdan başlasaydı for döngüsü kullanmak zorundaydık.
56 satır ile switch/case (loop5) bile tasnif dışı bırakılabilir çünkü loop1'deki gibi ekstra etiket kullanıldı. Yani bunlar (loop1 ve loop5) temelde bir döngü olmasalar da tekrar eden durumlarda yararlanılabilecek çok akıllı olanaklar. Zaten çoğu durumda assembly kodları yine cmp'ler ile dolu. Yani siz if de kullansanız switch/case de, kodu güzel ve kısa gösterme dışında assembly karşılıkları benzer. Üstelik etiket kullanarak birşeyler yapıyorsanız örneğin bir LDC'nin her şeyi başka etiketlerle ayırmasından dolayı gereksiz assembly kodu oluşuyor. Makine koduna çevirirken bu etiketler sadeleşiyor mu? İşte onu bilmiyorum...
// D Compiler v2.094.2
import std.stdio;
enum limit = 10;
uint[limit] n; // test array
void reset() {
assert(n == [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);/*
n.writeln; //*/
n = 0;
n[0] = 1;
assert(n == [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
"-ok-".writeln;
}
void main()
{
loop1(); // no prints
reset(); // ASMcode: 76 lines
loop2(); // foreach_reverse () { .. }
reset(); // ASMcode: 34 lines
loop3(); // for () { .. }
reset(); // ASMcode: 48 lines
loop4(); // do { .. } while();
reset(); // ASMcode: 45 lines
loop5(); // switch () { .. }
reset(); // ASMcode: 56 lines
loop4x(); // while () { .. }
}
void loop1()
{
increment:
n[0]++; // n = 1;
if(n[0] < limit) {
n[limit - n[0]] = n[0];
} else
goto print;
goto increment;
print:
assert(n == [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
__FUNCTION__.write(": ");
} // only 5 lines
void loop2()
{
foreach_reverse (ref i; n) {
i = n[0]++;
}
__FUNCTION__.write(": ");
} // only 3 lines
void loop3()
{
for (; n[0] < limit; ++n[0]) {
n[limit - n[0]] = n[0];
}
__FUNCTION__.write(": ");
} // only 3 lines
void loop4()
{
do {
n[limit - n[0]] = n[0];
} while (++n[0] < limit);
__FUNCTION__.write(": ");
} // only 3 lines
void loop5()
{
outterloop: switch (n[0]) {
case limit:
break;
default:
n[limit - n[0]] = n[0]++;
goto outterloop;
}
__FUNCTION__.write(": ");
} // only 5 lines
void loop4x()
{
while (++n[0] < 10) {
n[limit - n[0]] = n[0];
} // [ 10, 9, 8, 7, 6, 5, 4, 3, 2, 0 ]
__FUNCTION__.write(": ");
} // only 3 lines but wrong result
/* loop5test.d (10 July'22)
* Programmer: SDB@79
* Links: https://d.godbolt.org/z/no5xq7ohT
*/
Başarılar...