Structs implementing interfaces in D1
Tom S
h3r3tic at remove.mat.uni.torun.pl
Mon Feb 9 19:50:27 PST 2009
/** Just a simple hack to have interfaces implemented by structs ...
because I can :P
Tested on DMD 1.039 [win32], GDC (various versions) [linux32] and
codepad.org
Output:
Entering main
Foo.func1 called ; val1 = 3.141590, val2 = Hello, world!
Foo.func2 called ; val1 = 3.141590, val2 = Hello, world!
Foo.func2 called ; val1 = 3.141590, val2 = Hello, world!
Foo.func3 called ; val1 = 3.141590, val2 = Hello, world! ; p1 = 123, p2
= some parameter
Leaving main
*/
module structIface;
extern (C) int printf(char*, ...);
// ---- evil implementation
char[] structImplementInterface(char[] iface, char[][] funcs) {
char[] res = "private {";
res ~= \n"alias typeof(*this) _iface_"~iface~"_ThisType;";
foreach (func; funcs) {
res ~= \n"static assert (is(typeof(&"~iface~".init."~func~")),
`The interface "~iface~" doesn't declare a '"~func~"' function, `
`thus struct `~_iface_"~iface~"_ThisType.stringof~` cannot implement
it`);";
res ~= \n"static void _iface_" ~ iface ~ "_func_" ~ func ~ "() {";
version (GNU) {
res ~= \n\t"asm { naked; sub dword ptr 4[ESP], _iface_" ~ iface ~
"_vtbl.offsetof; jmp " ~ func ~ "; }";
} else {
res ~= \n\t"asm { naked; sub EAX, _iface_" ~ iface ~ "_vtbl.offsetof;
jmp " ~ func ~ "; }";
}
res ~= \n"}";
}
res ~= \n ~ iface ~ " as" ~ iface ~ "() {";
res ~= \n\t"return cast("~iface~")cast(void*)&_iface_" ~ iface ~ "_vtbl;";
res ~= \n"}";
res ~= \n"void** _iface_" ~ iface ~ "_vtbl = cast(void**)([";
res ~= \n\t"null"; // for classinfo
foreach (func; funcs) {
res ~= ",\n\tcast(void*)&Foo._iface_" ~ iface ~ "_func_" ~ func;
}
res ~= \n"]).ptr;";
res ~= "}";
return res;
}
// ---- end of the evil implementation
interface IFoo {
void func1();
void func2();
}
interface IBar {
void func2();
void func3(int, char[]);
}
struct Foo {
float val1;
char[] val2;
void func1() {
printf("Foo.func1 called ; val1 = %f, val2 = %.*s"\n, val1, val2);
}
void func2() {
printf("Foo.func2 called ; val1 = %f, val2 = %.*s"\n, val1, val2);
}
void func3(int p1, char[] p2) {
printf("Foo.func3 called ; val1 = %f, val2 = %.*s ; p1 = %d, p2 =
%.*s"\n, val1, val2, p1, p2);
}
mixin(structImplementInterface("IFoo", ["func1", "func2"]));
mixin(structImplementInterface("IBar", ["func2", "func3"]));
}
void main() {
printf("Entering main"\n);
Foo f;
f.val1 = 3.14159f;
f.val2 = "Hello, world!";
IFoo fi = f.asIFoo;
fi.func1();
fi.func2();
IBar bi = f.asIBar;
bi.func2();
bi.func3(123, "some parameter");
printf("Leaving main"\n);
}
/**
The concept is pretty simple. The mixin creates a vtable which points to
a set of generated functions of the form { adjust the 'this' ptr; jump
to the real function; }. Finally, the "InterfaceName asInterfaceName()"
functions generated inside the struct return pointers to the
corresponding vtables.
Now this would be so much nicer if there was a way to iterate the
functions of an interface at compile time in D1... Can we have D1 plus
__traits? Pleaaaase? Pretty please with a cherry on top?
Thanks to downs, Hxal and Jarrett!
*/
--
Tomasz Stachowiak
http://h3.team0xf.com/
h3/h3r3tic on #D freenode
More information about the Digitalmars-d
mailing list