December 17, 2014 A mixin template for automatic property generation (criticize my code?) | ||||
---|---|---|---|---|
| ||||
I'm trying (hard) to learn D templating, and (thanks to the great help on this forum) I've been able to solve one of the recent tasks I've been struggling about for a while. Wonder if anyone would take a moment to criticize the code so we rookies could learn? Could this be done more elegantly? P.S. will there ever be a static foreach for declarations?.. P.P.S. this is a great community, thanks again for all who answered to my previous questions :) Task at hand: there's a bunch of "private" variables (extern globals from a C library) scattered across a number of modules whose definitions look like this: private extern (C) __gshared int foo_g; private extern (C) __gshared long bar_g; for which one needs to generate module-level accessors like these: int foo() @property { func(); return foo_g; } long bar() @property { func(); return bar_g; } where "func" is some callable. Ideally, it would be done like so: mixin makeModuleProperties("_g", func); and it should respect qualified names and work across modules (that was the biggest problem -- just generating a huge code string and mixing it in turned out to be too fragile with respect to fully qualified names, and quite a mess in general). Solution: import std.traits; import std.string; import std.typetuple; template ID(alias T) { alias ID = T; } private bool _propertyNameMatches(alias parent, string suffix, alias name)() { static if (!__traits(compiles, __traits(getMember, parent, name))) return false; else { alias symbol = ID!(__traits(getMember, parent, name)); enum name = __traits(identifier, symbol); enum n = suffix.length; static if (!is(symbol) && is(typeof(symbol))) // variables only return (name.length > n) && (name[$ - n .. $] == suffix); else return false; } } private mixin template _makeProperty(alias parent, string suffix, alias func, string name) { mixin(("typeof(__traits(getMember, parent, name)) %s() @property " ~ "{ func(); return __traits(getMember, parent, name); }").format( name[0 .. $ - suffix.length])); } private mixin template _makeProperties(alias parent, string suffix, alias func, names...) { static if (names.length > 0) { static if (_propertyNameMatches!(parent, suffix, names[0])) mixin _makeProperty!(parent, suffix, func, names[0]); mixin _makeProperties!(parent, suffix, func, names[1 .. $]); } } mixin template makeProperties(alias parent, string suffix, alias func = {}) { static if (__traits(compiles, __traits(allMembers, parent))) mixin _makeProperties!(parent, suffix, func, __traits(allMembers, parent)); } mixin template makeModuleProperties(string suffix, alias func = {}) { mixin makeProperties!(mixin(__MODULE__), suffix, func); } unittest { struct Foo { static int x_g = 1; static int y_g = 2; static int z = 3; static mixin makeProperties!(Foo, "_g"); } int counter = 0; mixin makeProperties!(Foo, "_g", { counter++; }); assert(Foo.x == 1); assert(Foo.y == 2); assert(x == 1); assert(counter == 1); assert(y == 2); assert(counter == 2); static assert(!is(typeof(z))); } |
December 17, 2014 Re: A mixin template for automatic property generation (criticize my code?) | ||||
---|---|---|---|---|
| ||||
Posted in reply to aldanor | I've no idea why the forum decided to wrap all code; anyway: https://gist.github.com/aldanor/ddc45b2710a2deb9ee2b |
Copyright © 1999-2021 by the D Language Foundation