phobos/std/traits.d
Andrei Alexandrescu 29f3cc23f7 std.math: minor change in approxEqual.
std.contracts: added functions pointsTo()

std.numeric: minor unittest fixes.

std.bitmanip: fixed code bloat issue, reintroduced FloatRep and DoubleRep.

std.conv: minor simplification of implementation.

std.regexp: added reference to ECMA standard in the documentation.

std.getopt: changed return type from bool to void, error is signaled by use of exceptions.

std.functional: added unaryFun, binaryFun, adjoin.

std.string: updated documentation, changed code to compile with warnings enabled.

std.traits: changed FieldTypeTuple; added RepresentationTypeTuple, hasAliasing; fixed bug 1826; added call to flush() from within write; fixed unlisted bug in lines().

std.algorithm: added map, reduce, filter, inPlace, move, swap, overwriteAdjacent, find, findRange, findBoyerMoore, findAdjacent, findAmong, findAmongSorted, canFind, canFindAmong, canFindAmongSorted, count, equal, overlap, min, max, mismatch, EditOp, none, substitute, insert, remove, levenshteinDistance, levenshteinDistanceAndPath, copy, copyIf, iterSwap, swapRanges, reverse, rotate, SwapStrategy, Unstable, Semistable, Stable, eliminate, partition, nthElement, sort, schwartzSort, partialSort, isSorted, makeIndex, schwartzMakeIndex, lowerBound, upperBound, equalRange, canFindSorted.

std.thread: fixed so it compiles with warnings enabled.

std.file: made getSize() faster under Linux.

std.random: fixed so it compiles with warnings enabled; improved function uniform so it deduces type generated from its arguments.

std.format: added fixes to make formatting work with const data.

std.path: minor documentation changes.
2008-02-19 07:00:56 +00:00

952 lines
25 KiB
D

// Written in the D programming language.
/**
* Templates with which to extract information about
* types at compile time.
*
* Authors:
*
* $(WEB digitalmars.com, Walter Bright), Tomasz Stachowiak ($(D
* isExpressionTuple)), $(WEB erdani.org, Andrei Alexandrescu)
*
* Macros:
* WIKI = Phobos/StdTraits
* Copyright:
* Public Domain
*/
module std.traits;
import std.typetuple;
/***
* Get the type of the return value from a function,
* a pointer to function, a delegate, a struct
* with an opCall, a pointer to a struct with an opCall,
* or a class with an opCall.
* Example:
* ---
* import std.traits;
* int foo();
* ReturnType!(foo) x; // x is declared as int
* ---
*/
template ReturnType(alias dg)
{
alias ReturnType!(typeof(dg), void) ReturnType;
}
template ReturnType(dg, dummy = void)
{
static if (is(dg R == return))
alias R ReturnType;
else static if (is(dg T : T*))
alias ReturnType!(T, void) ReturnType;
else static if (is(dg S == struct))
alias ReturnType!(typeof(&dg.opCall), void) ReturnType;
else static if (is(dg C == class))
alias ReturnType!(typeof(&dg.opCall), void) ReturnType;
else
static assert(0, "argument has no return type");
}
unittest
{
struct G
{
int opCall (int i) { return 1;}
}
alias ReturnType!(G) ShouldBeInt;
static assert(is(ShouldBeInt == int));
G g;
static assert(is(ReturnType!(g) == int));
G* p;
alias ReturnType!(p) pg;
static assert(is(pg == int));
class C
{
int opCall (int i) { return 1;}
}
static assert(is(ReturnType!(C) == int));
C c;
static assert(is(ReturnType!(c) == int));
}
/***
* Get the types of the paramters to a function,
* a pointer to function, or a delegate as a tuple.
* Example:
* ---
* import std.traits;
* int foo(int, long);
* void bar(ParameterTypeTuple!(foo)); // declares void bar(int, long);
* void abc(ParameterTypeTuple!(foo)[1]); // declares void abc(long);
* ---
*/
template ParameterTypeTuple(alias dg)
{
alias ParameterTypeTuple!(typeof(dg)) ParameterTypeTuple;
}
/** ditto */
template ParameterTypeTuple(dg)
{
static if (is(dg P == function))
alias P ParameterTypeTuple;
else static if (is(dg P == delegate))
alias ParameterTypeTuple!(P) ParameterTypeTuple;
else static if (is(dg P == P*))
alias ParameterTypeTuple!(P) ParameterTypeTuple;
else
static assert(0, "argument has no parameters");
}
/***
* Get the types of the fields of a struct or class.
* This consists of the fields that take up memory space,
* excluding the hidden fields like the virtual function
* table pointer.
*/
template FieldTypeTuple(S)
{
static if (is(S == struct) || is(S == class) || is(S == union))
alias typeof(S.tupleof) FieldTypeTuple;
else
alias S FieldTypeTuple;
//static assert(0, "argument is not struct or class");
}
// // FieldOffsetsTuple
// private template FieldOffsetsTupleImpl(size_t n, T...)
// {
// static if (T.length == 0)
// {
// alias TypeTuple!() Result;
// }
// else
// {
// //private alias FieldTypeTuple!(T[0]) Types;
// private enum size_t myOffset =
// ((n + T[0].alignof - 1) / T[0].alignof) * T[0].alignof;
// static if (is(T[0] == struct))
// {
// alias FieldTypeTuple!(T[0]) MyRep;
// alias FieldOffsetsTupleImpl!(myOffset, MyRep, T[1 .. $]).Result
// Result;
// }
// else
// {
// private enum size_t mySize = T[0].sizeof;
// alias TypeTuple!(myOffset) Head;
// static if (is(T == union))
// {
// alias FieldOffsetsTupleImpl!(myOffset, T[1 .. $]).Result
// Tail;
// }
// else
// {
// alias FieldOffsetsTupleImpl!(myOffset + mySize,
// T[1 .. $]).Result
// Tail;
// }
// alias TypeTuple!(Head, Tail) Result;
// }
// }
// }
// template FieldOffsetsTuple(T...)
// {
// alias FieldOffsetsTupleImpl!(0, T).Result FieldOffsetsTuple;
// }
// unittest
// {
// alias FieldOffsetsTuple!(int) T1;
// assert(T1.length == 1 && T1[0] == 0);
// //
// struct S2 { char a; int b; char c; double d; char e, f; }
// alias FieldOffsetsTuple!(S2) T2;
// //pragma(msg, T2);
// static assert(T2.length == 6
// && T2[0] == 0 && T2[1] == 4 && T2[2] == 8 && T2[3] == 16
// && T2[4] == 24&& T2[5] == 25);
// //
// class C { int a, b, c, d; }
// struct S3 { char a; C b; char c; }
// alias FieldOffsetsTuple!(S3) T3;
// //pragma(msg, T2);
// static assert(T3.length == 3
// && T3[0] == 0 && T3[1] == 4 && T3[2] == 8);
// //
// struct S4 { char a; union { int b; char c; } int d; }
// alias FieldOffsetsTuple!(S4) T4;
// //pragma(msg, FieldTypeTuple!(S4));
// static assert(T4.length == 4
// && T4[0] == 0 && T4[1] == 4 && T4[2] == 8);
// }
// /***
// Get the offsets of the fields of a struct or class.
// */
// template FieldOffsetsTuple(S)
// {
// static if (is(S == struct) || is(S == class))
// alias typeof(S.tupleof) FieldTypeTuple;
// else
// static assert(0, "argument is not struct or class");
// }
/***
Get the primitive types of the fields of a struct or class, in
topological order.
Example:
----
struct S1 { int a; float b; }
struct S2 { char[] a; union { S1 b; S1 * c; } }
alias RepresentationTypeTuple!(S2) R;
assert(R.length == 4
&& is(R[0] == char[]) && is(R[1] == int)
&& is(R[2] == float) && is(R[3] == S1*));
----
*/
template RepresentationTypeTuple(T...)
{
static if (T.length == 0)
{
alias TypeTuple!() RepresentationTypeTuple;
}
else
{
static if (is(T[0] == struct) || is(T[0] == union))
// @@@BUG@@@ this should work
// alias .RepresentationTypes!(T[0].tupleof)
// RepresentationTypes;
alias .RepresentationTypeTuple!(FieldTypeTuple!(T[0]),
T[1 .. $])
RepresentationTypeTuple;
else static if (is(T[0] U == typedef))
{
alias .RepresentationTypeTuple!(FieldTypeTuple!(U),
T[1 .. $])
RepresentationTypeTuple;
}
else
{
alias TypeTuple!(T[0], RepresentationTypeTuple!(T[1 .. $]))
RepresentationTypeTuple;
}
}
}
unittest
{
alias RepresentationTypeTuple!(int) S1;
static assert(is(S1 == TypeTuple!(int)));
struct S2 { int a; }
static assert(is(RepresentationTypeTuple!(S2) == TypeTuple!(int)));
struct S3 { int a; char b; }
static assert(is(RepresentationTypeTuple!(S3) == TypeTuple!(int, char)));
struct S4 { S1 a; int b; S3 c; }
static assert(is(RepresentationTypeTuple!(S4) ==
TypeTuple!(int, int, int, char)));
struct S11 { int a; float b; }
struct S21 { char[] a; union { S11 b; S11 * c; } }
alias RepresentationTypeTuple!(S21) R;
assert(R.length == 4
&& is(R[0] == char[]) && is(R[1] == int)
&& is(R[2] == float) && is(R[3] == S11*));
}
/*
RepresentationOffsets
*/
// private template Repeat(size_t n, T...)
// {
// static if (n == 0) alias TypeTuple!() Repeat;
// else alias TypeTuple!(T, Repeat!(n - 1, T)) Repeat;
// }
// template RepresentationOffsetsImpl(size_t n, T...)
// {
// static if (T.length == 0)
// {
// alias TypeTuple!() Result;
// }
// else
// {
// private enum size_t myOffset =
// ((n + T[0].alignof - 1) / T[0].alignof) * T[0].alignof;
// static if (!is(T[0] == union))
// {
// alias Repeat!(n, FieldTypeTuple!(T[0])).Result
// Head;
// }
// static if (is(T[0] == struct))
// {
// alias .RepresentationOffsetsImpl!(n, FieldTypeTuple!(T[0])).Result
// Head;
// }
// else
// {
// alias TypeTuple!(myOffset) Head;
// }
// alias TypeTuple!(Head,
// RepresentationOffsetsImpl!(
// myOffset + T[0].sizeof, T[1 .. $]).Result)
// Result;
// }
// }
// template RepresentationOffsets(T)
// {
// alias RepresentationOffsetsImpl!(0, T).Result
// RepresentationOffsets;
// }
// unittest
// {
// struct S1 { char c; int i; }
// alias RepresentationOffsets!(S1) Offsets;
// static assert(Offsets[0] == 0);
// //pragma(msg, Offsets[1]);
// static assert(Offsets[1] == 4);
// }
// hasRawAliasing
private template HasRawPointerImpl(T...)
{
static if (T.length == 0)
{
enum result = false;
}
else
{
static if (is(T[0] foo : U*, U))
enum hasRawAliasing = !is(U == invariant);
else static if (is(T[0] foo : U[], U))
enum hasRawAliasing = !is(U == invariant);
else
enum hasRawAliasing = false;
enum result = hasRawAliasing || HasRawPointerImpl!(T[1 .. $]).result;
}
}
/*
Statically evaluates to $(D true) if and only if $(D T)'s
representation contains at least one field of pointer or array type.
Members of class types are not considered raw pointers. Pointers to
invariant objects are not considered raw aliasing.
Example:
---
// simple types
static assert(!hasRawAliasing!(int));
static assert(hasRawAliasing!(char*));
// references aren't raw pointers
static assert(!hasRawAliasing!(Object));
// built-in arrays do contain raw pointers
static assert(hasRawAliasing!(int[]));
// aggregate of simple types
struct S1 { int a; double b; }
static assert(!hasRawAliasing!(S1));
// indirect aggregation
struct S2 { S1 a; double b; }
static assert(!hasRawAliasing!(S2));
// struct with a pointer member
struct S3 { int a; double * b; }
static assert(hasRawAliasing!(S3));
// struct with an indirect pointer member
struct S4 { S3 a; double b; }
static assert(hasRawAliasing!(S4));
----
*/
private template hasRawAliasing(T...)
{
enum hasRawAliasing
= HasRawPointerImpl!(RepresentationTypeTuple!(T)).result;
}
unittest
{
// simple types
static assert(!hasRawAliasing!(int));
static assert(hasRawAliasing!(char*));
// references aren't raw pointers
static assert(!hasRawAliasing!(Object));
static assert(!hasRawAliasing!(int));
struct S1 { int z; }
static assert(!hasRawAliasing!(S1));
struct S2 { int* z; }
static assert(hasRawAliasing!(S2));
struct S3 { int a; int* z; int c; }
static assert(hasRawAliasing!(S3));
struct S4 { int a; int z; int c; }
static assert(!hasRawAliasing!(S4));
struct S5 { int a; Object z; int c; }
static assert(!hasRawAliasing!(S5));
union S6 { int a; int b; }
static assert(!hasRawAliasing!(S6));
union S7 { int a; int * b; }
static assert(hasRawAliasing!(S7));
typedef int* S8;
static assert(hasRawAliasing!(S8));
enum S9 { a };
static assert(!hasRawAliasing!(S9));
// indirect members
struct S10 { S7 a; int b; }
static assert(hasRawAliasing!(S10));
struct S11 { S6 a; int b; }
static assert(!hasRawAliasing!(S11));
}
/*
Statically evaluates to $(D true) if and only if $(D T)'s
representation includes at least one non-invariant object reference.
*/
private template hasObjects(T...)
{
static if (T.length == 0)
{
enum hasObjects = false;
}
else static if (is(T[0] U == typedef))
{
enum hasObjects = hasObjects!(U, T[1 .. $]);
}
else static if (is(T[0] == struct))
{
enum hasObjects = hasObjects!(
RepresentationTypeTuple!(T[0]), T[1 .. $]);
}
else
{
enum hasObjects = is(T[0] == class) || hasObjects!(T[1 .. $]);
}
}
/**
Returns $(D true) if and only if $(D T)'s representation includes at
least one of the following: $(OL $(LI a raw pointer $(D U*) and $(D U)
is not invariant;) $(LI an array $(D U[]) and $(D U) is not
invariant;) $(LI a reference to a class type $(D C) and $(D C) is not
invariant.))
*/
template hasAliasing(T...)
{
enum hasAliasing = hasRawAliasing!(T) || hasObjects!(T);
}
unittest
{
struct S1 { int a; Object b; }
static assert(hasAliasing!(S1));
struct S2 { string a; }
static assert(!hasAliasing!(S2));
}
/***
* Get a $(D_PARAM TypeTuple) of the base class and base interfaces of
* this class or interface. $(D_PARAM BaseTypeTuple!(Object)) returns
* the empty type tuple.
*
* Example:
* ---
* import std.traits, std.typetuple, std.stdio;
* interface I { }
* class A { }
* class B : A, I { }
*
* void main()
* {
* alias BaseTypeTuple!(B) TL;
* writeln(typeid(TL)); // prints: (A,I)
* }
* ---
*/
template BaseTypeTuple(A)
{
static if (is(A P == super))
alias P BaseTypeTuple;
else
static assert(0, "argument is not a class or interface");
}
unittest
{
interface I1 { }
interface I2 { }
class A { }
class C : A, I1, I2 { }
alias BaseTypeTuple!(C) TL;
assert(TL.length == 3);
assert(is (TL[0] == A));
assert(is (TL[1] == I1));
assert(is (TL[2] == I2));
assert(BaseTypeTuple!(Object).length == 0);
}
/**
* Get a $(D_PARAM TypeTuple) of $(I all) base classes of this class,
* in decreasing order. Interfaces are not included. $(D_PARAM
* BaseClassesTuple!(Object)) yields the empty type tuple.
*
* Example:
* ---
* import std.traits, std.typetuple, std.stdio;
* interface I { }
* class A { }
* class B : A, I { }
* class C : B { }
*
* void main()
* {
* alias BaseClassesTuple!(C) TL;
* writeln(typeid(TL)); // prints: (B,A,Object)
* }
* ---
*/
template BaseClassesTuple(T)
{
static if (is(T == Object))
{
alias TypeTuple!() BaseClassesTuple;
}
static if (is(BaseTypeTuple!(T)[0] == Object))
{
alias TypeTuple!(Object) BaseClassesTuple;
}
else
{
alias TypeTuple!(BaseTypeTuple!(T)[0],
BaseClassesTuple!(BaseTypeTuple!(T)[0]))
BaseClassesTuple;
}
}
/**
* Get a $(D_PARAM TypeTuple) of $(I all) interfaces directly or
* indirectly inherited by this class or interface. Interfaces do not
* repeat if multiply implemented. $(D_PARAM InterfacesTuple!(Object))
* yields the empty type tuple.
*
* Example:
* ---
* import std.traits, std.typetuple, std.stdio;
* interface I1 { }
* interface I2 { }
* class A : I1, I2 { }
* class B : A, I1 { }
* class C : B { }
*
* void main()
* {
* alias InterfacesTuple!(C) TL;
* writeln(typeid(TL)); // prints: (I1, I2)
* }
* ---
*/
template InterfacesTuple(T)
{
static if (is(T == Object))
{
alias TypeTuple!() InterfacesTuple;
}
static if (is(BaseTypeTuple!(T)[0] == Object))
{
alias TypeTuple!(BaseTypeTuple!(T)[1 .. $]) InterfacesTuple;
}
else
{
alias NoDuplicates!(
TypeTuple!(BaseTypeTuple!(T)[1 .. $], // direct interfaces
InterfacesTuple!(BaseTypeTuple!(T)[0])))
InterfacesTuple;
}
}
unittest
{
interface I1 {}
interface I2 {}
{
// doc example
class A : I1, I2 { }
class B : A, I1 { }
class C : B { }
alias InterfacesTuple!(C) TL;
assert(is(TL[0] == I1) && is(TL[1] == I2));
}
class B1 : I1, I2 {}
class B2 : B1, I1 {}
class B3 : B2, I2 {}
alias InterfacesTuple!(B3) TL;
//
assert(TL.length == 2);
assert(is (TL[0] == I2));
assert(is (TL[1] == I1));
}
/**
* Get a $(D_PARAM TypeTuple) of $(I all) base classes of $(D_PARAM
* T), in decreasing order, followed by $(D_PARAM T)'s
* interfaces. $(D_PARAM TransitiveBaseTypeTuple!(Object)) yields the
* empty type tuple.
*
* Example:
* ---
* import std.traits, std.typetuple, std.stdio;
* interface I { }
* class A { }
* class B : A, I { }
* class C : B { }
*
* void main()
* {
* alias TransitiveBaseTypeTuple!(C) TL;
* writeln(typeid(TL)); // prints: (B,A,Object,I)
* }
* ---
*/
template TransitiveBaseTypeTuple(T)
{
static if (is(T == Object))
alias TypeTuple!() TransitiveBaseTypeTuple;
else
alias TypeTuple!(BaseClassesTuple!(T),
InterfacesTuple!(T))
TransitiveBaseTypeTuple;
}
unittest
{
interface I1 {}
interface I2 {}
class B1 {}
class B2 : B1, I1, I2 {}
class B3 : B2, I1 {}
alias TransitiveBaseTypeTuple!(B3) TL;
assert(TL.length == 5);
assert(is (TL[0] == B2));
assert(is (TL[1] == B1));
assert(is (TL[2] == Object));
assert(is (TL[3] == I1));
assert(is (TL[4] == I2));
assert(TransitiveBaseTypeTuple!(Object).length == 0);
}
/**
Get the type that all types can be implicitly converted to. Useful
e.g. in figuring out an array type from a bunch of initializing
values. Returns $(D_PARAM void) if passed an empty list, or if the
types have no common type.
Example:
----
alias CommonType!(int, long, short) X;
assert(is(X == long));
alias CommonType!(int, char[], short) Y;
assert(is(Y == void));
----
*/
template CommonType(T...)
{
static if (!T.length)
alias void CommonType;
else static if (T.length == 1)
alias T[0] CommonType;
else static if (is(typeof(true ? T[0] : T[1]) U))
alias CommonType!(U, T[2 .. $]) CommonType;
else
alias void CommonType;
}
unittest
{
alias CommonType!(int, long, short) X;
assert(is(X == long));
alias CommonType!(char[], int, long, short) Y;
assert(is(Y == void), Y.stringof);
}
/**
* Returns a tuple with all possible target types of an implicit
* conversion of a value of type $(D_PARAM T).
*
* Important note:
*
* The possible targets are computed more conservatively than the D
* 2.005 compiler does, eliminating all dangerous conversions. For
* example, $(D_PARAM ImplicitConversionTargets!(double)) does not
* include $(D_PARAM float).
*/
template ImplicitConversionTargets(T)
{
static if (is(T == bool))
alias TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong,
float, double, real, char, wchar, dchar)
ImplicitConversionTargets;
else static if (is(T == byte))
alias TypeTuple!(short, ushort, int, uint, long, ulong,
float, double, real, char, wchar, dchar)
ImplicitConversionTargets;
else static if (is(T == ubyte))
alias TypeTuple!(short, ushort, int, uint, long, ulong,
float, double, real, char, wchar, dchar)
ImplicitConversionTargets;
else static if (is(T == short))
alias TypeTuple!(ushort, int, uint, long, ulong,
float, double, real)
ImplicitConversionTargets;
else static if (is(T == ushort))
alias TypeTuple!(int, uint, long, ulong, float, double, real)
ImplicitConversionTargets;
else static if (is(T == int))
alias TypeTuple!(long, ulong, float, double, real)
ImplicitConversionTargets;
else static if (is(T == uint))
alias TypeTuple!(long, ulong, float, double, real)
ImplicitConversionTargets;
else static if (is(T == long))
alias TypeTuple!(float, double, real)
ImplicitConversionTargets;
else static if (is(T == ulong))
alias TypeTuple!(float, double, real)
ImplicitConversionTargets;
else static if (is(T == float))
alias TypeTuple!(double, real)
ImplicitConversionTargets;
else static if (is(T == double))
alias TypeTuple!(real)
ImplicitConversionTargets;
else static if (is(T == char))
alias TypeTuple!(wchar, dchar, byte, ubyte, short, ushort,
int, uint, long, ulong, float, double, real)
ImplicitConversionTargets;
else static if (is(T == wchar))
alias TypeTuple!(wchar, dchar, short, ushort, int, uint, long, ulong,
float, double, real)
ImplicitConversionTargets;
else static if (is(T == dchar))
alias TypeTuple!(wchar, dchar, int, uint, long, ulong,
float, double, real)
ImplicitConversionTargets;
else static if(is(T : Object))
alias TransitiveBaseTypeTuple!(T) ImplicitConversionTargets;
else static if (is(T : void*))
alias TypeTuple!(void*) ImplicitConversionTargets;
else
alias TypeTuple!() ImplicitConversionTargets;
}
unittest
{
assert(is(ImplicitConversionTargets!(double)[0] == real));
}
/**
* Detect whether T is a built-in integral type
*/
template isIntegral(T)
{
static const isIntegral = is(T == byte) || is(T == ubyte) || is(T == short)
|| is(T == ushort) || is(T == int) || is(T == uint)
|| is(T == long) || is(T == ulong);
}
/**
* Detect whether T is a built-in floating point type
*/
template isFloatingPoint(T)
{
static const isFloatingPoint = is(T == float)
|| is(T == double) || is(T == real);
}
/**
* Detect whether T is a built-in numeric type
*/
template isNumeric(T)
{
static const isNumeric = isIntegral!(T) || isFloatingPoint!(T);
}
/**
* Detect whether T is one of the built-in string types
*/
template isSomeString(T)
{
static const isSomeString = is(T : const(char[]))
|| is(T : const(wchar[])) || is(T : const(dchar[]));
}
static assert(!isSomeString!(int));
static assert(!isSomeString!(int[]));
static assert(!isSomeString!(byte[]));
static assert(isSomeString!(char[]));
static assert(isSomeString!(dchar[]));
static assert(isSomeString!(string));
static assert(isSomeString!(wstring));
static assert(isSomeString!(dstring));
static assert(isSomeString!(char[4]));
/**
* Detect whether T is an associative array type
*/
template isAssociativeArray(T)
{
static const bool isAssociativeArray =
is(typeof(T.keys)) && is(typeof(T.values));
}
static assert(!isAssociativeArray!(int));
static assert(!isAssociativeArray!(int[]));
static assert(isAssociativeArray!(int[int]));
static assert(isAssociativeArray!(int[string]));
static assert(isAssociativeArray!(invariant(char[5])[int]));
/**
* Detect whether type T is a static array.
*/
template isStaticArray(T : U[N], U, size_t N)
{
const bool isStaticArray = true;
}
template isStaticArray(T)
{
const bool isStaticArray = false;
}
static assert (isStaticArray!(int[51]));
static assert (isStaticArray!(int[][2]));
static assert (isStaticArray!(char[][int][11]));
static assert (!isStaticArray!(const(int)[]));
static assert (!isStaticArray!(invariant(int)[]));
static assert (!isStaticArray!(const(int)[4][]));
static assert (!isStaticArray!(int[]));
static assert (!isStaticArray!(int[char]));
static assert (!isStaticArray!(int[1][]));
static assert (isStaticArray!(invariant char[13u]));
static assert (isStaticArray!(const(real)[1]));
static assert (isStaticArray!(const(real)[1][1]));
static assert (isStaticArray!(typeof("string literal")));
static assert (isStaticArray!(void[0]));
static assert (!isStaticArray!(int[int]));
static assert (!isStaticArray!(int));
/**
* Detect whether type T is a dynamic array.
*/
template isDynamicArray(T, U = void)
{
static const isDynamicArray = false;
}
template isDynamicArray(T : U[], U)
{
static const isDynamicArray = !isStaticArray!(T);
}
static assert(isDynamicArray!(int[]));
static assert(!isDynamicArray!(int[5]));
/**
* Detect whether type T is an array.
*/
template isArray(T)
{
static const isArray = isStaticArray!(T) || isDynamicArray!(T);
}
static assert(isArray!(int[]));
static assert(isArray!(int[5]));
static assert(!isArray!(uint));
static assert(!isArray!(uint[uint]));
static assert(isArray!(void[]));
/**
* Tells whether the tuple T is an expression tuple.
*/
template isExpressionTuple(T ...)
{
static if (is(void function(T)))
const bool isExpressionTuple = false;
else
const bool isExpressionTuple = true;
}
/**
* Returns the corresponding unsigned type for T. T must be a numeric
* integral type, otherwise a compile-time error occurs.
*/
template unsigned(T) {
static if (is(T == byte)) alias ubyte unsigned;
else static if (is(T == short)) alias ushort unsigned;
else static if (is(T == int)) alias uint unsigned;
else static if (is(T == long)) alias ulong unsigned;
else static if (is(T == ubyte)) alias ubyte unsigned;
else static if (is(T == ushort)) alias ushort unsigned;
else static if (is(T == uint)) alias uint unsigned;
else static if (is(T == ulong)) alias ulong unsigned;
else static if (is(T == char)) alias char unsigned;
else static if (is(T == wchar)) alias wchar unsigned;
else static if (is(T == dchar)) alias dchar unsigned;
else static if(is(T == enum))
static if (T.sizeof == 1) alias ubyte unsigned;
else static if (T.sizeof == 2) alias ushort unsigned;
else static if (T.sizeof == 4) alias uint unsigned;
else static if (T.sizeof == 8) alias ulong unsigned;
else static assert(false, "Type " ~ T.stringof
~ " does not have an unsigned counterpart");
}
unittest
{
alias unsigned!(int) U;
assert(is(U == uint));
}
/******
* Returns the mutable version of the type T.
*/
template Mutable(T)
{
static if (is(T U == const(U)))
alias U Mutable;
else static if (is(T U == invariant(U)))
alias U Mutable;
else
alias T Mutable;
}