Metaprogramming in D : Some Real-world Examples
rmcguire
rjmcguire at gmail.com
Fri Nov 13 04:30:15 PST 2009
Bill Baxter <wbaxter at gmail.com> wrote:
> On Mon, Nov 9, 2009 at 4:09 PM, Walter Bright
> <newshound1 at digitalmars.com> wrote:
>> Looks like Bill Baxter is giving a presentation on D Nov. 18!
>>
>> http://www.nwcpp.org/
>
> Yep, that's right, and I'd be quite grateful to you smart folks here
> if you could share your meta-programming favorites with me! If
> you've got a real-world example of meta-programming in D that you
> think is particularly handy, then please send it my way
>
> I'm looking for small-but-useful things that are easy to explain, and
> make something easier than it would be otherwise. Things like places
> where static if can save your butt, or loop unrolling, and passing
> code snippets to functions like in std.algorithm.
>
> Things like a compile-time raytracer or regexp parser (though quite
> cool!) are not what I'm after. Too involved for a short talk.
>
> --bb
>
I've use the code below to generate wrappers for my hessian serialization
implementation.
its not all absolutely necessary but is only 130 lines.
import std.stdio;
import std.typetuple;
import std.traits;
import std.metastrings;
string[] splitFuncs(string str) {
string[] res;
while (str.length > 0) {
while (str.length > 0 && (' ' == str[0] || ',' == str[0])) {
str = str[1..$];
}
int to = 0;
for (; to < str.length && str[to] != ' ' && str[to] != ','; ++to) {}
if (to > 0) {
res ~= str[0..to];
str = str[to..$];
}
}
return res;
}
string MethodTypeTuple_mixin(alias a)(string[] methods) {
string ret = "TypeTuple!("~ "typeof(&C.init."~methods[0]~")";
foreach (method; methods[1..$]) {
ret ~= ",typeof(&C.init."~method~")";
}
ret ~= ")";
return ret;
}
// test case
class A {
int a;
this(int a) {
this.a = a;
}
int getInt(string intname) {
return a;
}
void setInt(int i) {
a = i;
}
string getString(string s) {
return s ~"1234";
}
}
string ProxyMethods_mixin(alias C, string methodstr)() {
string ret;
foreach(i, t; mixin(MethodTypeTuple_mixin!(C)(splitFuncs(methodstr)))) {
// output function header
ret ~= "\t"~ReturnType!(t).stringof ~" "~ splitFuncs(methodstr)[i]~"(";
// output first arg
ret ~= ParameterTypeTuple!(t)[0].stringof~" arg";
// output remainder of args
foreach (j, t1; ParameterTypeTuple!(t)[1..$]) {
ret ~= ","~t1.stringof~" arg"~std.metastrings.ToString!(j);
}
// output body
ret ~= ") {\n";
// output serialization code
// send method name
ret ~= "\t\twritefln(\"serialize docall id\"); // the method call byte
id\n";
ret ~= "\t\t//serialize!(string)(\""~splitFuncs(methodstr)[i]~"\"); /+
the method name +/\n";
// send args
ret ~= "\t\t//serialize!("~ ParameterTypeTuple!(t)[0].stringof~")
(arg); /+ the first argument +/\n";
foreach (j, t1; ParameterTypeTuple!(t)[1..$]) {
ret ~= "\t\t//serialize!("~ t1.stringof ~")(arg"~ToString!(j)~"); /
+ argument "~ToString!(j)~" +/\n";
}
// receive return type
static if (!is(ReturnType!(t) == void)) {
pragma(msg, "WARNING: this will always result in Range violation
due to no real data. THIS IS JUST A DEMO");
pragma(msg, "\t\t need to implement the actual send/receive");
ret ~= "\t\t//return deserialize!("~ ReturnType!(t).stringof ~")
(buffer);\n";
// this is just here to make it still compile even though I've
commented out the real deserialize return above
static if (is(ReturnType!(t) == int)) {
ret ~= "\t\treturn 0;\n";
} else {
ret ~= "\t\treturn \"\";\n";
}
}
ret ~= "\t}\n";
}
return ret;
}
string ProxyClass_mixin(alias C, string methodstr)() {
string ret = "new class { ubyte[] buffer;\n";
ret ~= ProxyMethods_mixin!(C, methodstr)();
ret ~= "}\n";
pragma(msg, MethodTypeTuple_mixin!(C)(splitFuncs(methodstr)));
return ret;
}
class ProxyClass(alias C, string methodstr) {
ubyte[] buffer;
this() { }
mixin(ProxyMethods_mixin!(C,methodstr)());
}
/+ void serialize(T)(T value) {
writefln("serialize");
}
T deserialize(T)() {
writefln("deserialize");
static if (is(T==int)) {
return 1;
} else
return "asdf";
} +/
void main() {
pragma(msg, ProxyClass_mixin!(A,cast(string)"getInt setInt")());
writefln(ProxyClass_mixin!(A,cast(string)"getInt setInt")());
auto c = mixin(ProxyClass_mixin!(A,cast(string)"getInt setInt getString")
());
//pragma(msg, typeof(c).stringof);
writefln("c.getInt(\"adsf\"): "~ c.getString("asdf"));
auto pc = new ProxyClass!(A, cast(string)"getInt setInt getString");
writefln("ProxyClass: "~ pc.getString("asdf"));
}
More information about the Digitalmars-d-announce
mailing list