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 struct Converts { double value; alias value this; } 197 198 static assert ( isRealType!(double)); 199 static assert (!isRealType!(long)); 200 static assert (!isRealType!(Converts)); 201 } 202 203 204 /******************************************************************************* 205 206 Params: 207 T = type to check 208 209 Returns: 210 `true` if `T` is a built-in complex floating point type 211 212 *******************************************************************************/ 213 214 public template isComplexType( T ) 215 { 216 static immutable bool isComplexType = 217 is( Unqual!(T) == cfloat ) 218 || is( Unqual!(T) == cdouble ) 219 || is( Unqual!(T) == creal ); 220 } 221 222 /// 223 deprecated unittest 224 { 225 static assert ( isComplexType!(cdouble)); 226 static assert ( isComplexType!(const(cdouble))); 227 static assert (!isComplexType!(double)); 228 } 229 230 /******************************************************************************* 231 232 Params: 233 T = type to check 234 235 Returns: 236 `true` if `T` is a built-in imaginary floating point type 237 238 *******************************************************************************/ 239 240 public template isImaginaryType( T ) 241 { 242 static immutable bool isImaginaryType = 243 is( Unqual!(T) == ifloat ) 244 || is( Unqual!(T) == idouble ) 245 || is( Unqual!(T) == ireal ); 246 } 247 248 /// 249 deprecated unittest 250 { 251 static assert ( isImaginaryType!(idouble)); 252 static assert ( isImaginaryType!(const(idouble))); 253 static assert (!isImaginaryType!(double)); 254 } 255 256 /******************************************************************************* 257 258 Params: 259 T = type to check 260 261 Returns: 262 `true` if `T` is any built-in floating-point type: real, complex, or 263 imaginary. 264 265 *******************************************************************************/ 266 267 public template isFloatingPointType( T ) 268 { 269 static immutable bool isFloatingPointType = 270 isRealType!(T) 271 || isComplexType!(T) 272 || isImaginaryType!(T); 273 } 274 275 /// 276 unittest 277 { 278 static assert (isFloatingPointType!(double)); 279 static assert (isFloatingPointType!(ifloat)); 280 } 281 282 /******************************************************************************* 283 284 Used by other traits to distinguish between dynamic and static arrays 285 instead of plain `bool` values. 286 287 `ArrayKind.NotArray` is explicitly defined to have value `0` so that it can 288 be in regular condition, i.e. `static if (isArrayType!(T))`. 289 290 *******************************************************************************/ 291 292 public enum ArrayKind 293 { 294 NotArray = 0, 295 Static = 1, 296 Dynamic = 2, 297 Associative = 3, 298 } 299 300 /******************************************************************************* 301 302 Check if type is an array type and which kind of array it is 303 304 Params: 305 T = type to check 306 307 Returns: 308 `ArrayKind` value indicating if `T` is an array and if it is, static or 309 dynamic 310 311 *******************************************************************************/ 312 313 public template isArrayType ( T ) 314 { 315 static if (is(Unqual!(T) U == U[])) 316 static immutable isArrayType = ArrayKind.Dynamic; 317 else static if (is(Unqual!(T) U : U[])) 318 static immutable isArrayType = ArrayKind.Static; 319 else static if (is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == 320 Unqual!(T))) 321 static immutable isArrayType = ArrayKind.Associative; 322 else 323 static immutable isArrayType = ArrayKind.NotArray; 324 } 325 326 /// 327 unittest 328 { 329 static assert ( isArrayType!(char[15]) == ArrayKind.Static); 330 static assert ( isArrayType!(char[]) == ArrayKind.Dynamic); 331 static assert ( isArrayType!(char[][5]) == ArrayKind.Static); 332 static assert ( isArrayType!(char) == ArrayKind.NotArray); 333 static assert ( isArrayType!(int[int]) == ArrayKind.Associative); 334 static assert ( isArrayType!(const(int[int])) == ArrayKind.Associative); 335 static assert (!isArrayType!(char)); 336 } 337 338 unittest 339 { 340 static struct S { } 341 static assert (!isArrayType!(S)); 342 static assert ( isArrayType!(S[5])); 343 } 344 345 /******************************************************************************* 346 347 Params: 348 T = any type 349 350 Returns: 351 `true` if T is static or dynamic array, `false` otherwise 352 353 *******************************************************************************/ 354 355 public template isBasicArrayType ( T ) 356 { 357 static immutable isBasicArrayType = 358 (isArrayType!(T) == ArrayKind.Static) 359 || (isArrayType!(T) == ArrayKind.Dynamic); 360 } 361 362 /// 363 unittest 364 { 365 static assert ( isBasicArrayType!(int[])); 366 static assert ( isBasicArrayType!(int[5])); 367 static assert (!isBasicArrayType!(int[int])); 368 } 369 370 /******************************************************************************* 371 372 Params: 373 T = static array type 374 375 Returns: 376 for static array T[N] returns N 377 378 *******************************************************************************/ 379 380 public template staticArrayLength ( T : U[Dim], U, size_t Dim ) 381 { 382 static immutable staticArrayLength = Dim; 383 } 384 385 unittest 386 { 387 static assert (staticArrayLength!(int[][5]) == 5); 388 static assert (staticArrayLength!(char[42]) == 42); 389 static assert (staticArrayLength!(immutable(mstring[2])) == 2); 390 } 391 392 /******************************************************************************* 393 394 Params: 395 T = type to check 396 397 Returns: 398 `true` if `T` is a pointer type. 399 400 *******************************************************************************/ 401 402 template isPointerType ( T ) 403 { 404 static if (is(Unqual!(T) U == U*)) 405 static immutable isPointerType = true; 406 else 407 static immutable isPointerType = false; 408 } 409 410 /// 411 unittest 412 { 413 static assert ( isPointerType!(void*)); 414 static assert (!isPointerType!(char[])); 415 } 416 417 unittest 418 { 419 static assert ( isPointerType!(char[]*)); 420 static assert (!isPointerType!(char*[])); 421 static assert ( isPointerType!(const(real)*)); 422 static assert (!isPointerType!(uint)); 423 424 class Ham { void* a; } 425 426 static assert (!isPointerType!(Ham)); 427 428 union Eggs 429 { 430 void* a; 431 uint b; 432 } 433 434 static assert (!isPointerType!(Eggs)); 435 static assert ( isPointerType!(immutable(Eggs*))); 436 437 struct Bacon { } 438 439 static assert (!isPointerType!(Bacon)); 440 441 // function pointer is a pointer, but delegate is not: 442 void foo () {} 443 static void bar () {} 444 static assert (!isPointerType!(typeof(&foo))); 445 static assert ( isPointerType!(typeof(&bar))); 446 } 447 448 /******************************************************************************* 449 450 Params: 451 T = type to check 452 453 Returns: 454 `true` if `T` is a struct, class, interface or union 455 456 *******************************************************************************/ 457 458 template isReferenceType ( T ) 459 { 460 static immutable isReferenceType = 461 isPointerType!(T) 462 || is(T == delegate) 463 || isArrayType!(T) == ArrayKind.Dynamic 464 || isArrayType!(T) == ArrayKind.Associative 465 || is(T == class) 466 || is(T == interface); 467 } 468 469 /// 470 unittest 471 { 472 struct S { } 473 class C { } 474 interface I { } 475 476 static assert (!isReferenceType!(S)); 477 static assert ( isReferenceType!(S*)); 478 static assert ( isReferenceType!(S[])); 479 static assert ( isReferenceType!(C)); 480 static assert ( isReferenceType!(I)); 481 static assert ( isReferenceType!(S[C])); 482 static assert ( isReferenceType!(void function(int))); 483 484 static void foo ( ) { } 485 static assert (!isReferenceType!(typeof(foo))); 486 } 487 488 /******************************************************************************* 489 490 Params: 491 T = type to check 492 493 Returns: 494 `true` if `T` is a struct, class, interface or union 495 496 *******************************************************************************/ 497 498 template isAggregateType ( T ) 499 { 500 static immutable isAggregateType = 501 is(T == class) 502 || is(T == interface) 503 || is(T == struct) 504 || is(T == union); 505 } 506 507 /// 508 unittest 509 { 510 struct S { int x; } 511 union U { int x; double y; } 512 513 static assert ( isAggregateType!(S)); 514 static assert ( isAggregateType!(U)); 515 static assert (!isAggregateType!(S[2])); 516 } 517 518 /******************************************************************************* 519 520 Params: 521 T = type to check 522 523 Returns: 524 `true` if T is a function, function pointer or delegate 525 526 *******************************************************************************/ 527 528 template isFunctionType ( T ) 529 { 530 static immutable bool isFunctionType = 531 is(T == function) 532 || is(typeof(*T.init) == function) 533 || is(T == delegate); 534 } 535 536 /// 537 unittest 538 { 539 void foo1() { } 540 auto foo2 = () { }; 541 static void foo3() { } 542 543 static assert (isFunctionType!(typeof(&foo1))); 544 static assert (isFunctionType!(typeof(foo2))); 545 static assert (isFunctionType!(typeof(&foo3))); 546 static assert (isFunctionType!(typeof(foo3))); 547 } 548 549 unittest 550 { 551 static real func(ref int) { return 0; } 552 void nestedFunc() { } 553 class C 554 { 555 real method(ref int) { return 0; } 556 } 557 auto c = new C; 558 auto fp = &func; 559 auto dg = &c.method; 560 real val; 561 562 static assert ( isFunctionType!(typeof(func))); 563 static assert ( isFunctionType!(typeof(nestedFunc))); 564 static assert ( isFunctionType!(typeof(C.method))); 565 static assert ( isFunctionType!(typeof(fp))); 566 static assert ( isFunctionType!(typeof(dg))); 567 static assert ( isFunctionType!(real function(ref int))); 568 static assert ( isFunctionType!(real delegate(ref int))); 569 static assert ( isFunctionType!(typeof((int a) { return a; }))); 570 571 static assert (!isFunctionType!(int)); 572 static assert (!isFunctionType!(typeof(val))); 573 } 574 575 /******************************************************************************* 576 577 Params: 578 T = type to check 579 580 Returns: 581 `true` if T is a function, function pointer or delegate or callable 582 aggregate 583 584 *******************************************************************************/ 585 586 template isCallableType ( T ) 587 { 588 static if (is(typeof(T.opCall))) 589 static immutable isCallableType = isFunctionType!(typeof(&T.init.opCall)); 590 else 591 static immutable isCallableType = isFunctionType!(T); 592 } 593 594 /// 595 unittest 596 { 597 struct S 598 { 599 void opCall (int) { } 600 } 601 602 static assert (isCallableType!(S)); 603 static assert (isCallableType!(typeof(S.opCall))); 604 } 605 606 unittest 607 { 608 struct S2 609 { 610 static bool opCall( in int p1, in int p2 ) { return true; } 611 } 612 613 static assert (isCallableType!(S2)); 614 } 615 616 /******************************************************************************* 617 618 Used as result type for `isTypedef` trait. 619 620 `None` value is explicitly set to `0` so that it can be used in condition 621 like `if(isTypedef!(T))`. 622 623 *******************************************************************************/ 624 625 public enum TypedefKind 626 { 627 /// Not a typedef 628 None = 0, 629 /// D1 `typedef` keyword 630 Keyword, 631 /// Emulated by struct 632 Struct 633 } 634 635 /******************************************************************************* 636 637 Determines if T is a typedef of some kind 638 639 Params: 640 T = type to check 641 642 Evaluates to: 643 `TypedefKind` value which is non-zero is T is some typedef 644 645 *******************************************************************************/ 646 647 public template isTypedef (T) 648 { 649 static if (is(T.IsTypedef)) 650 static immutable isTypedef = TypedefKind.Struct; 651 else 652 static immutable isTypedef = TypedefKind.None; 653 } 654 655 unittest 656 { 657 mixin(Typedef!(double, "RealNum")); 658 659 static assert(!isTypedef!(int)); 660 static assert(!isTypedef!(double)); 661 static assert( isTypedef!(RealNum)); 662 663 static assert(isTypedef!(RealNum) == TypedefKind.Struct); 664 } 665 666 /****************************************************************************** 667 668 Check if the type of a member inside a struct or class is a D manifest 669 constant 670 671 Params: 672 T = The struct that will be checked 673 name = The struct member that will be checked 674 675 ******************************************************************************/ 676 677 bool isManifestConstant ( T, string name ) ( ) 678 { 679 T instance; 680 mixin(`return is(typeof(instance.`~name~`)) && !is(typeof(&instance.`~name~`));`); 681 } 682 683 unittest 684 { 685 struct Test 686 { 687 enum manifest = 2; 688 int notManifest1; 689 enum CustomType : int { 690 a = 1, b = 2 691 } 692 693 CustomType notManifest2; 694 } 695 696 static assert(isManifestConstant!(Test, "manifest")); 697 static assert(!isManifestConstant!(Test, "CustomType")); 698 static assert(!isManifestConstant!(Test, "notManifest1")); 699 static assert(!isManifestConstant!(Test, "notManifest2")); 700 } 701 702 703 704 /****************************************************************************** 705 706 Check if a constant is manifest constant 707 708 Params: 709 T = The constant 710 711 ******************************************************************************/ 712 713 bool isManifestConstant ( alias T ) ( ) 714 { 715 return is(typeof(T)) && !is(typeof(&T)); 716 } 717 718 unittest 719 { 720 enum manifest = 3; 721 int notManifest; 722 723 static assert(isManifestConstant!(manifest)); 724 static assert(!isManifestConstant!(notManifest)); 725 }