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 }));