1 module tame.meta;
2 
3 import std.traits;
4 import std.meta : AliasSeq;
5 
6 template staticIota(int beg, int end) {
7 	static if (beg + 1 >= end) {
8 		static if (beg >= end) {
9 			alias staticIota = AliasSeq!();
10 		} else {
11 			alias staticIota = AliasSeq!beg;
12 		}
13 	} else {
14 		enum mid = beg + (end - beg) / 2;
15 		alias staticIota = AliasSeq!(staticIota!(beg, mid), staticIota!(mid, end));
16 	}
17 }
18 
19 template getUDA(alias sym, T) {
20 	static foreach (uda; __traits(getAttributes, sym))
21 		static if (is(typeof(uda) == T))
22 			alias getUDA = uda;
23 	static if (is(typeof(getUDA) == void))
24 		alias getUDA = T.init;
25 }
26 
27 alias CutOut(size_t I, T...) = AliasSeq!(T[0 .. I], T[I + 1 .. $]);
28 
29 /**
30  * Generates a mixin string for repeating code. It can be used to unroll variadic arguments.
31  * A format string is instantiated a certain number times with an incrementing parameter.
32  * The results are then concatenated using an optional joiner.
33  *
34  * Params:
35  *   length = Number of elements you want to join. It is passed into format() as an incrementing number from [0 .. count$(RPAREN).
36  *   fmt = The format string to apply on each instanciation. Use %1d$ to refer to the current index multiple times when necessary.
37  *   joiner = Optional string that will be placed between instances. It could be a space or an arithmetic operation.
38  *
39  * Returns:
40  *   The combined elements as a mixin string.
41  *
42  * See_Also:
43  *   $(LINK2 http://forum.dlang.org/thread/vqfvihyezbmwcjkmpzin@forum.dlang.org, A simple way to do compile time loop unrolling)
44  */
45 enum ctfeJoin(size_t length)(in string fmt, in string joiner = null) {
46 	import std.range : iota;
47 	import std.algorithm : map;
48 
49 	// BUG: Cannot use, join(), as it "cannot access the nested function 'ctfeJoin'".
50 	string result;
51 	foreach (inst; map!(i => format(fmt, i))(iota(length))) {
52 		if (result && joiner)
53 			result ~= joiner;
54 		result ~= inst;
55 	}
56 	return result;
57 }
58 
59 auto ParameterDefaultsCount(func...)() {
60 	template PDC(alias func, int cnt) {
61 		static if (__traits(compiles, func(Parameters!func[0 .. cnt])))
62 			enum PDC = PDC!(func, cnt - 1);
63 		else
64 			enum PDC = arity!func - cnt;
65 	}
66 
67 	size_t n;
68 	static foreach (f; func)
69 		n += PDC!(f, arity!f);
70 	return n;
71 }
72 
73 unittest {
74 	import tame.ascii;
75 
76 	static assert(ParameterDefaultsCount!classify == 0);
77 }
78 
79 /++
80 `_` is a enum that provides overloaded `=` operator. That overload takes a value and promptly throws it away.
81 Examples:
82 ---
83 _ = 2 + 3;
84 _ = new A();
85 ---
86 +/
87 enum _ = Impl();
88 
89 private struct Impl {
90 	/++
91 	Take an argument, throw it away and do nothing.
92 	Params:
93 		first = value to be ignored.
94 	+/
95 	pragma(inline, true);
96 	void opAssign(T)(in T) inout {
97 	}
98 }
99 
100 unittest {
101 	_ = 2;
102 	_ = _;
103 }
104 
105 /++
106 A copy of std::tie from C++.
107 TODO: write proper documentation for this
108 Examples:
109 ---
110 int a;
111 string b;
112 tie(a, b) = tuple(3, "hi");
113 assert(a == 3 && b == hi);
114 ---
115 +/
116 auto tie(T...)(out T args) {
117 	struct Impl {
118 		void opAssign(U)(U tuple) if (U.length == T.length) {
119 			static foreach (i; 0 .. U.length)
120 				args[i] = tuple[i];
121 		}
122 	}
123 
124 	return Impl();
125 }