www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Min, max of enum

reply Profile Anaysis <PA gotacha.com> writes:
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?
Jan 25 2017
next sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
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.

 [...]
This can be done with Ctfe mixins and __traits, look at __traits(allMembers)
Jan 25 2017
prev sibling parent Biotronic <simen.kjaras gmail.com> writes:
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 }
Jan 26 2017