1 module libd.meta.traits; 2 3 alias AliasSeq(T...) = T; 4 5 template allSatisfy(alias Condition, T...) 6 { 7 bool func() 8 { 9 bool result = true; 10 11 static foreach(t; T) 12 { 13 static if(!Condition!t) 14 result = false; 15 } 16 17 return result; 18 } 19 20 enum allSatisfy = func(); 21 } 22 /// 23 @("allSatisfy") 24 unittest 25 { 26 enum isIntOrString(alias T) = is(typeof(T) == int) || is(typeof(T) == string); 27 static assert(allSatisfy!(isIntOrString, 0, "")); 28 static assert(!allSatisfy!(isIntOrString, 0, false, "")); 29 30 enum isIntOrStringT(T) = is(T == int) || is(T == string); 31 static assert(allSatisfy!(isIntOrStringT, int, string)); 32 static assert(!allSatisfy!(isIntOrStringT, int, bool, string)); 33 } 34 35 template anySatisfy(alias Condition, T...) 36 { 37 bool func() 38 { 39 bool result = false; 40 41 static foreach(t; T) 42 { 43 static if(Condition!t) 44 result = true; 45 } 46 47 return result; 48 } 49 50 enum anySatisfy = func(); 51 } 52 /// 53 @("anySatisfy") 54 unittest 55 { 56 enum isIntOrString(alias T) = is(typeof(T) == int) || is(typeof(T) == string); 57 static assert(anySatisfy!(isIntOrString, 0, false)); 58 static assert(!anySatisfy!(isIntOrString, ['s'], false)); 59 60 enum isIntOrStringT(T) = is(T == int) || is(T == string); 61 static assert(anySatisfy!(isIntOrStringT, int, bool)); 62 static assert(!anySatisfy!(isIntOrStringT, char[], bool)); 63 } 64 65 template isPartOfUnion(UnionT, ValueT) 66 { 67 bool func() 68 { 69 bool result; 70 71 static foreach(name; __traits(allMembers, UnionT)) 72 { 73 static if(is(ValueT == typeof(__traits(getMember, UnionT, name)))) 74 result = true; 75 } 76 77 return result; 78 } 79 80 enum isPartOfUnion = func(); 81 } 82 /// 83 @("isPartOfUnion") 84 unittest 85 { 86 static union U 87 { 88 int a; 89 string b; 90 } 91 92 static assert(isPartOfUnion!(U, int)); 93 static assert(isPartOfUnion!(U, string)); 94 static assert(!isPartOfUnion!(U, short)); 95 static assert(!isPartOfUnion!(U, bool)); 96 } 97 98 enum isSomeFunction(alias F) = is(FunctionTypeOf!F _ == function); 99 /// 100 @("isSomeFunction") 101 unittest 102 { 103 int a; 104 static void f(){} 105 scope d = (){ a = 0; }; 106 107 static assert(isSomeFunction!f); 108 static assert(isSomeFunction!d); 109 } 110 111 enum isCopyable(alias T) = __traits(isCopyable, T); 112 /// 113 @("isCopyable") 114 unittest 115 { 116 struct S 117 { 118 @disable this(this){} 119 } 120 121 static assert(isCopyable!int); 122 static assert(!isCopyable!S); 123 } 124 125 enum isSlice(alias T) = is(T == E[], E); 126 /// 127 @("isSlice") 128 unittest 129 { 130 static assert(isSlice!(int[])); 131 static assert(!isSlice!int); 132 } 133 134 enum isPointer(alias T) = is(T == E*, E); 135 /// 136 @("isPointer") 137 unittest 138 { 139 static assert(isPointer!(int*)); 140 static assert(!isPointer!int); 141 } 142 143 template ElementType(alias T) 144 { 145 import libd.algorithm.common : isInputRange; 146 147 static if(is(T == E[], E)) 148 alias ElementType = E; 149 else static if(isInputRange!T) 150 alias ElementType = typeof(T.init.front()); 151 else static assert(false, "Cannot determine element type of type `"~T.stringof~"`"); 152 } 153 /// 154 @("ElementType") 155 unittest 156 { 157 static assert(is(ElementType!(int[]) == int)); 158 } 159 160 template Parameters(alias F) 161 { 162 static if(is(FunctionTypeOf!F P == function)) 163 alias Parameters = P; 164 else 165 static assert(false, F.stringof~" is not a function/delegate/there's a bug."); 166 } 167 /// 168 @("Parameters") 169 unittest 170 { 171 static void a(){} 172 static void aa(int, string){} 173 auto b = (){}; 174 auto bb = (int s, string ss){}; 175 176 static assert(is(Parameters!a == AliasSeq!())); 177 static assert(is(Parameters!aa == AliasSeq!(int, string))); 178 static assert(is(Parameters!b == AliasSeq!())); 179 static assert(is(Parameters!bb == AliasSeq!(int, string))); 180 } 181 182 enum isInstanceOf(alias S, alias T) = is(T == S!Args, Args...); 183 184 template BitmaskUda(alias Uda, alias T) 185 { 186 static if(__traits(compiles, __traits(getAttributes, T))) 187 { 188 Uda get() 189 { 190 Uda value; 191 192 static foreach(uda; __traits(getAttributes, T)) 193 { 194 static if(__traits(compiles, typeof(uda)) && is(typeof(uda) == Uda)) 195 value |= uda; 196 } 197 198 return value; 199 } 200 enum BitmaskUda = get(); 201 } 202 else 203 enum BitmaskUda = Uda.init; 204 } 205 /// 206 @("BitmaskUda") 207 unittest 208 { 209 static enum Uda 210 { 211 a = 1, 212 b = 2, 213 c = 4 214 } 215 216 @(Uda.a, Uda.c) 217 static struct A {} 218 219 static assert(BitmaskUda!(Uda, A) == (Uda.a | Uda.c)); 220 } 221 222 template UdaOrDefault(alias Uda, alias T, Uda default_) 223 { 224 Uda get() 225 { 226 Uda value = default_; 227 228 static if(__traits(compiles, __traits(getAttributes, T))) 229 static foreach(uda; __traits(getAttributes, T)) 230 { 231 static if(__traits(compiles, typeof(uda)) && is(typeof(uda) == Uda)) 232 { 233 value = uda; 234 goto LReturn; // Super annoying, but D *still* hates it when a conditional return is generated alongside an always-existing return. 235 } 236 } 237 238 LReturn: 239 return value; 240 } 241 enum UdaOrDefault = get(); 242 } 243 /// 244 @("UdaOrDefault") 245 unittest 246 { 247 static struct Uda {int v;} 248 enum E 249 { 250 a, 251 b 252 } 253 254 @(E.b) 255 struct S{} 256 257 static assert(UdaOrDefault!(Uda, S, Uda(200)) == Uda(200)); 258 static assert(UdaOrDefault!(E, S, E.a) == E.b); 259 } 260 261 struct TypeId 262 { 263 string fqn; 264 uint fqnHash; 265 266 bool opEquals(const TypeId other) const @safe @nogc nothrow 267 { 268 return this.fqnHash == other.fqnHash; 269 } 270 271 size_t toHash() const @safe @nogc nothrow 272 { 273 return this.fqnHash; 274 } 275 } 276 277 template TypeIdOf(alias T) 278 { 279 import libd.data.hash : Murmur3_32; 280 281 const fqn = T.stringof;// TODO 282 const TypeIdOf = TypeId( 283 fqn, 284 (){Murmur3_32 hash; hash.put(fqn); return hash.value;}() 285 ); 286 } 287 /// 288 @("TypeIdOf") 289 unittest 290 { 291 const intId = TypeIdOf!int; 292 const stringId = TypeIdOf!string; 293 294 assert(intId.fqn == "int"); 295 assert(intId == intId); 296 assert(stringId != intId); 297 } 298 299 template UnsignedOf(alias NumT) 300 { 301 static if(__traits(isUnsigned, NumT)) 302 alias UnsignedOf = NumT; 303 else static if(__traits(isArithmetic, NumT)) 304 mixin("alias UnsignedOf = u"~NumT.stringof~";"); 305 else static assert(false); 306 } 307 /// 308 @("UnsignedOf") 309 unittest 310 { 311 static assert(is(UnsignedOf!byte == ubyte)); 312 static assert(is(UnsignedOf!ubyte == ubyte)); 313 } 314 315 template Unqual(T : const U, U) 316 { 317 static if (is(U == shared V, V)) 318 alias Unqual = V; 319 else 320 alias Unqual = U; 321 } 322 323 /+++++++++++++++++ STOLEN FROM PHOBOS +++++++++++++++++++/ 324 /** 325 Get the function type from a callable object `func`. 326 Using builtin `typeof` on a property function yields the types of the 327 property value, not of the property function itself. Still, 328 `FunctionTypeOf` is able to obtain function types of properties. 329 Note: 330 Do not confuse function types with function pointer types; function types are 331 usually used for compile-time reflection purposes. 332 */ 333 template FunctionTypeOf(func...) 334 if (func.length == 1) 335 { 336 static if (is(typeof(& func[0]) Fsym : Fsym*) && is(Fsym == function) || is(typeof(& func[0]) Fsym == delegate)) 337 { 338 alias FunctionTypeOf = Fsym; // HIT: (nested) function symbol 339 } 340 else static if (is(typeof(& func[0].opCall) Fobj == delegate)) 341 { 342 alias FunctionTypeOf = Fobj; // HIT: callable object 343 } 344 else static if (is(typeof(& func[0].opCall) Ftyp : Ftyp*) && is(Ftyp == function)) 345 { 346 alias FunctionTypeOf = Ftyp; // HIT: callable type 347 } 348 else static if (is(func[0] T) || is(typeof(func[0]) T)) 349 { 350 static if (is(T == function)) 351 alias FunctionTypeOf = T; // HIT: function 352 else static if (is(T Fptr : Fptr*) && is(Fptr == function)) 353 alias FunctionTypeOf = Fptr; // HIT: function pointer 354 else static if (is(T Fdlg == delegate)) 355 alias FunctionTypeOf = Fdlg; // HIT: delegate 356 else 357 static assert(0); 358 } 359 else 360 static assert(0); 361 }