1 /**
2  * Metaprogramming
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.utils.meta;
15 
16 public import ae.utils.meta.reference;
17 public import ae.utils.meta.x;
18 public import ae.utils.meta.proxy;
19 public import ae.utils.meta.binding_v1;
20 public import ae.utils.meta.binding;
21 
22 import ae.utils.meta.caps;
23 
24 // ************************************************************************
25 
26 import std.traits;
27 import std.typecons : tuple;
28 
29 /**
30  * Same as TypeTuple, but meant to be used with values.
31  *
32  * Example:
33  *   foreach (char channel; valueTuple!('r', 'g', 'b'))
34  *   {
35  *     // the loop is unrolled at compile-time
36  *     // "channel" is a compile-time value, and can be used in string mixins
37  *   }
38  */
39 template valueTuple(T...)
40 {
41 	alias T valueTuple;
42 }
43 deprecated alias ValueTuple = valueTuple;
44 
45 template _rangeTupleImpl(size_t N, R...)
46 {
47 	static if (N==R.length)
48 		alias R _rangeTupleImpl;
49 	else
50 		alias _rangeTupleImpl!(N, valueTuple!(R, R.length)) _rangeTupleImpl;
51 }
52 
53 /// Generate a tuple containing integers from 0 to N-1.
54 /// Useful for static loop unrolling. (staticIota)
55 template rangeTuple(size_t N)
56 {
57 	alias _rangeTupleImpl!(N, valueTuple!()) rangeTuple;
58 }
59 deprecated alias RangeTuple = rangeTuple;
60 
61 /// Expand an array to a tuple.
62 /// The array value must be known during compilation.
63 template arrayToTuple(alias arr, Elements...)
64 {
65 	///
66 	static if (arr.length)
67 		alias arrayToTuple = arrayToTuple!(arr[1..$], valueTuple!(Elements, arr[0]));
68 	else
69 		alias arrayToTuple = Elements;
70 }
71 deprecated alias ArrayToTuple = arrayToTuple;
72 
73 unittest
74 {
75 	alias X = arrayToTuple!"abc";
76 	static assert(X[0] == 'a' && X[2] == 'c');
77 	static assert([X] == "abc");
78 }
79 
80 /// Expand a static array to a tuple.
81 /// Unlike `arrayToTuple`, the array may be a runtime variable.
82 template expand(alias arr, size_t offset = 0)
83 	if (isStaticArray!(typeof(arr)))
84 {
85 	import std.typetuple : AliasSeq;
86 
87 	///
88 	static if (arr.length == offset)
89 		alias expand = AliasSeq!();
90 	else
91 	{
92 		@property ref getValue() { return arr[offset]; }
93 		alias expand = AliasSeq!(getValue, expand!(arr, offset+1));
94 	}
95 }
96 
97 unittest
98 {
99 	int[3] arr = [1, 2, 3];
100 	void test(int a, int b, int c) {}
101 	test(expand!arr);
102 }
103 
104 /// Maps values with a predicate, returning a `std.typecons` tuple.
105 auto tupleMap(alias pred, Values...)(auto ref Values values)
106 {
107 	static if (values.length == 0)
108 		return tuple();
109 	else
110 		return tuple(pred(values[0]), tupleMap!pred(values[1 .. $]).expand);
111 }
112 
113 unittest
114 {
115 	assert(tuple(2, 3.0).expand.tupleMap!(n => n + 1) == tuple(3, 4.0));
116 }
117 
118 /// Return something to foreach over optimally.
119 /// If A is known at compile-time, return a tuple,
120 /// so the foreach is unrolled at compile-time.
121 /// Otherwise, return A for a regular runtime foreach.
122 template CTIterate(alias A)
123 {
124 	///
125 	static if (is(typeof(arrayToTuple!A)))
126 		enum CTIterate = arrayToTuple!A;
127 	else
128 		alias CTIterate = A;
129 }
130 
131 unittest
132 {
133 	foreach (c; CTIterate!"abc") {}
134 	string s;
135 	foreach (c; CTIterate!s) {}
136 }
137 
138 /// Like std.typecons.Tuple, but a template mixin.
139 /// Unlike std.typecons.Tuple, names may not be omitted - but repeating types may be.
140 /// Example: FieldList!(ubyte, "r", "g", "b", ushort, "a");
141 mixin template FieldList(Fields...)
142 {
143 	template _GenFieldList(size_t ti, size_t i)
144 	{
145 		///
146 		static if (i == Fields.length)
147 			enum _GenFieldList = "";
148 		else
149 		{
150 			static if (is(typeof(Fields[i]) == string))
151 				enum _GenFieldList = "Fields[" ~ ti.stringof ~ "] " ~ Fields[i] ~ ";\n" ~ _GenFieldList!(ti, i + 1);
152 			else
153 				enum _GenFieldList = _GenFieldList!(i, i + 1);
154 		}
155 	}
156 
157 	mixin(_GenFieldList!(-1, 0));
158 }
159 
160 unittest
161 {
162 	struct S
163 	{
164 		mixin FieldList!(ubyte, "r", "g", "b", ushort, "a");
165 	}
166 	S s;
167 	static assert(is(typeof(s.r) == ubyte));
168 	static assert(is(typeof(s.g) == ubyte));
169 	static assert(is(typeof(s.b) == ubyte));
170 	static assert(is(typeof(s.a) == ushort));
171 }
172 
173 /// Return true if all of T's fields are the same type.
174 @property bool isHomogeneous(T)()
175 {
176 	foreach (i, f; T.init.tupleof)
177 		if (!is(typeof(T.init.tupleof[i]) == typeof(T.init.tupleof[0])))
178 			return false;
179 	return true;
180 }
181 deprecated alias isHomogenous = isHomogeneous;
182 
183 /// Resolves to `true` if tuple `T` contains a value whose type is `X`.
184 template isValueOfTypeInTuple(X, T...)
185 {
186 	///
187 	static if (T.length==0)
188 		enum bool isValueOfTypeInTuple = false;
189 	else
190 	static if (T.length==1)
191 		enum bool isValueOfTypeInTuple = is(typeof(T[0]) : X);
192 	else
193 		enum bool isValueOfTypeInTuple = isValueOfTypeInTuple!(X, T[0..$/2]) || isValueOfTypeInTuple!(X, T[$/2..$]);
194 }
195 
196 unittest
197 {
198 	static assert( isValueOfTypeInTuple!(int, valueTuple!("a", 42)));
199 	static assert(!isValueOfTypeInTuple!(int, valueTuple!("a", 42.42)));
200 	static assert(!isValueOfTypeInTuple!(int, valueTuple!()));
201 
202 	static assert(!isValueOfTypeInTuple!(int, "a", int, Object));
203 	static assert( isValueOfTypeInTuple!(int, "a", int, Object, 42));
204 }
205 
206 /// Returns the first value in `T` of type `X`.
207 template findValueOfTypeInTuple(X, T...)
208 {
209 	///
210 	static if (T.length==0)
211 		static assert(false, "Can't find value of type " ~ X.stringof ~ " in specified tuple");
212 	else
213 	static if (is(typeof(T[0]) : X))
214 		enum findValueOfTypeInTuple = T[0];
215 	else
216 		enum findValueOfTypeInTuple = findValueOfTypeInTuple!(X, T[1..$]);
217 }
218 
219 unittest
220 {
221 	static assert(findValueOfTypeInTuple!(int, valueTuple!("a", 42))==42);
222 	static assert(findValueOfTypeInTuple!(int, "a", int, Object, 42)==42);
223 }
224 
225 /// Combines the getMember and allMembers traits, to return the
226 /// parameter's members as aliases.
227 template AllMembers(X...)
228 if (X.length == 1)
229 {
230 	alias GetMember(string name) = I!(__traits(getMember, X, name));
231 	alias AllMembers = staticMap!(GetMember, __traits(allMembers, X));
232 }
233 
234 unittest
235 {
236 	import std.typetuple : AliasSeq;
237 
238 	struct A { struct B {} struct C {} }
239 	static assert(is(AllMembers!A == AliasSeq!(A.B, A.C)));
240 }
241 
242 // ************************************************************************
243 
244 /// One past the biggest element of the enum T.
245 /// Example: string[enumLength!E] arr;
246 template enumLength(T)
247 	if (is(T==enum))
248 {
249 	enum enumLength = cast(T)(cast(size_t)T.max + 1);
250 }
251 
252 deprecated alias EnumLength = enumLength;
253 
254 /// A range that iterates over all members of an enum.
255 @property auto enumIota(T)()
256 {
257 	import std.range : iota;
258 	return iota(T.init, enumLength!T);
259 }
260 
261 unittest
262 {
263 	import std.algorithm.comparison : equal;
264 	enum E { a, b, c }
265 	static assert(equal(enumIota!E, [E.a, E.b, E.c]));
266 }
267 
268 struct Has(E, bool byRef)
269 {
270 private:
271 	static if (byRef)
272 	{
273 		E* p;
274 		@property ref e() { return *p; }
275 	}
276 	else
277 		E e;
278 
279 public:
280 	@property bool opDispatch(string name)()
281 	if (__traits(hasMember, E, name))
282 	{
283 		static foreach (i, member; EnumMembers!E)
284 			static if (__traits(identifier, EnumMembers!E[i]) == name)
285 				return (e & member) == member;
286 	}
287 
288 	@property bool opDispatch(string name)(bool value)
289 	if (byRef && __traits(hasMember, E, name))
290 	{
291 		static foreach (i, member; EnumMembers!E)
292 			static if (__traits(identifier, EnumMembers!E[i]) == name)
293 			{
294 				if (value)
295 					e |= member;
296 				else
297 					e &= ~member;
298 				return value;
299 			}
300 	}
301 }
302 
303 /// Convenience facility for manipulating bitfield enums.
304 auto has(E)(ref E e) if (is(E == enum)) { return Has!(E, true)(&e); }
305 auto has(E)(    E e) if (is(E == enum)) { return Has!(E, false)(e); } /// ditto
306 
307 ///
308 unittest
309 {
310 	enum E
311 	{
312 		init = 0,
313 		foo = 1 << 0,
314 		bar = 1 << 1,
315 	}
316 	assert(E.foo.has.foo);
317 	E e;
318 	assert(!e.has.foo);
319 	e.has.foo = true;
320 	assert(e.has.foo);
321 }
322 
323 // ************************************************************************
324 
325 // Use strong typing to provably disambiguate BoxedVoid from any other type.
326 private struct BoxedVoidElement {}
327 
328 /// What to use instead of void for boxVoid/unboxVoid.
329 /// Use a zero-length array instead of an empty struct as this one has a .sizeof
330 /// of 0, unlike the struct.
331 alias BoxedVoid = BoxedVoidElement[0];
332 
333 static assert(BoxedVoid.sizeof == 0);
334 
335 /// Resolves to `BoxedVoid` if `T` is `void`, or to `T` otherwise.
336 template BoxVoid(T)
337 {
338 	///
339 	static if (is(T == void))
340 		alias BoxVoid = BoxedVoid;
341 	else
342 		alias BoxVoid = T;
343 }
344 
345 /// D does not allow void variables or parameters.
346 /// As such, there is no "common type" for functions that return void
347 /// and non-void.
348 /// To allow generic metaprogramming in such cases, this function will
349 /// "box" a void expression to a different type.
350 BoxVoid!T boxVoid(T)(lazy T expr)
351 {
352 	static if (is(T == void))
353 	{
354 		expr;
355 		return BoxedVoid.init;
356 	}
357 	else
358 		return expr;
359 }
360 
361 /// Inverse of boxVoid.
362 /// Can be used in a return statement, i.e.:
363 /// return unboxVoid(someBoxedVoid);
364 auto unboxVoid(T)(T value)
365 {
366 	static if (is(T == BoxedVoid))
367 		return;
368 	else
369 		return value;
370 }
371 
372 /// As boxVoid/unboxVoid, but returns a struct with zero or one members.
373 /// .tupleof can then be used to paste the tuple in e.g. an argument list.
374 auto voidStruct(T)(T value)
375 if (!is(T == void))
376 {
377 	static struct Result
378 	{
379 		static if (!is(T == BoxedVoid))
380 			T value;
381 	}
382 
383 	static if (is(T == BoxedVoid))
384 		return Result();
385 	else
386 		return Result(value);
387 }
388 
389 /// ditto
390 auto voidStruct(T)(lazy T value)
391 if (is(T == void))
392 {
393 	value; // evaluate
394 
395 	static struct Result {}
396 	return Result();
397 }
398 
399 unittest
400 {
401 	import std.typetuple : AliasSeq;
402 
403 	struct S { void* p; }
404 
405 	auto process(T)(T delegate() dg)
406 	{
407 		auto result = dg().boxVoid;
408 		return result.unboxVoid;
409 	}
410 
411 	S fun() { return S(); }
412 	assert(process(&fun) == S.init);
413 
414 	void gun() { }
415 	static assert(is(typeof(process(&gun)) == void));
416 
417 	gun(gun().boxVoid.voidStruct.tupleof);
418 	gun(gun().voidStruct.tupleof);
419 	static assert(is(typeof(fun().boxVoid.voidStruct.tupleof) == AliasSeq!S));
420 	static assert(is(typeof(fun().voidStruct.tupleof) == AliasSeq!S));
421 }
422 
423 // ************************************************************************
424 
425 /// `std.traits.ParameterIdentifierTuple` patched to support anonymous functions.
426 // https://issues.dlang.org/show_bug.cgi?id=13780
427 // https://github.com/dlang/phobos/pull/3620
428 template ParameterNames(func...)
429     if (func.length == 1 && isCallable!func)
430 {
431     static if (is(FunctionTypeOf!func PT == __parameters))
432     {
433         template Get(size_t i)
434         {
435             // Unnamed parameters yield CT error.
436             static if (is(typeof(__traits(identifier, PT[i..i+1]))x))
437             {
438                 enum Get = __traits(identifier, PT[i..i+1]);
439             }
440             else
441             {
442                 enum Get = "";
443             }
444         }
445     }
446     else
447     {
448         static assert(0, func[0].stringof ~ "is not a function");
449 
450         // Define dummy entities to avoid pointless errors
451         template Get(size_t i) { enum Get = ""; }
452         alias PT = AliasSeq!();
453     }
454 
455 	import std.typetuple : AliasSeq;
456 
457     template Impl(size_t i = 0)
458     {
459         static if (i == PT.length)
460             alias Impl = AliasSeq!();
461         else
462             alias Impl = AliasSeq!(Get!i, Impl!(i+1));
463     }
464 
465     alias ParameterNames = Impl!();
466 }
467 
468 /// Apply `.stringof` over `Args` and
469 /// return the result as a `string[]`.
470 static // https://issues.dlang.org/show_bug.cgi?id=7805
471 template stringofArray(Args...)
472 {
473 	static string[] stringofArray()
474 	{
475 		string[] args;
476 		foreach (i, _ ; typeof(Args))
477 			args ~= Args[i].stringof;
478 		return args;
479 	}
480 }
481 
482 /// Returns the index of fun's parameter with the name
483 /// matching "names", or asserts if the parameter is not found.
484 /// "names" can contain multiple names separated by slashes.
485 static size_t findParameter(alias fun, string names)()
486 {
487 	import std.array : split;
488 
489 	foreach (name; names.split("/"))
490 		foreach (i, param; ParameterNames!fun)
491 			if (param == name)
492 				return i;
493 	assert(false, "Function " ~ __traits(identifier, fun) ~ " doesn't have a parameter called " ~ names);
494 }
495 
496 /// ditto
497 // Workaround for no "static alias" template parameters
498 static size_t findParameter()(string[] searchedNames, string soughtNames, string funName)
499 {
500 	import std.array : split;
501 
502 	foreach (soughtName; soughtNames.split("/"))
503 	{
504 		import std.algorithm.searching : countUntil;
505 
506 		auto targetIndex = searchedNames.countUntil(soughtName);
507 		if (targetIndex >= 0)
508 			return targetIndex;
509 	}
510 
511 	{
512 		import std.format : format;
513 
514 		assert(false, "No argument %s in %s's parameters (%s)"
515 			.format(soughtNames, funName, searchedNames).idup);
516 	}
517 }
518 
519 unittest
520 {
521 	static void fun(int a, int b, int c) {}
522 
523 	static assert(findParameter!(fun, "x/c") == 2);
524 	assert(findParameter(["a", "b", "c"], "x/c", "fun") == 2);
525 }
526 
527 // ************************************************************************
528 
529 /// Generates a function which passes its arguments to a struct, which is
530 /// returned. Preserves field names (as parameter names) and default values.
531 template structFun(S)
532 {
533 	mixin((){
534 		import std.algorithm.iteration : map;
535 		import std.array : join;
536 		import std.format : format;
537 		import std.meta : staticMap;
538 		import std.range : iota;
539 
540 		enum identifierAt(int n) = __traits(identifier, S.tupleof[n]);
541 		enum names = [staticMap!(identifierAt, rangeTuple!(S.tupleof.length))];
542 
543 		return
544 			"S structFun(\n" ~
545 			S.tupleof.length.iota.map!(n =>
546 			"	typeof(S.init.tupleof[%d]) %s = S.init.tupleof[%d],\n".format(n, names[n], n)
547 			).join() ~
548 			`) { return S(` ~ names.join(", ") ~ "); }";
549 	}());
550 }
551 
552 unittest
553 {
554 	static struct Test
555 	{
556 		string a;
557 		int b = 42;
558 	}
559 
560 	Test test = structFun!Test("banana");
561 	assert(test.a is "banana");
562 	assert(test.b == 42);
563 }
564 
565 /// Generates a struct containing fields with names, types, and default values
566 /// corresponding to a function's parameter list.
567 struct StructFromParams(args...)
568 if (args.length == 1 || args.length == 2)
569 {
570 	mixin((){
571 		alias fun = args[0];
572 		static if (args.length == 1)
573 			enum bool voidInitializeRequired = false;
574 		else
575 			enum bool voidInitializeRequired = args[1];
576 		import ae.utils.text.ascii : toDec;
577 
578 		string code;
579 		foreach (i; rangeTuple!(ParameterTypeTuple!fun.length))
580 		{
581 			enum n = toDec(i);
582 
583 			code ~= `ParameterTypeTuple!(args[0])[` ~ n ~ `] `;
584 
585 			static if (ParameterNames!fun[i].length)
586 				code ~= ParameterNames!fun[i];
587 			else
588 				code ~= "_param_" ~ toDec(i);
589 
590 			static if (is(ParameterDefaultValueTuple!fun[i] == void))
591 				static if (voidInitializeRequired)
592 					code ~= ` = void;`;
593 				else
594 					code ~= `;`;
595 			else
596 				code ~= ` = ParameterDefaultValueTuple!(args[0])[` ~ n ~ `];`;
597 		}
598 		return code;
599 	}());
600 }
601 
602 unittest
603 {
604 	static void fun(string a, int b = 42) {}
605 	alias S = StructFromParams!fun;
606 	static assert(is(typeof(S.a) == string));
607 	static assert(S.init.b == 42);
608 }
609 
610 unittest
611 {
612 	static void fun(string, int = 42) {}
613 	alias Fun = typeof(&fun);
614 	alias S = StructFromParams!Fun;
615 	static assert(is(typeof(S.tupleof[0]) == string));
616 }
617 
618 // ************************************************************************
619 
620 // By Paul Backus: https://forum.dlang.org/post/mkiyylyjznwgkzpnbryk@forum.dlang.org
621 /// Pass struct / tuple members as arguments to a function.
622 alias tupleAs(alias fun) = args => fun(args.tupleof);
623 
624 /// Call a predicate with the given value. Return the value.
625 /// Intended to be used in UFCS chains using functions which mutate their argument,
626 /// such as skipOver and each.
627 template apply(alias dg)
628 {
629 	auto ref T apply(T)(auto ref T v)
630 	{
631 		dg(v);
632 		return v;
633 	}
634 }
635 
636 ///
637 unittest
638 {
639 	int i = 7;
640 	int j = i.apply!((ref v) => v++);
641 	assert(j == 8);
642 }
643 
644 /// Evaluate all arguments and return the last argument.
645 /// Can be used instead of the comma operator.
646 /// Inspired by http://clhs.lisp.se/Body/s_progn.htm
647 Args[$-1] progn(Args...)(lazy Args args)
648 {
649 	foreach (n; rangeTuple!(Args[1..$].length))
650 		cast(void)args[n];
651 	return args[$-1];
652 }
653 
654 unittest
655 {
656 	// Test that expressions are correctly evaluated exactly once.
657 	int a, b, c, d;
658 	d = progn(a++, b++, c++);
659 	assert(a==1 && b==1 && c == 1 && d == 0);
660 	d = progn(a++, b++, ++c);
661 	assert(a==2 && b==2 && c == 2 && d == 2);
662 }
663 
664 unittest
665 {
666 	// Test void expressions.
667 	int a, b;
668 	void incA() { a++; }
669 	void incB() { b++; }
670 	progn(incA(), incB());
671 	assert(a == 1 && b == 1);
672 }
673 
674 /// Like progn, but return the first argument instead.
675 Args[0] prog1(Args...)(lazy Args args)
676 {
677 	auto result = args[0];
678 	foreach (n; rangeTuple!(Args.length-1))
679 		cast(void)args[1+n];
680 	return result;
681 }
682 
683 unittest
684 {
685 	int a = 10, b = 20, c = 30;
686 	int d = prog1(a++, b++, c++);
687 	assert(a==11 && b==21 && c == 31 && d == 10);
688 }
689 
690 /// Resolves to `true` if there exists a non-`void`
691 /// common type for all elements of `T`.
692 enum bool haveCommonType(T...) = is(CommonType!T) && !is(CommonType!T == void);
693 
694 /// Lazily evaluate and return first true-ish result; otherwise return last result.
695 CommonType!Args or(Args...)(lazy Args args)
696 if (haveCommonType!Args)
697 {
698 	foreach (n; rangeTuple!(Args.length-1))
699 	{
700 		auto r = args[n];
701 		if (r)
702 			return r;
703 	}
704 	return args[$-1];
705 }
706 
707 unittest
708 {
709 	assert(or(0, 7, 5) == 7);
710 	assert(or(0, 0, 0) == 0);
711 	int fun() { assert(false); }
712 	assert(or(0, 7, fun) == 7);
713 }
714 
715 /// Lazily evaluate and return first false-ish result; otherwise return last result.
716 CommonType!Args and(Args...)(lazy Args args)
717 if (haveCommonType!Args)
718 {
719 	foreach (n; rangeTuple!(Args.length-1))
720 	{
721 		auto r = args[n];
722 		if (!r)
723 			return r;
724 	}
725 	return args[$-1];
726 }
727 
728 unittest
729 {
730 	assert(and(7, 5, 0) == 0);
731 	assert(and(7, 5, 3) == 3);
732 	int fun() { assert(false); }
733 	assert(and(7, 0, fun) == 0);
734 }
735 
736 // ************************************************************************
737 
738 // Using a compiler with UDA support?
739 deprecated alias HAVE_UDA = haveUDA;
740 
741 static if (haveUDA)
742 {
743 	/*
744 	template hasAttribute(T, alias D)
745 	{
746 		enum bool hasAttribute = isValueOfTypeInTuple!(T, __traits(getAttributes, D));
747 	}
748 	*/
749 
750 	/// Detects types and values of the given type.
751 	template hasAttribute(Args...)
752 		if (Args.length == 2)
753 	{
754 	//	alias attribute = Args[0];
755 	//	alias symbol = Args[1];
756 
757 		import std.typetuple : staticIndexOf;
758 		import std.traits : staticMap;
759 
760 		///
761 		static if (is(Args[0]))
762 		{
763 			template _isTypeOrValueInTuple(T, Args...)
764 			{
765 				static if (!Args.length)
766 					enum _isTypeOrValueInTuple = false;
767 				else
768 				static if (is(Args[0] == T))
769 					enum _isTypeOrValueInTuple = true;
770 				else
771 				static if (is(typeof(Args[0]) == T))
772 					enum _isTypeOrValueInTuple = true;
773 				else
774 					enum _isTypeOrValueInTuple = _isTypeOrValueInTuple!(T, Args[1..$]);
775 			}
776 
777 			enum bool hasAttribute = _isTypeOrValueInTuple!(Args[0], __traits(getAttributes, Args[1]));
778 		}
779 		else
780 			enum bool hasAttribute = staticIndexOf!(Args[0], __traits(getAttributes, Args[1])) != -1;
781 	}
782 
783 	/// Retrieves the attribute (type or value of the given type).
784 	template getAttribute(T, alias D)
785 	{
786 		enum T getAttribute = findValueOfTypeInTuple!(T, __traits(getAttributes, D));
787 	}
788 
789 	unittest
790 	{
791 		struct Attr { int i; }
792 
793 		struct S
794 		{
795 			@Attr int a;
796 			@Attr(5) int b;
797 			@("test") int c;
798 		}
799 
800 		static assert(hasAttribute!(Attr, S.a));
801 		static assert(hasAttribute!(Attr, S.b));
802 		static assert(hasAttribute!(string, S.c));
803 		static assert(hasAttribute!("test", S.c));
804 	}
805 }
806 else
807 {
808 	/// Stub (unsupported)>
809 	template hasAttribute(T, alias D)
810 	{
811 		enum bool hasAttribute = false;
812 	}
813 
814 	/// ditto
815 	template getAttribute(T, alias D)
816 	{
817 		static assert(false, "This D compiler has no UDA support.");
818 	}
819 }
820 
821 // ************************************************************************
822 
823 /// Generate constructors that simply call the parent class constructors.
824 /// Based on http://forum.dlang.org/post/i3hpj0$2vc6$1@digitalmars.com
825 mixin template GenerateConstructorProxies()
826 {
827 	mixin(() {
828 		import std.conv : text;
829 		import std.string : join;
830 		import std.traits : ParameterTypeTuple, fullyQualifiedName;
831 
832 		alias T = typeof(super);
833 
834 		string s;
835 		static if (__traits(hasMember, T, "__ctor"))
836 			foreach (ctor; __traits(getOverloads, T, "__ctor"))
837 			{
838 				string[] declarationList, usageList;
839 				foreach (i, param; ParameterTypeTuple!(typeof(&ctor)))
840 				{
841 					auto varName = "v" ~ text(i);
842 					declarationList ~= fullyQualifiedName!param ~ " " ~ varName;
843 					usageList ~= varName;
844 				}
845 				s ~= "this(" ~ declarationList.join(", ") ~ ") { super(" ~ usageList.join(", ") ~ "); }\n";
846 			}
847 		return s;
848 	} ());
849 }
850 
851 deprecated alias GenerateContructorProxies = GenerateConstructorProxies;
852 
853 unittest
854 {
855 	class A
856 	{
857 		int i, j;
858 		this() { }
859 		this(int i) { this.i = i; }
860 		this(int i, int j ) { this.i = i; this.j = j; }
861 	}
862 
863 	class B : A
864 	{
865 		mixin GenerateConstructorProxies;
866 	}
867 
868 	A a;
869 
870 	a = new B();
871 	assert(a.i == 0);
872 	a = new B(17);
873 	assert(a.i == 17);
874 	a = new B(17, 42);
875 	assert(a.j == 42);
876 }
877 
878 // ************************************************************************
879 
880 /// Generate a @property function which creates/returns
881 /// a thread-local singleton of a class with the given arguments.
882 
883 @property T singleton(T, args...)()
884 	if (is(typeof(new T(args))))
885 {
886 	static T instance;
887 	if (!instance)
888 		instance = new T(args);
889 	return instance;
890 }
891 
892 unittest
893 {
894 	static class C
895 	{
896 		static int n = 0;
897 
898 		this()      { n++; }
899 		this(int x) { n += x; }
900 
901 		void fun() {}
902 	}
903 
904 	alias singleton!C c0;
905 	c0.fun();
906 	c0.fun();
907 	assert(C.n == 1);
908 
909 	alias singleton!(C, 5) c1;
910 	c1.fun();
911 	c1.fun();
912 	assert(C.n == 6);
913 }
914 
915 /// As above, but using arbitrary types and a factory function.
916 @property singleton(alias fun, args...)()
917 	if (is(typeof(fun(args))))
918 {
919 	alias T = typeof(fun(args));
920 	static T instance;
921 	static bool initialized;
922 	if (!initialized)
923 	{
924 		instance = fun(args);
925 		initialized = true;
926 	}
927 	return instance;
928 }
929 
930 unittest
931 {
932 	int n;
933 	int gen(int _ = 0)
934 	{
935 		return ++n;
936 	}
937 
938 	alias singleton!gen c0;
939 	assert(c0 == 1);
940 	assert(c0 == 1);
941 
942 	alias singleton!(gen, 1) c1;
943 	assert(c1 == 2);
944 	assert(c1 == 2);
945 }
946 
947 // ************************************************************************
948 
949 /// Were we built with -debug?
950 debug
951 	enum isDebug = true;
952 else
953 	enum isDebug = false;
954 
955 deprecated alias IsDebug = isDebug;
956 
957 /// Is a specific version on?
958 template isVersion(string versionName)
959 {
960 	mixin(`version (` ~ versionName ~ `) enum isVersion = true; else enum isVersion = false;`);
961 }
962 
963 // ************************************************************************
964 
965 /// Identity function.
966 auto ref T identity(T)(auto ref T value) { return value; }
967 
968 /// Shorter synonym for std.traits.Identity.
969 /// Can be used to UFCS-chain static methods and nested functions.
970 alias I(alias A) = A;
971 
972 // ************************************************************************
973 
974 /// Get f's ancestor which represents its "this" pointer.
975 /// Skips template and mixin ancestors until it finds a struct or class.
976 template thisOf(alias f)
977 {
978 	alias _p = I!(__traits(parent, f));
979 	///
980 	static if (is(_p == class) || is(_p == struct) || is(_p == union))
981 		alias thisOf = _p;
982 	else
983 		alias thisOf = thisOf!_p;
984 }
985 
986 // ************************************************************************
987 
988 /// Return the number of bits used to store the value part, i.e.
989 /// T.sizeof*8 for integer parts and the mantissa size for
990 /// floating-point types.
991 template valueBits(T)
992 {
993 	///
994 	static if (is(T : ulong))
995 		enum valueBits = T.sizeof * 8;
996 	else
997 	static if (is(T : real))
998 		enum valueBits = T.mant_dig;
999 	else
1000 		static assert(false, "Don't know how many value bits there are in " ~ T.stringof);
1001 }
1002 
1003 static assert(valueBits!uint == 32);
1004 static assert(valueBits!double == 53);
1005 
1006 /// Expand to a built-in numeric type of the same kind
1007 /// (signed integer / unsigned integer / floating-point)
1008 /// with at least the indicated number of bits of precision.
1009 template ResizeNumericType(T, uint bits)
1010 {
1011 	///
1012 	static if (is(T : ulong))
1013 		static if (isSigned!T)
1014 			alias ResizeNumericType = SignedBitsType!bits;
1015 		else
1016 			alias ResizeNumericType = UnsignedBitsType!bits;
1017 	else
1018 	static if (is(T : real))
1019 	{
1020 		static if (bits <= float.mant_dig)
1021 			alias ResizeNumericType = float;
1022 		else
1023 		static if (bits <= double.mant_dig)
1024 			alias ResizeNumericType = double;
1025 		else
1026 		static if (bits <= real.mant_dig)
1027 			alias ResizeNumericType = real;
1028 		else
1029 			static assert(0, "No floating-point type big enough to fit " ~ bits.stringof ~ " bits");
1030 	}
1031 	else
1032 		static assert(false, "Don't know how to resize type: " ~ T.stringof);
1033 }
1034 
1035 static assert(is(ResizeNumericType!(float, double.mant_dig) == double));
1036 
1037 /// Expand to a built-in numeric type of the same kind
1038 /// (signed integer / unsigned integer / floating-point)
1039 /// with at least additionalBits more bits of precision.
1040 alias ExpandNumericType(T, uint additionalBits) =
1041 	ResizeNumericType!(T, valueBits!T + additionalBits);
1042 
1043 /// Like ExpandNumericType, but do not error if the resulting type is
1044 /// too large to fit any native D type - just expand to the largest
1045 /// type of the same kind instead.
1046 template TryExpandNumericType(T, uint additionalBits)
1047 {
1048 	///
1049 	static if (is(typeof(ExpandNumericType!(T, additionalBits))))
1050 		alias TryExpandNumericType = ExpandNumericType!(T, additionalBits);
1051 	else
1052 		static if (is(T : ulong))
1053 			static if (isSigned!T)
1054 				alias TryExpandNumericType = long;
1055 			else
1056 				alias TryExpandNumericType = ulong;
1057 		else
1058 		static if (is(T : real))
1059 			alias TryExpandNumericType = real;
1060 		else
1061 			static assert(false, "Don't know how to expand type: " ~ T.stringof);
1062 }
1063 
1064 /// Integer type big enough to fit N bits of precision.
1065 template UnsignedBitsType(uint bits)
1066 {
1067 	///
1068 	static if (bits <= 8)
1069 		alias ubyte UnsignedBitsType;
1070 	else
1071 	static if (bits <= 16)
1072 		alias ushort UnsignedBitsType;
1073 	else
1074 	static if (bits <= 32)
1075 		alias uint UnsignedBitsType;
1076 	else
1077 	static if (bits <= 64)
1078 		alias ulong UnsignedBitsType;
1079 	else
1080 		static assert(0, "No integer type big enough to fit " ~ bits.stringof ~ " bits");
1081 }
1082 
1083 /// ditto
1084 template SignedBitsType(uint bits)
1085 {
1086 	alias Signed!(UnsignedBitsType!bits) SignedBitsType;
1087 }
1088 
1089 /// Evaluates to array of strings with name for each field.
1090 @property string[] structFields(T)()
1091 	if (is(T == struct) || is(T == class))
1092 {
1093 	import std.string : split;
1094 
1095 	string[] fields;
1096 	foreach (i, f; T.init.tupleof)
1097 	{
1098 		string field = T.tupleof[i].stringof;
1099 		field = field.split(".")[$-1];
1100 		fields ~= field;
1101 	}
1102 	return fields;
1103 }
1104 
1105 /// Returns the class's initializer instance.
1106 /// Returns null if all class fields are zero.
1107 /// Can be used to get the value of class fields' initial values.
1108 immutable(T) classInit(T)()
1109 if (is(T == class))
1110 {
1111 	return cast(immutable(T))typeid(T).initializer.ptr;
1112 }
1113 
1114 ///
1115 unittest
1116 {
1117 	class C { int n = 42; }
1118 	assert(classInit!C.n == 42);
1119 }
1120 
1121 /// Create a functor value type (bound struct) from an alias.
1122 deprecated("Use ae.utils.functor")
1123 template functor(alias fun)
1124 {
1125 	struct Functor
1126 	{
1127 		//alias opCall = fun;
1128 		auto opCall(T...)(auto ref T args) { return fun(args); }
1129 	}
1130 
1131 	Functor functor()
1132 	{
1133 		Functor f;
1134 		return f;
1135 	}
1136 }
1137 
1138 static if (haveAliasStructBinding)
1139 unittest
1140 {
1141 	static void caller(F)(F fun)
1142 	{
1143 		fun(42);
1144 	}
1145 
1146 	int result;
1147 	caller(functor!((int i) => result = i));
1148 	assert(result == 42);
1149 }