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