1 module nxt.concatenation;
2 
3 /** Sum of the lengths of the static arrays 'A'.
4  */
5 template sumOfLengths(A...)
6 if (A.length) {
7 	static if (A.length == 1) {
8 		static if (isType!(A[0])) {
9 			static if (__traits(isStaticArray, A[0]))
10 				enum sumOfLengths = A[0].length;
11 			else
12 				enum sumOfLengths = 1;
13 		}
14 		else
15 		{
16 			static if (__traits(isStaticArray, typeof(A[0])))
17 				enum sumOfLengths = A[0].length;
18 			else
19 				enum sumOfLengths = 1;
20 		}
21 	}
22 	else
23 		enum sumOfLengths = A[0].length + sumOfLengths!(A[1 .. $]);
24 }
25 
26 /** Is `true` iff `T` is a type. */
27 private template isType(T)	   { enum isType = true; }
28 /// ditto
29 private template isType(alias T) { enum isType = false; }
30 
31 pure nothrow @safe @nogc unittest {
32 	int[2] x, y, z;
33 	int w;
34 	static assert(sumOfLengths!(x, y, z, w) == 7);
35 }
36 
37 /** Returns: concatenation of the static arrays `Args` as a static array.
38  * Move to Phobos's std.array.
39  */
40 StaticArrayElementType!(Args[0])[sumOfLengths!Args] concatenate(Args...)(const auto ref Args args) {
41 	pragma(inline, true);		 // must be inlineable
42 	typeof(return) result = void; // @trusted
43 	foreach (const i, arg; args) {
44 		static if (i == 0)
45 			enum offset = 0;
46 		else
47 			enum offset = sumOfLengths!(args[0 .. i]);
48 		static if (__traits(isStaticArray, typeof(arg)))
49 			result[offset .. offset + arg.length] = arg[];
50 		else
51 			result[offset] = arg;
52 	}
53 	return result;
54 }
55 
56 private alias StaticArrayElementType(A : E[n], E, size_t n) = E;
57 
58 pure nothrow @safe @nogc unittest {
59 	int[2] x = [11, 22];
60 	const int[2] y = [33, 44];
61 	const int w = 55;
62 	auto z = concatenate(x, y, w);
63 	static assert(is(typeof(z) == int[5]));
64 	assert(z == [11, 22, 33, 44, 55]);
65 }
66 
67 import core.internal.traits : hasElaborateDestructor;
68 import core.internal.traits : Unqual;
69 
70 /** Overload with faster compilation.
71  */
72 Unqual!T[n + 1] concatenate(T, size_t n)(auto ref T[n] a, T b)
73 if (!hasElaborateDestructor!T) {
74 	pragma(inline, true);		 // must be inlineable
75 	typeof(return) c = void;
76 	c[0 .. n] = a;
77 	c[n] = b;
78 	return c;
79 }
80 
81 pure nothrow @safe @nogc unittest {
82 	const int[2] x = [11, 22];
83 	int y = 33;
84 	auto z = concatenate(x, y);
85 	static assert(is(typeof(z) == int[3]));
86 	assert(z == [11, 22, 33]);
87 }