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
Permalink
Reply