mirror of
https://github.com/dlang/phobos.git
synced 2025-04-27 13:40:20 +03:00
807 lines
20 KiB
D
807 lines
20 KiB
D
// Written in the D programming language.
|
|
|
|
/**
|
|
* Templates with which to manipulate type tuples (also known as type lists).
|
|
*
|
|
* Some operations on type tuples are built in to the language,
|
|
* such as TL[$(I n)] which gets the $(I n)th type from the
|
|
* type tuple. TL[$(I lwr) .. $(I upr)] returns a new type
|
|
* list that is a slice of the old one.
|
|
*
|
|
* 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)
|
|
* Macros:
|
|
* WIKI = Phobos/StdTypeTuple
|
|
*
|
|
* Copyright: Copyright Digital Mars 2005 - 2009.
|
|
* License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
|
|
* Authors: $(WEB digitalmars.com, Walter Bright)
|
|
* Source: $(PHOBOSSRC std/_typetuple.d)
|
|
*/
|
|
/* Copyright Digital Mars 2005 - 2009.
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
|
* http://www.boost.org/LICENSE_1_0.txt)
|
|
*/
|
|
module std.typetuple;
|
|
|
|
import std.traits;
|
|
|
|
/**
|
|
* Creates a typetuple out of a sequence of zero or more types.
|
|
* Example:
|
|
* ---
|
|
* import std.typetuple;
|
|
* alias TypeTuple!(int, double) TL;
|
|
*
|
|
* int foo(TL td) // same as int foo(int, double);
|
|
* {
|
|
* return td[0] + cast(int)td[1];
|
|
* }
|
|
* ---
|
|
*
|
|
* Example:
|
|
* ---
|
|
* TypeTuple!(TL, char)
|
|
* // is equivalent to:
|
|
* TypeTuple!(int, double, char)
|
|
* ---
|
|
*/
|
|
template TypeTuple(TList...)
|
|
{
|
|
alias TList TypeTuple;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
* Example:
|
|
* ---
|
|
* import std.typetuple;
|
|
* import std.stdio;
|
|
*
|
|
* void foo()
|
|
* {
|
|
* writefln("The index of long is %s",
|
|
* staticIndexOf!(long, TypeTuple!(int, long, double)));
|
|
* // prints: The index of long is 1
|
|
* }
|
|
* ---
|
|
*/
|
|
template staticIndexOf(T, TList...)
|
|
{
|
|
enum staticIndexOf = genericIndexOf!(T, TList).index;
|
|
}
|
|
|
|
/// Ditto
|
|
template staticIndexOf(alias T, TList...)
|
|
{
|
|
enum staticIndexOf = genericIndexOf!(T, TList).index;
|
|
}
|
|
|
|
// [internal]
|
|
private template genericIndexOf(args...)
|
|
if (args.length >= 1)
|
|
{
|
|
alias Alias!(args[0]) e;
|
|
alias args[1 .. $] tuple;
|
|
|
|
static if (tuple.length)
|
|
{
|
|
alias Alias!(tuple[0]) head;
|
|
alias tuple[1 .. $] tail;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/// Kept for backwards compatibility
|
|
alias staticIndexOf IndexOf;
|
|
|
|
/**
|
|
* Returns a typetuple created from TList with the first occurrence,
|
|
* if any, of T removed.
|
|
* Example:
|
|
* ---
|
|
* Erase!(long, int, long, double, char)
|
|
* // is the same as:
|
|
* TypeTuple!(int, double, char)
|
|
* ---
|
|
*/
|
|
// template Erase(T, TList...)
|
|
// {
|
|
// static if (TList.length == 0)
|
|
// alias TList Erase;
|
|
// else static if (is(T == TList[0]))
|
|
// alias TList[1 .. $] Erase;
|
|
// else
|
|
// alias TypeTuple!(TList[0], Erase!(T, TList[1 .. $])) Erase;
|
|
// }
|
|
template Erase(T, TList...)
|
|
{
|
|
alias GenericErase!(T, TList).result Erase;
|
|
}
|
|
|
|
/// Ditto
|
|
template Erase(alias T, TList...)
|
|
{
|
|
alias GenericErase!(T, TList).result Erase;
|
|
}
|
|
|
|
// [internal]
|
|
private template GenericErase(args...)
|
|
if (args.length >= 1)
|
|
{
|
|
alias Alias!(args[0]) e;
|
|
alias args[1 .. $] tuple;
|
|
|
|
static if (tuple.length)
|
|
{
|
|
alias Alias!(tuple[0]) head;
|
|
alias tuple[1 .. $] tail;
|
|
|
|
static if (isSame!(e, head))
|
|
alias tail result;
|
|
else
|
|
alias TypeTuple!(head, GenericErase!(e, tail).result) result;
|
|
}
|
|
else
|
|
{
|
|
alias TypeTuple!() result;
|
|
}
|
|
}
|
|
|
|
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 a typetuple created from TList with the all occurrences,
|
|
* if any, of T removed.
|
|
* Example:
|
|
* ---
|
|
* alias TypeTuple!(int, long, long, int) TL;
|
|
*
|
|
* EraseAll!(long, TL)
|
|
* // is the same as:
|
|
* TypeTuple!(int, int)
|
|
* ---
|
|
*/
|
|
template EraseAll(T, TList...)
|
|
{
|
|
alias GenericEraseAll!(T, TList).result EraseAll;
|
|
}
|
|
|
|
/// Ditto
|
|
template EraseAll(alias T, TList...)
|
|
{
|
|
alias GenericEraseAll!(T, TList).result EraseAll;
|
|
}
|
|
|
|
// [internal]
|
|
private template GenericEraseAll(args...)
|
|
if (args.length >= 1)
|
|
{
|
|
alias Alias!(args[0]) e;
|
|
alias args[1 .. $] tuple;
|
|
|
|
static if (tuple.length)
|
|
{
|
|
alias Alias!(tuple[0]) head;
|
|
alias tuple[1 .. $] tail;
|
|
alias GenericEraseAll!(e, tail).result next;
|
|
|
|
static if (isSame!(e, head))
|
|
alias next result;
|
|
else
|
|
alias TypeTuple!(head, next) result;
|
|
}
|
|
else
|
|
{
|
|
alias TypeTuple!() result;
|
|
}
|
|
}
|
|
|
|
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 a typetuple created from TList with the all duplicate
|
|
* types removed.
|
|
* Example:
|
|
* ---
|
|
* alias TypeTuple!(int, long, long, int, float) TL;
|
|
*
|
|
* NoDuplicates!(TL)
|
|
* // is the same as:
|
|
* TypeTuple!(int, long, float)
|
|
* ---
|
|
*/
|
|
template NoDuplicates(TList...)
|
|
{
|
|
static if (TList.length == 0)
|
|
alias TList NoDuplicates;
|
|
else
|
|
alias TypeTuple!(TList[0], NoDuplicates!(EraseAll!(TList[0], TList[1 .. $]))) NoDuplicates;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static assert(
|
|
Pack!(
|
|
NoDuplicates!(1, int, 1, NoDuplicates, int, NoDuplicates, real))
|
|
.equals!(1, int, NoDuplicates, real));
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns a typetuple created from TList with the first occurrence
|
|
* of type T, if found, replaced with type U.
|
|
* Example:
|
|
* ---
|
|
* alias TypeTuple!(int, long, long, int, float) TL;
|
|
*
|
|
* Replace!(long, char, TL)
|
|
* // is the same as:
|
|
* TypeTuple!(int, char, long, int, float)
|
|
* ---
|
|
*/
|
|
template Replace(T, U, TList...)
|
|
{
|
|
alias GenericReplace!(T, U, TList).result Replace;
|
|
}
|
|
|
|
/// Ditto
|
|
template Replace(alias T, U, TList...)
|
|
{
|
|
alias GenericReplace!(T, U, TList).result Replace;
|
|
}
|
|
|
|
/// Ditto
|
|
template Replace(T, alias U, TList...)
|
|
{
|
|
alias GenericReplace!(T, U, TList).result Replace;
|
|
}
|
|
|
|
/// Ditto
|
|
template Replace(alias T, alias U, TList...)
|
|
{
|
|
alias GenericReplace!(T, U, TList).result Replace;
|
|
}
|
|
|
|
// [internal]
|
|
private template GenericReplace(args...)
|
|
if (args.length >= 2)
|
|
{
|
|
alias Alias!(args[0]) from;
|
|
alias Alias!(args[1]) to;
|
|
alias args[2 .. $] tuple;
|
|
|
|
static if (tuple.length)
|
|
{
|
|
alias Alias!(tuple[0]) head;
|
|
alias tuple[1 .. $] tail;
|
|
|
|
static if (isSame!(from, head))
|
|
alias TypeTuple!(to, tail) result;
|
|
else
|
|
alias TypeTuple!(head,
|
|
GenericReplace!(from, to, tail).result) result;
|
|
}
|
|
else
|
|
{
|
|
alias TypeTuple!() result;
|
|
}
|
|
}
|
|
|
|
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 a typetuple created from TList with all occurrences
|
|
* of type T, if found, replaced with type U.
|
|
* Example:
|
|
* ---
|
|
* alias TypeTuple!(int, long, long, int, float) TL;
|
|
*
|
|
* ReplaceAll!(long, char, TL)
|
|
* // is the same as:
|
|
* TypeTuple!(int, char, char, int, float)
|
|
* ---
|
|
*/
|
|
template ReplaceAll(T, U, TList...)
|
|
{
|
|
alias GenericReplaceAll!(T, U, TList).result ReplaceAll;
|
|
}
|
|
|
|
/// Ditto
|
|
template ReplaceAll(alias T, U, TList...)
|
|
{
|
|
alias GenericReplaceAll!(T, U, TList).result ReplaceAll;
|
|
}
|
|
|
|
/// Ditto
|
|
template ReplaceAll(T, alias U, TList...)
|
|
{
|
|
alias GenericReplaceAll!(T, U, TList).result ReplaceAll;
|
|
}
|
|
|
|
/// Ditto
|
|
template ReplaceAll(alias T, alias U, TList...)
|
|
{
|
|
alias GenericReplaceAll!(T, U, TList).result ReplaceAll;
|
|
}
|
|
|
|
// [internal]
|
|
private template GenericReplaceAll(args...)
|
|
if (args.length >= 2)
|
|
{
|
|
alias Alias!(args[0]) from;
|
|
alias Alias!(args[1]) to;
|
|
alias args[2 .. $] tuple;
|
|
|
|
static if (tuple.length)
|
|
{
|
|
alias Alias!(tuple[0]) head;
|
|
alias tuple[1 .. $] tail;
|
|
alias GenericReplaceAll!(from, to, tail).result next;
|
|
|
|
static if (isSame!(from, head))
|
|
alias TypeTuple!(to, next) result;
|
|
else
|
|
alias TypeTuple!(head, next) result;
|
|
}
|
|
else
|
|
{
|
|
alias TypeTuple!() result;
|
|
}
|
|
}
|
|
|
|
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 a typetuple created from TList with the order reversed.
|
|
* Example:
|
|
* ---
|
|
* alias TypeTuple!(int, long, long, int, float) TL;
|
|
*
|
|
* Reverse!(TL)
|
|
* // is the same as:
|
|
* TypeTuple!(float, int, long, long, int)
|
|
* ---
|
|
*/
|
|
template Reverse(TList...)
|
|
{
|
|
static if (TList.length == 0)
|
|
alias TList Reverse;
|
|
else
|
|
alias TypeTuple!(Reverse!(TList[1 .. $]), TList[0]) Reverse;
|
|
}
|
|
|
|
/**
|
|
* Returns the type from TList that is the most derived from type T.
|
|
* If none are found, T is returned.
|
|
* Example:
|
|
* ---
|
|
* class A { }
|
|
* class B : A { }
|
|
* class C : B { }
|
|
* alias TypeTuple!(A, C, B) TL;
|
|
*
|
|
* MostDerived!(Object, TL) x; // x is declared as type C
|
|
* ---
|
|
*/
|
|
template MostDerived(T, TList...)
|
|
{
|
|
static if (TList.length == 0)
|
|
alias T MostDerived;
|
|
else static if (is(TList[0] : T))
|
|
alias MostDerived!(TList[0], TList[1 .. $]) MostDerived;
|
|
else
|
|
alias MostDerived!(T, TList[1 .. $]) MostDerived;
|
|
}
|
|
|
|
/**
|
|
* Returns the typetuple TList with the types sorted so that the most
|
|
* derived types come first.
|
|
* Example:
|
|
* ---
|
|
* class A { }
|
|
* class B : A { }
|
|
* class C : B { }
|
|
* alias TypeTuple!(A, C, B) TL;
|
|
*
|
|
* DerivedToFront!(TL)
|
|
* // is the same as:
|
|
* TypeTuple!(C, B, A)
|
|
* ---
|
|
*/
|
|
template DerivedToFront(TList...)
|
|
{
|
|
static if (TList.length == 0)
|
|
alias TList DerivedToFront;
|
|
else
|
|
alias TypeTuple!(MostDerived!(TList[0], TList[1 .. $]),
|
|
DerivedToFront!(ReplaceAll!(MostDerived!(TList[0], TList[1 .. $]),
|
|
TList[0],
|
|
TList[1 .. $]))) DerivedToFront;
|
|
}
|
|
|
|
|
|
/**
|
|
Evaluates to $(D TypeTuple!(F!(T[0]), F!(T[1]), ..., F!(T[$ - 1]))).
|
|
|
|
Example:
|
|
----
|
|
alias staticMap!(Unqual, int, const int, immutable int) T;
|
|
static assert(is(T == TypeTuple!(int, int, int)));
|
|
----
|
|
*/
|
|
template staticMap(alias F, T...)
|
|
{
|
|
static if (T.length == 0)
|
|
{
|
|
alias TypeTuple!() staticMap;
|
|
}
|
|
else
|
|
{
|
|
alias TypeTuple!(F!(T[0]),
|
|
staticMap!(F, T[1 .. $])) staticMap;
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
// empty
|
|
alias staticMap!(Unqual) Empty;
|
|
static assert(Empty.length == 0);
|
|
|
|
// single
|
|
alias staticMap!(Unqual, const int) Single;
|
|
static assert(is(Single == TypeTuple!int));
|
|
|
|
alias staticMap!(Unqual, int, const int, immutable int) T;
|
|
static assert(is(T == TypeTuple!(int, int, int)));
|
|
}
|
|
|
|
/**
|
|
Evaluates to $(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])).
|
|
|
|
Example:
|
|
----
|
|
static assert(!allSatisfy!(isIntegral, int, double));
|
|
static assert(allSatisfy!(isIntegral, int, long));
|
|
----
|
|
*/
|
|
template allSatisfy(alias F, T...)
|
|
{
|
|
static if (T.length == 0)
|
|
{
|
|
enum bool allSatisfy = true;
|
|
}
|
|
else static if (T.length == 1)
|
|
{
|
|
alias F!(T[0]) allSatisfy;
|
|
}
|
|
else
|
|
{
|
|
enum bool allSatisfy = F!(T[0]) && allSatisfy!(F, T[1 .. $]);
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static assert(!allSatisfy!(isIntegral, int, double));
|
|
static assert(allSatisfy!(isIntegral, int, long));
|
|
}
|
|
|
|
/**
|
|
Evaluates to $(D F!(T[0]) || F!(T[1]) || ... || F!(T[$ - 1])).
|
|
|
|
Example:
|
|
----
|
|
static assert(!anySatisfy!(isIntegral, string, double));
|
|
static assert(anySatisfy!(isIntegral, int, double));
|
|
----
|
|
*/
|
|
template anySatisfy(alias F, T...)
|
|
{
|
|
static if(T.length == 0)
|
|
{
|
|
enum bool anySatisfy = false;
|
|
}
|
|
else static if (T.length == 1)
|
|
{
|
|
alias F!(T[0]) anySatisfy;
|
|
}
|
|
else
|
|
{
|
|
enum bool anySatisfy = F!(T[0]) || anySatisfy!(F, T[1 .. $]);
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static assert(!anySatisfy!(isIntegral, string, double));
|
|
static assert(anySatisfy!(isIntegral, int, double));
|
|
}
|
|
|
|
// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : //
|
|
private:
|
|
|
|
/*
|
|
* [internal] With the builtin alias declaration, you cannot declare
|
|
* aliases of, for example, literal values. You can alias anything
|
|
* including literal values via this template.
|
|
*/
|
|
private
|
|
{
|
|
// symbols and literal values
|
|
template Alias(alias a)
|
|
{
|
|
static if (__traits(compiles, { alias a x; }))
|
|
alias a Alias;
|
|
else static if (__traits(compiles, { enum x = a; }))
|
|
enum Alias = a;
|
|
else
|
|
static assert(0, "Cannot alias " ~ a.stringof);
|
|
}
|
|
// types and tuples
|
|
template Alias(a...)
|
|
{
|
|
alias a Alias;
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
enum abc = 1;
|
|
static assert(__traits(compiles, { alias Alias!(123) a; }));
|
|
static assert(__traits(compiles, { alias Alias!(abc) a; }));
|
|
static assert(__traits(compiles, { alias Alias!(int) a; }));
|
|
static assert(__traits(compiles, { alias Alias!(1,abc,int) a; }));
|
|
}
|
|
|
|
|
|
/*
|
|
* [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) {}
|
|
|
|
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 T tuple;
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static assert( Pack!(1, int, "abc").equals!(1, int, "abc"));
|
|
static assert(!Pack!(1, int, "abc").equals!(1, int, "cba"));
|
|
}
|
|
|
|
|
|
/++
|
|
Filters a $(D TypeTuple) using a template predicate. Returns a
|
|
$(D TypeTuple) of the elements which satisfy the predicate.
|
|
|
|
Examples:
|
|
--------------------
|
|
static assert(is(Filter!(isNarrowString, string, wstring,
|
|
dchar[], char[], dstring, int) ==
|
|
TypeTuple!(string, wstring, char[])));
|
|
static assert(is(Filter!(isUnsigned, int, byte, ubyte,
|
|
dstring, dchar, uint, ulong) ==
|
|
TypeTuple!(ubyte, uint, ulong)));
|
|
--------------------
|
|
+/
|
|
template Filter(alias pred, TList...)
|
|
{
|
|
static if(TList.length == 0)
|
|
alias TypeTuple!() Filter;
|
|
else static if(pred!(TList[0]))
|
|
alias TypeTuple!(TList[0], Filter!(pred, TList[1 .. $])) Filter;
|
|
else
|
|
alias Filter!(pred, TList[1 .. $]) Filter;
|
|
}
|
|
|
|
//Verify Examples
|
|
unittest
|
|
{
|
|
static assert(is(Filter!(isNarrowString, string, wstring,
|
|
dchar[], char[], dstring, int) ==
|
|
TypeTuple!(string, wstring, char[])));
|
|
static assert(is(Filter!(isUnsigned, int, byte, ubyte,
|
|
dstring, dchar, uint, ulong) ==
|
|
TypeTuple!(ubyte, uint, ulong)));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static assert(is(Filter!(isPointer, int, void*, char[], int*) == TypeTuple!(void*, int*)));
|
|
static assert(is(Filter!isPointer == TypeTuple!()));
|
|
}
|