www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Using Enums to Generate Scoped List of Names

reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
I was looking at Walter's ["Strawberries and Cream" 
presentation](https://github.com/dlang/dconf.org/blob/master/2022/online/slid
s/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 }`
Aug 03 2022
next sibling parent reply Dennis <dkorpel gmail.com> writes:
On Wednesday, 3 August 2022 at 15:49:25 UTC, Andrey Zherikov 
wrote:
 why do you need to generate code using string mixins if this 
 can be done in more readable way (IMHO).
In DMD, the generated getters/setters are `extern(C++)` so LDC and GDC can access them from C++. This doesn't work with opDispatch.
Aug 04 2022
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Thursday, 4 August 2022 at 14:45:26 UTC, Dennis wrote:
 In DMD, the generated getters/setters are `extern(C++)` so LDC 
 and GDC can access them from C++. This doesn't work with 
 opDispatch.
Will this work? It minimizes string mixins usage an has no `opDispatch`: ```d static struct S(E, T) { private T flags; private template Impl(T mask) { pure nothrow nogc safe final { bool Impl(bool v) { v ? (flags |= mask) : (flags &= ~mask); return v; } bool Impl() const scope { return !!(flags & mask); } } } static foreach (mem; __traits(allMembers, E)) mixin("alias "~mem~" = Impl!(1 << E."~mem~");"); } enum F { square,circle=5,triangle=7 } 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); ```
Aug 04 2022
parent Dennis <dkorpel gmail.com> writes:
On Thursday, 4 August 2022 at 23:31:37 UTC, Andrey Zherikov wrote:
 Will this work? It minimizes string mixins usage an has no 
 `opDispatch`:
Sorry for the late reply. I don't think it generates the right extern(C++) symbols for DMD, but I like the solution in general. Minimizing string mixins is good.
Aug 16 2022
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/3/2022 8:49 AM, Andrey Zherikov wrote:
 I was looking at Walter's ["Strawberries and Cream" 
 presentation](https://github.com/dlang/dconf.org/blob/master/2022/online/slid
s/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:
Haha, this is a nice improvement! Nobody can think of everything, which is why these forums are worth while!
Aug 16 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/16/22 08:07, Walter Bright wrote:

 Haha, this is a nice improvement! Nobody can think of everything, which 
 is why these forums are worth while!
And your array-at-compile-time example can subjectively be better like this: import std; void main() { pragma(msg, iota(20).map!(n => n * n).array); } Ali
Aug 16 2022
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/16/2022 8:34 AM, Ali Çehreli wrote:
 And your array-at-compile-time example can subjectively be better like this:
 
 import std;
 
 void main() {
    pragma(msg, iota(20).map!(n => n * n).array);
 }
True, but my example was a slide-friendly version of a much more complex piece of real life code.
Aug 16 2022
prev sibling parent Salih Dincer <salihdb hotmail.com> writes:
On Tuesday, 16 August 2022 at 15:34:30 UTC, Ali Çehreli wrote:
 On 8/16/22 08:07, Walter Bright wrote:
 And your array-at-compile-time example can subjectively be 
 better like this:
```d
 import std;

 void main() {
   pragma(msg, iota(20).map!(n => n * n).array);
 }
```
Generates different types if not specifically specified. Because Walter initialized a static array. Although your example runs with #pragma , it creates a dynamic array: ```d import std.stdio; enum N = 10; void main() { int[N] squares_A = () { int[N] squares; foreach (i; 0 .. N) squares[i] = i * i; return squares; }(); squares_A.writeln(": ", typeid(squares_A)); import std.algorithm, std.range; //pragma(msg, iota(20).map!(n => n * n).array);/* auto squares_B = iota(N).map!(n => n * n).array; squares_B ~= 100; squares_B.writeln(": ", typeid(squares_B));//*/ /* [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]: int[10] * [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]: int[] */ } ``` Also, squares_A doesn't get any help from any modules. SDB 79
Aug 20 2022