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