aboutsummaryrefslogtreecommitdiff
path: root/libphobos/src/std/meta.d
diff options
context:
space:
mode:
Diffstat (limited to 'libphobos/src/std/meta.d')
-rw-r--r--libphobos/src/std/meta.d1679
1 files changed, 1679 insertions, 0 deletions
diff --git a/libphobos/src/std/meta.d b/libphobos/src/std/meta.d
new file mode 100644
index 0000000..308e50f
--- /dev/null
+++ b/libphobos/src/std/meta.d
@@ -0,0 +1,1679 @@
+// Written in the D programming language.
+
+/**
+ * Templates to manipulate template argument lists (also known as type lists).
+ *
+ * Some operations on alias sequences are built in to the language,
+ * such as TL[$(I n)] which gets the $(I n)th type from the
+ * alias sequence. TL[$(I lwr) .. $(I upr)] returns a new type
+ * list that is a slice of the old one.
+ *
+ * Several templates in this module use or operate on eponymous templates that
+ * take a single argument and evaluate to a boolean constant. Such templates
+ * are referred to as $(I template predicates).
+ *
+ * $(SCRIPT inhibitQuickIndex = 1;)
+ * $(DIVC quickindex,
+ * $(BOOKTABLE ,
+ * $(TR $(TH Category) $(TH Templates))
+ * $(TR $(TD Building blocks) $(TD
+ * $(LREF Alias)
+ * $(LREF AliasSeq)
+ * $(LREF aliasSeqOf)
+ * ))
+ * $(TR $(TD Alias sequence filtering) $(TD
+ * $(LREF Erase)
+ * $(LREF EraseAll)
+ * $(LREF Filter)
+ * $(LREF NoDuplicates)
+ * $(LREF Stride)
+ * ))
+ * $(TR $(TD Alias sequence type hierarchy) $(TD
+ * $(LREF DerivedToFront)
+ * $(LREF MostDerived)
+ * ))
+ * $(TR $(TD Alias sequence transformation) $(TD
+ * $(LREF Repeat)
+ * $(LREF Replace)
+ * $(LREF ReplaceAll)
+ * $(LREF Reverse)
+ * $(LREF staticMap)
+ * $(LREF staticSort)
+ * ))
+ * $(TR $(TD Alias sequence searching) $(TD
+ * $(LREF allSatisfy)
+ * $(LREF anySatisfy)
+ * $(LREF staticIndexOf)
+ * ))
+ * $(TR $(TD Template predicates) $(TD
+ * $(LREF templateAnd)
+ * $(LREF templateNot)
+ * $(LREF templateOr)
+ * $(LREF staticIsSorted)
+ * ))
+ * $(TR $(TD Template instantiation) $(TD
+ * $(LREF ApplyLeft)
+ * $(LREF ApplyRight)
+ * ))
+ * ))
+ *
+ * References:
+ * Based on ideas in Table 3.1 from
+ * $(LINK2 http://amazon.com/exec/obidos/ASIN/0201704315/ref=ase_classicempire/102-2957199-2585768,
+ * Modern C++ Design),
+ * Andrei Alexandrescu (Addison-Wesley Professional, 2001)
+ * Copyright: Copyright Digital Mars 2005 - 2015.
+ * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
+ * Authors:
+ * $(HTTP digitalmars.com, Walter Bright),
+ * $(HTTP klickverbot.at, David Nadlinger)
+ * Source: $(PHOBOSSRC std/_meta.d)
+ */
+
+module std.meta;
+
+/**
+ * Creates a sequence of zero or more aliases. This is most commonly
+ * used as template parameters or arguments.
+ *
+ * In previous versions of Phobos, this was known as `TypeTuple`.
+ */
+template AliasSeq(TList...)
+{
+ alias AliasSeq = TList;
+}
+
+///
+@safe unittest
+{
+ import std.meta;
+ alias TL = AliasSeq!(int, double);
+
+ int foo(TL td) // same as int foo(int, double);
+ {
+ return td[0] + cast(int) td[1];
+ }
+}
+
+///
+@safe unittest
+{
+ alias TL = AliasSeq!(int, double);
+
+ alias Types = AliasSeq!(TL, char);
+ static assert(is(Types == AliasSeq!(int, double, char)));
+}
+
+
+/**
+ Returns an `AliasSeq` expression of `Func` being
+ applied to every variadic template argument.
+ */
+
+///
+@safe unittest
+{
+ auto ref ArgCall(alias Func, alias arg)()
+ {
+ return Func(arg);
+ }
+
+ template Map(alias Func, args...)
+ {
+ static if (args.length > 1)
+ {
+ alias Map = AliasSeq!(ArgCall!(Func, args[0]), Map!(Func, args[1 .. $]));
+ }
+ else
+ {
+ alias Map = ArgCall!(Func, args[0]);
+ }
+ }
+
+ static int square(int arg)
+ {
+ return arg * arg;
+ }
+
+ static int refSquare(ref int arg)
+ {
+ arg *= arg;
+ return arg;
+ }
+
+ static ref int refRetSquare(ref int arg)
+ {
+ arg *= arg;
+ return arg;
+ }
+
+ static void test(int a, int b)
+ {
+ assert(a == 4);
+ assert(b == 16);
+ }
+
+ static void testRef(ref int a, ref int b)
+ {
+ assert(a++ == 16);
+ assert(b++ == 256);
+ }
+
+ static int a = 2;
+ static int b = 4;
+
+ test(Map!(square, a, b));
+
+ test(Map!(refSquare, a, b));
+ assert(a == 4);
+ assert(b == 16);
+
+ testRef(Map!(refRetSquare, a, b));
+ assert(a == 17);
+ assert(b == 257);
+}
+
+/**
+ * Allows `alias`ing of any single symbol, type or compile-time expression.
+ *
+ * Not everything can be directly aliased. An alias cannot be declared
+ * of - for example - a literal:
+ *
+ * `alias a = 4; //Error`
+ *
+ * With this template any single entity can be aliased:
+ *
+ * `alias b = Alias!4; //OK`
+ *
+ * See_Also:
+ * To alias more than one thing at once, use $(LREF AliasSeq)
+ */
+alias Alias(alias a) = a;
+
+/// Ditto
+alias Alias(T) = T;
+
+///
+@safe unittest
+{
+ // Without Alias this would fail if Args[0] was e.g. a value and
+ // some logic would be needed to detect when to use enum instead
+ alias Head(Args ...) = Alias!(Args[0]);
+ alias Tail(Args ...) = Args[1 .. $];
+
+ alias Blah = AliasSeq!(3, int, "hello");
+ static assert(Head!Blah == 3);
+ static assert(is(Head!(Tail!Blah) == int));
+ static assert((Tail!Blah)[1] == "hello");
+}
+
+///
+@safe unittest
+{
+ alias a = Alias!(123);
+ static assert(a == 123);
+
+ enum abc = 1;
+ alias b = Alias!(abc);
+ static assert(b == 1);
+
+ alias c = Alias!(3 + 4);
+ static assert(c == 7);
+
+ alias concat = (s0, s1) => s0 ~ s1;
+ alias d = Alias!(concat("Hello", " World!"));
+ static assert(d == "Hello World!");
+
+ alias e = Alias!(int);
+ static assert(is(e == int));
+
+ alias f = Alias!(AliasSeq!(int));
+ static assert(!is(typeof(f[0]))); //not an AliasSeq
+ static assert(is(f == int));
+
+ auto g = 6;
+ alias h = Alias!g;
+ ++h;
+ assert(g == 7);
+}
+
+package template OldAlias(alias a)
+{
+ static if (__traits(compiles, { alias x = a; }))
+ alias OldAlias = a;
+ else static if (__traits(compiles, { enum x = a; }))
+ enum OldAlias = a;
+ else
+ static assert(0, "Cannot alias " ~ a.stringof);
+}
+
+import std.traits : isAggregateType, Unqual;
+
+package template OldAlias(T)
+if (!isAggregateType!T || is(Unqual!T == T))
+{
+ alias OldAlias = T;
+}
+
+@safe unittest
+{
+ static struct Foo {}
+ static assert(is(OldAlias!(const(Foo)) == Foo));
+ static assert(is(OldAlias!(const(int)) == const(int)));
+ static assert(OldAlias!123 == 123);
+ enum abc = 123;
+ static assert(OldAlias!abc == 123);
+}
+
+/**
+ * Returns the index of the first occurrence of type T in the
+ * sequence of zero or more types TList.
+ * If not found, -1 is returned.
+ */
+template staticIndexOf(T, TList...)
+{
+ enum staticIndexOf = genericIndexOf!(T, TList).index;
+}
+
+/// Ditto
+template staticIndexOf(alias T, TList...)
+{
+ enum staticIndexOf = genericIndexOf!(T, TList).index;
+}
+
+///
+@safe unittest
+{
+ import std.stdio;
+
+ void foo()
+ {
+ writefln("The index of long is %s",
+ staticIndexOf!(long, AliasSeq!(int, long, double)));
+ // prints: The index of long is 1
+ }
+}
+
+// [internal]
+private template genericIndexOf(args...)
+if (args.length >= 1)
+{
+ alias e = OldAlias!(args[0]);
+ alias tuple = args[1 .. $];
+
+ static if (tuple.length)
+ {
+ alias head = OldAlias!(tuple[0]);
+ alias tail = tuple[1 .. $];
+
+ static if (isSame!(e, head))
+ {
+ enum index = 0;
+ }
+ else
+ {
+ enum next = genericIndexOf!(e, tail).index;
+ enum index = (next == -1) ? -1 : 1 + next;
+ }
+ }
+ else
+ {
+ enum index = -1;
+ }
+}
+
+@safe unittest
+{
+ static assert(staticIndexOf!( byte, byte, short, int, long) == 0);
+ static assert(staticIndexOf!(short, byte, short, int, long) == 1);
+ static assert(staticIndexOf!( int, byte, short, int, long) == 2);
+ static assert(staticIndexOf!( long, byte, short, int, long) == 3);
+ static assert(staticIndexOf!( char, byte, short, int, long) == -1);
+ static assert(staticIndexOf!( -1, byte, short, int, long) == -1);
+ static assert(staticIndexOf!(void) == -1);
+
+ static assert(staticIndexOf!("abc", "abc", "def", "ghi", "jkl") == 0);
+ static assert(staticIndexOf!("def", "abc", "def", "ghi", "jkl") == 1);
+ static assert(staticIndexOf!("ghi", "abc", "def", "ghi", "jkl") == 2);
+ static assert(staticIndexOf!("jkl", "abc", "def", "ghi", "jkl") == 3);
+ static assert(staticIndexOf!("mno", "abc", "def", "ghi", "jkl") == -1);
+ static assert(staticIndexOf!( void, "abc", "def", "ghi", "jkl") == -1);
+ static assert(staticIndexOf!(42) == -1);
+
+ static assert(staticIndexOf!(void, 0, "void", void) == 2);
+ static assert(staticIndexOf!("void", 0, void, "void") == 2);
+}
+
+/**
+ * Returns an `AliasSeq` created from TList with the first occurrence,
+ * if any, of T removed.
+ */
+template Erase(T, TList...)
+{
+ alias Erase = GenericErase!(T, TList).result;
+}
+
+/// Ditto
+template Erase(alias T, TList...)
+{
+ alias Erase = GenericErase!(T, TList).result;
+}
+
+///
+@safe unittest
+{
+ alias Types = AliasSeq!(int, long, double, char);
+ alias TL = Erase!(long, Types);
+ static assert(is(TL == AliasSeq!(int, double, char)));
+}
+
+// [internal]
+private template GenericErase(args...)
+if (args.length >= 1)
+{
+ alias e = OldAlias!(args[0]);
+ alias tuple = args[1 .. $] ;
+
+ static if (tuple.length)
+ {
+ alias head = OldAlias!(tuple[0]);
+ alias tail = tuple[1 .. $];
+
+ static if (isSame!(e, head))
+ alias result = tail;
+ else
+ alias result = AliasSeq!(head, GenericErase!(e, tail).result);
+ }
+ else
+ {
+ alias result = AliasSeq!();
+ }
+}
+
+@safe unittest
+{
+ static assert(Pack!(Erase!(int,
+ short, int, int, 4)).
+ equals!(short, int, 4));
+
+ static assert(Pack!(Erase!(1,
+ real, 3, 1, 4, 1, 5, 9)).
+ equals!(real, 3, 4, 1, 5, 9));
+}
+
+
+/**
+ * Returns an `AliasSeq` created from TList with the all occurrences,
+ * if any, of T removed.
+ */
+template EraseAll(T, TList...)
+{
+ alias EraseAll = GenericEraseAll!(T, TList).result;
+}
+
+/// Ditto
+template EraseAll(alias T, TList...)
+{
+ alias EraseAll = GenericEraseAll!(T, TList).result;
+}
+
+///
+@safe unittest
+{
+ alias Types = AliasSeq!(int, long, long, int);
+
+ alias TL = EraseAll!(long, Types);
+ static assert(is(TL == AliasSeq!(int, int)));
+}
+
+// [internal]
+private template GenericEraseAll(args...)
+if (args.length >= 1)
+{
+ alias e = OldAlias!(args[0]);
+ alias tuple = args[1 .. $];
+
+ static if (tuple.length)
+ {
+ alias head = OldAlias!(tuple[0]);
+ alias tail = tuple[1 .. $];
+ alias next = AliasSeq!(
+ GenericEraseAll!(e, tail[0..$/2]).result,
+ GenericEraseAll!(e, tail[$/2..$]).result
+ );
+
+ static if (isSame!(e, head))
+ alias result = next;
+ else
+ alias result = AliasSeq!(head, next);
+ }
+ else
+ {
+ alias result = AliasSeq!();
+ }
+}
+
+@safe unittest
+{
+ static assert(Pack!(EraseAll!(int,
+ short, int, int, 4)).
+ equals!(short, 4));
+
+ static assert(Pack!(EraseAll!(1,
+ real, 3, 1, 4, 1, 5, 9)).
+ equals!(real, 3, 4, 5, 9));
+}
+
+
+/**
+ * Returns an `AliasSeq` created from TList with the all duplicate
+ * types removed.
+ */
+template NoDuplicates(TList...)
+{
+ template EraseAllN(uint N, T...)
+ {
+ static if (N <= 1)
+ {
+ alias EraseAllN = T;
+ }
+ else
+ {
+ alias EraseAllN = EraseAllN!(N-1, T[1 .. N], EraseAll!(T[0], T[N..$]));
+ }
+ }
+ static if (TList.length > 500)
+ {
+ enum steps = 16;
+ alias first = NoDuplicates!(TList[0 .. steps]);
+ alias NoDuplicates = NoDuplicates!(EraseAllN!(first.length, first, TList[steps..$]));
+ }
+ else static if (TList.length == 0)
+ {
+ alias NoDuplicates = TList;
+ }
+ else
+ {
+ alias NoDuplicates =
+ AliasSeq!(TList[0], NoDuplicates!(EraseAll!(TList[0], TList[1 .. $])));
+ }
+}
+
+///
+@safe unittest
+{
+ alias Types = AliasSeq!(int, long, long, int, float);
+
+ alias TL = NoDuplicates!(Types);
+ static assert(is(TL == AliasSeq!(int, long, float)));
+}
+
+@safe unittest
+{
+ // Bugzilla 14561: huge enums
+ alias LongList = Repeat!(1500, int);
+ static assert(NoDuplicates!LongList.length == 1);
+}
+
+@safe unittest
+{
+ static assert(
+ Pack!(
+ NoDuplicates!(1, int, 1, NoDuplicates, int, NoDuplicates, real))
+ .equals!(1, int, NoDuplicates, real));
+}
+
+
+/**
+ * Returns an `AliasSeq` created from TList with the first occurrence
+ * of type T, if found, replaced with type U.
+ */
+template Replace(T, U, TList...)
+{
+ alias Replace = GenericReplace!(T, U, TList).result;
+}
+
+/// Ditto
+template Replace(alias T, U, TList...)
+{
+ alias Replace = GenericReplace!(T, U, TList).result;
+}
+
+/// Ditto
+template Replace(T, alias U, TList...)
+{
+ alias Replace = GenericReplace!(T, U, TList).result;
+}
+
+/// Ditto
+template Replace(alias T, alias U, TList...)
+{
+ alias Replace = GenericReplace!(T, U, TList).result;
+}
+
+///
+@safe unittest
+{
+ alias Types = AliasSeq!(int, long, long, int, float);
+
+ alias TL = Replace!(long, char, Types);
+ static assert(is(TL == AliasSeq!(int, char, long, int, float)));
+}
+
+// [internal]
+private template GenericReplace(args...)
+if (args.length >= 2)
+{
+ alias from = OldAlias!(args[0]);
+ alias to = OldAlias!(args[1]);
+ alias tuple = args[2 .. $];
+
+ static if (tuple.length)
+ {
+ alias head = OldAlias!(tuple[0]);
+ alias tail = tuple[1 .. $];
+
+ static if (isSame!(from, head))
+ alias result = AliasSeq!(to, tail);
+ else
+ alias result = AliasSeq!(head,
+ GenericReplace!(from, to, tail).result);
+ }
+ else
+ {
+ alias result = AliasSeq!();
+ }
+ }
+
+@safe unittest
+{
+ static assert(Pack!(Replace!(byte, ubyte,
+ short, byte, byte, byte)).
+ equals!(short, ubyte, byte, byte));
+
+ static assert(Pack!(Replace!(1111, byte,
+ 2222, 1111, 1111, 1111)).
+ equals!(2222, byte, 1111, 1111));
+
+ static assert(Pack!(Replace!(byte, 1111,
+ short, byte, byte, byte)).
+ equals!(short, 1111, byte, byte));
+
+ static assert(Pack!(Replace!(1111, "11",
+ 2222, 1111, 1111, 1111)).
+ equals!(2222, "11", 1111, 1111));
+}
+
+/**
+ * Returns an `AliasSeq` created from TList with all occurrences
+ * of type T, if found, replaced with type U.
+ */
+template ReplaceAll(T, U, TList...)
+{
+ alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
+}
+
+/// Ditto
+template ReplaceAll(alias T, U, TList...)
+{
+ alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
+}
+
+/// Ditto
+template ReplaceAll(T, alias U, TList...)
+{
+ alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
+}
+
+/// Ditto
+template ReplaceAll(alias T, alias U, TList...)
+{
+ alias ReplaceAll = GenericReplaceAll!(T, U, TList).result;
+}
+
+///
+@safe unittest
+{
+ alias Types = AliasSeq!(int, long, long, int, float);
+
+ alias TL = ReplaceAll!(long, char, Types);
+ static assert(is(TL == AliasSeq!(int, char, char, int, float)));
+}
+
+// [internal]
+private template GenericReplaceAll(args...)
+if (args.length >= 2)
+{
+ alias from = OldAlias!(args[0]);
+ alias to = OldAlias!(args[1]);
+ alias tuple = args[2 .. $];
+
+ static if (tuple.length)
+ {
+ alias head = OldAlias!(tuple[0]);
+ alias tail = tuple[1 .. $];
+ alias next = GenericReplaceAll!(from, to, tail).result;
+
+ static if (isSame!(from, head))
+ alias result = AliasSeq!(to, next);
+ else
+ alias result = AliasSeq!(head, next);
+ }
+ else
+ {
+ alias result = AliasSeq!();
+ }
+}
+
+@safe unittest
+{
+ static assert(Pack!(ReplaceAll!(byte, ubyte,
+ byte, short, byte, byte)).
+ equals!(ubyte, short, ubyte, ubyte));
+
+ static assert(Pack!(ReplaceAll!(1111, byte,
+ 1111, 2222, 1111, 1111)).
+ equals!(byte, 2222, byte, byte));
+
+ static assert(Pack!(ReplaceAll!(byte, 1111,
+ byte, short, byte, byte)).
+ equals!(1111, short, 1111, 1111));
+
+ static assert(Pack!(ReplaceAll!(1111, "11",
+ 1111, 2222, 1111, 1111)).
+ equals!("11", 2222, "11", "11"));
+}
+
+/**
+ * Returns an `AliasSeq` created from TList with the order reversed.
+ */
+template Reverse(TList...)
+{
+ static if (TList.length <= 1)
+ {
+ alias Reverse = TList;
+ }
+ else
+ {
+ alias Reverse =
+ AliasSeq!(
+ Reverse!(TList[$/2 .. $ ]),
+ Reverse!(TList[ 0 .. $/2]));
+ }
+}
+
+///
+@safe unittest
+{
+ alias Types = AliasSeq!(int, long, long, int, float);
+
+ alias TL = Reverse!(Types);
+ static assert(is(TL == AliasSeq!(float, int, long, long, int)));
+}
+
+/**
+ * Returns the type from TList that is the most derived from type T.
+ * If none are found, T is returned.
+ */
+template MostDerived(T, TList...)
+{
+ static if (TList.length == 0)
+ alias MostDerived = T;
+ else static if (is(TList[0] : T))
+ alias MostDerived = MostDerived!(TList[0], TList[1 .. $]);
+ else
+ alias MostDerived = MostDerived!(T, TList[1 .. $]);
+}
+
+///
+@safe unittest
+{
+ class A { }
+ class B : A { }
+ class C : B { }
+ alias Types = AliasSeq!(A, C, B);
+
+ MostDerived!(Object, Types) x; // x is declared as type C
+ static assert(is(typeof(x) == C));
+}
+
+/**
+ * Returns the `AliasSeq` TList with the types sorted so that the most
+ * derived types come first.
+ */
+template DerivedToFront(TList...)
+{
+ static if (TList.length == 0)
+ alias DerivedToFront = TList;
+ else
+ alias DerivedToFront =
+ AliasSeq!(MostDerived!(TList[0], TList[1 .. $]),
+ DerivedToFront!(ReplaceAll!(MostDerived!(TList[0], TList[1 .. $]),
+ TList[0],
+ TList[1 .. $])));
+}
+
+///
+@safe unittest
+{
+ class A { }
+ class B : A { }
+ class C : B { }
+ alias Types = AliasSeq!(A, C, B);
+
+ alias TL = DerivedToFront!(Types);
+ static assert(is(TL == AliasSeq!(C, B, A)));
+}
+
+/**
+Evaluates to $(D AliasSeq!(F!(T[0]), F!(T[1]), ..., F!(T[$ - 1]))).
+ */
+template staticMap(alias F, T...)
+{
+ static if (T.length == 0)
+ {
+ alias staticMap = AliasSeq!();
+ }
+ else static if (T.length == 1)
+ {
+ alias staticMap = AliasSeq!(F!(T[0]));
+ }
+ else
+ {
+ alias staticMap =
+ AliasSeq!(
+ staticMap!(F, T[ 0 .. $/2]),
+ staticMap!(F, T[$/2 .. $ ]));
+ }
+}
+
+///
+@safe unittest
+{
+ import std.traits : Unqual;
+ alias TL = staticMap!(Unqual, int, const int, immutable int);
+ static assert(is(TL == AliasSeq!(int, int, int)));
+}
+
+@safe unittest
+{
+ import std.traits : Unqual;
+
+ // empty
+ alias Empty = staticMap!(Unqual);
+ static assert(Empty.length == 0);
+
+ // single
+ alias Single = staticMap!(Unqual, const int);
+ static assert(is(Single == AliasSeq!int));
+
+ alias T = staticMap!(Unqual, int, const int, immutable int);
+ static assert(is(T == AliasSeq!(int, int, int)));
+}
+
+/**
+Tests whether all given items satisfy a template predicate, i.e. evaluates to
+$(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])).
+
+Evaluation is $(I not) short-circuited if a false result is encountered; the
+template predicate must be instantiable with all the given items.
+ */
+template allSatisfy(alias F, T...)
+{
+ static if (T.length == 0)
+ {
+ enum allSatisfy = true;
+ }
+ else static if (T.length == 1)
+ {
+ enum allSatisfy = F!(T[0]);
+ }
+ else
+ {
+ enum allSatisfy =
+ allSatisfy!(F, T[ 0 .. $/2]) &&
+ allSatisfy!(F, T[$/2 .. $ ]);
+ }
+}
+
+///
+@safe unittest
+{
+ import std.traits : isIntegral;
+
+ static assert(!allSatisfy!(isIntegral, int, double));
+ static assert( allSatisfy!(isIntegral, int, long));
+}
+
+/**
+Tests whether any given items satisfy a template predicate, i.e. evaluates to
+$(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])).
+
+Evaluation is short-circuited if a true result is encountered; the
+template predicate must be instantiable with one of the given items.
+ */
+template anySatisfy(alias F, T...)
+{
+ static if (T.length == 0)
+ {
+ enum anySatisfy = false;
+ }
+ else static if (T.length == 1)
+ {
+ enum anySatisfy = F!(T[0]);
+ }
+ else
+ {
+ enum anySatisfy =
+ anySatisfy!(F, T[ 0 .. $/2]) ||
+ anySatisfy!(F, T[$/2 .. $ ]);
+ }
+}
+
+///
+@safe unittest
+{
+ import std.traits : isIntegral;
+
+ static assert(!anySatisfy!(isIntegral, string, double));
+ static assert( anySatisfy!(isIntegral, int, double));
+}
+
+
+/**
+ * Filters an $(D AliasSeq) using a template predicate. Returns a
+ * $(D AliasSeq) of the elements which satisfy the predicate.
+ */
+template Filter(alias pred, TList...)
+{
+ static if (TList.length == 0)
+ {
+ alias Filter = AliasSeq!();
+ }
+ else static if (TList.length == 1)
+ {
+ static if (pred!(TList[0]))
+ alias Filter = AliasSeq!(TList[0]);
+ else
+ alias Filter = AliasSeq!();
+ }
+ else
+ {
+ alias Filter =
+ AliasSeq!(
+ Filter!(pred, TList[ 0 .. $/2]),
+ Filter!(pred, TList[$/2 .. $ ]));
+ }
+}
+
+///
+@safe unittest
+{
+ import std.traits : isNarrowString, isUnsigned;
+
+ alias Types1 = AliasSeq!(string, wstring, dchar[], char[], dstring, int);
+ alias TL1 = Filter!(isNarrowString, Types1);
+ static assert(is(TL1 == AliasSeq!(string, wstring, char[])));
+
+ alias Types2 = AliasSeq!(int, byte, ubyte, dstring, dchar, uint, ulong);
+ alias TL2 = Filter!(isUnsigned, Types2);
+ static assert(is(TL2 == AliasSeq!(ubyte, uint, ulong)));
+}
+
+@safe unittest
+{
+ import std.traits : isPointer;
+
+ static assert(is(Filter!(isPointer, int, void*, char[], int*) == AliasSeq!(void*, int*)));
+ static assert(is(Filter!isPointer == AliasSeq!()));
+}
+
+
+// Used in template predicate unit tests below.
+private version (unittest)
+{
+ template testAlways(T...)
+ {
+ enum testAlways = true;
+ }
+
+ template testNever(T...)
+ {
+ enum testNever = false;
+ }
+
+ template testError(T...)
+ {
+ static assert(false, "Should never be instantiated.");
+ }
+}
+
+
+/**
+ * Negates the passed template predicate.
+ */
+template templateNot(alias pred)
+{
+ enum templateNot(T...) = !pred!T;
+}
+
+///
+@safe unittest
+{
+ import std.traits : isPointer;
+
+ alias isNoPointer = templateNot!isPointer;
+ static assert(!isNoPointer!(int*));
+ static assert(allSatisfy!(isNoPointer, string, char, float));
+}
+
+@safe unittest
+{
+ foreach (T; AliasSeq!(int, staticMap, 42))
+ {
+ static assert(!Instantiate!(templateNot!testAlways, T));
+ static assert(Instantiate!(templateNot!testNever, T));
+ }
+}
+
+
+/**
+ * Combines several template predicates using logical AND, i.e. constructs a new
+ * predicate which evaluates to true for a given input T if and only if all of
+ * the passed predicates are true for T.
+ *
+ * The predicates are evaluated from left to right, aborting evaluation in a
+ * short-cut manner if a false result is encountered, in which case the latter
+ * instantiations do not need to compile.
+ */
+template templateAnd(Preds...)
+{
+ template templateAnd(T...)
+ {
+ static if (Preds.length == 0)
+ {
+ enum templateAnd = true;
+ }
+ else
+ {
+ static if (Instantiate!(Preds[0], T))
+ alias templateAnd = Instantiate!(.templateAnd!(Preds[1 .. $]), T);
+ else
+ enum templateAnd = false;
+ }
+ }
+}
+
+///
+@safe unittest
+{
+ import std.traits : isNumeric, isUnsigned;
+
+ alias storesNegativeNumbers = templateAnd!(isNumeric, templateNot!isUnsigned);
+ static assert(storesNegativeNumbers!int);
+ static assert(!storesNegativeNumbers!string && !storesNegativeNumbers!uint);
+
+ // An empty list of predicates always yields true.
+ alias alwaysTrue = templateAnd!();
+ static assert(alwaysTrue!int);
+}
+
+@safe unittest
+{
+ foreach (T; AliasSeq!(int, staticMap, 42))
+ {
+ static assert( Instantiate!(templateAnd!(), T));
+ static assert( Instantiate!(templateAnd!(testAlways), T));
+ static assert( Instantiate!(templateAnd!(testAlways, testAlways), T));
+ static assert(!Instantiate!(templateAnd!(testNever), T));
+ static assert(!Instantiate!(templateAnd!(testAlways, testNever), T));
+ static assert(!Instantiate!(templateAnd!(testNever, testAlways), T));
+
+ static assert(!Instantiate!(templateAnd!(testNever, testError), T));
+ static assert(!is(typeof(Instantiate!(templateAnd!(testAlways, testError), T))));
+ }
+}
+
+
+/**
+ * Combines several template predicates using logical OR, i.e. constructs a new
+ * predicate which evaluates to true for a given input T if and only at least
+ * one of the passed predicates is true for T.
+ *
+ * The predicates are evaluated from left to right, aborting evaluation in a
+ * short-cut manner if a true result is encountered, in which case the latter
+ * instantiations do not need to compile.
+ */
+template templateOr(Preds...)
+{
+ template templateOr(T...)
+ {
+ static if (Preds.length == 0)
+ {
+ enum templateOr = false;
+ }
+ else
+ {
+ static if (Instantiate!(Preds[0], T))
+ enum templateOr = true;
+ else
+ alias templateOr = Instantiate!(.templateOr!(Preds[1 .. $]), T);
+ }
+ }
+}
+
+///
+@safe unittest
+{
+ import std.traits : isPointer, isUnsigned;
+
+ alias isPtrOrUnsigned = templateOr!(isPointer, isUnsigned);
+ static assert( isPtrOrUnsigned!uint && isPtrOrUnsigned!(short*));
+ static assert(!isPtrOrUnsigned!int && !isPtrOrUnsigned!(string));
+
+ // An empty list of predicates never yields true.
+ alias alwaysFalse = templateOr!();
+ static assert(!alwaysFalse!int);
+}
+
+@safe unittest
+{
+ foreach (T; AliasSeq!(int, staticMap, 42))
+ {
+ static assert( Instantiate!(templateOr!(testAlways), T));
+ static assert( Instantiate!(templateOr!(testAlways, testAlways), T));
+ static assert( Instantiate!(templateOr!(testAlways, testNever), T));
+ static assert( Instantiate!(templateOr!(testNever, testAlways), T));
+ static assert(!Instantiate!(templateOr!(), T));
+ static assert(!Instantiate!(templateOr!(testNever), T));
+
+ static assert( Instantiate!(templateOr!(testAlways, testError), T));
+ static assert( Instantiate!(templateOr!(testNever, testAlways, testError), T));
+ // DMD @@BUG@@: Assertion fails for int, seems like a error gagging
+ // problem. The bug goes away when removing some of the other template
+ // instantiations in the module.
+ // static assert(!is(typeof(Instantiate!(templateOr!(testNever, testError), T))));
+ }
+}
+
+/**
+ * Converts an input range $(D range) to an alias sequence.
+ */
+template aliasSeqOf(alias range)
+{
+ import std.traits : isArray, isNarrowString;
+
+ alias ArrT = typeof(range);
+ static if (isArray!ArrT && !isNarrowString!ArrT)
+ {
+ static if (range.length == 0)
+ {
+ alias aliasSeqOf = AliasSeq!();
+ }
+ else static if (range.length == 1)
+ {
+ alias aliasSeqOf = AliasSeq!(range[0]);
+ }
+ else
+ {
+ alias aliasSeqOf = AliasSeq!(aliasSeqOf!(range[0 .. $/2]), aliasSeqOf!(range[$/2 .. $]));
+ }
+ }
+ else
+ {
+ import std.range.primitives : isInputRange;
+ static if (isInputRange!ArrT)
+ {
+ import std.array : array;
+ alias aliasSeqOf = aliasSeqOf!(array(range));
+ }
+ else
+ {
+ static assert(false, "Cannot transform range of type " ~ ArrT.stringof ~ " into a AliasSeq.");
+ }
+ }
+}
+
+///
+@safe unittest
+{
+ import std.algorithm.iteration : map;
+ import std.algorithm.sorting : sort;
+ import std.string : capitalize;
+
+ struct S
+ {
+ int a;
+ int c;
+ int b;
+ }
+
+ alias capMembers = aliasSeqOf!([__traits(allMembers, S)].sort().map!capitalize());
+ static assert(capMembers[0] == "A");
+ static assert(capMembers[1] == "B");
+ static assert(capMembers[2] == "C");
+}
+
+///
+@safe unittest
+{
+ static immutable REF = [0, 1, 2, 3];
+ foreach (I, V; aliasSeqOf!([0, 1, 2, 3]))
+ {
+ static assert(V == I);
+ static assert(V == REF[I]);
+ }
+}
+
+@safe unittest
+{
+ import std.conv : to, octal;
+ import std.range : iota;
+ //Testing compile time octal
+ foreach (I2; aliasSeqOf!(iota(0, 8)))
+ foreach (I1; aliasSeqOf!(iota(0, 8)))
+ {
+ enum oct = I2 * 8 + I1;
+ enum dec = I2 * 10 + I1;
+ enum str = to!string(dec);
+ static assert(octal!dec == oct);
+ static assert(octal!str == oct);
+ }
+}
+
+@safe unittest
+{
+ enum REF = "日本語"d;
+ foreach (I, V; aliasSeqOf!"日本語"c)
+ {
+ static assert(V == REF[I]);
+ }
+}
+
+/**
+ * $(LINK2 http://en.wikipedia.org/wiki/Partial_application, Partially applies)
+ * $(D_PARAM Template) by binding its first (left) or last (right) arguments
+ * to $(D_PARAM args).
+ *
+ * Behaves like the identity function when $(D_PARAM args) is empty.
+ * Params:
+ * Template = template to partially apply
+ * args = arguments to bind
+ * Returns:
+ * _Template with arity smaller than or equal to $(D_PARAM Template)
+ */
+template ApplyLeft(alias Template, args...)
+{
+ alias ApplyLeft(right...) = SmartAlias!(Template!(args, right));
+}
+
+/// Ditto
+template ApplyRight(alias Template, args...)
+{
+ alias ApplyRight(left...) = SmartAlias!(Template!(left, args));
+}
+
+///
+@safe unittest
+{
+ // enum bool isImplicitlyConvertible(From, To)
+ import std.traits : isImplicitlyConvertible;
+
+ static assert(allSatisfy!(
+ ApplyLeft!(isImplicitlyConvertible, ubyte),
+ short, ushort, int, uint, long, ulong));
+
+ static assert(is(Filter!(ApplyRight!(isImplicitlyConvertible, short),
+ ubyte, string, short, float, int) == AliasSeq!(ubyte, short)));
+}
+
+///
+@safe unittest
+{
+ import std.traits : hasMember, ifTestable;
+
+ struct T1
+ {
+ bool foo;
+ }
+
+ struct T2
+ {
+ struct Test
+ {
+ bool opCast(T : bool)() { return true; }
+ }
+
+ Test foo;
+ }
+
+ static assert(allSatisfy!(ApplyRight!(hasMember, "foo"), T1, T2));
+ static assert(allSatisfy!(ApplyRight!(ifTestable, a => a.foo), T1, T2));
+}
+
+///
+@safe unittest
+{
+ import std.traits : Largest;
+
+ alias Types = AliasSeq!(byte, short, int, long);
+
+ static assert(is(staticMap!(ApplyLeft!(Largest, short), Types) ==
+ AliasSeq!(short, short, int, long)));
+ static assert(is(staticMap!(ApplyLeft!(Largest, int), Types) ==
+ AliasSeq!(int, int, int, long)));
+}
+
+///
+@safe unittest
+{
+ import std.traits : FunctionAttribute, SetFunctionAttributes;
+
+ static void foo() @system;
+ static int bar(int) @system;
+
+ alias SafeFunctions = AliasSeq!(
+ void function() @safe,
+ int function(int) @safe);
+
+ static assert(is(staticMap!(ApplyRight!(
+ SetFunctionAttributes, "D", FunctionAttribute.safe),
+ typeof(&foo), typeof(&bar)) == SafeFunctions));
+}
+
+private template SmartAlias(T...)
+{
+ static if (T.length == 1)
+ {
+ alias SmartAlias = Alias!T;
+ }
+ else
+ {
+ alias SmartAlias = AliasSeq!T;
+ }
+}
+
+@safe unittest
+{
+ static assert(is(typeof({
+ alias T(T0, int a, double b, alias T1, string c) = AliasSeq!(T0, a, b, T1, c);
+ alias T0 = ApplyRight!(ApplyLeft, ApplyRight);
+ alias T1 = T0!ApplyLeft;
+ alias T2 = T1!T;
+ alias T3 = T2!(3, "foo");
+ alias T4 = T3!(short, 3, 3.3);
+ static assert(Pack!T4.equals!(short, 3, 3.3, 3, "foo"));
+
+ import std.traits : isImplicitlyConvertible;
+ alias U1 = ApplyLeft!(ApplyRight, isImplicitlyConvertible);
+ alias U2 = U1!int;
+ enum U3 = U2!short;
+ static assert(U3);
+ })));
+}
+
+/**
+ * Creates an `AliasSeq` which repeats a type or an `AliasSeq` exactly `n` times.
+ */
+template Repeat(size_t n, TList...)
+if (n > 0)
+{
+ static if (n == 1)
+ {
+ alias Repeat = AliasSeq!TList;
+ }
+ else static if (n == 2)
+ {
+ alias Repeat = AliasSeq!(TList, TList);
+ }
+ else
+ {
+ alias R = Repeat!((n - 1) / 2, TList);
+ static if ((n - 1) % 2 == 0)
+ {
+ alias Repeat = AliasSeq!(TList, R, R);
+ }
+ else
+ {
+ alias Repeat = AliasSeq!(TList, TList, R, R);
+ }
+ }
+}
+
+///
+@safe unittest
+{
+ alias ImInt1 = Repeat!(1, immutable(int));
+ static assert(is(ImInt1 == AliasSeq!(immutable(int))));
+
+ alias Real3 = Repeat!(3, real);
+ static assert(is(Real3 == AliasSeq!(real, real, real)));
+
+ alias Real12 = Repeat!(4, Real3);
+ static assert(is(Real12 == AliasSeq!(real, real, real, real, real, real,
+ real, real, real, real, real, real)));
+
+ alias Composite = AliasSeq!(uint, int);
+ alias Composite2 = Repeat!(2, Composite);
+ static assert(is(Composite2 == AliasSeq!(uint, int, uint, int)));
+}
+
+
+///
+@safe unittest
+{
+ auto staticArray(T, size_t n)(Repeat!(n, T) elems)
+ {
+ T[n] a = [elems];
+ return a;
+ }
+
+ auto a = staticArray!(long, 3)(3, 1, 4);
+ assert(is(typeof(a) == long[3]));
+ assert(a == [3, 1, 4]);
+}
+
+/**
+ * Sorts a $(LREF AliasSeq) using $(D cmp).
+ *
+ * Parameters:
+ * cmp = A template that returns a $(D bool) (if its first argument is less than the second one)
+ * or an $(D int) (-1 means less than, 0 means equal, 1 means greater than)
+ *
+ * Seq = The $(LREF AliasSeq) to sort
+ *
+ * Returns: The sorted alias sequence
+ */
+template staticSort(alias cmp, Seq...)
+{
+ static if (Seq.length < 2)
+ {
+ alias staticSort = Seq;
+ }
+ else
+ {
+ private alias btm = staticSort!(cmp, Seq[0 .. $ / 2]);
+ private alias top = staticSort!(cmp, Seq[$ / 2 .. $]);
+
+ static if (isLessEq!(cmp, btm[$ - 1], top[0]))
+ alias staticSort = AliasSeq!(btm, top); // already ascending
+ else static if (isLessEq!(cmp, top[$ - 1], btm[0]))
+ alias staticSort = AliasSeq!(top, btm); // already descending
+ else
+ alias staticSort = staticMerge!(cmp, Seq.length / 2, btm, top);
+ }
+}
+
+///
+@safe unittest
+{
+ alias Nums = AliasSeq!(7, 2, 3, 23);
+ enum Comp(int N1, int N2) = N1 < N2;
+ static assert(AliasSeq!(2, 3, 7, 23) == staticSort!(Comp, Nums));
+}
+
+///
+@safe unittest
+{
+ alias Types = AliasSeq!(uint, short, ubyte, long, ulong);
+ enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1);
+ static assert(is(AliasSeq!(uint, ubyte, ulong, short, long) == staticSort!(Comp,
+ Types)));
+}
+
+private template staticMerge(alias cmp, int half, Seq...)
+{
+ static if (half == 0 || half == Seq.length)
+ {
+ alias staticMerge = Seq;
+ }
+ else
+ {
+ static if (isLessEq!(cmp, Seq[0], Seq[half]))
+ {
+ alias staticMerge = AliasSeq!(Seq[0],
+ staticMerge!(cmp, half - 1, Seq[1 .. $]));
+ }
+ else
+ {
+ alias staticMerge = AliasSeq!(Seq[half],
+ staticMerge!(cmp, half, Seq[0 .. half], Seq[half + 1 .. $]));
+ }
+ }
+}
+
+private template isLessEq(alias cmp, Seq...)
+if (Seq.length == 2)
+{
+ private enum Result = cmp!(Seq[1], Seq[0]);
+ static if (is(typeof(Result) == bool))
+ enum isLessEq = !Result;
+ else static if (is(typeof(Result) : int))
+ enum isLessEq = Result >= 0;
+ else
+ static assert(0, typeof(Result).stringof ~ " is not a value comparison type");
+}
+
+/**
+ * Checks if an $(LREF AliasSeq) is sorted according to $(D cmp).
+ *
+ * Parameters:
+ * cmp = A template that returns a $(D bool) (if its first argument is less than the second one)
+ * or an $(D int) (-1 means less than, 0 means equal, 1 means greater than)
+ *
+ * Seq = The $(LREF AliasSeq) to check
+ *
+ * Returns: `true` if `Seq` is sorted; otherwise `false`
+ */
+template staticIsSorted(alias cmp, Seq...)
+{
+ static if (Seq.length <= 1)
+ enum staticIsSorted = true;
+ else static if (Seq.length == 2)
+ enum staticIsSorted = isLessEq!(cmp, Seq[0], Seq[1]);
+ else
+ {
+ enum staticIsSorted =
+ isLessEq!(cmp, Seq[($ / 2) - 1], Seq[$ / 2]) &&
+ staticIsSorted!(cmp, Seq[0 .. $ / 2]) &&
+ staticIsSorted!(cmp, Seq[$ / 2 .. $]);
+ }
+}
+
+///
+@safe unittest
+{
+ enum Comp(int N1, int N2) = N1 < N2;
+ static assert( staticIsSorted!(Comp, 2, 2));
+ static assert( staticIsSorted!(Comp, 2, 3, 7, 23));
+ static assert(!staticIsSorted!(Comp, 7, 2, 3, 23));
+}
+
+///
+@safe unittest
+{
+ enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1);
+ static assert( staticIsSorted!(Comp, uint, ubyte, ulong, short, long));
+ static assert(!staticIsSorted!(Comp, uint, short, ubyte, long, ulong));
+}
+
+/**
+Selects a subset of the argument list by stepping with fixed `stepSize` over the list.
+A negative `stepSize` starts iteration with the last list element.
+
+Params:
+ stepSize = Number of elements to increment on each iteration. Can't be `0`.
+ Args = Template arguments
+
+Returns: A template argument list filtered by the selected stride.
+*/
+template Stride(int stepSize, Args...)
+if (stepSize != 0)
+{
+ static if (Args.length == 0)
+ {
+ alias Stride = AliasSeq!();
+ }
+ else static if (stepSize > 0)
+ {
+ static if (stepSize >= Args.length)
+ alias Stride = AliasSeq!(Args[0]);
+ else
+ alias Stride = AliasSeq!(Args[0], Stride!(stepSize, Args[stepSize .. $]));
+ }
+ else
+ {
+ static if (-stepSize >= Args.length)
+ alias Stride = AliasSeq!(Args[$ - 1]);
+ else
+ alias Stride = AliasSeq!(Args[$ - 1], Stride!(stepSize, Args[0 .. $ + stepSize]));
+ }
+}
+
+///
+@safe unittest
+{
+ static assert(is(Stride!(1, short, int, long) == AliasSeq!(short, int, long)));
+ static assert(is(Stride!(2, short, int, long) == AliasSeq!(short, long)));
+ static assert(is(Stride!(-1, short, int, long) == AliasSeq!(long, int, short)));
+ static assert(is(Stride!(-2, short, int, long) == AliasSeq!(long, short)));
+
+ alias attribs = AliasSeq!(short, int, long, ushort, uint, ulong);
+ static assert(is(Stride!(3, attribs) == AliasSeq!(short, ushort)));
+ static assert(is(Stride!(3, attribs[1 .. $]) == AliasSeq!(int, uint)));
+ static assert(is(Stride!(-3, attribs) == AliasSeq!(ulong, long)));
+}
+
+@safe unittest
+{
+ static assert(Pack!(Stride!(5, int)).equals!(int));
+ static assert(Pack!(Stride!(-5, int)).equals!(int));
+ static assert(!__traits(compiles, Stride!(0, int)));
+}
+
+// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : //
+private:
+
+/*
+ * [internal] Returns true if a and b are the same thing, or false if
+ * not. Both a and b can be types, literals, or symbols.
+ *
+ * How: When:
+ * is(a == b) - both are types
+ * a == b - both are literals (true literals, enums)
+ * __traits(isSame, a, b) - other cases (variables, functions,
+ * templates, etc.)
+ */
+private template isSame(ab...)
+if (ab.length == 2)
+{
+ static if (__traits(compiles, expectType!(ab[0]),
+ expectType!(ab[1])))
+ {
+ enum isSame = is(ab[0] == ab[1]);
+ }
+ else static if (!__traits(compiles, expectType!(ab[0])) &&
+ !__traits(compiles, expectType!(ab[1])) &&
+ __traits(compiles, expectBool!(ab[0] == ab[1])))
+ {
+ static if (!__traits(compiles, &ab[0]) ||
+ !__traits(compiles, &ab[1]))
+ enum isSame = (ab[0] == ab[1]);
+ else
+ enum isSame = __traits(isSame, ab[0], ab[1]);
+ }
+ else
+ {
+ enum isSame = __traits(isSame, ab[0], ab[1]);
+ }
+}
+private template expectType(T) {}
+private template expectBool(bool b) {}
+
+@safe unittest
+{
+ static assert( isSame!(int, int));
+ static assert(!isSame!(int, short));
+
+ enum a = 1, b = 1, c = 2, s = "a", t = "a";
+ static assert( isSame!(1, 1));
+ static assert( isSame!(a, 1));
+ static assert( isSame!(a, b));
+ static assert(!isSame!(b, c));
+ static assert( isSame!("a", "a"));
+ static assert( isSame!(s, "a"));
+ static assert( isSame!(s, t));
+ static assert(!isSame!(1, "1"));
+ static assert(!isSame!(a, "a"));
+ static assert( isSame!(isSame, isSame));
+ static assert(!isSame!(isSame, a));
+
+ static assert(!isSame!(byte, a));
+ static assert(!isSame!(short, isSame));
+ static assert(!isSame!(a, int));
+ static assert(!isSame!(long, isSame));
+
+ static immutable X = 1, Y = 1, Z = 2;
+ static assert( isSame!(X, X));
+ static assert(!isSame!(X, Y));
+ static assert(!isSame!(Y, Z));
+
+ int foo();
+ int bar();
+ real baz(int);
+ static assert( isSame!(foo, foo));
+ static assert(!isSame!(foo, bar));
+ static assert(!isSame!(bar, baz));
+ static assert( isSame!(baz, baz));
+ static assert(!isSame!(foo, 0));
+
+ int x, y;
+ real z;
+ static assert( isSame!(x, x));
+ static assert(!isSame!(x, y));
+ static assert(!isSame!(y, z));
+ static assert( isSame!(z, z));
+ static assert(!isSame!(x, 0));
+}
+
+/*
+ * [internal] Confines a tuple within a template.
+ */
+private template Pack(T...)
+{
+ alias tuple = T;
+
+ // For convenience
+ template equals(U...)
+ {
+ static if (T.length == U.length)
+ {
+ static if (T.length == 0)
+ enum equals = true;
+ else
+ enum equals = isSame!(T[0], U[0]) &&
+ Pack!(T[1 .. $]).equals!(U[1 .. $]);
+ }
+ else
+ {
+ enum equals = false;
+ }
+ }
+}
+
+@safe unittest
+{
+ static assert( Pack!(1, int, "abc").equals!(1, int, "abc"));
+ static assert(!Pack!(1, int, "abc").equals!(1, int, "cba"));
+}
+
+/*
+ * Instantiates the given template with the given list of parameters.
+ *
+ * Used to work around syntactic limitations of D with regard to instantiating
+ * a template from an alias sequence (e.g. T[0]!(...) is not valid) or a template
+ * returning another template (e.g. Foo!(Bar)!(Baz) is not allowed).
+ */
+// TODO: Consider publicly exposing this, maybe even if only for better
+// understandability of error messages.
+alias Instantiate(alias Template, Params...) = Template!Params;