Thread overview
Min, max of enum
Jan 26, 2017
Profile Anaysis
Jan 26, 2017
Stefan Koch
Jan 26, 2017
Biotronic
January 26, 2017
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?




January 26, 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.
>
> [...]

This can be done with Ctfe mixins and __traits,

look at __traits(allMembers)
January 26, 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
}