aarch64: Fix sve/acle/general/ldff1_8.c failures
[gcc.git] / libphobos / libdruntime / core / internal / array / arrayassign.d
blob21690caf5d940e231c4fa5121d0726b02345b26f
1 module core.internal.array.arrayassign;
3 // Force `enforceRawArraysConformable` to remain `pure` `@nogc`
4 private void enforceRawArraysConformable(const char[] action, const size_t elementSize,
5 const void[] a1, const void[] a2, const bool allowOverlap) @trusted @nogc pure nothrow
7 import core.internal.util.array : enforceRawArraysConformable;
9 alias Type = void function(const char[] action, const size_t elementSize,
10 const void[] a1, const void[] a2, in bool allowOverlap = false) @nogc pure nothrow;
11 (cast(Type)&enforceRawArraysConformable)(action, elementSize, a1, a2, allowOverlap);
14 private template CopyElem(string CopyAction)
16 const char[] CopyElem = "{\n" ~ q{
17 memcpy(&tmp, cast(void*) &dst, elemSize);
18 } ~ CopyAction ~ q{
19 auto elem = cast(Unqual!T*) &tmp;
20 destroy(*elem);
21 } ~ "}\n";
24 private template CopyArray(bool CanOverlap, string CopyAction)
26 const char[] CopyArray = CanOverlap ? q{
27 if (vFrom.ptr < vTo.ptr && vTo.ptr < vFrom.ptr + elemSize * vFrom.length)
28 foreach_reverse (i, ref dst; to)
29 } ~ CopyElem!(CopyAction) ~ q{
30 else
31 foreach (i, ref dst; to)
32 } ~ CopyElem!(CopyAction)
33 : q{
34 foreach (i, ref dst; to)
35 } ~ CopyElem!(CopyAction);
38 private template ArrayAssign(string CopyLogic, string AllowOverLap)
40 const char[] ArrayAssign = q{
41 import core.internal.traits : hasElaborateCopyConstructor, Unqual;
42 import core.lifetime : copyEmplace;
43 import core.stdc.string : memcpy;
45 void[] vFrom = (cast(void*) from.ptr)[0 .. from.length];
46 void[] vTo = (cast(void*) to.ptr)[0 .. to.length];
47 enum elemSize = T.sizeof;
49 enforceRawArraysConformable("copy", elemSize, vFrom, vTo, } ~ AllowOverLap ~ q{);
51 void[elemSize] tmp = void;
53 } ~ CopyLogic ~ q{
55 return to;
59 /**
60 * Does array assignment (not construction) from another array of the same
61 * element type. Handles overlapping copies. Assumes the right hand side is an
62 * lvalue,
64 * Used for static array assignment with non-POD element types:
65 * ---
66 * struct S
67 * {
68 * ~this() {} // destructor, so not Plain Old Data
69 * }
71 * void main()
72 * {
73 * S[3] arr;
74 * S[3] lvalue;
76 * arr = lvalue;
77 * // Generates:
78 * // _d_arrayassign_l(arr[], lvalue[]), arr;
79 * }
80 * ---
82 * Params:
83 * to = destination array
84 * from = source array
85 * Returns:
86 * `to`
88 Tarr _d_arrayassign_l(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @trusted
90 mixin(ArrayAssign!(q{
91 static if (hasElaborateCopyConstructor!T)
92 } ~ CopyArray!(true, "copyEmplace(from[i], dst);") ~ q{
93 else
94 } ~ CopyArray!(true, "memcpy(cast(void*) &dst, cast(void*) &from[i], elemSize);"),
95 "true"));
98 @safe unittest
100 int counter;
101 struct S
103 int val;
104 this(int val) { this.val = val; }
105 this(const scope ref S rhs)
107 val = rhs.val;
108 counter++;
112 S[4] arr1;
113 S[4] arr2 = [S(0), S(1), S(2), S(3)];
114 _d_arrayassign_l(arr1[], arr2[]);
116 assert(counter == 4);
117 assert(arr1 == arr2);
120 // copy constructor
121 @safe unittest
123 int counter;
124 struct S
126 int val;
127 this(int val) { this.val = val; }
128 this(const scope ref S rhs)
130 val = rhs.val;
131 counter++;
135 S[4] arr1;
136 S[4] arr2 = [S(0), S(1), S(2), S(3)];
137 _d_arrayassign_l(arr1[], arr2[]);
139 assert(counter == 4);
140 assert(arr1 == arr2);
143 @safe nothrow unittest
145 // Test that throwing works
146 int counter;
147 bool didThrow;
149 struct Throw
151 int val;
152 this(this)
154 counter++;
155 if (counter == 2)
156 throw new Exception("");
161 Throw[4] a;
162 Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)];
163 _d_arrayassign_l(a[], b[]);
165 catch (Exception)
167 didThrow = true;
169 assert(didThrow);
170 assert(counter == 2);
173 // Test that `nothrow` works
174 didThrow = false;
175 counter = 0;
176 struct NoThrow
178 int val;
179 this(this)
181 counter++;
186 NoThrow[4] a;
187 NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];
188 _d_arrayassign_l(a[], b[]);
190 catch (Exception)
192 didThrow = false;
194 assert(!didThrow);
195 assert(counter == 4);
199 * Does array assignment (not construction) from another array of the same
200 * element type. Does not support overlapping copies. Assumes the right hand
201 * side is an rvalue,
203 * Used for static array assignment with non-POD element types:
204 * ---
205 * struct S
207 * ~this() {} // destructor, so not Plain Old Data
210 * void main()
212 * S[3] arr;
213 * S[3] getRvalue() {return lvalue;}
215 * arr = getRvalue();
216 * // Generates:
217 * // (__appendtmp = getRvalue), _d_arrayassign_l(arr[], __appendtmp), arr;
219 * ---
221 * Params:
222 * to = destination array
223 * from = source array
224 * Returns:
225 * `to`
227 Tarr _d_arrayassign_r(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @trusted
229 mixin(ArrayAssign!(
230 CopyArray!(false, "memcpy(cast(void*) &dst, cast(void*) &from[i], elemSize);"),
231 "false"));
234 @safe unittest
236 int counter;
237 struct S
239 int val;
240 this(int val) { this.val = val; }
241 this(const scope ref S rhs)
243 val = rhs.val;
244 counter++;
248 S[4] arr1;
249 S[4] arr2 = [S(0), S(1), S(2), S(3)];
250 _d_arrayassign_r(arr1[], arr2[]);
252 assert(counter == 0);
253 assert(arr1 == arr2);
256 // copy constructor
257 @safe unittest
259 int counter;
260 struct S
262 int val;
263 this(int val) { this.val = val; }
264 this(const scope ref S rhs)
266 val = rhs.val;
267 counter++;
271 S[4] arr1;
272 S[4] arr2 = [S(0), S(1), S(2), S(3)];
273 _d_arrayassign_r(arr1[], arr2[]);
275 assert(counter == 0);
276 assert(arr1 == arr2);
279 @safe nothrow unittest
281 // Test that `nothrow` works
282 bool didThrow = false;
283 int counter = 0;
284 struct NoThrow
286 int val;
287 this(this)
289 counter++;
294 NoThrow[4] a;
295 NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];
296 _d_arrayassign_r(a[], b[]);
298 catch (Exception)
300 didThrow = false;
302 assert(!didThrow);
303 assert(counter == 0);
307 * Sets all elements of an array to a single value. Takes into account postblits,
308 * copy constructors and destructors. For Plain Old Data elements,`rt/memset.d`
309 * is used.
311 * ---
312 * struct S
314 * ~this() {} // destructor, so not Plain Old Data
317 * void main()
319 * S[3] arr;
320 * S value;
322 * arr = value;
323 * // Generates:
324 * // _d_arraysetassign(arr[], value), arr;
326 * ---
328 * Params:
329 * to = destination array
330 * value = the element to set
331 * Returns:
332 * `to`
334 Tarr _d_arraysetassign(Tarr : T[], T)(return scope Tarr to, scope ref T value) @trusted
336 import core.internal.traits : Unqual;
337 import core.lifetime : copyEmplace;
338 import core.stdc.string : memcpy;
340 enum elemSize = T.sizeof;
341 void[elemSize] tmp = void;
343 foreach (ref dst; to)
345 memcpy(&tmp, cast(void*) &dst, elemSize);
346 // Use `memcpy` if `T` has a `@disable`d postblit.
347 static if (__traits(isCopyable, T))
348 copyEmplace(value, dst);
349 else
350 memcpy(cast(void*) &dst, cast(void*) &value, elemSize);
351 auto elem = cast(Unqual!T*) &tmp;
352 destroy(*elem);
355 return to;
358 // postblit and destructor
359 @safe unittest
361 string ops;
362 struct S
364 int val;
365 this(this) { ops ~= "="; }
366 ~this() { ops ~= "~"; }
369 S[4] arr;
370 S s = S(1234);
371 _d_arraysetassign(arr[], s);
372 assert(ops == "=~=~=~=~");
373 assert(arr == [S(1234), S(1234), S(1234), S(1234)]);
376 // copy constructor
377 @safe unittest
379 string ops;
380 struct S
382 int val;
383 this(const scope ref S rhs)
385 val = rhs.val;
386 ops ~= "=";
388 ~this() { ops ~= "~"; }
391 S[4] arr;
392 S s = S(1234);
393 _d_arraysetassign(arr[], s);
394 assert(ops == "=~=~=~=~");
395 assert(arr == [S(1234), S(1234), S(1234), S(1234)]);
398 // disabled copy constructor
399 @safe unittest
401 static struct S
403 int val;
404 @disable this(ref S);
406 S[1] arr;
407 S s = S(1234);
408 _d_arraysetassign(arr[], s);
409 assert(arr[0].val == 1234);
412 // throwing and `nothrow`
413 @safe nothrow unittest
415 // Test that throwing works
416 bool didThrow;
417 int counter;
418 struct Throw
420 int val;
421 this(this)
423 counter++;
424 if (counter == 2)
425 throw new Exception("Oh no.");
431 Throw[4] a;
432 Throw b = Throw(1);
433 _d_arraysetassign(a[], b);
435 catch (Exception)
437 didThrow = true;
439 assert(didThrow);
440 assert(counter == 2);
442 // Test that `nothrow` works
443 didThrow = false;
444 counter = 0;
445 struct NoThrow
447 int val;
448 this(this) { counter++; }
453 NoThrow[4] a;
454 NoThrow b = NoThrow(1);
455 _d_arraysetassign(a[], b);
456 foreach (ref e; a)
457 assert(e == NoThrow(1));
459 catch (Exception)
461 didThrow = true;
463 assert(!didThrow);
464 // The array `a` is destroyed when the `try` block ends.
465 assert(counter == 4);