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