summaryrefslogtreecommitdiff
path: root/libphobos/libdruntime/core/internal/array/arrayassign.d
diff options
context:
space:
mode:
Diffstat (limited to 'libphobos/libdruntime/core/internal/array/arrayassign.d')
-rw-r--r--libphobos/libdruntime/core/internal/array/arrayassign.d148
1 files changed, 148 insertions, 0 deletions
diff --git a/libphobos/libdruntime/core/internal/array/arrayassign.d b/libphobos/libdruntime/core/internal/array/arrayassign.d
index 6132e68db1a..6e3c1fdc3ef 100644
--- a/libphobos/libdruntime/core/internal/array/arrayassign.d
+++ b/libphobos/libdruntime/core/internal/array/arrayassign.d
@@ -302,3 +302,151 @@ Tarr _d_arrayassign_r(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @tru
assert(!didThrow);
assert(counter == 0);
}
+
+/**
+ * Sets all elements of an array to a single value. Takes into account postblits,
+ * copy constructors and destructors. For Plain Old Data elements,`rt/memset.d`
+ * is used.
+ *
+ * ---
+ * struct S
+ * {
+ * ~this() {} // destructor, so not Plain Old Data
+ * }
+ *
+ * void main()
+ * {
+ * S[3] arr;
+ * S value;
+ *
+ * arr = value;
+ * // Generates:
+ * // _d_arraysetassign(arr[], value), arr;
+ * }
+ * ---
+ *
+ * Params:
+ * to = destination array
+ * value = the element to set
+ * Returns:
+ * `to`
+ */
+Tarr _d_arraysetassign(Tarr : T[], T)(return scope Tarr to, scope ref T value) @trusted
+{
+ import core.internal.traits : Unqual;
+ import core.lifetime : copyEmplace;
+ import core.stdc.string : memcpy;
+
+ enum elemSize = T.sizeof;
+ void[elemSize] tmp = void;
+
+ foreach (ref dst; to)
+ {
+ memcpy(&tmp, cast(void*) &dst, elemSize);
+ // Use `memcpy` if `T` has a `@disable`d postblit.
+ static if (__traits(isCopyable, T))
+ copyEmplace(value, dst);
+ else
+ memcpy(cast(void*) &value, cast(void*) &dst, elemSize);
+ auto elem = cast(Unqual!T*) &tmp;
+ destroy(*elem);
+ }
+
+ return to;
+}
+
+// postblit and destructor
+@safe unittest
+{
+ string ops;
+ struct S
+ {
+ int val;
+ this(this) { ops ~= "="; }
+ ~this() { ops ~= "~"; }
+ }
+
+ S[4] arr;
+ S s = S(1234);
+ _d_arraysetassign(arr[], s);
+ assert(ops == "=~=~=~=~");
+ assert(arr == [S(1234), S(1234), S(1234), S(1234)]);
+}
+
+// copy constructor
+@safe unittest
+{
+ string ops;
+ struct S
+ {
+ int val;
+ this(const scope ref S rhs)
+ {
+ val = rhs.val;
+ ops ~= "=";
+ }
+ ~this() { ops ~= "~"; }
+ }
+
+ S[4] arr;
+ S s = S(1234);
+ _d_arraysetassign(arr[], s);
+ assert(ops == "=~=~=~=~");
+ assert(arr == [S(1234), S(1234), S(1234), S(1234)]);
+}
+
+// throwing and `nothrow`
+@safe nothrow unittest
+{
+ // Test that throwing works
+ bool didThrow;
+ int counter;
+ struct Throw
+ {
+ int val;
+ this(this)
+ {
+ counter++;
+ if (counter == 2)
+ throw new Exception("Oh no.");
+ }
+ }
+
+ try
+ {
+ Throw[4] a;
+ Throw b = Throw(1);
+ _d_arraysetassign(a[], b);
+ }
+ catch (Exception)
+ {
+ didThrow = true;
+ }
+ assert(didThrow);
+ assert(counter == 2);
+
+ // Test that `nothrow` works
+ didThrow = false;
+ counter = 0;
+ struct NoThrow
+ {
+ int val;
+ this(this) { counter++; }
+ }
+
+ try
+ {
+ NoThrow[4] a;
+ NoThrow b = NoThrow(1);
+ _d_arraysetassign(a[], b);
+ foreach (ref e; a)
+ assert(e == NoThrow(1));
+ }
+ catch (Exception)
+ {
+ didThrow = true;
+ }
+ assert(!didThrow);
+ // The array `a` is destroyed when the `try` block ends.
+ assert(counter == 4);
+}