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