September 29

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.