Compile time evaluation
If I write
enum chars = digits ~ uppercase;
will the string be concatenated at compile time? I'm assuming it will. If I replace it with a string literal or a CTFE function I can't measure any significant performance differences (even calling it a hundred million times). I do get a difference if I replace enum with const. I've been told it's inefficient to write it like this. I thought it was kind of convenient and I don't see the inefficiency. (BTW, the line is in a function that's called recursively).
The full code (converting to a numeral system with a different base)
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];
}
Edit: updated code, in response to comments, not relevant to the question
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;
}
enum
instantiations like that are always evaluated at compile-time (and throw compile errors when the evaluation is impossible at compile time)
so the concatenation is done at compile-time and an immutable version is stored in the code and referenced at runtime
One way to check for yourself whether the string is concatenated at compile time is to compile the code and examine the object file. Assuming your file is called test.d
:
dmd -c test.d
objdump test.o | grep -C3 "012345"
...should produce something like:
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 $....... .......
(This is on Linux; on other platforms, you'll need different tools to inspect the object file.)
If you change your enum
to const
or string
, you will (probably) get no output: there will be no concatenated string for grep
to find.
But the compiler may concatenate strings at compile-time even when enum
is not used. Consider this program:
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);
}
Now, compile it, and examine the object file:
% 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........
We see that x
, y
and z
are all static literals. (Mark a
, b
and c
as const
instead of enum
, and you may see different behaviour.) So, while enum
is a guarantee of compile-time evaluation, the absence of enum
doesn't prevent compile-time evaluation.
精彩评论