Mercurial > projects > qtd
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 } |