summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2017-08-16 06:45:15 +0200
committerEugen Wissner <belka@caraus.de>2017-08-16 06:45:15 +0200
commite8dd6e321737abd6c0f0542575084e04d5269992 (patch)
tree74d76cea0b8d9384a827ee24fda8b2a5a8ec9863 /source
parent94a7fdbb9117317f63271565a5e20b6df8236068 (diff)
downloadtanya-e8dd6e321737abd6c0f0542575084e04d5269992.tar.gz
Add more traits
Diffstat (limited to 'source')
-rw-r--r--source/tanya/meta/traits.d838
-rw-r--r--source/tanya/meta/transform.d86
2 files changed, 919 insertions, 5 deletions
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));
+}