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).

Reply via email to