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
73 module 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 */
AliasSeq(TList...)81 template 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
foo(TL td)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 {
ArgCall(alias Func,alias arg)116 auto ref ArgCall(alias Func, alias arg)()
117 {
118 return Func(arg);
119 }
120
Map(alias Func,args...)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
square(int arg)133 static int square(int arg)
134 {
135 return arg * arg;
136 }
137
refSquare(ref int arg)138 static int refSquare(ref int arg)
139 {
140 arg *= arg;
141 return arg;
142 }
143
refRetSquare(ref int arg)144 static ref int refRetSquare(ref int arg)
145 {
146 arg *= arg;
147 return arg;
148 }
149
test(int a,int b)150 static void test(int a, int b)
151 {
152 assert(a == 4);
153 assert(b == 16);
154 }
155
testRef(ref int a,ref int b)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 */
191 alias Alias(alias a) = a;
192
193 /// Ditto
194 alias 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
OldAlias(alias a)240 package 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
250 import std.traits : isAggregateType, Unqual;
251
252 package template OldAlias(T)
253 if (!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 */
staticIndexOf(T,TList...)273 template staticIndexOf(T, TList...)
274 {
275 enum staticIndexOf = genericIndexOf!(T, TList).index;
276 }
277
278 /// Ditto
staticIndexOf(alias T,TList...)279 template staticIndexOf(alias T, TList...)
280 {
281 enum staticIndexOf = genericIndexOf!(T, TList).index;
282 }
283
284 ///
285 @safe unittest
286 {
287 import std.stdio;
288
foo()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]
298 private template genericIndexOf(args...)
299 if (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 */
Erase(T,TList...)351 template Erase(T, TList...)
352 {
353 alias Erase = GenericErase!(T, TList).result;
354 }
355
356 /// Ditto
Erase(alias T,TList...)357 template 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]
371 private template GenericErase(args...)
372 if (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 */
EraseAll(T,TList...)409 template EraseAll(T, TList...)
410 {
411 alias EraseAll = GenericEraseAll!(T, TList).result;
412 }
413
414 /// Ditto
EraseAll(alias T,TList...)415 template 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]
430 private template GenericEraseAll(args...)
431 if (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 */
NoDuplicates(TList...)472 template 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 */
Replace(T,U,TList...)531 template Replace(T, U, TList...)
532 {
533 alias Replace = GenericReplace!(T, U, TList).result;
534 }
535
536 /// Ditto
Replace(alias T,U,TList...)537 template Replace(alias T, U, TList...)
538 {
539 alias Replace = GenericReplace!(T, U, TList).result;
540 }
541
542 /// Ditto
Replace(T,alias U,TList...)543 template Replace(T, alias U, TList...)
544 {
545 alias Replace = GenericReplace!(T, U, TList).result;
546 }
547
548 /// Ditto
Replace(alias T,alias U,TList...)549 template 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]
564 private template GenericReplace(args...)
565 if (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 */
ReplaceAll(T,U,TList...)611 template ReplaceAll(T, U, TList...)
612 {
613 alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
614 }
615
616 /// Ditto
ReplaceAll(alias T,U,TList...)617 template ReplaceAll(alias T, U, TList...)
618 {
619 alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
620 }
621
622 /// Ditto
ReplaceAll(T,alias U,TList...)623 template ReplaceAll(T, alias U, TList...)
624 {
625 alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
626 }
627
628 /// Ditto
ReplaceAll(alias T,alias U,TList...)629 template 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]
644 private template GenericReplaceAll(args...)
645 if (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 */
Reverse(TList...)690 template 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 */
MostDerived(T,TList...)718 template 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 */
DerivedToFront(TList...)744 template 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 /**
769 Evaluates to $(D AliasSeq!(F!(T[0]), F!(T[1]), ..., F!(T[$ - 1]))).
770 */
staticMap(alias F,T...)771 template 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 /**
815 Tests whether all given items satisfy a template predicate, i.e. evaluates to
816 $(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])).
817
818 Evaluation is $(I not) short-circuited if a false result is encountered; the
819 template predicate must be instantiable with all the given items.
820 */
allSatisfy(alias F,T...)821 template 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 /**
849 Tests whether any given items satisfy a template predicate, i.e. evaluates to
850 $(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])).
851
852 Evaluation is short-circuited if a true result is encountered; the
853 template predicate must be instantiable with one of the given items.
854 */
anySatisfy(alias F,T...)855 template 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 */
Filter(alias pred,TList...)887 template 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.
version(unittest)933 private 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 */
templateNot(alias pred)955 template 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 */
templateAnd(Preds...)989 template 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 */
templateOr(Preds...)1047 template 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 */
aliasSeqOf(alias range)1102 template 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 */
ApplyLeft(alias Template,args...)1205 template ApplyLeft(alias Template, args...)
1206 {
1207 alias ApplyLeft(right...) = SmartAlias!(Template!(args, right));
1208 }
1209
1210 /// Ditto
ApplyRight(alias Template,args...)1211 template 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
SmartAlias(T...)1284 private 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 */
1318 template Repeat(size_t n, TList...)
1319 if (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 {
staticArray(T,size_t n)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 */
staticSort(alias cmp,Seq...)1387 template 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
staticMerge(alias cmp,int half,Seq...)1424 private 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
1445 private template isLessEq(alias cmp, Seq...)
1446 if (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 */
staticIsSorted(alias cmp,Seq...)1468 template 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 /**
1501 Selects a subset of the argument list by stepping with fixed `stepSize` over the list.
1502 A negative `stepSize` starts iteration with the last list element.
1503
1504 Params:
1505 stepSize = Number of elements to increment on each iteration. Can't be `0`.
1506 Args = Template arguments
1507
1508 Returns: A template argument list filtered by the selected stride.
1509 */
1510 template Stride(int stepSize, Args...)
1511 if (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 // : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : //
1555 private:
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 */
1567 private template isSame(ab...)
1568 if (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 }
expectType(T)1590 private template expectType(T) {}
expectBool(bool b)1591 private 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 */
Pack(T...)1642 private 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.
1679 alias Instantiate(alias Template, Params...) = Template!Params;
1680