1// Written in the D programming language. 2 3/** 4 * Templates to manipulate template argument lists (also known as type lists). 5 * 6 * Some operations on alias sequences are built in to the language, 7 * such as TL[$(I n)] which gets the $(I n)th type from the 8 * alias sequence. TL[$(I lwr) .. $(I upr)] returns a new type 9 * list that is a slice of the old one. 10 * 11 * Several templates in this module use or operate on eponymous templates that 12 * take a single argument and evaluate to a boolean constant. Such templates 13 * are referred to as $(I template predicates). 14 * 15 * $(SCRIPT inhibitQuickIndex = 1;) 16 * $(DIVC quickindex, 17 * $(BOOKTABLE , 18 * $(TR $(TH Category) $(TH Templates)) 19 * $(TR $(TD Building blocks) $(TD 20 * $(LREF Alias) 21 * $(LREF AliasSeq) 22 * $(LREF aliasSeqOf) 23 * )) 24 * $(TR $(TD Alias sequence filtering) $(TD 25 * $(LREF Erase) 26 * $(LREF EraseAll) 27 * $(LREF Filter) 28 * $(LREF NoDuplicates) 29 * $(LREF Stride) 30 * )) 31 * $(TR $(TD Alias sequence type hierarchy) $(TD 32 * $(LREF DerivedToFront) 33 * $(LREF MostDerived) 34 * )) 35 * $(TR $(TD Alias sequence transformation) $(TD 36 * $(LREF Repeat) 37 * $(LREF Replace) 38 * $(LREF ReplaceAll) 39 * $(LREF Reverse) 40 * $(LREF staticMap) 41 * $(LREF staticSort) 42 * )) 43 * $(TR $(TD Alias sequence searching) $(TD 44 * $(LREF allSatisfy) 45 * $(LREF anySatisfy) 46 * $(LREF staticIndexOf) 47 * )) 48 * $(TR $(TD Template predicates) $(TD 49 * $(LREF templateAnd) 50 * $(LREF templateNot) 51 * $(LREF templateOr) 52 * $(LREF staticIsSorted) 53 * )) 54 * $(TR $(TD Template instantiation) $(TD 55 * $(LREF ApplyLeft) 56 * $(LREF ApplyRight) 57 * )) 58 * )) 59 * 60 * References: 61 * Based on ideas in Table 3.1 from 62 * $(LINK2 http://amazon.com/exec/obidos/ASIN/0201704315/ref=ase_classicempire/102-2957199-2585768, 63 * Modern C++ Design), 64 * Andrei Alexandrescu (Addison-Wesley Professional, 2001) 65 * Copyright: Copyright Digital Mars 2005 - 2015. 66 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 67 * Authors: 68 * $(HTTP digitalmars.com, Walter Bright), 69 * $(HTTP klickverbot.at, David Nadlinger) 70 * Source: $(PHOBOSSRC std/_meta.d) 71 */ 72 73module std.meta; 74 75/** 76 * Creates a sequence of zero or more aliases. This is most commonly 77 * used as template parameters or arguments. 78 * 79 * In previous versions of Phobos, this was known as `TypeTuple`. 80 */ 81template AliasSeq(TList...) 82{ 83 alias AliasSeq = TList; 84} 85 86/// 87@safe unittest 88{ 89 import std.meta; 90 alias TL = AliasSeq!(int, double); 91 92 int foo(TL td) // same as int foo(int, double); 93 { 94 return td[0] + cast(int) td[1]; 95 } 96} 97 98/// 99@safe unittest 100{ 101 alias TL = AliasSeq!(int, double); 102 103 alias Types = AliasSeq!(TL, char); 104 static assert(is(Types == AliasSeq!(int, double, char))); 105} 106 107 108/** 109 Returns an `AliasSeq` expression of `Func` being 110 applied to every variadic template argument. 111 */ 112 113/// 114@safe unittest 115{ 116 auto ref ArgCall(alias Func, alias arg)() 117 { 118 return Func(arg); 119 } 120 121 template Map(alias Func, args...) 122 { 123 static if (args.length > 1) 124 { 125 alias Map = AliasSeq!(ArgCall!(Func, args[0]), Map!(Func, args[1 .. $])); 126 } 127 else 128 { 129 alias Map = ArgCall!(Func, args[0]); 130 } 131 } 132 133 static int square(int arg) 134 { 135 return arg * arg; 136 } 137 138 static int refSquare(ref int arg) 139 { 140 arg *= arg; 141 return arg; 142 } 143 144 static ref int refRetSquare(ref int arg) 145 { 146 arg *= arg; 147 return arg; 148 } 149 150 static void test(int a, int b) 151 { 152 assert(a == 4); 153 assert(b == 16); 154 } 155 156 static void testRef(ref int a, ref int b) 157 { 158 assert(a++ == 16); 159 assert(b++ == 256); 160 } 161 162 static int a = 2; 163 static int b = 4; 164 165 test(Map!(square, a, b)); 166 167 test(Map!(refSquare, a, b)); 168 assert(a == 4); 169 assert(b == 16); 170 171 testRef(Map!(refRetSquare, a, b)); 172 assert(a == 17); 173 assert(b == 257); 174} 175 176/** 177 * Allows `alias`ing of any single symbol, type or compile-time expression. 178 * 179 * Not everything can be directly aliased. An alias cannot be declared 180 * of - for example - a literal: 181 * 182 * `alias a = 4; //Error` 183 * 184 * With this template any single entity can be aliased: 185 * 186 * `alias b = Alias!4; //OK` 187 * 188 * See_Also: 189 * To alias more than one thing at once, use $(LREF AliasSeq) 190 */ 191alias Alias(alias a) = a; 192 193/// Ditto 194alias Alias(T) = T; 195 196/// 197@safe unittest 198{ 199 // Without Alias this would fail if Args[0] was e.g. a value and 200 // some logic would be needed to detect when to use enum instead 201 alias Head(Args ...) = Alias!(Args[0]); 202 alias Tail(Args ...) = Args[1 .. $]; 203 204 alias Blah = AliasSeq!(3, int, "hello"); 205 static assert(Head!Blah == 3); 206 static assert(is(Head!(Tail!Blah) == int)); 207 static assert((Tail!Blah)[1] == "hello"); 208} 209 210/// 211@safe unittest 212{ 213 alias a = Alias!(123); 214 static assert(a == 123); 215 216 enum abc = 1; 217 alias b = Alias!(abc); 218 static assert(b == 1); 219 220 alias c = Alias!(3 + 4); 221 static assert(c == 7); 222 223 alias concat = (s0, s1) => s0 ~ s1; 224 alias d = Alias!(concat("Hello", " World!")); 225 static assert(d == "Hello World!"); 226 227 alias e = Alias!(int); 228 static assert(is(e == int)); 229 230 alias f = Alias!(AliasSeq!(int)); 231 static assert(!is(typeof(f[0]))); //not an AliasSeq 232 static assert(is(f == int)); 233 234 auto g = 6; 235 alias h = Alias!g; 236 ++h; 237 assert(g == 7); 238} 239 240package template OldAlias(alias a) 241{ 242 static if (__traits(compiles, { alias x = a; })) 243 alias OldAlias = a; 244 else static if (__traits(compiles, { enum x = a; })) 245 enum OldAlias = a; 246 else 247 static assert(0, "Cannot alias " ~ a.stringof); 248} 249 250import std.traits : isAggregateType, Unqual; 251 252package template OldAlias(T) 253if (!isAggregateType!T || is(Unqual!T == T)) 254{ 255 alias OldAlias = T; 256} 257 258@safe unittest 259{ 260 static struct Foo {} 261 static assert(is(OldAlias!(const(Foo)) == Foo)); 262 static assert(is(OldAlias!(const(int)) == const(int))); 263 static assert(OldAlias!123 == 123); 264 enum abc = 123; 265 static assert(OldAlias!abc == 123); 266} 267 268/** 269 * Returns the index of the first occurrence of type T in the 270 * sequence of zero or more types TList. 271 * If not found, -1 is returned. 272 */ 273template staticIndexOf(T, TList...) 274{ 275 enum staticIndexOf = genericIndexOf!(T, TList).index; 276} 277 278/// Ditto 279template staticIndexOf(alias T, TList...) 280{ 281 enum staticIndexOf = genericIndexOf!(T, TList).index; 282} 283 284/// 285@safe unittest 286{ 287 import std.stdio; 288 289 void foo() 290 { 291 writefln("The index of long is %s", 292 staticIndexOf!(long, AliasSeq!(int, long, double))); 293 // prints: The index of long is 1 294 } 295} 296 297// [internal] 298private template genericIndexOf(args...) 299if (args.length >= 1) 300{ 301 alias e = OldAlias!(args[0]); 302 alias tuple = args[1 .. $]; 303 304 static if (tuple.length) 305 { 306 alias head = OldAlias!(tuple[0]); 307 alias tail = tuple[1 .. $]; 308 309 static if (isSame!(e, head)) 310 { 311 enum index = 0; 312 } 313 else 314 { 315 enum next = genericIndexOf!(e, tail).index; 316 enum index = (next == -1) ? -1 : 1 + next; 317 } 318 } 319 else 320 { 321 enum index = -1; 322 } 323} 324 325@safe unittest 326{ 327 static assert(staticIndexOf!( byte, byte, short, int, long) == 0); 328 static assert(staticIndexOf!(short, byte, short, int, long) == 1); 329 static assert(staticIndexOf!( int, byte, short, int, long) == 2); 330 static assert(staticIndexOf!( long, byte, short, int, long) == 3); 331 static assert(staticIndexOf!( char, byte, short, int, long) == -1); 332 static assert(staticIndexOf!( -1, byte, short, int, long) == -1); 333 static assert(staticIndexOf!(void) == -1); 334 335 static assert(staticIndexOf!("abc", "abc", "def", "ghi", "jkl") == 0); 336 static assert(staticIndexOf!("def", "abc", "def", "ghi", "jkl") == 1); 337 static assert(staticIndexOf!("ghi", "abc", "def", "ghi", "jkl") == 2); 338 static assert(staticIndexOf!("jkl", "abc", "def", "ghi", "jkl") == 3); 339 static assert(staticIndexOf!("mno", "abc", "def", "ghi", "jkl") == -1); 340 static assert(staticIndexOf!( void, "abc", "def", "ghi", "jkl") == -1); 341 static assert(staticIndexOf!(42) == -1); 342 343 static assert(staticIndexOf!(void, 0, "void", void) == 2); 344 static assert(staticIndexOf!("void", 0, void, "void") == 2); 345} 346 347/** 348 * Returns an `AliasSeq` created from TList with the first occurrence, 349 * if any, of T removed. 350 */ 351template Erase(T, TList...) 352{ 353 alias Erase = GenericErase!(T, TList).result; 354} 355 356/// Ditto 357template Erase(alias T, TList...) 358{ 359 alias Erase = GenericErase!(T, TList).result; 360} 361 362/// 363@safe unittest 364{ 365 alias Types = AliasSeq!(int, long, double, char); 366 alias TL = Erase!(long, Types); 367 static assert(is(TL == AliasSeq!(int, double, char))); 368} 369 370// [internal] 371private template GenericErase(args...) 372if (args.length >= 1) 373{ 374 alias e = OldAlias!(args[0]); 375 alias tuple = args[1 .. $] ; 376 377 static if (tuple.length) 378 { 379 alias head = OldAlias!(tuple[0]); 380 alias tail = tuple[1 .. $]; 381 382 static if (isSame!(e, head)) 383 alias result = tail; 384 else 385 alias result = AliasSeq!(head, GenericErase!(e, tail).result); 386 } 387 else 388 { 389 alias result = AliasSeq!(); 390 } 391} 392 393@safe unittest 394{ 395 static assert(Pack!(Erase!(int, 396 short, int, int, 4)). 397 equals!(short, int, 4)); 398 399 static assert(Pack!(Erase!(1, 400 real, 3, 1, 4, 1, 5, 9)). 401 equals!(real, 3, 4, 1, 5, 9)); 402} 403 404 405/** 406 * Returns an `AliasSeq` created from TList with the all occurrences, 407 * if any, of T removed. 408 */ 409template EraseAll(T, TList...) 410{ 411 alias EraseAll = GenericEraseAll!(T, TList).result; 412} 413 414/// Ditto 415template EraseAll(alias T, TList...) 416{ 417 alias EraseAll = GenericEraseAll!(T, TList).result; 418} 419 420/// 421@safe unittest 422{ 423 alias Types = AliasSeq!(int, long, long, int); 424 425 alias TL = EraseAll!(long, Types); 426 static assert(is(TL == AliasSeq!(int, int))); 427} 428 429// [internal] 430private template GenericEraseAll(args...) 431if (args.length >= 1) 432{ 433 alias e = OldAlias!(args[0]); 434 alias tuple = args[1 .. $]; 435 436 static if (tuple.length) 437 { 438 alias head = OldAlias!(tuple[0]); 439 alias tail = tuple[1 .. $]; 440 alias next = AliasSeq!( 441 GenericEraseAll!(e, tail[0..$/2]).result, 442 GenericEraseAll!(e, tail[$/2..$]).result 443 ); 444 445 static if (isSame!(e, head)) 446 alias result = next; 447 else 448 alias result = AliasSeq!(head, next); 449 } 450 else 451 { 452 alias result = AliasSeq!(); 453 } 454} 455 456@safe unittest 457{ 458 static assert(Pack!(EraseAll!(int, 459 short, int, int, 4)). 460 equals!(short, 4)); 461 462 static assert(Pack!(EraseAll!(1, 463 real, 3, 1, 4, 1, 5, 9)). 464 equals!(real, 3, 4, 5, 9)); 465} 466 467 468/** 469 * Returns an `AliasSeq` created from TList with the all duplicate 470 * types removed. 471 */ 472template NoDuplicates(TList...) 473{ 474 template EraseAllN(uint N, T...) 475 { 476 static if (N <= 1) 477 { 478 alias EraseAllN = T; 479 } 480 else 481 { 482 alias EraseAllN = EraseAllN!(N-1, T[1 .. N], EraseAll!(T[0], T[N..$])); 483 } 484 } 485 static if (TList.length > 500) 486 { 487 enum steps = 16; 488 alias first = NoDuplicates!(TList[0 .. steps]); 489 alias NoDuplicates = NoDuplicates!(EraseAllN!(first.length, first, TList[steps..$])); 490 } 491 else static if (TList.length == 0) 492 { 493 alias NoDuplicates = TList; 494 } 495 else 496 { 497 alias NoDuplicates = 498 AliasSeq!(TList[0], NoDuplicates!(EraseAll!(TList[0], TList[1 .. $]))); 499 } 500} 501 502/// 503@safe unittest 504{ 505 alias Types = AliasSeq!(int, long, long, int, float); 506 507 alias TL = NoDuplicates!(Types); 508 static assert(is(TL == AliasSeq!(int, long, float))); 509} 510 511@safe unittest 512{ 513 // Bugzilla 14561: huge enums 514 alias LongList = Repeat!(1500, int); 515 static assert(NoDuplicates!LongList.length == 1); 516} 517 518@safe unittest 519{ 520 static assert( 521 Pack!( 522 NoDuplicates!(1, int, 1, NoDuplicates, int, NoDuplicates, real)) 523 .equals!(1, int, NoDuplicates, real)); 524} 525 526 527/** 528 * Returns an `AliasSeq` created from TList with the first occurrence 529 * of type T, if found, replaced with type U. 530 */ 531template Replace(T, U, TList...) 532{ 533 alias Replace = GenericReplace!(T, U, TList).result; 534} 535 536/// Ditto 537template Replace(alias T, U, TList...) 538{ 539 alias Replace = GenericReplace!(T, U, TList).result; 540} 541 542/// Ditto 543template Replace(T, alias U, TList...) 544{ 545 alias Replace = GenericReplace!(T, U, TList).result; 546} 547 548/// Ditto 549template Replace(alias T, alias U, TList...) 550{ 551 alias Replace = GenericReplace!(T, U, TList).result; 552} 553 554/// 555@safe unittest 556{ 557 alias Types = AliasSeq!(int, long, long, int, float); 558 559 alias TL = Replace!(long, char, Types); 560 static assert(is(TL == AliasSeq!(int, char, long, int, float))); 561} 562 563// [internal] 564private template GenericReplace(args...) 565if (args.length >= 2) 566{ 567 alias from = OldAlias!(args[0]); 568 alias to = OldAlias!(args[1]); 569 alias tuple = args[2 .. $]; 570 571 static if (tuple.length) 572 { 573 alias head = OldAlias!(tuple[0]); 574 alias tail = tuple[1 .. $]; 575 576 static if (isSame!(from, head)) 577 alias result = AliasSeq!(to, tail); 578 else 579 alias result = AliasSeq!(head, 580 GenericReplace!(from, to, tail).result); 581 } 582 else 583 { 584 alias result = AliasSeq!(); 585 } 586 } 587 588@safe unittest 589{ 590 static assert(Pack!(Replace!(byte, ubyte, 591 short, byte, byte, byte)). 592 equals!(short, ubyte, byte, byte)); 593 594 static assert(Pack!(Replace!(1111, byte, 595 2222, 1111, 1111, 1111)). 596 equals!(2222, byte, 1111, 1111)); 597 598 static assert(Pack!(Replace!(byte, 1111, 599 short, byte, byte, byte)). 600 equals!(short, 1111, byte, byte)); 601 602 static assert(Pack!(Replace!(1111, "11", 603 2222, 1111, 1111, 1111)). 604 equals!(2222, "11", 1111, 1111)); 605} 606 607/** 608 * Returns an `AliasSeq` created from TList with all occurrences 609 * of type T, if found, replaced with type U. 610 */ 611template ReplaceAll(T, U, TList...) 612{ 613 alias ReplaceAll = GenericReplaceAll!(T, U, TList).result; 614} 615 616/// Ditto 617template ReplaceAll(alias T, U, TList...) 618{ 619 alias ReplaceAll = GenericReplaceAll!(T, U, TList).result; 620} 621 622/// Ditto 623template ReplaceAll(T, alias U, TList...) 624{ 625 alias ReplaceAll = GenericReplaceAll!(T, U, TList).result; 626} 627 628/// Ditto 629template ReplaceAll(alias T, alias U, TList...) 630{ 631 alias ReplaceAll = GenericReplaceAll!(T, U, TList).result; 632} 633 634/// 635@safe unittest 636{ 637 alias Types = AliasSeq!(int, long, long, int, float); 638 639 alias TL = ReplaceAll!(long, char, Types); 640 static assert(is(TL == AliasSeq!(int, char, char, int, float))); 641} 642 643// [internal] 644private template GenericReplaceAll(args...) 645if (args.length >= 2) 646{ 647 alias from = OldAlias!(args[0]); 648 alias to = OldAlias!(args[1]); 649 alias tuple = args[2 .. $]; 650 651 static if (tuple.length) 652 { 653 alias head = OldAlias!(tuple[0]); 654 alias tail = tuple[1 .. $]; 655 alias next = GenericReplaceAll!(from, to, tail).result; 656 657 static if (isSame!(from, head)) 658 alias result = AliasSeq!(to, next); 659 else 660 alias result = AliasSeq!(head, next); 661 } 662 else 663 { 664 alias result = AliasSeq!(); 665 } 666} 667 668@safe unittest 669{ 670 static assert(Pack!(ReplaceAll!(byte, ubyte, 671 byte, short, byte, byte)). 672 equals!(ubyte, short, ubyte, ubyte)); 673 674 static assert(Pack!(ReplaceAll!(1111, byte, 675 1111, 2222, 1111, 1111)). 676 equals!(byte, 2222, byte, byte)); 677 678 static assert(Pack!(ReplaceAll!(byte, 1111, 679 byte, short, byte, byte)). 680 equals!(1111, short, 1111, 1111)); 681 682 static assert(Pack!(ReplaceAll!(1111, "11", 683 1111, 2222, 1111, 1111)). 684 equals!("11", 2222, "11", "11")); 685} 686 687/** 688 * Returns an `AliasSeq` created from TList with the order reversed. 689 */ 690template Reverse(TList...) 691{ 692 static if (TList.length <= 1) 693 { 694 alias Reverse = TList; 695 } 696 else 697 { 698 alias Reverse = 699 AliasSeq!( 700 Reverse!(TList[$/2 .. $ ]), 701 Reverse!(TList[ 0 .. $/2])); 702 } 703} 704 705/// 706@safe unittest 707{ 708 alias Types = AliasSeq!(int, long, long, int, float); 709 710 alias TL = Reverse!(Types); 711 static assert(is(TL == AliasSeq!(float, int, long, long, int))); 712} 713 714/** 715 * Returns the type from TList that is the most derived from type T. 716 * If none are found, T is returned. 717 */ 718template MostDerived(T, TList...) 719{ 720 static if (TList.length == 0) 721 alias MostDerived = T; 722 else static if (is(TList[0] : T)) 723 alias MostDerived = MostDerived!(TList[0], TList[1 .. $]); 724 else 725 alias MostDerived = MostDerived!(T, TList[1 .. $]); 726} 727 728/// 729@safe unittest 730{ 731 class A { } 732 class B : A { } 733 class C : B { } 734 alias Types = AliasSeq!(A, C, B); 735 736 MostDerived!(Object, Types) x; // x is declared as type C 737 static assert(is(typeof(x) == C)); 738} 739 740/** 741 * Returns the `AliasSeq` TList with the types sorted so that the most 742 * derived types come first. 743 */ 744template DerivedToFront(TList...) 745{ 746 static if (TList.length == 0) 747 alias DerivedToFront = TList; 748 else 749 alias DerivedToFront = 750 AliasSeq!(MostDerived!(TList[0], TList[1 .. $]), 751 DerivedToFront!(ReplaceAll!(MostDerived!(TList[0], TList[1 .. $]), 752 TList[0], 753 TList[1 .. $]))); 754} 755 756/// 757@safe unittest 758{ 759 class A { } 760 class B : A { } 761 class C : B { } 762 alias Types = AliasSeq!(A, C, B); 763 764 alias TL = DerivedToFront!(Types); 765 static assert(is(TL == AliasSeq!(C, B, A))); 766} 767 768/** 769Evaluates to $(D AliasSeq!(F!(T[0]), F!(T[1]), ..., F!(T[$ - 1]))). 770 */ 771template staticMap(alias F, T...) 772{ 773 static if (T.length == 0) 774 { 775 alias staticMap = AliasSeq!(); 776 } 777 else static if (T.length == 1) 778 { 779 alias staticMap = AliasSeq!(F!(T[0])); 780 } 781 else 782 { 783 alias staticMap = 784 AliasSeq!( 785 staticMap!(F, T[ 0 .. $/2]), 786 staticMap!(F, T[$/2 .. $ ])); 787 } 788} 789 790/// 791@safe unittest 792{ 793 import std.traits : Unqual; 794 alias TL = staticMap!(Unqual, int, const int, immutable int); 795 static assert(is(TL == AliasSeq!(int, int, int))); 796} 797 798@safe unittest 799{ 800 import std.traits : Unqual; 801 802 // empty 803 alias Empty = staticMap!(Unqual); 804 static assert(Empty.length == 0); 805 806 // single 807 alias Single = staticMap!(Unqual, const int); 808 static assert(is(Single == AliasSeq!int)); 809 810 alias T = staticMap!(Unqual, int, const int, immutable int); 811 static assert(is(T == AliasSeq!(int, int, int))); 812} 813 814/** 815Tests whether all given items satisfy a template predicate, i.e. evaluates to 816$(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])). 817 818Evaluation is $(I not) short-circuited if a false result is encountered; the 819template predicate must be instantiable with all the given items. 820 */ 821template allSatisfy(alias F, T...) 822{ 823 static if (T.length == 0) 824 { 825 enum allSatisfy = true; 826 } 827 else static if (T.length == 1) 828 { 829 enum allSatisfy = F!(T[0]); 830 } 831 else 832 { 833 enum allSatisfy = 834 allSatisfy!(F, T[ 0 .. $/2]) && 835 allSatisfy!(F, T[$/2 .. $ ]); 836 } 837} 838 839/// 840@safe unittest 841{ 842 import std.traits : isIntegral; 843 844 static assert(!allSatisfy!(isIntegral, int, double)); 845 static assert( allSatisfy!(isIntegral, int, long)); 846} 847 848/** 849Tests whether any given items satisfy a template predicate, i.e. evaluates to 850$(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])). 851 852Evaluation is short-circuited if a true result is encountered; the 853template predicate must be instantiable with one of the given items. 854 */ 855template anySatisfy(alias F, T...) 856{ 857 static if (T.length == 0) 858 { 859 enum anySatisfy = false; 860 } 861 else static if (T.length == 1) 862 { 863 enum anySatisfy = F!(T[0]); 864 } 865 else 866 { 867 enum anySatisfy = 868 anySatisfy!(F, T[ 0 .. $/2]) || 869 anySatisfy!(F, T[$/2 .. $ ]); 870 } 871} 872 873/// 874@safe unittest 875{ 876 import std.traits : isIntegral; 877 878 static assert(!anySatisfy!(isIntegral, string, double)); 879 static assert( anySatisfy!(isIntegral, int, double)); 880} 881 882 883/** 884 * Filters an $(D AliasSeq) using a template predicate. Returns a 885 * $(D AliasSeq) of the elements which satisfy the predicate. 886 */ 887template Filter(alias pred, TList...) 888{ 889 static if (TList.length == 0) 890 { 891 alias Filter = AliasSeq!(); 892 } 893 else static if (TList.length == 1) 894 { 895 static if (pred!(TList[0])) 896 alias Filter = AliasSeq!(TList[0]); 897 else 898 alias Filter = AliasSeq!(); 899 } 900 else 901 { 902 alias Filter = 903 AliasSeq!( 904 Filter!(pred, TList[ 0 .. $/2]), 905 Filter!(pred, TList[$/2 .. $ ])); 906 } 907} 908 909/// 910@safe unittest 911{ 912 import std.traits : isNarrowString, isUnsigned; 913 914 alias Types1 = AliasSeq!(string, wstring, dchar[], char[], dstring, int); 915 alias TL1 = Filter!(isNarrowString, Types1); 916 static assert(is(TL1 == AliasSeq!(string, wstring, char[]))); 917 918 alias Types2 = AliasSeq!(int, byte, ubyte, dstring, dchar, uint, ulong); 919 alias TL2 = Filter!(isUnsigned, Types2); 920 static assert(is(TL2 == AliasSeq!(ubyte, uint, ulong))); 921} 922 923@safe unittest 924{ 925 import std.traits : isPointer; 926 927 static assert(is(Filter!(isPointer, int, void*, char[], int*) == AliasSeq!(void*, int*))); 928 static assert(is(Filter!isPointer == AliasSeq!())); 929} 930 931 932// Used in template predicate unit tests below. 933private version (unittest) 934{ 935 template testAlways(T...) 936 { 937 enum testAlways = true; 938 } 939 940 template testNever(T...) 941 { 942 enum testNever = false; 943 } 944 945 template testError(T...) 946 { 947 static assert(false, "Should never be instantiated."); 948 } 949} 950 951 952/** 953 * Negates the passed template predicate. 954 */ 955template templateNot(alias pred) 956{ 957 enum templateNot(T...) = !pred!T; 958} 959 960/// 961@safe unittest 962{ 963 import std.traits : isPointer; 964 965 alias isNoPointer = templateNot!isPointer; 966 static assert(!isNoPointer!(int*)); 967 static assert(allSatisfy!(isNoPointer, string, char, float)); 968} 969 970@safe unittest 971{ 972 foreach (T; AliasSeq!(int, staticMap, 42)) 973 { 974 static assert(!Instantiate!(templateNot!testAlways, T)); 975 static assert(Instantiate!(templateNot!testNever, T)); 976 } 977} 978 979 980/** 981 * Combines several template predicates using logical AND, i.e. constructs a new 982 * predicate which evaluates to true for a given input T if and only if all of 983 * the passed predicates are true for T. 984 * 985 * The predicates are evaluated from left to right, aborting evaluation in a 986 * short-cut manner if a false result is encountered, in which case the latter 987 * instantiations do not need to compile. 988 */ 989template templateAnd(Preds...) 990{ 991 template templateAnd(T...) 992 { 993 static if (Preds.length == 0) 994 { 995 enum templateAnd = true; 996 } 997 else 998 { 999 static if (Instantiate!(Preds[0], T)) 1000 alias templateAnd = Instantiate!(.templateAnd!(Preds[1 .. $]), T); 1001 else 1002 enum templateAnd = false; 1003 } 1004 } 1005} 1006 1007/// 1008@safe unittest 1009{ 1010 import std.traits : isNumeric, isUnsigned; 1011 1012 alias storesNegativeNumbers = templateAnd!(isNumeric, templateNot!isUnsigned); 1013 static assert(storesNegativeNumbers!int); 1014 static assert(!storesNegativeNumbers!string && !storesNegativeNumbers!uint); 1015 1016 // An empty list of predicates always yields true. 1017 alias alwaysTrue = templateAnd!(); 1018 static assert(alwaysTrue!int); 1019} 1020 1021@safe unittest 1022{ 1023 foreach (T; AliasSeq!(int, staticMap, 42)) 1024 { 1025 static assert( Instantiate!(templateAnd!(), T)); 1026 static assert( Instantiate!(templateAnd!(testAlways), T)); 1027 static assert( Instantiate!(templateAnd!(testAlways, testAlways), T)); 1028 static assert(!Instantiate!(templateAnd!(testNever), T)); 1029 static assert(!Instantiate!(templateAnd!(testAlways, testNever), T)); 1030 static assert(!Instantiate!(templateAnd!(testNever, testAlways), T)); 1031 1032 static assert(!Instantiate!(templateAnd!(testNever, testError), T)); 1033 static assert(!is(typeof(Instantiate!(templateAnd!(testAlways, testError), T)))); 1034 } 1035} 1036 1037 1038/** 1039 * Combines several template predicates using logical OR, i.e. constructs a new 1040 * predicate which evaluates to true for a given input T if and only at least 1041 * one of the passed predicates is true for T. 1042 * 1043 * The predicates are evaluated from left to right, aborting evaluation in a 1044 * short-cut manner if a true result is encountered, in which case the latter 1045 * instantiations do not need to compile. 1046 */ 1047template templateOr(Preds...) 1048{ 1049 template templateOr(T...) 1050 { 1051 static if (Preds.length == 0) 1052 { 1053 enum templateOr = false; 1054 } 1055 else 1056 { 1057 static if (Instantiate!(Preds[0], T)) 1058 enum templateOr = true; 1059 else 1060 alias templateOr = Instantiate!(.templateOr!(Preds[1 .. $]), T); 1061 } 1062 } 1063} 1064 1065/// 1066@safe unittest 1067{ 1068 import std.traits : isPointer, isUnsigned; 1069 1070 alias isPtrOrUnsigned = templateOr!(isPointer, isUnsigned); 1071 static assert( isPtrOrUnsigned!uint && isPtrOrUnsigned!(short*)); 1072 static assert(!isPtrOrUnsigned!int && !isPtrOrUnsigned!(string)); 1073 1074 // An empty list of predicates never yields true. 1075 alias alwaysFalse = templateOr!(); 1076 static assert(!alwaysFalse!int); 1077} 1078 1079@safe unittest 1080{ 1081 foreach (T; AliasSeq!(int, staticMap, 42)) 1082 { 1083 static assert( Instantiate!(templateOr!(testAlways), T)); 1084 static assert( Instantiate!(templateOr!(testAlways, testAlways), T)); 1085 static assert( Instantiate!(templateOr!(testAlways, testNever), T)); 1086 static assert( Instantiate!(templateOr!(testNever, testAlways), T)); 1087 static assert(!Instantiate!(templateOr!(), T)); 1088 static assert(!Instantiate!(templateOr!(testNever), T)); 1089 1090 static assert( Instantiate!(templateOr!(testAlways, testError), T)); 1091 static assert( Instantiate!(templateOr!(testNever, testAlways, testError), T)); 1092 // DMD @@BUG@@: Assertion fails for int, seems like a error gagging 1093 // problem. The bug goes away when removing some of the other template 1094 // instantiations in the module. 1095 // static assert(!is(typeof(Instantiate!(templateOr!(testNever, testError), T)))); 1096 } 1097} 1098 1099/** 1100 * Converts an input range $(D range) to an alias sequence. 1101 */ 1102template aliasSeqOf(alias range) 1103{ 1104 import std.traits : isArray, isNarrowString; 1105 1106 alias ArrT = typeof(range); 1107 static if (isArray!ArrT && !isNarrowString!ArrT) 1108 { 1109 static if (range.length == 0) 1110 { 1111 alias aliasSeqOf = AliasSeq!(); 1112 } 1113 else static if (range.length == 1) 1114 { 1115 alias aliasSeqOf = AliasSeq!(range[0]); 1116 } 1117 else 1118 { 1119 alias aliasSeqOf = AliasSeq!(aliasSeqOf!(range[0 .. $/2]), aliasSeqOf!(range[$/2 .. $])); 1120 } 1121 } 1122 else 1123 { 1124 import std.range.primitives : isInputRange; 1125 static if (isInputRange!ArrT) 1126 { 1127 import std.array : array; 1128 alias aliasSeqOf = aliasSeqOf!(array(range)); 1129 } 1130 else 1131 { 1132 static assert(false, "Cannot transform range of type " ~ ArrT.stringof ~ " into a AliasSeq."); 1133 } 1134 } 1135} 1136 1137/// 1138@safe unittest 1139{ 1140 import std.algorithm.iteration : map; 1141 import std.algorithm.sorting : sort; 1142 import std.string : capitalize; 1143 1144 struct S 1145 { 1146 int a; 1147 int c; 1148 int b; 1149 } 1150 1151 alias capMembers = aliasSeqOf!([__traits(allMembers, S)].sort().map!capitalize()); 1152 static assert(capMembers[0] == "A"); 1153 static assert(capMembers[1] == "B"); 1154 static assert(capMembers[2] == "C"); 1155} 1156 1157/// 1158@safe unittest 1159{ 1160 static immutable REF = [0, 1, 2, 3]; 1161 foreach (I, V; aliasSeqOf!([0, 1, 2, 3])) 1162 { 1163 static assert(V == I); 1164 static assert(V == REF[I]); 1165 } 1166} 1167 1168@safe unittest 1169{ 1170 import std.conv : to, octal; 1171 import std.range : iota; 1172 //Testing compile time octal 1173 foreach (I2; aliasSeqOf!(iota(0, 8))) 1174 foreach (I1; aliasSeqOf!(iota(0, 8))) 1175 { 1176 enum oct = I2 * 8 + I1; 1177 enum dec = I2 * 10 + I1; 1178 enum str = to!string(dec); 1179 static assert(octal!dec == oct); 1180 static assert(octal!str == oct); 1181 } 1182} 1183 1184@safe unittest 1185{ 1186 enum REF = "���������"d; 1187 foreach (I, V; aliasSeqOf!"���������"c) 1188 { 1189 static assert(V == REF[I]); 1190 } 1191} 1192 1193/** 1194 * $(LINK2 http://en.wikipedia.org/wiki/Partial_application, Partially applies) 1195 * $(D_PARAM Template) by binding its first (left) or last (right) arguments 1196 * to $(D_PARAM args). 1197 * 1198 * Behaves like the identity function when $(D_PARAM args) is empty. 1199 * Params: 1200 * Template = template to partially apply 1201 * args = arguments to bind 1202 * Returns: 1203 * _Template with arity smaller than or equal to $(D_PARAM Template) 1204 */ 1205template ApplyLeft(alias Template, args...) 1206{ 1207 alias ApplyLeft(right...) = SmartAlias!(Template!(args, right)); 1208} 1209 1210/// Ditto 1211template ApplyRight(alias Template, args...) 1212{ 1213 alias ApplyRight(left...) = SmartAlias!(Template!(left, args)); 1214} 1215 1216/// 1217@safe unittest 1218{ 1219 // enum bool isImplicitlyConvertible(From, To) 1220 import std.traits : isImplicitlyConvertible; 1221 1222 static assert(allSatisfy!( 1223 ApplyLeft!(isImplicitlyConvertible, ubyte), 1224 short, ushort, int, uint, long, ulong)); 1225 1226 static assert(is(Filter!(ApplyRight!(isImplicitlyConvertible, short), 1227 ubyte, string, short, float, int) == AliasSeq!(ubyte, short))); 1228} 1229 1230/// 1231@safe unittest 1232{ 1233 import std.traits : hasMember, ifTestable; 1234 1235 struct T1 1236 { 1237 bool foo; 1238 } 1239 1240 struct T2 1241 { 1242 struct Test 1243 { 1244 bool opCast(T : bool)() { return true; } 1245 } 1246 1247 Test foo; 1248 } 1249 1250 static assert(allSatisfy!(ApplyRight!(hasMember, "foo"), T1, T2)); 1251 static assert(allSatisfy!(ApplyRight!(ifTestable, a => a.foo), T1, T2)); 1252} 1253 1254/// 1255@safe unittest 1256{ 1257 import std.traits : Largest; 1258 1259 alias Types = AliasSeq!(byte, short, int, long); 1260 1261 static assert(is(staticMap!(ApplyLeft!(Largest, short), Types) == 1262 AliasSeq!(short, short, int, long))); 1263 static assert(is(staticMap!(ApplyLeft!(Largest, int), Types) == 1264 AliasSeq!(int, int, int, long))); 1265} 1266 1267/// 1268@safe unittest 1269{ 1270 import std.traits : FunctionAttribute, SetFunctionAttributes; 1271 1272 static void foo() @system; 1273 static int bar(int) @system; 1274 1275 alias SafeFunctions = AliasSeq!( 1276 void function() @safe, 1277 int function(int) @safe); 1278 1279 static assert(is(staticMap!(ApplyRight!( 1280 SetFunctionAttributes, "D", FunctionAttribute.safe), 1281 typeof(&foo), typeof(&bar)) == SafeFunctions)); 1282} 1283 1284private template SmartAlias(T...) 1285{ 1286 static if (T.length == 1) 1287 { 1288 alias SmartAlias = Alias!T; 1289 } 1290 else 1291 { 1292 alias SmartAlias = AliasSeq!T; 1293 } 1294} 1295 1296@safe unittest 1297{ 1298 static assert(is(typeof({ 1299 alias T(T0, int a, double b, alias T1, string c) = AliasSeq!(T0, a, b, T1, c); 1300 alias T0 = ApplyRight!(ApplyLeft, ApplyRight); 1301 alias T1 = T0!ApplyLeft; 1302 alias T2 = T1!T; 1303 alias T3 = T2!(3, "foo"); 1304 alias T4 = T3!(short, 3, 3.3); 1305 static assert(Pack!T4.equals!(short, 3, 3.3, 3, "foo")); 1306 1307 import std.traits : isImplicitlyConvertible; 1308 alias U1 = ApplyLeft!(ApplyRight, isImplicitlyConvertible); 1309 alias U2 = U1!int; 1310 enum U3 = U2!short; 1311 static assert(U3); 1312 }))); 1313} 1314 1315/** 1316 * Creates an `AliasSeq` which repeats a type or an `AliasSeq` exactly `n` times. 1317 */ 1318template Repeat(size_t n, TList...) 1319if (n > 0) 1320{ 1321 static if (n == 1) 1322 { 1323 alias Repeat = AliasSeq!TList; 1324 } 1325 else static if (n == 2) 1326 { 1327 alias Repeat = AliasSeq!(TList, TList); 1328 } 1329 else 1330 { 1331 alias R = Repeat!((n - 1) / 2, TList); 1332 static if ((n - 1) % 2 == 0) 1333 { 1334 alias Repeat = AliasSeq!(TList, R, R); 1335 } 1336 else 1337 { 1338 alias Repeat = AliasSeq!(TList, TList, R, R); 1339 } 1340 } 1341} 1342 1343/// 1344@safe unittest 1345{ 1346 alias ImInt1 = Repeat!(1, immutable(int)); 1347 static assert(is(ImInt1 == AliasSeq!(immutable(int)))); 1348 1349 alias Real3 = Repeat!(3, real); 1350 static assert(is(Real3 == AliasSeq!(real, real, real))); 1351 1352 alias Real12 = Repeat!(4, Real3); 1353 static assert(is(Real12 == AliasSeq!(real, real, real, real, real, real, 1354 real, real, real, real, real, real))); 1355 1356 alias Composite = AliasSeq!(uint, int); 1357 alias Composite2 = Repeat!(2, Composite); 1358 static assert(is(Composite2 == AliasSeq!(uint, int, uint, int))); 1359} 1360 1361 1362/// 1363@safe unittest 1364{ 1365 auto staticArray(T, size_t n)(Repeat!(n, T) elems) 1366 { 1367 T[n] a = [elems]; 1368 return a; 1369 } 1370 1371 auto a = staticArray!(long, 3)(3, 1, 4); 1372 assert(is(typeof(a) == long[3])); 1373 assert(a == [3, 1, 4]); 1374} 1375 1376/** 1377 * Sorts a $(LREF AliasSeq) using $(D cmp). 1378 * 1379 * Parameters: 1380 * cmp = A template that returns a $(D bool) (if its first argument is less than the second one) 1381 * or an $(D int) (-1 means less than, 0 means equal, 1 means greater than) 1382 * 1383 * Seq = The $(LREF AliasSeq) to sort 1384 * 1385 * Returns: The sorted alias sequence 1386 */ 1387template staticSort(alias cmp, Seq...) 1388{ 1389 static if (Seq.length < 2) 1390 { 1391 alias staticSort = Seq; 1392 } 1393 else 1394 { 1395 private alias btm = staticSort!(cmp, Seq[0 .. $ / 2]); 1396 private alias top = staticSort!(cmp, Seq[$ / 2 .. $]); 1397 1398 static if (isLessEq!(cmp, btm[$ - 1], top[0])) 1399 alias staticSort = AliasSeq!(btm, top); // already ascending 1400 else static if (isLessEq!(cmp, top[$ - 1], btm[0])) 1401 alias staticSort = AliasSeq!(top, btm); // already descending 1402 else 1403 alias staticSort = staticMerge!(cmp, Seq.length / 2, btm, top); 1404 } 1405} 1406 1407/// 1408@safe unittest 1409{ 1410 alias Nums = AliasSeq!(7, 2, 3, 23); 1411 enum Comp(int N1, int N2) = N1 < N2; 1412 static assert(AliasSeq!(2, 3, 7, 23) == staticSort!(Comp, Nums)); 1413} 1414 1415/// 1416@safe unittest 1417{ 1418 alias Types = AliasSeq!(uint, short, ubyte, long, ulong); 1419 enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1); 1420 static assert(is(AliasSeq!(uint, ubyte, ulong, short, long) == staticSort!(Comp, 1421 Types))); 1422} 1423 1424private template staticMerge(alias cmp, int half, Seq...) 1425{ 1426 static if (half == 0 || half == Seq.length) 1427 { 1428 alias staticMerge = Seq; 1429 } 1430 else 1431 { 1432 static if (isLessEq!(cmp, Seq[0], Seq[half])) 1433 { 1434 alias staticMerge = AliasSeq!(Seq[0], 1435 staticMerge!(cmp, half - 1, Seq[1 .. $])); 1436 } 1437 else 1438 { 1439 alias staticMerge = AliasSeq!(Seq[half], 1440 staticMerge!(cmp, half, Seq[0 .. half], Seq[half + 1 .. $])); 1441 } 1442 } 1443} 1444 1445private template isLessEq(alias cmp, Seq...) 1446if (Seq.length == 2) 1447{ 1448 private enum Result = cmp!(Seq[1], Seq[0]); 1449 static if (is(typeof(Result) == bool)) 1450 enum isLessEq = !Result; 1451 else static if (is(typeof(Result) : int)) 1452 enum isLessEq = Result >= 0; 1453 else 1454 static assert(0, typeof(Result).stringof ~ " is not a value comparison type"); 1455} 1456 1457/** 1458 * Checks if an $(LREF AliasSeq) is sorted according to $(D cmp). 1459 * 1460 * Parameters: 1461 * cmp = A template that returns a $(D bool) (if its first argument is less than the second one) 1462 * or an $(D int) (-1 means less than, 0 means equal, 1 means greater than) 1463 * 1464 * Seq = The $(LREF AliasSeq) to check 1465 * 1466 * Returns: `true` if `Seq` is sorted; otherwise `false` 1467 */ 1468template staticIsSorted(alias cmp, Seq...) 1469{ 1470 static if (Seq.length <= 1) 1471 enum staticIsSorted = true; 1472 else static if (Seq.length == 2) 1473 enum staticIsSorted = isLessEq!(cmp, Seq[0], Seq[1]); 1474 else 1475 { 1476 enum staticIsSorted = 1477 isLessEq!(cmp, Seq[($ / 2) - 1], Seq[$ / 2]) && 1478 staticIsSorted!(cmp, Seq[0 .. $ / 2]) && 1479 staticIsSorted!(cmp, Seq[$ / 2 .. $]); 1480 } 1481} 1482 1483/// 1484@safe unittest 1485{ 1486 enum Comp(int N1, int N2) = N1 < N2; 1487 static assert( staticIsSorted!(Comp, 2, 2)); 1488 static assert( staticIsSorted!(Comp, 2, 3, 7, 23)); 1489 static assert(!staticIsSorted!(Comp, 7, 2, 3, 23)); 1490} 1491 1492/// 1493@safe unittest 1494{ 1495 enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1); 1496 static assert( staticIsSorted!(Comp, uint, ubyte, ulong, short, long)); 1497 static assert(!staticIsSorted!(Comp, uint, short, ubyte, long, ulong)); 1498} 1499 1500/** 1501Selects a subset of the argument list by stepping with fixed `stepSize` over the list. 1502A negative `stepSize` starts iteration with the last list element. 1503 1504Params: 1505 stepSize = Number of elements to increment on each iteration. Can't be `0`. 1506 Args = Template arguments 1507 1508Returns: A template argument list filtered by the selected stride. 1509*/ 1510template Stride(int stepSize, Args...) 1511if (stepSize != 0) 1512{ 1513 static if (Args.length == 0) 1514 { 1515 alias Stride = AliasSeq!(); 1516 } 1517 else static if (stepSize > 0) 1518 { 1519 static if (stepSize >= Args.length) 1520 alias Stride = AliasSeq!(Args[0]); 1521 else 1522 alias Stride = AliasSeq!(Args[0], Stride!(stepSize, Args[stepSize .. $])); 1523 } 1524 else 1525 { 1526 static if (-stepSize >= Args.length) 1527 alias Stride = AliasSeq!(Args[$ - 1]); 1528 else 1529 alias Stride = AliasSeq!(Args[$ - 1], Stride!(stepSize, Args[0 .. $ + stepSize])); 1530 } 1531} 1532 1533/// 1534@safe unittest 1535{ 1536 static assert(is(Stride!(1, short, int, long) == AliasSeq!(short, int, long))); 1537 static assert(is(Stride!(2, short, int, long) == AliasSeq!(short, long))); 1538 static assert(is(Stride!(-1, short, int, long) == AliasSeq!(long, int, short))); 1539 static assert(is(Stride!(-2, short, int, long) == AliasSeq!(long, short))); 1540 1541 alias attribs = AliasSeq!(short, int, long, ushort, uint, ulong); 1542 static assert(is(Stride!(3, attribs) == AliasSeq!(short, ushort))); 1543 static assert(is(Stride!(3, attribs[1 .. $]) == AliasSeq!(int, uint))); 1544 static assert(is(Stride!(-3, attribs) == AliasSeq!(ulong, long))); 1545} 1546 1547@safe unittest 1548{ 1549 static assert(Pack!(Stride!(5, int)).equals!(int)); 1550 static assert(Pack!(Stride!(-5, int)).equals!(int)); 1551 static assert(!__traits(compiles, Stride!(0, int))); 1552} 1553 1554// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : // 1555private: 1556 1557/* 1558 * [internal] Returns true if a and b are the same thing, or false if 1559 * not. Both a and b can be types, literals, or symbols. 1560 * 1561 * How: When: 1562 * is(a == b) - both are types 1563 * a == b - both are literals (true literals, enums) 1564 * __traits(isSame, a, b) - other cases (variables, functions, 1565 * templates, etc.) 1566 */ 1567private template isSame(ab...) 1568if (ab.length == 2) 1569{ 1570 static if (__traits(compiles, expectType!(ab[0]), 1571 expectType!(ab[1]))) 1572 { 1573 enum isSame = is(ab[0] == ab[1]); 1574 } 1575 else static if (!__traits(compiles, expectType!(ab[0])) && 1576 !__traits(compiles, expectType!(ab[1])) && 1577 __traits(compiles, expectBool!(ab[0] == ab[1]))) 1578 { 1579 static if (!__traits(compiles, &ab[0]) || 1580 !__traits(compiles, &ab[1])) 1581 enum isSame = (ab[0] == ab[1]); 1582 else 1583 enum isSame = __traits(isSame, ab[0], ab[1]); 1584 } 1585 else 1586 { 1587 enum isSame = __traits(isSame, ab[0], ab[1]); 1588 } 1589} 1590private template expectType(T) {} 1591private template expectBool(bool b) {} 1592 1593@safe unittest 1594{ 1595 static assert( isSame!(int, int)); 1596 static assert(!isSame!(int, short)); 1597 1598 enum a = 1, b = 1, c = 2, s = "a", t = "a"; 1599 static assert( isSame!(1, 1)); 1600 static assert( isSame!(a, 1)); 1601 static assert( isSame!(a, b)); 1602 static assert(!isSame!(b, c)); 1603 static assert( isSame!("a", "a")); 1604 static assert( isSame!(s, "a")); 1605 static assert( isSame!(s, t)); 1606 static assert(!isSame!(1, "1")); 1607 static assert(!isSame!(a, "a")); 1608 static assert( isSame!(isSame, isSame)); 1609 static assert(!isSame!(isSame, a)); 1610 1611 static assert(!isSame!(byte, a)); 1612 static assert(!isSame!(short, isSame)); 1613 static assert(!isSame!(a, int)); 1614 static assert(!isSame!(long, isSame)); 1615 1616 static immutable X = 1, Y = 1, Z = 2; 1617 static assert( isSame!(X, X)); 1618 static assert(!isSame!(X, Y)); 1619 static assert(!isSame!(Y, Z)); 1620 1621 int foo(); 1622 int bar(); 1623 real baz(int); 1624 static assert( isSame!(foo, foo)); 1625 static assert(!isSame!(foo, bar)); 1626 static assert(!isSame!(bar, baz)); 1627 static assert( isSame!(baz, baz)); 1628 static assert(!isSame!(foo, 0)); 1629 1630 int x, y; 1631 real z; 1632 static assert( isSame!(x, x)); 1633 static assert(!isSame!(x, y)); 1634 static assert(!isSame!(y, z)); 1635 static assert( isSame!(z, z)); 1636 static assert(!isSame!(x, 0)); 1637} 1638 1639/* 1640 * [internal] Confines a tuple within a template. 1641 */ 1642private template Pack(T...) 1643{ 1644 alias tuple = T; 1645 1646 // For convenience 1647 template equals(U...) 1648 { 1649 static if (T.length == U.length) 1650 { 1651 static if (T.length == 0) 1652 enum equals = true; 1653 else 1654 enum equals = isSame!(T[0], U[0]) && 1655 Pack!(T[1 .. $]).equals!(U[1 .. $]); 1656 } 1657 else 1658 { 1659 enum equals = false; 1660 } 1661 } 1662} 1663 1664@safe unittest 1665{ 1666 static assert( Pack!(1, int, "abc").equals!(1, int, "abc")); 1667 static assert(!Pack!(1, int, "abc").equals!(1, int, "cba")); 1668} 1669 1670/* 1671 * Instantiates the given template with the given list of parameters. 1672 * 1673 * Used to work around syntactic limitations of D with regard to instantiating 1674 * a template from an alias sequence (e.g. T[0]!(...) is not valid) or a template 1675 * returning another template (e.g. Foo!(Bar)!(Baz) is not allowed). 1676 */ 1677// TODO: Consider publicly exposing this, maybe even if only for better 1678// understandability of error messages. 1679alias Instantiate(alias Template, Params...) = Template!Params; 1680