Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

root/tags/releases/0.99.9/tango/core/Traits.d

Revision 5267, 14.5 kB (checked in by larsivi, 2 years ago)

Added ExprOfType?, thanks Abscissa, closes #1737

  • Property svn:mime-type set to text/x-dsrc
  • Property svn:eol-style set to native
Line 
1 /**
2  * The traits module defines tools useful for obtaining detailed compile-time
3  * information about a type.  Please note that the mixed naming scheme used in
4  * this module is intentional.  Templates which evaluate to a type follow the
5  * naming convention used for types, and templates which evaluate to a value
6  * follow the naming convention used for functions.
7  *
8  * Copyright: Copyright (C) 2005-2006 Sean Kelly.  All rights reserved.
9  * License:   BSD style: $(LICENSE)
10  * Authors:   Sean Kelly, Fawzi Mohamed
11  */
12 module tango.core.Traits;
13
14
15 /**
16  * Evaluates to true if T is char, wchar, or dchar.
17  */
18 template isCharType( T )
19 {
20     const bool isCharType = is( T == char )  ||
21                             is( T == wchar ) ||
22                             is( T == dchar );
23 }
24
25
26 /**
27  * Evaluates to true if T is a signed integer type.
28  */
29 template isSignedIntegerType( T )
30 {
31     const bool isSignedIntegerType = is( T == byte )  ||
32                                      is( T == short ) ||
33                                      is( T == int )   ||
34                                      is( T == long )/+||
35                                      is( T == cent  )+/;
36 }
37
38
39 /**
40  * Evaluates to true if T is an unsigned integer type.
41  */
42 template isUnsignedIntegerType( T )
43 {
44     const bool isUnsignedIntegerType = is( T == ubyte )  ||
45                                        is( T == ushort ) ||
46                                        is( T == uint )   ||
47                                        is( T == ulong )/+||
48                                        is( T == ucent  )+/;
49 }
50
51
52 /**
53  * Evaluates to true if T is a signed or unsigned integer type.
54  */
55 template isIntegerType( T )
56 {
57     const bool isIntegerType = isSignedIntegerType!(T) ||
58                                isUnsignedIntegerType!(T);
59 }
60
61
62 /**
63  * Evaluates to true if T is a real floating-point type.
64  */
65 template isRealType( T )
66 {
67     const bool isRealType = is( T == float )  ||
68                             is( T == double ) ||
69                             is( T == real );
70 }
71
72
73 /**
74  * Evaluates to true if T is a complex floating-point type.
75  */
76 template isComplexType( T )
77 {
78     const bool isComplexType = is( T == cfloat )  ||
79                                is( T == cdouble ) ||
80                                is( T == creal );
81 }
82
83
84 /**
85  * Evaluates to true if T is an imaginary floating-point type.
86  */
87 template isImaginaryType( T )
88 {
89     const bool isImaginaryType = is( T == ifloat )  ||
90                                  is( T == idouble ) ||
91                                  is( T == ireal );
92 }
93
94
95 /**
96  * Evaluates to true if T is any floating-point type: real, complex, or
97  * imaginary.
98  */
99 template isFloatingPointType( T )
100 {
101     const bool isFloatingPointType = isRealType!(T)    ||
102                                      isComplexType!(T) ||
103                                      isImaginaryType!(T);
104 }
105
106 /// true if T is an atomic type
107 template isAtomicType(T)
108 {
109     static if( is( T == bool )
110             || is( T == char )
111             || is( T == wchar )
112             || is( T == dchar )
113             || is( T == byte )
114             || is( T == short )
115             || is( T == int )
116             || is( T == long )
117             || is( T == ubyte )
118             || is( T == ushort )
119             || is( T == uint )
120             || is( T == ulong )
121             || is( T == float )
122             || is( T == double )
123             || is( T == real )
124             || is( T == ifloat )
125             || is( T == idouble )
126             || is( T == ireal ) )
127         const isAtomicType = true;
128     else
129         const isAtomicType = false;
130 }
131
132 /**
133  * complex type for the given type
134  */
135 template ComplexTypeOf(T){
136     static if(is(T==float)||is(T==ifloat)||is(T==cfloat)){
137         alias cfloat ComplexTypeOf;
138     } else static if(is(T==double)|| is(T==idouble)|| is(T==cdouble)){
139         alias cdouble ComplexTypeOf;
140     } else static if(is(T==real)|| is(T==ireal)|| is(T==creal)){
141         alias creal ComplexTypeOf;
142     } else static assert(0,"unsupported type in ComplexTypeOf "~T.stringof);
143 }
144
145 /**
146  * real type for the given type
147  */
148 template RealTypeOf(T){
149     static if(is(T==float)|| is(T==ifloat)|| is(T==cfloat)){
150         alias float RealTypeOf;
151     } else static if(is(T==double)|| is(T==idouble)|| is(T==cdouble)){
152         alias double RealTypeOf;
153     } else static if(is(T==real)|| is(T==ireal)|| is(T==creal)){
154         alias real RealTypeOf;
155     } else static assert(0,"unsupported type in RealTypeOf "~T.stringof);
156 }
157
158 /**
159  * imaginary type for the given type
160  */
161 template ImaginaryTypeOf(T){
162     static if(is(T==float)|| is(T==ifloat)|| is(T==cfloat)){
163         alias ifloat ImaginaryTypeOf;
164     } else static if(is(T==double)|| is(T==idouble)|| is(T==cdouble)){
165         alias idouble ImaginaryTypeOf;
166     } else static if(is(T==real)|| is(T==ireal)|| is(T==creal)){
167         alias ireal ImaginaryTypeOf;
168     } else static assert(0,"unsupported type in ImaginaryTypeOf "~T.stringof);
169 }
170
171 /// type with maximum precision
172 template MaxPrecTypeOf(T){
173     static if (isComplexType!(T)){
174         alias creal MaxPrecTypeOf;
175     } else static if (isImaginaryType!(T)){
176         alias ireal MaxPrecTypeOf;
177     } else {
178         alias real MaxPrecTypeOf;
179     }
180 }
181
182
183 /**
184  * Evaluates to true if T is a pointer type.
185  */
186 template isPointerType(T)
187 {
188         const isPointerType = false;
189 }
190
191 template isPointerType(T : T*)
192 {
193         const isPointerType = true;
194 }
195
196 debug( UnitTest )
197 {
198     unittest
199     {
200         static assert( isPointerType!(void*) );
201         static assert( !isPointerType!(char[]) );
202         static assert( isPointerType!(char[]*) );
203         static assert( !isPointerType!(char*[]) );
204         static assert( isPointerType!(real*) );
205         static assert( !isPointerType!(uint) );
206         static assert( is(MaxPrecTypeOf!(float)==real));
207         static assert( is(MaxPrecTypeOf!(cfloat)==creal));
208         static assert( is(MaxPrecTypeOf!(ifloat)==ireal));
209
210         class Ham
211         {
212             void* a;
213         }
214
215         static assert( !isPointerType!(Ham) );
216
217         union Eggs
218         {
219             void* a;
220             uint  b;
221         };
222
223         static assert( !isPointerType!(Eggs) );
224         static assert( isPointerType!(Eggs*) );
225
226         struct Bacon {};
227
228         static assert( !isPointerType!(Bacon) );
229
230     }
231 }
232
233 /**
234  * Evaluates to true if T is a a pointer, class, interface, or delegate.
235  */
236 template isReferenceType( T )
237 {
238
239     const bool isReferenceType = isPointerType!(T)  ||
240                                is( T == class )     ||
241                                is( T == interface ) ||
242                                is( T == delegate );
243 }
244
245
246 /**
247  * Evaulates to true if T is a dynamic array type.
248  */
249 template isDynamicArrayType( T )
250 {
251     const bool isDynamicArrayType = is( typeof(T.init[0])[] == T );
252 }
253
254 /**
255  * Evaluates to true if T is a static array type.
256  */
257 version( GNU )
258 {
259     // GDC should also be able to use the other version, but it probably
260     // relies on a frontend fix in one of the latest DMD versions - will
261     // remove this when GDC is ready. For now, this code pass the unittests.
262     private template isStaticArrayTypeInst( T )
263     {
264         const T isStaticArrayTypeInst = void;
265     }
266
267     template isStaticArrayType( T )
268     {
269         static if( is( typeof(T.length) ) && !is( typeof(T) == typeof(T.init) ) )
270         {
271             const bool isStaticArrayType = is( T == typeof(T[0])[isStaticArrayTypeInst!(T).length] );
272         }
273         else
274         {
275             const bool isStaticArrayType = false;
276         }
277     }
278 }
279 else
280 {
281     template isStaticArrayType( T : T[U], size_t U )
282     {
283         const bool isStaticArrayType = true;
284     }
285
286     template isStaticArrayType( T )
287     {
288         const bool isStaticArrayType = false;
289     }
290 }
291
292 /// true for array types
293 template isArrayType(T)
294 {
295     static if (is( T U : U[] ))
296         const bool isArrayType=true;
297     else
298         const bool isArrayType=false;
299 }
300
301 debug( UnitTest )
302 {
303     unittest
304     {
305         static assert( isStaticArrayType!(char[5][2]) );
306         static assert( !isDynamicArrayType!(char[5][2]) );
307         static assert( isArrayType!(char[5][2]) );
308
309         static assert( isStaticArrayType!(char[15]) );
310         static assert( !isStaticArrayType!(char[]) );
311
312         static assert( isDynamicArrayType!(char[]) );
313         static assert( !isDynamicArrayType!(char[15]) );
314
315         static assert( isArrayType!(char[15]) );
316         static assert( isArrayType!(char[]) );
317         static assert( !isArrayType!(char) );
318     }
319 }
320
321 /**
322  * Evaluates to true if T is an associative array type.
323  */
324 template isAssocArrayType( T )
325 {
326     const bool isAssocArrayType = is( typeof(T.init.values[0])[typeof(T.init.keys[0])] == T );
327 }
328
329
330 /**
331  * Evaluates to true if T is a function, function pointer, delegate, or
332  * callable object.
333  */
334 template isCallableType( T )
335 {
336     const bool isCallableType = is( T == function )             ||
337                                 is( typeof(*T) == function )    ||
338                                 is( T == delegate )             ||
339                                 is( typeof(T.opCall) == function );
340 }
341
342
343 /**
344  * Evaluates to the return type of Fn.  Fn is required to be a callable type.
345  */
346 template ReturnTypeOf( Fn )
347 {
348     static if( is( Fn Ret == return ) )
349         alias Ret ReturnTypeOf;
350     else
351         static assert( false, "Argument has no return type." );
352 }
353
354 /**
355  * Returns the type that a T would evaluate to in an expression.
356  * Expr is not required to be a callable type
357  */
358 template ExprTypeOf( Expr )
359 {
360     static if(isCallableType!( Expr ))
361         alias ReturnTypeOf!( Expr ) ExprTypeOf;
362     else
363         alias Expr ExprTypeOf;
364 }
365
366
367 /**
368  * Evaluates to the return type of fn.  fn is required to be callable.
369  */
370 template ReturnTypeOf( alias fn )
371 {
372     static if( is( typeof(fn) Base == typedef ) )
373         alias ReturnTypeOf!(Base) ReturnTypeOf;
374     else
375         alias ReturnTypeOf!(typeof(fn)) ReturnTypeOf;
376 }
377
378
379 /**
380  * Evaluates to a tuple representing the parameters of Fn.  Fn is required to
381  * be a callable type.
382  */
383 template ParameterTupleOf( Fn )
384 {
385     static if( is( Fn Params == function ) )
386         alias Params ParameterTupleOf;
387     else static if( is( Fn Params == delegate ) )
388         alias ParameterTupleOf!(Params) ParameterTupleOf;
389     else static if( is( Fn Params == Params* ) )
390         alias ParameterTupleOf!(Params) ParameterTupleOf;
391     else
392         static assert( false, "Argument has no parameters." );
393 }
394
395
396 /**
397  * Evaluates to a tuple representing the parameters of fn.  n is required to
398  * be callable.
399  */
400 template ParameterTupleOf( alias fn )
401 {
402     static if( is( typeof(fn) Base == typedef ) )
403         alias ParameterTupleOf!(Base) ParameterTupleOf;
404     else
405         alias ParameterTupleOf!(typeof(fn)) ParameterTupleOf;
406 }
407
408
409 /**
410  * Evaluates to a tuple representing the ancestors of T.  T is required to be
411  * a class or interface type.
412  */
413 template BaseTypeTupleOf( T )
414 {
415     static if( is( T Base == super ) )
416         alias Base BaseTypeTupleOf;
417     else
418         static assert( false, "Argument is not a class or interface." );
419 }
420
421 /**
422  * Strips the []'s off of a type.
423  */
424 template BaseTypeOfArrays(T)
425 {
426     static if( is( T S : S[]) ) {
427         alias BaseTypeOfArrays!(S)  BaseTypeOfArrays;
428     }
429     else {
430         alias T BaseTypeOfArrays;
431     }
432 }
433
434 /**
435  * strips one [] off a type
436  */
437 template ElementTypeOfArray(T:T[])
438 {
439     alias T ElementTypeOfArray;
440 }
441
442 /**
443  * Count the []'s on an array type
444  */
445 template rankOfArray(T) {
446     static if(is(T S : S[])) {
447         const uint rankOfArray = 1 + rankOfArray!(S);
448     } else {
449         const uint rankOfArray = 0;
450     }
451 }
452
453 /// type of the keys of an AA
454 template KeyTypeOfAA(T){
455     alias typeof(T.init.keys[0]) KeyTypeOfAA;
456 }
457
458 /// type of the values of an AA
459 template ValTypeOfAA(T){
460     alias typeof(T.init.values[0]) ValTypeOfAA;
461 }
462
463 /// returns the size of a static array
464 template staticArraySize(T)
465 {
466     static assert(isStaticArrayType!(T),"staticArraySize needs a static array as type");
467     static assert(rankOfArray!(T)==1,"implemented only for 1d arrays...");
468     const size_t staticArraySize=(T).sizeof / typeof(T.init).sizeof;
469 }
470
471 /// is T is static array returns a dynamic array, otherwise returns T
472 template DynamicArrayType(T)
473 {
474     static if( isStaticArrayType!(T) )
475         alias typeof(T.dup) DynamicArrayType;
476     else
477         alias T DynamicArrayType;
478 }
479
480 debug( UnitTest )
481 {
482     static assert( is(BaseTypeOfArrays!(real[][])==real) );
483     static assert( is(BaseTypeOfArrays!(real[2][3])==real) );
484     static assert( is(ElementTypeOfArray!(real[])==real) );
485     static assert( is(ElementTypeOfArray!(real[][])==real[]) );
486     static assert( is(ElementTypeOfArray!(real[2][])==real[2]) );
487     static assert( is(ElementTypeOfArray!(real[2][2])==real[2]) );
488     static assert( rankOfArray!(real[][])==2 );
489     static assert( rankOfArray!(real[2][])==2 );
490     static assert( is(ValTypeOfAA!(char[int])==char));
491     static assert( is(KeyTypeOfAA!(char[int])==int));
492     static assert( is(ValTypeOfAA!(char[][int])==char[]));
493     static assert( is(KeyTypeOfAA!(char[][int[]])==int[]));
494     static assert( isAssocArrayType!(char[][int[]]));
495     static assert( !isAssocArrayType!(char[]));
496     static assert( is(DynamicArrayType!(char[2])==DynamicArrayType!(char[])));
497     static assert( is(DynamicArrayType!(char[2])==char[]));
498     static assert( staticArraySize!(char[2])==2);
499 }
500
501 // ------- CTFE -------
502
503 /// compile time integer to string
504 char [] ctfe_i2a(int i){
505     char[] digit="0123456789";
506     char[] res="";
507     if (i==0){
508         return "0";
509     }
510     bool neg=false;
511     if (i<0){
512         neg=true;
513         i=-i;
514     }
515     while (i>0) {
516         res=digit[i%10]~res;
517         i/=10;
518     }
519     if (neg)
520         return '-'~res;
521     else
522         return res;
523 }
524 /// ditto
525 char [] ctfe_i2a(long i){
526     char[] digit="0123456789";
527     char[] res="";
528     if (i==0){
529         return "0";
530     }
531     bool neg=false;
532     if (i<0){
533         neg=true;
534         i=-i;
535     }
536     while (i>0) {
537         res=digit[cast(size_t)(i%10)]~res;
538         i/=10;
539     }
540     if (neg)
541         return '-'~res;
542     else
543         return res;
544 }
545 /// ditto
546 char [] ctfe_i2a(uint i){
547     char[] digit="0123456789";
548     char[] res="";
549     if (i==0){
550         return "0";
551     }
552     bool neg=false;
553     while (i>0) {
554         res=digit[i%10]~res;
555         i/=10;
556     }
557     return res;
558 }
559 /// ditto
560 char [] ctfe_i2a(ulong i){
561     char[] digit="0123456789";
562     char[] res="";
563     if (i==0){
564         return "0";
565     }
566     bool neg=false;
567     while (i>0) {
568         res=digit[cast(size_t)(i%10)]~res;
569         i/=10;
570     }
571     return res;
572 }
573
574 debug( UnitTest )
575 {
576     unittest {
577     static assert( ctfe_i2a(31)=="31" );
578     static assert( ctfe_i2a(-31)=="-31" );
579     static assert( ctfe_i2a(14u)=="14" );
580     static assert( ctfe_i2a(14L)=="14" );
581     static assert( ctfe_i2a(14UL)=="14" );
582     }
583 }
Note: See TracBrowser for help on using the browser.