[资料] 元编程应用之:编译期 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 写道
一个D语言Variant类,演示了 mixin 的强大功能,据火星上的人说比 C++ Boost.variant 紧凑80倍。
D 代码(见原帖)

用 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 编译成功,运行时上句断言出错。
Global site tag (gtag.js) - Google Analytics