diff options
Diffstat (limited to 'source/tanya/meta/traits.d')
| -rw-r--r-- | source/tanya/meta/traits.d | 353 |
1 files changed, 325 insertions, 28 deletions
diff --git a/source/tanya/meta/traits.d b/source/tanya/meta/traits.d index f603ea1..a15b5db 100644 --- a/source/tanya/meta/traits.d +++ b/source/tanya/meta/traits.d @@ -17,6 +17,7 @@ */ module tanya.meta.traits; +import tanya.meta.metafunction; import tanya.meta.transform; /** @@ -966,14 +967,13 @@ pure nothrow @safe @nogc unittest * 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. + * + * See_Also: $(D_PSYMBOL isAbstractFunction). */ enum bool isAbstractClass(T) = __traits(isAbstractClass, T); @@ -1004,20 +1004,18 @@ pure nothrow @safe @nogc unittest 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. + * + * See_Also: $(D_PSYMBOL isFinalFunction). */ enum bool isFinalClass(T) = __traits(isFinalClass, T); @@ -1038,20 +1036,15 @@ pure nothrow @safe @nogc unittest /** * 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. + * + * See_Also: $(D_PSYMBOL isAbstractClass). */ -template isAbstractFunction(F...) -if (F.length == 1) -{ - enum bool isAbstractFunction = __traits(isAbstractFunction, F[0]); -} +enum bool isAbstractFunction(alias F) = __traits(isAbstractFunction, F); /// pure nothrow @safe @nogc unittest @@ -1075,26 +1068,20 @@ pure nothrow @safe @nogc unittest 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. + * + * See_Also: $(D_PSYMBOL isFinalClass). */ -template isFinalFunction(F...) -if (F.length == 1) -{ - enum bool isFinalFunction = __traits(isFinalFunction, F[0]); -} +enum bool isFinalFunction(alias F) = __traits(isFinalFunction, F); /// pure nothrow @safe @nogc unittest @@ -1111,7 +1098,6 @@ pure nothrow @safe @nogc unittest static assert(isFinalFunction!(A.finalFunc)); static assert(!isFinalFunction!(A.virtualFunc)); - static assert(!isFinalFunction!int); } /** @@ -1252,7 +1238,7 @@ template isFunction(F...) if (F.length == 1) { static if (is(F[0] == function) - || is(typeof(&F[0]) U == delegate) + || is(typeof(&F[0]) T == delegate) || (is(typeof(&F[0]) T : T*) && is(T == function))) { enum bool isFunction = true; @@ -1348,7 +1334,8 @@ pure nothrow @safe @nogc unittest template isCallable(F...) if (F.length == 1) { - static if (isSomeFunction!F || (is(typeof(F[0].opCall) U) && isFunction!U)) + static if (isSomeFunction!F + || (is(typeof(F[0].opCall)) && isFunction!(F[0].opCall))) { enum bool isCallable = true; } @@ -1384,6 +1371,20 @@ pure nothrow @safe @nogc unittest static assert(!isCallable!I); } +private pure nothrow @safe @nogc unittest +{ + struct S + { + @property int opCall() + { + return 0; + } + } + S s; + static assert(isCallable!S); + static assert(isCallable!s); +} + /** * Params: * T = Aggregate type. @@ -1403,8 +1404,304 @@ pure nothrow @safe @nogc unittest void member2() { } + static int member3; + static void member4() + { + } } static assert(hasMember!(S, "member1")); static assert(hasMember!(S, "member2")); - static assert(!hasMember!(S, "member3")); + static assert(hasMember!(S, "member3")); + static assert(hasMember!(S, "member4")); + static assert(!hasMember!(S, "member6")); +} + +/** + * Params: + * T = Aggregate type. + * member = Symbol name. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM member) is a static method of + * $(D_PARAM T), $(D_KEYWORD false) otherwise. + */ +template hasStaticMember(T, string member) +{ + static if (hasMember!(T, member)) + { + alias Member = Alias!(__traits(getMember, T, member)); + + static if (__traits(isStaticFunction, Member) + || (!isFunction!Member && is(typeof(&Member)))) + { + enum bool hasStaticMember = true; + } + else + { + enum bool hasStaticMember = false; + } + } + else + { + enum bool hasStaticMember = false; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + struct S + { + int member1; + void member2() + { + } + static int member3; + static void member4() + { + } + static void function() member5; + } + static assert(!hasStaticMember!(S, "member1")); + static assert(!hasStaticMember!(S, "member2")); + static assert(hasStaticMember!(S, "member3")); + static assert(hasStaticMember!(S, "member4")); + static assert(hasStaticMember!(S, "member5")); +} + +/** + * Determines whether $(D_PARAM T) is mutable, i.e. has one of the following + * qualifiers or a combination of them: + * + * $(UL + * $(LI $(D_KEYWORD const)) + * $(LI $(D_KEYWORD immutable)) + * $(LI $(D_KEYWORD const)) + * ) + * + * Params: + * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is mutable, + * $(D_KEYWORD false) otherwise. + */ +template isMutable(T) +{ + static if (is(T U == const U) + || is(T U == inout U) + || is(T U == inout const U) + || is(T U == immutable U) + || is(T U == shared const U) + || is(T U == shared inout U) + || is(T U == shared inout const U)) + { + enum bool isMutable = false; + } + else + { + enum bool isMutable = true; + } +} + +/// +pure nothrow @safe @nogc unittest +{ + struct S + { + void method() + { + static assert(isMutable!(typeof(this))); + } + + void method() inout + { + static assert(!isMutable!(typeof(this))); + } + + void immMethod() const + { + static assert(!isMutable!(typeof(this))); + } + void immMethod() immutable + { + static assert(!isMutable!(typeof(this))); + } + } +} + +/** + * POD (Plain Old Data) is a $(D_KEYWORD struct) without constructors, + * destructors and member functions. + * + * Params: + * T = A type. + * + * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a POD type, + * $(D_KEYWORD false) otherwise. + */ +enum bool isPOD(T) = __traits(isPOD, T); + +/// +pure nothrow @safe @nogc unittest +{ + struct S1 + { + void method() + { + } + } + static assert(!isPOD!S1); + + struct S2 + { + void function() val; // Function pointer, not a member function. + } + static assert(isPOD!S2); + + struct S3 + { + this(this) + { + } + } + static assert(!isPOD!S3); +} + +/** + * Params: + * T = $(D_KEYWORD class), $(D_KEYWORD struct) or $(D_KEYWORD union) type. + * + * Returns: $(D_KEYWORD true) if the argument is a nested type which internally + * stores a context pointer, $(D_KEYWORD false) otherwise. + */ +template isNested(T) +if (is(T == class) || is(T == struct) || is(T == union)) +{ + enum bool isNested = __traits(isNested, T); +} + +/// +pure nothrow @safe unittest +{ + static struct S + { + } + static assert(!isNested!S); + + class C + { + void method() + { + } + } + static assert(isNested!C); +} + +/** + * Params: + * T = A function. + * + * Returns $(D_KEYWORD true) if the $(D_PARAM T) is a nested function, + * $(D_KEYWORD false) otherwise. + */ +enum bool isNestedFunction(alias F) = __traits(isNested, F); + +/// +pure nothrow @safe @nogc unittest +{ + void func() + { + void nestedFunc() + { + } + static assert(isNestedFunction!nestedFunc); + } +} + +/** + * Params: + * F = A function. + * + * Returns: Type of the function $(D_PARAM F). + */ +template FunctionTypeOf(F...) +if (F.length == 1 && isCallable!F) +{ + static if ((is(typeof(F[0]) T : T*) && is(T == function)) + || (is(F[0] T : T*) && is(T == function)) + || is(F[0] T == delegate) + || is(typeof(F[0]) T == delegate) + || is(F[0] T == function) + || is(typeof(&F[0]) T == delegate) + || (is(typeof(&F[0]) T : T*) && is(T == function))) + { + alias FunctionTypeOf = T; + } + else + { + alias FunctionTypeOf = FunctionTypeOf!(F[0].opCall); + } +} + +/// +pure nothrow @safe @nogc unittest +{ + static assert(is(FunctionTypeOf!(void function()) == function)); + static assert(is(FunctionTypeOf!(() {}) == function)); +} + +private pure nothrow @safe @nogc unittest +{ + static assert(is(FunctionTypeOf!(void delegate()) == function)); + + static void staticFunc() + { + } + auto functionPointer = &staticFunc; + static assert(is(FunctionTypeOf!staticFunc == function)); + static assert(is(FunctionTypeOf!functionPointer == function)); + + void func() + { + } + auto dg = &func; + static assert(is(FunctionTypeOf!func == function)); + static assert(is(FunctionTypeOf!dg == function)); + + interface I + { + @property int prop(); + } + static assert(is(FunctionTypeOf!(I.prop) == function)); + + struct S + { + void opCall() + { + } + } + class C + { + static void opCall() + { + } + } + S s; + + static assert(is(FunctionTypeOf!s == function)); + static assert(is(FunctionTypeOf!C == function)); + static assert(is(FunctionTypeOf!S == function)); +} + +private pure nothrow @safe @nogc unittest +{ + struct S2 + { + @property int opCall() + { + return 0; + } + } + S2 s2; + static assert(is(FunctionTypeOf!S2 == function)); + static assert(is(FunctionTypeOf!s2 == function)); } |
