Last active
June 13, 2019 06:24
-
-
Save 9rnsr/4152297 to your computer and use it in GitHub Desktop.
isType, isFunction, isPropertyFunction, isVariable, isEnum, isFinal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.traits; | |
/** | |
* Detect whether $(D X) is a type or not. | |
*/ | |
template isType(X...) if (X.length == 1) | |
{ | |
enum isType = is(X[0]); | |
} | |
unittest | |
{ | |
struct S { | |
template Test() {} | |
} | |
class C {} | |
interface I {} | |
union U {} | |
static assert( isType!int); | |
static assert( isType!string); | |
static assert( isType!(int[int])); | |
static assert( isType!S); | |
static assert( isType!C); | |
static assert( isType!I); | |
static assert( isType!U); | |
int n; | |
void func(){} | |
static assert(!isType!n); | |
static assert(!isType!func); | |
static assert(!isType!(S.Test)); | |
static assert(!isType!(S.Test!())); | |
static assert(!isType!(std)); | |
static assert(!isType!(std.traits)); | |
} | |
/** | |
* Detect whether symbol or type $(D X) is a function. | |
*/ | |
template isFunction(X...) if (X.length == 1) | |
{ | |
static if (is(typeof(&X[0]) U : U*) && is(U == function) || | |
is(typeof(&X[0]) U == delegate)) | |
{ | |
// x is a (nested) function symbol. | |
enum isFunction = true; | |
} | |
else static if (is(X[0] T)) | |
{ | |
// x is a type. Take the type of it and examine. | |
enum isFunction = is(T == function); | |
} | |
else | |
enum isFunction = false; | |
} | |
/** | |
* Detect whether symbol or type $(D X) is a function. | |
*/ | |
template isPropertyFunction(X...) if (X.length == 1) | |
{ | |
static if (isFunction!(X[0])) | |
{ | |
alias fa = functionAttributes; | |
alias FA = FunctionAttribute; | |
enum isPropertyFunction = (fa!(FunctionTypeOf!(X[0])) & FA.property) != 0; | |
} | |
else | |
enum isPropertyFunction = false; | |
} | |
unittest | |
{ | |
// for (nested) (property) function symbols | |
static void func(){} | |
static @property int prop(){ return 0; } | |
void nested_func(){} | |
@property int nested_prop(){ return 0; } | |
static assert( isFunction!func); | |
static assert( isFunction!prop); | |
static assert( isFunction!nested_func); | |
static assert( isFunction!nested_prop); | |
static assert(!isPropertyFunction!func); | |
static assert( isPropertyFunction!prop); | |
static assert(!isPropertyFunction!nested_func); | |
static assert( isPropertyFunction!nested_prop); | |
// for functino types | |
alias F = typeof(func); | |
alias P = SetFunctionAttributes!(F, "D", FunctionAttribute.property); | |
alias DG = typeof(&nested_func); | |
alias DP = typeof(&nested_prop); | |
static assert( isFunction!F); | |
static assert( isFunction!P); | |
static assert(!isFunction!DG); // DG is delegate type, not function type | |
static assert(!isFunction!DP); // DP is delegate type, not function type | |
static assert(!isPropertyFunction!F); | |
static assert( isPropertyFunction!P); | |
static assert(!isPropertyFunction!DG); | |
static assert(!isPropertyFunction!DP); | |
// other cases | |
int n; | |
struct S {} | |
static assert(!isFunction!int); | |
static assert(!isFunction!void); | |
static assert(!isFunction!n); | |
static assert(!isFunction!S); | |
static assert(!isFunction!std); | |
static assert(!isPropertyFunction!int); | |
static assert(!isPropertyFunction!void); | |
static assert(!isPropertyFunction!n); | |
static assert(!isPropertyFunction!S); | |
static assert(!isPropertyFunction!std); | |
enum E { x = 10 } | |
static assert(!isFunction!(E.x)); | |
static assert(!isPropertyFunction!(E.x)); | |
} | |
/** | |
* Detect whether symbol $(D X) is a run-time variable. | |
*/ | |
template isVariable(X...) if (X.length == 1) | |
{ | |
static if (!is(X[0]) && | |
!is(typeof(X[0]) == void) && | |
!isFunction!(X[0])) | |
{ | |
enum isVariable = | |
is(typeof({ auto ptr = &X[0]; })) | |
|| is(typeof({ enum off = X[0].offsetof; })); | |
} | |
else | |
enum isVariable = false; | |
} | |
/** | |
* Detect whether $(D X) is an enum type, or manifest constant. | |
*/ | |
template isEnum(X...) if (X.length == 1) | |
{ | |
static if (is(X[0] == enum)) | |
{ | |
enum isEnum = true; | |
} | |
else static if (!is(X[0]) && | |
!is(typeof(X[0]) == void) && | |
!isFunction!(X[0])) | |
{ | |
enum isEnum = | |
!is(typeof({ auto ptr = &X[0]; })) | |
&& !is(typeof({ enum off = X[0].offsetof; })); | |
} | |
else | |
enum isEnum = false; | |
} | |
version(unittest) | |
{ | |
// for module variables | |
int mx; | |
immutable int ix = 0; | |
immutable int ix2; static this() { ix2 = 0; } | |
enum int ex = 0; | |
static assert( isVariable!mx); | |
static assert( isVariable!ix); | |
static assert( isVariable!ix2); | |
static assert(!isVariable!ex); | |
static assert(!isEnum!mx); | |
static assert(!isEnum!ix); | |
static assert(!isEnum!ix2); | |
static assert( isEnum!ex); | |
} | |
unittest | |
{ | |
// for local variables | |
int my; | |
immutable int iy = 0; | |
enum int ey = 0; | |
static assert( isVariable!my); | |
static assert( isVariable!iy); | |
static assert(!isVariable!ey); | |
static assert(!isEnum!my); | |
static assert(!isEnum!iy); | |
static assert( isEnum!ey); | |
// for member variables | |
struct S { | |
int mz; | |
immutable int iz = 0; | |
immutable int iz2; this(int) { iz2 = 0; } | |
enum int ez = 0; | |
static int sval; | |
template Test() {} | |
} | |
static assert( isVariable!(S.mz)); | |
static assert( isVariable!(S.iz)); | |
static assert( isVariable!(S.iz2)); | |
static assert(!isVariable!(S.ez)); | |
static assert( isVariable!(S.sval)); | |
static assert(!isEnum!(S.mz)); | |
static assert(!isEnum!(S.iz)); | |
static assert(!isEnum!(S.iz2)); | |
static assert( isEnum!(S.ez)); | |
static assert(!isEnum!(S.sval)); | |
void function() fp; | |
void delegate() dg; | |
static assert( isVariable!(fp)); | |
static assert( isVariable!(dg)); | |
static assert(!isEnum!(fp)); | |
static assert(!isEnum!(dg)); | |
// for function and property function | |
void func(){} | |
@property int prop(){ return 0; } | |
static assert(!isVariable!func); | |
static assert(!isVariable!prop); | |
static assert(!isEnum!func); | |
static assert(!isEnum!prop); | |
// for aggregates | |
class C {} | |
interface I {} | |
union U {} | |
static assert(!isVariable!S); | |
static assert(!isVariable!C); | |
static assert(!isVariable!I); | |
static assert(!isVariable!U); | |
static assert(!isEnum!S); | |
static assert(!isEnum!C); | |
static assert(!isEnum!I); | |
static assert(!isEnum!U); | |
// for other symbols | |
static assert(!isVariable!(std)); // package | |
static assert(!isVariable!(std.traits)); // module | |
static assert(!isVariable!(S.Test)); // template | |
static assert(!isVariable!(S.Test!())); // template instance | |
static assert(!isEnum!(std)); // package | |
static assert(!isEnum!(std.traits)); // module | |
static assert(!isEnum!(S.Test)); // template | |
static assert(!isEnum!(S.Test!())); // template instance | |
enum E { x = 10 } | |
static assert(!isVariable!(E.x)); | |
static assert( isEnum!(E.x)); | |
} | |
unittest | |
{ | |
enum E1 { a, b } | |
enum E2 : string { a = "A", b = "B" } | |
static assert( isEnum!E1); | |
static assert( isEnum!E2); | |
} | |
/** | |
* Detect whether $(D X) is a final function or class or not. | |
*/ | |
template isFinal(X...) if (X.length == 1) | |
{ | |
static if (is(X[0] == class)) | |
{ | |
enum isFinal = __traits(isFinalClass, X[0]); | |
} | |
else static if (isSomeFunction!X) | |
{ | |
enum isFinal = __traits(isFinalFunction, X[0]); | |
} | |
else | |
enum isFinal = false; | |
} | |
unittest | |
{ | |
class C | |
{ | |
void nf() {} | |
static void sf() {} | |
final void ff() {} | |
} | |
final class FC { } | |
static assert(!isFinal!(C)); | |
static assert( isFinal!(FC)); | |
static assert(!isFinal!(C.nf)); | |
static assert(!isFinal!(C.sf)); | |
static assert( isFinal!(C.ff)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated. Add
isFinal
from Issue 6614 - std.traits should have an isFinal template