comparison qt/d1/qt/QtdObject.d @ 258:1da8870e9a62 lifetime

branched for changes to object lifetime handling
author maxter
date Wed, 16 Sep 2009 14:16:33 +0000
parents b1abe7f57321
children 515d6e1c7b10
comparison
equal deleted inserted replaced
257:17b5e13364b7 258:1da8870e9a62
1 /** 1 /**
2 * 2 *
3 * Copyright: Copyright QtD Team, 2008-2009 3 * Copyright: Copyright QtD Team, 2008-2009
4 * License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a> 4 * License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>
5 * Authors: Max Samukha, Eldar Insafutdinov
5 * 6 *
6 * Copyright QtD Team, 2008-2009 7 * Copyright QtD Team, 2008-2009
7 * Distributed under the Boost Software License, Version 1.0. 8 * 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 * (See accompanying file boost-license-1.0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 * 10 *
10 */ 11 */
11 12
12 module qt.QtdObject; 13 module qt.QtdObject;
13 14
14 import qt.Signal; 15 import qt.Signal;
15 //import tango.io.Stdout; 16 import tango.core.Memory;
17 debug (QtdVerbose)
18 import tango.io.Stdout;
19
16 20
17 enum QtdObjectFlags : ubyte 21 enum QtdObjectFlags : ubyte
18 { 22 {
19 none, 23 none,
20 nativeOwnership = 0x1, 24 // The native object will not be deleted when the wrapper is deleted
21 dOwnership = 0x2, 25 skipNativeDelete = 0b0001,
22 dynamicEntity = 0x4 26 skipDDelete = 0b0010,
23 //gcManaged = 0x4 27 hasDId = 0b0100,
24 } 28 stackAllocated = 0b1000
25 29 /+
26 package abstract class QtdObject 30 // The will be deleted when is goes out of scope. Implies skipNativeDelete
27 { 31 scoped = 0x08
28 protected QtdObjectFlags __flags_; 32 +/
33 }
34
35 class MetaObject
36 {
37 alias typeof(this) This;
38
39 private
40 {
41 MetaObject _base;
42 ClassInfo _classInfo;
43 }
44
45 //COMPILER BUG: not accessible from QMetaObject
46 protected
47 {
48 This _firstDerived;
49 This _next;
50 }
51
52 private void addDerived(This mo)
53 {
54 mo._next = _firstDerived;
55 _firstDerived = mo;
56 }
57
58 /++
59 Next sibling on this derivation level
60 +/
61 final This next()
62 {
63 return _next;
64 }
65
66 /++
67 Head of the linked list of derived classes
68 +/
69 final This firstDerived()
70 {
71 return _firstDerived;
72 }
73
74 // NOTE: construction is split between this non-templated constructor and 'construct' function below.
75 this(This base)
76 {
77 if (base)
78 {
79 base.addDerived(this);
80 _base = base;
81 }
82 }
83
84 // TODO: can be removed when D acquires templated constructors
85 void construct(T : Object)()
86 {
87 _classInfo = T.classinfo;
88 }
89
90 final This base()
91 {
92 return _base;
93 }
94
95 final ClassInfo classInfo()
96 {
97 return _classInfo;
98 }
99 }
100
101
102 abstract class QtdMetaObject : MetaObject
103 {
104 QtdObjectBase function(void* nativeId, QtdObjectFlags flags) _createWrapper;
105
106 void construct(T : QtdObject, Concrete = T)()
107 {
108 super.construct!(T);
109 _createWrapper = &T.__createWrapper;
110 }
111 }
112
113 /++
114 Meta-object for polymorphic Qt classes.
115 +/
116 final class QtdMetaObject : MetaObject
117 {
118 alias typeof(this) This;
119
120 private void* _typeId;
121
122 this(void* typeId, QtdMetaObject base)
123 {
124 super(base);
125 _typeId = typeId;
126 }
127
128 QtdObject wrap(void* nativeId, void* typeId, QtdObjectFlags flags = QtdObjectFlags.skipNativeDelete)
129 {
130 if (typeId == _typeId)
131 {
132 /+
133 if (auto p = nativeId in _nativeToDMap)
134 return *p;
135 +/
136 }
137 else
138 {
139 for (auto mo = static_cast!(This)(_firstDerived); mo; mo = static_cast!(This)(mo._next))
140 {
141 if (auto obj = mo.wrap(nativeId, typeId, flags))
142 return obj;
143 }
144 }
145
146 return _createWrapper(nativeId, flags);
147 }
148 }
149
150 abstract class QtdObjectBase
151 {
152 alias typeof(this) This;
153
29 void* __nativeId; 154 void* __nativeId;
30 155 QtdObjectFlags __flags;
156
157 new (size_t size, QtdObjectFlags flags = QtdObjectFlags.none)
158 {
159 return flags & QtdObjectFlags.stackAllocated ? __stackAlloc.alloc(size) :
160 GC.malloc(size, GC.BlkAttr.FINALIZE);
161 }
162
163 delete (void* p)
164 {
165 if ((cast(This)p).__flags & QtdObjectFlags.stackAllocated)
166 __stackAlloc.free(this.classinfo.init.length);
167 else
168 GC.free(p);
169 }
170
171 this(void* nativeId, QtdObjectFlags flags = QtdObjectFlags.none)
172 {
173 __nativeId = nativeId;
174 __flags = flags;
175 debug(QtdVerbose) __print("D wrapper constructed");
176 }
177
178 debug(QtdVerbose)
179 {
180 void __print(string msg)
181 {
182 Stdout.formatln("{} (native: {}, D: {}, flags 0b{:b})", msg, __nativeId, cast(void*)this, __flags);
183 }
184 }
185
186 protected void __deleteNative()
187 {
188 assert(false, "Cannot delete native "
189 ~ this.classinfo.name
190 ~ " because it has no public destructor");
191 }
192
193 ~this()
194 {
195 debug(QtdVerbose) __print("In QtdObjectBase destructor");
196
197 if (!(__flags & QtdObjectFlags.skipNativeDelete))
198 {
199 __flags |= QtdObjectFlags.skipDDelete;
200 debug(QtdVerbose) __print("About to call native delete");
201 __deleteNative;
202 }
203 }
204 }
205
206 // Base class for by-reference objects
207 abstract class QtdObject : QtdObjectBase
208 {
209 private
210 {
211 typeof(this) __next, __prev;
212 static typeof(this) __root;
213 }
214
215 /++
216 Use this method instead of 'is' operator to check if two D objects
217 wrap the same native object.
218 +/
219 bool isSame(QtdObject other)
220 {
221 return __nativeId == other.__nativeId;
222 }
223
31 mixin SignalHandlerOps; 224 mixin SignalHandlerOps;
32 225
33 this(void* nativeId, QtdObjectFlags flags = QtdObjectFlags.none) 226 this(void* nativeId, QtdObjectFlags flags)
34 { 227 {
35 //Stdout.formatln("Created D object {} {:x}", nativeId, flags).newline; 228 super (nativeId, flags);
36 __nativeId = nativeId; 229 if (!(flags & QtdObjectFlags.skipNativeDelete))
37 __flags_ = flags; 230 __pin;
38 } 231 }
39 232
40 final QtdObjectFlags __flags() 233 final void __pin()
41 { 234 {
42 return __flags_; 235 debug(QtdVerbose) __print("Pinning");
43 } 236
44 237 __next = __root;
45 /+ final +/ void __setFlags(QtdObjectFlags flags, bool value) 238 __root = this;
46 { 239 if (__next)
240 __next.__prev = this;
241 }
242
243 final void __unpin()
244 {
245 debug(QtdVerbose) __print("Unpinning");
246
247 if (__prev)
248 __prev.__next = __next;
249 else
250 __root = __next;
251
252 if (__next)
253 __next.__prev = __prev;
254 }
255
256 void __nativeOwnership(bool value)
257 {
47 if (value) 258 if (value)
48 __flags_ |= flags; 259 {
260 assert (!(__flags & QtdObjectFlags.skipNativeDelete));
261 __flags |= QtdObjectFlags.skipNativeDelete;
262 __unpin;
263 }
49 else 264 else
50 __flags_ &= ~flags; 265 {
51 } 266 assert (__flags & QtdObjectFlags.skipNativeDelete);
52 267 __flags = __flags &= ~QtdObjectFlags.skipNativeDelete;
53 // COMPILER BUG: 3206 268 __pin;
54 protected void __deleteNative() 269 }
55 { 270 }
56 assert(false); 271
57 }
58
59 ~this() 272 ~this()
60 { 273 {
61 //Stdout.formatln("Deleting D object {}", __nativeId); 274 debug(QtdVerbose) __print("In QtdObject destructor");
62 if (!(__flags_ & QtdObjectFlags.nativeOwnership)) 275
63 { 276 if (__prev || __root is this)
64 // avoid deleting D object twice. 277 __unpin;
65 //Stdout.formatln("About to delete native object {}", __nativeId); 278 }
66 __flags_ |= QtdObjectFlags.dOwnership; 279 }
67 __deleteNative; 280
68 } 281 /++
69 //Stdout.formatln("Deleted native D object {}", __nativeId); 282 +/
70 } 283 void dispose(QtdObjectBase obj)
71 } 284 {
285 obj.__flags &= ~QtdObjectFlags.skipNativeDelete;
286 delete obj;
287 }
288
289 // Called from shell destructors
290 extern(C) void qtd_delete_d_object(void* dId)
291 {
292 auto obj = cast(QtdObject)dId;
293 debug(QtdVerbose) obj.__print("In qtd_delete_d_object");
294
295 if (!(obj.__flags & QtdObjectFlags.skipDDelete))
296 {
297 // Avoid deleting native object twice
298 obj.__flags |= QtdObjectFlags.skipNativeDelete;
299 delete obj;
300 }
301 }