Using Enums to Generate Scoped List of Names

Andrey Zherikov andrey.zherikov at gmail.com
Wed Aug 3 15:49:25 UTC 2022


I was looking at Walter's ["Strawberries and Cream" 
presentation](https://github.com/dlang/dconf.org/blob/master/2022/online/slides/strawberries.pdf) 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:
```d
     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:
```d
     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 }`


More information about the Digitalmars-d mailing list