Min, max of enum

Biotronic via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Jan 26 00:27:00 PST 2017


On Thursday, 26 January 2017 at 05:58:26 UTC, Profile Anaysis 
wrote:
> Since we do not have attributes for enums, I use _ in front of 
> the names for meta values.
>
> I need to get the non-meta values for the enum so I can iterate 
> over it and use it properly.
>
> enum myEnum
> {
>     _Meta1 = 0,
>     A,B,C,
>     _Meta3 = 43,
>     D = 3,
> }
>
> The num, for all practical purposes does not contain _Meta1, 
> and_Meta3. But in code I use to!myEnum(intI) and having the 
> meta values complicate things(simple shifting may or may not 
> work).
>
> I also need to create array indexers based on myEnum that don't 
> include the meta characters.
>
> What I do a lot is convert integers in to fields of the enum.
>
> If I do not include any Meta, then it is straight forward 
> to!myEnum(i), but with them it is not, so doing things like
>
> int[myEnum] x;
>
> x[to!myEnum(i))] is difficult because the conversion will be 
> invalid for meta. I'd have to do some work on i to get the 0-n 
> representation to map properly in to the enum... basically 
> avoiding the meta fields.
>
> This would all be solved with attributes for enums, but that, I 
> suppose is a pipe dream.
>
> Any ideas how I can make this easy?

Like Stefan said, __traits(allMembers, myEnum) lets you iterate 
over the elements of the enum. For a to!myEnum that ignores _Meta 
fields, you could do something like this:

T toEnum(T)(int n) {
     foreach (element; __traits(allMembers, myEnum)) {
         static if (element[0] != '_') {
             if (n == cast(int)__traits(getMember, myEnum, 
element))
                 return __traits(getMember, myEnum, element);
         }
     }
     assert(false);
}

Looking at your code though, I wonder if the problem you want 
solved is a different one. Especially this part:

> I'd have to do some work on i to get the 0-n representation to 
> map properly in to the enum... basically avoiding the meta 
> fields.

If I understand you correctly, you want this:

enum myEnum
{
     _Meta1 = 0,
     A,B,C,
     _Meta3 = 43,
     D = 3,
}

to become this:

enum myEnum
{
     A = 0,
     B = 1,
     C = 2,
     D = 3
}

That's a taller order, especially given that the original is 
equivalent to this:

enum myEnum
{
     A = 1,
     B = 2,
     C = 3,
     D = 3
     // And some meta members, but not relevant here.
}

One option would look somewhat like this:

alias myEnum = Enum!q{
     _Meta1 = 0,
     A, B, C,
     _Meta2 = 43,
     D
};

template Enum(string enumBody) {
     mixin(generateEnum!enumBody);
}

string generateEnum(string enumBody)() {
     import std.conv;
     string result;
     mixin("enum members {"~enumBody~"}");

     foreach (element; __traits(allMembers, members)) {
         if (element[0] != '_') {
             result ~= element ~ ",";
         }
     }

     return "@MetaData!\""~enumBody~"\" enum Enum {"~result~"}";
}

template MetaData(string enumBody) {
     mixin(generateMeta!enumBody);
}

string generateMeta(string enumBody)() {
     import std.conv;
     string result;
     mixin("enum members {"~enumBody~"}");

     foreach (element; __traits(allMembers, members)) {
         if (element[0] == '_') {
             result ~= element ~ " = " ~ 
(cast(int)__traits(getMember, members, element)).to!string ~ ",";
         }
     }

     return "enum MetaData {"~result~"}";
}



template meta(T) if (is(T == enum)) {
     import std.typetuple;
     alias meta = AliasSeq!(__traits(getAttributes, T))[0];
}

void main() {
     import std.stdio;
     import std.conv;
     import std.typetuple;

     writeln(myEnum.A, ": ", cast(int)myEnum.A);
     writeln(myEnum.B, ": ", cast(int)myEnum.B);
     writeln(myEnum.C, ": ", cast(int)myEnum.C);
     writeln(myEnum.D, ": ", cast(int)myEnum.D);

     writeln(meta!myEnum._Meta1, ":", cast(int)meta!myEnum._Meta1);
     writeln(meta!myEnum._Meta2, ":", cast(int)meta!myEnum._Meta2);
}

This lets you define the enum with a somewhat familiar syntax:

alias myEnum = Enum!q{
     _Meta1 = 0,
     A, B, C,
     _Meta2 = 43,
     D
};

and generates from that the equivalent of this:

@myEnum_Meta
enum myEnum {
     A, B, C, D
}

enum myEnum_Meta {
     _Meta1 = 0,
     _Meta2 = 43
}




More information about the Digitalmars-d-learn mailing list