Mercurial > projects > qtd
comparison d2/qtd/QtdObject.d @ 372:a032df77b6ab
Simple debug helper. Unittests. Meta-object for polymorphic non-QObjects
author | Max Samukha <maxter@spambox.com> |
---|---|
date | Thu, 08 Jul 2010 17:19:05 +0300 |
parents | 9784459f0750 |
children | 1d56b2a2e10c |
comparison
equal
deleted
inserted
replaced
370:7fd4b69378bf | 372:a032df77b6ab |
---|---|
1 /** | 1 /** |
2 * | 2 * |
3 * Copyright: Copyright QtD Team, 2008-2009 | 3 * Copyright: Copyright QtD Team, 2008-2010 |
4 * License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a> | 4 * License: Boost License 1.0 |
5 * | 5 * Authors: Max Samukha, Eldar Insafutdinov |
6 * Copyright QtD Team, 2008-2009 | |
7 * Distributed under the Boost Software License, Version 1.0. | |
8 * (See accompanying file boost-license-1.0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
9 * | 6 * |
10 */ | 7 */ |
11 | 8 |
12 module qtd.QtdObject; | 9 module qtd.QtdObject; |
13 import qtd.Core; | 10 |
14 | 11 import |
15 enum QtdObjectFlags : ubyte | 12 core.memory, |
13 std.bitmanip, | |
14 qtd.Core, | |
15 qtd.Debug, | |
16 qtd.meta.Runtime; | |
17 | |
18 /** | |
19 QtdObject initialization options. | |
20 */ | |
21 enum QtdObjectInitFlags | |
16 { | 22 { |
17 none, | 23 none, |
18 nativeOwnership = 0x1, | 24 /// The wrapper is being created by user code. |
19 dOwnership = 0x2, | 25 createdByD = 0x1, |
20 dynamicEntity = 0x4 | 26 /// The wrapper is being created with native ownership. |
21 //gcManaged = 0x4 | 27 nativeOwnership = 0x2, |
22 } | 28 /// The wrapper is allocated on stack. |
23 | 29 onStack = 0x4 |
24 package abstract class QtdObject | 30 } |
25 { | 31 |
26 protected QtdObjectFlags __flags_; | 32 /** |
27 void* __nativeId; | 33 */ |
28 | 34 enum QtdObjectOwnership |
29 this(void* nativeId, QtdObjectFlags flags = QtdObjectFlags.none) | 35 { |
30 { | 36 /// |
31 __nativeId = nativeId; | 37 native, |
32 __flags_ = flags; | 38 /// |
33 } | 39 d |
34 | 40 } |
35 final QtdObjectFlags __flags() | 41 |
36 { | 42 /** |
37 return __flags_; | 43 */ |
38 } | 44 struct QtdObjectFlags |
39 | 45 { |
40 /+ final +/ void __setFlags(QtdObjectFlags flags, bool value) | 46 mixin (bitfields!( |
41 { | 47 bool, "nativeDeleteDisabled" , 1, |
42 if (value) | 48 bool, "wrapperDeleteDisabled" , 1, |
43 __flags_ |= flags; | 49 bool, "createdByD" , 1, |
50 bool, "pinned" , 1, | |
51 bool, "isQObject" , 1, | |
52 bool, "polymorphic" , 1, | |
53 bool, "onStack" , 1, | |
54 int , "reserved" , 1 | |
55 )); | |
56 } | |
57 | |
58 | |
59 /* package */ abstract class QtdObject | |
60 { | |
61 alias typeof(this) This; | |
62 | |
63 private | |
64 { | |
65 void* _nativeId; | |
66 This _next; | |
67 This _prev; | |
68 __gshared static This _root; | |
69 } | |
70 | |
71 protected QtdObjectFlags _flags; | |
72 | |
73 /** | |
74 */ | |
75 @property QtdObjectFlags qtdFlags() | |
76 { | |
77 return _flags; | |
78 } | |
79 | |
80 /** | |
81 */ | |
82 @property final const | |
83 { | |
84 void* qtdNativeId() | |
85 { | |
86 return cast(void*)_nativeId; | |
87 } | |
88 | |
89 void qtdNativeId(void* v) | |
90 { | |
91 unqual(_nativeId) = v; | |
92 } | |
93 } | |
94 | |
95 this(void* nativeId, QtdObjectInitFlags initFlags = QtdObjectInitFlags.none) | |
96 { | |
97 _nativeId = nativeId; | |
98 | |
99 if (initFlags & QtdObjectInitFlags.createdByD) | |
100 _flags.createdByD = true; | |
101 | |
102 if (initFlags & QtdObjectInitFlags.nativeOwnership) | |
103 qtdSetOwnership(QtdObjectOwnership.native); | |
104 | |
105 if (initFlags & QtdObjectInitFlags.onStack) | |
106 { | |
107 //assert(!_flags.isQObject); | |
108 assert(!(initFlags & QtdObjectInitFlags.nativeOwnership)); | |
109 | |
110 _flags.nativeDeleteDisabled = true; | |
111 _flags.wrapperDeleteDisabled = true; | |
112 } | |
113 | |
114 mixin(debugHandler("onWrapperConstructed", "this")); | |
115 } | |
116 | |
117 /** | |
118 Disables GC for this object; | |
119 */ | |
120 // TODO: needs to be properly synchronized | |
121 final void qtdPin() const | |
122 { | |
123 assert(!_flags.pinned); | |
124 //GC.addRoot(cast(void*)this); | |
125 | |
126 auto obj = unqual(this); | |
127 | |
128 obj._next = _root; | |
129 _root = obj; | |
130 if (_next) | |
131 obj._next._prev = obj; | |
132 | |
133 obj._flags.pinned = true; | |
134 } | |
135 | |
136 /** | |
137 Multiple wrappers for a single native object may exist. | |
138 This function is used to test that this and the other wrapper point | |
139 to the same native object (identity test). | |
140 | |
141 Note that wrappers for QObject instances and instances of classes | |
142 derived from QObject are always unique, therefore | |
143 the 'is' expression can be used instead of this function. | |
144 */ | |
145 final bool isSame(const(QtdObject) other) const | |
146 { | |
147 return other !is null && (other is this || other.qtdNativeId == qtdNativeId); | |
148 } | |
149 | |
150 /** | |
151 Enables GC for this object. | |
152 */ | |
153 // TODO: needs to be properly synchronized | |
154 final void qtdUnpin() const | |
155 { | |
156 assert(_flags.pinned); | |
157 //GC.removeRoot(cast(void*)this); | |
158 | |
159 auto obj = unqual(this); | |
160 if (_prev) | |
161 obj._prev._next = obj._next; | |
44 else | 162 else |
45 __flags_ &= ~flags; | 163 _root = obj._next; |
164 | |
165 if (_next) | |
166 obj._next._prev = obj._prev; | |
167 | |
168 obj._flags.pinned = false; | |
169 } | |
170 | |
171 /** | |
172 Sets the ownership of this object. | |
173 Setting the same ownership twice results in undefined behavior. | |
174 The function is not thread-safe. | |
175 */ | |
176 void qtdSetOwnership(QtdObjectOwnership own) const | |
177 { | |
178 if (_flags.isQObject) | |
179 return; | |
180 | |
181 assert(!_flags.onStack); | |
182 auto obj = unqual(this); | |
183 | |
184 if (own == QtdObjectOwnership.native) | |
185 { | |
186 if (_flags.polymorphic && _flags.createdByD) | |
187 qtdPin(); | |
188 else | |
189 obj._flags.nativeDeleteDisabled = true; | |
190 } | |
191 else if (own == QtdObjectOwnership.d) | |
192 { | |
193 if (_flags.polymorphic && _flags.createdByD) | |
194 qtdUnpin(); | |
195 else | |
196 obj._flags.nativeDeleteDisabled = false; | |
197 } | |
198 else | |
199 assert(false); | |
200 | |
201 mixin(debugHandler("onWrapperOwnershipChanged", "obj")); | |
46 } | 202 } |
47 | 203 |
48 // COMPILER BUG: 3206 | 204 // COMPILER BUG: 3206 |
49 protected void __deleteNative() | 205 protected void qtdDeleteNative() |
50 { | 206 { |
51 assert(false); | 207 assert(false); |
52 } | 208 } |
53 | 209 |
54 ~this() | 210 ~this() |
55 { | 211 { |
56 if (!(__flags_ & QtdObjectFlags.nativeOwnership)) | 212 mixin(debugHandler("onWrapperDestruction", "this")); |
213 | |
214 if (!_flags.nativeDeleteDisabled) | |
57 { | 215 { |
58 // avoid deleting D object twice. | 216 // avoid deleting D object twice. |
59 __flags_ |= QtdObjectFlags.dOwnership; | 217 |
60 __deleteNative; | 218 _flags.wrapperDeleteDisabled = true; |
61 } | 219 qtdDeleteNative; |
62 } | 220 |
63 } | 221 mixin(debugHandler("onNativeDeleted", "this")); |
222 } | |
223 | |
224 if (_flags.pinned) | |
225 qtdUnpin(); | |
226 | |
227 mixin(debugHandler("onWrapperDestroyed", "this")); | |
228 } | |
229 } | |
230 | |
231 /** | |
232 Base class for polymorphic non-QObjects (TBD). | |
233 */ | |
234 /* package */ abstract class NonQObject : QtdObject | |
235 { | |
236 alias NonQObjectMetaClass Meta; | |
237 | |
238 this(void* nativeId, QtdObjectInitFlags initFlags) | |
239 { | |
240 _flags.polymorphic = true; | |
241 super(nativeId, initFlags); | |
242 } | |
243 } | |
244 | |
245 /** | |
246 Base class for QtD meta-object classes. | |
247 */ | |
248 abstract class QtdMetaClass : MetaClass | |
249 { | |
250 alias QtdObject function(void* nativeId, QtdObjectInitFlags initFlags) CreateWrapper; | |
251 | |
252 private void* _nativeId; | |
253 protected CreateWrapper _createWrapper; | |
254 | |
255 this() {} | |
256 | |
257 /** | |
258 */ | |
259 @property | |
260 void* nativeId() | |
261 { | |
262 return _nativeId; | |
263 } | |
264 | |
265 void construct(T)() | |
266 { | |
267 super.construct!T(); | |
268 _nativeId = T.qtdNativeStaticMetaObject(); | |
269 _createWrapper = &T.qtdCreateWrapper; | |
270 } | |
271 | |
272 abstract QtdObject getWrapper(void* nativeId, QtdObjectInitFlags initFlags = QtdObjectInitFlags.none); | |
273 } | |
274 | |
275 /** | |
276 Meta-object class for non-QObject polymorphic classes. | |
277 */ | |
278 final class NonQObjectMetaClass : QtdMetaClass | |
279 { | |
280 alias typeof(this) This; | |
281 alias createImpl!This create; | |
282 | |
283 @property override This next() | |
284 { | |
285 return static_cast!This(super.next); | |
286 } | |
287 | |
288 @property override This firstDerived() | |
289 { | |
290 return static_cast!This(super.firstDerived); | |
291 } | |
292 | |
293 override QtdObject getWrapper(void* nativeId, QtdObjectInitFlags initFlags) | |
294 { | |
295 // traverse the inheritance tree to find a matching meta-object. | |
296 // if the exact match is not found, return the closest base. | |
297 This lookUp(This mo) | |
298 { | |
299 if (!qtdTypeInfosEqual(mo.nativeId, nativeId)) | |
300 { | |
301 for (auto mo2 = mo.firstDerived; mo2 !is null; mo2 = mo2.next) | |
302 { | |
303 mo2 = lookUp(mo2); | |
304 if (mo != mo2) | |
305 break; | |
306 } | |
307 } | |
308 return mo; | |
309 } | |
310 | |
311 auto mo = lookUp(this); | |
312 return static_cast!NonQObject(mo._createWrapper(nativeId, initFlags)); | |
313 } | |
314 } | |
315 | |
316 extern (C) bool qtdTypeInfosEqual(void* info1, void* info2); | |
64 | 317 |
65 mixin(qtdExport("void", "QtdObject_delete", "void* dId", | 318 mixin(qtdExport("void", "QtdObject_delete", "void* dId", |
66 q{ | 319 q{ |
67 auto obj = cast(QtdObject)dId; | 320 auto obj = cast(QtdObject)dId; |
68 | 321 |
69 if (!(obj.__flags & QtdObjectFlags.dOwnership)) | 322 mixin(debugHandler("onDeletingWrapperFromNative", "dId")); |
323 | |
324 if (!obj._flags.wrapperDeleteDisabled) | |
70 { | 325 { |
71 // Avoid deleting native object twice | 326 // Avoid deleting native object twice |
72 obj.__setFlags(QtdObjectFlags.nativeOwnership, true); | 327 obj._flags.nativeDeleteDisabled = true; |
73 delete obj; | 328 delete obj; |
74 } | 329 } |
75 })); | 330 })); |