Thread overview
Compile time mapping
May 11, 2019
Bogdan
May 11, 2019
Adam D. Ruppe
May 12, 2019
Patrick Schluter
May 12, 2019
Bastiaan Veelo
May 12, 2019
Bastiaan Veelo
May 12, 2019
Bogdan
May 12, 2019
Bastiaan Veelo
May 11, 2019
What would be the most straight-forward way of mapping the members of an enum to the members of another enum (one-to-one mapping) at compile time?
May 11, 2019
On Saturday, 11 May 2019 at 15:48:44 UTC, Bogdan wrote:
> What would be the most straight-forward way of mapping the members of an enum to the members of another enum (one-to-one mapping) at compile time?

I'd probably have either a definition of one in terms of the other:

enum Other {
   a = First.a,
   b = First.b
}

or a helper function that just converts:

Other convert(First v) {
   final switch(v) {
     case First.a: return Other.a;
     case First.b: return Other.b;
   }
}

and then call the function and it can ctfe it. The second one is probably more practical.
May 12, 2019
On Saturday, 11 May 2019 at 15:48:44 UTC, Bogdan wrote:
> What would be the most straight-forward way of mapping the members of an enum to the members of another enum (one-to-one mapping) at compile time?

An example of a Initial enum that creates a derived enum using the same element names but applying a transformation via a function foo() pus adding some other enum elements in the Derived one not present in the Initial.
It's a little bit clumsy but works very well.
I use this at module level. This allows to have the Derived enum at compile time so that it can be used to declare variables or functions at compile time.



mixin({
  string code = "enum Derived : ulong { "~
                        "init = 0,";      /* We set the dummy init value to 0 */
  static foreach(i; __traits(allMembers, Initial)) {
    code ~= i~"= foo(Initial."~i~"),";
  }
  code ~= "
    ALL    =  Whatever,
    THING  =  42,
  return code ~ "}";
}());


May 12, 2019
On Saturday, 11 May 2019 at 15:48:44 UTC, Bogdan wrote:
> What would be the most straight-forward way of mapping the members of an enum to the members of another enum (one-to-one mapping) at compile time?

If I understand your question correctly, you have two enums of equal length, and you want to convert members across enums according to their position, right? You can do that with a little bit of template programming and static foreach. The following works irrespective of underlying value and type, the only requirement is that there are no duplicate values:

https://run.dlang.io/is/dNssel
```
void main()
{
    enum FromEnum {F1 = 10, F2, F3}
    enum ToEnum   {T1 = 20, T2, T3}
    enum CharEnum : char {C1 = 'c', C2, C3}

    static assert(to!ToEnum(FromEnum.F2) == ToEnum.T2);
    static assert(to!ToEnum(FromEnum.F2) == 21);
    static assert(to!CharEnum(FromEnum.F2) == CharEnum.C2);
    static assert(to!CharEnum(FromEnum.F2) == 'd');
}

// Converts enumerations by position.
T to(T, F)(F f) if (is(F==enum) && is(T == enum))
{
    import std.traits;
    import std.meta;
    static assert(NoDuplicates!(EnumMembers!F).length == EnumMembers!F.length,
                  F.stringof ~ " has duplicates.");
    static assert(NoDuplicates!(EnumMembers!T).length == EnumMembers!T.length,
                  F.stringof ~ " has duplicates.");
    static assert(EnumMembers!F.length == EnumMembers!T.length,
                  F.stringof ~ " and " ~ T.stringof ~ " differ in length.");
    static foreach(i, t; EnumMembers!T)
        if (rank(f) == i)
            return t;
    assert(0, "Not an enum member");
}

// Returns i if e is the i-th enumerator of E.
static size_t rank(E)(E e) if (is(E == enum))
{
    import std.traits;
    static foreach (i, member; EnumMembers!E)
        if (e == member)
            return i;
    assert(0, "Not an enum member");
}
```
May 12, 2019
On Sunday, 12 May 2019 at 17:53:56 UTC, Bastiaan Veelo wrote:
> On Saturday, 11 May 2019 at 15:48:44 UTC, Bogdan wrote:
>> What would be the most straight-forward way of mapping the members of an enum to the members of another enum (one-to-one mapping) at compile time?
>
> If I understand your question correctly, you have two enums of equal length, and you want to convert members across enums according to their position, right? You can do that with a little bit of template programming and static foreach. The following works irrespective of underlying value and type, the only requirement is that there are no duplicate values:
>
> https://run.dlang.io/is/dNssel

There was an error in the error reporting. That should teach me to never copy+paste if you can static foreach :-) This one is better:

https://run.dlang.io/is/TVl9db
May 12, 2019
On Sunday, 12 May 2019 at 17:53:56 UTC, Bastiaan Veelo wrote:
> If I understand your question correctly, you have two enums of equal length, and you want to convert members across enums according to their position, right?

My question was very vague, sorry about that.

In my use case I'd like to map SDL2 keyboard scan codes to my own game input keyboard codes. The two enums would look something like this:

```
enum SDL_Scancode
{
    SDL_SCANCODE_UNKNOWN = 0,
    SDL_SCANCODE_A = 4,
    SDL_SCANCODE_B = 5,
    SDL_SCANCODE_C = 6,
    SDL_SCANCODE_D = 7,
}

enum MY_Scancode
{
  KEY_A,
  KEY_B,
  KEY_C,
  KEY_D,
}
```

The two enums are not of equal length, so in the end I just decided to create an immutable array of type My_Scancode[] where the index is an SDL_Scancode and the value is the corresponding MY_Scancode enum member. I'm ok with using some memory for this, as long as it's as fast as possible.
May 12, 2019
On Sunday, 12 May 2019 at 18:47:20 UTC, Bogdan wrote:
> On Sunday, 12 May 2019 at 17:53:56 UTC, Bastiaan Veelo wrote:
>> If I understand your question correctly, you have two enums of equal length, and you want to convert members across enums according to their position, right?
>
> My question was very vague, sorry about that.
>
> In my use case I'd like to map SDL2 keyboard scan codes to my own game input keyboard codes. The two enums would look something like this:
>
> ```
> enum SDL_Scancode
> {
>     SDL_SCANCODE_UNKNOWN = 0,
>     SDL_SCANCODE_A = 4,
>     SDL_SCANCODE_B = 5,
>     SDL_SCANCODE_C = 6,
>     SDL_SCANCODE_D = 7,
> }
>
> enum MY_Scancode
> {
>   KEY_A,
>   KEY_B,
>   KEY_C,
>   KEY_D,
> }
> ```
>
> The two enums are not of equal length, so in the end I just decided to create an immutable array of type My_Scancode[] where the index is an SDL_Scancode and the value is the corresponding MY_Scancode enum member. I'm ok with using some memory for this, as long as it's as fast as possible.

If the only difference is the extra _UNKNOWN member, you can still use the static foreach approach. Just make it a non-template function and rip out the checks, and add a +1 in the right place.