Mercurial > projects > qtd
comparison d2/qtd/meta/Runtime.d @ 368:185df9220ea7
Fixed startsWith. Implemented meta-object members as ranges. Freed QMetaObject from stuff that belongs to MetaClass
author | Max Samukha <maxter@maxter.com> |
---|---|
date | Mon, 28 Jun 2010 21:29:32 +0300 |
parents | 958e8b9a89bd |
children | a032df77b6ab |
comparison
equal
deleted
inserted
replaced
367:f69341b40588 | 368:185df9220ea7 |
---|---|
2 Copyright: Copyright Max Samukha, 2010 | 2 Copyright: Copyright Max Samukha, 2010 |
3 Authors: Max Samukha | 3 Authors: Max Samukha |
4 License: Boost Software License 1.0 | 4 License: Boost Software License 1.0 |
5 **************************************************************************/ | 5 **************************************************************************/ |
6 module qtd.meta.Runtime; | 6 module qtd.meta.Runtime; |
7 //TODO: Probably replace switch dispatch with pointer dispatch | |
8 //and leave switch dispatch only in C interface | |
9 | 7 |
10 import | 8 import |
11 qtd.meta.Compiletime, | 9 qtd.meta.Compiletime, |
12 | 10 |
13 std.typetuple, | 11 std.typetuple, |
14 std.conv, | 12 std.conv, |
15 std.variant, | 13 std.stdio, |
16 core.sync.rwmutex; | 14 std.traits, |
17 | 15 std.variant; |
18 private __gshared ReadWriteMutex lock; | 16 |
17 import std.range : isForwardRange, isRandomAccessRange; | |
18 | |
19 /** | |
20 Object to lock on when accessing thread-shared meta-objects. | |
21 */ | |
22 immutable Object metaLock; | |
19 shared static this() | 23 shared static this() |
20 { | 24 { |
21 lock = new ReadWriteMutex; | 25 metaLock = cast(immutable)new Object; |
22 } | 26 } |
23 | 27 |
24 /** | 28 /** |
25 IDs of the built-in basic types. | 29 IDs of the built-in basic types. |
26 */ | 30 */ |
85 { | 89 { |
86 super(msg); | 90 super(msg); |
87 } | 91 } |
88 } | 92 } |
89 | 93 |
90 abstract class Meta | 94 abstract class MetaBase |
91 { | 95 { |
92 alias typeof(this) This; | 96 alias typeof(this) This; |
93 | 97 |
94 string name; | 98 string name; |
95 MetaAttribute[] attributes; | 99 MetaAttribute[] attributes; |
96 Meta[] members; | 100 |
101 protected MetaBase[] members_; | |
97 | 102 |
98 template createImpl(M : This) | 103 template createImpl(M : This) |
99 { | 104 { |
100 static M createImpl(alias symbol)() | 105 static M createImpl(alias symbol)() |
101 { | 106 { |
123 } | 128 } |
124 } | 129 } |
125 | 130 |
126 protected void construct(alias symbol)() | 131 protected void construct(alias symbol)() |
127 { | 132 { |
133 name = symbol.stringof; | |
128 createAttrs!symbol; | 134 createAttrs!symbol; |
129 } | 135 } |
130 } | 136 |
131 | 137 static struct MembersRange |
132 /** | 138 { |
133 Base class for run time attributes. | 139 private MetaBase[] members_; |
140 | |
141 @property | |
142 MetaBase front() | |
143 { | |
144 return members_[0]; | |
145 } | |
146 | |
147 @property | |
148 bool empty() | |
149 { | |
150 return members_.length == 0; | |
151 } | |
152 | |
153 @property | |
154 MembersRange save() | |
155 { | |
156 return this; | |
157 } | |
158 | |
159 @property | |
160 MetaBase back() | |
161 { | |
162 return members_[$ - 1]; | |
163 } | |
164 | |
165 void popFront() | |
166 { | |
167 members_ = members_[1..$]; | |
168 } | |
169 | |
170 void popBack() | |
171 { | |
172 members_ = members_[0..$ - 1]; | |
173 } | |
174 | |
175 MetaBase opIndex(size_t i) | |
176 { | |
177 return members_[i]; | |
178 } | |
179 | |
180 @property | |
181 size_t length() | |
182 { | |
183 return members_.length; | |
184 } | |
185 } | |
186 | |
187 /** | |
188 Returns a random access range of members of the class described by this meta-object. | |
189 */ | |
190 @property | |
191 MembersRange members() | |
192 { | |
193 return MembersRange(members_); | |
194 } | |
195 } | |
196 | |
197 version (QtdUnittest) unittest | |
198 { | |
199 static assert(isRandomAccessRange!(MetaBase.MembersRange)); | |
200 } | |
201 | |
202 /** | |
203 Base class for run-time attributes. | |
134 */ | 204 */ |
135 abstract class MetaAttribute | 205 abstract class MetaAttribute |
136 { | 206 { |
137 alias typeof(this) This; | |
138 | |
139 string name; | 207 string name; |
140 AttributeOptions options; | 208 AttributeOptions options; |
141 | 209 |
142 This create(string name, AttributeOptions opts, A...)() | 210 this(string name, AttributeOptions opts) |
143 { | |
144 auto ma = new This; | |
145 ma.construct!(name, opts, A)(); | |
146 return ma; | |
147 } | |
148 | |
149 void construct(string name, AttributeOptions opts)() | |
150 { | 211 { |
151 this.name = name; | 212 this.name = name; |
152 options = opts; | 213 options = opts; |
153 } | 214 } |
154 } | 215 } |
155 | 216 |
156 abstract class MetaType : Meta | 217 abstract class MetaType : MetaBase |
157 { | 218 { |
158 } | 219 } |
159 | 220 |
160 abstract class MetaAggregate : MetaType | 221 abstract class MetaAggregate : MetaType |
161 { | 222 { |
162 } | 223 } |
163 | 224 |
164 class MetaClass : MetaAggregate | 225 class MetaClass : MetaAggregate |
226 { | |
227 alias typeof(this) This; | |
228 | |
229 private | |
230 { | |
231 This base_; | |
232 This firstDerived_; | |
233 This next_; | |
234 ClassInfo classInfo_; | |
235 } | |
236 | |
237 alias createImpl!This create; | |
238 | |
239 static struct AllMembersRange | |
240 { | |
241 public //private | |
242 { | |
243 This metaClass_; | |
244 MetaBase[] members_; | |
245 | |
246 void skipEmpty() | |
247 { | |
248 while (!metaClass_.members_.length) | |
249 { | |
250 metaClass_ = metaClass_.base_; | |
251 if (!metaClass_) | |
252 { | |
253 members_ = null; | |
254 return; | |
255 } | |
256 } | |
257 | |
258 members_ = metaClass_.members_; | |
259 } | |
260 } | |
261 | |
262 this(This metaClass) | |
263 { | |
264 metaClass_ = metaClass; | |
265 skipEmpty(); | |
266 } | |
267 | |
268 @property | |
269 MetaBase front() | |
270 { | |
271 return members_[0]; | |
272 } | |
273 | |
274 @property | |
275 bool empty() | |
276 { | |
277 return members_.length == 0; | |
278 } | |
279 | |
280 @property | |
281 AllMembersRange save() | |
282 { | |
283 return this; | |
284 } | |
285 | |
286 void popFront() | |
287 { | |
288 members_ = members_[1..$]; | |
289 if (!members_.length) | |
290 { | |
291 metaClass_ = metaClass_.base_; | |
292 if (metaClass_) | |
293 skipEmpty(); | |
294 } | |
295 } | |
296 } | |
297 | |
298 /** | |
299 Returns a forward range of members of the class described by this meta-object, | |
300 including base class members. | |
301 */ | |
302 @property | |
303 AllMembersRange allMembers() | |
304 { | |
305 return AllMembersRange(this); | |
306 } | |
307 | |
308 /** | |
309 Returns the meta-object of the base class. | |
310 */ | |
311 @property | |
312 This base() | |
313 { | |
314 return base_; | |
315 } | |
316 | |
317 /** | |
318 Returns the next meta-object on this level of the inheritance hierarchy. | |
319 */ | |
320 @property | |
321 This next() | |
322 { | |
323 return next_; | |
324 } | |
325 | |
326 /** | |
327 Returns the meta-object for the first derived class. | |
328 */ | |
329 @property | |
330 This firstDerived() | |
331 { | |
332 return firstDerived_; | |
333 } | |
334 | |
335 /** | |
336 D class info. | |
337 */ | |
338 @property | |
339 ClassInfo classInfo() | |
340 { | |
341 return classInfo_; | |
342 } | |
343 | |
344 | |
345 /* internal */ void construct(T : Object)() | |
346 { | |
347 super.construct!T(); | |
348 static if (!is(T == Object)) | |
349 { | |
350 alias BaseClassesTuple!(T)[0] Base; | |
351 base_ = meta!Base; | |
352 | |
353 next_ = base_.firstDerived_; | |
354 base_.firstDerived_ = this; | |
355 } | |
356 classInfo_ = T.classinfo; | |
357 } | |
358 | |
359 /** | |
360 */ | |
361 override string toString() const | |
362 { | |
363 return "MetaClass for " ~ classInfo_.name; | |
364 } | |
365 } | |
366 | |
367 version (QtdUnittest) unittest | |
368 { | |
369 static assert (isForwardRange!(MetaClass.AllMembersRange)); | |
370 } | |
371 | |
372 class MetaStruct : MetaAggregate | |
165 { | 373 { |
166 alias typeof(this) This; | 374 alias typeof(this) This; |
167 alias createImpl!This create; | 375 alias createImpl!This create; |
168 } | 376 } |
169 | 377 |
170 class MetaStruct : MetaAggregate | 378 /** |
171 { | 379 */ |
172 alias typeof(this) This; | |
173 alias createImpl!This create; | |
174 } | |
175 | |
176 @property | 380 @property |
177 auto meta(alias symbol, M : Meta)() | 381 M meta(alias symbol, M : MetaBase)() |
178 { | 382 { |
179 __gshared static M m; | 383 __gshared static M sharedM; |
180 | 384 static M m; |
181 { | |
182 lock.reader.lock; | |
183 scope(exit) | |
184 lock.reader.unlock; | |
185 if (m) | |
186 return m; | |
187 } | |
188 | |
189 lock.writer.lock; | |
190 scope(exit) | |
191 lock.writer.unlock; | |
192 | 385 |
193 if (!m) | 386 if (!m) |
194 m = M.create!symbol; | 387 { |
388 synchronized(metaLock) | |
389 { | |
390 if (!sharedM) | |
391 sharedM = M.create!symbol; | |
392 } | |
393 m = sharedM; | |
394 } | |
395 | |
396 assert (m is sharedM); | |
195 return m; | 397 return m; |
196 } | 398 } |
197 | 399 |
400 version (QtdUnittest) unittest | |
401 { | |
402 class A | |
403 { | |
404 } | |
405 | |
406 auto m = meta!A; | |
407 assert(m is meta!A); | |
408 } | |
409 | |
410 /** | |
411 */ | |
198 // only classes and structs for now | 412 // only classes and structs for now |
199 @property | 413 @property |
200 auto meta(T)() | 414 auto meta(T)() |
201 { | 415 { |
202 static if (is(typeof(T.staticMetaObject))) | 416 static if (is(T.Meta)) |
203 return T.staticMetaObject; | 417 return meta!(T, T.Meta); |
204 else static if (is(T == class)) | 418 else static if (is(T == class)) |
205 return meta!(T, MetaClass); | 419 return meta!(T, MetaClass); |
206 else static if (is(T == struct)) | 420 else static if (is(T == struct)) |
207 return meta!(T, MetaStruct); | 421 return meta!(T, MetaStruct); |
208 else | 422 else |
209 static assert(false, "No meta object for symbol " ~ T.stringof); | 423 static assert(false, "No meta-object for symbol " ~ T.stringof); |
210 } | 424 } |
211 | 425 |
212 /** | 426 /** |
213 A run time attribute implementation that stores the attribute data in an | 427 A run-time attribute implementation that stores the attribute data in an |
214 array of variants. | 428 array of variants. |
215 */ | 429 */ |
216 class MetaVariantAttribute : MetaAttribute | 430 class MetaVariantAttribute : MetaAttribute |
217 { | 431 { |
432 alias typeof(this) This; | |
433 | |
218 Variant[] values; | 434 Variant[] values; |
219 | 435 |
220 private this() | 436 private this(string name, AttributeOptions opts) |
221 { | 437 { |
222 } | 438 super(name, opts); |
223 | 439 } |
224 static MetaVariantAttribute create(string category, AttributeOptions opts, A...)() | 440 |
225 { | 441 static MetaVariantAttribute create(string name, AttributeOptions opts, A...)() |
226 auto ret = new MetaVariantAttribute; | 442 { |
227 ret.construct!(category, opts)(); | 443 auto ret = new This(name, opts); |
228 foreach(i, _; A) | 444 foreach(i, _; A) |
229 { | 445 { |
230 static if (__traits(compiles, { ret.values ~= Variant(A[i]); } )) | 446 static if (__traits(compiles, { ret.values ~= Variant(A[i]); } )) |
231 ret.values ~= Variant(A[i]); | 447 ret.values ~= Variant(A[i]); |
232 } | 448 } |
233 return ret; | 449 return ret; |
234 } | 450 } |
235 } | 451 } |
236 | 452 |
237 /** | 453 /** |
238 A run time attribute implementation that stores the attribute data in an | 454 A run-time attribute implementation that stores the attribute data in an |
239 assiciative array of variants. | 455 assiciative array of variants. |
240 */ | 456 */ |
241 class MetaVariantDictAttribute : MetaAttribute | 457 class MetaVariantDictAttribute : MetaAttribute |
242 { | 458 { |
243 Variant[string] values; | 459 Variant[string] values; |
244 alias typeof(this) This; | 460 alias typeof(this) This; |
245 | 461 |
246 private this() | 462 private this(string name, AttributeOptions opts) |
247 { | 463 { |
248 } | 464 super(name, opts); |
249 | 465 } |
250 static This create(string category, AttributeOptions opts, A...)() | 466 |
251 { | 467 static This create(string name, AttributeOptions opts, A...)() |
252 auto ret = new This; | 468 { |
253 ret.construct!(category, opts)(); | 469 auto ret = new This(name, opts); |
254 foreach(i, _; A) | 470 foreach(i, _; A) |
255 { | 471 { |
256 static if (i % 2 == 0 && __traits(compiles, { ret.values[A[i]] = Variant(A[i + 1]); } )) | 472 static if (i % 2 == 0 && __traits(compiles, { ret.values[A[i]] = Variant(A[i + 1]); } )) |
257 ret.values[A[i]] = Variant(A[i + 1]); // PHOBOS BUG: phobos asserts on this | 473 ret.values[A[i]] = Variant(A[i + 1]); // PHOBOS BUG: phobos asserts on this |
258 } | 474 } |
259 return ret; | 475 return ret; |
260 } | 476 } |
261 } | 477 } |
262 | 478 |
263 version (QtdUnittest) | 479 version(QtdUnittest) unittest |
264 { | 480 { |
265 unittest | 481 static void foo() {} |
266 { | 482 |
267 static void foo() {} | 483 static class C |
268 | 484 { |
269 static class C | 485 mixin InnerAttribute!("variantAttribute", MetaVariantAttribute, "22", foo, 33); |
270 { | 486 mixin InnerAttribute!("variantDictAttribute", MetaVariantDictAttribute, |
271 mixin InnerAttribute!("variantAttribute", MetaVariantAttribute, "22", foo, 33); | 487 //"a", "33", // PHOBOS BUG: variant is unusable with AAs |
272 mixin InnerAttribute!("variantDictAttribute", MetaVariantDictAttribute, | 488 "b", foo |
273 //"a", "33", // PHOBOS BUG: variant is unusable with AAs | 489 //"c", 44 |
274 "b", foo | 490 ); |
275 //"c", 44 | 491 } |
276 ); | 492 |
277 } | 493 auto attrs = meta!(C).attributes; |
278 | 494 assert(attrs.length == 2); |
279 auto attrs = meta!(C).attributes; | 495 auto attr = cast(MetaVariantAttribute)attrs[0]; |
280 assert(attrs.length == 2); | 496 |
281 auto attr = cast(MetaVariantAttribute)attrs[0]; | 497 assert(attr.name == "variantAttribute"); |
282 | 498 assert(attr.values[0] == "22"); |
283 assert(attr.name == "variantAttribute"); | 499 assert(attr.values[1] == 33); |
284 assert(attr.values[0] == "22"); | 500 |
285 assert(attr.values[1] == 33); | 501 auto attr2 = cast(MetaVariantDictAttribute) attrs[1]; |
286 | 502 assert(attr2.name == "variantDictAttribute"); |
287 auto attr2 = cast(MetaVariantDictAttribute) attrs[1]; | 503 //assert(attr2.values["a"] == "33"); |
288 assert(attr2.name == "variantDictAttribute"); | 504 //assert(attr2.values["c"] == 44); |
289 //assert(attr2.values["a"] == "33"); | 505 } |
290 //assert(attr2.values["c"] == 44); | |
291 } | |
292 } |