## digitalmars.D.learn - replace switch for mapping

• EntangledQuanta (68/68) Aug 31 2017 Generally one has to use a switch to map dynamic components.
• EntangledQuanta (152/152) Sep 01 2017 I came up with a library solution that isn't pretty ;/
• Andrea Fontana (5/8) Sep 04 2017 Does this work for you?
• EntangledQuanta (5/14) Sep 04 2017 No, do you realize you are passing those enums at compile time?
• Andrea Fontana (5/22) Sep 05 2017 So at runtime you can do in a couple of ways if i'm right:
EntangledQuanta <EQ universe.com> writes:
```Generally one has to use a switch to map dynamic components.
Given a set X and Y one can form a switch to map X to Y:

switch(X)
{
case x1 : y1; break;
....
case x1 : y1;
}

Is there any easier way to do this where one simply specifies the
set's rather than having to create a switch directly?

In my specific case, I have to map a two sets of types

A = {Ta1,...,Tan}
B = {Tb1,...,Tbm}

to a template function that takes two types

foo(Tak, Taj)

so, given an arbitrary (a,b) in AxB, it it maps to foo(F(a),G(b)).

Using switches would require n*m cases.

What I actually have is something like

enum X
{
Float,
Int,
`Etc`
}

and X x, y;

and need to call foo!(x,y) but with x and y replaced by their
correct D equivalent types.

e.g., if x = X.Float; y = X.Int; then I need to call
foo!(float,int) rather than foo!(X.Float,x.Int).

This allows me to create a dynamic dispatcher at runtime and use
a templated function rather than having to handle each type
independently. One templated function rather than nxm regular
functions for each type or a nxm switch.

Unfortunately, a complicating factor is that the enum's names do
not directly correspond to the D types through some simple
transformation(e.g., lowerCase). D doesn't seem to support
attributes on enum members for some inane reason and using
strings will complicate
things[https://forum.dlang.org/post/nmgloo\$bd1\$1 digitalmars.com]. I think I
could use a struct though to solve that.

So, given something like

struct A
{
("float") enum Float = 0,
("int") enum Int = 1,
}

struct B
{
("double") enum Double = 0,
("short") enum Short = 1,
}

foo(T1,T2)();

create a mapping that takes an A and B and maps AxB to foo that
does something like the following internally.

fooDispatch(A a, B b)
{
switch(a) // Actually needs to be over attributes
{
case "float" :
switch(b) // Actually needs to be over attributes
{
case "double" : return foo!(float, double)();
}
...
}
}

or whatever. I could write a string mixin that generates the
above code but I'm hoping I don't have to and some genius will
find a simple way to do it quickly, efficiently, and performant.
```
Aug 31 2017
EntangledQuanta <EQ universe.com> writes:
```I came up with a library solution that isn't pretty ;/

I offer it up to the gods, but being gods, they probably don't
care.

template EnumMapper(alias func, string[] args, eT...)
{
import std.meta, std.typecons, std.traits, std.string,
std.algorithm, std.array, std.conv;

private auto recSwitch(string[] args, int depth, alias N,
T...)(string[] attrs = null)
{
string str;
auto tab = replicate("\t", depth);
static if (T.length == 0)
{
string at;
foreach(k, a; args)
{
at ~= "cast(Parameters!("~func~"!("~attrs.join(",
")~"))["~to!string(k)~"])"~a;
if (k < args.length-1) at ~= ", ";
}
return tab~"\treturn "~func~"!("~attrs.join(",
")~")("~at~");\n";
}
else
{

str ~= tab~"switch("~N[0]~")\n"~tab~"{\n"~tab~"\tdefault:
break;\n";
foreach(v; __traits(allMembers, T[0]))
{
mixin(`enum attr = __traits(getAttributes,
T[0].`~v~`).stringof[6..\$-1].strip();`);
static if (attr != "")
{
str ~= tab~"\t"~"case "~v~":\n";
attrs ~= attr[1..\$-1];
str ~= recSwitch!(args, depth + 2 , N[1..\$],
T[1..\$])(attrs);
attrs = attrs[0..\$-1];
str ~= tab~"\t\tbreak;\n";

}
}
str ~= tab~"}\n";

return str;
}
}

private auto genMapper(string[] args, alias N, T...)()
{
string str;
foreach(e; AliasSeq!(eT[0..eT.length/2]))
str ~= "with("~e.stringof~") ";
auto code = recSwitch!(args, 0, N, T)();
return str~"\n"~code;
}

auto EnumMapper()
{
return "import std.traits;\n"~genMapper!(args,
[eT[eT.length/2..\$]], eT[0..eT.length/2])();
}
}

Because D only half-assley implements __traits for templates, a
lot of it is hacks and kludges.

It is used like

struct enumA
{
int value;
alias value this;
("float") enum Float = cast(enumA)0;
("int") enum Int = cast(enumA)1;
}

struct enumB
{
int value;
alias value this;
("double") enum Double = cast(enumB)0;
("byte") enum Byte = cast(enumB)1;
}

auto foo(T1, T2)(T1 a, T2 b)
{
import std.conv;
return to!string(a)~" - "~to!string(b);

}

void main()
{
auto res = ()
{
int a = 4;
double b = 1.23;
enumA enumAVal = enumA.Float;
enumB enumBVal = enumB.Byte;
mixin(EnumMapper!("foo", ["a", "b"], enumA, enumB,
"enumAVal", "enumBVal")());
return "--------";
}();

writeln(res);
getchar();
}

and basically generates the nested switch structure:

---------------------
with(enumA) with(enumB)
switch(enumAVal)
{
default: break;
case Float:
switch(enumBVal)
{
default: break;
case Double:
return foo!(float, double)(cast(Parameters!(foo!(float,
double))[0])a, cast(Parameters!(foo!(float, double))[1])b);
break;
case Byte:
return foo!(float, byte)(cast(Parameters!(foo!(float,
byte))[0])a, cast(Parameters!(foo!(float, byte))[1])b);
break;
}
break;
case Int:
switch(enumBVal)
{
default: break;
case Double:
return foo!(int, double)(cast(Parameters!(foo!(int,
double))[0])a, cast(Parameters!(foo!(int, double))[1])b);
break;
case Byte:
return foo!(int, byte)(cast(Parameters!(foo!(int,
byte))[0])a, cast(Parameters!(foo!(int, byte))[1])b);
break;
}
break;
}
---------------------

and so it maps the arbitrary (a,b) to the correct foo. The idea
is simple: Given a templated function, we want map the arbitrary
values, assuming they can be properly cast to the templated
function depending on the enum values.

the enum values control which foo is called. But this works at
runtime!

This is useful when one has many different representations of
data that all can be overloaded, but one doesn't know which
overload to use at compile time.

Could be used with variants to create automatic variant handlers
also.

This is only useful when one templated function can handle all
the cases though, just like how templates are used in the first
place for overloading.

Maybe someone can clean it up and make it in to something special.
```
Sep 01 2017
Andrea Fontana <nospam example.com> writes:
```On Thursday, 31 August 2017 at 23:17:52 UTC, EntangledQuanta
wrote:
Generally one has to use a switch to map dynamic components.
Given a set X and Y one can form a switch to map X to Y:

[...]

Does this work for you?
https://dpaste.dzfl.pl/e2669b595539

Andrea
```
Sep 04 2017
EntangledQuanta <EQ universe.com> writes:
```On Monday, 4 September 2017 at 09:23:24 UTC, Andrea Fontana wrote:
On Thursday, 31 August 2017 at 23:17:52 UTC, EntangledQuanta
wrote:
Generally one has to use a switch to map dynamic components.
Given a set X and Y one can form a switch to map X to Y:

[...]

Does this work for you?
https://dpaste.dzfl.pl/e2669b595539

Andrea

No, do you realize you are passing those enums at compile time?
It won't work if they are "runtime" variables, which is the whole
point of doing all this. You've essentially make a simple problem
complicated. Why not just overload foo properly?
```
Sep 04 2017
Andrea Fontana <nospam example.com> writes:
```On Monday, 4 September 2017 at 20:54:27 UTC, EntangledQuanta
wrote:
On Monday, 4 September 2017 at 09:23:24 UTC, Andrea Fontana
wrote:
On Thursday, 31 August 2017 at 23:17:52 UTC, EntangledQuanta
wrote:
Generally one has to use a switch to map dynamic components.
Given a set X and Y one can form a switch to map X to Y:

[...]

Does this work for you?
https://dpaste.dzfl.pl/e2669b595539

Andrea

No, do you realize you are passing those enums at compile time?
It won't work if they are "runtime" variables, which is the
whole point of doing all this. You've essentially make a simple
problem complicated. Why not just overload foo properly?

So at runtime you can do in a couple of ways if i'm right:
http://dpaste.com/02W9FX6

Andrea
```
Sep 05 2017