# HG changeset patch # User Max Samukha # Date 1276090644 -10800 # Node ID bcbfffef4f9e1e4182375900511dcb892cd6fd8a # Parent beaf4a2974d707aa57e3bac87cc13e8b5cbcf016 Undecorated D types can be registered with Qt diff -r beaf4a2974d7 -r bcbfffef4f9e d2/qtd/QMetaTypeImpl.d --- a/d2/qtd/QMetaTypeImpl.d Wed Jun 09 11:08:56 2010 +0300 +++ b/d2/qtd/QMetaTypeImpl.d Wed Jun 09 16:37:24 2010 +0300 @@ -1,12 +1,17 @@ module qtd.QMetaTypeImpl; import + std.traits, + core.memory, + core.exception, qt.core.Qt, qt.core.QDataStream, + qt.core.QMetaType, qtd.QtdObject; // TODO: remove import std.stdio; +import std.conv; private struct DArrayToC { @@ -17,15 +22,38 @@ */ template MetaTypeOps(T) { + // Note that in case of byref objects we follow Qt's convention and + // allocate/copy references, not objects. static void* construct(void* copy) { - static assert (is(T : Object)); - return cast(void*)new T(cast(T)copy); + auto T* p = cast(T*)GC.malloc(T.sizeof); + if (!p) + onOutOfMemoryError(); + + if (copy) + *p = *cast(T*)copy; + else + { + static if (!is(T == class) && __traits(compiles, T())) + *p = T(); + else static if (isAssociativeArray!T) + { + // COMPILER BUG: need to special-case this because AA.init is broken. + // Consequently, no custom AA init values are supported. + *p = null; + } + else + *p = T.init; + } + + return p; } static void destroy(void* ptr) { - (cast(T)ptr).dispose(); + // Run destructors for value types. Let the GC reclaim the memory. + static if (is(T == struct) && __traits(compiles, T.__dtor)) + (cast(T*)ptr).__dtor; } } @@ -44,18 +72,10 @@ } } -/** - */ -int qRegisterMetaType(T, alias ops = MetaTypeOps)(string name = null) +// TODO: only GNU C++ is supported +private template typeOpShim(alias op) { - if (!name.length) - name = typeid(T).toString; //TODO: use compile time full name? - - alias ops!T.construct construct; - alias ops!T.destroy destroy; - - // TODO: only GNU C++ - extern(C) static void ctorShim() + extern(C) void typeOpShim() { asm { @@ -63,27 +83,113 @@ push EBP; mov EBP, ESP; mov EAX, 0x8[EBP]; - call construct; + call op; leave; ret; } } +} - extern(C) static void dtorShim() +/** + */ +int qRegisterMetaType(T, alias ops = MetaTypeOps)(string name = null) +{ + if (!name.length) + name = typeid(T).toString; //TODO: use compile time full name + + return qtd_registerType(toStringz(name), &typeOpShim!(ops!T.destroy), &typeOpShim!(ops!T.construct)); +} + +version (QtdUnittest) +{ + unittest { - asm + static class A + { + int x; + } + + static struct S + { + int x; + + static S* dtorCalled; + + static S opCall(int x = 31) + { + S s; + s.x = x; + return s; + } + + ~this() + { + dtorCalled = &this; + } + } + + static void test(T)(T val, string typeName = null) { - naked; - push EBP; - mov EBP, ESP; - mov EAX, 0x8[EBP]; - call destroy; - leave; - ret; + int id = qRegisterMetaType!T(typeName); + assert(id > 0); + auto p = cast(T*)QMetaType.construct(id, null); + + assert(*p is T.init); + QMetaType.destroy(id, p); + + p = cast(T*)QMetaType.construct(id, &val); + assert(p !is &val); + assert(*p == val); + QMetaType.destroy(id, p); } - } + + test(42, "d_int"); + test(new A); + test([1, 2, 3]); + + int sId = qRegisterMetaType!S(); + int saId = qRegisterMetaType!(int[3])(); + int aaId = qRegisterMetaType!(int[int])(); + + // structs + auto s = S(42); + + auto ps1 = cast(S*)QMetaType.construct(sId, null); + assert(ps1.x == 31); + + auto ps2 = cast(S*)QMetaType.construct(sId, &s); + assert(ps2 !is &s); + assert(ps2.x == 42); + + QMetaType.destroy(sId, ps1); + assert(S.dtorCalled is ps1); - return qtd_registerType(toStringz(name), &dtorShim, &ctorShim); + QMetaType.destroy(sId, ps2); + assert(S.dtorCalled is ps2); + + // static arrays + int sa[3] = [42, 43, 44]; + auto psa = cast(int[3]*)QMetaType.construct(saId, null); + assert(*psa == [0, 0, 0] /* int[3].init */); + QMetaType.destroy(saId, psa); + + auto psa2 = cast(int[3]*)QMetaType.construct(saId, &sa); + assert(psa2 !is &sa); + assert(*psa2 == sa); + + // associative arrays + int[int] aa = [1: 42, 2: 43, 3: 44]; + auto paa = cast(int[int]*)QMetaType.construct(aaId, null); + // COMPILER BUG: AA.init is broken + // assert (*paa == (int[int]).init); + assert(!(*paa).length); + QMetaType.destroy(aaId, paa); + + auto paa2 = cast(int[int]*)QMetaType.construct(aaId, &aa); + assert(paa2 !is &aa); + assert(*paa2 == aa); + QMetaType.destroy(aaId, paa); + } } diff -r beaf4a2974d7 -r bcbfffef4f9e mini/test1/build.bat --- a/mini/test1/build.bat Wed Jun 09 11:08:56 2010 +0300 +++ b/mini/test1/build.bat Wed Jun 09 16:37:24 2010 +0300 @@ -1,2 +1,2 @@ set LIB=E:\d-projects\qtd-trunk\output\build\lib -dmd main.d ..\..\output\build\lib\qtdcore.lib -I../../d2 -I../../output/build \ No newline at end of file +dmd main.d -debug -unittest -version=QtdUnittest ..\..\output\build\lib\qtdcore.lib -I../../d2 -I../../output/build \ No newline at end of file diff -r beaf4a2974d7 -r bcbfffef4f9e mini/test1/main.d --- a/mini/test1/main.d Wed Jun 09 11:08:56 2010 +0300 +++ b/mini/test1/main.d Wed Jun 09 16:37:24 2010 +0300 @@ -27,36 +27,4 @@ void main(string[] args) { - int id = qRegisterMetaType!A(); - qRegisterMetaTypeStreamOperators!A(); - - foreach (i; 0..10) - { - writeln("Iter ", i); - - void foo(int x, int y, int z) - { - auto a = new A("A" ~ to!string(i)); - auto b = cast(A)QMetaType.construct(id, cast(void*)a); - writeln(b.name); - - QMetaType.destroy(id, cast(void*)a); - QMetaType.destroy(id, cast(void*)b); - - scope ds = new QDataStream(cast(void*)3, QtdObjectFlags.nativeOwnership); - QMetaType.save(ds, id, cast(void*)i); - QMetaType.load(ds, id, cast(void*)i); - writeln("Done iterating ", x, " ", y, " ", z); - } - - foo(i + 1, i + 2, i + 3); - } - /+ - - writeln("Great!"); - - - writeln("Even greater!"); - +/ - }