1 module mir.internal.meta; 2 3 /++ 4 Determine if a symbol has a given 5 $(DDSUBLINK spec/attribute, uda, user-defined attribute). 6 7 See_Also: 8 $(LREF getUDAs) 9 +/ 10 enum hasUDA(alias symbol, alias attribute) = getUDAs!(symbol, attribute).length != 0; 11 12 /// 13 @safe unittest 14 { 15 enum E; 16 struct S {} 17 18 @("alpha") int a; 19 static assert(hasUDA!(a, "alpha")); 20 static assert(!hasUDA!(a, S)); 21 static assert(!hasUDA!(a, E)); 22 23 @(E) int b; 24 static assert(!hasUDA!(b, "alpha")); 25 static assert(!hasUDA!(b, S)); 26 static assert(hasUDA!(b, E)); 27 28 @E int c; 29 static assert(!hasUDA!(c, "alpha")); 30 static assert(!hasUDA!(c, S)); 31 static assert(hasUDA!(c, E)); 32 33 @(S, E) int d; 34 static assert(!hasUDA!(d, "alpha")); 35 static assert(hasUDA!(d, S)); 36 static assert(hasUDA!(d, E)); 37 38 @S int e; 39 static assert(!hasUDA!(e, "alpha")); 40 static assert(hasUDA!(e, S)); 41 static assert(!hasUDA!(e, S())); 42 static assert(!hasUDA!(e, E)); 43 44 @S() int f; 45 static assert(!hasUDA!(f, "alpha")); 46 static assert(hasUDA!(f, S)); 47 static assert(hasUDA!(f, S())); 48 static assert(!hasUDA!(f, E)); 49 50 @(S, E, "alpha") int g; 51 static assert(hasUDA!(g, "alpha")); 52 static assert(hasUDA!(g, S)); 53 static assert(hasUDA!(g, E)); 54 55 @(100) int h; 56 static assert(hasUDA!(h, 100)); 57 58 struct Named { string name; } 59 60 @Named("abc") int i; 61 static assert(hasUDA!(i, Named)); 62 static assert(hasUDA!(i, Named("abc"))); 63 static assert(!hasUDA!(i, Named("def"))); 64 65 struct AttrT(T) 66 { 67 string name; 68 T value; 69 } 70 71 @AttrT!int("answer", 42) int j; 72 static assert(hasUDA!(j, AttrT)); 73 static assert(hasUDA!(j, AttrT!int)); 74 static assert(!hasUDA!(j, AttrT!string)); 75 76 @AttrT!string("hello", "world") int k; 77 static assert(hasUDA!(k, AttrT)); 78 static assert(!hasUDA!(k, AttrT!int)); 79 static assert(hasUDA!(k, AttrT!string)); 80 81 struct FuncAttr(alias f) { alias func = f; } 82 static int fourtyTwo() { return 42; } 83 static size_t getLen(string s) { return s.length; } 84 85 @FuncAttr!getLen int l; 86 static assert(hasUDA!(l, FuncAttr)); 87 static assert(!hasUDA!(l, FuncAttr!fourtyTwo)); 88 static assert(hasUDA!(l, FuncAttr!getLen)); 89 static assert(!hasUDA!(l, FuncAttr!fourtyTwo())); 90 static assert(!hasUDA!(l, FuncAttr!getLen())); 91 92 @FuncAttr!getLen() int m; 93 static assert(hasUDA!(m, FuncAttr)); 94 static assert(!hasUDA!(m, FuncAttr!fourtyTwo)); 95 static assert(hasUDA!(m, FuncAttr!getLen)); 96 static assert(!hasUDA!(m, FuncAttr!fourtyTwo())); 97 static assert(hasUDA!(m, FuncAttr!getLen())); 98 } 99 100 /++ 101 Gets the matching $(DDSUBLINK spec/attribute, uda, user-defined attributes) 102 from the given symbol. 103 104 If the UDA is a type, then any UDAs of the same type on the symbol will 105 match. If the UDA is a template for a type, then any UDA which is an 106 instantiation of that template will match. And if the UDA is a value, 107 then any UDAs on the symbol which are equal to that value will match. 108 109 See_Also: 110 $(LREF hasUDA) 111 +/ 112 template getUDAs(alias symbol, alias attribute) 113 { 114 import std.meta : Filter, AliasSeq, staticMap; 115 116 static if (AliasSeq!symbol.length != 1) 117 alias getUDAs = AliasSeq!(); 118 else 119 static if (__traits(compiles, __traits(getAttributes, symbol))) 120 alias getUDAs = Filter!(isDesiredUDA!attribute, __traits(getAttributes, symbol)); 121 else 122 alias getUDAs = AliasSeq!(); 123 } 124 125 /// 126 @safe unittest 127 { 128 struct Attr 129 { 130 string name; 131 int value; 132 } 133 134 @Attr("Answer", 42) int a; 135 static assert(getUDAs!(a, Attr).length == 1); 136 static assert(getUDAs!(a, Attr)[0].name == "Answer"); 137 static assert(getUDAs!(a, Attr)[0].value == 42); 138 139 @(Attr("Answer", 42), "string", 9999) int b; 140 static assert(getUDAs!(b, Attr).length == 1); 141 static assert(getUDAs!(b, Attr)[0].name == "Answer"); 142 static assert(getUDAs!(b, Attr)[0].value == 42); 143 144 @Attr("Answer", 42) @Attr("Pi", 3) int c; 145 static assert(getUDAs!(c, Attr).length == 2); 146 static assert(getUDAs!(c, Attr)[0].name == "Answer"); 147 static assert(getUDAs!(c, Attr)[0].value == 42); 148 static assert(getUDAs!(c, Attr)[1].name == "Pi"); 149 static assert(getUDAs!(c, Attr)[1].value == 3); 150 151 static assert(getUDAs!(c, Attr("Answer", 42)).length == 1); 152 static assert(getUDAs!(c, Attr("Answer", 42))[0].name == "Answer"); 153 static assert(getUDAs!(c, Attr("Answer", 42))[0].value == 42); 154 155 static assert(getUDAs!(c, Attr("Answer", 99)).length == 0); 156 157 struct AttrT(T) 158 { 159 string name; 160 T value; 161 } 162 163 @AttrT!uint("Answer", 42) @AttrT!int("Pi", 3) @AttrT int d; 164 static assert(getUDAs!(d, AttrT).length == 2); 165 static assert(getUDAs!(d, AttrT)[0].name == "Answer"); 166 static assert(getUDAs!(d, AttrT)[0].value == 42); 167 static assert(getUDAs!(d, AttrT)[1].name == "Pi"); 168 static assert(getUDAs!(d, AttrT)[1].value == 3); 169 170 static assert(getUDAs!(d, AttrT!uint).length == 1); 171 static assert(getUDAs!(d, AttrT!uint)[0].name == "Answer"); 172 static assert(getUDAs!(d, AttrT!uint)[0].value == 42); 173 174 static assert(getUDAs!(d, AttrT!int).length == 1); 175 static assert(getUDAs!(d, AttrT!int)[0].name == "Pi"); 176 static assert(getUDAs!(d, AttrT!int)[0].value == 3); 177 178 struct SimpleAttr {} 179 180 @SimpleAttr int e; 181 static assert(getUDAs!(e, SimpleAttr).length == 1); 182 static assert(is(getUDAs!(e, SimpleAttr)[0] == SimpleAttr)); 183 184 @SimpleAttr() int f; 185 static assert(getUDAs!(f, SimpleAttr).length == 1); 186 static assert(is(typeof(getUDAs!(f, SimpleAttr)[0]) == SimpleAttr)); 187 188 struct FuncAttr(alias f) { alias func = f; } 189 static int add42(int v) { return v + 42; } 190 static string concat(string l, string r) { return l ~ r; } 191 192 @FuncAttr!add42 int g; 193 static assert(getUDAs!(g, FuncAttr).length == 1); 194 static assert(getUDAs!(g, FuncAttr)[0].func(5) == 47); 195 196 static assert(getUDAs!(g, FuncAttr!add42).length == 1); 197 static assert(getUDAs!(g, FuncAttr!add42)[0].func(5) == 47); 198 199 static assert(getUDAs!(g, FuncAttr!add42()).length == 0); 200 201 static assert(getUDAs!(g, FuncAttr!concat).length == 0); 202 static assert(getUDAs!(g, FuncAttr!concat()).length == 0); 203 204 @FuncAttr!add42() int h; 205 static assert(getUDAs!(h, FuncAttr).length == 1); 206 static assert(getUDAs!(h, FuncAttr)[0].func(5) == 47); 207 208 static assert(getUDAs!(h, FuncAttr!add42).length == 1); 209 static assert(getUDAs!(h, FuncAttr!add42)[0].func(5) == 47); 210 211 static assert(getUDAs!(h, FuncAttr!add42()).length == 1); 212 static assert(getUDAs!(h, FuncAttr!add42())[0].func(5) == 47); 213 214 static assert(getUDAs!(h, FuncAttr!concat).length == 0); 215 static assert(getUDAs!(h, FuncAttr!concat()).length == 0); 216 217 @("alpha") @(42) int i; 218 static assert(getUDAs!(i, "alpha").length == 1); 219 static assert(getUDAs!(i, "alpha")[0] == "alpha"); 220 221 static assert(getUDAs!(i, 42).length == 1); 222 static assert(getUDAs!(i, 42)[0] == 42); 223 224 static assert(getUDAs!(i, 'c').length == 0); 225 } 226 227 private template isFunction(T, string member) 228 { 229 static if (is(typeof(&__traits(getMember, T, member)) U : U*) && is(U == function) || 230 is(typeof(&__traits(getMember, T, member)) U == delegate)) 231 { 232 // x is a (nested) function symbol. 233 enum isFunction = true; 234 } 235 else static if (is(__traits(getMember, T, member) T)) 236 { 237 // x is a type. Take the type of it and examine. 238 enum isFunction = is(T == function); 239 } 240 else 241 enum isFunction = false; 242 } 243 244 private template autoGetUDAs(alias symbol) 245 { 246 import std.meta : AliasSeq; 247 static if (__traits(compiles, __traits(getAttributes, symbol))) 248 alias autoGetUDAs = __traits(getAttributes, symbol); 249 else 250 alias autoGetUDAs = AliasSeq!(); 251 } 252 253 /++ 254 Gets the matching $(DDSUBLINK spec/attribute, uda, user-defined attributes) 255 from the given symbol. 256 If the UDA is a type, then any UDAs of the same type on the symbol will 257 match. If the UDA is a template for a type, then any UDA which is an 258 instantiation of that template will match. And if the UDA is a value, 259 then any UDAs on the symbol which are equal to that value will match. 260 See_Also: 261 $(LREF hasUDA) 262 +/ 263 template getUDAs(T, string member, alias attribute) 264 { 265 import std.meta : Filter, AliasSeq, staticMap; 266 private __gshared T* aggregate; 267 static if (!__traits(hasMember, T, member)) 268 { 269 alias getUDAs = AliasSeq!(); 270 } 271 else 272 static if (is(T == union) && !__traits(compiles, __traits(getMember, aggregate, member))) 273 { 274 275 alias getUDAs = AliasSeq!(); 276 } 277 else 278 static if (AliasSeq!(__traits(getMember, T, member)).length != 1) 279 { 280 alias getUDAs = AliasSeq!(); 281 } 282 else 283 static if (__traits(getOverloads, T, member, true).length >= 1) 284 { 285 alias getUDAsImpl(alias overload) = Filter!(isDesiredUDA!attribute, autoGetUDAs!overload); 286 alias getUDAs = staticMap!(getUDAsImpl, __traits(getOverloads, T, member, true)); 287 } 288 else 289 { 290 alias getUDAs = Filter!(isDesiredUDA!attribute, __traits(getAttributes, __traits(getMember, T, member))); 291 } 292 } 293 294 /++ 295 Determine if a symbol has a given 296 $(DDSUBLINK spec/attribute, uda, user-defined attribute). 297 See_Also: 298 $(LREF getUDAs) 299 +/ 300 enum hasUDA(T, string member, alias attribute) = getUDAs!(T, member, attribute).length != 0; 301 302 303 private template isDesiredUDA(alias attribute) 304 { 305 template isDesiredUDA(alias toCheck) 306 { 307 import std.traits: isInstanceOf; 308 static if (is(typeof(attribute)) && !__traits(isTemplate, attribute)) 309 { 310 static if (__traits(compiles, toCheck == attribute)) 311 enum isDesiredUDA = toCheck == attribute; 312 else 313 enum isDesiredUDA = false; 314 } 315 else static if (is(typeof(toCheck))) 316 { 317 static if (__traits(isTemplate, attribute)) 318 enum isDesiredUDA = isInstanceOf!(attribute, typeof(toCheck)); 319 else 320 enum isDesiredUDA = is(typeof(toCheck) == attribute); 321 } 322 else static if (__traits(isTemplate, attribute)) 323 enum isDesiredUDA = isInstanceOf!(attribute, toCheck); 324 else 325 enum isDesiredUDA = is(toCheck == attribute); 326 } 327 } 328 329 template memberTypeOf(T, string member) 330 { 331 private __gshared T* aggregate; 332 alias memberTypeOf = typeof(__traits(getMember, aggregate, member)); 333 } 334 335 template isMemberType(T, string member) 336 { 337 enum isMemberType = is(typeof((ref __traits(getMember, T, member) v){})) || is(__traits(getMember, T, member) : void); 338 } 339 340 template isSingleMember(T, string member) 341 { 342 import std.meta: AliasSeq; 343 enum isSingleMember = AliasSeq!(__traits(getMember, T, member)).length == 1; 344 } 345 346 template AllMembersRec(T) 347 { 348 static if (is(T == class) || is(T == struct) || is(T == union) || is(T == interface)) 349 { 350 static if (__traits(getAliasThis, T).length) 351 { 352 private __gshared T* aggregate; 353 static if (is(typeof(__traits(getMember, aggregate, __traits(getAliasThis, T))))) 354 { 355 import std.meta: Filter, AliasSeq; 356 alias baseMembers = AllMembersRec!(typeof(__traits(getMember, aggregate, __traits(getAliasThis, T)))); 357 alias members = Erase!(__traits(getAliasThis, T)[0], __traits(allMembers, T)); 358 alias AllMembersRec = NoDuplicates!(AliasSeq!(baseMembers, members)); 359 } 360 else 361 { 362 alias AllMembersRec = __traits(allMembers, T); 363 } 364 } 365 else 366 { 367 alias AllMembersRec = __traits(allMembers, T); 368 } 369 } 370 else 371 { 372 import std.meta: AliasSeq; 373 alias AllMembersRec = AliasSeq!(); 374 } 375 } 376 377 alias ConstOf(T) = const T; 378 enum Alignof(T) = T.alignof; 379 enum canConstructWith(From, To) = __traits(compiles, (From a) { To b = a; } ); 380 enum canImplicitlyRemoveConst(T) = __traits(compiles, {static T _function_(ref const T a) { return a; }} ); 381 enum canRemoveConst(T) = canConstructWith!(const T, T); 382 enum canRemoveImmutable(T) = canConstructWith!(immutable T, T); 383 enum hasOpPostMove(T) = __traits(hasMember, T, "opPostMove"); 384 enum hasOpCmp(T) = __traits(hasMember, T, "opCmp"); 385 enum hasToHash(T) = __traits(hasMember, T, "toHash"); 386 static if (__VERSION__ < 2094) 387 enum isCopyable(S) = is(typeof({ S foo = S.init; S copy = foo; })); 388 else 389 enum isCopyable(S) = __traits(isCopyable, S); 390 enum isPOD(T) = __traits(isPOD, T); 391 enum Sizeof(T) = T.sizeof; 392 393 enum hasInoutConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope inout S rhs) inout { this.a = rhs.a; } }} ); 394 enum hasConstConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope const S rhs) const { this.a = rhs.a; } }} ); 395 enum hasImmutableConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope immutable S rhs) immutable { this.a = rhs.a; } }} ); 396 enum hasMutableConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope S rhs) { this.a = rhs.a; } }} ); 397 enum hasSemiImmutableConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope const S rhs) immutable { this.a = rhs.a; } }} ); 398 enum hasSemiMutableConstruction(T) = __traits(compiles, {static struct S { T a; this(ref return scope const S rhs) { this.a = rhs.a; } }} ); 399 400 @safe version(mir_core_test) unittest 401 { 402 static struct S { this(ref return scope inout S) inout {} } 403 static inout(S) _function_(ref inout S a) { return a; } 404 static struct C2 { uint* a; this(ref return scope const S) const {} } 405 static assert(hasInoutConstruction!uint); 406 static assert(hasInoutConstruction!(immutable(uint)[])); 407 static assert(hasInoutConstruction!(typeof(null))); 408 static assert(hasInoutConstruction!S); 409 } 410 411 template staticIsSorted(alias cmp, Seq...) 412 { 413 static if (Seq.length <= 1) 414 enum staticIsSorted = true; 415 else static if (Seq.length == 2) 416 enum staticIsSorted = cmp!(Seq[0], Seq[1]); 417 else 418 { 419 enum staticIsSorted = 420 cmp!(Seq[($ / 2) - 1], Seq[$ / 2]) && 421 staticIsSorted!(cmp, Seq[0 .. $ / 2]) && 422 staticIsSorted!(cmp, Seq[$ / 2 .. $]); 423 } 424 } 425 426 template TryRemoveConst(T) 427 { 428 import std.traits: Unqual; 429 alias U = Unqual!T; 430 static if (canImplicitlyRemoveConst!U) 431 { 432 alias TryRemoveConst = U; 433 } 434 else 435 { 436 alias TryRemoveConst = T; 437 } 438 } 439 440 441 template TypeCmp(A, B) 442 { 443 enum bool TypeCmp = is(A == B) ? false: 444 is(A == typeof(null)) ? true: 445 is(B == typeof(null)) ? false: 446 is(A == void) ? true: 447 is(B == void) ? false: 448 A.sizeof < B.sizeof ? true: 449 A.sizeof > B.sizeof ? false: 450 A.mangleof < B.mangleof; 451 } 452 453 template isInstanceOf(alias S) 454 { 455 enum isInstanceOf(T) = is(T == S!Args, Args...); 456 } 457 458 version(mir_core_test) unittest 459 { 460 static assert(is(TryRemoveConst!(const int) == int)); 461 } 462 463 464 // taken from std.meta.allSatisfy 465 template allSatisfy(alias F, T...) 466 { 467 static foreach (Ti; T) 468 { 469 static if (!is(typeof(allSatisfy) == bool) && // not yet defined 470 !F!(Ti)) 471 { 472 enum allSatisfy = false; 473 } 474 } 475 static if (!is(typeof(allSatisfy) == bool)) // if not yet defined 476 { 477 enum allSatisfy = true; 478 } 479 } 480 481 template Erase(T, TList...) 482 { 483 alias Erase = GenericErase!(T, TList).result; 484 } 485 486 template Erase(alias T, TList...) 487 { 488 alias Erase = GenericErase!(T, TList).result; 489 } 490 491 template GenericErase(args...) 492 if (args.length >= 1) 493 { 494 import std.meta: AliasSeq; 495 496 alias e = OldAlias!(args[0]); 497 alias tuple = args[1 .. $] ; 498 499 static if (tuple.length) 500 { 501 alias head = OldAlias!(tuple[0]); 502 alias tail = tuple[1 .. $]; 503 504 static if (isSame!(e, head)) 505 alias result = tail; 506 else 507 alias result = AliasSeq!(head, GenericErase!(e, tail).result); 508 } 509 else 510 { 511 alias result = AliasSeq!(); 512 } 513 } 514 515 template Pack(T...) 516 { 517 alias Expand = T; 518 enum equals(U...) = isSame!(Pack!T, Pack!U); 519 } 520 521 522 template EraseAll(T, TList...) 523 { 524 alias EraseAll = GenericEraseAll!(T, TList).result; 525 } 526 527 template EraseAll(alias T, TList...) 528 { 529 alias EraseAll = GenericEraseAll!(T, TList).result; 530 } 531 532 template GenericEraseAll(args...) 533 if (args.length >= 1) 534 { 535 import std.meta: AliasSeq; 536 537 alias e = OldAlias!(args[0]); 538 alias tuple = args[1 .. $]; 539 540 static if (tuple.length) 541 { 542 alias head = OldAlias!(tuple[0]); 543 alias tail = tuple[1 .. $]; 544 alias next = AliasSeq!( 545 GenericEraseAll!(e, tail[0..$/2]).result, 546 GenericEraseAll!(e, tail[$/2..$]).result 547 ); 548 549 static if (isSame!(e, head)) 550 alias result = next; 551 else 552 alias result = AliasSeq!(head, next); 553 } 554 else 555 { 556 alias result = AliasSeq!(); 557 } 558 } 559 560 template OldAlias(T) 561 { 562 alias OldAlias = T; 563 } 564 565 template OldAlias(alias T) 566 { 567 alias OldAlias = T; 568 } 569 570 template EraseAllN(uint N, TList...) 571 { 572 static if (N == 1) 573 { 574 alias EraseAllN = EraseAll!(TList[0], TList[1 .. $]); 575 } 576 else 577 { 578 static if (N & 1) 579 alias EraseAllN = EraseAllN!(N / 2, TList[N / 2 + 1 .. N], 580 EraseAllN!(N / 2 + 1, TList[0 .. N / 2 + 1], TList[N .. $])); 581 else 582 alias EraseAllN = EraseAllN!(N / 2, TList[N / 2 .. N], 583 EraseAllN!(N / 2, TList[0 .. N / 2], TList[N .. $])); 584 } 585 } 586 587 template NoDuplicates(TList...) 588 { 589 static if (TList.length >= 2) 590 { 591 import std.meta: AliasSeq; 592 593 alias fst = NoDuplicates!(TList[0 .. $/2]); 594 alias snd = NoDuplicates!(TList[$/2 .. $]); 595 alias NoDuplicates = AliasSeq!(fst, EraseAllN!(fst.length, fst, snd)); 596 } 597 else 598 { 599 alias NoDuplicates = TList; 600 } 601 } 602 603 604 template isSame(ab...) 605 if (ab.length == 2) 606 { 607 static if (is(ab[0]) && is(ab[1])) 608 { 609 enum isSame = is(ab[0] == ab[1]); 610 } 611 else static if (!is(ab[0]) && !is(ab[1]) && 612 !(is(typeof(&ab[0])) && is(typeof(&ab[1]))) && 613 __traits(compiles, { enum isSame = ab[0] == ab[1]; })) 614 { 615 enum isSame = (ab[0] == ab[1]); 616 } 617 else 618 { 619 enum isSame = __traits(isSame, ab[0], ab[1]); 620 } 621 } 622 623 template Mod(From, To) 624 { 625 template Mod(T) 626 { 627 static if (is(T == From)) 628 alias Mod = To; 629 else 630 alias Mod = T; 631 } 632 } 633 634 template Replace(From, To, T...) 635 { 636 import std.meta: staticMap; 637 alias Replace = staticMap!(Mod!(From, To), T); 638 } 639 640 template ReplaceTypeUnless(alias pred, From, To, T...) 641 { 642 static if (T.length == 1) 643 { 644 import std.meta: staticMap; 645 static if (pred!(T[0])) 646 alias ReplaceTypeUnless = T[0]; 647 else static if (is(T[0] == From)) 648 alias ReplaceTypeUnless = To; 649 else static if (is(T[0] == const(U), U)) 650 alias ReplaceTypeUnless = const(ReplaceTypeUnless!(pred, From, To, U)); 651 else static if (is(T[0] == immutable(U), U)) 652 alias ReplaceTypeUnless = immutable(ReplaceTypeUnless!(pred, From, To, U)); 653 else static if (is(T[0] == shared(U), U)) 654 alias ReplaceTypeUnless = shared(ReplaceTypeUnless!(pred, From, To, U)); 655 else static if (is(T[0] == U*, U)) 656 { 657 static if (is(U == function)) 658 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]); 659 else 660 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)*; 661 } 662 else static if (is(T[0] == delegate)) 663 { 664 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]); 665 } 666 else static if (is(T[0] == function)) 667 { 668 static assert(0, "Function types not supported," ~ 669 " use a function pointer type instead of " ~ T[0].stringof); 670 } 671 else static if (is(T[0] == U!V, alias U, V...)) 672 { 673 template replaceTemplateArgs(T...) 674 { 675 static if (is(typeof(T[0]))) 676 static if (__traits(compiles, {alias replaceTemplateArgs = T[0];})) 677 alias replaceTemplateArgs = T[0]; 678 else 679 enum replaceTemplateArgs = T[0]; 680 else 681 alias replaceTemplateArgs = ReplaceTypeUnless!(pred, From, To, T[0]); 682 } 683 alias ReplaceTypeUnless = U!(staticMap!(replaceTemplateArgs, V)); 684 } 685 else static if (is(T[0] == struct)) 686 // don't match with alias this struct below 687 // https://issues.dlang.org/show_bug.cgi?id=15168 688 alias ReplaceTypeUnless = T[0]; 689 else static if (is(T[0] == enum)) 690 alias ReplaceTypeUnless = T[0]; 691 else static if (is(T[0] == U[], U)) 692 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[]; 693 else static if (is(T[0] == U[n], U, size_t n)) 694 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[n]; 695 else static if (is(T[0] == U[V], U, V)) 696 alias ReplaceTypeUnless = 697 ReplaceTypeUnless!(pred, From, To, U)[ReplaceTypeUnless!(pred, From, To, V)]; 698 else 699 alias ReplaceTypeUnless = T[0]; 700 } 701 else static if (T.length > 1) 702 { 703 import std.meta: AliasSeq; 704 alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(pred, From, To, T[0]), 705 ReplaceTypeUnless!(pred, From, To, T[1 .. $])); 706 } 707 else 708 { 709 import std.meta: AliasSeq; 710 alias ReplaceTypeUnless = AliasSeq!(); 711 } 712 } 713 714 @safe version(mir_core_test) unittest 715 { 716 import std.typecons: Tuple; 717 import std.traits : isArray; 718 static assert( 719 is(ReplaceTypeUnless!(isArray, int, string, int*) == string*) && 720 is(ReplaceTypeUnless!(isArray, int, string, int[]) == int[]) && 721 is(ReplaceTypeUnless!(isArray, int, string, Tuple!(int, int[])) 722 == Tuple!(string, int[])) 723 ); 724 } 725 726 template Contains(Types...) 727 { 728 import std.meta: staticIndexOf; 729 enum Contains(T) = staticIndexOf!(T, Types) >= 0; 730 } 731 732 template replaceTypeInFunctionTypeUnless(alias pred, From, To, fun) 733 { 734 import std.meta; 735 import std.traits; 736 alias RX = ReplaceTypeUnless!(pred, From, To, ReturnType!fun); 737 alias PX = AliasSeq!(ReplaceTypeUnless!(pred, From, To, Parameters!fun)); 738 // Wrapping with AliasSeq is neccesary because ReplaceType doesn't return 739 // tuple if Parameters!fun.length == 1 740 string gen() 741 { 742 enum linkage = functionLinkage!fun; 743 alias attributes = functionAttributes!fun; 744 enum variadicStyle = variadicFunctionStyle!fun; 745 alias storageClasses = ParameterStorageClassTuple!fun; 746 string result; 747 result ~= "extern(" ~ linkage ~ ") "; 748 static if (attributes & FunctionAttribute.ref_) 749 { 750 result ~= "ref "; 751 } 752 result ~= "RX"; 753 static if (is(fun == delegate)) 754 result ~= " delegate"; 755 else 756 result ~= " function"; 757 result ~= "("; 758 static foreach (i; 0 .. PX.length) 759 { 760 if (i) 761 result ~= ", "; 762 if (storageClasses[i] & ParameterStorageClass.scope_) 763 result ~= "scope "; 764 if (storageClasses[i] & ParameterStorageClass.out_) 765 result ~= "out "; 766 if (storageClasses[i] & ParameterStorageClass.ref_) 767 result ~= "ref "; 768 if (storageClasses[i] & ParameterStorageClass.lazy_) 769 result ~= "lazy "; 770 if (storageClasses[i] & ParameterStorageClass.return_) 771 result ~= "return "; 772 result ~= "PX[" ~ i.stringof ~ "]"; 773 } 774 static if (variadicStyle == Variadic.typesafe) 775 result ~= " ..."; 776 else static if (variadicStyle != Variadic.no) 777 result ~= ", ..."; 778 result ~= ")"; 779 static if (attributes & FunctionAttribute.pure_) 780 result ~= " pure"; 781 static if (attributes & FunctionAttribute.nothrow_) 782 result ~= " nothrow"; 783 static if (attributes & FunctionAttribute.property) 784 result ~= " @property"; 785 static if (attributes & FunctionAttribute.trusted) 786 result ~= " @trusted"; 787 static if (attributes & FunctionAttribute.safe) 788 result ~= " @safe"; 789 static if (attributes & FunctionAttribute.nogc) 790 result ~= " @nogc"; 791 static if (attributes & FunctionAttribute.system) 792 result ~= " @system"; 793 static if (attributes & FunctionAttribute.const_) 794 result ~= " const"; 795 static if (attributes & FunctionAttribute.immutable_) 796 result ~= " immutable"; 797 static if (attributes & FunctionAttribute.inout_) 798 result ~= " inout"; 799 static if (attributes & FunctionAttribute.shared_) 800 result ~= " shared"; 801 static if (attributes & FunctionAttribute.return_) 802 result ~= " return"; 803 return result; 804 } 805 mixin("alias replaceTypeInFunctionTypeUnless = " ~ gen() ~ ";"); 806 } 807 808 enum false_(T) = false; 809 810 alias ReplaceType(From, To, T...) = ReplaceTypeUnless!(false_, From, To, T); 811 812 version(mir_core_test) @safe unittest 813 { 814 import std.typecons: Unique, Tuple; 815 template Test(Ts...) 816 { 817 static if (Ts.length) 818 { 819 //pragma(msg, "Testing: ReplaceType!("~Ts[0].stringof~", " 820 // ~Ts[1].stringof~", "~Ts[2].stringof~")"); 821 static assert(is(ReplaceType!(Ts[0], Ts[1], Ts[2]) == Ts[3]), 822 "ReplaceType!("~Ts[0].stringof~", "~Ts[1].stringof~", " 823 ~Ts[2].stringof~") == " 824 ~ReplaceType!(Ts[0], Ts[1], Ts[2]).stringof); 825 alias Test = Test!(Ts[4 .. $]); 826 } 827 else alias Test = void; 828 } 829 //import core.stdc.stdio; 830 alias RefFun1 = ref int function(float, long); 831 alias RefFun2 = ref float function(float, long); 832 extern(C) int printf(const char*, ...) nothrow @nogc @system; 833 extern(C) float floatPrintf(const char*, ...) nothrow @nogc @system; 834 int func(float); 835 int x; 836 struct S1 { void foo() { x = 1; } } 837 struct S2 { void bar() { x = 2; } } 838 alias Pass = Test!( 839 int, float, typeof(&func), float delegate(float), 840 int, float, typeof(&printf), typeof(&floatPrintf), 841 int, float, int function(out long, ...), 842 float function(out long, ...), 843 int, float, int function(ref float, long), 844 float function(ref float, long), 845 int, float, int function(ref int, long), 846 float function(ref float, long), 847 int, float, int function(out int, long), 848 float function(out float, long), 849 int, float, int function(lazy int, long), 850 float function(lazy float, long), 851 int, float, int function(out long, ref const int), 852 float function(out long, ref const float), 853 int, int, int, int, 854 int, float, int, float, 855 int, float, const int, const float, 856 int, float, immutable int, immutable float, 857 int, float, shared int, shared float, 858 int, float, int*, float*, 859 int, float, const(int)*, const(float)*, 860 int, float, const(int*), const(float*), 861 const(int)*, float, const(int*), const(float), 862 int*, float, const(int)*, const(int)*, 863 int, float, int[], float[], 864 int, float, int[42], float[42], 865 int, float, const(int)[42], const(float)[42], 866 int, float, const(int[42]), const(float[42]), 867 int, float, int[int], float[float], 868 int, float, int[double], float[double], 869 int, float, double[int], double[float], 870 int, float, int function(float, long), float function(float, long), 871 int, float, int function(float), float function(float), 872 int, float, int function(float, int), float function(float, float), 873 int, float, int delegate(float, long), float delegate(float, long), 874 int, float, int delegate(float), float delegate(float), 875 int, float, int delegate(float, int), float delegate(float, float), 876 int, float, Unique!int, Unique!float, 877 int, float, Tuple!(float, int), Tuple!(float, float), 878 int, float, RefFun1, RefFun2, 879 S1, S2, 880 S1[1][][S1]* function(), 881 S2[1][][S2]* function(), 882 int, string, 883 int[3] function( int[] arr, int[2] ...) pure @trusted, 884 string[3] function(string[] arr, string[2] ...) pure @trusted, 885 ); 886 // https://issues.dlang.org/show_bug.cgi?id=15168 887 static struct T1 { string s; alias s this; } 888 static struct T2 { char[10] s; alias s this; } 889 static struct T3 { string[string] s; alias s this; } 890 alias Pass2 = Test!( 891 ubyte, ubyte, T1, T1, 892 ubyte, ubyte, T2, T2, 893 ubyte, ubyte, T3, T3, 894 ); 895 } 896 // https://issues.dlang.org/show_bug.cgi?id=17116 897 version(mir_core_test) @safe unittest 898 { 899 alias ConstDg = void delegate(float) const; 900 alias B = void delegate(int) const; 901 alias A = ReplaceType!(float, int, ConstDg); 902 static assert(is(B == A)); 903 } 904 // https://issues.dlang.org/show_bug.cgi?id=19696 905 version(mir_core_test) @safe unittest 906 { 907 static struct T(U) {} 908 static struct S { T!int t; alias t this; } 909 static assert(is(ReplaceType!(float, float, S) == S)); 910 } 911 // https://issues.dlang.org/show_bug.cgi?id=19697 912 version(mir_core_test) @safe unittest 913 { 914 class D(T) {} 915 class C : D!C {} 916 static assert(is(ReplaceType!(float, float, C))); 917 } 918 // https://issues.dlang.org/show_bug.cgi?id=16132 919 version(mir_core_test) @safe unittest 920 { 921 interface I(T) {} 922 class C : I!int {} 923 static assert(is(ReplaceType!(int, string, C) == C)); 924 } 925 926 template basicElementType(T) 927 { 928 import std.traits: isArray, ForeachType; 929 static if (isArray!T) 930 alias basicElementType = ForeachType!T; 931 else 932 alias basicElementType = T; 933 }