1 /**
2  * Contains traits for runtime internal usage.
3  *
4  * Copyright: Copyright Digital Mars 2014 -.
5  * License:   $(HTTP 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
12 template TypeTuple(TList...)
13 {
14     alias TypeTuple = TList;
15 }
16 alias AliasSeq = TypeTuple;
17 
18 template FieldTypeTuple(T)
19 {
20     static if (is(T == struct) || is(T == union))
21         alias FieldTypeTuple = typeof(T.tupleof[0 .. $ - __traits(isNested, T)]);
22     else static if (is(T == class))
23         alias FieldTypeTuple = typeof(T.tupleof);
24     else
25     {
26         alias FieldTypeTuple = TypeTuple!T;
27     }
28 }
29 
30 T trustedCast(T, U)(auto ref U u) @trusted pure nothrow
31 {
32     return cast(T)u;
33 }
34 
35 template Unconst(T)
36 {
37          static if (is(T U ==   immutable U)) alias Unconst = U;
38     else static if (is(T U == inout const U)) alias Unconst = U;
39     else static if (is(T U == inout       U)) alias Unconst = U;
40     else static if (is(T U ==       const U)) alias Unconst = U;
41     else                                      alias Unconst = T;
42 }
43 
44 /// taken from std.traits.Unqual
45 template Unqual(T)
46 {
47     version (none) // Error: recursive alias declaration @@@BUG1308@@@
48     {
49              static if (is(T U ==     const U)) alias Unqual = Unqual!U;
50         else static if (is(T U == immutable U)) alias Unqual = Unqual!U;
51         else static if (is(T U ==     inout U)) alias Unqual = Unqual!U;
52         else static if (is(T U ==    shared U)) alias Unqual = Unqual!U;
53         else                                    alias Unqual =        T;
54     }
55     else // workaround
56     {
57              static if (is(T U ==          immutable U)) alias Unqual = U;
58         else static if (is(T U == shared inout const U)) alias Unqual = U;
59         else static if (is(T U == shared inout       U)) alias Unqual = U;
60         else static if (is(T U == shared       const U)) alias Unqual = U;
61         else static if (is(T U == shared             U)) alias Unqual = U;
62         else static if (is(T U ==        inout const U)) alias Unqual = U;
63         else static if (is(T U ==        inout       U)) alias Unqual = U;
64         else static if (is(T U ==              const U)) alias Unqual = U;
65         else                                             alias Unqual = T;
66     }
67 }
68 
69 // Substitute all `inout` qualifiers that appears in T to `const`
70 template substInout(T)
71 {
72     static if (is(T == immutable))
73     {
74         alias substInout = T;
75     }
76     else static if (is(T : shared const U, U) || is(T : const U, U))
77     {
78         // U is top-unqualified
79         mixin("alias substInout = "
80             ~ (is(T == shared) ? "shared " : "")
81             ~ (is(T == const) || is(T == inout) ? "const " : "")    // substitute inout to const
82             ~ "substInoutForm!U;");
83     }
84     else
85         static assert(0);
86 }
87 
88 private template substInoutForm(T)
89 {
90     static if (is(T == struct) || is(T == class) || is(T == union) || is(T == interface))
91     {
92         alias substInoutForm = T;   // prevent matching to the form of alias-this-ed type
93     }
94     else static if (is(T : V[K], K, V))        alias substInoutForm = substInout!V[substInout!K];
95     else static if (is(T : U[n], U, size_t n)) alias substInoutForm = substInout!U[n];
96     else static if (is(T : U[], U))            alias substInoutForm = substInout!U[];
97     else static if (is(T : U*, U))             alias substInoutForm = substInout!U*;
98     else                                       alias substInoutForm = T;
99 }
100 
101 /// used to declare an extern(D) function that is defined in a different module
102 template externDFunc(string fqn, T:FT*, FT) if (is(FT == function))
103 {
104     static if (is(FT RT == return) && is(FT Args == function))
105     {
106         import core.demangle : mangleFunc;
107         enum decl = {
108             string s = "extern(D) RT externDFunc(Args)";
109             foreach (attr; __traits(getFunctionAttributes, FT))
110                 s ~= " " ~ attr;
111             return s ~ ";";
112         }();
113         pragma(mangle, mangleFunc!T(fqn)) mixin(decl);
114     }
115     else
116         static assert(0);
117 }
118 
119 template staticIota(int beg, int end)
120 {
121     static if (beg + 1 >= end)
122     {
123         static if (beg >= end)
124         {
125             alias staticIota = TypeTuple!();
126         }
127         else
128         {
129             alias staticIota = TypeTuple!(+beg);
130         }
131     }
132     else
133     {
134         enum mid = beg + (end - beg) / 2;
135         alias staticIota = TypeTuple!(staticIota!(beg, mid), staticIota!(mid, end));
136     }
137 }
138 
139 private struct __InoutWorkaroundStruct {}
140 @property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
141 @property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
142 
143 // taken from std.traits.isAssignable
144 template isAssignable(Lhs, Rhs = Lhs)
145 {
146     enum isAssignable = __traits(compiles, lvalueOf!Lhs = rvalueOf!Rhs) && __traits(compiles, lvalueOf!Lhs = lvalueOf!Rhs);
147 }
148 
149 // taken from std.traits.isInnerClass
150 template isInnerClass(T) if (is(T == class))
151 {
152     static if (is(typeof(T.outer)))
153     {
154         template hasOuterMember(T...)
155         {
156             static if (T.length == 0)
157                 enum hasOuterMember = false;
158             else
159                 enum hasOuterMember = T[0] == "outer" || hasOuterMember!(T[1 .. $]);
160         }
161         enum isInnerClass = __traits(isSame, typeof(T.outer), __traits(parent, T)) && !hasOuterMember!(__traits(allMembers, T));
162     }
163     else
164         enum isInnerClass = false;
165 }
166 
167 template dtorIsNothrow(T)
168 {
169     enum dtorIsNothrow = is(typeof(function{T t=void;}) : void function() nothrow);
170 }
171 
172 // taken from std.meta.allSatisfy
173 template allSatisfy(alias F, T...)
174 {
175     static foreach (Ti; T)
176     {
177         static if (!is(typeof(allSatisfy) == bool) && // not yet defined
178                    !F!(Ti))
179         {
180             enum allSatisfy = false;
181         }
182     }
183     static if (!is(typeof(allSatisfy) == bool)) // if not yet defined
184     {
185         enum allSatisfy = true;
186     }
187 }
188 
189 // taken from std.meta.anySatisfy
190 template anySatisfy(alias F, T...)
191 {
192     static foreach (Ti; T)
193     {
194         static if (!is(typeof(anySatisfy) == bool) && // not yet defined
195                    F!(Ti))
196         {
197             enum anySatisfy = true;
198         }
199     }
200     static if (!is(typeof(anySatisfy) == bool)) // if not yet defined
201     {
202         enum anySatisfy = false;
203     }
204 }
205 
206 // simplified from std.traits.maxAlignment
207 template maxAlignment(U...)
208 {
209     static if (U.length == 0)
210         static assert(0);
211     else static if (U.length == 1)
212         enum maxAlignment = U[0].alignof;
213     else static if (U.length == 2)
214         enum maxAlignment = U[0].alignof > U[1].alignof ? U[0].alignof : U[1].alignof;
215     else
216     {
217         enum a = maxAlignment!(U[0 .. ($+1)/2]);
218         enum b = maxAlignment!(U[($+1)/2 .. $]);
219         enum maxAlignment = a > b ? a : b;
220     }
221 }
222 
223 // std.traits.Fields
224 template Fields(T)
225 {
226     static if (is(T == struct) || is(T == union))
227         alias Fields = typeof(T.tupleof[0 .. $ - __traits(isNested, T)]);
228     else static if (is(T == class))
229         alias Fields = typeof(T.tupleof);
230     else
231         alias Fields = TypeTuple!T;
232 }
233 
234 // std.traits.hasElaborateDestructor
235 template hasElaborateDestructor(S)
236 {
237     static if (__traits(isStaticArray, S) && S.length)
238     {
239         enum bool hasElaborateDestructor = hasElaborateDestructor!(typeof(S.init[0]));
240     }
241     else static if (is(S == struct))
242     {
243         enum hasElaborateDestructor = __traits(hasMember, S, "__dtor")
244             || anySatisfy!(.hasElaborateDestructor, Fields!S);
245     }
246     else
247     {
248         enum bool hasElaborateDestructor = false;
249     }
250 }
251 
252 // std.traits.hasElaborateCopyDestructor
253 template hasElaborateCopyConstructor(S)
254 {
255     static if (__traits(isStaticArray, S) && S.length)
256     {
257         enum bool hasElaborateCopyConstructor = hasElaborateCopyConstructor!(typeof(S.init[0]));
258     }
259     else static if (is(S == struct))
260     {
261         enum hasElaborateCopyConstructor = __traits(hasMember, S, "__xpostblit");
262     }
263     else
264     {
265         enum bool hasElaborateCopyConstructor = false;
266     }
267 }
268 
269 template hasElaborateAssign(S)
270 {
271     static if (__traits(isStaticArray, S) && S.length)
272     {
273         enum bool hasElaborateAssign = hasElaborateAssign!(typeof(S.init[0]));
274     }
275     else static if (is(S == struct))
276     {
277         enum hasElaborateAssign = is(typeof(S.init.opAssign(rvalueOf!S))) ||
278                                   is(typeof(S.init.opAssign(lvalueOf!S))) ||
279                                   anySatisfy!(.hasElaborateAssign, FieldTypeTuple!S);
280     }
281     else
282     {
283         enum bool hasElaborateAssign = false;
284     }
285 }
286 
287 // std.meta.Filter
288 template Filter(alias pred, TList...)
289 {
290     static if (TList.length == 0)
291     {
292         alias Filter = TypeTuple!();
293     }
294     else static if (TList.length == 1)
295     {
296         static if (pred!(TList[0]))
297             alias Filter = TypeTuple!(TList[0]);
298         else
299             alias Filter = TypeTuple!();
300     }
301     else
302     {
303         alias Filter =
304             TypeTuple!(
305                 Filter!(pred, TList[ 0  .. $/2]),
306                 Filter!(pred, TList[$/2 ..  $ ]));
307     }
308 }
309 
310 // std.meta.staticMap
311 template staticMap(alias F, T...)
312 {
313     static if (T.length == 0)
314     {
315         alias staticMap = TypeTuple!();
316     }
317     else static if (T.length == 1)
318     {
319         alias staticMap = TypeTuple!(F!(T[0]));
320     }
321     else
322     {
323         alias staticMap =
324             TypeTuple!(
325                 staticMap!(F, T[ 0  .. $/2]),
326                 staticMap!(F, T[$/2 ..  $ ]));
327     }
328 }
329 
330 // std.exception.assertCTFEable
331 version (unittest) package(core)
332 void assertCTFEable(alias dg)()
333 {
334     static assert({ cast(void) dg(); return true; }());
335     cast(void) dg();
336 }
Suggestion Box / Bug Report