October 28

Just something I realized, when I was coding something.

struct ReservedBit {
}
struct ReservedBits {
  int width;
}
struct Bit {
  string name;
}
struct Bits {
  int width;
  string name;
}


string genWrapped(Fields...)() {
  static if (Fields.length == 0) {
    return "struct Wrapped { ubyte v; }";
  }
  string ret = "struct Wrapped {\n";
  int bit_offset = 0;
  static foreach (Field; Fields) {
    static if (is(typeof(Field) : Bit) || is(typeof(Field) : ReservedBit)) {
      bit_offset += 1;
    } else static if (is(typeof(Field) : Bits) || is(typeof(Field) : ReservedBits)) {
      bit_offset += Field.width;
    } else {
      static assert(false);
    }
  }
  // ...
  return ret ~ "}\n";
}

mixin(genWrapped!(Bit("x"), ReservedBits(2), Bits(3, "y"), ReservedBits(2))());

Hmm. Wouldn't it be nice to be able to do this (or something similar) instead?

string genWrapped(Fields...)() {
  static if (Fields.length == 0) {
    return "struct Wrapped { ubyte v; }";
  }
  string ret = "struct Wrapped {\n";
  int bit_offset = 0;
  static foreach (Field; Fields) {
    static /*final*/ switch {
      case is(typeof(Field) : Bit):
      case is(typeof(Field) : ReservedBit):
        bit_offset += 1;
        /*static?*/ break;
      case is(typeof(Field) : Bits))):
      case is(typeof(Field) : ReservedBits):
        bit_offset += Field.width;
        /*static?*/ break;
      // default: static assert(false);
    }
  }
  // ...
  return ret ~ "}\n";
}

And using template specialization pattern matching in the is expression, it should be available in the specific case "branch" too.

I know I could have just passed these struct values by value as arguments, to the CTFE string builder, but sometimes you want to pass as types (when using some alias template arguments for example).