1 /// Expansive traits module meant to replace `std.traits`. 2 module tern.traits; 3 4 // TODO: Legacy imports, get rid of this eventually 5 public import std.traits : functionAttributes, hasFunctionAttributes, functionLinkage, FunctionTypeOf, 6 ParameterDefaults, ParameterIdentifierTuple, ParameterStorageClassTuple, SetFunctionAttributes, variadicFunctionStyle, 7 BaseClassesTuple, BaseTypeTuple, EnumMembers, FieldNameTuple, hasStaticMember, hasNested, hasIndirections, isNested, 8 RepresentationTypeTuple, TemplateArgsOf, TemplateOf, TransitiveBaseTypeTuple, InoutOf, ConstOf, SharedOf, SharedInoutOf, 9 SharedConstInoutOf, SharedConstOf, ImmutableOf, QualifierOf, allSameType, ForeachType, KeyType, Largest, mostNegative, 10 PointerTarget, Signed, Unconst, Unshared, Unqual, Unsigned, ValueType, Promoted, lvalueOf, rvalueOf, select, Select, 11 hasUDA, getUDAs, getSymbolsByUDA; 12 static import std.traits; 13 static import tern.traits; 14 import std.meta; 15 import std.string; 16 import std.functional : toDelegate; 17 import std.conv; 18 19 /// Gets the partial identifier of `A` excluding all parents. 20 public enum identifier(alias A) = 21 { 22 static if (!__traits(compiles, { auto _ = __traits(identifier, A); }) || isType!A || isExpression!A) 23 return A.stringof; 24 else 25 return __traits(identifier, A); 26 }(); 27 /// Gets the full identifier of `A` including all parents. 28 public enum fullIdentifier(alias A) = 29 { 30 // TODO: Fix, use identifier unless type or expression 31 static if (hasParents!A) 32 return identifier!(Parent!A)~"."~identifier!A; 33 else 34 return identifier!A; 35 }(); 36 /// Gets the parent of `A`. 37 public alias Parent(alias A) = __traits(parent, A); 38 /// Gets the children of `A`. 39 public alias Children(alias A) = __traits(allMembers, A); 40 /// Gets the `alias this` of `T`. 41 public alias AliasThis(T) = __traits(getAliasThis, T); 42 /// Gets all attributes that are applied to `A`. 43 public alias Attributes(alias A) = __traits(getAttributes, A); 44 /// True if `A` has a child `M`. 45 public enum hasChild(alias A, string M) = std.traits.hasMember!(A, M); 46 /// True if `A` has a field `M`. 47 public enum hasField(alias A, string M) = std.traits.hasMember!(A, M) && isField!(getChild!(M, A)); 48 /// True if `A` has a function `M`. 49 public enum hasFunction(alias A, string M) = std.traits.hasMember!(A, M) && isFunction!(getChild!(M, A)); 50 /// True if `A` has a type `M`. 51 public enum hasType(alias A, string M) = std.traits.hasMember!(A, M) && isType!(getChild!(M, A)); 52 /// True if `A` has a type `M`. 53 public enum hasTemplate(alias A, string M) = std.traits.hasMember!(A, M) && isTemplate!(getChild!(M, A)); 54 /// Gets an alias to child `M` in `A`. 55 public alias getChild(alias A, string M) = __traits(getMember, A, M); 56 /// True if `A` has a parent `P`. 57 public enum hasParent(alias A, alias P) = staticIndexOf!(P, Implements!A) != -1; 58 /// True if type `B` is an instance of type `A`. 59 public enum isInstanceOf(A, B) = hasParent!(A, B) || (isTemplate!A && std.traits.isInstanceOf!(A, B)); 60 /// True if `A` contains any kind of aliasing. 61 public enum hasAliasing(alias A) = std.traits.hasAliasing!A; 62 /// True if `A` contains any kind of unshared (thread-unsafe) aliasing. 63 public enum hasUnsharedAliasing(alias A) = std.traits.hasUnsharedAliasing!A; 64 /// True if `T` has a user defined assignment operation. 65 public enum hasElaborateAssign(T) = std.traits.hasElaborateAssign!T; 66 /// True if `T` has a user defined copy constructor. 67 public enum hasElaborateCopyConstructor(T) = std.traits.hasElaborateCopyConstructor!T; 68 /// True if `T` has a user defined destructor. 69 public enum hasElaborateDestructor(T) = std.traits.hasElaborateDestructor!T; 70 /// True if `T` has a user defined move operation. 71 public enum hasElaborateMove(T) = std.traits.hasElaborateMove!T; 72 /// True if `F` is safe. 73 public enum isSafe(alias F) = std.traits.isSafe!F; 74 /// True if `F` is unsafe. 75 public enum isUnsafe(alias F) = std.traits.isUnsafe!F; 76 /// True if `A` is final. 77 public enum isFinal(alias A) = std.traits.isFinal!A; 78 /// True if `A` is final. 79 public enum isAbstract(alias A) = std.traits.isAbstractClass!A || std.traits.isAbstractFunction!A; 80 /// True if `F` has no return type (`void`.) 81 public enum isNoReturn(alias F) = is(ReturnType!F == void); 82 /// True if type `A` is assignable to type `B`. 83 public enum isAssignable(A, B) = std.traits.isAssignable!(A, B); 84 /// True if type `A` is covariant with type `B`. 85 public enum isCovariantWith(A, B) = std.traits.isCovariantWith!(A, B); 86 /// True if type `A` is implicitly convertible to type `B`. 87 public enum isImplicitlyConvertible(A, B) = std.traits.isImplicitlyConvertible!(A, B); 88 /// True if type `A` is qualifier convertible to type `B`. 89 public enum isQualifierConvertible(A, B) = std.traits.isQualifierConvertible!(A, B); 90 /// True if type `A` is reinterpretable to type `B`. 91 public enum isReinterpretable(A, B) = 92 { 93 static if ((is(A == void*) && is(B == class)) || (is(A == class) && is(B == void*))) 94 return true; 95 96 static if (is(A == class) != is(B == class)) 97 return false; 98 99 static if (A.sizeof > B.sizeof) 100 return false; 101 102 static if (hasChildren!A && hasChildren!B) 103 { 104 static foreach (i, field; Fields!A) 105 {{ 106 alias FA = getChild!(A, field); 107 alias FB = getChild!(B, Fields!B[i]); 108 static if (!isReinterpretable!(typeof(FA), typeof(FB)) || (isManifest!FA != isManifest!FB)) 109 return false; 110 }} 111 } 112 else static if (hasChildren!A || hasChildren!B) 113 { 114 static if (hasChildren!A) 115 { 116 static if (isManifest!(getChild!(A, Fields!A[0]))) 117 return false; 118 119 alias FA = typeof(getChild!(A, Fields!A[0])); 120 } 121 else 122 alias FA = A; 123 124 static if (hasChildren!B) 125 { 126 static if (isManifest!(getChild!(B, Fields!B[0]))) 127 return false; 128 129 alias FB = typeof(getChild!(B, Fields!B[0])); 130 } 131 else 132 alias FB = B; 133 134 return isReinterpretable!(FA, FB); 135 } 136 137 return true; 138 }(); 139 /// True if `T` is an array. 140 public enum isArray(T) = std.traits.isArray!T; 141 /// True if `T` is a dynamic array. 142 public enum isDynamicArray(T) = std.traits.isDynamicArray!T; 143 /// True if `T` is a static array. 144 public enum isStaticArray(T) = std.traits.isStaticArray!T; 145 /// True if `T` is an associative array. 146 public enum isAssociativeArray(T) = std.traits.isAssociativeArray!T; 147 /// True if `T` is an auto-decodeable string. 148 public enum isAutodecodeableString(T) = std.traits.isAutodecodableString!T; 149 /// True if `T` is a built-in type, as in any language defined type. 150 public enum isBuiltinType(T) = std.traits.isBuiltinType!T; 151 /// True if `T` is an integral. 152 public enum isIntegral(T) = std.traits.isIntegral!T; 153 /// True if `T` is an intrinsically numeric. 154 public enum isScalar(T) = std.traits.isScalarType!T; 155 /// True if `T` is a floating point. 156 public enum isFloatingPoint(T) = std.traits.isFloatingPoint!T; 157 /// True if `T` is a `string` or `wstring`. 158 public enum isNarrowString(T) = std.traits.isNarrowString!T; 159 /// True if `T` is numerically represented, as in integral or float. 160 public enum isNumeric(T) = std.traits.isNumeric!T; 161 /// True if `T` is a pointer. 162 public enum isPointer(T) = std.traits.isPointer!T; 163 /// True if `T` is any string. 164 public enum isString(T) = std.traits.isSomeString!T; 165 /// True if `T` is any char. 166 public enum isChar(T) = std.traits.isSomeChar!T; 167 /// True if `T` is signed. 168 public enum isSigned(T) = std.traits.isSigned!T; 169 /// True if `T` is unsigned. 170 public enum isUnsigned(T) = std.traits.isUnsigned!T; 171 /// True if `T` is unable to be copied. 172 public enum isCopyable(T) = std.traits.isCopyable!T; 173 /// True if `T` is able to be equality compared. 174 public enum isEqualityComparable(T) = std.traits.isTestable!T || std.traits.isEqualityComparable!T; 175 /// True if `T` is able to be ordering compared, as in `<`, `>`, etc. 176 public enum isOrderingComparable(T) = std.traits.isOrderingComparable!T; 177 /// True if `T` is an indirection. 178 public enum isReferenceType(T) = is(T == class) || is(T == interface) || isPointer!T || isDynamicArray!T || isAssociativeArray!T; 179 /// True if `T` is not an indirection. 180 public enum isValueType(T) = is(T == struct) || is(T == enum) || is(T == union) || isBuiltinType!T || hasModifiers!T; 181 /// True if `A` is a template. 182 public enum isTemplate(alias A) = __traits(isTemplate, A); 183 /// True if `A` is a module. 184 public enum isModule(alias A) = __traits(isModule, A); 185 /// True if `A` is a package. 186 public enum isPackage(alias A) = __traits(isPackage, A); 187 /// True if `A` is a field. 188 public enum isField(alias A) = !isType!A && !isFunction!A && !isTemplate!A && !isModule!A && !isPackage!A; 189 /// True if `A` is a local. 190 public enum isLocal(alias A) = !isManifest!A && !__traits(compiles, { enum _ = A; }) && __traits(compiles, { auto _ = A; }); 191 /// True if `A` is an expression, like a string, numeric, or other manifest data. 192 public enum isExpression(alias A) = __traits(compiles, { enum _ = A; }); 193 /// True if `A` is a function symbol. 194 public enum isFunction(alias A) = std.traits.isFunction!A; 195 /// True if `A` is a function pointer symbol. 196 public enum isFunctionPointer(alias A) = std.traits.isFunctionPointer!A; 197 /// True if `A` is a delegate symbol. 198 public enum isDelegate(alias A) = std.traits.isDelegate!A; 199 /// True if `A` is a type symbol. 200 public enum isType(alias A) = std.traits.isType!A; 201 /// True if `A` is a class type symbol. 202 public enum isClass(alias A) = is(A == class); 203 /// True if `A` is a interface type symbol. 204 public enum isInterface(alias A) = is(A == interface); 205 /// True if `A` is a struct type symbol. 206 public enum isStruct(alias A) = is(A == struct); 207 /// True if `A` is a enum type symbol. 208 public enum isEnum(alias A) = is(A == enum); 209 /// True if `A` is a union type symbol. 210 public enum isUnion(alias A) = is(A == union); 211 /// True if `A` is an aggregate type symbol. 212 public enum isAggregateType(alias A) = std.traits.isAggregateType!A; 213 /// True if `A` is an alias to a top-level symbol, like a package or intrinsic, which has no parent. 214 public enum isTopLevel(alias A) = !__traits(compiles, { alias _ = Parent!A; }) || !__traits(compiles, { enum _ = is(Parent!A == void); }) || is(Parent!A == void); 215 /// True if `A` has any parents. 216 public enum hasParents(alias A) = !isManifest!A && !isTopLevel!A; 217 /// True if `T` is an enum, array, or pointer. 218 public enum hasModifiers(T) = isArray!T || isPointer!T || isEnum!T; 219 /// True if `A` has any children. 220 public enum hasChildren(alias A) = isModule!A || isPackage!A || (!isType!A || (!isBuiltinType!A && !hasModifiers!A)); 221 /// True if `T` has any instance constructor ("__ctor"). 222 public enum hasConstructor(alias A) = std.traits.hasMember!(T, "__ctor"); 223 /// True if `F` is a constructor; 224 public enum isConstructor(alias F) = isFunction!F && (__traits(identifier, F).startsWith("__ctor") || __traits(identifier, F).startsWith("_staticCtor")); 225 /// True if `F` is a destructor. 226 public enum isDestructor(alias F) = isFunction!F && (__traits(identifier, F).startsWith("__dtor") || __traits(identifier, F).startsWith("__xdtor") || __traits(identifier, F).startsWith("_staticDtor")); 227 /// True if `A` is a static field. 228 public enum isStatic(alias A) = !isManifest!A && ((isField!A && __traits(compiles, { auto _ = __traits(getMember, Parent!A, __traits(identifier, A)); })) || (isLocal!A && __traits(compiles, { static auto _() { return A; } }))); 229 /// True if `A` is an enum field or local. 230 public enum isManifest(alias A) = __traits(compiles, { enum _ = __traits(getMember, Parent!A, __traits(identifier, A)); }); 231 /// True if `A` is an implementation defined alias (ie: __ctor, std, rt, etc.) 232 public enum isDImplDefined(alias A) = 233 { 234 static if ((isModule!A || (isType!A && !isBuiltinType!A)) && (getPackage!A.stringof == "package std" || getPackage!A.stringof == "package rt" || getPackage!A.stringof == "package core")) 235 return true; 236 else static if (isPackage!A && (A.stringof == "package std" || A.stringof == "package rt" || A.stringof == "package core")) 237 return true; 238 else static if (isType!A && isBuiltinType!A) 239 return true; 240 else static if (isFunction!A && 241 // Not exactly accurate but good enough 242 (__traits(identifier, A).startsWith("_d_") || __traits(identifier, A).startsWith("rt_") || 243 __traits(identifier, A).startsWith("__") || __traits(identifier, A).startsWith("op"))) 244 return true; 245 else static if (isConstructor!A || isDestructor!A || (isFunction!F && (__traits(identifier, F).startsWith("toHash") || __traits(identifier, F).startsWith("toString")))) 246 return true; 247 else 248 return false; 249 }(); 250 /// True if `A` is not D implementation defined. 251 public enum isOrganic(alias A) = !isDImplDefined!A; 252 /// True if `T` is able to be indexed. 253 public enum isIndexable(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; auto _ = t[0]; }); 254 /// True if `T` is able to be index assigned. 255 public enum isIndexAssignable(T) = __traits(compiles, { T t; auto _ = (t[0] = t[1]); }) && isMutable!(ElementType!T); 256 /// True if `T` is able to be sliced. 257 public enum isSliceable(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; auto _ = t[0..1]; }); 258 /// True if `T` is able to be slice assigned. 259 public enum isSliceAssignable(T) = __traits(compiles, { T t; auto _ = (t[0..1] = t[1..2]); } && isMutable!(ElementType!T)); 260 /// True if `T` is able to be iterated upon forwards. 261 public enum isForward(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; foreach (u; t) { } }); 262 /// True if `T` is able to be iterated upon forwards. 263 public enum isBackward(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; foreach_reverse (u; t) { } }); 264 /// True if `B` is an element type of `A` (assignable as element.) 265 public enum isElement(A, B) = isAssignable!(B, ElementType!A); 266 /// True if `B` is able to be used as a range the same as `A`. 267 public enum isSimRange(A, B) = isAssignable!(ElementType!B, ElementType!A); 268 /// True if `F` is a lambda. 269 public enum isLambda(alias F) = __traits(identifier, F).startsWith("__lambda"); 270 /// True if `F` is a dynamic lambda (templated, ie: `x => x + 1`) 271 public enum isTemplatedCallable(alias F) = std.traits.isCallable!(DefaultInstance!F); 272 /// True if `F` is a dynamic lambda (templated, ie: `x => x + 1`) 273 public enum isDynamicLambda(alias F) = isLambda!F && is(typeof(F) == void); 274 /// True if `F` is a function, lambda, or otherwise may be called using `(...)` 275 public enum isCallable(alias F) = std.traits.isCallable!F || isLambda!F || isTemplatedCallable!F; 276 /// True if `F` is a property of any kind. 277 public enum isProperty(alias F) = hasUDA!(F, property); 278 /// True if `F` is a pure callable. 279 public enum isPure(alias F) = isCallable!F && hasFunctionAttributes!(F, "pure"); 280 /// True if type `A` implements type `B`. 281 public enum isImplement(A, B) = staticIndexOf!(B, Implements!A) != -1; 282 /// True if `A` is not mutable (const, immutable, enum, etc.). 283 public enum isMutable(alias A) = 284 { 285 static if (isType!A) 286 return std.traits.isMutable!A; 287 else static if (isField!A) 288 return std.traits.isMutable!(typeof(A)) || !isManifest!A; 289 else 290 return false; 291 }(); 292 293 /// Gets all children of child `M` in `A`. 294 public alias Children(alias A, string M) = Children!(getChild!(A, M)); 295 /// Gets all attributes of child `M` in `A`. 296 public alias Attributes(alias A, string M) = Attributes!(getChild!(A, M)); 297 /// True if child `M1` in `A` has a child `M2`. 298 public alias hasChild(alias A, string M1, string M2) = hasChild!(getChild!(A, M1), M2); 299 /// True if child `M1` in `A` has a field `M2`. 300 public alias hasField(alias A, string M1, string M2) = hasField!(getChild!(A, M1), M2); 301 /// True if child `M1` in `A` has a function `M2`. 302 public alias hasFunction(alias A, string M1, string M2) = hasFunction!(getChild!(A, M1), M2); 303 /// True if child `M1` in `A` has a type `M2`. 304 public alias hasType(alias A, string M1, string M2) = hasType!(getChild!(A, M1), M2); 305 /// True if child `M1` in `A` has a template `M2`. 306 public alias hasTemplate(alias A, string M1, string M2) = hasTemplate!(getChild!(A, M1), M2); 307 /// Gets the child `M2` in `M1` in `A`. 308 public alias getChild(alias A, string M1, string M2) = getChild!(getChild!(A, M1), M2); 309 /// True if child `M1` in `A` has a parent `P`. 310 public alias hasParent(alias A, string M, alias P) = hasParent!(getChild!(A, M), P); 311 /// True if the type of `M` in `A` has aliasing. 312 public alias hasAliasing(alias A, string M) = hasAliasing!(typeof(getChild!(A, M))); 313 /// True if the type of `M` in `A` has unshared aliasing. 314 public alias hasUnsharedAliasing(alias A, string M) = hasUnsharedAliasing!(typeof(getChild!(A, M))); 315 /// True if the type of `M` in `A` has an elaborate assign. 316 public alias hasElaborateAssign(alias A, string M) = hasElaborateAssign!(typeof(getChild!(A, M))); 317 /// True if the type of `M` in `A` has an elaborate copy constructor. 318 public alias hasElaborateCopyConstructor(alias A, string M) = hasElaborateCopyConstructor!(typeof(getChild!(A, M))); 319 /// True if the type of `M` in `A` has an elaborate destructor. 320 public alias hasElaborateDestructor(alias A, string M) = hasElaborateDestructor!(typeof(getChild!(A, M))); 321 /// True if the type of `M` in `A` has an elaborate move. 322 public alias hasElaborateMove(alias A, string M) = hasElaborateMove!(typeof(getChild!(A, M))); 323 /// True if the type of `M` in `A` is safe. 324 public alias isSafe(alias A, string M) = isSafe!(typeof(getChild!(A, M))); 325 /// True if the type of `M` in `A` is unsafe. 326 public alias isUnsafe(alias A, string M) = isUnsafe!(typeof(getChild!(A, M))); 327 /// True if the type of `M` in `A` is final. 328 public alias isFinal(alias A, string M) = isFinal!(typeof(getChild!(A, M))); 329 /// True if the type of `M` in `A` is abstract. 330 public alias isAbstract(alias A, string M) = isAbstract!(typeof(getChild!(A, M))); 331 /// True if the type of `M` in `A` is a void returning callable. 332 public alias isNoReturn(alias A, string M) = isNoReturn!(typeof(getChild!(A, M))); 333 /// True if the type of `M` in `A` is assignable to `B`. 334 public alias isAssignable(alias A, string M, alias B) = isAssignable!(typeof(getChild!(A, M), B)); 335 /// True if the type of `M` in `A` is covariant with `B`. 336 public alias isCovariantWith(alias A, string M, alias B) = isCovariantWith!(typeof(getChild!(A, M), B)); 337 /// True if the type of `M` in `A` is implicitly convertible to `B`. 338 public alias isImplicitlyConvertible(alias A, string M, alias B) = isImplicitlyConvertible!(typeof(getChild!(A, M), B)); 339 /// True if the type of `M` in `A` is qualifier convertible to `B`. 340 public alias isQualifierConvertible(alias A, string M, alias B) = isQualifierConvertible!(typeof(getChild!(A, M), B)); 341 /// True if the type of `M` in `A` is reinterpretable to `B`. 342 public alias isReinterpretable(alias A, string M, alias B) = isReinterpretable!(typeof(getChild!(A, M), B)); 343 /// True if the type of `M` in `A` is an array. 344 public alias isArray(alias A, string M) = isArray!(typeof(getChild!(A, M))); 345 /// True if the type of `M` in `A` is a dynamic array. 346 public alias isDynamicArray(alias A, string M) = isDynamicArray!(typeof(getChild!(A, M))); 347 /// True if the type of `M` in `A` is a static array. 348 public alias isStaticArray(alias A, string M) = isStaticArray!(typeof(getChild!(A, M))); 349 /// True if the type of `M` in `A` is an associative array. 350 public alias isAssociativeArray(alias A, string M) = isAssociativeArray!(typeof(getChild!(A, M))); 351 /// True if the type of `M` in `A` is an auto-decodeable string. 352 public alias isAutodecodableString(alias A, string M) = isAutodecodableString!(typeof(getChild!(A, M))); 353 /// True if the type of `M` in `A` is a built-in type. 354 public alias isBuiltinType(alias A, string M) = isBuiltinType!(typeof(getChild!(A, M))); 355 /// True if the type of `M` in `A` is an integral. 356 public alias isIntegral(alias A, string M) = isIntegral!(typeof(getChild!(A, M))); 357 /// True if the type of `M` in `A` is a scalar. 358 public alias isScalar(alias A, string M) = isScalar!(typeof(getChild!(A, M))); 359 /// True if the type of `M` in `A` is a floating-point. 360 public alias isFloatingPoint(alias A, string M) = isFloatingPoint!(typeof(getChild!(A, M))); 361 /// True if the type of `M` in `A` is a narrow string. 362 public alias isNarrowString(alias A, string M) = isNarrowString!(typeof(getChild!(A, M))); 363 /// True if the type of `M` in `A` is numeric. 364 public alias isNumeric(alias A, string M) = isNumeric!(typeof(getChild!(A, M))); 365 /// True if the type of `M` in `A` is a pointer. 366 public alias isPointer(alias A, string M) = isPointer!(typeof(getChild!(A, M))); 367 /// True if the type of `M` in `A` is any string. 368 public alias isString(alias A, string M) = isString!(typeof(getChild!(A, M))); 369 /// True if the type of `M` in `A` is any char. 370 public alias isChar(alias A, string M) = isChar!(typeof(getChild!(A, M))); 371 /// True if the type of `M` in `A` is signed. 372 public alias isSigned(alias A, string M) = isSigned!(typeof(getChild!(A, M))); 373 /// True if the type of `M` in `A` is unsigned. 374 public alias isUnsigned(alias A, string M) = isUnsigned!(typeof(getChild!(A, M))); 375 /// True if the type of `M` in `A` is copyable. 376 public alias isCopyable(alias A, string M) = isCopyable!(typeof(getChild!(A, M))); 377 /// True if the type of `M` in `A` is equality comparable. 378 public alias isEqualityComparable(alias A, string M) = isEqualityComparable!(typeof(getChild!(A, M))); 379 /// True if the type of `M` in `A` is ordering comparable. 380 public alias isOrderingComparable(alias A, string M) = isOrderingComparable!(typeof(getChild!(A, M))); 381 /// True if the type of `M` in `A` is a reference type. 382 public alias isReferenceType(alias A, string M) = isReferenceType!(typeof(getChild!(A, M))); 383 /// True if the type of `M` in `A` is a value type. 384 public alias isValueType(alias A, string M) = isValueType!(typeof(getChild!(A, M))); 385 /// True if `M` in `A` is a template. 386 public alias isTemplate(alias A, string M) = isTemplate!(getChild!(A, M)); 387 /// True if `M` in `A` is a module. 388 public alias isModule(alias A, string M) = isModule!(getChild!(A, M)); 389 /// True if `M` in `A` is a field. 390 public alias isField(alias A, string M) = isField!(getChild!(A, M)); 391 /// True if `M` in `A` is a local. 392 public alias isLocal(alias A, string M) = isLocal!(getChild!(A, M)); 393 /// True if `M` in `A` is a function. 394 public alias isFunction(alias A, string M) = isFunction!(getChild!(A, M)); 395 /// True if the type of `M` in `A` is a function pointer. 396 public alias isFunctionPointer(alias A, string M) = isFunctionPointer!(typeof(getChild!(A, M))); 397 /// True if the type of `M` in `A` is a delegate. 398 public alias isDelegate(alias A, string M) = isDelegate!(typeof(getChild!(A, M))); 399 /// True if `M` in `A` is a type. 400 public alias isType(alias A, string M) = isType!(getChild!(A, M)); 401 /// True if the type of `M` in `A` is a class. 402 public alias isClass(alias A, string M) = isClass!(typeof(getChild!(A, M))); 403 /// True if the type of `M` in `A` is an interface. 404 public alias isInterface(alias A, string M) = isInterface!(typeof(getChild!(A, M))); 405 /// True if the type of `M` in `A` is a struct. 406 public alias isStruct(alias A, string M) = isStruct!(typeof(getChild!(A, M))); 407 /// True if the type of `M` in `A` is an enum. 408 public alias isEnum(alias A, string M) = isEnum!(typeof(getChild!(A, M))); 409 /// True if the type of `M` in `A` is a union. 410 public alias isUnion(alias A, string M) = isUnion!(typeof(getChild!(A, M))); 411 /// True if the type of `M` in `A` is an aggregate type. 412 public alias isAggregateType(alias A, string M) = isAggregateType!(typeof(getChild!(A, M))); 413 /// True if the type of `M` in `A` is an instance of `B`. 414 public alias isInstanceOf(alias A, string M, alias B) = isInstanceOf!(typeof(getChild!(A, M)), B); 415 /// True if the type of `M` in `A` has modifiers. 416 public alias hasModifiers(alias A, string M) = hasModifiers!(typeof(getChild!(A, M))); 417 /// True if `M` in `A` has children. 418 public alias hasChildren(alias A, string M) = hasChildren!(getChild!(A, M)); 419 /// True if the type of `M` in `A` has a constructor. 420 public alias hasConstructor(alias A, string M) = hasChildren!(typeof(getChild!(A, M))); 421 /// True if `M` in `A` is static. 422 public alias isStatic(alias A, string M) = isStatic!(getChild!(A, M)); 423 /// True if `M` in `A` is manifest data. 424 public alias isManifest(alias A, string M) = isManifest!(getChild!(A, M)); 425 /// True if `M` in `A` is implementation defined. 426 public alias isDImplDefined(alias A, string M) = isDImplDefined!(getChild!(A, M)); 427 /// True if `M` in `A` is not implementation defined. 428 public alias isOrganic(alias A, string M) = isOrganic!(getChild!(A, M)); 429 /// True if the type of `M` in `A` is indexable. 430 public alias isIndexable(alias A, string M) = isIndexable!(typeof(getChild!(A, M))); 431 /// True if the type of `M` in `A` is index assignable. 432 public alias isIndexAssignable(alias A, string M) = isIndexAssignable!(typeof(getChild!(A, M))); 433 /// True if the type of `M` in `A` is sliceable. 434 public alias isSliceable(alias A, string M) = isSliceable!(typeof(getChild!(A, M))); 435 /// True if the type of `M` in `A` is slice assignable. 436 public alias isSliceAssignable(alias A, string M) = isSliceAssignable!(typeof(getChild!(A, M))); 437 /// True if the type of `M` in `A` is forward iterable. 438 public alias isForward(alias A, string M) = isForward!(typeof(getChild!(A, M))); 439 /// True if the type of `M` in `A` is backward iterable. 440 public alias isBackward(alias A, string M) = isBackward!(typeof(getChild!(A, M))); 441 /// True if the type of `M` in `A` is an element of `B`. 442 public alias isElement(alias A, string M, alias B) = isElement!(typeof(getChild!(A, M)), B); 443 /// True if the type of `M` in `A` shares element type with `B`. 444 public alias isSimRange(alias A, string M, alias B) = isSimRange!(typeof(getChild!(A, M)), B); 445 /// True if the type of `M` in `A` is a lambda. 446 public alias isLambda(alias A, string M) = isLambda!(typeof(getChild!(A, M))); 447 /// True if the type of `M` in `A` is a templated callable. 448 public alias isTemplatedCallable(alias A, string M) = isTemplatedCallable!(typeof(getChild!(A, M))); 449 /// True if the type of `M` in `A` is a dynamic lambda. 450 public alias isDynamicLambda(alias A, string M) = isDynamicLambda!(typeof(getChild!(A, M))); 451 /// True if the type of `M` in `A` is callable. 452 public alias isCallable(alias A, string M) = isCallable!(typeof(getChild!(A, M))); 453 /// True if `M` in `A` is a property. 454 public alias isProperty(alias A, string M) = isProperty!(getChild!(A, M)); 455 /// True if the type of `M` in `A` is pure. 456 public alias isPure(alias A, string M) = isPure!(typeof(getChild!(A, M))); 457 /// True if the type of `M` in `A` implements `B`. 458 public alias isImplement(alias A, string M, alias B) = isImplement!(typeof(getChild!(A, M)), B); 459 /// True if `M` in `A` is mutable. 460 public alias isMutable(alias A, string M) = isMutable!(getChild!(A, M)); 461 462 /// Gets the alignment of `T` dynamically, returning the actual instance alignment. 463 public enum alignof(T) = 464 { 465 static if (is(T == class)) 466 return __traits(classInstanceAlignment, T); 467 else 468 return T.alignof; 469 }(); 470 471 /// Gets the size of `T` dynamically, returning the actual instance size. 472 public enum sizeof(T) = 473 { 474 static if (is(T == class)) 475 return __traits(classInstanceSize, T); 476 else 477 return T.sizeof; 478 }(); 479 480 /// Instantiates `T` using all default arguments (`void[]` for types or variadic) 481 public template DefaultInstantiate(alias T) 482 if (isTemplate!T) 483 { 484 string args() 485 { 486 string ret; 487 static foreach (arg; T.stringof[(T.stringof.indexOf("(") + 1)..T.stringof.indexOf(")")].split(", ")) 488 { 489 static if (arg.split(" ").length == 1) 490 ret ~= "void[], "; 491 else 492 ret ~= arg.split(" ")[0]~".init, "; 493 } 494 return ret[0..(ret.length >= 2 ? $-2 : $)]; 495 } 496 497 alias defaultInstantiate = mixin("T!("~args~")"); 498 } 499 500 /// Gets the number of arguments that `F` takes, undefined or variadic. 501 public enum Arity(alias F) = 502 { 503 static if (F.stringof.startsWith("__lambda") && !is(typeof(F) == void)) 504 { 505 typeof(toDelegate(F)) dg; 506 return Parameters!dg.length; 507 } 508 static if (!F.stringof.startsWith("__lambda") || !is(typeof(F) == void)) 509 return Parameters!F.length; 510 else 511 { 512 string p = F.stringof[(F.stringof.lastIndexOf("(") + 1)..(F.stringof.lastIndexOf(")"))]; 513 return p.split(", ").length; 514 } 515 }(); 516 517 /// Gets the module that `A` is declared in, or itself, if it has no module. 518 public template Module(alias A) 519 { 520 static if (!hasParents!A || isPackage!(Parent!A)) 521 alias Module = A; 522 else 523 alias Module = Module!(Parent!A); 524 } 525 526 /// Gets the package that `A` is declared in, or itself, if it has no package. 527 public template Package(alias A) 528 { 529 static if (!hasParents!A) 530 alias Package = A; 531 else static if (isPackage!(Parent!A)) 532 alias Package = Parent!A; 533 else 534 alias Package = Package!(Parent!A); 535 } 536 537 /// Gets the return type of a callable symbol. 538 public template ReturnType(alias F) 539 if (isCallable!F) 540 { 541 static if (isLambda!F && !__traits(compiles, { alias _ = std.traits.ReturnType!F; })) 542 { 543 typeof(toDelegate(F)) dg; 544 alias ReturnType = typeof(dg); 545 } 546 else 547 alias ReturnType = std.traits.ReturnType!F; 548 } 549 550 /// Gets the parameters of a callable symbol. 551 public template Parameters(alias F) 552 if (isCallable!F) 553 { 554 static if (isLambda!F && !__traits(compiles, { alias _ = std.traits.Parameters!F; })) 555 { 556 typeof(toDelegate(F)) dg; 557 alias Parameters = std.traits.Parameters!dg; 558 } 559 else 560 alias Parameters = std.traits.Parameters!F; 561 } 562 563 /// Gets the element type of `T`, if applicable. 564 /// Returns the type of enum values if `T` is an enum. 565 public template ElementType(T) 566 { 567 static if (is(T == U[], U) || is(T == U*, U) || is(T U == U[L], size_t L)) 568 alias ElementType = ElementType!U; 569 else static if (isIndexable!T) 570 { 571 T temp; 572 alias ElementType = ElementType!(typeof(temp[0])); 573 } 574 else 575 alias ElementType = std.traits.OriginalType!T; 576 } 577 578 /// Gets the length of `T`, if applicable. 579 public template Length(T) 580 { 581 static if (is(T U == U[L], size_t L)) 582 enum Length = L; 583 } 584 585 /// Gets an `AliasSeq` all types that `T` implements. 586 public template Implements(T) 587 { 588 private template Flatten(H, T...) 589 { 590 static if (T.length) 591 { 592 alias Flatten = AliasSeq!(Flatten!H, Flatten!T); 593 } 594 else 595 { 596 static if (!is(H == Object) && (is(H == class) || is(H == interface))) 597 alias Flatten = AliasSeq!(H, Implements!H); 598 else 599 alias Flatten = Implements!H; 600 } 601 } 602 603 static if (is(T S == super) && S.length) 604 { 605 static if (getAliasThis!T.length != 0) 606 alias Implements = AliasSeq!(TypeOf!(T, getAliasThis!T), Implements!(TypeOf!(T, getAliasThis!T)), NoDuplicates!(Flatten!S)); 607 else 608 alias Implements = NoDuplicates!(Flatten!S); 609 } 610 else 611 { 612 static if (getAliasThis!T.length != 0) 613 alias Implements = AliasSeq!(TypeOf!(T, getAliasThis!T), Implements!(TypeOf!(T, getAliasThis!T))); 614 else 615 alias Implements = AliasSeq!(); 616 } 617 } 618 619 /// Gets an `AliasSeq` of the names of all fields in `A`. 620 public template Fields(alias A) 621 { 622 alias Fields = AliasSeq!(); 623 624 static if (hasChildren!A) 625 static foreach (member; Children!A) 626 { 627 static if (isField!(getChild!(A, member))) 628 Fields = AliasSeq!(Fields, member); 629 } 630 } 631 632 /// Gets an `AliasSeq` of the names all functions in `A`. 633 public template Functions(alias A) 634 { 635 alias Functions = AliasSeq!(); 636 637 static if (hasChildren!A) 638 static foreach (member; Children!A) 639 { 640 static if (isFunction!(getChild!(A, member))) 641 Functions = AliasSeq!(Functions, member); 642 } 643 } 644 645 /// Gets an `AliasSeq` of the names of all types in `A`. 646 public template Types(alias A) 647 { 648 alias Types = AliasSeq!(); 649 650 static if (hasChildren!A) 651 static foreach (member; Children!A) 652 { 653 static if (isType!(getChild!(A, member))) 654 Types = AliasSeq!(Types, member); 655 } 656 } 657 658 /// Gets an `AliasSeq` of the names of all templates in `A`. 659 public template Templates(alias A) 660 { 661 alias Templates = AliasSeq!(); 662 663 static if (hasChildren!A) 664 static foreach (member; Children!A) 665 { 666 static if (isTemplate!(getChild!(A, member))) 667 Templates = AliasSeq!(Templates, member); 668 } 669 } 670 671 /// Gets the signature of `A` as a string, has defined special behavior for callables and fields. 672 /// This includes all attributes, templates (must be already initialized, names are lost,) and parameters. 673 public template Signature(alias A, bool DECLARING = true) 674 { 675 static if (isCallable!A) 676 enum Signature = 677 { 678 static if (DECLARING) 679 { 680 string paramSig = "("; 681 static if (__traits(compiles, { alias _ = TemplateArgsOf!A; })) 682 { 683 static foreach (i, A; TemplateArgsOf!A) 684 { 685 static if (__traits(compiles, { enum _ = B; })) 686 paramSig ~= fullIdentifier!(typeof(B))~" T"~i.stringof[0..$-2]; 687 else 688 paramSig ~= "alias T"~i.stringof[0..$-2]; 689 } 690 paramSig ~= ")("; 691 } 692 693 foreach (i, P; Parameters!A) 694 { 695 foreach (Q; __traits(getParameterStorageClasses, A, i)) 696 paramSig ~= Q~" "; 697 paramSig ~= fullIdentifier!P~" "~ParameterIdentifierTuple!A[i]~(i == Parameters!A.length - 1 ? null : ", "); 698 } 699 paramSig ~= ")"; 700 701 string attrs; 702 static foreach (ATTR; __traits(getFunctionAttributes, A)) 703 attrs ~= ATTR~" "; 704 attrs = attrs[0..(attrs.length == 0 ? $ : $-1)]; 705 } 706 else 707 { 708 string paramSig = "("; 709 static if (__traits(compiles, { alias _ = TemplateArgsOf!A; })) 710 { 711 static foreach (i, A; TemplateArgsOf!A) 712 { 713 static if (__traits(compiles, { enum _ = B; })) 714 paramSig ~= "T"~i.stringof[0..$-2]; 715 else 716 paramSig ~= "T"~i.stringof[0..$-2]; 717 } 718 paramSig ~= ")("; 719 } 720 721 foreach (i, P; Parameters!A) 722 paramSig ~= ParameterIdentifierTuple!A[i]~(i == Parameters!A.length - 1 ? null : ", "); 723 paramSig ~= ")"; 724 } 725 726 static if (DECLARING) 727 return attrs~" "~fullIdentifier!(ReturnType!A)~" "~identifier!A~paramSig; 728 else 729 return identifier!A~paramSig; 730 }(); 731 732 static if (isField!A) 733 enum Signature = 734 { 735 static if (isManifest!F) 736 return "enum "~fullIdentifier!(typeof(F))~" "~identifier!F~" = "~F.stringof; 737 else static if (isStatic!F) 738 return "static "~fullIdentifier!(typeof(F))~" "~identifier!F; 739 else 740 return fullIdentifier!(typeof(F))~" "~identifier!F; 741 }(); 742 743 static if (!isCallable!A && !isField!A) 744 enum Signature = fullIdentifier!A; 745 } 746 747 /// Gets an alias to the return type of `M` in `A`. 748 public alias ReturnType(alias A, string M) = ReturnType!(getChild!(A, M)); 749 /// Gets an alias to the parameters of `M` in `A`. 750 public alias Parameters(alias A, string M) = Parameters!(getChild!(A, M)); 751 /// Gets an alias to the element type of `M` in `A`. 752 public alias ElementType(alias A, string M) = ElementType!(typeof(getChild!(A, M))); 753 /// Gets an alias to the length of `M` in `A`. 754 public alias Length(alias A, string M) = Length!(typeof(getChild!(A, M))); 755 /// Gets an `AliasSeq` with all types implemented by `M` in `A`. 756 public alias Implements(alias A, string M) = Implements!(getChild!(A, M)); 757 /// Gets an `AliasSeq` with all fields in `M` in `A`. 758 public alias Fields(alias A, string M) = Fields!(getChild!(A, M)); 759 /// Gets an `AliasSeq` with all functions in `M` in `A`. 760 public alias Functions(alias A, string M) = Functions!(getChild!(A, M)); 761 /// Gets an `AliasSeq` with all types in `M` in `A`. 762 public alias Types(alias A, string M) = Types!(getChild!(A, M)); 763 /// Gets an `AliasSeq` with all templates in `M` in `A`. 764 public alias Templates(alias A, string M) = Templates!(getChild!(A, M)); 765 /// Gets the signature of `M` in `A`. 766 public alias Signature(alias A, string M) = Signature!(getChild!(A, M));