I was looking at Walter's "Strawberries and Cream" presentation this morning and "Using Enums to Generate Scoped List of Names" section caught me with bad feeling: why do you need to generate code using string mixins if this can be done in more readable way (IMHO). So I played with it a bit and here is my solution:
static struct S(E, T)
{
private T flags;
private enum mask(string name) = 1 << __traits(getMember, E, name);
pure nothrow @nogc @safe final {
bool opDispatch(string name)(bool v)
{
v ? (flags |= mask!name) : (flags &= ~mask!name);
return v;
}
bool opDispatch(string name)() const scope
{
return !!(flags & mask!name);
}
}
}
enum F {square,circle,triangle }
S!(F, ubyte) s;
assert(s.square = true);
assert(!(s.circle = false));
assert(s.triangle = true);
assert(s.square);
assert(!s.circle);
assert(s.triangle);
Compare with this from the presentation:
string generateBitFlags(E, T)() {
string result = "pure nothrow @nogc @safe final {";
enum enumName = __traits(identifier, E);
foreach (size_t i, mem; __traits(allMembers, E)) {
static assert(i < T.sizeof * 8, "too many fields”);
enum mask = "(1 << "~i.stringof~")";
result ~= "
bool "~mem~"() const scope { return !!(flags & "~mask~"); }
bool "~mem~"(bool v) {
v ? (flags |= "~mask~") : (flags &= ~"~mask~");
return v;
}";
}
return result ~ "}\n private "~T.stringof~" flags;\n";
}
static struct S
{
mixin(generateFlags!(F, ubyte));
}
enum F { square, circle, triangle }
S s;
s.square = true;
s.circle = false;
s.triangle = true;
assert(s.square == true);
assert(s.circle == false);
assert(s.triangle == true);
My solution can even support sparse bitmasks by simply tuning the enum:
enum F {square, circle=5, triangle=7 }