diff --git a/source/tanya/meta/transform.d b/source/tanya/meta/transform.d index bec52c8..84615f7 100644 --- a/source/tanya/meta/transform.d +++ b/source/tanya/meta/transform.d @@ -5,7 +5,8 @@ /** * Type transformations. * - * Templates in this module applied to a type produce a transformed type. + * Templates in this module can be used to modify type qualifiers or transform + * types. * * Copyright: Eugene Wissner 2017. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, @@ -16,6 +17,8 @@ */ module tanya.meta.transform; +import tanya.meta.traits; + /** * Removes any type qualifiers from $(D_PARAM T). * @@ -33,6 +36,8 @@ module tanya.meta.transform; * * Params: * T = A type. + * + * Returns: $(D_PARAM T) without any type qualifiers. */ template Unqual(T) { @@ -66,11 +71,15 @@ pure nothrow @safe @nogc unittest } /** - * If $(D_PARAM T) is an $(D_KEYWORD enum), $(D_INLINECODE OriginalType!T) evaluates to the - * most base type of that $(D_KEYWORD enum) and to $(D_PARAM T) otherwise. + * If $(D_PARAM T) is an $(D_KEYWORD enum), $(D_INLINECODE OriginalType!T) + * evaluates to the most base type of that $(D_KEYWORD enum) and to + * $(D_PARAM T) otherwise. * * Params: * T = A type. + * + * Returns: Base type of the $(D_KEYWORD enum) $(D_PARAM T) or $(D_PARAM T) + * itself. */ template OriginalType(T) { @@ -110,3 +119,273 @@ pure nothrow @safe @nogc unittest static assert(is(OriginalType!E4 == bool)); static assert(is(OriginalType!(const E4) == bool)); } + +/** + * Copies constness of $(D_PARAM From) to $(D_PARAM To). + * + * The following type qualifiers affect the constness and hence are copied: + * $(UL + * $(LI const) + * $(LI immutable) + * $(LI inout) + * $(LI inout const) + * ) + * + * Params: + * From = Source type. + * To = Target type. + * + * Returns: $(D_PARAM To) with the constness of $(D_PARAM From). + * + * See_Also: $(D_PSYMBOL CopyTypeQualifiers). + */ +template CopyConstness(From, To) +{ + static if (is(From T == immutable T)) + { + alias CopyConstness = immutable To; + } + else static if (is(From T == const T) || is(From T == shared const T)) + { + alias CopyConstness = const To; + } + else static if (is(From T == inout T) || is(From T == shared inout T)) + { + alias CopyConstness = inout To; + } + else static if (is(From T == inout const T) + || is(From T == shared inout const T)) + { + alias CopyConstness = inout const To; + } + else + { + alias CopyConstness = To; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(CopyConstness!(int, char) == char)); + static assert(is(CopyConstness!(const int, char) == const char)); + static assert(is(CopyConstness!(immutable int, char) == immutable char)); + static assert(is(CopyConstness!(inout int, char) == inout char)); + static assert(is(CopyConstness!(inout const int, char) == inout const char)); + + static assert(is(CopyConstness!(shared int, char) == char)); + static assert(is(CopyConstness!(shared const int, char) == const char)); + static assert(is(CopyConstness!(shared inout int, char) == inout char)); + static assert(is(CopyConstness!(shared inout const int, char) == inout const char)); + + static assert(is(CopyConstness!(const int, shared char) == shared const char)); + static assert(is(CopyConstness!(const int, immutable char) == immutable char)); + static assert(is(CopyConstness!(immutable int, const char) == immutable char)); +} + +/** + * Copies type qualifiers of $(D_PARAM From) to $(D_PARAM To). + * + * Type qualifiers copied are: + * $(UL + * $(LI const) + * $(LI immutable) + * $(LI inout) + * $(LI shared) + * ) + * and combinations of these. + * + * Params: + * From = Source type. + * To = Target type. + * + * Returns: $(D_PARAM To) with the type qualifiers of $(D_PARAM From). + * + * See_Also: $(D_PSYMBOL CopyConstness). + */ +template CopyTypeQualifiers(From, To) +{ + static if (is(From T == immutable T)) + { + alias CopyTypeQualifiers = immutable To; + } + else static if (is(From T == const T)) + { + alias CopyTypeQualifiers = const To; + } + else static if (is(From T == shared T)) + { + alias CopyTypeQualifiers = shared To; + } + else static if (is(From T == shared const T)) + { + alias CopyTypeQualifiers = shared const To; + } + else static if (is(From T == inout T)) + { + alias CopyTypeQualifiers = inout To; + } + else static if (is(From T == shared inout T)) + { + alias CopyTypeQualifiers = shared inout To; + } + else static if (is(From T == inout const T)) + { + alias CopyTypeQualifiers = inout const To; + } + else static if (is(From T == shared inout const T)) + { + alias CopyTypeQualifiers = shared inout const To; + } + else + { + alias CopyTypeQualifiers = To; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(CopyTypeQualifiers!(int, char) == char)); + static assert(is(CopyTypeQualifiers!(const int, char) == const char)); + static assert(is(CopyTypeQualifiers!(immutable int, char) == immutable char)); + static assert(is(CopyTypeQualifiers!(inout int, char) == inout char)); + static assert(is(CopyTypeQualifiers!(inout const int, char) == inout const char)); + + static assert(is(CopyTypeQualifiers!(shared int, char) == shared char)); + static assert(is(CopyTypeQualifiers!(shared const int, char) == shared const char)); + static assert(is(CopyTypeQualifiers!(shared inout int, char) == shared inout char)); + static assert(is(CopyTypeQualifiers!(shared inout const int, char) == shared inout const char)); +} + +/** + * Evaluates to the unsigned counterpart of the integral type $(D_PARAM T) preserving all type qualifiers. + * If $(D_PARAM T) is already unsigned, $(D_INLINECODE Unsigned!T) aliases $(D_PARAM T). + * + * Params: + * T = A type. + * + * Returns: Unsigned counterpart of $(D_PARAM T). + * + * See_Also: $(D_PSYMBOL isSigned). + */ +template Unsigned(T) +if (isIntegral!T) +{ + alias UnqualedType = Unqual!(OriginalType!T); + static if (is(UnqualedType == byte)) + { + alias Unsigned = CopyTypeQualifiers!(T, ubyte); + } + else static if (is(UnqualedType == short)) + { + alias Unsigned = CopyTypeQualifiers!(T, ushort); + } + else static if (is(UnqualedType == int)) + { + alias Unsigned = CopyTypeQualifiers!(T, uint); + } + else static if (is(UnqualedType == long)) + { + alias Unsigned = CopyTypeQualifiers!(T, ulong); + } + else + { + alias Unsigned = T; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(Unsigned!byte == ubyte)); + static assert(is(Unsigned!short == ushort)); + static assert(is(Unsigned!int == uint)); + static assert(is(Unsigned!long == ulong)); + + static assert(is(Unsigned!(const byte) == const ubyte)); + static assert(is(Unsigned!(shared byte) == shared ubyte)); + static assert(is(Unsigned!(shared const byte) == shared const ubyte)); + + static assert(!is(Unsigned!float)); + static assert(is(Unsigned!ubyte == ubyte)); +} + +/** + * Evaluates to the signed counterpart of the integral type $(D_PARAM T) preserving all type qualifiers. + * If $(D_PARAM T) is already signed, $(D_INLINECODE Signed!T) aliases $(D_PARAM T). + * + * Params: + * T = A type. + * + * Returns: Signed counterpart of $(D_PARAM T). + * + * See_Also: $(D_PSYMBOL isUnsigned). + */ +template Signed(T) +if (isIntegral!T) +{ + alias UnqualedType = Unqual!(OriginalType!T); + static if (is(UnqualedType == ubyte)) + { + alias Signed = CopyTypeQualifiers!(T, byte); + } + else static if (is(UnqualedType == ushort)) + { + alias Signed = CopyTypeQualifiers!(T, short); + } + else static if (is(UnqualedType == uint)) + { + alias Signed = CopyTypeQualifiers!(T, int); + } + else static if (is(UnqualedType == ulong)) + { + alias Signed = CopyTypeQualifiers!(T, long); + } + else + { + alias Signed = T; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(Signed!ubyte == byte)); + static assert(is(Signed!ushort == short)); + static assert(is(Signed!uint == int)); + static assert(is(Signed!ulong == long)); + + static assert(is(Signed!(const ubyte) == const byte)); + static assert(is(Signed!(shared ubyte) == shared byte)); + static assert(is(Signed!(shared const ubyte) == shared const byte)); + + static assert(!is(Signed!float)); + static assert(is(Signed!byte == byte)); +} + +/** + * Retrieves the target type `U` of a pointer `U*`. + * + * Params: + * T = Pointer type. + * + * Returns: Pointer target type. + */ +template PointerTarget(T) +if (isPointer!T) +{ + static if (is(T U : U*)) + { + alias PointerTarget = U; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(PointerTarget!(bool*) == bool)); + static assert(is(PointerTarget!(const bool*) == const bool)); + static assert(is(PointerTarget!(const shared bool*) == const shared bool)); + static assert(!is(PointerTarget!bool)); +}