A mixin template for automatic property generation (criticize my code?)
aldanor via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Wed Dec 17 14:48:56 PST 2014
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)));
}
More information about the Digitalmars-d-learn
mailing list