@@ -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.
@@ -124,7 +138,7 @@ struct DynamicArray(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange
124138 import std.traits : hasElaborateAssign, hasElaborateDestructor;
125139 static if (is (T == struct ) && (hasElaborateAssign! T || hasElaborateDestructor! T))
126140 {
127- // If a destructor is run before blit or copying involves
141+ // If a destructor is run before blit or assignment involves
128142 // more than just a blit, ensure that arr[l] is in a valid
129143 // state before assigning to it.
130144 import core.stdc.string : memcpy, memset;
@@ -143,34 +157,90 @@ struct DynamicArray(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange
143157 /**
144158 * ~= operator overload
145159 */
146- void opOpAssign (string op)(T value) if (op == " ~" )
160+ scope ref typeof ( this ) opOpAssign(string op)(T value) if (op == " ~" )
147161 {
148162 insert(value);
163+ return this ;
164+ }
165+
166+ /**
167+ * ~= operator overload for an array of items
168+ */
169+ scope ref typeof (this ) opOpAssign(string op, bool checkForOverlap = true )(AppendT[] rhs)
170+ if (op == " ~" && ! is (T == AppendT[]))
171+ {
172+ // Disabling checkForOverlap when this function is called from opBinary!"~"
173+ // is not just for efficiency, but to avoid circular function calls that
174+ // would prevent inference of @nogc, etc.
175+ static if (checkForOverlap)
176+ if ((() @trusted => arr.ptr <= rhs.ptr && arr.ptr + arr.length > rhs.ptr)())
177+ {
178+ // Special case where rhs is a slice of this array.
179+ this = this ~ rhs;
180+ return this ;
181+ }
182+ reserve (l + rhs.length);
183+ import std.traits : hasElaborateAssign, hasElaborateDestructor;
184+ static if (is (T == struct ) && (hasElaborateAssign! T || hasElaborateDestructor! T))
185+ {
186+ // If a destructor is run before blit or assignment involves
187+ // more than just a blit, ensure that arr[l] is in a valid
188+ // state before assigning to it.
189+ import core.stdc.string : memcpy, memset;
190+ const init = typeid (T).initializer();
191+ if (init.ptr is null ) // null pointer means initialize to 0s
192+ {
193+ foreach (ref value; rhs)
194+ {
195+ // We could call memset just once for the entire range
196+ // but this way has better memory locality.
197+ (() @trusted => memset(arr.ptr + l, 0 , T.sizeof))();
198+ arr[l++ ] = value;
199+ }
200+ }
201+ else
202+ {
203+ foreach (ref value; rhs)
204+ {
205+ (() @trusted => memcpy(arr.ptr + l, init.ptr, T.sizeof))();
206+ arr[l++ ] = value;
207+ }
208+ }
209+ }
210+ else
211+ {
212+ arr[l .. l + rhs.length] = rhs[0 .. rhs.length];
213+ l += rhs.length;
214+ }
215+ return this ;
216+ }
217+
218+ // / ditto
219+ scope ref typeof (this ) opOpAssign(string op)(ref AppendTypeOfThis rhs)
220+ if (op == " ~" )
221+ {
222+ return this ~= rhs.arr[0 .. rhs.l];
149223 }
150224
151225 /**
152226 * ~ operator overload
153227 */
154- typeof (this ) opBinary (string op)(ref typeof ( this ) other) if (op == " ~" )
228+ typeof (this ) opBinary (string op)(ref AppendTypeOfThis other) if (op == " ~" )
155229 {
156230 typeof (this ) ret;
157231 ret.reserve (l + other.l);
158- foreach (value; arr[0 .. l])
159- ret.insert(value);
160- foreach (value; other.arr[0 .. other.l])
161- ret.insert(value);
232+ ret.opOpAssign! (" ~" , false )(arr[0 .. l]);
233+ ret.opOpAssign! (" ~" , false )(other.arr[0 .. other.l]);
162234 return ret;
163235 }
164236
165237 // / ditto
166- typeof (this ) opBinary (string op)(T [] values ) if (op == " ~" )
238+ typeof (this ) opBinary (string op)(AppendT [] values ) if (op == " ~" )
167239 {
168240 typeof (this ) ret;
169241 ret.reserve (l + values .length);
170- foreach (value; arr[0 .. l])
171- ret.insert(value);
172- foreach (value; values )
173- ret.insert(value);
242+ ret.opOpAssign! (" ~" , false )(arr[0 .. l]);
243+ ret.opOpAssign! (" ~" , false )(values );
174244 return ret;
175245 }
176246
@@ -502,3 +572,13 @@ unittest
502572 auto hs = HStorage();
503573}
504574
575+ @nogc unittest
576+ {
577+ DynamicArray! char a;
578+ const DynamicArray! char b = a ~ " def" ;
579+ a ~= " abc" ;
580+ a ~= b;
581+ assert (a[] == " abcdef" );
582+ a ~= a;
583+ assert (a[] == " abcdefabcdef" );
584+ }
0 commit comments