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
);
19 auto elem
= cast(Unqual
!T
*) &tmp
;
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
{
31 foreach (i
, ref dst
; to
)
32 } ~ CopyElem
!(CopyAction
)
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;
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
64 * Used for static array assignment with non-POD element types:
68 * ~this() {} // destructor, so not Plain Old Data
78 * // _d_arrayassign_l(arr[], lvalue[]), arr;
83 * to = destination array
88 Tarr
_d_arrayassign_l(Tarr
: T
[], T
)(return scope Tarr to
, scope Tarr from
) @trusted
91 static if (hasElaborateCopyConstructor
!T
)
92 } ~ CopyArray
!(true, "copyEmplace(from[i], dst);") ~ q
{
94 } ~ CopyArray
!(true, "memcpy(cast(void*) &dst, cast(void*) &from[i], elemSize);"),
104 this(int val
) { this.val
= val
; }
105 this(const scope ref S rhs
)
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
);
127 this(int val
) { this.val
= val
; }
128 this(const scope ref S rhs
)
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
156 throw new Exception("");
162 Throw
[4] b
= [Throw(1), Throw(2), Throw(3), Throw(4)];
163 _d_arrayassign_l(a
[], b
[]);
170 assert(counter
== 2);
173 // Test that `nothrow` works
187 NoThrow
[4] b
= [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];
188 _d_arrayassign_l(a
[], b
[]);
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
203 * Used for static array assignment with non-POD element types:
207 * ~this() {} // destructor, so not Plain Old Data
213 * S[3] getRvalue() {return lvalue;}
217 * // (__appendtmp = getRvalue), _d_arrayassign_l(arr[], __appendtmp), arr;
222 * to = destination array
223 * from = source array
227 Tarr
_d_arrayassign_r(Tarr
: T
[], T
)(return scope Tarr to
, scope Tarr from
) @trusted
230 CopyArray
!(false, "memcpy(cast(void*) &dst, cast(void*) &from[i], elemSize);"),
240 this(int val
) { this.val
= val
; }
241 this(const scope ref S rhs
)
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
);
263 this(int val
) { this.val
= val
; }
264 this(const scope ref S rhs
)
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;
295 NoThrow
[4] b
= [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];
296 _d_arrayassign_r(a
[], b
[]);
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`
314 * ~this() {} // destructor, so not Plain Old Data
324 * // _d_arraysetassign(arr[], value), arr;
329 * to = destination array
330 * value = the element to set
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
);
350 memcpy(cast(void*) &dst
, cast(void*) &value
, elemSize
);
351 auto elem
= cast(Unqual
!T
*) &tmp
;
358 // postblit and destructor
365 this(this) { ops
~= "="; }
366 ~this() { ops
~= "~"; }
371 _d_arraysetassign(arr
[], s
);
372 assert(ops
== "=~=~=~=~");
373 assert(arr
== [S(1234), S(1234), S(1234), S(1234)]);
383 this(const scope ref S rhs
)
388 ~this() { ops
~= "~"; }
393 _d_arraysetassign(arr
[], s
);
394 assert(ops
== "=~=~=~=~");
395 assert(arr
== [S(1234), S(1234), S(1234), S(1234)]);
398 // disabled copy constructor
404 @disable this(ref S
);
408 _d_arraysetassign(arr
[], s
);
409 assert(arr
[0].val
== 1234);
412 // throwing and `nothrow`
413 @safe nothrow unittest
415 // Test that throwing works
425 throw new Exception("Oh no.");
433 _d_arraysetassign(a
[], b
);
440 assert(counter
== 2);
442 // Test that `nothrow` works
448 this(this) { counter
++; }
454 NoThrow b
= NoThrow(1);
455 _d_arraysetassign(a
[], b
);
457 assert(e
== NoThrow(1));
464 // The array `a` is destroyed when the `try` block ends.
465 assert(counter
== 4);