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