module tailconst; import std.traits; import std.range; /** * Return the tail-const type for a given type **/ template TailConst( T ) { static if ( is( T U : U[] ) ) { alias const(Unqual!U)[] TailConst; } else static if ( is( T U : U* ) ) { alias const(Unqual!U)* TailConst; } else static if ( is( T.tailconst_t ) ) { alias T.tailconst_t TailConst; } else static assert( false ); } /** * Ditto for tail-mutable **/ template TailMutable( T ) { static if ( is( T U : U[] ) ) { alias Unqual!U[] TailMutable; } else static if ( is( T U : U* ) ) { alias Unqual!U* TailMutable; } else static if ( is( T.tailmutable_t ) ) { alias T.tailmutable_t TailMutable; } else static assert( false ); } /** * Ditto for tail-immutable **/ template TailImmutable( T ) { static if ( is( T U : U[] ) ) { alias immutable(Unqual!U)[] TailImmutable; } else static if ( is( T U : U* ) ) { alias immutable(Unqual!U)* TailImmutable; } else static if ( is( T.tailimmutable_t ) ) { alias T.tailimmutable_t TailImmutable; } else static assert( false ); } unittest { struct test { alias int tailmutable_t; alias double tailconst_t; alias string tailimmutable_t; } assert( is( TailMutable!( int[] ) == int[] ) ); assert( is( TailMutable!( immutable( int[] ) ) == int[] ) ); assert( is( TailMutable!( const(int)[] ) == int[] ) ); assert( is( TailMutable!test == int ) ); assert( is( TailConst!( int[] ) == const(int)[] ) ); assert( is( TailConst!( immutable( int[] ) ) == const(int)[] ) ); assert( is( TailConst!( const(int)[] ) == const(int)[] ) ); assert( is( TailConst!test == double ) ); assert( is( TailImmutable!( int[] ) == immutable(int)[] ) ); assert( is( TailImmutable!( immutable( int[] ) ) == immutable(int)[] ) ); assert( is( TailImmutable!( const(int)[] ) == immutable(int)[] ) ); assert( is( TailImmutable!test == string ) ); } /** * Converts the given parameter to tail const **/ TailConst!T tailconst( T )( T t ) { TailConst!T tmp = t; return tmp; } /** * Converts the given parameter to tail mutable **/ TailMutable!T tailmutable( T )( T t ) { TailMutable!T tmp = t; return tmp; } /** * Converts the given parameter to tail immutable **/ TailImmutable!T tailimmutable( T )( T t ) { TailImmutable!T tmp = t; return tmp; } unittest { struct test( T ) { alias test!(Unqual!T) tailmutable_t; alias test!(const Unqual!T) tailconst_t; alias test!(immutable T) tailimmutable_t; this( tailmutable_t t ) {} this( tailconst_t t ) {} this( tailimmutable_t t ) {} } test!(const int) t; tailmutable( t ); assert( __traits( compiles, { tailconst( [1,2,3] ); } ) ); assert( __traits( compiles, { test!int t; tailconst( t ); } ) ); assert( __traits( compiles, { test!(const int) t; tailconst( t ); } ) ); assert( __traits( compiles, { test!(immutable int) t; tailconst( t ); } ) ); assert( __traits( compiles, { test!int t; tailconst( t ); } ) ); assert( __traits( compiles, { tailmutable( [1,2,3] ); } ) ); assert( __traits( compiles, { test!int t; tailmutable( t ); } ) ); assert( __traits( compiles, { test!(const int) t; tailmutable( t ); } ) ); assert( __traits( compiles, { test!(immutable int) t; tailmutable( t ); } ) ); assert( !__traits( compiles, { tailimmutable( [1,2,3] ); } ) ); assert( __traits( compiles, { test!int t; tailimmutable( t ); } ) ); assert( __traits( compiles, { test!(const int) t; tailimmutable( t ); } ) ); assert( __traits( compiles, { test!(immutable int) t; tailimmutable( t ); } ) ); } /** * Example range implementing what is needed for tail-const. **/ struct SimpleRange( T ) { T innerRange; alias SimpleRange!(TailConst!T) tailconst_t; alias SimpleRange!(TailMutable!T) tailmutable_t; alias SimpleRange!(TailImmutable!T) tailimmutable_t; static if ( !is( T == TailMutable!T ) ) { this( TailImmutable!SimpleRange r ) { innerRange = r.innerRange; } } static if ( !is( T == TailImmutable!T ) ) { this( TailMutable!SimpleRange r ) { innerRange = r.innerRange; } } static if ( !is( T == TailConst!T ) ) { TailConst!SimpleRange get( ) { return tailconst( this ); } alias get this; } this( T t ) { innerRange = t; } auto front( ) { return innerRange.front; } void popFront( ) { innerRange.popFront( ); } bool empty( ) { return innerRange.empty; } SimpleRange save( ) { return this; } } SimpleRange!T simpleRange( T )( T r ) { return SimpleRange!T( r ); } void main( ) { int[] a = [1,2,3]; auto o = simpleRange( a ); TailConst!( typeof( o ) ) c = o; immutable(int)[] b = [4,5,6]; auto p = simpleRange( b ); TailConst!( typeof( p ) ) d = p; }