I just discovered quite an interesting technique for writing code that needs to be repeated / interleaved / vectorized.
It uses a clever recursive mixin, where first mixin generating function receives a string, that is to be used as interpolation sequence inside that function, and then interpolates it (and constructs that interpolation sequence string using interpolation string - that part is optional tho).
It is handy.
@attribute("flatten")
KV*[4] GetWithHash4(const ref K k0, H hash0, const ref K k1, H hash1, const ref K k2, H hash2, const ref K k3, H hash3) {
static enum N = 4;
KV*[4] ret;
static string repeat_i(string pattern)() {
string ret;
import std.conv : to, text;
foreach (i_; 0 .. N) {
const string i = i_.to!string;
ret ~= mixin(i"i\"$(pattern)\"".text).text;
// ret ~= mixin(i"i\"$(pattern)\".text".text); // also works.
}
return ret;
}
mixin(repeat_i!"bool r$(i)_search = true;");
ulong todo_count = N;
mixin(repeat_i!"auto slot_idx$(i) = hash$(i) % slots.length;");
while (todo_count != 0) {
mixin(repeat_i!"Slot* slot$(i) = &slots[slot_idx$(i)];");
asm { "" ::: "memory"; };
mixin(repeat_i!"auto slot$(i)_hash = slot$(i).hash_;");
asm { "" ::: "memory"; };
mixin(repeat_i!q{
if (r$(i)_search) {
if (slot$(i)_hash == hash$(i)) {
if (slot$(i).kv.k == k$(i)) {
ret[$(i)] = &slot$(i).kv;
r$(i)_search = false;
todo_count--;
}
} else if (slot$(i)_hash == EMPTY) {
r$(i)_search = false;
todo_count--;
} else {
slot_idx$(i) = (slot_idx$(i) + 1) % slots.length;
}
}
});
}
return ret;
}
The interleaving technique here, I call software threading (similar to hyper-threading / SMT on CPUs, running multiple context in parallel). I used it in the past using C macros, maybe 10 years ago, for similar effect. But in D, it actually is nicer to achieve.
Purposes of the code above are not that important, but I thought it might be interesting sharing the double mixin with double interpolation technique for building code, without a need for extra functions. And quite compact and readable code.
The iteration over integers / string here is trivial to extend to other options, like arrays, for other code generation purposes.