On 23.08.21 08:14, Brian Tiffin wrote:
From ~~a~~ little reading, it seems associative array literal
initialization is still pending for global scope, but allowed in a
module constructor? *If I understood the skimming surface reading so far*.
```d
immutable string[string] things;
static (this) {
things = ["key1": "value 1", "key2": "value 2"];
}
```
(Typo: It's `static this()`.)
Is there a magic incantation that could convert the values to a
`std.zlib.compress`ed ubyte array, at compile time? So the object code
gets keys:compvals instead of the full string value?
There's a big roadblock: std.zlib.compress cannot go through CTFE,
because the source code of zlib isn't available to the compiler; it's
not even D code.
Maybe there's a CTFE-able compression library on dub. If not, you can
write your own function and run that through CTFE. Example with simple
run-length encoding:
----
uint[] my_compress(string s)
{
import std.algorithm: group;
import std.string: representation;
uint[] compressed;
foreach (c_n; group(s.representation))
{
compressed ~= [c_n[0], c_n[1]];
}
return compressed;
}
string my_uncompress(const(uint)[] compressed)
{
import std.conv: to;
string uncompressed = "";
for (; compressed.length >= 2; compressed = compressed[2 .. $])
{
foreach (i; 0 .. compressed[1])
{
uncompressed ~= compressed[0].to!char;
}
}
return uncompressed;
}
import std.array: replicate;
/* CTFE compression: */
enum compressed = my_compress("f" ~ "o".replicate(100_000) ~ "bar");
immutable string[string] things;
shared static this()
{
/* Runtime decompression: */
things = ["key1": my_uncompress(compressed)];
}
----
If you compile that, the object file should be far smaller than 100,000
bytes, thanks to the compression.
[...]
I'm not sure about
a) if code in a module constructor is even a candidate for CTFE?
The word "candidate" might indicate a common misunderstanding of CTFE.
CTFE doesn't look for candidates. It's not an optimization. The language
dictates which values go through CTFE.
In a way, static constructors are the opposite of CTFE. Initializers in
module scope do go through CTFE. When you have code that you cannot (or
don't want to) put through CTFE, you put it in a static constructor.
You can still trigger CTFE within a static constructor by other means
(e.g., `enum`), but the static constructor itself is just another
function as far as CTFE is concerned.
b) what a cast might look like to get a `q"DELIM ... DELIM"` delimited
string for use as input to std.zlib.compress?
A cast to get a string literal? That doesn't make sense.
You might be looking for `import("some_file")`. That gives you the
contents of a file as a string. You can then run that string through
your compression function in CTFE, put the resulting compressed data
into the object file, and decompress it at runtime (like the example
above does).