Оценка времени компиляции - PullRequest
12 голосов
/ 03 июля 2011

Если я напишу

enum chars = digits ~ uppercase;

будет ли строка конкатенирована во время компиляции? Я предполагаю, что это будет. Если я заменю его строковым литералом или функцией CTFE, я не смогу измерить каких-либо существенных различий в производительности (даже вызывая это сто миллионов раз). Я получаю разницу, если я заменяю enum на const. Мне сказали, что неэффективно так писать. Я думал, что это было удобно, и я не вижу неэффективности. (Кстати, строка находится в функции, которая вызывается рекурсивно).

Полный код (преобразование в систему счисления с другой базой)

import std.string;

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    static string sign;
    if (n < 0) {
        n *= -1;
        sign = "-";
    }
    enum chars = digits ~ uppercase;
    size_t r = cast(size_t)(n % b);
    if (n == r) {
        return sign ~ chars[r];
    }
    return toBase((n - r) / b, b) ~ chars[r];
}

Редактировать: обновленный код, в ответ на комментарии, не относящиеся к вопросу

string toBase(long n, int b) 
in {
    assert(2 <= b && b <= 35);
} body {
    enum chars = digits ~ uppercase;
    long r = n % b;
    char c = chars[cast(size_t) abs(r)];
    if (n == r) {
        return (n < 0 ? "-" : "") ~ c;
    }
    return toBase((n - r) / b, b) ~ c;
}

Ответы [ 2 ]

9 голосов
/ 03 июля 2011

enum подобные экземпляры всегда оцениваются во время компиляции (и генерируют ошибки компиляции, когда оценка невозможна во время компиляции)

, поэтому конкатенация выполняется при компиляциивремя и неизменная версия хранятся в коде и ссылаются во время выполнения

5 голосов
/ 16 июля 2011

Один из способов проверить, соединена ли строка во время компиляции, - это скомпилировать код и проверить объектный файл.Предполагая, что ваш файл называется test.d:

dmd -c test.d
objdump test.o | grep -C3 "012345"

... должен выдать что-то вроде:

Contents of section .rodata:
 0000 2d000000 00000000 00000000 00000000  -...............
 0010 01000000 00000000 00000000 00000000  ................
 0020 30313233 34353637 38394142 43444546  0123456789ABCDEF
 0030 4748494a 4b4c4d4e 4f505152 53545556  GHIJKLMNOPQRSTUV
 0040 5758595a 00000000 00000000 00000000  WXYZ............
 0050 24000000 00000000 20000000 00000000  $....... .......

(Это в Linux; на других платформах вам понадобятся разныеинструменты для проверки объектного файла.)

Если вы измените свой enum на const или string, вы (вероятно) не получите никакого вывода: не будет никакой сцепленной строки для grep дляfind.

Но компилятор может объединять строки во время компиляции, даже если enum не используется.Рассмотрим следующую программу:

 import std.stdio;

 enum a = "Aaaa";
 enum b = "Bbbb";
 enum c = "Cccc";

 void main() 
 {
   enum   x = a ~ b;
   const  y = b ~ a;
   string z = a ~ c;
   writeln(x, y, z);
 }

Теперь скомпилируйте ее и проверьте файл объекта:

% dmd -c test2.d && objdump -s test2.o | egrep "(Aaaa|Bbbb)"
 0000 42626262 41616161 00000000 00000000  BbbbAaaa........
 0020 41616161 43636363 00000000 00000000  AaaaCccc........
 0040 41616161 42626262 00000000 00000000  AaaaBbbb........

Мы видим, что x, y и z все статическиелитералы.(Отметьте a, b и c как const вместо enum, и вы можете увидеть другое поведение.) Таким образом, хотя enum является гарантией оценки во время компиляции, отсутствие enum не мешает оценке во время компиляции.

...