[资料] 元编程应用之:编译期 DLL 包装类
oldrev
2007-02-24
大家好!我刚加入,感觉这里是唯一的中文D语言论坛,真不容易啊。
发一个我写的元编程例子: // dll.d // A simple DLL wrapper // Author: Oldrev (wstring#AT#gmail.com) import std.c.windows.windows; import std.stdio; import std.traits; import std.string; import std.metastrings; struct Symbol(char[] Sym, Func) { const char[] Name = Sym; extern(Windows) alias ReturnType!(Func) function(ParameterTypeTuple!(Func)) FunctionType; // extern(Windows) alias FuncType FunctionType // Why is this Invalid? DMD's bug? } private template MixinMembers(S, V...) { mixin(Format!("alias S.FunctionType FP_%s;", S.Name)); mixin(Format!("S.FunctionType %s;", S.Name)); static if(V.length > 0) mixin MixinMembers!(V); } final class Module(char[] Path, Symbols...) { private HMODULE m_handle = null; public mixin MixinMembers!(Symbols); public this() { load(); initSymbols(); } public ~this() { free(); } private void initSymbols() { foreach (S; Symbols) { mixin(Format!("%s = getSymbol!(FP_%s)(S.Name);", S.Name, S.Name)); //mixin(Format!("assert(%s);", S.Name)); } } private void load() { m_handle = LoadLibraryA(toStringz(Path)); assert(m_handle); } private void free() { FreeLibrary(m_handle); } private T getSymbol(T)(char[] sym) { return cast(T)getSymbolAddress(sym); } private void* getSymbolAddress(char[] sym) { assert(m_handle); return GetProcAddress(m_handle, toStringz(sym)); } } void main() { auto dll = new Module!("User32.dll", Symbol!("MessageBoxW", int function(HWND, LPCWSTR, LPCWSTR, UINT)), Symbol!("MessageBoxA", int function(HWND, LPCSTR, LPCSTR, UINT)) ); dll.MessageBoxW(null, "Hello! DLL! ", "Hello from MessageBoxW", MB_OK); dll.MessageBoxA(null, "Hello! DLL! ", "Hello from MessageBoxA", MB_OK); } |
|
oldrev
2007-02-25
一个D语言Variant类,演示了 mixin 的强大功能,据火星上的人说比 C++ Boost.variant 紧凑80倍。
D 代码 import std.stdio; import std.metastrings; import std.typetuple; private template MixinMembers(int I, T, V...) { mixin(Format!("T var%s;", I)); static if(V.length > 0) mixin MixinMembers!(I + 1, V); } //catenate strings at compile time.... private template MixinThisFunc(char[] S, T, V...) { public const char[] Result = S ~ Format!("public this(%s v) { assign!(%s)(v); } ", T.stringof, T.stringof); pragma(msg, Result ~ "\n"); static if(V.length > 0) mixin MixinThisFunc!(Result, V); } class Variant(TList...) { public alias TList TypeList; public alias Variant!(TList) SelfType; // no union.tupleof? private union Holder { mixin MixinMembers!(0, TList); } private Holder m_holder; private int m_which = -1; public mixin(MixinThisFunc!("",TypeList).Result); public this() { m_holder.var0 = m_holder.var0.init; m_which = 0; } public SelfType assign(T)(T rhs) { enum { index = IndexOf!(T, TypeList) } static assert( index >= 0); mixin(Format!("m_holder.var%s = rhs;", index)); m_which = index; return this; } public SelfType opAssign(T)(T rhs) { return assign(rhs); } public int which() { return m_which; } public T get(T)() { enum { index = IndexOf!(T, TypeList) } static assert(index >= 0); assert(index == which()); mixin(Format!("return m_holder.var%s;", index)); } } void main() { scope auto v = new Variant!(int, double, char, char[])(1000); writefln("which: %d", v.which()); v = 100.0; v = 'A'; writefln("which: %d", v.which()); char[] str = "foobar"; v = str; writefln("which: %d", v.which()); str = ""; str = v.get!(char[]); writefln(str); } |
|
ideage
2007-02-25
太好了,正在学习!
|
|
oldrev
2007-02-26
上面那个Variant类好像不支持非POD类型,我重写了一个支持 POD 的,几乎达到了 boost.variant 的功能。
import std.metastrings; import std.stdio; import std.typetuple; import std.traits; private template MaxSizeImp(T, V...) { static if(V.length > 0) private const int tailResult = MaxSizeImp!(V).result; else private const int tailResult = T.sizeof; public const int result = T.sizeof > tailResult ? T.sizeof : tailResult; }; template MaxSize(TList...) { const int MaxSize = MaxSizeImp!(TList).result; } struct Variant(TList...) { public alias TList TypeList; public alias Variant!(TypeList) SelfType; private alias ubyte[MaxSize!(TypeList)] Holder; private Holder m_held; private int m_which = -1; public int which() { return m_which; } public SelfType assign(ValueType)(ValueType val) { static if(is(ValueType == SelfType)) { foreach(T; TypeList) { const int i = IndexOf!(T, TypeList); if(val.which == i) { assign!(T)(val.get!(T)); m_which = i; } } } else { const int i = IndexOf!(ValueType, TypeList); static assert(i >= 0); ValueType* heldPtr = cast(ValueType*)m_held.ptr; *heldPtr = val; m_which = i; } return *this; } public SelfType opAssign(ValueType)(ValueType rhs) { return assign!(ValueType)(rhs); } public bool opEquals(ValueType)(ValueType rhs) { static if(is(ValueType == SelfType)) { foreach(T; TypeList) { const int i = IndexOf!(T, TypeList); if(i == which) { return (rhs.which == which) && (get!(T) == rhs.get!(T)); } } } else { const int i = IndexOf!(ValueType, TypeList); static assert(i >= 0); ValueType* heldPtr = cast(ValueType*)m_held.ptr; return *heldPtr == rhs; } } public int opCmp(ValueType)(ValueType rhs) { if(rhs == *this)return 0; static if(is(ValueType == SelfType)) { foreach(T; TypeList) { const int i = IndexOf!(T, TypeList); if((i == which) && (rhs.which == which)) { return get!(T) < rhs.get!(T) ? -1 : 1; } } } else { const int i = IndexOf!(ValueType, TypeList); static assert(i >= 0); ValueType* heldPtr = cast(ValueType*)m_held.ptr; return *heldPtr < rhs ? -1 : 1; } } public TypeInfo type() { foreach(T; TypeList) { const int i = IndexOf!(T, TypeList); if(i == which) { return typeid(TypeList[i]); } } } public ValueType get(ValueType)() { return *(cast(ValueType*)m_held.ptr); } public bool empty() { return m_which < 0; } public bool isKindOf(ValueType)(ValueType val) { const int i = IndexOf!(ValueType, TypeList); static assert(i >= 0); return which == i; } } void main() { class Foo { public: int n = 0; int x = 0; int y = 0; int z = 0; Foo opAssign(int rhs) { z = rhs; return this; } } Variant!(double, char, int, char[], Foo) v; v = 2; assert(v == 2); v = 2.22; assert(v == 2.22); assert(v.type == typeid(double)); v = new Foo; assert(v.type == typeid(Foo)); v.get!(Foo)() = 2; assert(v.get!(Foo)().z == 2); typeof(v) v2 = v; assert(v2 == v); assert(v <= 2); v = cast(char[])"Foobar"; assert(v == cast(char[])"Foobar"); } |
|
qiezi
2007-02-28
写个linux版嘛,用version(Windows)和version(linux)区分开。
下面这个Variant和库里的boxer好像功能相似吧? |
|
oldrev
2007-03-01
怎么我老是得到:超人,您的请求服务器暂时无法响应,请体谅人类服务器脆弱的心脏吧。
请稍后再尝试。 |
|
oldrev
2007-03-01
> 写个linux版嘛,用version(Windows)和version(linux)区分开。
其实差不多嘛,就是自己换一下dlopen 那些函数。这个类不好用,因为我发现当定义较多函数时会产生超长标识符,导致编译错误 > 下面这个Variant和库里的boxer好像功能相似吧? 与boxer相似的应该是 boost.any variant 是基于栈的可识别联合,你可以仔细看看 boost.any 和 boost.variant 的区别: http://www.boost.org/doc/html/variant/misc.html#variant.versus-any |
|
liuwangxia
2008-01-15
oldrev 写道 大家好!我刚加入,感觉这里是唯一的中文D语言论坛,真不容易啊。
发一个我写的元编程例子: auto dll = new Module!("User32.dll", Symbol!("MessageBoxW", int function(HWND, LPCWSTR, LPCWSTR, UINT)), Symbol!("MessageBoxA", int function(HWND, LPCSTR, LPCSTR, UINT)) ); 我用 DMD 2.009 编译时上面的句子报错: 引用 template instance Symbol!("MessageBoxW",int function(HANDLE, const wchar*, const wchar*, uint)*) does not match any template declaration
|
|
liuwangxia
2008-01-15
oldrev 写道
用 DMD 2.009 编译出错,但没有提供行号: 引用 semicolon expected, not '%'
Declaration expected, not '%' Declaration expected, not '0' |
|
liuwangxia
2008-01-15
oldrev 写道 上面那个Variant类好像不支持非POD类型,我重写了一个支持 POD 的,几乎达到了 boost.variant 的功能。
assert(v <= 2); 用 DMD 2.009 编译成功,运行时上句断言出错。 |