www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Compile time mapping

reply Bogdan <olar.bogdan.dev gmail.com> writes:
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
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
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 11 2019
prev sibling next sibling parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
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
prev sibling parent reply Bastiaan Veelo <Bastiaan Veelo.net> writes:
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
next sibling parent Bastiaan Veelo <Bastiaan Veelo.net> writes:
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
prev sibling parent reply Bogdan <olar.bogdan.dev gmail.com> writes:
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
parent Bastiaan Veelo <Bastiaan Veelo.net> writes:
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.
May 12 2019