replace switch for mapping

EntangledQuanta via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri Sep 1 18:40:37 PDT 2017


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.








More information about the Digitalmars-d-learn mailing list