1 module nxt.appending;
2 
3 /** Append arguments $(args) to `data`.
4  *
5  * See_Also: http://forum.dlang.org/thread/mevnosveagdiswkxtbrv@forum.dlang.org?page=1
6  */
7 ref R append(R, Args...)(ref R data,
8                          auto ref Args args)
9 if (args.length != 0)
10 {
11     import std.range.primitives : ElementType, isRandomAccessRange;
12 
13     alias E = ElementType!R;
14 
15     import std.traits : isAssignable;
16     enum isElementType(U) = isAssignable!(E, U);
17 
18     import std.meta : allSatisfy;
19 
20     static if (args.length == 1)
21     {
22         data ~= args[0];
23     }
24     else static if (isRandomAccessRange!R &&
25                     allSatisfy!(isElementType, Args))
26     {
27         data.length += args.length;
28         foreach (i, arg; args)
29         {
30             data[$ - args.length + i] = arg;
31         }
32     }
33     else
34     {
35         static size_t estimateLength(Args args)
36         {
37             size_t result;
38             import std.traits : isArray;
39             foreach (arg; args)
40             {
41                 alias A = typeof(arg);
42                 import std.range.primitives : hasLength;
43                 static if (isArray!A &&
44                            is(E == ElementType!A) &&
45                            hasLength!A)
46                 {
47                     result += arg.length;
48                 }
49                 else
50                 {
51                     result += 1;
52                 }
53             }
54             // import std.stdio;
55             // writeln(args, ` : `, result);
56             return result;
57         }
58 
59         import std.range: appender;
60         auto app = appender!(R)(data);
61 
62         app.reserve(data.length + estimateLength(args));
63 
64         foreach (arg; args)
65         {
66             app.put(arg);
67         }
68         data = app.data;
69     }
70 
71     return data;
72 }
73 
74 ///
75 @safe pure nothrow unittest
76 {
77     int[] data;
78     import std.range: only, iota;
79 
80     data.append(-1, 0, only(1, 2, 3), iota(4, 9));
81     assert(data == [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8]);
82 
83     data.append(9, 10);
84     assert(data == [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
85 
86     data.append([11, 12], [13, 14]);
87     assert(data == [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]);
88 
89     // int[3] d;
90     // data.append(d, d);
91 
92     static assert(!__traits(compiles, { data.append(); }));
93 }