The OpenD Programming Language

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 }