1 /******************************************************************************* 2 3 Basic traits allowing to distinguish various types between each other. Any 4 more convoluted traits dedicated to specific type kinds should go in 5 dedicated modules. 6 7 NB: because this module is often used as purely compile-time dependency it 8 used built-in asserts instead of `ocean.core.Test` to reduce amount of 9 cyclic imports. `ocean.meta` modules in general are not supposed to 10 import anything outside of `ocean.meta`. 11 12 Copyright: 13 Copyright (C) 2017 dunnhumby Germany GmbH. All rights reserved. 14 15 License: 16 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 17 Alternatively, this file may be distributed under the terms of the Tango 18 3-Clause BSD License (see LICENSE_BSD.txt for details). 19 20 *******************************************************************************/ 21 22 module ocean.meta.traits.Basic; 23 24 import ocean.meta.types.Qualifiers; 25 import ocean.meta.types.Typedef; 26 27 /******************************************************************************* 28 29 Primitive types are the types from which one or multiple other types cannot 30 be derived from using the ``is()`` expression or corresponding template type 31 parameter specialisation. The following types are not primitive: 32 - arrays (static, dynamic and associative) and pointers, 33 - classes structs and unions, 34 - delegates, function pointers and functions (function pointer base types), 35 - enums and typedefs. 36 37 All other, including arithmetic and character types are primitive. Each 38 primitive type is represented by a D keyword. 39 ``void`` is a primitive type. Imaginary and complex numbers are considered 40 primitive types, too, which may be subject to discussion. 41 42 Params: 43 T = type to check 44 45 Returns: 46 `true` if `T` is a primitive type 47 48 *******************************************************************************/ 49 50 public template isPrimitiveType ( T ) 51 { 52 static immutable isPrimitiveType = 53 is(Unqual!(T) == void) 54 || is(Unqual!(T) == bool) 55 || isIntegerType!(T) 56 || isCharType!(T) 57 || isFloatingPointType!(T); 58 } 59 60 /// 61 unittest 62 { 63 static assert ( isPrimitiveType!(int)); 64 static assert (!isPrimitiveType!(int*)); 65 struct S { } 66 static assert (!isPrimitiveType!(S)); 67 } 68 69 /******************************************************************************* 70 71 Params: 72 T = type to check 73 74 Returns: 75 `true` if `T` is one of supported string element types 76 77 *******************************************************************************/ 78 79 public template isCharType ( T ) 80 { 81 static immutable bool isCharType = 82 is(Unqual!(T) == char) 83 || is(Unqual!(T) == wchar) 84 || is(Unqual!(T) == dchar); 85 } 86 87 /// 88 unittest 89 { 90 static assert ( isCharType!(wchar)); 91 static assert ( isCharType!(const(char))); 92 static assert (!isCharType!(byte)); 93 } 94 95 /******************************************************************************* 96 97 Params: 98 T = type to check 99 100 Returns: 101 `true` if `T` is a built-in signed integer type 102 103 *******************************************************************************/ 104 105 public template isSignedIntegerType ( T ) 106 { 107 static immutable bool isSignedIntegerType = 108 is(Unqual!(T) == byte) 109 || is(Unqual!(T) == short) 110 || is(Unqual!(T) == int) 111 || is(Unqual!(T) == long); 112 } 113 114 /// 115 unittest 116 { 117 static assert ( isSignedIntegerType!(int)); 118 static assert ( isSignedIntegerType!(const(long))); 119 static assert (!isSignedIntegerType!(ubyte)); 120 } 121 122 /******************************************************************************* 123 124 Params: 125 T = type to check 126 127 Returns: 128 `true` if `T` is a built-in unsigned integer type 129 130 *******************************************************************************/ 131 132 public template isUnsignedIntegerType ( T ) 133 { 134 static immutable bool isUnsignedIntegerType = 135 is(Unqual!(T) == ubyte) 136 || is(Unqual!(T) == ushort) 137 || is(Unqual!(T) == uint) 138 || is(Unqual!(T) == ulong); 139 } 140 141 /// 142 unittest 143 { 144 static assert (!isUnsignedIntegerType!(int)); 145 static assert ( isUnsignedIntegerType!(ubyte)); 146 static assert ( isUnsignedIntegerType!(const(ulong))); 147 } 148 149 /******************************************************************************* 150 151 Params: 152 T = type to check 153 154 Returns: 155 `true` if `T` is a built-in integer type 156 157 *******************************************************************************/ 158 159 public template isIntegerType ( T ) 160 { 161 static immutable bool isIntegerType = 162 isSignedIntegerType!(T) 163 || isUnsignedIntegerType!(T); 164 } 165 166 /// 167 unittest 168 { 169 static assert ( isIntegerType!(long)); 170 static assert ( isIntegerType!(ubyte)); 171 static assert (!isIntegerType!(char)); 172 } 173 174 /******************************************************************************* 175 176 Params: 177 T = type to check 178 179 Returns: 180 `true` if `T` is a built-in floating point type, excluding 181 complex/imaginary ones 182 183 *******************************************************************************/ 184 185 public template isRealType ( T ) 186 { 187 static immutable bool isRealType = 188 is( Unqual!(T) == float ) 189 || is( Unqual!(T) == double ) 190 || is( Unqual!(T) == real ); 191 } 192 193 /// 194 unittest 195 { 196 static assert ( isRealType!(double)); 197 static assert (!isRealType!(long)); 198 static assert (!isRealType!(cdouble)); 199 } 200 201 202 /******************************************************************************* 203 204 Params: 205 T = type to check 206 207 Returns: 208 `true` if `T` is a built-in complex floating point type 209 210 *******************************************************************************/ 211 212 public template isComplexType( T ) 213 { 214 static immutable bool isComplexType = 215 is( Unqual!(T) == cfloat ) 216 || is( Unqual!(T) == cdouble ) 217 || is( Unqual!(T) == creal ); 218 } 219 220 /// 221 unittest 222 { 223 static assert ( isComplexType!(cdouble)); 224 static assert ( isComplexType!(const(cdouble))); 225 static assert (!isComplexType!(double)); 226 } 227 228 /******************************************************************************* 229 230 Params: 231 T = type to check 232 233 Returns: 234 `true` if `T` is a built-in imaginary floating point type 235 236 *******************************************************************************/ 237 238 public template isImaginaryType( T ) 239 { 240 static immutable bool isImaginaryType = 241 is( Unqual!(T) == ifloat ) 242 || is( Unqual!(T) == idouble ) 243 || is( Unqual!(T) == ireal ); 244 } 245 246 /// 247 unittest 248 { 249 static assert ( isImaginaryType!(idouble)); 250 static assert ( isImaginaryType!(const(idouble))); 251 static assert (!isImaginaryType!(double)); 252 } 253 254 /******************************************************************************* 255 256 Params: 257 T = type to check 258 259 Returns: 260 `true` if `T` is any built-in floating-point type: real, complex, or 261 imaginary. 262 263 *******************************************************************************/ 264 265 public template isFloatingPointType( T ) 266 { 267 static immutable bool isFloatingPointType = 268 isRealType!(T) 269 || isComplexType!(T) 270 || isImaginaryType!(T); 271 } 272 273 /// 274 unittest 275 { 276 static assert (isFloatingPointType!(double)); 277 static assert (isFloatingPointType!(ifloat)); 278 } 279 280 /******************************************************************************* 281 282 Used by other traits to distinguish between dynamic and static arrays 283 instead of plain `bool` values. 284 285 `ArrayKind.NotArray` is explicitly defined to have value `0` so that it can 286 be in regular condition, i.e. `static if (isArrayType!(T))`. 287 288 *******************************************************************************/ 289 290 public enum ArrayKind 291 { 292 NotArray = 0, 293 Static = 1, 294 Dynamic = 2, 295 Associative = 3, 296 } 297 298 /******************************************************************************* 299 300 Check if type is an array type and which kind of array it is 301 302 Params: 303 T = type to check 304 305 Returns: 306 `ArrayKind` value indicating if `T` is an array and if it is, static or 307 dynamic 308 309 *******************************************************************************/ 310 311 public template isArrayType ( T ) 312 { 313 static if (is(Unqual!(T) U == U[])) 314 static immutable isArrayType = ArrayKind.Dynamic; 315 else static if (is(Unqual!(T) U : U[])) 316 static immutable isArrayType = ArrayKind.Static; 317 else static if (is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == 318 Unqual!(T))) 319 static immutable isArrayType = ArrayKind.Associative; 320 else 321 static immutable isArrayType = ArrayKind.NotArray; 322 } 323 324 /// 325 unittest 326 { 327 static assert ( isArrayType!(char[15]) == ArrayKind.Static); 328 static assert ( isArrayType!(char[]) == ArrayKind.Dynamic); 329 static assert ( isArrayType!(char[][5]) == ArrayKind.Static); 330 static assert ( isArrayType!(char) == ArrayKind.NotArray); 331 static assert ( isArrayType!(int[int]) == ArrayKind.Associative); 332 static assert ( isArrayType!(const(int[int])) == ArrayKind.Associative); 333 static assert (!isArrayType!(char)); 334 } 335 336 unittest 337 { 338 static struct S { } 339 static assert (!isArrayType!(S)); 340 static assert ( isArrayType!(S[5])); 341 } 342 343 /******************************************************************************* 344 345 Params: 346 T = any type 347 348 Returns: 349 `true` if T is static or dynamic array, `false` otherwise 350 351 *******************************************************************************/ 352 353 public template isBasicArrayType ( T ) 354 { 355 static immutable isBasicArrayType = 356 (isArrayType!(T) == ArrayKind.Static) 357 || (isArrayType!(T) == ArrayKind.Dynamic); 358 } 359 360 /// 361 unittest 362 { 363 static assert ( isBasicArrayType!(int[])); 364 static assert ( isBasicArrayType!(int[5])); 365 static assert (!isBasicArrayType!(int[int])); 366 } 367 368 /******************************************************************************* 369 370 Params: 371 T = static array type 372 373 Returns: 374 for static array T[N] returns N 375 376 *******************************************************************************/ 377 378 public template staticArrayLength ( T : U[Dim], U, size_t Dim ) 379 { 380 static immutable staticArrayLength = Dim; 381 } 382 383 unittest 384 { 385 static assert (staticArrayLength!(int[][5]) == 5); 386 static assert (staticArrayLength!(char[42]) == 42); 387 static assert (staticArrayLength!(immutable(mstring[2])) == 2); 388 } 389 390 /******************************************************************************* 391 392 Params: 393 T = type to check 394 395 Returns: 396 `true` if `T` is a pointer type. 397 398 *******************************************************************************/ 399 400 template isPointerType ( T ) 401 { 402 static if (is(Unqual!(T) U == U*)) 403 static immutable isPointerType = true; 404 else 405 static immutable isPointerType = false; 406 } 407 408 /// 409 unittest 410 { 411 static assert ( isPointerType!(void*)); 412 static assert (!isPointerType!(char[])); 413 } 414 415 unittest 416 { 417 static assert ( isPointerType!(char[]*)); 418 static assert (!isPointerType!(char*[])); 419 static assert ( isPointerType!(const(real)*)); 420 static assert (!isPointerType!(uint)); 421 422 class Ham { void* a; } 423 424 static assert (!isPointerType!(Ham)); 425 426 union Eggs 427 { 428 void* a; 429 uint b; 430 } 431 432 static assert (!isPointerType!(Eggs)); 433 static assert ( isPointerType!(immutable(Eggs*))); 434 435 struct Bacon { } 436 437 static assert (!isPointerType!(Bacon)); 438 439 // function pointer is a pointer, but delegate is not: 440 void foo () {} 441 static void bar () {} 442 static assert (!isPointerType!(typeof(&foo))); 443 static assert ( isPointerType!(typeof(&bar))); 444 } 445 446 /******************************************************************************* 447 448 Params: 449 T = type to check 450 451 Returns: 452 `true` if `T` is a struct, class, interface or union 453 454 *******************************************************************************/ 455 456 template isReferenceType ( T ) 457 { 458 static immutable isReferenceType = 459 isPointerType!(T) 460 || is(T == delegate) 461 || isArrayType!(T) == ArrayKind.Dynamic 462 || isArrayType!(T) == ArrayKind.Associative 463 || is(T == class) 464 || is(T == interface); 465 } 466 467 /// 468 unittest 469 { 470 struct S { } 471 class C { } 472 interface I { } 473 474 static assert (!isReferenceType!(S)); 475 static assert ( isReferenceType!(S*)); 476 static assert ( isReferenceType!(S[])); 477 static assert ( isReferenceType!(C)); 478 static assert ( isReferenceType!(I)); 479 static assert ( isReferenceType!(S[C])); 480 static assert ( isReferenceType!(void function(int))); 481 482 static void foo ( ) { } 483 static assert (!isReferenceType!(typeof(foo))); 484 } 485 486 /******************************************************************************* 487 488 Params: 489 T = type to check 490 491 Returns: 492 `true` if `T` is a struct, class, interface or union 493 494 *******************************************************************************/ 495 496 template isAggregateType ( T ) 497 { 498 static immutable isAggregateType = 499 is(T == class) 500 || is(T == interface) 501 || is(T == struct) 502 || is(T == union); 503 } 504 505 /// 506 unittest 507 { 508 struct S { int x; } 509 union U { int x; double y; } 510 511 static assert ( isAggregateType!(S)); 512 static assert ( isAggregateType!(U)); 513 static assert (!isAggregateType!(S[2])); 514 } 515 516 /******************************************************************************* 517 518 Params: 519 T = type to check 520 521 Returns: 522 `true` if T is a function, function pointer or delegate 523 524 *******************************************************************************/ 525 526 template isFunctionType ( T ) 527 { 528 static immutable bool isFunctionType = 529 is(T == function) 530 || is(typeof(*T.init) == function) 531 || is(T == delegate); 532 } 533 534 /// 535 unittest 536 { 537 void foo1() { } 538 auto foo2 = () { }; 539 static void foo3() { } 540 541 static assert (isFunctionType!(typeof(&foo1))); 542 static assert (isFunctionType!(typeof(foo2))); 543 static assert (isFunctionType!(typeof(&foo3))); 544 static assert (isFunctionType!(typeof(foo3))); 545 } 546 547 unittest 548 { 549 static real func(ref int) { return 0; } 550 void nestedFunc() { } 551 class C 552 { 553 real method(ref int) { return 0; } 554 } 555 auto c = new C; 556 auto fp = &func; 557 auto dg = &c.method; 558 real val; 559 560 static assert ( isFunctionType!(typeof(func))); 561 static assert ( isFunctionType!(typeof(nestedFunc))); 562 static assert ( isFunctionType!(typeof(C.method))); 563 static assert ( isFunctionType!(typeof(fp))); 564 static assert ( isFunctionType!(typeof(dg))); 565 static assert ( isFunctionType!(real function(ref int))); 566 static assert ( isFunctionType!(real delegate(ref int))); 567 static assert ( isFunctionType!(typeof((int a) { return a; }))); 568 569 static assert (!isFunctionType!(int)); 570 static assert (!isFunctionType!(typeof(val))); 571 } 572 573 /******************************************************************************* 574 575 Params: 576 T = type to check 577 578 Returns: 579 `true` if T is a function, function pointer or delegate or callable 580 aggregate 581 582 *******************************************************************************/ 583 584 template isCallableType ( T ) 585 { 586 static if (is(typeof(T.opCall))) 587 static immutable isCallableType = isFunctionType!(typeof(&T.init.opCall)); 588 else 589 static immutable isCallableType = isFunctionType!(T); 590 } 591 592 /// 593 unittest 594 { 595 struct S 596 { 597 void opCall (int) { } 598 } 599 600 static assert (isCallableType!(S)); 601 static assert (isCallableType!(typeof(S.opCall))); 602 } 603 604 unittest 605 { 606 struct S2 607 { 608 static bool opCall( in int p1, in int p2 ) { return true; } 609 } 610 611 static assert (isCallableType!(S2)); 612 } 613 614 /******************************************************************************* 615 616 Used as result type for `isTypedef` trait. 617 618 `None` value is explicitly set to `0` so that it can be used in condition 619 like `if(isTypedef!(T))`. 620 621 *******************************************************************************/ 622 623 public enum TypedefKind 624 { 625 /// Not a typedef 626 None = 0, 627 /// D1 `typedef` keyword 628 Keyword, 629 /// Emulated by struct 630 Struct 631 } 632 633 /******************************************************************************* 634 635 Determines if T is a typedef of some kind 636 637 Params: 638 T = type to check 639 640 Evaluates to: 641 `TypedefKind` value which is non-zero is T is some typedef 642 643 *******************************************************************************/ 644 645 public template isTypedef (T) 646 { 647 static if (is(T.IsTypedef)) 648 static immutable isTypedef = TypedefKind.Struct; 649 else 650 static immutable isTypedef = TypedefKind.None; 651 } 652 653 unittest 654 { 655 mixin(Typedef!(double, "RealNum")); 656 657 static assert(!isTypedef!(int)); 658 static assert(!isTypedef!(double)); 659 static assert( isTypedef!(RealNum)); 660 661 static assert(isTypedef!(RealNum) == TypedefKind.Struct); 662 } 663 664 /****************************************************************************** 665 666 Check if the type of a member inside a struct or class is a D manifest 667 constant 668 669 Params: 670 T = The struct that will be checked 671 name = The struct member that will be checked 672 673 ******************************************************************************/ 674 675 bool isManifestConstant ( T, string name ) ( ) 676 { 677 T instance; 678 mixin(`return is(typeof(instance.`~name~`)) && !is(typeof(&instance.`~name~`));`); 679 } 680 681 unittest 682 { 683 struct Test 684 { 685 enum manifest = 2; 686 int notManifest1; 687 enum CustomType : int { 688 a = 1, b = 2 689 } 690 691 CustomType notManifest2; 692 } 693 694 static assert(isManifestConstant!(Test, "manifest")); 695 static assert(!isManifestConstant!(Test, "CustomType")); 696 static assert(!isManifestConstant!(Test, "notManifest1")); 697 static assert(!isManifestConstant!(Test, "notManifest2")); 698 } 699 700 701 702 /****************************************************************************** 703 704 Check if a constant is manifest constant 705 706 Params: 707 T = The constant 708 709 ******************************************************************************/ 710 711 bool isManifestConstant ( alias T ) ( ) 712 { 713 return is(typeof(T)) && !is(typeof(&T)); 714 } 715 716 unittest 717 { 718 enum manifest = 3; 719 int notManifest; 720 721 static assert(isManifestConstant!(manifest)); 722 static assert(!isManifestConstant!(notManifest)); 723 }