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