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