Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@Samathy
Last active May 27, 2020 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Samathy/0ee1669eb1c0e478c8bffebee5164234 to your computer and use it in GitHub Desktop.
Save Samathy/0ee1669eb1c0e478c8bffebee5164234 to your computer and use it in GitHub Desktop.
Dlang CTFE fun to generate a map of class names, to factories for that class for every class inheriting from given class.
import std.stdio;
class wibble
{
const string name()
{
return typeid(this).name;
}
}
class fibble: wibble
{
}
class bibble: wibble
{
}
class bobble:wobble
{
}
/**
* Generate a compile-time assotiative array of class names, to
* object factories which generate a new object of that type when called
*
*/
template getTypes(T)
{
static T function() [string] getTypes()
{
assert(__ctfe); //Let us know if d-runtime tries to run getTypes at runtime, because we don't want it too!
/**
* Get all 'members' of this file.
* That is functions, classes, structs, global data, everything
**/
const static string[] members = [__traits(allMembers, mixin(__MODULE__))];
// Make the assotiative array.
T function() [string] types;
// Loop over each 'member'
static foreach(m; members)
{
//If its something that is a specialization of T ( i.e a subclass )
static if (is (mixin(m) : T)) // If its a class
{
/** Add it too the array by name,
with a function which generates an object of that type as the value
**/
types[m] = makeObjectFactory!(mixin(m));
}
}
return types;
}
/**
* Take a type, and return a function which, when called, creates an object of that type.
*/
template makeObjectFactory ( factoryType )
{
T function() makeObjectFactory()
{
return function(){ return new factoryType; };
}
}
}
int main()
{
/**
* The types array has to be an enum, otherwise dlang just re-runs the
* getTypes templated function at runtime and regenerates the array.
* If you declare 'types' here to be const, then dlang runs getTypes at compile time, so the pragma passes.
* But it then just discards it and runs it at runtime again.
* This is because the runtimes for assotiative arrays are different at compile time, and runtime.
* https://forum.dlang.org/thread/rxmwzorpoteukxwcjsbv@forum.dlang.org
**/
enum wibble function()[string] types = getTypes!wibble();
/** We can tell the array above is created at compile time, because this pragma works.
* ["wibble":function () pure nothrow @safe => new wibble, "fibble":function () pure nothrow @safe => new fibble]......
*/
pragma(msg, types);
//Call the factory function for 'fibble' objects
auto w = types["fibble"]();
writeln(w.name()); // test.fibble
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment