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