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 }
Permalink
Reply