1 module mir.internal.meta; 2 3 template memberTypeOf(T, string member) 4 { 5 T* aggregate; 6 alias memberTypeOf = typeof(__traits(getMember, aggregate, member)); 7 } 8 9 template isMemberType(T, string member) 10 { 11 enum isMemberType = is(typeof((ref __traits(getMember, T, member) v){})) || is(__traits(getMember, T, member) : void); 12 } 13 14 template isSingleMember(T, string member) 15 { 16 import std.meta: AliasSeq; 17 enum isSingleMember = AliasSeq!(__traits(getMember, T, member)).length == 1; 18 } 19 20 template AllMembersRec(T) 21 { 22 static if (is(T == class) || is(T == struct) || is(T == union) || is(T == interface)) 23 { 24 static if (__traits(getAliasThis, T).length) 25 { 26 T* aggregate; 27 static if (is(typeof(__traits(getMember, aggregate, __traits(getAliasThis, T))))) 28 { 29 import std.meta: Filter, AliasSeq; 30 alias baseMembers = AllMembersRec!(typeof(__traits(getMember, aggregate, __traits(getAliasThis, T)))); 31 alias members = Erase!(__traits(getAliasThis, T)[0], __traits(allMembers, T)); 32 alias AllMembersRec = NoDuplicates!(AliasSeq!(baseMembers, members)); 33 } 34 else 35 { 36 alias AllMembersRec = __traits(allMembers, T); 37 } 38 } 39 else 40 { 41 alias AllMembersRec = __traits(allMembers, T); 42 } 43 } 44 else 45 { 46 import std.meta: AliasSeq; 47 alias AllMembersRec = AliasSeq!(); 48 } 49 } 50 51 alias ConstOf(T) = const T; 52 enum Alignof(T) = T.alignof; 53 enum canConstructWith(From, To) = __traits(compiles, (From a) { To b = a; } ); 54 enum canImplicitlyRemoveConst(T) = __traits(compiles, {static T _function_(ref const T a) { return a; }} ); 55 enum canRemoveConst(T) = canConstructWith!(const T, T); 56 enum canRemoveImmutable(T) = canConstructWith!(immutable T, T); 57 enum hasOpPostMove(T) = __traits(hasMember, T, "opPostMove"); 58 enum hasToHash(T) = __traits(hasMember, T, "toHash"); 59 static if (__VERSION__ < 2094) 60 enum isCopyable(S) = is(typeof({ S foo = S.init; S copy = foo; })); 61 else 62 enum isCopyable(S) = __traits(isCopyable, S); 63 enum isPOD(T) = __traits(isPOD, T); 64 enum Sizeof(T) = T.sizeof; 65 66 enum hasInoutConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope inout S rhs) inout { this.a = rhs.a; } }} ); 67 enum hasConstConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope const S rhs) const { this.a = rhs.a; } }} ); 68 enum hasImmutableConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope immutable S rhs) immutable { this.a = rhs.a; } }} ); 69 enum hasMutableConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope S rhs) { this.a = rhs.a; } }} ); 70 enum hasSemiImmutableConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope const S rhs) immutable { this.a = rhs.a; } }} ); 71 enum hasSemiMutableConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope const S rhs) { this.a = rhs.a; } }} ); 72 73 @safe version(mir_core_test) unittest 74 { 75 static struct S { this(ref return scope inout S) inout {} } 76 static inout(S) _function_(ref inout S a) { return a; } 77 static struct C2 { uint* a; this(ref return scope const S) const {} } 78 static assert(hasInoutConstruction!uint); 79 static assert(hasInoutConstruction!(immutable(uint)[])); 80 static assert(hasInoutConstruction!(typeof(null))); 81 static assert(hasInoutConstruction!S); 82 } 83 84 template staticIsSorted(alias cmp, Seq...) 85 { 86 static if (Seq.length <= 1) 87 enum staticIsSorted = true; 88 else static if (Seq.length == 2) 89 enum staticIsSorted = cmp!(Seq[0], Seq[1]); 90 else 91 { 92 enum staticIsSorted = 93 cmp!(Seq[($ / 2) - 1], Seq[$ / 2]) && 94 staticIsSorted!(cmp, Seq[0 .. $ / 2]) && 95 staticIsSorted!(cmp, Seq[$ / 2 .. $]); 96 } 97 } 98 99 template TryRemoveConst(T) 100 { 101 import std.traits: Unqual; 102 alias U = Unqual!T; 103 static if (canImplicitlyRemoveConst!U) 104 { 105 alias TryRemoveConst = U; 106 } 107 else 108 { 109 alias TryRemoveConst = T; 110 } 111 } 112 113 114 template TypeCmp(A, B) 115 { 116 enum bool TypeCmp = is(A == B) ? false: 117 is(A == typeof(null)) ? true: 118 is(B == typeof(null)) ? false: 119 is(A == void) ? true: 120 is(B == void) ? false: 121 A.sizeof < B.sizeof ? true: 122 A.sizeof > B.sizeof ? false: 123 A.mangleof < B.mangleof; 124 } 125 126 template isInstanceOf(alias S) 127 { 128 enum isInstanceOf(T) = is(T == S!Args, Args...); 129 } 130 131 version(mir_core_test) unittest 132 { 133 static assert(is(TryRemoveConst!(const int) == int)); 134 } 135 136 137 // taken from std.meta.allSatisfy 138 template allSatisfy(alias F, T...) 139 { 140 static foreach (Ti; T) 141 { 142 static if (!is(typeof(allSatisfy) == bool) && // not yet defined 143 !F!(Ti)) 144 { 145 enum allSatisfy = false; 146 } 147 } 148 static if (!is(typeof(allSatisfy) == bool)) // if not yet defined 149 { 150 enum allSatisfy = true; 151 } 152 } 153 154 template Erase(T, TList...) 155 { 156 alias Erase = GenericErase!(T, TList).result; 157 } 158 159 template Erase(alias T, TList...) 160 { 161 alias Erase = GenericErase!(T, TList).result; 162 } 163 164 template GenericErase(args...) 165 if (args.length >= 1) 166 { 167 import std.meta: AliasSeq; 168 169 alias e = OldAlias!(args[0]); 170 alias tuple = args[1 .. $] ; 171 172 static if (tuple.length) 173 { 174 alias head = OldAlias!(tuple[0]); 175 alias tail = tuple[1 .. $]; 176 177 static if (isSame!(e, head)) 178 alias result = tail; 179 else 180 alias result = AliasSeq!(head, GenericErase!(e, tail).result); 181 } 182 else 183 { 184 alias result = AliasSeq!(); 185 } 186 } 187 188 template Pack(T...) 189 { 190 alias Expand = T; 191 enum equals(U...) = isSame!(Pack!T, Pack!U); 192 } 193 194 195 template EraseAll(T, TList...) 196 { 197 alias EraseAll = GenericEraseAll!(T, TList).result; 198 } 199 200 template EraseAll(alias T, TList...) 201 { 202 alias EraseAll = GenericEraseAll!(T, TList).result; 203 } 204 205 template GenericEraseAll(args...) 206 if (args.length >= 1) 207 { 208 import std.meta: AliasSeq; 209 210 alias e = OldAlias!(args[0]); 211 alias tuple = args[1 .. $]; 212 213 static if (tuple.length) 214 { 215 alias head = OldAlias!(tuple[0]); 216 alias tail = tuple[1 .. $]; 217 alias next = AliasSeq!( 218 GenericEraseAll!(e, tail[0..$/2]).result, 219 GenericEraseAll!(e, tail[$/2..$]).result 220 ); 221 222 static if (isSame!(e, head)) 223 alias result = next; 224 else 225 alias result = AliasSeq!(head, next); 226 } 227 else 228 { 229 alias result = AliasSeq!(); 230 } 231 } 232 233 template OldAlias(T) 234 { 235 alias OldAlias = T; 236 } 237 238 template OldAlias(alias T) 239 { 240 alias OldAlias = T; 241 } 242 243 template EraseAllN(uint N, TList...) 244 { 245 static if (N == 1) 246 { 247 alias EraseAllN = EraseAll!(TList[0], TList[1 .. $]); 248 } 249 else 250 { 251 static if (N & 1) 252 alias EraseAllN = EraseAllN!(N / 2, TList[N / 2 + 1 .. N], 253 EraseAllN!(N / 2 + 1, TList[0 .. N / 2 + 1], TList[N .. $])); 254 else 255 alias EraseAllN = EraseAllN!(N / 2, TList[N / 2 .. N], 256 EraseAllN!(N / 2, TList[0 .. N / 2], TList[N .. $])); 257 } 258 } 259 260 template NoDuplicates(TList...) 261 { 262 static if (TList.length >= 2) 263 { 264 import std.meta: AliasSeq; 265 266 alias fst = NoDuplicates!(TList[0 .. $/2]); 267 alias snd = NoDuplicates!(TList[$/2 .. $]); 268 alias NoDuplicates = AliasSeq!(fst, EraseAllN!(fst.length, fst, snd)); 269 } 270 else 271 { 272 alias NoDuplicates = TList; 273 } 274 } 275 276 277 template isSame(ab...) 278 if (ab.length == 2) 279 { 280 static if (is(ab[0]) && is(ab[1])) 281 { 282 enum isSame = is(ab[0] == ab[1]); 283 } 284 else static if (!is(ab[0]) && !is(ab[1]) && 285 !(is(typeof(&ab[0])) && is(typeof(&ab[1]))) && 286 __traits(compiles, { enum isSame = ab[0] == ab[1]; })) 287 { 288 enum isSame = (ab[0] == ab[1]); 289 } 290 else 291 { 292 enum isSame = __traits(isSame, ab[0], ab[1]); 293 } 294 } 295 296 template Mod(From, To) 297 { 298 template Mod(T) 299 { 300 static if (is(T == From)) 301 alias Mod = To; 302 else 303 alias Mod = T; 304 } 305 } 306 307 template Replace(From, To, T...) 308 { 309 import std.meta: staticMap; 310 alias Replace = staticMap!(Mod!(From, To), T); 311 } 312 313 template ReplaceTypeUnless(alias pred, From, To, T...) 314 { 315 static if (T.length == 1) 316 { 317 import std.meta: staticMap; 318 static if (pred!(T[0])) 319 alias ReplaceTypeUnless = T[0]; 320 else static if (is(T[0] == From)) 321 alias ReplaceTypeUnless = To; 322 else static if (is(T[0] == const(U), U)) 323 alias ReplaceTypeUnless = const(ReplaceTypeUnless!(pred, From, To, U)); 324 else static if (is(T[0] == immutable(U), U)) 325 alias ReplaceTypeUnless = immutable(ReplaceTypeUnless!(pred, From, To, U)); 326 else static if (is(T[0] == shared(U), U)) 327 alias ReplaceTypeUnless = shared(ReplaceTypeUnless!(pred, From, To, U)); 328 else static if (is(T[0] == U*, U)) 329 { 330 static if (is(U == function)) 331 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]); 332 else 333 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)*; 334 } 335 else static if (is(T[0] == delegate)) 336 { 337 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]); 338 } 339 else static if (is(T[0] == function)) 340 { 341 static assert(0, "Function types not supported," ~ 342 " use a function pointer type instead of " ~ T[0].stringof); 343 } 344 else static if (is(T[0] == U!V, alias U, V...)) 345 { 346 template replaceTemplateArgs(T...) 347 { 348 static if (is(typeof(T[0]))) 349 static if (__traits(compiles, {alias replaceTemplateArgs = T[0];})) 350 alias replaceTemplateArgs = T[0]; 351 else 352 enum replaceTemplateArgs = T[0]; 353 else 354 alias replaceTemplateArgs = ReplaceTypeUnless!(pred, From, To, T[0]); 355 } 356 alias ReplaceTypeUnless = U!(staticMap!(replaceTemplateArgs, V)); 357 } 358 else static if (is(T[0] == struct)) 359 // don't match with alias this struct below 360 // https://issues.dlang.org/show_bug.cgi?id=15168 361 alias ReplaceTypeUnless = T[0]; 362 else static if (is(T[0] == enum)) 363 alias ReplaceTypeUnless = T[0]; 364 else static if (is(T[0] == U[], U)) 365 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[]; 366 else static if (is(T[0] == U[n], U, size_t n)) 367 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[n]; 368 else static if (is(T[0] == U[V], U, V)) 369 alias ReplaceTypeUnless = 370 ReplaceTypeUnless!(pred, From, To, U)[ReplaceTypeUnless!(pred, From, To, V)]; 371 else 372 alias ReplaceTypeUnless = T[0]; 373 } 374 else static if (T.length > 1) 375 { 376 import std.meta: AliasSeq; 377 alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(pred, From, To, T[0]), 378 ReplaceTypeUnless!(pred, From, To, T[1 .. $])); 379 } 380 else 381 { 382 import std.meta: AliasSeq; 383 alias ReplaceTypeUnless = AliasSeq!(); 384 } 385 } 386 387 @safe version(mir_core_test) unittest 388 { 389 import std.typecons: Tuple; 390 import std.traits : isArray; 391 static assert( 392 is(ReplaceTypeUnless!(isArray, int, string, int*) == string*) && 393 is(ReplaceTypeUnless!(isArray, int, string, int[]) == int[]) && 394 is(ReplaceTypeUnless!(isArray, int, string, Tuple!(int, int[])) 395 == Tuple!(string, int[])) 396 ); 397 } 398 399 template Contains(Types...) 400 { 401 import std.meta: staticIndexOf; 402 enum Contains(T) = staticIndexOf!(T, Types) >= 0; 403 } 404 405 template replaceTypeInFunctionTypeUnless(alias pred, From, To, fun) 406 { 407 import std.meta; 408 import std.traits; 409 alias RX = ReplaceTypeUnless!(pred, From, To, ReturnType!fun); 410 alias PX = AliasSeq!(ReplaceTypeUnless!(pred, From, To, Parameters!fun)); 411 // Wrapping with AliasSeq is neccesary because ReplaceType doesn't return 412 // tuple if Parameters!fun.length == 1 413 string gen() 414 { 415 enum linkage = functionLinkage!fun; 416 alias attributes = functionAttributes!fun; 417 enum variadicStyle = variadicFunctionStyle!fun; 418 alias storageClasses = ParameterStorageClassTuple!fun; 419 string result; 420 result ~= "extern(" ~ linkage ~ ") "; 421 static if (attributes & FunctionAttribute.ref_) 422 { 423 result ~= "ref "; 424 } 425 result ~= "RX"; 426 static if (is(fun == delegate)) 427 result ~= " delegate"; 428 else 429 result ~= " function"; 430 result ~= "("; 431 static foreach (i; 0 .. PX.length) 432 { 433 if (i) 434 result ~= ", "; 435 if (storageClasses[i] & ParameterStorageClass.scope_) 436 result ~= "scope "; 437 if (storageClasses[i] & ParameterStorageClass.out_) 438 result ~= "out "; 439 if (storageClasses[i] & ParameterStorageClass.ref_) 440 result ~= "ref "; 441 if (storageClasses[i] & ParameterStorageClass.lazy_) 442 result ~= "lazy "; 443 if (storageClasses[i] & ParameterStorageClass.return_) 444 result ~= "return "; 445 result ~= "PX[" ~ i.stringof ~ "]"; 446 } 447 static if (variadicStyle == Variadic.typesafe) 448 result ~= " ..."; 449 else static if (variadicStyle != Variadic.no) 450 result ~= ", ..."; 451 result ~= ")"; 452 static if (attributes & FunctionAttribute.pure_) 453 result ~= " pure"; 454 static if (attributes & FunctionAttribute.nothrow_) 455 result ~= " nothrow"; 456 static if (attributes & FunctionAttribute.property) 457 result ~= " @property"; 458 static if (attributes & FunctionAttribute.trusted) 459 result ~= " @trusted"; 460 static if (attributes & FunctionAttribute.safe) 461 result ~= " @safe"; 462 static if (attributes & FunctionAttribute.nogc) 463 result ~= " @nogc"; 464 static if (attributes & FunctionAttribute.system) 465 result ~= " @system"; 466 static if (attributes & FunctionAttribute.const_) 467 result ~= " const"; 468 static if (attributes & FunctionAttribute.immutable_) 469 result ~= " immutable"; 470 static if (attributes & FunctionAttribute.inout_) 471 result ~= " inout"; 472 static if (attributes & FunctionAttribute.shared_) 473 result ~= " shared"; 474 static if (attributes & FunctionAttribute.return_) 475 result ~= " return"; 476 return result; 477 } 478 mixin("alias replaceTypeInFunctionTypeUnless = " ~ gen() ~ ";"); 479 } 480 481 enum false_(T) = false; 482 483 alias ReplaceType(From, To, T...) = ReplaceTypeUnless!(false_, From, To, T); 484 485 version(mir_core_test) @safe unittest 486 { 487 import std.typecons: Unique, Tuple; 488 template Test(Ts...) 489 { 490 static if (Ts.length) 491 { 492 //pragma(msg, "Testing: ReplaceType!("~Ts[0].stringof~", " 493 // ~Ts[1].stringof~", "~Ts[2].stringof~")"); 494 static assert(is(ReplaceType!(Ts[0], Ts[1], Ts[2]) == Ts[3]), 495 "ReplaceType!("~Ts[0].stringof~", "~Ts[1].stringof~", " 496 ~Ts[2].stringof~") == " 497 ~ReplaceType!(Ts[0], Ts[1], Ts[2]).stringof); 498 alias Test = Test!(Ts[4 .. $]); 499 } 500 else alias Test = void; 501 } 502 //import core.stdc.stdio; 503 alias RefFun1 = ref int function(float, long); 504 alias RefFun2 = ref float function(float, long); 505 extern(C) int printf(const char*, ...) nothrow @nogc @system; 506 extern(C) float floatPrintf(const char*, ...) nothrow @nogc @system; 507 int func(float); 508 int x; 509 struct S1 { void foo() { x = 1; } } 510 struct S2 { void bar() { x = 2; } } 511 alias Pass = Test!( 512 int, float, typeof(&func), float delegate(float), 513 int, float, typeof(&printf), typeof(&floatPrintf), 514 int, float, int function(out long, ...), 515 float function(out long, ...), 516 int, float, int function(ref float, long), 517 float function(ref float, long), 518 int, float, int function(ref int, long), 519 float function(ref float, long), 520 int, float, int function(out int, long), 521 float function(out float, long), 522 int, float, int function(lazy int, long), 523 float function(lazy float, long), 524 int, float, int function(out long, ref const int), 525 float function(out long, ref const float), 526 int, int, int, int, 527 int, float, int, float, 528 int, float, const int, const float, 529 int, float, immutable int, immutable float, 530 int, float, shared int, shared float, 531 int, float, int*, float*, 532 int, float, const(int)*, const(float)*, 533 int, float, const(int*), const(float*), 534 const(int)*, float, const(int*), const(float), 535 int*, float, const(int)*, const(int)*, 536 int, float, int[], float[], 537 int, float, int[42], float[42], 538 int, float, const(int)[42], const(float)[42], 539 int, float, const(int[42]), const(float[42]), 540 int, float, int[int], float[float], 541 int, float, int[double], float[double], 542 int, float, double[int], double[float], 543 int, float, int function(float, long), float function(float, long), 544 int, float, int function(float), float function(float), 545 int, float, int function(float, int), float function(float, float), 546 int, float, int delegate(float, long), float delegate(float, long), 547 int, float, int delegate(float), float delegate(float), 548 int, float, int delegate(float, int), float delegate(float, float), 549 int, float, Unique!int, Unique!float, 550 int, float, Tuple!(float, int), Tuple!(float, float), 551 int, float, RefFun1, RefFun2, 552 S1, S2, 553 S1[1][][S1]* function(), 554 S2[1][][S2]* function(), 555 int, string, 556 int[3] function( int[] arr, int[2] ...) pure @trusted, 557 string[3] function(string[] arr, string[2] ...) pure @trusted, 558 ); 559 // https://issues.dlang.org/show_bug.cgi?id=15168 560 static struct T1 { string s; alias s this; } 561 static struct T2 { char[10] s; alias s this; } 562 static struct T3 { string[string] s; alias s this; } 563 alias Pass2 = Test!( 564 ubyte, ubyte, T1, T1, 565 ubyte, ubyte, T2, T2, 566 ubyte, ubyte, T3, T3, 567 ); 568 } 569 // https://issues.dlang.org/show_bug.cgi?id=17116 570 version(mir_core_test) @safe unittest 571 { 572 alias ConstDg = void delegate(float) const; 573 alias B = void delegate(int) const; 574 alias A = ReplaceType!(float, int, ConstDg); 575 static assert(is(B == A)); 576 } 577 // https://issues.dlang.org/show_bug.cgi?id=19696 578 version(mir_core_test) @safe unittest 579 { 580 static struct T(U) {} 581 static struct S { T!int t; alias t this; } 582 static assert(is(ReplaceType!(float, float, S) == S)); 583 } 584 // https://issues.dlang.org/show_bug.cgi?id=19697 585 version(mir_core_test) @safe unittest 586 { 587 class D(T) {} 588 class C : D!C {} 589 static assert(is(ReplaceType!(float, float, C))); 590 } 591 // https://issues.dlang.org/show_bug.cgi?id=16132 592 version(mir_core_test) @safe unittest 593 { 594 interface I(T) {} 595 class C : I!int {} 596 static assert(is(ReplaceType!(int, string, C) == C)); 597 }