1 module libd.meta.traits;
2 
3 alias AliasSeq(T...) = T;
4 
5 template allSatisfy(alias Condition, T...)
6 {
7     bool func() 
8     {
9         bool result = true;
10 
11         static foreach(t; T)
12         {
13             static if(!Condition!t)
14                 result = false;    
15         }
16         
17         return result;
18     }
19 
20     enum allSatisfy = func();
21 }
22 ///
23 @("allSatisfy")
24 unittest
25 {
26     enum isIntOrString(alias T) = is(typeof(T) == int) || is(typeof(T) == string);
27     static assert(allSatisfy!(isIntOrString, 0, ""));
28     static assert(!allSatisfy!(isIntOrString, 0, false, ""));
29 
30     enum isIntOrStringT(T) = is(T == int) || is(T == string);
31     static assert(allSatisfy!(isIntOrStringT, int, string));
32     static assert(!allSatisfy!(isIntOrStringT, int, bool, string));
33 }
34 
35 template anySatisfy(alias Condition, T...)
36 {
37     bool func()
38     {
39         bool result = false;
40 
41         static foreach(t; T)
42         {
43             static if(Condition!t)
44                 result = true;
45         }
46 
47         return result;
48     }
49 
50     enum anySatisfy = func();
51 }
52 ///
53 @("anySatisfy")
54 unittest
55 {
56     enum isIntOrString(alias T) = is(typeof(T) == int) || is(typeof(T) == string);
57     static assert(anySatisfy!(isIntOrString, 0, false));
58     static assert(!anySatisfy!(isIntOrString, ['s'], false));
59 
60     enum isIntOrStringT(T) = is(T == int) || is(T == string);
61     static assert(anySatisfy!(isIntOrStringT, int, bool));
62     static assert(!anySatisfy!(isIntOrStringT, char[], bool));
63 }
64 
65 template isPartOfUnion(UnionT, ValueT)
66 {
67     bool func()
68     {
69         bool result;
70 
71         static foreach(name; __traits(allMembers, UnionT))
72         {
73             static if(is(ValueT == typeof(__traits(getMember, UnionT, name))))
74                 result = true;
75         }
76 
77         return result;
78     }
79 
80     enum isPartOfUnion = func();
81 }
82 ///
83 @("isPartOfUnion")
84 unittest
85 {
86     static union U
87     {
88         int a;
89         string b;
90     }
91 
92     static assert(isPartOfUnion!(U, int));
93     static assert(isPartOfUnion!(U, string));
94     static assert(!isPartOfUnion!(U, short));
95     static assert(!isPartOfUnion!(U, bool));
96 }
97 
98 enum isSomeFunction(alias F) = is(FunctionTypeOf!F _ == function);
99 ///
100 @("isSomeFunction")
101 unittest
102 {
103     int a;
104     static void f(){}
105     scope d = (){ a = 0; };
106 
107     static assert(isSomeFunction!f);
108     static assert(isSomeFunction!d);
109 }
110 
111 enum isCopyable(alias T) = __traits(isCopyable, T);
112 ///
113 @("isCopyable")
114 unittest
115 {
116     struct S 
117     {
118         @disable this(this){}
119     }
120 
121     static assert(isCopyable!int);
122     static assert(!isCopyable!S);
123 }
124 
125 enum isSlice(alias T) = is(T == E[], E);
126 ///
127 @("isSlice")
128 unittest
129 {
130     static assert(isSlice!(int[]));
131     static assert(!isSlice!int);
132 }
133 
134 enum isPointer(alias T) = is(T == E*, E);
135 ///
136 @("isPointer")
137 unittest
138 {
139     static assert(isPointer!(int*));
140     static assert(!isPointer!int);
141 }
142 
143 template ElementType(alias T)
144 {
145     import libd.algorithm.common : isInputRange;
146 
147     static if(is(T == E[], E))
148         alias ElementType = E;
149     else static if(isInputRange!T)
150         alias ElementType = typeof(T.init.front());
151     else static assert(false, "Cannot determine element type of type `"~T.stringof~"`");
152 }
153 ///
154 @("ElementType")
155 unittest
156 {
157     static assert(is(ElementType!(int[]) == int));
158 }
159 
160 template Parameters(alias F)
161 {
162     static if(is(FunctionTypeOf!F P == function))
163         alias Parameters = P;
164     else
165         static assert(false, F.stringof~" is not a function/delegate/there's a bug.");
166 }
167 ///
168 @("Parameters")
169 unittest
170 {
171     static void a(){}
172     static void aa(int, string){}
173     auto b = (){};
174     auto bb = (int s, string ss){};
175 
176     static assert(is(Parameters!a == AliasSeq!()));
177     static assert(is(Parameters!aa == AliasSeq!(int, string)));
178     static assert(is(Parameters!b == AliasSeq!()));
179     static assert(is(Parameters!bb == AliasSeq!(int, string)));
180 }
181 
182 enum isInstanceOf(alias S, alias T) = is(T == S!Args, Args...);
183 
184 template BitmaskUda(alias Uda, alias T)
185 {
186     static if(__traits(compiles, __traits(getAttributes, T)))
187     {
188         Uda get()
189         {
190             Uda value;
191 
192             static foreach(uda; __traits(getAttributes, T))
193             {
194                 static if(__traits(compiles, typeof(uda)) && is(typeof(uda) == Uda))
195                     value |= uda;
196             }
197 
198             return value;
199         }
200         enum BitmaskUda = get();
201     }
202     else
203         enum BitmaskUda = Uda.init;
204 }
205 ///
206 @("BitmaskUda")
207 unittest
208 {
209     static enum Uda
210     {
211         a = 1,
212         b = 2,
213         c = 4
214     }
215 
216     @(Uda.a, Uda.c)
217     static struct A {}
218 
219     static assert(BitmaskUda!(Uda, A) == (Uda.a | Uda.c));
220 }
221 
222 template UdaOrDefault(alias Uda, alias T, Uda default_)
223 {
224     Uda get()
225     {
226         Uda value = default_;
227 
228         static if(__traits(compiles, __traits(getAttributes, T)))
229         static foreach(uda; __traits(getAttributes, T))
230         {
231             static if(__traits(compiles, typeof(uda)) && is(typeof(uda) == Uda))
232             {
233                 value = uda;
234                 goto LReturn; // Super annoying, but D *still* hates it when a conditional return is generated alongside an always-existing return.
235             }
236         } 
237 
238         LReturn:
239         return value;
240     }
241     enum UdaOrDefault = get();
242 }
243 ///
244 @("UdaOrDefault")
245 unittest
246 {
247     static struct Uda {int v;}
248     enum E
249     {
250         a,
251         b
252     }
253 
254     @(E.b)
255     struct S{}
256 
257     static assert(UdaOrDefault!(Uda, S, Uda(200)) == Uda(200));
258     static assert(UdaOrDefault!(E, S, E.a) == E.b);
259 }
260 
261 struct TypeId
262 {
263     string fqn;
264     uint fqnHash;
265 
266     bool opEquals(const TypeId other) const @safe @nogc nothrow
267     {
268         return this.fqnHash == other.fqnHash;
269     }
270 
271     size_t toHash() const @safe @nogc nothrow
272     {
273         return this.fqnHash;
274     }
275 }
276 
277 template TypeIdOf(alias T)
278 {
279     import libd.data.hash : Murmur3_32;
280 
281     const fqn = T.stringof;// TODO
282     const TypeIdOf = TypeId(
283         fqn,
284         (){Murmur3_32 hash; hash.put(fqn); return hash.value;}()
285     ); 
286 }
287 ///
288 @("TypeIdOf")
289 unittest
290 {
291     const intId = TypeIdOf!int;
292     const stringId = TypeIdOf!string;
293 
294     assert(intId.fqn == "int");
295     assert(intId == intId);
296     assert(stringId != intId);
297 }
298 
299 template UnsignedOf(alias NumT)
300 {
301     static if(__traits(isUnsigned, NumT))
302         alias UnsignedOf = NumT;
303     else static if(__traits(isArithmetic, NumT))
304         mixin("alias UnsignedOf = u"~NumT.stringof~";");
305     else static assert(false);
306 }
307 ///
308 @("UnsignedOf")
309 unittest
310 {
311     static assert(is(UnsignedOf!byte == ubyte));
312     static assert(is(UnsignedOf!ubyte == ubyte));
313 }
314 
315 template Unqual(T : const U, U)
316 {
317     static if (is(U == shared V, V))
318         alias Unqual = V;
319     else
320         alias Unqual = U;
321 }
322 
323 /+++++++++++++++++ STOLEN FROM PHOBOS +++++++++++++++++++/
324 /**
325 Get the function type from a callable object `func`.
326 Using builtin `typeof` on a property function yields the types of the
327 property value, not of the property function itself.  Still,
328 `FunctionTypeOf` is able to obtain function types of properties.
329 Note:
330 Do not confuse function types with function pointer types; function types are
331 usually used for compile-time reflection purposes.
332  */
333 template FunctionTypeOf(func...)
334 if (func.length == 1)
335 {
336     static if (is(typeof(& func[0]) Fsym : Fsym*) && is(Fsym == function) || is(typeof(& func[0]) Fsym == delegate))
337     {
338         alias FunctionTypeOf = Fsym; // HIT: (nested) function symbol
339     }
340     else static if (is(typeof(& func[0].opCall) Fobj == delegate))
341     {
342         alias FunctionTypeOf = Fobj; // HIT: callable object
343     }
344     else static if (is(typeof(& func[0].opCall) Ftyp : Ftyp*) && is(Ftyp == function))
345     {
346         alias FunctionTypeOf = Ftyp; // HIT: callable type
347     }
348     else static if (is(func[0] T) || is(typeof(func[0]) T))
349     {
350         static if (is(T == function))
351             alias FunctionTypeOf = T;    // HIT: function
352         else static if (is(T Fptr : Fptr*) && is(Fptr == function))
353             alias FunctionTypeOf = Fptr; // HIT: function pointer
354         else static if (is(T Fdlg == delegate))
355             alias FunctionTypeOf = Fdlg; // HIT: delegate
356         else
357             static assert(0);
358     }
359     else
360         static assert(0);
361 }