diff --git a/source/tanya/meta/traits.d b/source/tanya/meta/traits.d index 6d34e4a..f603ea1 100644 --- a/source/tanya/meta/traits.d +++ b/source/tanya/meta/traits.d @@ -31,6 +31,9 @@ import tanya.meta.transform; * * Params: * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a floating point type, + * $(D_KEYWORD false) otherwise. */ enum bool isFloatingPoint(T) = is(Unqual!(OriginalType!T) == double) || is(Unqual!(OriginalType!T) == float) @@ -65,6 +68,9 @@ pure nothrow @safe @nogc unittest * Params: * T = A type. * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a signed numeric type, + * $(D_KEYWORD false) otherwise. + * * See_Also: $(D_PSYMBOL isUnsigned). */ enum bool isSigned(T) = is(Unqual!(OriginalType!T) == byte) @@ -104,6 +110,9 @@ pure nothrow @safe @nogc unittest * Params: * T = A type. * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an unsigned numeric type, + * $(D_KEYWORD false) otherwise. + * * See_Also: $(D_PSYMBOL isSigned). */ enum bool isUnsigned(T) = is(Unqual!(OriginalType!T) == ubyte) @@ -145,6 +154,9 @@ pure nothrow @safe @nogc unittest * * Params: * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an integral type, + * $(D_KEYWORD false) otherwise. */ enum bool isIntegral(T) = isUnsigned!T || is(Unqual!(OriginalType!T) == byte) @@ -175,6 +187,9 @@ pure nothrow @safe @nogc unittest * * Params: * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a complex type, + * $(D_KEYWORD false) otherwise. */ enum bool isComplex(T) = is(Unqual!(OriginalType!T) == cfloat) || is(Unqual!(OriginalType!T) == ifloat) @@ -205,6 +220,9 @@ pure nothrow @safe @nogc unittest * Params: * T = A type. * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a numeric type, + * $(D_KEYWORD false) otherwise. + * * See_Also: $(D_PSYMBOL isIntegral!T), * $(D_PSYMBOL isFloatingPoint), * $(D_PSYMBOL isComplex). @@ -226,6 +244,9 @@ pure nothrow @safe @nogc unittest * * Params: * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a boolean type, + * $(D_KEYWORD false) otherwise. */ enum bool isBoolean(T) = is(Unqual!(OriginalType!T) == bool); @@ -274,6 +295,9 @@ pure nothrow @safe @nogc unittest * * Params: * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a character type, + * $(D_KEYWORD false) otherwise. */ enum bool isSomeChar(T) = is(Unqual!(OriginalType!T) == char) || is(Unqual!(OriginalType!T) == wchar) @@ -302,6 +326,9 @@ pure nothrow @safe @nogc unittest * Params: * T = A type. * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a scalar type, + * $(D_KEYWORD false) otherwise. + * * See_Also: $(D_PSYMBOL isNumeric), * $(D_PSYMBOL isBoolean), * $(D_PSYMBOL isSomeChar). @@ -323,6 +350,9 @@ pure nothrow @safe @nogc unittest * Params: * T = A type. * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a basic type, + * $(D_KEYWORD false) otherwise. + * * See_Also: $(D_PSYMBOL isScalarType). */ enum bool isBasicType(T) = isScalarType!T || is(T : void); @@ -350,6 +380,9 @@ pure nothrow @safe @nogc unittest * * Params: * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a pointer type, + * $(D_KEYWORD false) otherwise. */ template isPointer(T) { @@ -379,6 +412,9 @@ pure nothrow @safe @nogc unittest * Params: * T = A type. * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an array type, + * $(D_KEYWORD false) otherwise. + * * See_Also: $(D_PSYMBOL isAssociativeArray). */ template isArray(T) @@ -405,11 +441,14 @@ pure nothrow @safe @nogc unittest } /** - * Determines whether $(D_PARAM T) is a static array. + * Determines whether $(D_PARAM T) is a static array type. * * Params: * T = A type. * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a static array type, + * $(D_KEYWORD false) otherwise. + * * See_Also: $(D_PSYMBOL isArray). */ template isStaticArray(T) @@ -436,11 +475,14 @@ pure nothrow @safe @nogc unittest } /** - * Determines whether $(D_PARAM T) is a dynamic array. + * Determines whether $(D_PARAM T) is a dynamic array type. * * Params: * T = A type. * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a dynamic array type, + * $(D_KEYWORD false) otherwise. + * * See_Also: $(D_PSYMBOL isArray). */ enum bool isDynamicArray(T) = isArray!T && !isStaticArray!T; @@ -457,11 +499,14 @@ pure nothrow @safe @nogc unittest } /** - * Determines whether $(D_PARAM T) is an associative array. + * Determines whether $(D_PARAM T) is an associative array type. * * Params: * T = A type. * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an associative array type, + * $(D_KEYWORD false) otherwise. + * * See_Also: $(D_PSYMBOL isArray). */ template isAssociativeArray(T) @@ -495,6 +540,9 @@ pure nothrow @safe @nogc unittest * Params: * T = A type. * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a built-in type, + * $(D_KEYWORD false) otherwise. + * * See_Also: $(D_PSYMBOL isBasicType!T), * $(D_PSYMBOL isArray), * $(D_PSYMBOL isAssociativeArray). @@ -526,6 +574,9 @@ pure nothrow @safe @nogc unittest * * Params: * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an aggregate type, + * $(D_KEYWORD false) otherwise. */ enum bool isAggregateType(T) = is(T == struct) || is(T == class) @@ -553,7 +604,10 @@ pure nothrow @safe @nogc unittest * Determines whether $(D_PARAM T) is some type. * * Params: - * T = Some symbol. + * T = A symbol. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a type, + * $(D_KEYWORD false) otherwise. */ enum bool isType(alias T) = is(T); @@ -578,3 +632,779 @@ pure nothrow @safe @nogc unittest static assert(!isType!5); static assert(!isType!(tanya.meta.traits)); } + +/** + * Determines whether $(D_PARAM T) is a narrow string, i.e. consists of + * $(D_KEYWORD char) or $(D_KEYWORD wchar). + * + * The character type of the string can be qualified with $(D_KEYWORD const), + * $(D_KEYWORD immutable) or $(D_KEYWORD inout), but an occurrence of + * $(D_KEYWORD shared) in the character type results in returning + * $(D_KEYWORD false). + * The string itself (in contrast to its character type) can have any type + * qualifiers. + * + * Static $(D_KEYWORD char) and $(D_KEYWORD wchar) arrays are not considered + * strings. + * + * Params: + * T = A Type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a narrow string, + * $(D_KEYWORD false) otherwise. + * + * See_Also: $(D_PSYMBOL isWideString). + */ +enum bool isNarrowString(T) = (is(T : const char[]) || is (T : const wchar[])) + && !isStaticArray!T; + +/// +pure nothrow @safe @nogc unittest +{ + static assert(isNarrowString!(char[])); + static assert(isNarrowString!(wchar[])); + static assert(!isNarrowString!(dchar[])); + + static assert(isNarrowString!string); + static assert(isNarrowString!wstring); + static assert(!isNarrowString!dstring); + + static assert(isNarrowString!(const string)); + static assert(isNarrowString!(const wstring)); + static assert(!isNarrowString!(const dstring)); + + static assert(isNarrowString!(shared string)); + static assert(isNarrowString!(shared wstring)); + static assert(!isNarrowString!(shared dstring)); + + static assert(isNarrowString!(const(char)[])); + static assert(isNarrowString!(inout(char)[])); + static assert(!isNarrowString!(shared(const(char))[])); + static assert(!isNarrowString!(shared(char)[])); + static assert(!isNarrowString!(char[10])); +} + +/** + * Determines whether $(D_PARAM T) is a wide string, i.e. consists of + * $(D_KEYWORD dchar). + * + * The character type of the string can be qualified with $(D_KEYWORD const), + * $(D_KEYWORD immutable) or $(D_KEYWORD inout), but an occurrence of + * $(D_KEYWORD shared) in the character type results in returning + * $(D_KEYWORD false). + * The string itself (in contrast to its character type) can have any type + * qualifiers. + * + * Static $(D_KEYWORD char) and $(D_KEYWORD wchar) arrays are not considered + * strings. + * + * Params: + * T = A Type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a wide string, + * $(D_KEYWORD false) otherwise. + * + * See_Also: $(D_PSYMBOL isNarrowString). + */ +enum bool isWideString(T) = is(T : const dchar[]) && !isStaticArray!T; + +/// +pure nothrow @safe @nogc unittest +{ + static assert(isWideString!(dchar[])); + static assert(!isWideString!(char[])); + static assert(!isWideString!(wchar[])); + + static assert(isWideString!dstring); + static assert(!isWideString!string); + static assert(!isWideString!wstring); + + static assert(isWideString!(const dstring)); + static assert(!isWideString!(const string)); + static assert(!isWideString!(const wstring)); + + static assert(isWideString!(shared dstring)); + static assert(!isWideString!(shared string)); + static assert(!isWideString!(shared wstring)); + + static assert(isWideString!(const(dchar)[])); + static assert(isWideString!(inout(dchar)[])); + static assert(!isWideString!(shared(const(dchar))[])); + static assert(!isWideString!(shared(dchar)[])); + static assert(!isWideString!(dchar[10])); +} + +/** + * Determines whether $(D_PARAM T) is a string, i.e. consists of + * $(D_KEYWORD char), $(D_KEYWORD wchar) or $(D_KEYWORD dchar). + * + * The character type of the string can be qualified with $(D_KEYWORD const), + * $(D_KEYWORD immutable) or $(D_KEYWORD inout), but an occurrence of + * $(D_KEYWORD shared) in the character type results in returning + * $(D_KEYWORD false). + * The string itself (in contrast to its character type) can have any type + * qualifiers. + * + * Static character arrays are not considered strings. + * + * Params: + * T = A Type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a string, + * $(D_KEYWORD false) otherwise. + * + * See_Also: $(D_PSYMBOL isNarrowString), $(D_PSYMBOL isWideString). + */ +enum bool isSomeString(T) = isNarrowString!T || isWideString!T; + +/// +pure nothrow @safe @nogc unittest +{ + static assert(isSomeString!(dchar[])); + static assert(isSomeString!(char[])); + static assert(isSomeString!(wchar[])); + + static assert(isSomeString!dstring); + static assert(isSomeString!string); + static assert(isSomeString!wstring); + + static assert(isSomeString!(const dstring)); + static assert(isSomeString!(const string)); + static assert(isSomeString!(const wstring)); + + static assert(isSomeString!(shared dstring)); + static assert(isSomeString!(shared string)); + static assert(isSomeString!(shared wstring)); + + static assert(isSomeString!(const(char)[])); + static assert(isSomeString!(inout(char)[])); + static assert(!isSomeString!(shared(const(char))[])); + static assert(!isSomeString!(shared(char)[])); + static assert(!isSomeString!(char[10])); +} + +/** + * Returns the minimum value of type $(D_PARAM T). In contrast to + * $(D_INLINECODE T.min) this template works with floating point and complex + * types as well. + * + * Params: + * T = Integral, boolean, floating point, complex or character type. + * + * Returns: The minimum value of $(D_PARAM T). + * + * See_Also: $(D_PSYMBOL isIntegral), + * $(D_PSYMBOL isBoolean), + * $(D_PSYMBOL isSomeChar), + * $(D_PSYMBOL isFloatingPoint), + * $(D_PSYMBOL isComplex). + */ +template mostNegative(T) +{ + static if (isIntegral!T || isBoolean!T || isSomeChar!T) + { + enum T mostNegative = T.min; + } + else static if (isFloatingPoint!T || isComplex!T) + { + enum T mostNegative = -T.max; + } + else + { + static assert(false, T.stringof ~ " doesn't have the minimum value"); + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(mostNegative!char == char.min); + static assert(mostNegative!wchar == wchar.min); + static assert(mostNegative!dchar == dchar.min); + + static assert(mostNegative!byte == byte.min); + static assert(mostNegative!ubyte == ubyte.min); + static assert(mostNegative!bool == bool.min); + + static assert(mostNegative!float == -float.max); + static assert(mostNegative!double == -double.max); + static assert(mostNegative!real == -real.max); + + static assert(mostNegative!ifloat == -ifloat.max); + static assert(mostNegative!cfloat == -cfloat.max); +} + +/** + * Finds the type with the largest size in the $(D_PARAM Args) list. If several + * types have the same type, the leftmost is returned. + * + * Params: + * Args = Type list. + * + * Returns: The largest type. + * + * See_Also: $(D_PSYMBOL Smallest). + */ +template Largest(Args...) +if (Args.length >= 1) +{ + static assert(is(Args[0]), T.stringof ~ " doesn't have .sizeof property"); + + static if (Args.length == 1) + { + alias Largest = Args[0]; + } + else static if (Largest!(Args[1 .. $]).sizeof > Args[0].sizeof) + { + alias Largest = Largest!(Args[1 .. $]); + } + else + { + alias Largest = Args[0]; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(Largest!(int, short, uint) == int)); + static assert(is(Largest!(short) == short)); + static assert(is(Largest!(ubyte[8], ubyte[5]) == ubyte[8])); + static assert(!is(Largest!(short, 5))); +} + +/** + * Finds the type with the smallest size in the $(D_PARAM Args) list. If + * several types have the same type, the leftmost is returned. + * + * Params: + * Args = Type list. + * + * Returns: The smallest type. + * + * See_Also: $(D_PSYMBOL Largest). + */ +template Smallest(Args...) +if (Args.length >= 1) +{ + static assert(is(Args[0]), T.stringof ~ " doesn't have .sizeof property"); + + static if (Args.length == 1) + { + alias Smallest = Args[0]; + } + else static if (Smallest!(Args[1 .. $]).sizeof < Args[0].sizeof) + { + alias Smallest = Smallest!(Args[1 .. $]); + } + else + { + alias Smallest = Args[0]; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(Smallest!(int, ushort, uint, short) == ushort)); + static assert(is(Smallest!(short) == short)); + static assert(is(Smallest!(ubyte[8], ubyte[5]) == ubyte[5])); + static assert(!is(Smallest!(short, 5))); +} + +/** + * Determines whether the type $(D_PARAM T) is copyable. + * + * Only structs can be not copyable if their postblit constructor or the + * postblit constructor of one of its fields is disabled, i.e. annotated with + * $(D_KEYWORD @disable). + * + * Params: + * T = A type. + * + * Returns: $(D_PARAM true) if $(D_PARAM T) can be copied, + * $(D_PARAM false) otherwise. + */ +enum bool isCopyable(T) = is(typeof({ T s1 = T.init; T s2 = s1; })); + +/// +pure nothrow @safe @nogc unittest +{ + struct S1 + { + } + struct S2 + { + this(this) + { + } + } + struct S3 + { + @disable this(this); + } + struct S4 + { + S3 s; + } + class C + { + } + + static assert(isCopyable!S1); + static assert(isCopyable!S2); + static assert(!isCopyable!S3); + static assert(!isCopyable!S4); + + static assert(isCopyable!C); + static assert(isCopyable!bool); +} + +/** + * Determines whether $(D_PARAM T) is an abstract class. + * + * Abstract class is a class marked as such or a class that has any abstract + * methods or doesn't implement all methods of abstract base classes. + * + * For all non-classes $(D_INLINECODE isAbstractClass!T) evaluates to + * $(D_KEYWORD false). + * + * Params: + * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is an abstract class, + * $(D_KEYWORD false) otherwise. + */ +enum bool isAbstractClass(T) = __traits(isAbstractClass, T); + +/// +pure nothrow @safe @nogc unittest +{ + class A + { + } + abstract class B + { + } + class C + { + abstract void func(); + } + class D : C + { + } + class E : C + { + override void func() + { + } + } + static assert(!isAbstractClass!A); + static assert(isAbstractClass!B); + static assert(isAbstractClass!C); + static assert(isAbstractClass!D); + static assert(!isAbstractClass!E); + static assert(!isAbstractClass!int); +} + +/** + * Determines whether $(D_PARAM T) is a final class. + * + * For all non-classes $(D_INLINECODE isFinalClass!T) evaluates to + * $(D_KEYWORD false). + * + * Params: + * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a final class, + * $(D_KEYWORD false) otherwise. + */ +enum bool isFinalClass(T) = __traits(isFinalClass, T); + +/// +pure nothrow @safe @nogc unittest +{ + final class A + { + } + class B + { + } + + static assert(isFinalClass!A); + static assert(!isFinalClass!B); +} + +/** + * Determines whether $(D_PARAM T) is an abstract method. + * + * For all non-methods $(D_INLINECODE isAbstractFunction!T) evaluates to + * $(D_KEYWORD false). + * + * Params: + * F = A symbol. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM F) is an abstract method, + * $(D_KEYWORD false) otherwise. + */ +template isAbstractFunction(F...) +if (F.length == 1) +{ + enum bool isAbstractFunction = __traits(isAbstractFunction, F[0]); +} + +/// +pure nothrow @safe @nogc unittest +{ + class A + { + void func() + { + } + } + class B + { + abstract void func(); + } + class C : B + { + override void func() + { + } + } + static assert(!isAbstractFunction!(A.func)); + static assert(isAbstractFunction!(B.func)); + static assert(!isAbstractFunction!(C.func)); + static assert(!isAbstractFunction!int); +} + +/** + * Determines whether $(D_PARAM T) is a final method. + * + * For all non-methods $(D_INLINECODE isFinalFunction!T) evaluates to + * $(D_KEYWORD false). + * + * Params: + * F = A symbol. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM F) is a final method, + * $(D_KEYWORD false) otherwise. + */ +template isFinalFunction(F...) +if (F.length == 1) +{ + enum bool isFinalFunction = __traits(isFinalFunction, F[0]); +} + +/// +pure nothrow @safe @nogc unittest +{ + class A + { + void virtualFunc() + { + } + final void finalFunc() + { + } + } + + static assert(isFinalFunction!(A.finalFunc)); + static assert(!isFinalFunction!(A.virtualFunc)); + static assert(!isFinalFunction!int); +} + +/** + * Function pointer is a pointer to a function. So a simple function is not + * a function pointer, but getting the address of such function returns a + * function pointer. + * + * A function pointer doesn't save the context pointer, thus cannot have access + * to its outer scope. + * + * Params: + * F = A symbol. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM F) is a function pointer, + * $(D_KEYWORD false) otherwise. + * + * See_Also: $(LINK2 http://dlang.org/spec/function.html#closures, + * Delegates, Function Pointers, and Closures). + */ +template isFunctionPointer(F...) +if (F.length == 1) +{ + static if ((is(typeof(F[0]) T : T*) && is(T == function)) + || (is(F[0] T : T*) && is(T == function))) + { + enum bool isFunctionPointer = true; + } + else + { + enum bool isFunctionPointer = false; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(isFunctionPointer!(void function())); + static assert(!isFunctionPointer!(void delegate())); + + static assert(isFunctionPointer!(() {})); + + void func() + { + } + static void staticFunc() + { + } + interface I + { + @property int prop(); + } + + static assert(!isFunctionPointer!func); + static assert(!isFunctionPointer!staticFunc); + + auto functionPointer = &staticFunc; + auto dg = &func; + + static assert(isFunctionPointer!functionPointer); + static assert(!isFunctionPointer!dg); + + static assert(!isFunctionPointer!(I.prop)); +} + +/** + * Delegate stores the function pointer and function context. + * + * Params: + * F = A symbol. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM F) is a delegate, + * $(D_KEYWORD false) delegate. + * + * See_Also: $(LINK2 http://dlang.org/spec/function.html#closures, + * Delegates, Function Pointers, and Closures). + */ +template isDelegate(F...) +if (F.length == 1) +{ + static if (is(F[0] == delegate) + || is(typeof(F[0]) == delegate)) + { + enum bool isDelegate = true; + } + else + { + enum bool isDelegate = false; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(isDelegate!(void delegate())); + static assert(!isDelegate!(void function())); + + static assert(!isDelegate!(() {})); + + void func() + { + } + static void staticFunc() + { + } + interface I + { + @property int prop(); + } + + static assert(!isDelegate!func); + static assert(!isDelegate!staticFunc); + + auto functionPointer = &staticFunc; + auto dg = &func; + + static assert(!isDelegate!functionPointer); + static assert(isDelegate!dg); + + static assert(!isDelegate!(I.prop)); +} + +/** + * $(D_PSYMBOL isFunction) returns $(D_KEYWORD true) only for plain functions, + * not function pointers or delegates. Use $(D_PSYMBOL isFunctionPointer) or + * $(D_PSYMBOL isDelegate) to detect them or $(D_PSYMBOL isSomeFunction) + * for detecting a function of any type. + * + * Params: + * F = A symbol. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM F) is a function, + * $(D_KEYWORD false) otherwise. + * + * See_Also: $(LINK2 http://dlang.org/spec/function.html#closures, + * Delegates, Function Pointers, and Closures). + */ +template isFunction(F...) +if (F.length == 1) +{ + static if (is(F[0] == function) + || is(typeof(&F[0]) U == delegate) + || (is(typeof(&F[0]) T : T*) && is(T == function))) + { + enum bool isFunction = true; + } + else + { + enum bool isFunction = false; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(!isFunction!(void function())); + static assert(!isFunction!(() {})); + static assert(!isFunction!(void delegate())); + + void func() + { + } + static void staticFunc() + { + } + interface I + { + @property int prop(); + } + + static assert(isFunction!func); + static assert(isFunction!staticFunc); + + auto functionPointer = &staticFunc; + auto dg = &func; + + static assert(!isFunction!functionPointer); + static assert(!isFunction!dg); + + static assert(isFunction!(I.prop)); +} + +/** + * Params: + * F = A symbol. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM F) is a function, function pointer + * or delegate, $(D_KEYWORD false) otherwise. + * + * See_Also: $(D_PSYMBOL isFunction), + * $(D_PSYMBOL isDelegate), + * $(D_PSYMBOL isFunctionPointer). + */ +template isSomeFunction(F...) +if (F.length == 1) +{ + enum bool isSomeFunction = isFunctionPointer!F + || isFunction!F + || isDelegate!F; +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(isSomeFunction!(void function())); + static assert(isSomeFunction!(() {})); + static assert(isSomeFunction!(void delegate())); + + void func() + { + } + static void staticFunc() + { + } + + static assert(isSomeFunction!func); + static assert(isSomeFunction!staticFunc); + + auto functionPointer = &staticFunc; + auto dg = &func; + + static assert(isSomeFunction!functionPointer); + static assert(isSomeFunction!dg); + + static assert(!isSomeFunction!int); +} + +/** + * Params: + * F = A symbol. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM F) is callable, + * $(D_KEYWORD false) otherwise. + */ +template isCallable(F...) +if (F.length == 1) +{ + static if (isSomeFunction!F || (is(typeof(F[0].opCall) U) && isFunction!U)) + { + enum bool isCallable = true; + } + else + { + enum bool isCallable = false; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + struct S + { + void opCall() + { + } + } + class C + { + static void opCall() + { + } + } + interface I + { + } + S s; + + static assert(isCallable!s); + static assert(isCallable!C); + static assert(isCallable!S); + static assert(!isCallable!I); +} + +/** + * Params: + * T = Aggregate type. + * member = Symbol name. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) defines a symbol + * $(D_PARAM member), $(D_KEYWORD false) otherwise. + */ +enum bool hasMember(T, string member) = __traits(hasMember, T, member); + +/// +pure nothrow @safe @nogc unittest +{ + struct S + { + int member1; + void member2() + { + } + } + static assert(hasMember!(S, "member1")); + static assert(hasMember!(S, "member2")); + static assert(!hasMember!(S, "member3")); +} diff --git a/source/tanya/meta/transform.d b/source/tanya/meta/transform.d index 84615f7..bdefd4e 100644 --- a/source/tanya/meta/transform.d +++ b/source/tanya/meta/transform.d @@ -373,12 +373,15 @@ pure nothrow @safe @nogc unittest * Returns: Pointer target type. */ template PointerTarget(T) -if (isPointer!T) { static if (is(T U : U*)) { alias PointerTarget = U; } + else + { + static assert(T.stringof ~ " isn't a pointer type"); + } } /// @@ -389,3 +392,84 @@ pure nothrow @safe @nogc unittest static assert(is(PointerTarget!(const shared bool*) == const shared bool)); static assert(!is(PointerTarget!bool)); } + +/** + * Params: + * T = The type of the associative array. + * + * Returns: The key type of the associative array $(D_PARAM T). + */ +template KeyType(T) +{ + static if (is(T V : V[K], K)) + { + alias KeyType = K; + } + else + { + static assert(false, T.stringof ~ " isn't an associative array"); + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(KeyType!(int[string]) == string)); + static assert(!is(KeyType!(int[15]))); +} + +/** + * Params: + * T = The type of the associative array. + * + * Returns: The value type of the associative array $(D_PARAM T). + */ +template ValueType(T) +{ + static if (is(T V : V[K], K)) + { + alias ValueType = V; + } + else + { + static assert(false, T.stringof ~ " isn't an associative array"); + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(ValueType!(int[string]) == int)); + static assert(!is(ValueType!(int[15]))); +} + +/** + * Params: + * T = Scalar type. + * + * Returns: The type $(D_PARAM T) will promote to. + * + * See_Also: $(LINK2 https://dlang.org/spec/type.html#integer-promotions, + * Integer Promotions). + */ +template Promoted(T) +if (isScalarType!T) +{ + alias Promoted = CopyTypeQualifiers!(T, typeof(T.init + T.init)); +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(Promoted!bool == int)); + static assert(is(Promoted!byte == int)); + static assert(is(Promoted!ubyte == int)); + static assert(is(Promoted!short == int)); + static assert(is(Promoted!ushort == int)); + static assert(is(Promoted!char == int)); + static assert(is(Promoted!wchar == int)); + static assert(is(Promoted!dchar == uint)); + + static assert(is(Promoted!(const bool) == const int)); + static assert(is(Promoted!(shared bool) == shared int)); +}