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