Mercurial > projects > qtd
comparison d2/qtd/QMetaTypeImpl.d @ 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 | a032df77b6ab |
comparison
equal
deleted
inserted
replaced
361:beaf4a2974d7 | 362:bcbfffef4f9e |
---|---|
1 module qtd.QMetaTypeImpl; | 1 module qtd.QMetaTypeImpl; |
2 | 2 |
3 import | 3 import |
4 std.traits, | |
5 core.memory, | |
6 core.exception, | |
4 qt.core.Qt, | 7 qt.core.Qt, |
5 qt.core.QDataStream, | 8 qt.core.QDataStream, |
9 qt.core.QMetaType, | |
6 qtd.QtdObject; | 10 qtd.QtdObject; |
7 | 11 |
8 // TODO: remove | 12 // TODO: remove |
9 import std.stdio; | 13 import std.stdio; |
14 import std.conv; | |
10 | 15 |
11 private struct DArrayToC | 16 private struct DArrayToC |
12 { | 17 { |
13 void[] array; | 18 void[] array; |
14 } | 19 } |
15 | 20 |
16 /** | 21 /** |
17 */ | 22 */ |
18 template MetaTypeOps(T) | 23 template MetaTypeOps(T) |
19 { | 24 { |
25 // Note that in case of byref objects we follow Qt's convention and | |
26 // allocate/copy references, not objects. | |
20 static void* construct(void* copy) | 27 static void* construct(void* copy) |
21 { | 28 { |
22 static assert (is(T : Object)); | 29 auto T* p = cast(T*)GC.malloc(T.sizeof); |
23 return cast(void*)new T(cast(T)copy); | 30 if (!p) |
31 onOutOfMemoryError(); | |
32 | |
33 if (copy) | |
34 *p = *cast(T*)copy; | |
35 else | |
36 { | |
37 static if (!is(T == class) && __traits(compiles, T())) | |
38 *p = T(); | |
39 else static if (isAssociativeArray!T) | |
40 { | |
41 // COMPILER BUG: need to special-case this because AA.init is broken. | |
42 // Consequently, no custom AA init values are supported. | |
43 *p = null; | |
44 } | |
45 else | |
46 *p = T.init; | |
47 } | |
48 | |
49 return p; | |
24 } | 50 } |
25 | 51 |
26 static void destroy(void* ptr) | 52 static void destroy(void* ptr) |
27 { | 53 { |
28 (cast(T)ptr).dispose(); | 54 // Run destructors for value types. Let the GC reclaim the memory. |
55 static if (is(T == struct) && __traits(compiles, T.__dtor)) | |
56 (cast(T*)ptr).__dtor; | |
29 } | 57 } |
30 } | 58 } |
31 | 59 |
32 /** | 60 /** |
33 */ | 61 */ |
42 { | 70 { |
43 writeln("Loading ", ds.__nativeId, " ", data); | 71 writeln("Loading ", ds.__nativeId, " ", data); |
44 } | 72 } |
45 } | 73 } |
46 | 74 |
47 /** | 75 // TODO: only GNU C++ is supported |
48 */ | 76 private template typeOpShim(alias op) |
49 int qRegisterMetaType(T, alias ops = MetaTypeOps)(string name = null) | 77 { |
50 { | 78 extern(C) void typeOpShim() |
51 if (!name.length) | |
52 name = typeid(T).toString; //TODO: use compile time full name? | |
53 | |
54 alias ops!T.construct construct; | |
55 alias ops!T.destroy destroy; | |
56 | |
57 // TODO: only GNU C++ | |
58 extern(C) static void ctorShim() | |
59 { | 79 { |
60 asm | 80 asm |
61 { | 81 { |
62 naked; | 82 naked; |
63 push EBP; | 83 push EBP; |
64 mov EBP, ESP; | 84 mov EBP, ESP; |
65 mov EAX, 0x8[EBP]; | 85 mov EAX, 0x8[EBP]; |
66 call construct; | 86 call op; |
67 leave; | 87 leave; |
68 ret; | 88 ret; |
69 } | 89 } |
70 } | 90 } |
71 | 91 } |
72 extern(C) static void dtorShim() | 92 |
73 { | 93 /** |
74 asm | 94 */ |
75 { | 95 int qRegisterMetaType(T, alias ops = MetaTypeOps)(string name = null) |
76 naked; | 96 { |
77 push EBP; | 97 if (!name.length) |
78 mov EBP, ESP; | 98 name = typeid(T).toString; //TODO: use compile time full name |
79 mov EAX, 0x8[EBP]; | 99 |
80 call destroy; | 100 return qtd_registerType(toStringz(name), &typeOpShim!(ops!T.destroy), &typeOpShim!(ops!T.construct)); |
81 leave; | 101 } |
82 ret; | 102 |
83 } | 103 version (QtdUnittest) |
84 } | 104 { |
85 | 105 unittest |
86 return qtd_registerType(toStringz(name), &dtorShim, &ctorShim); | 106 { |
107 static class A | |
108 { | |
109 int x; | |
110 } | |
111 | |
112 static struct S | |
113 { | |
114 int x; | |
115 | |
116 static S* dtorCalled; | |
117 | |
118 static S opCall(int x = 31) | |
119 { | |
120 S s; | |
121 s.x = x; | |
122 return s; | |
123 } | |
124 | |
125 ~this() | |
126 { | |
127 dtorCalled = &this; | |
128 } | |
129 } | |
130 | |
131 static void test(T)(T val, string typeName = null) | |
132 { | |
133 int id = qRegisterMetaType!T(typeName); | |
134 assert(id > 0); | |
135 auto p = cast(T*)QMetaType.construct(id, null); | |
136 | |
137 assert(*p is T.init); | |
138 QMetaType.destroy(id, p); | |
139 | |
140 p = cast(T*)QMetaType.construct(id, &val); | |
141 assert(p !is &val); | |
142 assert(*p == val); | |
143 QMetaType.destroy(id, p); | |
144 } | |
145 | |
146 test(42, "d_int"); | |
147 test(new A); | |
148 test([1, 2, 3]); | |
149 | |
150 int sId = qRegisterMetaType!S(); | |
151 int saId = qRegisterMetaType!(int[3])(); | |
152 int aaId = qRegisterMetaType!(int[int])(); | |
153 | |
154 // structs | |
155 auto s = S(42); | |
156 | |
157 auto ps1 = cast(S*)QMetaType.construct(sId, null); | |
158 assert(ps1.x == 31); | |
159 | |
160 auto ps2 = cast(S*)QMetaType.construct(sId, &s); | |
161 assert(ps2 !is &s); | |
162 assert(ps2.x == 42); | |
163 | |
164 QMetaType.destroy(sId, ps1); | |
165 assert(S.dtorCalled is ps1); | |
166 | |
167 QMetaType.destroy(sId, ps2); | |
168 assert(S.dtorCalled is ps2); | |
169 | |
170 // static arrays | |
171 int sa[3] = [42, 43, 44]; | |
172 auto psa = cast(int[3]*)QMetaType.construct(saId, null); | |
173 assert(*psa == [0, 0, 0] /* int[3].init */); | |
174 QMetaType.destroy(saId, psa); | |
175 | |
176 auto psa2 = cast(int[3]*)QMetaType.construct(saId, &sa); | |
177 assert(psa2 !is &sa); | |
178 assert(*psa2 == sa); | |
179 | |
180 // associative arrays | |
181 int[int] aa = [1: 42, 2: 43, 3: 44]; | |
182 auto paa = cast(int[int]*)QMetaType.construct(aaId, null); | |
183 // COMPILER BUG: AA.init is broken | |
184 // assert (*paa == (int[int]).init); | |
185 assert(!(*paa).length); | |
186 QMetaType.destroy(aaId, paa); | |
187 | |
188 auto paa2 = cast(int[int]*)QMetaType.construct(aaId, &aa); | |
189 assert(paa2 !is &aa); | |
190 assert(*paa2 == aa); | |
191 QMetaType.destroy(aaId, paa); | |
192 } | |
87 } | 193 } |
88 | 194 |
89 | 195 |
90 // COMPILER BUG: cannot put this inside qRegisterMetaTypeStreamOperators | 196 // COMPILER BUG: cannot put this inside qRegisterMetaTypeStreamOperators |
91 // COMPILER BUG 2: cannot use extern(C) with templated functions: extern(C) void foo(T)(){} | 197 // COMPILER BUG 2: cannot use extern(C) with templated functions: extern(C) void foo(T)(){} |