Mercurial > projects > qtd
annotate d2/qtd/meta/Compiletime.d @ 357:9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Q_CLASSINFO implementation
Now Qtd can be built on Windows
author | Max Samukha <maxter@spambox.com> |
---|---|
date | Wed, 02 Jun 2010 19:38:05 +0300 |
parents | 59d847a814e3 |
children | a084e2df3776 |
rev | line source |
---|---|
351 | 1 /************************************************************************** |
2 Copyright: QtD Team, 2010 | |
3 Authors: Max Samukha, Eldar Insafutdinov | |
4 License: Boost Software License 1.0 | |
5 **************************************************************************/ | |
6 module qtd.meta.Compiletime; | |
7 | |
8 import | |
9 std.traits, | |
10 std.conv, | |
11 std.variant, | |
12 std.typetuple; | |
13 | |
14 import std.string : startsWith; | |
15 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
16 /** |
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
17 */ |
351 | 18 enum standardNamespace = "qtd"; |
19 | |
20 template Alias(A...) if (A.length == 1) | |
21 { | |
22 static if (__traits(compiles, { alias A[0] x; })) | |
23 alias A[0] Alias; | |
24 else | |
25 enum Alias = A[0]; | |
26 } | |
27 | |
28 /** | |
29 Encapsulates a static tuple. Useful for preventing tuples from | |
30 flattening when they are passed to a variadic template. | |
31 */ | |
32 template TypeTupleWrapper(A...) | |
33 { | |
34 alias A tuple; | |
35 } | |
36 | |
37 | |
38 /** | |
39 Returns a tuple with T repeated count times. | |
40 */ | |
41 // TODO: generalize to accept any symbol | |
42 template Repeat(T, size_t count) | |
43 { | |
44 static if (count) | |
45 alias TypeTuple!(count, Repeat!(T, count - 1)) Repeat; | |
46 else | |
47 alias TypeTuple!() Repeat; | |
48 } | |
49 | |
50 /** | |
51 Returns the required number of function arguments, optional arguments excluded | |
52 */ | |
53 int requiredArgCount(alias fn)() { | |
54 alias ParameterTypeTuple!(typeof(&fn)) P; | |
55 P p; | |
56 static if (P.length == 0) | |
57 return 0; | |
58 | |
59 foreach(i, _; P) | |
60 { | |
61 static if (!__traits(compiles, fn(p[0..$-i-1]))) | |
62 { | |
63 return p.length - i; | |
64 } | |
65 } | |
66 return 0; | |
67 } | |
68 | |
69 /** | |
70 Returns true if is a delegate type. | |
71 */ | |
72 template isDelegate(T) | |
73 { | |
74 enum isDelegate = is(T == delegate); | |
75 } | |
76 | |
77 /** | |
78 Returns true if T is a function pointer type. | |
79 */ | |
80 template isFunctionPointer(T) | |
81 { | |
82 enum isFuntionPointer = is(typeof(*T.init) == function); | |
83 } | |
84 | |
85 /** | |
86 Returns true if entity is a function or function type. | |
87 */ | |
88 template isFunction(alias entity) | |
89 { | |
90 static if (is(entity)) | |
91 alias isFunction!(entity, void) isFunction; | |
92 else | |
93 enum isFunction = is(typeof(entity) == function); | |
94 } | |
95 | |
96 template isFunction(T, Dummy = void) | |
97 { | |
98 enum isFunction = is(T == function); | |
99 } | |
100 | |
101 | |
102 //TODO: hack | |
103 uint isModule(string str) | |
104 { | |
105 return startsWith(str, "module "); | |
106 } | |
107 | |
108 | |
109 template qualifiedCppName(T) | |
110 { | |
111 static if(!isModule(__traits(parent, T).stringof)) | |
112 enum qualifiedCppName = qualifiedCppName!(__traits(parent, T)) ~ "::" ~ T.stringof; | |
113 else | |
114 enum qualifiedCppName = T.stringof; | |
115 } | |
116 | |
117 template qualifiedName(T) | |
118 { | |
119 static if (!isModule(__traits(parent, T).stringof)) | |
120 enum qualifiedName = qualifiedName!(__traits(parent, T)) ~ "." ~ T.stringof; | |
121 else | |
122 enum qualifiedName = T.stringof; | |
123 } | |
124 | |
125 template fullName(T) | |
126 { | |
127 static if (is(T == enum)) | |
128 enum fullName = qualifiedName!T; | |
129 else | |
130 enum fullName = T.stringof; | |
131 } | |
132 | |
133 /** | |
134 */ | |
135 enum AttributeOptions | |
136 { | |
137 /** | |
138 */ | |
139 none, | |
140 | |
141 /** | |
142 Allows multiple equally named attributes to be associated with the symbol. | |
143 */ | |
144 allowMultiple = 0x0000_0001, | |
145 | |
146 /* internal */ inner = 0x0000_0002, | |
147 } | |
148 | |
149 /** | |
150 When mixed in an aggregate, converts a compile-time tuple to | |
151 members of that aggregate. | |
152 */ | |
153 mixin template tupleToMembers(string nameSpace, size_t index, A...) | |
154 { | |
155 static if (index < A.length) | |
156 { | |
157 enum indexStr = to!string(index); | |
158 | |
159 static if (is(typeof( { typeof(A[index]) x; }() ))) | |
160 mixin("typeof(A[" ~ indexStr ~ "]) " ~ nameSpace ~ indexStr ~ " = A[" ~ indexStr ~"];\n"); | |
161 else | |
162 mixin("alias Alias!(A[" ~ indexStr ~ "]) " ~ nameSpace ~ indexStr ~ ";\n"); | |
163 | |
164 mixin tupleToMembers!(nameSpace, index + 1, A); | |
165 } | |
166 } | |
167 | |
168 /** | |
169 When mixed in an aggregate, converts a compile-time tuple of name-value pairs to | |
170 members of that aggregate. | |
171 */ | |
172 mixin template NameValueTupleToFields(A...) | |
173 { | |
174 | |
175 } | |
176 | |
177 version (QtdUnittest) | |
178 { | |
179 unittest | |
180 { | |
181 static int foo() | |
182 { | |
183 return 42; | |
184 } | |
185 | |
186 static struct S | |
187 { | |
188 mixin tupleToMembers!("member", 0, | |
189 int, | |
190 "a", | |
191 22, | |
192 foo); | |
193 } | |
194 | |
195 static assert(is(S.member0 == int)); | |
196 S s; | |
197 assert(s.member1 == "a"); | |
198 assert(s.member2 == 22); | |
199 assert(S.member3() == 42); | |
200 } | |
201 } | |
202 | |
203 private template attributeId(alias symbol, uint index = 0) | |
204 { | |
205 enum attributeId = standardNamespace ~ "_attr_" ~ uniqueId!symbol ~ "_" ~ to!string(index); | |
206 } | |
207 | |
208 /** | |
209 Attributes allow to associate arbitrary compile-time data | |
210 with a declaration and optionaly make that data available at run-time. | |
211 | |
212 ---- | |
213 class A | |
214 { | |
215 } | |
216 mixin Attribute!(C, "someAttribute", "B"); | |
217 ---- | |
218 | |
219 The example above associates the string "B" with class A under the attribute name "someAttribute". | |
220 Multiple attributes with the same name can be associated with a single declaration. | |
221 | |
222 ---- | |
223 class A | |
224 { | |
225 } | |
226 mixin Attribute!(C, "someAttribute", "B"); | |
227 mixin Attribute!(C, "someAttribute", AttributeOptions.allowMultiple, "C"); | |
228 ---- | |
229 | |
230 Attributes can be accessed at compile-time as follows: | |
231 | |
232 ---- | |
233 alias GetAttributes!(C, "someAttribute") attrs; | |
234 ---- | |
235 | |
236 GetAttribute returns a static tuple, which contains "someAttribute" attributes in the form | |
237 of TypeTupleWrapper instances. The wrapped tuples have the following layout: | |
238 | |
239 [0] - attribute name | |
240 [1] - attribute options | |
241 [2..$] - attribute data | |
242 | |
243 ---- | |
244 alias attrs[0] attr0; | |
245 alias attrs[1] attr1; | |
246 | |
247 static assert(attrs0.tuple[0] == "someAttribute" && attrs0.tuple[2] == "B"); | |
248 static assert(attrs1.tuple[0] == "someAttribute" && attrs1.tuple[2] == "C"); | |
249 ---- | |
250 | |
251 Attributes can be inserted inside the body of a declaration. | |
252 ---- | |
253 class A | |
254 { | |
255 mixin Attribute!("someAttribute", "B"); | |
256 } | |
257 ---- | |
258 | |
259 Attributes can be made available at run time by means of the declaration's meta-object | |
260 ---- | |
261 // prints names of all attributes associated with class A | |
262 auto a = new A; | |
263 foreach (attr; a.metaObject.attributes) | |
264 writeln(attr.name); | |
265 ---- | |
266 | |
267 Attributes can be specialized | |
268 | |
269 ---- | |
270 mixin template DbFieldAttribute(alias prop, string columnName) | |
271 { | |
272 mixin Attribute!(prop, "DbFieldAttribute", columnName); | |
273 } | |
274 | |
275 class A | |
276 { | |
277 int value; | |
278 mixin DbFieldAttribute!(value, "Value"); | |
279 | |
280 int anotherValue; | |
281 mixin DbFieldAttribute!(anotherValue, "Value2"); | |
282 } | |
283 | |
284 assert(GetAttributes!(A.value, "DbFieldAttribute")[0].tuple[1] == "Value"); | |
285 assert(GetAttributes!(A.anotherValue, "DbFieldAttribute")[0].tuple[1] == "Value2"); | |
286 ---- | |
287 | |
288 */ | |
289 mixin template Attribute(alias symbol, string attrClass, A...) | |
290 { | |
291 mixin Attribute!(symbol, attrClass, AttributeOptions.none, A); | |
292 } | |
293 | |
294 /// ditto | |
295 mixin template Attribute(alias symbol, string attrClass, AttributeOptions opts, A...) | |
296 { | |
297 mixin AttributeImpl!(symbol, attrClass, opts, 0, A); | |
298 } | |
299 | |
300 | |
301 /// ditto | |
302 // TODO: probably make this an overload of Attribute | |
303 mixin template InnerAttribute(string attrClass, AttributeOptions opts, A...) | |
304 { | |
305 // BUG: needs to be generalized to accept any parent | |
306 mixin Attribute!(typeof(this), attrClass, opts | AttributeOptions.inner, A); | |
307 } | |
308 | |
309 /// ditto | |
310 mixin template InnerAttribute(string attrClass, A...) | |
311 { | |
312 mixin InnerAttribute!(attrClass, AttributeOptions.none, A); | |
313 } | |
314 | |
315 private mixin template AttributeImpl(alias symbol, string attrClass, AttributeOptions opts, size_t index, A...) | |
316 { | |
317 private enum attrId = attributeId!(symbol, index) ~ (opts & AttributeOptions.inner ? "_inner" : ""); | |
318 | |
319 static if (is(typeof(mixin(attrId)))) | |
320 { | |
321 mixin ("alias " ~ attrId ~ " attr;"); | |
322 static if (!(opts & AttributeOptions.allowMultiple)) | |
323 { | |
324 static assert (attr[0] != attrClass, "Multiple " ~ attrClass ~ " attributes are not allowed for " | |
325 ~ __traits(parent, symbol).stringof ~ "." ~ stringOf!symbol); | |
326 } | |
327 | |
328 mixin AttributeImpl!(symbol, attrClass, opts, index + 1, A); | |
329 } | |
330 else | |
331 { | |
332 mixin ("alias TypeTuple!(attrClass, opts, A) " ~ attrId ~ ";"); | |
333 } | |
334 } | |
335 | |
336 private string stringOfFunction(alias symbol)() | |
337 { | |
338 auto ptrType = typeof(&symbol).stringof; | |
339 auto paramList = ParameterTypeTuple!(symbol).stringof; | |
340 | |
341 string result = ReturnType!(symbol).stringof ~ " " ~ __traits(identifier, symbol) ~ paramList; | |
342 | |
343 if (ptrType[$ - 1] != ')') | |
344 { | |
345 for (size_t i = ptrType.length - 2;; --i) | |
346 { | |
347 if (ptrType[i] == ')') | |
348 { | |
349 result ~= ptrType[i + 1..$]; | |
350 break; | |
351 } | |
352 } | |
353 } | |
354 | |
355 return result; | |
356 } | |
357 | |
358 /** | |
359 String of any symbol, including functions | |
360 */ | |
361 template stringOf(alias symbol) | |
362 { | |
363 static if (isFunction!symbol) | |
364 enum stringOf = stringOfFunction!symbol; | |
365 else | |
366 enum stringOf = symbol.stringof; | |
367 } | |
368 | |
369 /** | |
370 Returns the string uniquely identifying the | |
371 symbol in its container. | |
372 */ | |
373 template uniqueName(alias symbol) | |
374 { | |
375 enum uniqueName = stringOf!symbol; | |
376 } | |
377 | |
378 // TODO: works only for simple types. implement | |
379 string uniqueIdImpl(string symbol) | |
380 { | |
381 char[] r = symbol.dup; | |
382 foreach (i, c; symbol) | |
383 { | |
384 if (c == '(' || c == ')' || c == ' ') | |
385 r[i] = '_'; | |
386 } | |
387 | |
388 return cast(immutable)r; | |
389 } | |
390 | |
391 /** | |
392 Returns a valid D identifier uniquely | |
393 identifying symbol in its container. | |
394 */ | |
395 template uniqueId(alias symbol) | |
396 { | |
397 enum uniqueId = uniqueIdImpl(stringOf!symbol); | |
398 } | |
399 | |
400 version (QtdUnittest) | |
401 { | |
402 unittest | |
403 { | |
404 static class C | |
405 { | |
406 void foo() const {}; | |
407 bool bar(int) { return true; }; | |
408 int x; | |
409 static assert (stringOf!foo == "void foo() const"); | |
410 static assert (uniqueName!foo == "void foo() const"); | |
411 static assert (stringOf!bar == "bool bar(int)"); | |
412 static assert (uniqueName!bar == "bool bar(int)"); | |
413 static assert (stringOf!x == "x"); | |
414 static assert (uniqueName!x == "x"); | |
415 } | |
416 | |
417 static assert (stringOf!(C.foo) == "void foo() const"); | |
418 static assert (uniqueName!(C.foo) == "void foo() const"); | |
419 static assert (stringOf!(C.bar) == "bool bar(int)"); | |
420 static assert (uniqueName!(C.bar) == "bool bar(int)"); | |
421 | |
422 static assert (stringOf!(C.x) == "x"); | |
423 static assert (uniqueName!(C.x) == "x"); | |
424 } | |
425 } | |
426 | |
427 /** | |
428 Predicate that always evaluates to true regardless of arguments. | |
429 */ | |
430 template truePred(A...) | |
431 { | |
432 enum truePred = true; | |
433 } | |
434 | |
435 private template attrNamePred(string name) | |
436 { | |
437 template attrNamePred(A...) | |
438 { | |
439 enum attrNamePred = A[0] == name; | |
440 } | |
441 } | |
442 | |
443 /** | |
444 Returns a compile-time tuple of attributes that | |
445 match pred. | |
446 */ | |
447 template GetAttributes(alias symbol, alias pred = truePred) | |
448 { | |
449 alias GetAttributesImpl!(symbol, 0, pred).result GetAttributes; | |
450 } | |
451 | |
452 /** | |
453 Returns a compile-time tuple of attributes | |
454 matching the specified attribute name. | |
455 */ | |
456 template GetAttributes(alias symbol, string attrName) | |
457 { | |
458 alias GetAttributes!(symbol, attrNamePred!attrName) GetAttributes; | |
459 } | |
460 | |
461 | |
462 template GetAttributesImpl(alias symbol, size_t index, alias pred) | |
463 { | |
464 //pragma(msg, mixin("symbol." ~ attributeId!(symbol, index) ~ "_inner").stringof); | |
465 static if (is(typeof(mixin("__traits(parent, symbol)." ~ attributeId!(symbol, index))))) | |
466 mixin ("alias Alias!(__traits(parent, symbol))." ~ attributeId!(symbol, index) ~ " attr;"); | |
467 else static if (is(typeof(mixin("symbol." ~ attributeId!(symbol, index) ~ "_inner")))) | |
468 mixin ("alias symbol." ~ attributeId!(symbol, index) ~ "_inner attr;"); | |
469 | |
470 static if (is(typeof(attr))) | |
471 { | |
472 alias GetAttributesImpl!(symbol, index + 1, pred).result next; | |
473 | |
474 static if (pred!attr) | |
475 alias TypeTuple!(TypeTupleWrapper!attr, next) result; | |
476 else | |
477 alias next result; | |
478 } | |
479 else | |
480 alias TypeTuple!() result; | |
481 } | |
482 | |
483 version (QtdUnittest) | |
484 { | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
485 mixin template QtdCustomAttribute(alias symbol, A...) |
351 | 486 { |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
487 mixin Attribute!(symbol, "QtdCustomAttribute", AttributeOptions.allowMultiple, A); |
351 | 488 } |
489 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
490 mixin template QtdCustomInnerAttribute(string name, alias value) |
351 | 491 { |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
492 mixin InnerAttribute!("QtdCustomInnerAttribute", AttributeOptions.allowMultiple, name, value); |
351 | 493 } |
494 | |
495 unittest | |
496 { | |
497 static class C | |
498 { | |
499 // inner C attributes | |
500 mixin InnerAttribute!("Inner", 33); // generic | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
501 mixin QtdCustomInnerAttribute!("version", 123); |
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
502 mixin QtdCustomInnerAttribute!("author", "James Bond"); |
351 | 503 |
504 | |
505 void foo() {}; | |
506 // foo attributes | |
507 mixin Attribute!(foo, "SomeAttribute", 42); | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
508 mixin QtdCustomAttribute!(foo, 1, 2); |
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
509 mixin QtdCustomAttribute!(foo, 3, 4); |
351 | 510 |
511 alias GetAttributes!(typeof(this), "Inner") innerAttrs; | |
512 static assert(innerAttrs[0].tuple[0] == "Inner"); | |
513 } | |
514 // outer C attribute | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
515 mixin QtdCustomAttribute!(C, 24); |
351 | 516 |
517 alias GetAttributes!(C, "Inner") innerAttrs; | |
518 static assert(innerAttrs[0].tuple[0] == "Inner" && innerAttrs[0].tuple[2] == 33); | |
519 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
520 alias GetAttributes!(C, "QtdCustomInnerAttribute") ciAttrs; |
351 | 521 static assert(ciAttrs[0].tuple[2] == "version" && ciAttrs[0].tuple[3] == 123); |
522 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
523 /+ Fails on Windows but passes on Linux |
351 | 524 alias GetAttributes!(C.foo, "SomeAttribute") someAttr; |
525 static assert(someAttr.length == 1); | |
526 static assert(someAttr[0].tuple[0] == "SomeAttribute"); | |
527 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
528 alias GetAttributes!(C.foo, "QtdCustomAttribute") myAttrs; |
351 | 529 |
530 //COMPILER BUG: cannot 'alias myAttrs[0].tuple myAttrs_0'; | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
531 |
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
532 static assert(myAttrs[0].tuple[0] == "QtdCustomAttribute"); |
351 | 533 static assert(myAttrs[0].tuple[2] == 1 && myAttrs[0].tuple[3] == 2); |
534 | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
535 static assert(myAttrs[1].tuple[0] == "QtdCustomAttribute"); |
351 | 536 static assert(myAttrs[1].tuple[2] == 3 && myAttrs[1].tuple[3] == 4); |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
537 +/ |
351 | 538 |
539 /+ BUG: Fails: local declarations cannot be accessed as parent.localDecl | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
540 alias GetAttributes!(C, "QtdCustomAttribute") myAttrs2; |
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
541 static assert(myAttrs2[0].tuple[0] == "QtdCustomAttribute"); |
351 | 542 static assert(myAttrs2[0].tuple[1] == 24); |
543 +/ | |
357
9784459f0750
An attempt (failed due to optlink) to improve locality of declarations exported from QtD executables
Max Samukha <maxter@spambox.com>
parents:
351
diff
changeset
|
544 |
351 | 545 } |
546 } |