@@ -26,6 +26,20 @@ struct DynamicArray(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange
2626
2727 private import stdx.allocator.common : stateSize;
2828
29+ static if (is (typeof ((T[] a, const T[] b) => a[0 .. b.length] = b[0 .. $])))
30+ {
31+ // / Either const(T) or T.
32+ alias AppendT = const (T);
33+
34+ // / Either const(typeof(this)) or typeof(this).
35+ alias AppendTypeOfThis = const (typeof (this ));
36+ }
37+ else
38+ {
39+ alias AppendT = T;
40+ alias AppendTypeOfThis = typeof (this );
41+ }
42+
2943 static if (stateSize! Allocator != 0 )
3044 {
3145 // / No default construction if an allocator must be provided.
@@ -123,7 +137,7 @@ struct DynamicArray(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange
123137 import std.traits : hasElaborateAssign, hasElaborateDestructor;
124138 static if (is (T == struct ) && (hasElaborateAssign! T || hasElaborateDestructor! T))
125139 {
126- // If a destructor is run before blit or copying involves
140+ // If a destructor is run before blit or assignment involves
127141 // more than just a blit, ensure that arr[l] is in a valid
128142 // state before assigning to it.
129143 import core.stdc.string : memcpy, memset;
@@ -147,29 +161,83 @@ struct DynamicArray(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange
147161 insert(value);
148162 }
149163
164+ /**
165+ * ~= operator overload for an array of items
166+ */
167+ void opOpAssign (string op, bool checkForOverlap = true )(AppendT[] rhs)
168+ if (op == " ~" && ! is (T == AppendT[]))
169+ {
170+ // Disabling checkForOverlap when this function is called from opBinary!"~"
171+ // is not just for efficiency, but to avoid circular function calls that
172+ // would prevent inference of @nogc, etc.
173+ static if (checkForOverlap)
174+ if ((() @trusted => arr.ptr <= rhs.ptr && arr.ptr + arr.length > rhs.ptr)())
175+ {
176+ // Special case where rhs is a slice of this array.
177+ this = this ~ rhs;
178+ return ;
179+ }
180+ reserve (l + rhs.length);
181+ import std.traits : hasElaborateAssign, hasElaborateDestructor;
182+ static if (is (T == struct ) && (hasElaborateAssign! T || hasElaborateDestructor! T))
183+ {
184+ // If a destructor is run before blit or assignment involves
185+ // more than just a blit, ensure that arr[l] is in a valid
186+ // state before assigning to it.
187+ import core.stdc.string : memcpy, memset;
188+ const init = typeid (T).initializer();
189+ if (init.ptr is null ) // null pointer means initialize to 0s
190+ {
191+ foreach (ref value; rhs)
192+ {
193+ // We could call memset just once for the entire range
194+ // but this way has better memory locality.
195+ (() @trusted => memset(arr.ptr + l, 0 , T.sizeof))();
196+ arr[l++ ] = value;
197+ }
198+ }
199+ else
200+ {
201+ foreach (ref value; rhs)
202+ {
203+ (() @trusted => memcpy(arr.ptr + l, init.ptr, T.sizeof))();
204+ arr[l++ ] = value;
205+ }
206+ }
207+ }
208+ else
209+ {
210+ arr[l .. l + rhs.length] = rhs[0 .. rhs.length];
211+ l += rhs.length;
212+ }
213+ }
214+
215+ // / ditto
216+ void opOpAssign (string op)(ref AppendTypeOfThis rhs)
217+ if (op == " ~" )
218+ {
219+ this ~= rhs.arr[0 .. rhs.l];
220+ }
221+
150222 /**
151223 * ~ operator overload
152224 */
153- typeof (this ) opBinary (string op)(ref typeof ( this ) other) if (op == " ~" )
225+ typeof (this ) opBinary (string op)(ref AppendTypeOfThis other) if (op == " ~" )
154226 {
155227 typeof (this ) ret;
156228 ret.reserve (l + other.l);
157- foreach (value; arr[0 .. l])
158- ret.insert(value);
159- foreach (value; other.arr[0 .. other.l])
160- ret.insert(value);
229+ ret.opOpAssign! (" ~" , false )(arr[0 .. l]);
230+ ret.opOpAssign! (" ~" , false )(other.arr[0 .. other.l]);
161231 return ret;
162232 }
163233
164234 // / ditto
165- typeof (this ) opBinary (string op)(T [] values ) if (op == " ~" )
235+ typeof (this ) opBinary (string op)(AppendT [] values ) if (op == " ~" )
166236 {
167237 typeof (this ) ret;
168238 ret.reserve (l + values .length);
169- foreach (value; arr[0 .. l])
170- ret.insert(value);
171- foreach (value; values )
172- ret.insert(value);
239+ ret.opOpAssign! (" ~" , false )(arr[0 .. l]);
240+ ret.opOpAssign! (" ~" , false )(values );
173241 return ret;
174242 }
175243
@@ -501,3 +569,13 @@ unittest
501569 auto hs = HStorage();
502570}
503571
572+ @nogc unittest
573+ {
574+ DynamicArray! char a;
575+ const DynamicArray! char b = a ~ " def" ;
576+ a ~= " abc" ;
577+ a ~= b;
578+ assert (a[] == " abcdef" );
579+ a ~= a;
580+ assert (a[] == " abcdefabcdef" );
581+ }
0 commit comments