comparison d2/qtd/meta/Compiletime.d @ 351:59d847a814e3

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