1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /** 6 * Type traits. 7 * 8 * Templates in this module are used to obtain type information at compile 9 * time. 10 * 11 * Copyright: Eugene Wissner 2017-2020. 12 * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, 13 * Mozilla Public License, v. 2.0). 14 * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) 15 * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/trait.d, 16 * tanya/meta/trait.d) 17 */ 18 module tanya.meta.trait; 19 20 import tanya.meta.metafunction; 21 import tanya.meta.transform; 22 23 /** 24 * Determines whether $(D_PARAM T) is a wide string, i.e. consists of 25 * $(D_KEYWORD dchar). 26 * 27 * The character type of the string can be qualified with $(D_KEYWORD const), 28 * $(D_KEYWORD immutable) or $(D_KEYWORD inout), but an occurrence of 29 * $(D_KEYWORD shared) in the character type results in returning 30 * $(D_KEYWORD false). 31 * The string itself (in contrast to its character type) can have any type 32 * qualifiers. 33 * 34 * Static $(D_KEYWORD char) and $(D_KEYWORD wchar) arrays are not considered 35 * strings. 36 * 37 * Params: 38 * T = A Type. 39 * 40 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a wide string, 41 * $(D_KEYWORD false) otherwise. 42 * 43 * See_Also: $(D_PSYMBOL isNarrowString). 44 */ 45 enum bool isWideString(T) = is(T : const dchar[]) && !isStaticArray!T; 46 47 /// 48 @nogc nothrow pure @safe unittest 49 { 50 static assert(isWideString!(dchar[])); 51 static assert(!isWideString!(char[])); 52 static assert(!isWideString!(wchar[])); 53 54 static assert(isWideString!dstring); 55 static assert(!isWideString!string); 56 static assert(!isWideString!wstring); 57 58 static assert(isWideString!(const dstring)); 59 static assert(!isWideString!(const string)); 60 static assert(!isWideString!(const wstring)); 61 62 static assert(isWideString!(shared dstring)); 63 static assert(!isWideString!(shared string)); 64 static assert(!isWideString!(shared wstring)); 65 66 static assert(isWideString!(const(dchar)[])); 67 static assert(isWideString!(inout(dchar)[])); 68 static assert(!isWideString!(shared(const(dchar))[])); 69 static assert(!isWideString!(shared(dchar)[])); 70 static assert(!isWideString!(dchar[10])); 71 } 72 73 /* 74 * Tests whether $(D_PARAM T) is an interface. 75 * 76 * Params: 77 * T = A type. 78 * 79 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an interface, 80 * $(D_KEYWORD false) otherwise. 81 */ 82 private enum bool isInterface(T) = is(T == interface); 83 84 /** 85 * Determines whether $(D_PARAM T) is a polymorphic type, i.e. a 86 * $(D_KEYWORD class) or an $(D_KEYWORD interface). 87 * 88 * Params: 89 * T = A type. 90 * 91 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a $(D_KEYWORD class) or an 92 * $(D_KEYWORD interface), $(D_KEYWORD false) otherwise. 93 */ 94 enum bool isPolymorphicType(T) = is(T == class) || is(T == interface); 95 96 /// 97 @nogc nothrow pure @safe unittest 98 { 99 interface I 100 { 101 } 102 static assert(isPolymorphicType!Object); 103 static assert(isPolymorphicType!I); 104 static assert(!isPolymorphicType!short); 105 } 106 107 /** 108 * Determines whether the type $(D_PARAM T) has a static method 109 * named $(D_PARAM member). 110 * 111 * Params: 112 * T = Aggregate type. 113 * member = Symbol name. 114 * 115 * Returns: $(D_KEYWORD true) if $(D_PARAM member) is a static method of 116 * $(D_PARAM T), $(D_KEYWORD false) otherwise. 117 */ 118 template hasStaticMember(T, string member) 119 { 120 static if (hasMember!(T, member)) 121 { 122 alias Member = Alias!(__traits(getMember, T, member)); 123 124 static if (__traits(isStaticFunction, Member) 125 || (!isFunction!Member && is(typeof(&Member)))) 126 { 127 enum bool hasStaticMember = true; 128 } 129 else 130 { 131 enum bool hasStaticMember = false; 132 } 133 } 134 else 135 { 136 enum bool hasStaticMember = false; 137 } 138 } 139 140 /// 141 @nogc nothrow pure @safe unittest 142 { 143 static struct S 144 { 145 int member1; 146 void member2() 147 { 148 } 149 static int member3; 150 static void member4() 151 { 152 } 153 static void function() member5; 154 } 155 static assert(!hasStaticMember!(S, "member1")); 156 static assert(!hasStaticMember!(S, "member2")); 157 static assert(hasStaticMember!(S, "member3")); 158 static assert(hasStaticMember!(S, "member4")); 159 static assert(hasStaticMember!(S, "member5")); 160 } 161 162 /** 163 * Determines whether $(D_PARAM T) is a floating point type. 164 * 165 * Floating point types are: 166 * $(UL 167 * $(LI float) 168 * $(LI double) 169 * $(LI real) 170 * ) 171 * 172 * Params: 173 * T = A type. 174 * 175 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a floating point type, 176 * $(D_KEYWORD false) otherwise. 177 */ 178 enum bool isFloatingPoint(T) = is(Unqual!(OriginalType!T) == double) 179 || is(Unqual!(OriginalType!T) == float) 180 || is(Unqual!(OriginalType!T) == real); 181 182 /// 183 @nogc nothrow pure @safe unittest 184 { 185 static assert(isFloatingPoint!float); 186 static assert(isFloatingPoint!double); 187 static assert(isFloatingPoint!real); 188 static assert(isFloatingPoint!(const float)); 189 static assert(isFloatingPoint!(shared float)); 190 static assert(isFloatingPoint!(shared const float)); 191 static assert(!isFloatingPoint!int); 192 } 193 194 /** 195 * Determines whether $(D_PARAM T) is a signed numeric type. 196 * 197 * Signed numeric types are: 198 * $(UL 199 * $(LI byte) 200 * $(LI short) 201 * $(LI int) 202 * $(LI long) 203 * $(LI float) 204 * $(LI double) 205 * $(LI real) 206 * ) 207 * 208 * Params: 209 * T = A type. 210 * 211 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a signed numeric type, 212 * $(D_KEYWORD false) otherwise. 213 * 214 * See_Also: $(D_PSYMBOL isUnsigned). 215 */ 216 enum bool isSigned(T) = is(Unqual!(OriginalType!T) == byte) 217 || is(Unqual!(OriginalType!T) == short) 218 || is(Unqual!(OriginalType!T) == int) 219 || is(Unqual!(OriginalType!T) == long) 220 || isFloatingPoint!T; 221 222 /// 223 @nogc nothrow pure @safe unittest 224 { 225 static assert(isSigned!byte); 226 static assert(isSigned!short); 227 static assert(isSigned!int); 228 static assert(isSigned!long); 229 static assert(isSigned!float); 230 static assert(isSigned!double); 231 static assert(isSigned!real); 232 233 static assert(!isSigned!ubyte); 234 static assert(!isSigned!ushort); 235 static assert(!isSigned!uint); 236 static assert(!isSigned!ulong); 237 } 238 239 /** 240 * Determines whether $(D_PARAM T) is an unsigned numeric type. 241 * 242 * Unsigned numeric types are: 243 * $(UL 244 * $(LI ubyte) 245 * $(LI ushort) 246 * $(LI uint) 247 * $(LI ulong) 248 * ) 249 * 250 * Params: 251 * T = A type. 252 * 253 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an unsigned numeric type, 254 * $(D_KEYWORD false) otherwise. 255 * 256 * See_Also: $(D_PSYMBOL isSigned). 257 */ 258 enum bool isUnsigned(T) = is(Unqual!(OriginalType!T) == ubyte) 259 || is(Unqual!(OriginalType!T) == ushort) 260 || is(Unqual!(OriginalType!T) == uint) 261 || is(Unqual!(OriginalType!T) == ulong); 262 263 /// 264 @nogc nothrow pure @safe unittest 265 { 266 static assert(isUnsigned!ubyte); 267 static assert(isUnsigned!ushort); 268 static assert(isUnsigned!uint); 269 static assert(isUnsigned!ulong); 270 271 static assert(!isUnsigned!byte); 272 static assert(!isUnsigned!short); 273 static assert(!isUnsigned!int); 274 static assert(!isUnsigned!long); 275 static assert(!isUnsigned!float); 276 static assert(!isUnsigned!double); 277 static assert(!isUnsigned!real); 278 } 279 280 /** 281 * Determines whether $(D_PARAM T) is an integral type. 282 * 283 * Integral types are: 284 * $(UL 285 * $(LI ubyte) 286 * $(LI ushort) 287 * $(LI uint) 288 * $(LI ulong) 289 * $(LI byte) 290 * $(LI short) 291 * $(LI int) 292 * $(LI long) 293 * ) 294 * 295 * Params: 296 * T = A type. 297 * 298 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an integral type, 299 * $(D_KEYWORD false) otherwise. 300 */ 301 enum bool isIntegral(T) = isUnsigned!T 302 || is(Unqual!(OriginalType!T) == byte) 303 || is(Unqual!(OriginalType!T) == short) 304 || is(Unqual!(OriginalType!T) == int) 305 || is(Unqual!(OriginalType!T) == long); 306 307 /// 308 @nogc nothrow pure @safe unittest 309 { 310 static assert(isIntegral!ubyte); 311 static assert(isIntegral!byte); 312 static assert(!isIntegral!float); 313 } 314 315 /** 316 * Determines whether $(D_PARAM T) is a boolean type, i.e. $(D_KEYWORD bool). 317 * 318 * Params: 319 * T = A type. 320 * 321 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a boolean type, 322 * $(D_KEYWORD false) otherwise. 323 */ 324 enum bool isBoolean(T) = is(Unqual!(OriginalType!T) == bool); 325 326 /// 327 @nogc nothrow pure @safe unittest 328 { 329 static assert(isBoolean!bool); 330 static assert(isBoolean!(shared const bool)); 331 static assert(!isBoolean!(ubyte)); 332 static assert(!isBoolean!(byte)); 333 334 enum E : bool 335 { 336 t = true, 337 f = false, 338 } 339 static assert(isBoolean!E); 340 341 static struct S1 342 { 343 bool b; 344 alias b this; 345 } 346 static assert(!isBoolean!S1); 347 348 static struct S2 349 { 350 bool opCast(T : bool)() 351 { 352 return true; 353 } 354 } 355 static assert(!isBoolean!S2); 356 } 357 358 /** 359 * Determines whether $(D_PARAM T) is a character type. 360 * 361 * Character types are: 362 * 363 * $(UL 364 * $(LI char) 365 * $(LI wchar) 366 * $(LI dchar) 367 * ) 368 * 369 * Params: 370 * T = A type. 371 * 372 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a character type, 373 * $(D_KEYWORD false) otherwise. 374 */ 375 enum bool isSomeChar(T) = is(Unqual!(OriginalType!T) == char) 376 || is(Unqual!(OriginalType!T) == wchar) 377 || is(Unqual!(OriginalType!T) == dchar); 378 379 /// 380 @nogc nothrow pure @safe unittest 381 { 382 static assert(isSomeChar!char); 383 static assert(isSomeChar!wchar); 384 static assert(isSomeChar!dchar); 385 386 static assert(!isSomeChar!byte); 387 static assert(!isSomeChar!ubyte); 388 static assert(!isSomeChar!short); 389 static assert(!isSomeChar!ushort); 390 static assert(!isSomeChar!int); 391 static assert(!isSomeChar!uint); 392 } 393 394 /** 395 * Determines whether $(D_PARAM T) is a pointer type. 396 * 397 * Params: 398 * T = A type. 399 * 400 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a pointer type, 401 * $(D_KEYWORD false) otherwise. 402 */ 403 template isPointer(T) 404 { 405 static if (is(T U : U*)) 406 { 407 enum bool isPointer = !is(Unqual!(OriginalType!T) == typeof(null)); 408 } 409 else 410 { 411 enum bool isPointer = false; 412 } 413 } 414 415 /// 416 @nogc nothrow pure @safe unittest 417 { 418 static assert(isPointer!(bool*)); 419 static assert(isPointer!(const bool*)); 420 static assert(isPointer!(const shared bool*)); 421 static assert(!isPointer!bool); 422 } 423 424 /** 425 * Determines whether $(D_PARAM T) is an array type (dynamic or static, but 426 * not an associative one). 427 * 428 * Params: 429 * T = A type. 430 * 431 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an array type, 432 * $(D_KEYWORD false) otherwise. 433 * 434 * See_Also: $(D_PSYMBOL isAssociativeArray). 435 */ 436 template isArray(T) 437 { 438 static if (is(T U : U[])) 439 { 440 enum bool isArray = true; 441 } 442 else 443 { 444 enum bool isArray = false; 445 } 446 } 447 448 /// 449 @nogc nothrow pure @safe unittest 450 { 451 static assert(isArray!(bool[])); 452 static assert(isArray!(const bool[])); 453 static assert(isArray!(shared bool[])); 454 static assert(isArray!(bool[8])); 455 static assert(!isArray!bool); 456 static assert(!isArray!(bool[string])); 457 } 458 459 /** 460 * Determines whether $(D_PARAM T) is a static array type. 461 * 462 * Params: 463 * T = A type. 464 * 465 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a static array type, 466 * $(D_KEYWORD false) otherwise. 467 * 468 * See_Also: $(D_PSYMBOL isArray). 469 */ 470 template isStaticArray(T) 471 { 472 static if (is(T U : U[L], size_t L)) 473 { 474 enum bool isStaticArray = true; 475 } 476 else 477 { 478 enum bool isStaticArray = false; 479 } 480 } 481 482 /// 483 @nogc nothrow pure @safe unittest 484 { 485 static assert(isStaticArray!(bool[8])); 486 static assert(isStaticArray!(const bool[8])); 487 static assert(isStaticArray!(shared bool[8])); 488 static assert(!isStaticArray!(bool[])); 489 static assert(!isStaticArray!bool); 490 static assert(!isStaticArray!(bool[string])); 491 } 492 493 /** 494 * Determines whether $(D_PARAM T) is a dynamic array type. 495 * 496 * Params: 497 * T = A type. 498 * 499 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a dynamic array type, 500 * $(D_KEYWORD false) otherwise. 501 * 502 * See_Also: $(D_PSYMBOL isArray). 503 */ 504 enum bool isDynamicArray(T) = isArray!T && !isStaticArray!T; 505 506 /// 507 @nogc nothrow pure @safe unittest 508 { 509 static assert(isDynamicArray!(bool[])); 510 static assert(isDynamicArray!(const bool[])); 511 static assert(isDynamicArray!(shared bool[])); 512 static assert(!isDynamicArray!(bool[8])); 513 static assert(!isDynamicArray!bool); 514 static assert(!isDynamicArray!(bool[string])); 515 } 516 517 /** 518 * Determines whether $(D_PARAM T) is an associative array type. 519 * 520 * Params: 521 * T = A type. 522 * 523 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an associative array type, 524 * $(D_KEYWORD false) otherwise. 525 * 526 * See_Also: $(D_PSYMBOL isArray). 527 */ 528 template isAssociativeArray(T) 529 { 530 static if (is(T U : U[L], L)) 531 { 532 enum bool isAssociativeArray = true; 533 } 534 else 535 { 536 enum bool isAssociativeArray = false; 537 } 538 } 539 540 /// 541 @nogc nothrow pure @safe unittest 542 { 543 static assert(isAssociativeArray!(bool[string])); 544 static assert(isAssociativeArray!(const bool[string])); 545 static assert(isAssociativeArray!(shared const bool[string])); 546 static assert(!isAssociativeArray!(bool[])); 547 static assert(!isAssociativeArray!(bool[8])); 548 static assert(!isAssociativeArray!bool); 549 } 550 551 /** 552 * Determines whether $(D_PARAM T) is an aggregate type. 553 * 554 * Aggregate types are: 555 * 556 * $(UL 557 * $(LI $(D_KEYWORD struct)s) 558 * $(LI $(D_KEYWORD class)es) 559 * $(LI $(D_KEYWORD interface)s) 560 * $(LI $(D_KEYWORD union)s) 561 * ) 562 * 563 * Params: 564 * T = A type. 565 * 566 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an aggregate type, 567 * $(D_KEYWORD false) otherwise. 568 */ 569 enum bool isAggregateType(T) = is(T == struct) 570 || is(T == class) 571 || is(T == interface) 572 || is(T == union); 573 574 /// 575 @nogc nothrow pure @safe unittest 576 { 577 static struct S; 578 class C; 579 interface I; 580 union U; 581 enum E; 582 583 static assert(isAggregateType!S); 584 static assert(isAggregateType!C); 585 static assert(isAggregateType!I); 586 static assert(isAggregateType!U); 587 static assert(!isAggregateType!E); 588 static assert(!isAggregateType!void); 589 } 590 591 /** 592 * Determines whether $(D_PARAM T) is a narrow string, i.e. consists of 593 * $(D_KEYWORD char) or $(D_KEYWORD wchar). 594 * 595 * The character type of the string can be qualified with $(D_KEYWORD const), 596 * $(D_KEYWORD immutable) or $(D_KEYWORD inout), but an occurrence of 597 * $(D_KEYWORD shared) in the character type results in returning 598 * $(D_KEYWORD false). 599 * The string itself (in contrast to its character type) can have any type 600 * qualifiers. 601 * 602 * Static $(D_KEYWORD char) and $(D_KEYWORD wchar) arrays are not considered 603 * strings. 604 * 605 * Params: 606 * T = A Type. 607 * 608 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a narrow string, 609 * $(D_KEYWORD false) otherwise. 610 * 611 * See_Also: $(D_PSYMBOL isWideString). 612 */ 613 enum bool isNarrowString(T) = (is(T : const char[]) || is (T : const wchar[])) 614 && !isStaticArray!T; 615 616 /// 617 @nogc nothrow pure @safe unittest 618 { 619 static assert(isNarrowString!(char[])); 620 static assert(isNarrowString!(wchar[])); 621 static assert(!isNarrowString!(dchar[])); 622 623 static assert(isNarrowString!string); 624 static assert(isNarrowString!wstring); 625 static assert(!isNarrowString!dstring); 626 627 static assert(isNarrowString!(const string)); 628 static assert(isNarrowString!(const wstring)); 629 static assert(!isNarrowString!(const dstring)); 630 631 static assert(isNarrowString!(shared string)); 632 static assert(isNarrowString!(shared wstring)); 633 static assert(!isNarrowString!(shared dstring)); 634 635 static assert(isNarrowString!(const(char)[])); 636 static assert(isNarrowString!(inout(char)[])); 637 static assert(!isNarrowString!(shared(const(char))[])); 638 static assert(!isNarrowString!(shared(char)[])); 639 static assert(!isNarrowString!(char[10])); 640 } 641 642 /** 643 * Determines whether $(D_PARAM T) is a string, i.e. consists of 644 * $(D_KEYWORD char), $(D_KEYWORD wchar) or $(D_KEYWORD dchar). 645 * 646 * The character type of the string can be qualified with $(D_KEYWORD const), 647 * $(D_KEYWORD immutable) or $(D_KEYWORD inout), but an occurrence of 648 * $(D_KEYWORD shared) in the character type results in returning 649 * $(D_KEYWORD false). 650 * The string itself (in contrast to its character type) can have any type 651 * qualifiers. 652 * 653 * Static character arrays are not considered strings. 654 * 655 * Params: 656 * T = A Type. 657 * 658 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a string, 659 * $(D_KEYWORD false) otherwise. 660 * 661 * See_Also: $(D_PSYMBOL isNarrowString), $(D_PSYMBOL isWideString). 662 */ 663 enum bool isSomeString(T) = isNarrowString!T || isWideString!T; 664 665 /// 666 @nogc nothrow pure @safe unittest 667 { 668 static assert(isSomeString!(dchar[])); 669 static assert(isSomeString!(char[])); 670 static assert(isSomeString!(wchar[])); 671 672 static assert(isSomeString!dstring); 673 static assert(isSomeString!string); 674 static assert(isSomeString!wstring); 675 676 static assert(isSomeString!(const dstring)); 677 static assert(isSomeString!(const string)); 678 static assert(isSomeString!(const wstring)); 679 680 static assert(isSomeString!(shared dstring)); 681 static assert(isSomeString!(shared string)); 682 static assert(isSomeString!(shared wstring)); 683 684 static assert(isSomeString!(const(char)[])); 685 static assert(isSomeString!(inout(char)[])); 686 static assert(!isSomeString!(shared(const(char))[])); 687 static assert(!isSomeString!(shared(char)[])); 688 static assert(!isSomeString!(char[10])); 689 } 690 691 /** 692 * Determines whether the type $(D_PARAM T) is copyable. 693 * 694 * Only structs can be not copyable if their postblit constructor or the 695 * postblit constructor of one of its fields is disabled, i.e. annotated with 696 * $(D_KEYWORD @disable). 697 * 698 * Params: 699 * T = A type. 700 * 701 * Returns: $(D_PARAM true) if $(D_PARAM T) can be copied, 702 * $(D_PARAM false) otherwise. 703 */ 704 enum bool isCopyable(T) = is(typeof({ T s1 = T.init; T s2 = s1; })); 705 706 /// 707 @nogc nothrow pure @safe unittest 708 { 709 static struct S1 710 { 711 } 712 static struct S2 713 { 714 this(this) 715 { 716 } 717 } 718 static struct S3 719 { 720 @disable this(this); 721 } 722 static struct S4 723 { 724 S3 s; 725 } 726 class C 727 { 728 } 729 730 static assert(isCopyable!S1); 731 static assert(isCopyable!S2); 732 static assert(!isCopyable!S3); 733 static assert(!isCopyable!S4); 734 735 static assert(isCopyable!C); 736 static assert(isCopyable!bool); 737 } 738 739 /** 740 * Determines whether $(D_PARAM T) is an abstract class. 741 * 742 * Abstract class is a class marked as such or a class that has any abstract 743 * methods or doesn't implement all methods of abstract base classes. 744 * 745 * Params: 746 * T = A type. 747 * 748 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an abstract class, 749 * $(D_KEYWORD false) otherwise. 750 * 751 * See_Also: $(D_PSYMBOL isAbstractFunction). 752 */ 753 enum bool isAbstractClass(T) = __traits(isAbstractClass, T); 754 755 /// 756 @nogc nothrow pure @safe unittest 757 { 758 class A 759 { 760 } 761 abstract class B 762 { 763 } 764 class C 765 { 766 abstract void func(); 767 } 768 class D : C 769 { 770 } 771 class E : C 772 { 773 override void func() 774 { 775 } 776 } 777 static assert(!isAbstractClass!A); 778 static assert(isAbstractClass!B); 779 static assert(isAbstractClass!C); 780 static assert(isAbstractClass!D); 781 static assert(!isAbstractClass!E); 782 } 783 784 /** 785 * Checks whether $(D_PARAM T) is a type, same as `is(T)` does. 786 * 787 * Params: 788 * T = A symbol. 789 * 790 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a type, $(D_KEYWORD false) 791 * otherwise. 792 */ 793 enum bool isType(alias T) = is(T); 794 795 /// ditto 796 enum bool isType(T) = true; 797 798 /** 799 * Determines whether $(D_PARAM Args) contains only types. 800 * 801 * Params: 802 * Args = Alias sequence. 803 * 804 * Returns: $(D_KEYWORD true) if $(D_PARAM Args) consists only of types, 805 * $(D_KEYWORD false) otherwise. 806 */ 807 enum bool isTypeTuple(Args...) = allSatisfy!(isType, Args); 808 809 /// 810 @nogc nothrow pure @safe unittest 811 { 812 static assert(isTypeTuple!(int, uint, Object)); 813 static assert(isTypeTuple!()); 814 static assert(!isTypeTuple!(int, 8, Object)); 815 static assert(!isTypeTuple!(5, 8, 2)); 816 817 class C 818 { 819 } 820 enum E : bool 821 { 822 t, 823 f, 824 } 825 union U 826 { 827 } 828 static struct T() 829 { 830 } 831 832 static assert(isTypeTuple!C); 833 static assert(isTypeTuple!E); 834 static assert(isTypeTuple!U); 835 static assert(isTypeTuple!void); 836 static assert(isTypeTuple!int); 837 static assert(!isTypeTuple!T); 838 static assert(isTypeTuple!(T!())); 839 static assert(!isTypeTuple!5); 840 static assert(!isTypeTuple!(tanya.meta.trait)); 841 } 842 843 /** 844 * Tells whether $(D_PARAM Args) contains only expressions. 845 * 846 * An expression is determined by applying $(D_KEYWORD typeof) to an argument: 847 * 848 * --- 849 * static if (is(typeof(Args[i]))) 850 * { 851 * // Args[i] is an expression. 852 * } 853 * else 854 * { 855 * // Args[i] is not an expression. 856 * } 857 * --- 858 * 859 * Params: 860 * Args = Alias sequence. 861 * 862 * Returns: $(D_KEYWORD true) if $(D_PARAM Args) consists only of expressions, 863 * $(D_KEYWORD false) otherwise. 864 */ 865 template isExpressions(Args...) 866 { 867 static if (Args.length == 0) 868 { 869 enum bool isExpressions = true; 870 } 871 else static if (is(typeof(Args[0]) U)) 872 { 873 enum bool isExpressions = !is(U == void) 874 && isExpressions!(Args[1 .. $]); 875 } 876 else 877 { 878 enum bool isExpressions = false; 879 } 880 } 881 882 /// 883 @nogc nothrow pure @safe unittest 884 { 885 static assert(isExpressions!(5, 8, 2)); 886 static assert(isExpressions!()); 887 static assert(!isExpressions!(int, uint, Object)); 888 static assert(!isExpressions!(int, 8, Object)); 889 890 template T(U) 891 { 892 } 893 static assert(!isExpressions!T); 894 } 895 896 /** 897 * Determines whether $(D_PARAM T) is a final class. 898 * 899 * Params: 900 * T = A type. 901 * 902 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a final class, 903 * $(D_KEYWORD false) otherwise. 904 * 905 * See_Also: $(D_PSYMBOL isFinalFunction). 906 */ 907 enum bool isFinalClass(T) = __traits(isFinalClass, T); 908 909 /// 910 @nogc nothrow pure @safe unittest 911 { 912 final class A 913 { 914 } 915 class B 916 { 917 } 918 919 static assert(isFinalClass!A); 920 static assert(!isFinalClass!B); 921 } 922 923 /** 924 * Determines whether $(D_PARAM T) is an abstract method. 925 * 926 * Params: 927 * F = A symbol. 928 * 929 * Returns: $(D_KEYWORD true) if $(D_PARAM F) is an abstract method, 930 * $(D_KEYWORD false) otherwise. 931 * 932 * See_Also: $(D_PSYMBOL isAbstractClass). 933 */ 934 enum bool isAbstractFunction(alias F) = __traits(isAbstractFunction, F); 935 936 /// 937 @nogc nothrow pure @safe unittest 938 { 939 class A 940 { 941 void func() 942 { 943 } 944 } 945 class B 946 { 947 abstract void func(); 948 } 949 class C : B 950 { 951 override void func() 952 { 953 } 954 } 955 static assert(!isAbstractFunction!(A.func)); 956 static assert(isAbstractFunction!(B.func)); 957 static assert(!isAbstractFunction!(C.func)); 958 } 959 960 /** 961 * Determines whether $(D_PARAM T) is a final method. 962 * 963 * Params: 964 * F = A symbol. 965 * 966 * Returns: $(D_KEYWORD true) if $(D_PARAM F) is a final method, 967 * $(D_KEYWORD false) otherwise. 968 * 969 * See_Also: $(D_PSYMBOL isFinalClass). 970 */ 971 enum bool isFinalFunction(alias F) = __traits(isFinalFunction, F); 972 973 /// 974 @nogc nothrow pure @safe unittest 975 { 976 class A 977 { 978 void virtualFunc() 979 { 980 } 981 final void finalFunc() 982 { 983 } 984 } 985 986 static assert(isFinalFunction!(A.finalFunc)); 987 static assert(!isFinalFunction!(A.virtualFunc)); 988 } 989 990 /** 991 * Function pointer is a pointer to a function. So a simple function is not 992 * a function pointer, but getting the address of such function returns a 993 * function pointer. 994 * 995 * A function pointer doesn't save the context pointer, thus cannot have access 996 * to its outer scope. 997 * 998 * Params: 999 * F = A symbol. 1000 * 1001 * Returns: $(D_KEYWORD true) if $(D_PARAM F) is a function pointer, 1002 * $(D_KEYWORD false) otherwise. 1003 * 1004 * See_Also: $(LINK2 http://dlang.org/spec/function.html#closures, 1005 * Delegates, Function Pointers, and Closures). 1006 */ 1007 template isFunctionPointer(F...) 1008 if (F.length == 1) 1009 { 1010 static if ((is(typeof(F[0]) T : T*) && is(T == function)) 1011 || (is(F[0] T : T*) && is(T == function))) 1012 { 1013 enum bool isFunctionPointer = true; 1014 } 1015 else 1016 { 1017 enum bool isFunctionPointer = false; 1018 } 1019 } 1020 1021 /// 1022 @nogc nothrow pure @safe unittest 1023 { 1024 static assert(isFunctionPointer!(void function())); 1025 static assert(!isFunctionPointer!(void delegate())); 1026 1027 static assert(isFunctionPointer!(() {})); 1028 1029 void func() 1030 { 1031 } 1032 static void staticFunc() 1033 { 1034 } 1035 interface I 1036 { 1037 @property int prop(); 1038 } 1039 1040 static assert(!isFunctionPointer!func); 1041 static assert(!isFunctionPointer!staticFunc); 1042 1043 auto functionPointer = &staticFunc; 1044 auto dg = &func; 1045 1046 static assert(isFunctionPointer!functionPointer); 1047 static assert(!isFunctionPointer!dg); 1048 1049 static assert(!isFunctionPointer!(I.prop)); 1050 } 1051 1052 /** 1053 * Delegate stores the function pointer and function context. 1054 * 1055 * Params: 1056 * F = A symbol. 1057 * 1058 * Returns: $(D_KEYWORD true) if $(D_PARAM F) is a delegate, 1059 * $(D_KEYWORD false) delegate. 1060 * 1061 * See_Also: $(LINK2 http://dlang.org/spec/function.html#closures, 1062 * Delegates, Function Pointers, and Closures). 1063 */ 1064 template isDelegate(F...) 1065 if (F.length == 1) 1066 { 1067 static if (is(F[0] == delegate) 1068 || is(typeof(F[0]) == delegate)) 1069 { 1070 enum bool isDelegate = true; 1071 } 1072 else 1073 { 1074 enum bool isDelegate = false; 1075 } 1076 } 1077 1078 /// 1079 @nogc nothrow pure @safe unittest 1080 { 1081 static assert(isDelegate!(void delegate())); 1082 static assert(!isDelegate!(void function())); 1083 1084 static assert(!isDelegate!(() {})); 1085 1086 void func() 1087 { 1088 } 1089 static void staticFunc() 1090 { 1091 } 1092 interface I 1093 { 1094 @property int prop(); 1095 } 1096 1097 static assert(!isDelegate!func); 1098 static assert(!isDelegate!staticFunc); 1099 1100 auto functionPointer = &staticFunc; 1101 auto dg = &func; 1102 1103 static assert(!isDelegate!functionPointer); 1104 static assert(isDelegate!dg); 1105 1106 static assert(!isDelegate!(I.prop)); 1107 } 1108 1109 /** 1110 * $(D_PSYMBOL isFunction) returns $(D_KEYWORD true) only for plain functions, 1111 * not function pointers or delegates. Use $(D_PSYMBOL isFunctionPointer) or 1112 * $(D_PSYMBOL isDelegate) to detect them or $(D_PSYMBOL isSomeFunction) 1113 * for detecting a function of any type. 1114 * 1115 * Params: 1116 * F = A symbol. 1117 * 1118 * Returns: $(D_KEYWORD true) if $(D_PARAM F) is a function, 1119 * $(D_KEYWORD false) otherwise. 1120 * 1121 * See_Also: $(LINK2 http://dlang.org/spec/function.html#closures, 1122 * Delegates, Function Pointers, and Closures). 1123 */ 1124 template isFunction(F...) 1125 if (F.length == 1) 1126 { 1127 static if (is(F[0] == function) 1128 || is(typeof(&F[0]) T == delegate) 1129 || (is(typeof(&F[0]) T : T*) && is(T == function))) 1130 { 1131 enum bool isFunction = true; 1132 } 1133 else 1134 { 1135 enum bool isFunction = false; 1136 } 1137 } 1138 1139 /// 1140 @nogc nothrow pure @safe unittest 1141 { 1142 static assert(!isFunction!(void function())); 1143 static assert(!isFunction!(() {})); 1144 static assert(!isFunction!(void delegate())); 1145 1146 void func() 1147 { 1148 } 1149 static void staticFunc() 1150 { 1151 } 1152 interface I 1153 { 1154 @property int prop(); 1155 } 1156 1157 static assert(isFunction!func); 1158 static assert(isFunction!staticFunc); 1159 1160 auto functionPointer = &staticFunc; 1161 auto dg = &func; 1162 1163 static assert(!isFunction!functionPointer); 1164 static assert(!isFunction!dg); 1165 1166 static assert(isFunction!(I.prop)); 1167 } 1168 1169 /** 1170 * Params: 1171 * F = A symbol. 1172 * 1173 * Returns: $(D_KEYWORD true) if $(D_PARAM F) is a function, function pointer 1174 * or delegate, $(D_KEYWORD false) otherwise. 1175 * 1176 * See_Also: $(D_PSYMBOL isFunction), 1177 * $(D_PSYMBOL isDelegate), 1178 * $(D_PSYMBOL isFunctionPointer). 1179 */ 1180 template isSomeFunction(F...) 1181 if (F.length == 1) 1182 { 1183 enum bool isSomeFunction = isFunctionPointer!F 1184 || isFunction!F 1185 || isDelegate!F; 1186 } 1187 1188 /// 1189 @nogc nothrow pure @safe unittest 1190 { 1191 static assert(isSomeFunction!(void function())); 1192 static assert(isSomeFunction!(() {})); 1193 static assert(isSomeFunction!(void delegate())); 1194 1195 void func() 1196 { 1197 } 1198 static void staticFunc() 1199 { 1200 } 1201 1202 static assert(isSomeFunction!func); 1203 static assert(isSomeFunction!staticFunc); 1204 1205 auto functionPointer = &staticFunc; 1206 auto dg = &func; 1207 1208 static assert(isSomeFunction!functionPointer); 1209 static assert(isSomeFunction!dg); 1210 1211 static assert(!isSomeFunction!int); 1212 } 1213 1214 /** 1215 * Params: 1216 * F = A symbol. 1217 * 1218 * Returns: $(D_KEYWORD true) if $(D_PARAM F) is callable, 1219 * $(D_KEYWORD false) otherwise. 1220 */ 1221 template isCallable(F...) 1222 if (F.length == 1) 1223 { 1224 static if (isSomeFunction!F 1225 || (is(typeof(F[0].opCall)) && isFunction!(F[0].opCall))) 1226 { 1227 enum bool isCallable = true; 1228 } 1229 else 1230 { 1231 enum bool isCallable = false; 1232 } 1233 } 1234 1235 /// 1236 @nogc nothrow pure @safe unittest 1237 { 1238 static struct S 1239 { 1240 void opCall() 1241 { 1242 } 1243 } 1244 class C 1245 { 1246 static void opCall() 1247 { 1248 } 1249 } 1250 interface I 1251 { 1252 } 1253 S s; 1254 1255 static assert(isCallable!s); 1256 static assert(isCallable!C); 1257 static assert(isCallable!S); 1258 static assert(!isCallable!I); 1259 } 1260 1261 /** 1262 * Determines whether $(D_PARAM T) defines a symbol $(D_PARAM member). 1263 * 1264 * Params: 1265 * T = Aggregate type. 1266 * member = Symbol name. 1267 * 1268 * Returns: $(D_KEYWORD true) if $(D_PARAM T) defines a symbol 1269 * $(D_PARAM member), $(D_KEYWORD false) otherwise. 1270 */ 1271 enum bool hasMember(T, string member) = __traits(hasMember, T, member); 1272 1273 /// 1274 @nogc nothrow pure @safe unittest 1275 { 1276 static struct S 1277 { 1278 int member1; 1279 void member2() 1280 { 1281 } 1282 static int member3; 1283 static void member4() 1284 { 1285 } 1286 } 1287 static assert(hasMember!(S, "member1")); 1288 static assert(hasMember!(S, "member2")); 1289 static assert(hasMember!(S, "member3")); 1290 static assert(hasMember!(S, "member4")); 1291 static assert(!hasMember!(S, "member6")); 1292 } 1293 1294 /** 1295 * Determines whether $(D_PARAM T) is mutable, i.e. has one of the following 1296 * qualifiers or a combination of them: 1297 * 1298 * $(UL 1299 * $(LI $(D_KEYWORD const)) 1300 * $(LI $(D_KEYWORD immutable)) 1301 * $(LI $(D_KEYWORD const)) 1302 * ) 1303 * 1304 * Params: 1305 * T = A type. 1306 * 1307 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is mutable, 1308 * $(D_KEYWORD false) otherwise. 1309 */ 1310 template isMutable(T) 1311 { 1312 static if (is(T U == const U) 1313 || is(T U == inout U) 1314 || is(T U == inout const U) 1315 || is(T U == immutable U) 1316 || is(T U == shared const U) 1317 || is(T U == shared inout U) 1318 || is(T U == shared inout const U)) 1319 { 1320 enum bool isMutable = false; 1321 } 1322 else 1323 { 1324 enum bool isMutable = true; 1325 } 1326 } 1327 1328 /// 1329 @nogc nothrow pure @safe unittest 1330 { 1331 static struct S 1332 { 1333 void method() 1334 { 1335 static assert(isMutable!(typeof(this))); 1336 } 1337 1338 void method() inout 1339 { 1340 static assert(!isMutable!(typeof(this))); 1341 } 1342 1343 void immMethod() const 1344 { 1345 static assert(!isMutable!(typeof(this))); 1346 } 1347 void immMethod() immutable 1348 { 1349 static assert(!isMutable!(typeof(this))); 1350 } 1351 } 1352 } 1353 1354 /** 1355 * Determines whether $(D_PARAM T) is a nested type, i.e. $(D_KEYWORD class), 1356 * $(D_KEYWORD struct) or $(D_KEYWORD union), which internally stores a context 1357 * pointer. 1358 * 1359 * Params: 1360 * T = $(D_KEYWORD class), $(D_KEYWORD struct) or $(D_KEYWORD union) type. 1361 * 1362 * Returns: $(D_KEYWORD true) if the argument is a nested type which internally 1363 * stores a context pointer, $(D_KEYWORD false) otherwise. 1364 */ 1365 template isNested(T) 1366 if (is(T == class) || is(T == struct) || is(T == union)) 1367 { 1368 enum bool isNested = __traits(isNested, T); 1369 } 1370 1371 /// 1372 @nogc pure nothrow @safe unittest 1373 { 1374 static struct S 1375 { 1376 } 1377 static assert(!isNested!S); 1378 1379 class C 1380 { 1381 void method() 1382 { 1383 } 1384 } 1385 static assert(isNested!C); 1386 } 1387 1388 /** 1389 * Determines whether $(D_PARAM T) is a nested function. 1390 * 1391 * Params: 1392 * F = A function. 1393 * 1394 * Returns $(D_KEYWORD true) if the $(D_PARAM T) is a nested function, 1395 * $(D_KEYWORD false) otherwise. 1396 */ 1397 enum bool isNestedFunction(alias F) = __traits(isNested, F); 1398 1399 /// 1400 @nogc nothrow pure @safe unittest 1401 { 1402 void func() 1403 { 1404 void nestedFunc() 1405 { 1406 } 1407 static assert(isNestedFunction!nestedFunc); 1408 } 1409 } 1410 1411 /** 1412 * Determines the type of the callable $(D_PARAM F). 1413 * 1414 * Params: 1415 * F = A function. 1416 * 1417 * Returns: Type of the function $(D_PARAM F). 1418 */ 1419 template FunctionTypeOf(F...) 1420 if (isCallable!F) 1421 { 1422 static if ((is(typeof(F[0]) T : T*) && is(T == function)) 1423 || (is(F[0] T : T*) && is(T == function)) 1424 || is(F[0] T == delegate) 1425 || is(typeof(F[0]) T == delegate) 1426 || is(F[0] T == function) 1427 || is(typeof(&F[0]) T == delegate) 1428 || (is(typeof(&F[0]) T : T*) && is(T == function))) 1429 { 1430 alias FunctionTypeOf = T; 1431 } 1432 else 1433 { 1434 alias FunctionTypeOf = FunctionTypeOf!(F[0].opCall); 1435 } 1436 } 1437 1438 /// 1439 @nogc nothrow pure @safe unittest 1440 { 1441 static assert(is(FunctionTypeOf!(void function()) == function)); 1442 static assert(is(FunctionTypeOf!(() {}) == function)); 1443 } 1444 1445 /** 1446 * Determines the return type of the callable $(D_PARAM F). 1447 * 1448 * Params: 1449 * F = A callable object. 1450 * 1451 * Returns: Return type of $(D_PARAM F). 1452 */ 1453 template ReturnType(F...) 1454 if (isCallable!F) 1455 { 1456 static if (is(FunctionTypeOf!(F[0]) T == return)) 1457 { 1458 alias ReturnType = T; 1459 } 1460 else 1461 { 1462 static assert(false, "Argument is not a callable"); 1463 } 1464 } 1465 1466 /// 1467 @nogc nothrow pure @safe unittest 1468 { 1469 static assert(is(ReturnType!(int delegate()) == int)); 1470 static assert(is(ReturnType!(bool function()) == bool)); 1471 } 1472 1473 /** 1474 * Determines the template $(D_PARAM T) is an instance of. 1475 * 1476 * Params: 1477 * T = Template instance. 1478 * 1479 * Returns: Template $(D_PARAM T) is an instance of. 1480 */ 1481 alias TemplateOf(alias T : Base!Args, alias Base, Args...) = Base; 1482 1483 /// 1484 @nogc nothrow pure @safe unittest 1485 { 1486 static struct S(T) 1487 { 1488 } 1489 static assert(__traits(isSame, TemplateOf!(S!int), S)); 1490 1491 static void func(T)() 1492 { 1493 } 1494 static assert(__traits(isSame, TemplateOf!(func!int), func)); 1495 1496 template T(U) 1497 { 1498 } 1499 static assert(__traits(isSame, TemplateOf!(T!int), T)); 1500 } 1501 1502 /** 1503 * Returns the mangled name of the symbol $(D_PARAM T). 1504 * 1505 * Params: 1506 * T = A symbol. 1507 * 1508 * Returns: Mangled name of $(D_PARAM T). 1509 */ 1510 enum string mangledName(T) = T.mangleof; 1511 1512 /// 1513 enum string mangledName(alias T) = T.mangleof; 1514 1515 /** 1516 * Tests whether $(D_PARAM I) is an instance of template $(D_PARAM T). 1517 * 1518 * Params: 1519 * T = Template. 1520 * I = Template instance. 1521 * 1522 * Returns: $(D_KEYWORD true) if $(D_PARAM I) is an instance of $(D_PARAM T), 1523 * $(D_KEYWORD false) otherwise. 1524 */ 1525 enum bool isInstanceOf(alias T, I) = is(I == T!Args, Args...); 1526 1527 template isInstanceOf(alias T, alias I) 1528 { 1529 static if (is(typeof(TemplateOf!I))) 1530 { 1531 enum bool isInstanceOf = __traits(isSame, TemplateOf!I, T); 1532 } 1533 else 1534 { 1535 enum bool isInstanceOf = false; 1536 } 1537 } 1538 1539 /// 1540 @nogc nothrow pure @safe unittest 1541 { 1542 static struct S(T) 1543 { 1544 } 1545 static assert(isInstanceOf!(S, S!int)); 1546 1547 static void func(T)(); 1548 static assert(isInstanceOf!(func, func!int)); 1549 1550 template T(U) 1551 { 1552 } 1553 static assert(isInstanceOf!(T, T!int)); 1554 } 1555 1556 /** 1557 * Checks whether $(D_PARAM From) is implicitly (without explicit 1558 * $(D_KEYWORD cast)) to $(D_PARAM To). 1559 * 1560 * Params: 1561 * From = Source type. 1562 * To = Conversion target type. 1563 * 1564 * Returns: $(D_KEYWORD true) if $(D_PARAM From) is implicitly convertible to 1565 * $(D_PARAM To), $(D_KEYWORD false) if not. 1566 */ 1567 enum bool isImplicitlyConvertible(From, To) = is(From : To); 1568 1569 /// 1570 @nogc nothrow pure @safe unittest 1571 { 1572 static assert(isImplicitlyConvertible!(const(byte), byte)); 1573 static assert(isImplicitlyConvertible!(byte, char)); 1574 static assert(isImplicitlyConvertible!(byte, short)); 1575 static assert(!isImplicitlyConvertible!(short, byte)); 1576 static assert(isImplicitlyConvertible!(string, const(char)[])); 1577 } 1578 1579 /** 1580 * Returns a tuple of base classes and interfaces of $(D_PARAM T). 1581 * 1582 * $(D_PSYMBOL BaseTypeTuple) returns only classes and interfaces $(D_PARAM T) 1583 * directly inherits from, but not the base classes and interfaces of its parents. 1584 * 1585 * Params: 1586 * T = Class or interface type. 1587 * 1588 * Returns: A tuple of base classes or interfaces of ($D_PARAM T). 1589 * 1590 * See_Also: $(D_PSYMBOL TransitiveBaseTypeTuple). 1591 */ 1592 template BaseTypeTuple(T) 1593 if (is(T == class) || (is(T == interface))) 1594 { 1595 static if (is(T Tuple == super)) 1596 { 1597 alias BaseTypeTuple = Tuple; 1598 } 1599 else 1600 { 1601 static assert(false, "Argument isn't a class or interface"); 1602 } 1603 } 1604 1605 /// 1606 @nogc nothrow pure @safe unittest 1607 { 1608 interface I1 1609 { 1610 } 1611 interface I2 1612 { 1613 } 1614 interface I3 : I1, I2 1615 { 1616 } 1617 interface I4 1618 { 1619 } 1620 class A : I3, I4 1621 { 1622 } 1623 static assert(is(BaseTypeTuple!A == AliasSeq!(Object, I3, I4))); 1624 static assert(BaseTypeTuple!Object.length == 0); 1625 } 1626 1627 /** 1628 * Returns a tuple of all base classes and interfaces of $(D_PARAM T). 1629 * 1630 * $(D_PSYMBOL TransitiveBaseTypeTuple) returns first the parent class, then 1631 * grandparent and so on. The last class is $(D_PSYMBOL Object). Then the interfaces 1632 * follow. 1633 * 1634 * Params: 1635 * T = Class or interface type. 1636 * 1637 * Returns: A tuple of all base classes and interfaces of ($D_PARAM T). 1638 * 1639 * See_Also: $(D_PSYMBOL BaseTypeTuple). 1640 */ 1641 template TransitiveBaseTypeTuple(T) 1642 if (is(T == class) || is(T == interface)) 1643 { 1644 private template Impl(T...) 1645 { 1646 static if (T.length == 0) 1647 { 1648 alias Impl = AliasSeq!(); 1649 } 1650 else 1651 { 1652 alias Impl = AliasSeq!(BaseTypeTuple!(T[0]), 1653 Map!(ImplCopy, BaseTypeTuple!(T[0]))); 1654 } 1655 } 1656 private alias ImplCopy = Impl; // To avoid recursive template expansion. 1657 private enum bool cmp(A, B) = is(B == interface) && is(A == class); 1658 1659 alias TransitiveBaseTypeTuple = NoDuplicates!(Sort!(cmp, Impl!T)); 1660 } 1661 1662 /// 1663 @nogc nothrow pure @safe unittest 1664 { 1665 interface I1 1666 { 1667 } 1668 interface I2 : I1 1669 { 1670 } 1671 class A : I2 1672 { 1673 } 1674 class B : A, I1 1675 { 1676 } 1677 class C : B, I2 1678 { 1679 } 1680 alias Expected = AliasSeq!(B, A, Object, I2, I1); 1681 static assert(is(TransitiveBaseTypeTuple!C == Expected)); 1682 1683 static assert(is(TransitiveBaseTypeTuple!Object == AliasSeq!())); 1684 static assert(is(TransitiveBaseTypeTuple!I2 == AliasSeq!(I1))); 1685 } 1686 1687 /** 1688 * Returns all the base classes of $(D_PARAM T), the direct parent class comes 1689 * first, $(D_PSYMBOL Object) ist the last one. 1690 * 1691 * The only type that doesn't have any base class is $(D_PSYMBOL Object). 1692 * 1693 * Params: 1694 * T = Class type. 1695 * 1696 * Returns: Base classes of $(D_PARAM T). 1697 */ 1698 template BaseClassesTuple(T) 1699 if (is(T == class)) 1700 { 1701 static if (is(T == Object)) 1702 { 1703 alias BaseClassesTuple = AliasSeq!(); 1704 } 1705 else 1706 { 1707 private alias Parents = BaseTypeTuple!T; 1708 alias BaseClassesTuple = AliasSeq!(Parents[0], BaseClassesTuple!(Parents[0])); 1709 } 1710 } 1711 1712 /// 1713 @nogc nothrow pure @safe unittest 1714 { 1715 interface I1 1716 { 1717 } 1718 interface I2 1719 { 1720 } 1721 class A : I1, I2 1722 { 1723 } 1724 class B : A, I1 1725 { 1726 } 1727 class C : B, I2 1728 { 1729 } 1730 static assert(is(BaseClassesTuple!C == AliasSeq!(B, A, Object))); 1731 static assert(BaseClassesTuple!Object.length == 0); 1732 } 1733 1734 /** 1735 * Returns all the interfaces $(D_PARAM T) inherits from. 1736 * 1737 * Params: 1738 * T = Class or interface type. 1739 * 1740 * Returns: Interfaces $(D_PARAM T) inherits from. 1741 */ 1742 template InterfacesTuple(T) 1743 if (is(T == class) || is(T == interface)) 1744 { 1745 alias InterfacesTuple = Filter!(isInterface, TransitiveBaseTypeTuple!T); 1746 } 1747 1748 /// 1749 @nogc nothrow pure @safe unittest 1750 { 1751 interface I1 1752 { 1753 } 1754 interface I2 : I1 1755 { 1756 } 1757 class A : I2 1758 { 1759 } 1760 class B : A, I1 1761 { 1762 } 1763 class C : B, I2 1764 { 1765 } 1766 static assert(is(InterfacesTuple!C == AliasSeq!(I2, I1))); 1767 1768 static assert(is(InterfacesTuple!Object == AliasSeq!())); 1769 static assert(is(InterfacesTuple!I1 == AliasSeq!())); 1770 } 1771 1772 /** 1773 * Tests whether a value of type $(D_PARAM Rhs) can be assigned to a variable 1774 * of type $(D_PARAM Lhs). 1775 * 1776 * If $(D_PARAM Rhs) isn't specified, $(D_PSYMBOL isAssignable) tests whether a 1777 * value of type $(D_PARAM Lhs) can be assigned to a variable of the same type. 1778 * 1779 * $(D_PSYMBOL isAssignable) tells whether $(D_PARAM Rhs) can be assigned by 1780 * value as well by reference. 1781 * 1782 * Params: 1783 * Lhs = Variable type. 1784 * Rhs = Expression type. 1785 * 1786 * Returns: $(D_KEYWORD true) if a value of type $(D_PARAM Rhs) can be assigned 1787 * to a variable of type $(D_PARAM Lhs), $(D_KEYWORD false) otherwise. 1788 */ 1789 template isAssignable(Lhs, Rhs = Lhs) 1790 { 1791 enum bool isAssignable = is(typeof({ 1792 Lhs lhs = Lhs.init; 1793 Rhs rhs = Rhs.init; 1794 lhs = ((inout ref Rhs) => Rhs.init)(rhs); 1795 })); 1796 } 1797 1798 /// 1799 @nogc nothrow pure @safe unittest 1800 { 1801 static struct S1 1802 { 1803 @disable this(); 1804 @disable this(this); 1805 } 1806 static struct S2 1807 { 1808 void opAssign(S1 s) pure nothrow @safe @nogc 1809 { 1810 } 1811 } 1812 static struct S3 1813 { 1814 void opAssign(ref S1 s) pure nothrow @safe @nogc 1815 { 1816 } 1817 } 1818 static assert(isAssignable!(S2, S1)); 1819 static assert(!isAssignable!(S3, S1)); 1820 1821 static assert(isAssignable!(const(char)[], string)); 1822 static assert(!isAssignable!(string, char[])); 1823 1824 static assert(isAssignable!int); 1825 static assert(!isAssignable!(const int, int)); 1826 } 1827 1828 /** 1829 * Returns template parameters of $(D_PARAM T). 1830 * 1831 * Params: 1832 * T = Template instance. 1833 * 1834 * Returns: Template parameters of $(D_PARAM T). 1835 */ 1836 alias TemplateArgsOf(alias T : Base!Args, alias Base, Args...) = Args; 1837 1838 /// 1839 @nogc nothrow pure @safe unittest 1840 { 1841 template T(A, B) 1842 { 1843 } 1844 static assert(is(TemplateArgsOf!(T!(int, uint)) == AliasSeq!(int, uint))); 1845 } 1846 1847 /** 1848 * Returns a tuple with parameter types of a function. 1849 * 1850 * Params: 1851 * F = A function. 1852 * 1853 * Returns: Tuple with parameter types of a function. 1854 */ 1855 template Parameters(F...) 1856 if (isCallable!F) 1857 { 1858 static if (is(FunctionTypeOf!F T == function)) 1859 { 1860 alias Parameters = T; 1861 } 1862 else 1863 { 1864 static assert(false, "Function has no parameters"); 1865 } 1866 } 1867 1868 /// 1869 @nogc nothrow pure @safe unittest 1870 { 1871 int func(Object, uint[]); 1872 static assert(is(Parameters!func == AliasSeq!(Object, uint[]))); 1873 } 1874 1875 /** 1876 * Returns a string array with all parameter names of a function. 1877 * 1878 * If a parameter has no name, an empty string is placed into array. 1879 * 1880 * Params: 1881 * F = A function. 1882 * 1883 * Returns: Function parameter names. 1884 */ 1885 template ParameterIdentifierTuple(F...) 1886 if (isCallable!F) 1887 { 1888 static if (is(FunctionTypeOf!F Params == __parameters)) 1889 { 1890 string[] Impl() 1891 { 1892 string[] tuple; 1893 1894 foreach (k, P; Params) 1895 { 1896 static if (is(typeof(__traits(identifier, Params[k .. $])))) 1897 { 1898 tuple ~= __traits(identifier, Params[k .. $]); 1899 } 1900 else 1901 { 1902 tuple ~= ""; 1903 } 1904 } 1905 1906 return tuple; 1907 } 1908 enum string[] ParameterIdentifierTuple = Impl(); 1909 } 1910 else 1911 { 1912 static assert(false, "Function has no parameters"); 1913 } 1914 } 1915 1916 /// 1917 @nogc nothrow pure @safe unittest 1918 { 1919 int func(ref Object stuff, uint[] = null, scope uint k = 1); 1920 alias P = ParameterIdentifierTuple!func; 1921 static assert(P[0] == "stuff"); 1922 static assert(P[1] == ""); 1923 static assert(P[2] == "k"); 1924 } 1925 1926 /// Attributes can be attached to a function. 1927 enum FunctionAttribute : uint 1928 { 1929 none = 0x0000, 1930 pure_ = 0x0001, 1931 nothrow_ = 0x0002, 1932 ref_ = 0x0004, 1933 property = 0x0008, 1934 trusted = 0x0010, 1935 safe = 0x0020, 1936 nogc = 0x0040, 1937 system = 0x0080, 1938 const_ = 0x0100, 1939 immutable_ = 0x0200, 1940 inout_ = 0x0400, 1941 shared_ = 0x0800, 1942 return_ = 0x1000, 1943 scope_ = 0x2000, 1944 } 1945 1946 /** 1947 * Retrieves the attributes of the function $(D_PARAM F). 1948 * 1949 * The attributes are returned as a bit-mask of 1950 * $(D_PSYMBOL FunctionAttribute) values. 1951 * 1952 * Params: A function. 1953 * 1954 * Returns: Attributes of the function $(D_PARAM F). 1955 * 1956 * See_Also: $(D_PSYMBOL FunctionAttribute). 1957 */ 1958 template functionAttributes(F...) 1959 if (isCallable!F) 1960 { 1961 uint Impl() 1962 { 1963 uint attrs = FunctionAttribute.none; 1964 foreach (a; __traits(getFunctionAttributes, F[0])) 1965 { 1966 static if (a == "const") 1967 { 1968 attrs |= FunctionAttribute.const_; 1969 } 1970 else static if (a == "immutable") 1971 { 1972 attrs |= FunctionAttribute.immutable_; 1973 } 1974 else static if (a == "inout") 1975 { 1976 attrs |= FunctionAttribute.inout_; 1977 } 1978 else static if (a == "@nogc") 1979 { 1980 attrs |= FunctionAttribute.nogc; 1981 } 1982 else static if (a == "nothrow") 1983 { 1984 attrs |= FunctionAttribute.nothrow_; 1985 } 1986 else static if (a == "@property") 1987 { 1988 attrs |= FunctionAttribute.property; 1989 } 1990 else static if (a == "pure") 1991 { 1992 attrs |= FunctionAttribute.pure_; 1993 } 1994 else static if (a == "ref") 1995 { 1996 attrs |= FunctionAttribute.ref_; 1997 } 1998 else static if (a == "return") 1999 { 2000 attrs |= FunctionAttribute.return_; 2001 } 2002 else static if (a == "@safe") 2003 { 2004 attrs |= FunctionAttribute.safe; 2005 } 2006 else static if (a == "scope") 2007 { 2008 attrs |= FunctionAttribute.scope_; 2009 } 2010 else static if (a == "shared") 2011 { 2012 attrs |= FunctionAttribute.shared_; 2013 } 2014 else static if (a == "@system") 2015 { 2016 attrs |= FunctionAttribute.system; 2017 } 2018 else static if (a == "@trusted") 2019 { 2020 attrs |= FunctionAttribute.trusted; 2021 } 2022 } 2023 return attrs; 2024 } 2025 enum uint functionAttributes = Impl(); 2026 } 2027 2028 /// 2029 @nogc nothrow pure @safe unittest 2030 { 2031 @property ref int func1() pure nothrow @safe @nogc shared scope; 2032 static assert((functionAttributes!func1 & FunctionAttribute.pure_) 2033 == FunctionAttribute.pure_); 2034 static assert((functionAttributes!func1 & FunctionAttribute.nothrow_) 2035 == FunctionAttribute.nothrow_); 2036 static assert((functionAttributes!func1 & FunctionAttribute.safe) 2037 == FunctionAttribute.safe); 2038 static assert((functionAttributes!func1 & FunctionAttribute.nogc) 2039 == FunctionAttribute.nogc); 2040 static assert((functionAttributes!func1 & FunctionAttribute.shared_) 2041 == FunctionAttribute.shared_); 2042 static assert((functionAttributes!func1 & FunctionAttribute.ref_) 2043 == FunctionAttribute.ref_); 2044 static assert((functionAttributes!func1 & FunctionAttribute.property) 2045 == FunctionAttribute.property); 2046 static assert((functionAttributes!func1 & FunctionAttribute.scope_) 2047 == FunctionAttribute.scope_); 2048 static assert((functionAttributes!func1 & FunctionAttribute.system) == 0); 2049 static assert((functionAttributes!func1 & FunctionAttribute.trusted) == 0); 2050 static assert((functionAttributes!func1 & FunctionAttribute.return_) == 0); 2051 } 2052 2053 /** 2054 * Determines whether a function has attribute. 2055 * 2056 * This template should get at least two arguments: the function itself and the 2057 * attributes it should be tested for. If more than one attribute is given, 2058 * $(D_PSYMBOL hasFunctionAttributes) evaluates to $(D_KEYWORD true) if all of 2059 * them are present. The attributes should be $(D_PSYMBOL FunctionAttribute) 2060 * members. 2061 * 2062 * Params: 2063 * Args = The function and attributes. 2064 * 2065 * Returns: 2066 * 2067 * See_Also: $(D_PSYMBOL FunctionAttribute). 2068 */ 2069 template hasFunctionAttributes(Args...) 2070 if (Args.length > 1 2071 && is(typeof(Args[1]) == FunctionAttribute) 2072 && isCallable!(Args[0]) 2073 && allSameType!(Map!(TypeOf, Args[1 .. $]))) 2074 { 2075 enum uint pred(Args_...) = Args_[0] | Args_[1]; 2076 2077 template Reduce(Args_...) 2078 { 2079 static if (Args_.length == 1) 2080 { 2081 enum uint Reduce = Args_[0]; 2082 } 2083 else 2084 { 2085 enum uint Reduce = Reduce!(pred!(Args_[0], Args_[1]), Args_[2 .. $]); 2086 } 2087 } 2088 enum uint field = Reduce!(0, Args[1 .. $]); 2089 enum hasFunctionAttributes = (functionAttributes!(Args[0]) & field) == field; 2090 } 2091 2092 /// 2093 @nogc nothrow pure @safe unittest 2094 { 2095 static struct Range 2096 { 2097 @property auto front() inout 2098 { 2099 return 8; 2100 } 2101 } 2102 static assert(hasFunctionAttributes!(Range.init.front, FunctionAttribute.inout_)); 2103 static assert(!hasFunctionAttributes!(Range.init.front, FunctionAttribute.const_)); 2104 static assert(!hasFunctionAttributes!(Range.init.front, 2105 FunctionAttribute.inout_, FunctionAttribute.const_)); 2106 } 2107 2108 /** 2109 * Returns a tuple with default values of the parameters to $(D_PARAM F). 2110 * 2111 * If a parameter doesn't have a default value, $(D_KEYWORD void) is returned. 2112 * 2113 * Params: 2114 * F = A function. 2115 * 2116 * Returns: Default values of the parameters to $(D_PARAM F). 2117 */ 2118 template ParameterDefaults(F...) 2119 if (isCallable!F) 2120 { 2121 static if (is(FunctionTypeOf!F T == __parameters)) 2122 { 2123 private template GetDefault(size_t i) 2124 { 2125 static if (i == T.length) 2126 { 2127 alias GetDefault = AliasSeq!(); 2128 } 2129 else 2130 { 2131 auto getDefault(T[i .. i + 1] name) 2132 { 2133 return name[0]; 2134 } 2135 static if (is(typeof(getDefault()))) 2136 { 2137 alias Default = Alias!(getDefault()); 2138 } 2139 else 2140 { 2141 alias Default = void; 2142 } 2143 alias GetDefault = AliasSeq!(Default, GetDefault!(i + 1)); 2144 } 2145 } 2146 2147 alias ParameterDefaults = GetDefault!0; 2148 } 2149 } 2150 2151 /// 2152 @nogc nothrow pure @safe unittest 2153 { 2154 void func1(int k, uint b = 5, int[] = [1, 2]); 2155 alias Defaults = ParameterDefaults!func1; 2156 static assert(is(Defaults[0] == void)); 2157 static assert(Defaults[1 .. 3] == AliasSeq!(5, [1, 2])); 2158 } 2159 2160 /** 2161 * Determines whether $(D_PARAM T) has an elaborate destructor. 2162 * 2163 * Only $(D_KEYWORD struct)s and static arrays of $(D_KEYWORD struct)s with the 2164 * length greater than`0` can have elaborate destructors, for all other types 2165 * $(D_PSYMBOL hasElaborateDestructor) evaluates to $(D_KEYWORD false). 2166 * 2167 * An elaborate destructor is an explicitly defined destructor or one generated 2168 * by the compiler. The compiler generates a destructor for a 2169 * $(D_KEYWORD struct) if it has members with an elaborate destructor. 2170 * 2171 * Params: 2172 * T = A type. 2173 * 2174 * Returns: $(D_KEYWORD true) if $(D_PARAM T) has an elaborate destructor, 2175 * $(D_KEYWORD false) otherwise. 2176 */ 2177 template hasElaborateDestructor(T) 2178 { 2179 static if (is(T E : E[L], size_t L)) 2180 { 2181 enum bool hasElaborateDestructor = L > 0 && hasElaborateDestructor!E; 2182 } 2183 else 2184 { 2185 enum bool hasElaborateDestructor = is(T == struct) 2186 && hasMember!(T, "__xdtor"); 2187 } 2188 } 2189 2190 /// 2191 @nogc nothrow pure @safe unittest 2192 { 2193 class C 2194 { 2195 ~this() 2196 { 2197 } 2198 } 2199 static assert(!hasElaborateDestructor!C); 2200 2201 static struct S 2202 { 2203 ~this() 2204 { 2205 } 2206 } 2207 static struct S1 2208 { 2209 S s; 2210 } 2211 static struct S2 2212 { 2213 } 2214 static assert(hasElaborateDestructor!S); // Explicit destructor. 2215 static assert(hasElaborateDestructor!S1); // Compiler-generated destructor. 2216 static assert(!hasElaborateDestructor!S2); // No destructor. 2217 2218 static assert(hasElaborateDestructor!(S[1])); 2219 static assert(!hasElaborateDestructor!(S[0])); 2220 } 2221 2222 /** 2223 * Determines whether $(D_PARAM T) has an elaborate postblit constructor. 2224 * 2225 * Only $(D_KEYWORD struct)s and static arrays of $(D_KEYWORD struct)s with the 2226 * length greater than`0` can have elaborate postblit constructors, for all 2227 * other types $(D_PSYMBOL hasElaborateCopyConstructor) evaluates to 2228 * $(D_KEYWORD false). 2229 * 2230 * An elaborate postblit constructor is an explicitly defined postblit 2231 * constructor or one generated by the compiler. The compiler generates a 2232 * postblit constructor for a 2233 * $(D_KEYWORD struct) if it has members with an elaborate postblit 2234 * constructor. 2235 * 2236 * Params: 2237 * T = A type. 2238 * 2239 * Returns: $(D_KEYWORD true) if $(D_PARAM T) has an elaborate postblit 2240 * constructor, $(D_KEYWORD false) otherwise. 2241 */ 2242 template hasElaborateCopyConstructor(T) 2243 { 2244 static if (is(T E : E[L], size_t L)) 2245 { 2246 enum bool hasElaborateCopyConstructor = L > 0 2247 && hasElaborateCopyConstructor!E; 2248 } 2249 else 2250 { 2251 enum bool hasElaborateCopyConstructor = is(T == struct) 2252 && hasMember!(T, "__xpostblit"); 2253 } 2254 } 2255 2256 /// 2257 @nogc nothrow pure @safe unittest 2258 { 2259 static assert(!hasElaborateCopyConstructor!int); 2260 2261 static struct S 2262 { 2263 this(this) 2264 { 2265 } 2266 } 2267 static struct S1 2268 { 2269 S s; 2270 } 2271 static struct S2 2272 { 2273 } 2274 static assert(hasElaborateCopyConstructor!S); // Explicit destructor. 2275 static assert(hasElaborateCopyConstructor!S1); // Compiler-generated destructor. 2276 static assert(!hasElaborateCopyConstructor!S2); // No destructor. 2277 static assert(hasElaborateCopyConstructor!(S[1])); 2278 static assert(!hasElaborateCopyConstructor!(S[0])); 2279 } 2280 2281 /** 2282 * Determines whether $(D_PARAM T) has an elaborate assign. 2283 * 2284 * Only $(D_KEYWORD struct)s and static arrays of $(D_KEYWORD struct)s with the 2285 * length greater than`0` can have an elaborate assign, for all 2286 * other types $(D_PSYMBOL hasElaborateAssign) evaluates to $(D_KEYWORD false). 2287 * 2288 * An elaborate assign is defined with $(D_INLINECODE opAssign(typeof(this))) 2289 * or $(D_INLINECODE opAssign(ref typeof(this))). An elaborate assign can be 2290 * generated for a $(D_KEYWORD struct) by the compiler if one of the members of 2291 * this $(D_KEYWORD struct) has an elaborate assign. 2292 * 2293 * Params: 2294 * T = A type. 2295 * 2296 * Returns: $(D_KEYWORD true) if $(D_PARAM T) has an elaborate assign, 2297 * $(D_KEYWORD false) otherwise. 2298 */ 2299 template hasElaborateAssign(T) 2300 { 2301 static if (is(T E : E[L], size_t L)) 2302 { 2303 enum bool hasElaborateAssign = L > 0 && hasElaborateAssign!E; 2304 } 2305 else static if (is(T == struct)) 2306 { 2307 private enum bool valueAssign = is(typeof({ T.init.opAssign(T()); })); 2308 enum bool hasElaborateAssign = valueAssign || is(typeof({ 2309 T s; 2310 s.opAssign(s); 2311 })); 2312 } 2313 else 2314 { 2315 enum bool hasElaborateAssign = false; 2316 } 2317 } 2318 2319 /** 2320 * Returns all members of $(D_KEYWORD enum) $(D_PARAM T). 2321 * 2322 * The members of $(D_PARAM T) are typed as $(D_PARAM T), not as a base type 2323 * of the enum. 2324 * 2325 * $(D_PARAM EnumMembers) returns all members of $(D_PARAM T), also if there 2326 * are some duplicates. 2327 * 2328 * Params: 2329 * T = A $(D_KEYWORD enum). 2330 * 2331 * Returns: All members of $(D_PARAM T). 2332 */ 2333 template EnumMembers(T) 2334 if (is(T == enum)) 2335 { 2336 private template getEnumMembers(Args...) 2337 { 2338 static if (Args.length == 1) 2339 { 2340 enum T getEnumMembers = __traits(getMember, T, Args[0]); 2341 } 2342 else 2343 { 2344 alias getEnumMembers = AliasSeq!(__traits(getMember, T, Args[0]), 2345 getEnumMembers!(Args[1 .. $])); 2346 } 2347 } 2348 private alias allMembers = AliasSeq!(__traits(allMembers, T)); 2349 static if (allMembers.length == 1) 2350 { 2351 alias EnumMembers = AliasSeq!(__traits(getMember, T, allMembers)); 2352 } 2353 else 2354 { 2355 alias EnumMembers = getEnumMembers!allMembers; 2356 } 2357 } 2358 2359 /// 2360 @nogc nothrow pure @safe unittest 2361 { 2362 enum E : int 2363 { 2364 one, 2365 two, 2366 three, 2367 } 2368 static assert([EnumMembers!E] == [E.one, E.two, E.three]); 2369 } 2370 2371 /** 2372 * Different than $(D_INLINECODE T.alignof), which is the same for all class 2373 * types, $(D_PSYMBOL classInstanceOf) determines the alignment of the class 2374 * instance and not of its reference. 2375 * 2376 * Params: 2377 * T = A class. 2378 * 2379 * Returns: Alignment of an instance of the class $(D_PARAM T). 2380 */ 2381 template classInstanceAlignment(T) 2382 if (is(T == class)) 2383 { 2384 private enum ptrdiff_t pred(U1, U2) = U1.alignof - U2.alignof; 2385 private alias Fields = typeof(T.tupleof); 2386 enum size_t classInstanceAlignment = Max!(pred, T, Fields).alignof; 2387 } 2388 2389 /// 2390 @nogc nothrow pure @safe unittest 2391 { 2392 class C1 2393 { 2394 } 2395 static assert(classInstanceAlignment!C1 == C1.alignof); 2396 2397 static struct S 2398 { 2399 align(8) 2400 uint s; 2401 2402 int i; 2403 } 2404 class C2 2405 { 2406 S s; 2407 } 2408 static assert(classInstanceAlignment!C2 == S.alignof); 2409 } 2410 2411 /** 2412 * Returns the size in bytes of the state that needs to be allocated to hold an 2413 * object of type $(D_PARAM T). 2414 * 2415 * There is a difference between the `.sizeof`-property and 2416 * $(D_PSYMBOL stateSize) if $(D_PARAM T) is a class or an interface. 2417 * `T.sizeof` is constant on the given architecture then and is the same as 2418 * `size_t.sizeof` and `ptrdiff_t.sizeof`. This is because classes and 2419 * interfaces are reference types and `.sizeof` returns the size of the 2420 * reference which is the same as the size of a pointer. $(D_PSYMBOL stateSize) 2421 * returns the size of the instance itself. 2422 * 2423 * The size of a dynamic array is `size_t.sizeof * 2` since a dynamic array 2424 * stores its length and a data pointer. The size of the static arrays is 2425 * calculated differently since they are value types. It is the array length 2426 * multiplied by the element size. 2427 * 2428 * `stateSize!void` is `1` since $(D_KEYWORD void) is mostly used as a synonym 2429 * for $(D_KEYWORD byte)/$(D_KEYWORD ubyte) in `void*`. 2430 * 2431 * Params: 2432 * T = Object type. 2433 * 2434 * Returns: Size of an instance of type $(D_PARAM T). 2435 */ 2436 template stateSize(T) 2437 { 2438 static if (isPolymorphicType!T) 2439 { 2440 enum size_t stateSize = __traits(classInstanceSize, T); 2441 } 2442 else 2443 { 2444 enum size_t stateSize = T.sizeof; 2445 } 2446 } 2447 2448 /// 2449 @nogc nothrow pure @safe unittest 2450 { 2451 static assert(stateSize!int == 4); 2452 static assert(stateSize!bool == 1); 2453 static assert(stateSize!(int[]) == (size_t.sizeof * 2)); 2454 static assert(stateSize!(short[3]) == 6); 2455 2456 static struct Empty 2457 { 2458 } 2459 static assert(stateSize!Empty == 1); 2460 static assert(stateSize!void == 1); 2461 } 2462 2463 /** 2464 * Tests whether $(D_INLINECODE pred(T)) can be used as condition in an 2465 * $(D_KEYWORD if)-statement or a ternary operator. 2466 * 2467 * $(D_PARAM pred) is an optional parameter. By default $(D_PSYMBOL ifTestable) 2468 * tests whether $(D_PARAM T) itself is usable as condition in an 2469 * $(D_KEYWORD if)-statement or a ternary operator, i.e. if it a value of type 2470 * $(D_PARAM T) can be converted to a boolean. 2471 * 2472 * Params: 2473 * T = A type. 2474 * pred = Function with one argument. 2475 * 2476 * Returns: $(D_KEYWORD true) if $(D_INLINECODE pred(T)) can be used as 2477 * condition in an $(D_KEYWORD if)-statement or a ternary operator. 2478 */ 2479 template ifTestable(T, alias pred = a => a) 2480 { 2481 enum bool ifTestable = is(typeof(pred(T.init) ? true : false)); 2482 } 2483 2484 /// 2485 @nogc nothrow pure @safe unittest 2486 { 2487 static assert(ifTestable!int); 2488 2489 static struct S1 2490 { 2491 } 2492 static assert(!ifTestable!S1); 2493 2494 static struct S2 2495 { 2496 bool opCast(T : bool)() 2497 { 2498 return true; 2499 } 2500 } 2501 static assert(ifTestable!S2); 2502 } 2503 2504 /** 2505 * Returns a compile-time tuple of user-defined attributes (UDA) attached to 2506 * $(D_PARAM symbol). 2507 * 2508 * $(D_PARAM symbol) can be: 2509 * 2510 * $(DL 2511 * $(DT Template) 2512 * $(DD The attribute is matched if it is an instance of the template 2513 * $(D_PARAM attr).) 2514 * $(DT Type) 2515 * $(DD The attribute is matched if it its type is $(D_PARAM attr).) 2516 * $(DT Expression) 2517 * $(DD The attribute is matched if it equals to $(D_PARAM attr).) 2518 * ) 2519 * 2520 * If $(D_PARAM attr) isn't given, all user-defined attributes of 2521 * $(D_PARAM symbol) are returned. 2522 * 2523 * Params: 2524 * symbol = A symbol. 2525 * attr = User-defined attribute. 2526 * 2527 * Returns: A tuple of user-defined attributes attached to $(D_PARAM symbol) 2528 * and matching $(D_PARAM attr). 2529 * 2530 * See_Also: $(LINK2 https://dlang.org/spec/attribute.html#uda, 2531 * User Defined Attributes). 2532 */ 2533 template getUDAs(alias symbol, alias attr) 2534 { 2535 private template FindUDA(T...) 2536 { 2537 static if (T.length == 0) 2538 { 2539 alias FindUDA = AliasSeq!(); 2540 } 2541 else static if ((isTypeTuple!attr && is(TypeOf!(T[0]) == attr)) 2542 || (is(typeof(T[0] == attr)) && (T[0] == attr)) 2543 || isInstanceOf!(attr, TypeOf!(T[0]))) 2544 { 2545 alias FindUDA = AliasSeq!(T[0], FindUDA!(T[1 .. $])); 2546 } 2547 else 2548 { 2549 alias FindUDA = FindUDA!(T[1 .. $]); 2550 } 2551 } 2552 alias getUDAs = FindUDA!(__traits(getAttributes, symbol)); 2553 } 2554 2555 /// 2556 alias getUDAs(alias symbol) = AliasSeq!(__traits(getAttributes, symbol)); 2557 2558 /// 2559 @nogc nothrow pure @safe unittest 2560 { 2561 static struct Attr 2562 { 2563 int i; 2564 } 2565 @Attr int a; 2566 static assert(getUDAs!(a, Attr).length == 1); 2567 2568 @Attr(8) int b; 2569 static assert(getUDAs!(b, Attr).length == 1); 2570 static assert(getUDAs!(b, Attr)[0].i == 8); 2571 static assert(getUDAs!(b, Attr(8)).length == 1); 2572 static assert(getUDAs!(b, Attr(7)).length == 0); 2573 2574 @("string", 5) int c; 2575 static assert(getUDAs!(c, "string").length == 1); 2576 static assert(getUDAs!(c, 5).length == 1); 2577 static assert(getUDAs!(c, "String").length == 0); 2578 static assert(getUDAs!(c, 4).length == 0); 2579 2580 static struct T(U) 2581 { 2582 enum U s = 7; 2583 U i; 2584 } 2585 @T!int @T!int(8) int d; 2586 static assert(getUDAs!(d, T).length == 2); 2587 static assert(getUDAs!(d, T)[0].s == 7); 2588 static assert(getUDAs!(d, T)[1].i == 8); 2589 2590 @T int e; 2591 static assert(getUDAs!(e, T).length == 0); 2592 } 2593 2594 /** 2595 * Determines whether $(D_PARAM symbol) has user-defined attribute 2596 * $(D_PARAM attr) attached to it. 2597 * 2598 * Params: 2599 * symbol = A symbol. 2600 * attr = User-defined attribute. 2601 * 2602 * Returns: $(D_KEYWORD true) if $(D_PARAM symbol) has user-defined attribute 2603 * $(D_PARAM attr), $(D_KEYWORD false) otherwise. 2604 * 2605 * See_Also: $(LINK2 https://dlang.org/spec/attribute.html#uda, 2606 * User Defined Attributes). 2607 */ 2608 template hasUDA(alias symbol, alias attr) 2609 { 2610 enum bool hasUDA = getUDAs!(symbol, attr).length != 0; 2611 } 2612 2613 /// 2614 @nogc nothrow pure @safe unittest 2615 { 2616 static struct Attr1 2617 { 2618 } 2619 static struct Attr2 2620 { 2621 } 2622 @Attr1 int a; 2623 static assert(hasUDA!(a, Attr1)); 2624 static assert(!hasUDA!(a, Attr2)); 2625 } 2626 2627 /** 2628 * If $(D_PARAM T) is a type, constructs its default value, otherwise 2629 * $(D_PSYMBOL evalUDA) aliases itself to $(D_PARAM T). 2630 * 2631 * This template is useful when working with UDAs with default parameters, 2632 * i.e. if an attribute can be given as `@Attr` or `@Attr("param")`, 2633 * $(D_PSYMBOL evalUDA) makes `@Attr()` from `@Attr`, but returns 2634 * `@Attr("param")` as is. 2635 * 2636 * $(D_PARAM T) (or its type if it isn't a type already) should have a default 2637 * constructor. 2638 * 2639 * Params: 2640 * T = User Defined Attribute. 2641 */ 2642 alias evalUDA(alias T) = T; 2643 2644 /// ditto 2645 alias evalUDA(T) = Alias!(T()); 2646 2647 /// 2648 @nogc nothrow pure @safe unittest 2649 { 2650 static struct Length 2651 { 2652 size_t length = 8; 2653 } 2654 @Length @Length(0) int i; 2655 alias uda = AliasSeq!(__traits(getAttributes, i)); 2656 2657 alias attr1 = evalUDA!(uda[0]); 2658 alias attr2 = evalUDA!(uda[1]); 2659 2660 static assert(is(typeof(attr1) == Length)); 2661 static assert(is(typeof(attr2) == Length)); 2662 2663 static assert(attr1.length == 8); 2664 static assert(attr2.length == 0); 2665 } 2666 2667 /** 2668 * Tests whether $(D_PARAM T) is an inner class, i.e. a class nested inside 2669 * another class. 2670 * 2671 * All inner classes get `outer` propery automatically generated, which points 2672 * to its parent class, though it can be explicitly defined to be something 2673 * different. If $(D_PARAM T) does this, $(D_PSYMBOL isInnerClass) 2674 * evaluates to $(D_KEYWORD false). 2675 * 2676 * Params: 2677 * T = Class to be tested. 2678 * 2679 * Returns $(D_KEYWORD true) if $(D_PARAM T) is an inner class, 2680 * $(D_KEYWORD false) otherwise. 2681 */ 2682 template isInnerClass(T) 2683 { 2684 static if (is(T == class) && is(typeof(T.outer) == class)) 2685 { 2686 enum bool isInnerClass = !canFind!("outer", __traits(allMembers, T)); 2687 } 2688 else 2689 { 2690 enum bool isInnerClass = false; 2691 } 2692 } 2693 2694 /// 2695 @nogc nothrow pure @safe unittest 2696 { 2697 class A 2698 { 2699 } 2700 class O 2701 { 2702 class I 2703 { 2704 } 2705 class Fake 2706 { 2707 bool outer; 2708 } 2709 } 2710 static assert(!isInnerClass!(O)); 2711 static assert(isInnerClass!(O.I)); 2712 static assert(!isInnerClass!(O.Fake)); 2713 } 2714 2715 /** 2716 * Returns the types of all members of $(D_PARAM T). 2717 * 2718 * If $(D_PARAM T) is a $(D_KEYWORD struct) or $(D_KEYWORD union) or 2719 * $(D_KEYWORD class), returns the types of all its fields. It is actually the 2720 * same as `T.tupleof`, but the content pointer for the nested type isn't 2721 * included. 2722 * 2723 * If $(D_PARAM T) is neither a $(D_KEYWORD struct) nor $(D_KEYWORD union) nor 2724 * $(D_KEYWORD class), $(D_PSYMBOL Fields) returns an $(D_PSYMBOL AliasSeq) 2725 * with the single element $(D_PARAM T). 2726 * 2727 * Params: 2728 * T = A type. 2729 * 2730 * Returns: $(D_PARAM T)'s fields. 2731 */ 2732 template Fields(T) 2733 { 2734 static if ((is(T == struct) || is(T == union)) && isNested!T) 2735 { 2736 // The last element of .tupleof of a nested struct or union is "this", 2737 // the context pointer, type "void*". 2738 alias Fields = typeof(T.tupleof[0 .. $ - 1]); 2739 } 2740 else static if (is(T == class) || is(T == struct) || is(T == union)) 2741 { 2742 alias Fields = typeof(T.tupleof); 2743 } 2744 else 2745 { 2746 alias Fields = AliasSeq!T; 2747 } 2748 } 2749 2750 /// 2751 @nogc nothrow pure @safe unittest 2752 { 2753 struct Nested 2754 { 2755 int i; 2756 2757 void func() 2758 { 2759 } 2760 } 2761 static assert(is(Fields!Nested == AliasSeq!int)); 2762 2763 class C 2764 { 2765 uint u; 2766 } 2767 static assert(is(Fields!C == AliasSeq!uint)); 2768 2769 static assert(is(Fields!short == AliasSeq!short)); 2770 } 2771 2772 /** 2773 * Determines whether all $(D_PARAM Types) are the same. 2774 * 2775 * If $(D_PARAM Types) is empty, returns $(D_KEYWORD true). 2776 * 2777 * Params: 2778 * Types = Type sequence. 2779 * 2780 * Returns: $(D_KEYWORD true) if all $(D_PARAM Types) are the same, 2781 * $(D_KEYWORD false) otherwise. 2782 */ 2783 template allSameType(Types...) 2784 { 2785 static if (Types.length == 0) 2786 { 2787 enum bool allSameType = true; 2788 } 2789 else 2790 { 2791 private enum bool sameType(T) = is(T == Types[0]); 2792 2793 enum bool allSameType = allSatisfy!(sameType, Types[1 .. $]); 2794 } 2795 } 2796 2797 /// 2798 @nogc nothrow pure @safe unittest 2799 { 2800 static assert(allSameType!()); 2801 static assert(allSameType!int); 2802 static assert(allSameType!(int, int, int)); 2803 static assert(!allSameType!(int, uint, int)); 2804 static assert(!allSameType!(int, uint, short)); 2805 } 2806 2807 /** 2808 * Determines whether values of type $(D_PARAM T) can be compared for equality, 2809 * i.e. using `==` or `!=` binary operators. 2810 * 2811 * Params: 2812 * T = Type to test. 2813 * 2814 * Returns: $(D_KEYWORD true) if $(D_PARAM T) can be compared for equality, 2815 * $(D_KEYWORD false) otherwise. 2816 */ 2817 enum bool isEqualityComparable(T) = ifTestable!(T, a => a == a); 2818 2819 /// 2820 @nogc nothrow pure @safe unittest 2821 { 2822 static assert(isEqualityComparable!int); 2823 } 2824 2825 /** 2826 * Determines whether values of type $(D_PARAM T) can be compared for ordering, 2827 * i.e. using `>`, `>=`, `<` or `<=` binary operators. 2828 * 2829 * Params: 2830 * T = Type to test. 2831 * 2832 * Returns: $(D_KEYWORD true) if $(D_PARAM T) can be compared for ordering, 2833 * $(D_KEYWORD false) otherwise. 2834 */ 2835 enum bool isOrderingComparable(T) = ifTestable!(T, a => a > a); 2836 2837 /// 2838 @nogc nothrow pure @safe unittest 2839 { 2840 static assert(isOrderingComparable!int); 2841 }