| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603 | /** * The traits module defines tools useful for obtaining detailed compile-time * information about a type. Please note that the mixed naming scheme used in * this module is intentional. Templates which evaluate to a type follow the * naming convention used for types, and templates which evaluate to a value * follow the naming convention used for functions. * * Copyright: Copyright (C) 2005-2006 Sean Kelly. All rights reserved. * License: BSD style: $(LICENSE) * Authors: Sean Kelly, Fawzi Mohamed, Abscissa */ module tango.core.Traits; /** * Strips the qualifiers from a type */ template BaseTypeOf( T ) { static if (is(T S : shared(S))) alias S BaseTypeOf; else static if (is(T S : shared(const(S)))) alias S BaseTypeOf; else static if (is(T S : const(S))) alias S BaseTypeOf; else alias T BaseTypeOf; } /** * Computes the effective type that inout would have if you have it two parameters of difference constness */ template InoutTypeOf(T, M) { static assert(is(BaseTypeOf!(T) == BaseTypeOf!(M))); static if (is(immutable(BaseTypeOf!(T)) == T) && is(immutable(BaseTypeOf!(T)) == M)) alias immutable(BaseTypeOf!(T)) InoutTypeOf; else static if ((is(BaseTypeOf!(T) == T) && is(BaseTypeOf!(T) == M))) alias BaseTypeOf!(T) InoutTypeOf; else alias const(BaseTypeOf!(T)) InoutTypeOf; } /** * Evaluates to true if T is char[], wchar[], or dchar[]. */ template isStringType( T ) { const bool isStringType = is( T : const(char)[] ) || is( T : const(wchar)[] ) || is( T : const(dchar)[] ); } /** * Evaluates to true if T is char, wchar, or dchar. */ template isCharType( T ) { const bool isCharType = is( BaseTypeOf!(T) == char ) || is( BaseTypeOf!(T) == wchar ) || is( BaseTypeOf!(T) == dchar ); } /** * Evaluates to true if T is a signed integer type. */ template isSignedIntegerType( T ) { const bool isSignedIntegerType = is( BaseTypeOf!(T) == byte ) || is( BaseTypeOf!(T) == short ) || is( BaseTypeOf!(T) == int ) || is( BaseTypeOf!(T) == long )/+|| is( T == cent )+/; } /** * Evaluates to true if T is an unsigned integer type. */ template isUnsignedIntegerType( T ) { const bool isUnsignedIntegerType = is( BaseTypeOf!(T) == ubyte ) || is( BaseTypeOf!(T) == ushort ) || is( BaseTypeOf!(T) == uint ) || is( BaseTypeOf!(T) == ulong )/+|| is( T == ucent )+/; } /** * Evaluates to true if T is a signed or unsigned integer type. */ template isIntegerType( T ) { const bool isIntegerType = isSignedIntegerType!(T) || isUnsignedIntegerType!(T); } /** * Evaluates to true if T is a real floating-point type. */ template isRealType( T ) { const bool isRealType = is( BaseTypeOf!(T) == float ) || is( BaseTypeOf!(T) == double ) || is( BaseTypeOf!(T) == real ); } /** * Evaluates to true if T is a complex floating-point type. */ template isComplexType( T ) { const bool isComplexType = is( BaseTypeOf!(T) == cfloat ) || is( BaseTypeOf!(T) == cdouble ) || is( BaseTypeOf!(T) == creal ); } /** * Evaluates to true if T is an imaginary floating-point type. */ template isImaginaryType( T ) { const bool isImaginaryType = is( T == ifloat ) || is( T == idouble ) || is( T == ireal ); } /** * Evaluates to true if T is any floating-point type: real, complex, or * imaginary. */ template isFloatingPointType( T ) { const bool isFloatingPointType = isRealType!(T) || isComplexType!(T) || isImaginaryType!(T); } /// true if T is an atomic type template isAtomicType(T) { static if( is( T == bool ) || is( T == char ) || is( T == wchar ) || is( T == dchar ) || is( T == byte ) || is( T == short ) || is( T == int ) || is( T == long ) || is( T == ubyte ) || is( T == ushort ) || is( T == uint ) || is( T == ulong ) || is( T == float ) || is( T == double ) || is( T == real ) || is( T == ifloat ) || is( T == idouble ) || is( T == ireal ) ) const isAtomicType = true; else const isAtomicType = false; } /** * complex type for the given type */ template ComplexTypeOf(T){ static if(is(T==float)||is(T==ifloat)||is(T==cfloat)){ alias cfloat ComplexTypeOf; } else static if(is(T==double)|| is(T==idouble)|| is(T==cdouble)){ alias cdouble ComplexTypeOf; } else static if(is(T==real)|| is(T==ireal)|| is(T==creal)){ alias creal ComplexTypeOf; } else static assert(0,"unsupported type in ComplexTypeOf "~T.stringof); } /** * real type for the given type */ template RealTypeOf(T){ static if(is(T==float)|| is(T==ifloat)|| is(T==cfloat)){ alias float RealTypeOf; } else static if(is(T==double)|| is(T==idouble)|| is(T==cdouble)){ alias double RealTypeOf; } else static if(is(T==real)|| is(T==ireal)|| is(T==creal)){ alias real RealTypeOf; } else static assert(0,"unsupported type in RealTypeOf "~T.stringof); } /** * imaginary type for the given type */ template ImaginaryTypeOf(T){ static if(is(T==float)|| is(T==ifloat)|| is(T==cfloat)){ alias ifloat ImaginaryTypeOf; } else static if(is(T==double)|| is(T==idouble)|| is(T==cdouble)){ alias idouble ImaginaryTypeOf; } else static if(is(T==real)|| is(T==ireal)|| is(T==creal)){ alias ireal ImaginaryTypeOf; } else static assert(0,"unsupported type in ImaginaryTypeOf "~T.stringof); } /// type with maximum precision template MaxPrecTypeOf(T){ static if (isComplexType!(T)){ alias creal MaxPrecTypeOf; } else static if (isImaginaryType!(T)){ alias ireal MaxPrecTypeOf; } else { alias real MaxPrecTypeOf; } } /** * Evaluates to true if T is a pointer type. */ template isPointerType(T) { const isPointerType = false; } template isPointerType(T : T*) { const isPointerType = true; } debug( UnitTest ) { unittest { static assert( is(BaseTypeOf!(const(int))==int) ); static assert( is(BaseTypeOf!(immutable(int))==int) ); static assert( is(BaseTypeOf!(shared(int))==int) ); static assert( is(BaseTypeOf!(inout(int))==int) ); static assert( isPointerType!(void*) ); static assert( !isPointerType!(char[]) ); static assert( isPointerType!(char[]*) ); static assert( !isPointerType!(char*[]) ); static assert( isPointerType!(real*) ); static assert( !isPointerType!(uint) ); static assert( is(MaxPrecTypeOf!(float)==real)); static assert( is(MaxPrecTypeOf!(cfloat)==creal)); static assert( is(MaxPrecTypeOf!(ifloat)==ireal)); class Ham { void* a; } static assert( !isPointerType!(Ham) ); union Eggs { void* a; uint b; } static assert( !isPointerType!(Eggs) ); static assert( isPointerType!(Eggs*) ); struct Bacon {} static assert( !isPointerType!(Bacon) ); } } /** * Evaluates to true if T is a a pointer, class, interface, or delegate. */ template isReferenceType( T ) { const bool isReferenceType = isPointerType!(T) || is( T == class ) || is( T == interface ) || is( T == delegate ); } /** * Evaulates to true if T is a dynamic array type. */ template isDynamicArrayType( T ) { const bool isDynamicArrayType = is( typeof(T.init[0])[] == T ); } /** * Evaluates to true if T is a static array type. */ template isStaticArrayType( T : T[U], size_t U ) { const bool isStaticArrayType = true; } template isStaticArrayType( T ) { const bool isStaticArrayType = false; } /// true for array types template isArrayType(T) { static if (is( T U : U[] )) const bool isArrayType=true; else const bool isArrayType=false; } debug( UnitTest ) { unittest { static assert( isStaticArrayType!(char[5][2]) ); static assert( !isDynamicArrayType!(char[5][2]) ); static assert( isArrayType!(char[5][2]) ); static assert( isStaticArrayType!(char[15]) ); static assert( !isStaticArrayType!(char[]) ); static assert( isDynamicArrayType!(char[]) ); static assert( !isDynamicArrayType!(char[15]) ); static assert( isArrayType!(char[15]) ); static assert( isArrayType!(char[]) ); static assert( !isArrayType!(char) ); } } /** * Evaluates to true if T is an associative array type. */ template isAssocArrayType( T ) { const bool isAssocArrayType = is( typeof(T.init.values[0])[typeof(T.init.keys[0])] == T ); } /** * Evaluates to true if T is a function, function pointer, delegate, or * callable object. */ template isCallableType( T ) { const bool isCallableType = is( T == function ) || is( typeof(*T) == function ) || is( T == delegate ) || is( typeof(T.opCall) == function ); } /** * Evaluates to the return type of Fn. Fn is required to be a callable type. */ template ReturnTypeOf( Fn ) { static if( is( Fn Ret == return ) ) alias Ret ReturnTypeOf; else static assert( false, "Argument has no return type." ); } /** * Returns the type that a T would evaluate to in an expression. * Expr is not required to be a callable type */ template ExprTypeOf( Expr ) { static if(isCallableType!( Expr )) alias ReturnTypeOf!( Expr ) ExprTypeOf; else alias Expr ExprTypeOf; } /** * Evaluates to the return type of fn. fn is required to be callable. */ template ReturnTypeOf( alias fn ) { // static if( is( typeof(fn) Base == typedef ) ) // alias ReturnTypeOf!(Base) ReturnTypeOf; // else alias ReturnTypeOf!(typeof(fn)) ReturnTypeOf; } /** * Evaluates to a tuple representing the parameters of Fn. Fn is required to * be a callable type. */ template ParameterTupleOf( Fn ) { static if( is( Fn Params == function ) ) alias Params ParameterTupleOf; else static if( is( Fn Params == delegate ) ) alias ParameterTupleOf!(Params) ParameterTupleOf; else static if( is( Fn Params == Params* ) ) alias ParameterTupleOf!(Params) ParameterTupleOf; else static assert( false, "Argument has no parameters." ); } /** * Evaluates to a tuple representing the parameters of fn. n is required to * be callable. */ template ParameterTupleOf( alias fn ) { // static if( is( typeof(fn) Base == typedef ) ) // alias ParameterTupleOf!(Base) ParameterTupleOf; // else alias ParameterTupleOf!(typeof(fn)) ParameterTupleOf; } /** * Evaluates to a tuple representing the ancestors of T. T is required to be * a class or interface type. */ template BaseTypeTupleOf( T ) { static if( is( T Base == super ) ) alias Base BaseTypeTupleOf; else static assert( false, "Argument is not a class or interface." ); } /** * Strips the []'s off of a type. */ template BaseTypeOfArrays(T) { static if( is( T S : S[]) ) { alias BaseTypeOfArrays!(S) BaseTypeOfArrays; } else { alias T BaseTypeOfArrays; } } /** * strips one [] off a type */ template ElementTypeOfArray(T:T[]) { alias T ElementTypeOfArray; } /** * Count the []'s on an array type */ template rankOfArray(T) { static if(is(T S : S[])) { const uint rankOfArray = 1 + rankOfArray!(S); } else { const uint rankOfArray = 0; } } /// type of the keys of an AA template KeyTypeOfAA(T){ alias typeof(T.init.keys[0]) KeyTypeOfAA; } /// type of the values of an AA template ValTypeOfAA(T){ alias typeof(T.init.values[0]) ValTypeOfAA; } /// returns the size of a static array template staticArraySize(T) { static assert(isStaticArrayType!(T),"staticArraySize needs a static array as type"); static assert(rankOfArray!(T)==1,"implemented only for 1d arrays..."); const size_t staticArraySize=(T).sizeof / typeof(*T.ptr).sizeof; } /// is T is static array returns a dynamic array, otherwise returns T template DynamicArrayType(T) { static if( isStaticArrayType!(T) ) alias typeof(T.dup) DynamicArrayType; else alias T DynamicArrayType; } debug( UnitTest ) { static assert( is(BaseTypeOfArrays!(real[][])==real) ); static assert( is(BaseTypeOfArrays!(real[2][3])==real) ); static assert( is(ElementTypeOfArray!(real[])==real) ); static assert( is(ElementTypeOfArray!(real[][])==real[]) ); static assert( is(ElementTypeOfArray!(real[2][])==real[2]) ); static assert( is(ElementTypeOfArray!(real[2][2])==real[2]) ); static assert( rankOfArray!(real[][])==2 ); static assert( rankOfArray!(real[2][])==2 ); static assert( is(ValTypeOfAA!(char[int])==char)); static assert( is(KeyTypeOfAA!(char[int])==int)); static assert( is(ValTypeOfAA!(char[][int])==char[])); static assert( is(KeyTypeOfAA!(char[][int[]])==const(int)[])); static assert( isAssocArrayType!(char[][int[]])); static assert( !isAssocArrayType!(char[])); static assert( is(DynamicArrayType!(char[2])==DynamicArrayType!(char[]))); static assert( is(DynamicArrayType!(char[2])==char[])); static assert( staticArraySize!(char[2])==2); } // ------- CTFE ------- /// compile time integer to string char [] ctfe_i2a(int i){ char[] digit="0123456789".dup; char[] res="".dup; if (i==0){ return "0".dup; } bool neg=false; if (i<0){ neg=true; i=-i; } while (i>0) { res=digit[i%10]~res; i/=10; } if (neg) return '-'~res; else return res; } /// ditto char [] ctfe_i2a(long i){ char[] digit="0123456789".dup; char[] res="".dup; if (i==0){ return "0".dup; } bool neg=false; if (i<0){ neg=true; i=-i; } while (i>0) { res=digit[cast(size_t)(i%10)]~res; i/=10; } if (neg) return '-'~res; else return res; } /// ditto char [] ctfe_i2a(uint i){ const(char)[] digit="0123456789"; char[] res; if (i==0){ return "0".dup; } bool neg=false; while (i>0) { res=digit[i%10]~res; i/=10; } return res; } /// ditto char [] ctfe_i2a(ulong i){ const(char)[] digit="0123456789"; char[] res; if (i==0){ return "0".dup; } bool neg=false; while (i>0) { res=digit[cast(size_t)(i%10)]~res; i/=10; } return res; } debug( UnitTest ) { unittest { static assert( ctfe_i2a(31)=="31" ); static assert( ctfe_i2a(-31)=="-31" ); static assert( ctfe_i2a(14u)=="14" ); static assert( ctfe_i2a(14L)=="14" ); static assert( ctfe_i2a(14UL)=="14" ); } } |