1 /**
2  * Contains traits for runtime internal usage.
3  *
4  * Copyright: Copyright Digital Mars 2014 -.
5  * License:   $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6  * Authors:   Martin Nowak
7  * Source: $(DRUNTIMESRC core/internal/_traits.d)
8  */
9 module core.internal.traits;
10 
11 /// taken from std.typetuple.TypeTuple
TypeTuple(TList...)12 template TypeTuple(TList...)
13 {
14     alias TypeTuple = TList;
15 }
16 
trustedCast(T,U)17 T trustedCast(T, U)(auto ref U u) @trusted pure nothrow
18 {
19     return cast(T)u;
20 }
21 
Unconst(T)22 template Unconst(T)
23 {
24          static if (is(T U ==   immutable U)) alias Unconst = U;
25     else static if (is(T U == inout const U)) alias Unconst = U;
26     else static if (is(T U == inout       U)) alias Unconst = U;
27     else static if (is(T U ==       const U)) alias Unconst = U;
28     else                                      alias Unconst = T;
29 }
30 
31 /// taken from std.traits.Unqual
Unqual(T)32 template Unqual(T)
33 {
34     version (none) // Error: recursive alias declaration @@@BUG1308@@@
35     {
36              static if (is(T U ==     const U)) alias Unqual = Unqual!U;
37         else static if (is(T U == immutable U)) alias Unqual = Unqual!U;
38         else static if (is(T U ==     inout U)) alias Unqual = Unqual!U;
39         else static if (is(T U ==    shared U)) alias Unqual = Unqual!U;
40         else                                    alias Unqual =        T;
41     }
42     else // workaround
43     {
44              static if (is(T U ==          immutable U)) alias Unqual = U;
45         else static if (is(T U == shared inout const U)) alias Unqual = U;
46         else static if (is(T U == shared inout       U)) alias Unqual = U;
47         else static if (is(T U == shared       const U)) alias Unqual = U;
48         else static if (is(T U == shared             U)) alias Unqual = U;
49         else static if (is(T U ==        inout const U)) alias Unqual = U;
50         else static if (is(T U ==        inout       U)) alias Unqual = U;
51         else static if (is(T U ==              const U)) alias Unqual = U;
52         else                                             alias Unqual = T;
53     }
54 }
55 
56 // Substitute all `inout` qualifiers that appears in T to `const`
substInout(T)57 template substInout(T)
58 {
59     static if (is(T == immutable))
60     {
61         alias substInout = T;
62     }
63     else static if (is(T : shared const U, U) || is(T : const U, U))
64     {
65         // U is top-unqualified
66         mixin("alias substInout = "
67             ~ (is(T == shared) ? "shared " : "")
68             ~ (is(T == const) || is(T == inout) ? "const " : "")    // substitute inout to const
69             ~ "substInoutForm!U;");
70     }
71     else
72         static assert(0);
73 }
74 
substInoutForm(T)75 private template substInoutForm(T)
76 {
77     static if (is(T == struct) || is(T == class) || is(T == union) || is(T == interface))
78     {
79         alias substInoutForm = T;   // prevent matching to the form of alias-this-ed type
80     }
81     else static if (is(T : V[K], K, V))        alias substInoutForm = substInout!V[substInout!K];
82     else static if (is(T : U[n], U, size_t n)) alias substInoutForm = substInout!U[n];
83     else static if (is(T : U[], U))            alias substInoutForm = substInout!U[];
84     else static if (is(T : U*, U))             alias substInoutForm = substInout!U*;
85     else                                       alias substInoutForm = T;
86 }
87 
88 /// used to declare an extern(D) function that is defined in a different module
89 template externDFunc(string fqn, T:FT*, FT) if (is(FT == function))
90 {
91     static if (is(FT RT == return) && is(FT Args == function))
92     {
93         import core.demangle : mangleFunc;
94         enum decl = {
95             string s = "extern(D) RT externDFunc(Args)";
96             foreach (attr; __traits(getFunctionAttributes, FT))
97                 s ~= " " ~ attr;
98             return s ~ ";";
99         }();
100         pragma(mangle, mangleFunc!T(fqn)) mixin(decl);
101     }
102     else
103         static assert(0);
104 }
105 
staticIota(int beg,int end)106 template staticIota(int beg, int end)
107 {
108     static if (beg + 1 >= end)
109     {
110         static if (beg >= end)
111         {
112             alias staticIota = TypeTuple!();
113         }
114         else
115         {
116             alias staticIota = TypeTuple!(+beg);
117         }
118     }
119     else
120     {
121         enum mid = beg + (end - beg) / 2;
122         alias staticIota = TypeTuple!(staticIota!(beg, mid), staticIota!(mid, end));
123     }
124 }
125 
dtorIsNothrow(T)126 template dtorIsNothrow(T)
127 {
128     enum dtorIsNothrow = is(typeof(function{T t=void;}) : void function() nothrow);
129 }
130 
131 /*
132 Tests whether all given items satisfy a template predicate, i.e. evaluates to
133 $(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])).
134 */
135 package(core.internal)
allSatisfy(alias F,T...)136 template allSatisfy(alias F, T...)
137 {
138     static if (T.length == 0)
139     {
140         enum allSatisfy = true;
141     }
142     else static if (T.length == 1)
143     {
144         enum allSatisfy = F!(T[0]);
145     }
146     else
147     {
148         static if (allSatisfy!(F, T[0  .. $/2]))
149             enum allSatisfy = allSatisfy!(F, T[$/2 .. $]);
150         else
151             enum allSatisfy = false;
152     }
153 }
154 
anySatisfy(alias F,T...)155 template anySatisfy(alias F, T...)
156 {
157     static if (T.length == 0)
158     {
159         enum anySatisfy = false;
160     }
161     else static if (T.length == 1)
162     {
163         enum anySatisfy = F!(T[0]);
164     }
165     else
166     {
167         enum anySatisfy =
168             anySatisfy!(F, T[ 0  .. $/2]) ||
169             anySatisfy!(F, T[$/2 ..  $ ]);
170     }
171 }
172 
173 // simplified from std.traits.maxAlignment
maxAlignment(U...)174 template maxAlignment(U...)
175 {
176     static if (U.length == 0)
177         static assert(0);
178     else static if (U.length == 1)
179         enum maxAlignment = U[0].alignof;
180     else static if (U.length == 2)
181         enum maxAlignment = U[0].alignof > U[1].alignof ? U[0].alignof : U[1].alignof;
182     else
183     {
184         enum a = maxAlignment!(U[0 .. ($+1)/2]);
185         enum b = maxAlignment!(U[($+1)/2 .. $]);
186         enum maxAlignment = a > b ? a : b;
187     }
188 }
189 
190 template classInstanceAlignment(T)
191 if (is(T == class))
192 {
193     alias classInstanceAlignment = maxAlignment!(void*, typeof(T.tupleof));
194 }
195 
196 // Somehow fails for non-static nested structs without support for aliases
hasElaborateDestructor(T...)197 template hasElaborateDestructor(T...)
198 {
199     static if (is(T[0]))
200         alias S = T[0];
201     else
202         alias S = typeof(T[0]);
203 
204     static if (is(S : E[n], E, size_t n) && S.length)
205     {
206         enum bool hasElaborateDestructor = hasElaborateDestructor!E;
207     }
208     else static if (is(S == struct))
209     {
210         enum hasElaborateDestructor = __traits(hasMember, S, "__dtor")
211             || anySatisfy!(.hasElaborateDestructor, S.tupleof);
212     }
213     else
214         enum bool hasElaborateDestructor = false;
215 }
216 
217 // Somehow fails for non-static nested structs without support for aliases
hasElaborateCopyConstructor(T...)218 template hasElaborateCopyConstructor(T...)
219 {
220     static if (is(T[0]))
221         alias S = T[0];
222     else
223         alias S = typeof(T[0]);
224 
225     static if (is(S : E[n], E, size_t n) && S.length)
226     {
227         enum bool hasElaborateCopyConstructor = hasElaborateCopyConstructor!E;
228     }
229     else static if (is(S == struct))
230     {
231         enum hasElaborateCopyConstructor = __traits(hasMember, S, "__postblit")
232             || anySatisfy!(.hasElaborateCopyConstructor, S.tupleof);
233     }
234     else
235         enum bool hasElaborateCopyConstructor = false;
236 }
237 
238 // std.meta.Filter
Filter(alias pred,TList...)239 template Filter(alias pred, TList...)
240 {
241     static if (TList.length == 0)
242     {
243         alias Filter = TypeTuple!();
244     }
245     else static if (TList.length == 1)
246     {
247         static if (pred!(TList[0]))
248             alias Filter = TypeTuple!(TList[0]);
249         else
250             alias Filter = TypeTuple!();
251     }
252     else
253     {
254         alias Filter =
255             TypeTuple!(
256                 Filter!(pred, TList[ 0  .. $/2]),
257                 Filter!(pred, TList[$/2 ..  $ ]));
258     }
259 }
260