changeset 362:bcbfffef4f9e

Undecorated D types can be registered with Qt
author Max Samukha <maxter@maxter.com>
date Wed, 09 Jun 2010 16:37:24 +0300
parents beaf4a2974d7
children 3b0545d4d479
files d2/qtd/QMetaTypeImpl.d mini/test1/build.bat mini/test1/main.d
diffstat 3 files changed, 133 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- 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);
+    }
 }
 
 
--- 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
--- 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!");
-    +/
-
 }