/** This module contains compiler support for constructing dynamic arrays Copyright: Copyright Digital Mars 2000 - 2019. License: Distributed under the $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). (See accompanying file LICENSE) Source: $(DRUNTIMESRC core/internal/_array/_construction.d)*/module core.internal.array.construction; import core.internal.traits : Unqual; debug(PRINTF){ import core.stdc.stdio : printf;} /** * Does array initialization (not assignment) from another array of the same element type. * Params: * to = what array to initialize * from = what data the array should be initialized with * makeWeaklyPure = unused; its purpose is to prevent the function from becoming * strongly pure and risk being optimised out * Returns: * The created and initialized array `to` * Bugs: * This function template was ported from a much older runtime hook that bypassed safety, * purity, and throwabilty checks. To prevent breaking existing code, this function template * is temporarily declared `@trusted` until the implementation can be brought up to modern D expectations. * * The third parameter is never used, but is necessary in order for the * function be treated as weakly pure, instead of strongly pure. * This is needed because constructions such as the one below can be ignored by * the compiler if `_d_arrayctor` is believed to be pure, because purity would * mean the call to `_d_arrayctor` has no effects (no side effects and the * return value is ignored), despite it actually modifying the contents of `a`. * const S[2] b; * const S[2] a = b; // this would get lowered to _d_arrayctor(a, b) */Tarr _d_arrayctor(Tarr : T[], T)(return scope Tarr to, scope Tarr from, char* makeWeaklyPure = null) @trusted{ version (DigitalMars) pragma(inline, false); import core.internal.traits : hasElaborateCopyConstructor; import core.lifetime : copyEmplace; import core.stdc.string : memcpy; import core.stdc.stdint : uintptr_t; debug(PRINTF) printf("_d_arrayctor(from = %p,%zd) size = %zd\n", from.ptr, from.length, T.sizeof); void[] vFrom = (cast(void*) from.ptr)[0..from.length]; void[] vTo = (cast(void*) to.ptr)[0..to.length]; // Force `enforceRawArraysConformable` to remain weakly `pure` void enforceRawArraysConformable(const char[] action, const size_t elementSize, const void[] a1, const void[] a2) @trusted { import core.internal.util.array : enforceRawArraysConformableNogc; alias Type = void function(const char[] action, const size_t elementSize, const void[] a1, const void[] a2, in bool allowOverlap = false) @nogc pure nothrow; (cast(Type)&enforceRawArraysConformableNogc)(action, elementSize, a1, a2, false); } enforceRawArraysConformable("initialization", T.sizeof, vFrom, vTo); static if (__traits(hasCopyConstructor, T)) { size_t i; try { for (i = 0; i < to.length; i++) copyEmplace(from[i], to[i]); } catch (Exception o) { /* Destroy, in reverse order, what we've constructed so far */ while (i--) { auto elem = cast(Unqual!T*) &to[i]; destroy(*elem); } throw o; } } else { if (to.length) { // blit all elements at once memcpy(cast(void*) to.ptr, from.ptr, to.length * T.sizeof); // call postblits if they exist static if (__traits(hasPostblit, T)) { import core.internal.lifetime : __doPostblit; size_t i = 0; try __doPostblit(to, i); catch (Exception o) { // Destroy, in reverse order, what we've constructed so far while (i--) { auto elem = cast(Unqual!T*) &to[i]; destroy(*elem); } throw o; } } } } return to;} // postblit@safe unittest{ int counter; struct S { int val; this(this) { counter++; } } S[4] arr1; S[4] arr2 = [S(0), S(1), S(2), S(3)]; _d_arrayctor(arr1[], arr2[]); assert(counter == 4); assert(arr1 == arr2);} // copy constructor@safe unittest{ int counter; struct S { int val; this(int val) { this.val = val; } this(const scope ref S rhs) { val = rhs.val; counter++; } } S[4] arr1; S[4] arr2 = [S(0), S(1), S(2), S(3)]; _d_arrayctor(arr1[], arr2[]); assert(counter == 4); assert(arr1 == arr2);} @safe nothrow unittest{ // Test that throwing works int counter; bool didThrow; struct Throw { int val; this(this) { counter++; if (counter == 2) throw new Exception(""); } } try { Throw[4] a; Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)]; _d_arrayctor(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[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)]; _d_arrayctor(a[], b[]); } catch (Exception) { didThrow = false; } assert(!didThrow); assert(counter == 4);} /** * Do construction of an array. * ti[count] p = value; * Params: * p = what array to initialize * value = what data to construct the array with * Bugs: * This function template was ported from a much older runtime hook that bypassed safety, * purity, and throwabilty checks. To prevent breaking existing code, this function template * is temporarily declared `@trusted` until the implementation can be brought up to modern D expectations. */void _d_arraysetctor(Tarr : T[], T)(scope Tarr p, scope ref T value) @trusted{ version (DigitalMars) pragma(inline, false); import core.lifetime : copyEmplace; size_t i; try { for (i = 0; i < p.length; i++) copyEmplace(value, p[i]); } catch (Exception o) { // Destroy, in reverse order, what we've constructed so far while (i--) { auto elem = cast(Unqual!T*)&p[i]; destroy(*elem); } throw o; }} // postblit@safe unittest{ int counter; struct S { int val; this(this) { counter++; } } S[4] arr; S s = S(1234); _d_arraysetctor(arr[], s); assert(counter == arr.length); assert(arr == [S(1234), S(1234), S(1234), S(1234)]);} // copy constructor@safe unittest{ int counter; struct S { int val; this(int val) { this.val = val; } this(const scope ref S rhs) { val = rhs.val; counter++; } } S[4] arr; S s = S(1234); _d_arraysetctor(arr[], s); assert(counter == arr.length); assert(arr == [S(1234), S(1234), S(1234), S(1234)]);} @safe nothrow unittest{ // Test that throwing works int counter; bool didThrow; struct Throw { int val; this(this) { counter++; if (counter == 2) throw new Exception("Oh no."); } } try { Throw[4] a; Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)]; _d_arrayctor(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_arraysetctor(a[], b); foreach (ref e; a) assert(e == NoThrow(1)); } catch (Exception) { didThrow = false; } assert(!didThrow); assert(counter == 4);} /** * Allocate an array with the garbage collector. Also initalize elements if * their type has an initializer. Otherwise, not zero-initialize the array. * * Has three variants: * `_d_newarrayU` leaves elements uninitialized * `_d_newarrayT` initializes to 0 or based on initializer * * Params: * length = `.length` of resulting array * * Returns: * newly allocated array */T[] _d_newarrayUPureNothrow(T)(size_t length, bool isShared=false) pure nothrow @trusted{ alias PureType = T[] function(size_t length, bool isShared) pure nothrow @trusted; return (cast(PureType) &_d_newarrayU!T)(length, isShared);} T[] _d_newarrayU(T)(size_t length, bool isShared=false) @trusted{ import core.checkedint : mulu; import core.exception : onOutOfMemoryError; import core.internal.traits : Unqual; import core.internal.array.utils : __arrayAlloc; alias UnqT = Unqual!T; size_t elemSize = T.sizeof; debug(PRINTF) printf("_d_newarrayU(length = x%zu, size = %zu)\n", length, elemSize); if (length == 0 || elemSize == 0) return null; bool overflow = false; const arraySize = mulu(elemSize, length, overflow); if (!overflow) { if (auto arr = __arrayAlloc!UnqT(arraySize)) { debug(PRINTF) printf("p = %p\n", arr.ptr); return (cast(T*) arr.ptr)[0 .. length]; } } onOutOfMemoryError(); assert(0);} /// dittoT[] _d_newarrayT(T)(size_t length, bool isShared=false) @trusted{ T[] result = _d_newarrayU!T(length, isShared); static if (__traits(isZeroInit, T)) { import core.stdc.string : memset; memset(result.ptr, 0, length * T.sizeof); } else { import core.internal.lifetime : emplaceInitializer; foreach (ref elem; result) emplaceInitializer(elem); } return result;} unittest{ { // zero-initialization struct S { int x, y; } S[] s = _d_newarrayT!S(10); assert(s !is null); assert(s.length == 10); foreach (ref elem; s) { assert(elem.x == 0); assert(elem.y == 0); } } { // S.init struct S { int x = 2, y = 3; } S[] s = _d_newarrayT!S(10); assert(s.length == 10); foreach (ref elem; s) { assert(elem.x == 2); assert(elem.y == 3); } }} unittest{ int pblits; struct S { this(this) { pblits++; } } S[] s = _d_newarrayT!S(2); assert(s.length == 2); assert(pblits == 0);} version (D_ProfileGC){ /** * TraceGC wrapper around $(REF _d_newarrayT, core,internal.array.construction). */ T[] _d_newarrayTTrace(T)(size_t length, bool isShared, string file = __FILE__, int line = __LINE__, string funcname = __FUNCTION__) @trusted { version (D_TypeInfo) { import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure; mixin(TraceHook!("T", "_d_newarrayT")); return _d_newarrayT!T(length, isShared); } else assert(0, "Cannot create new array if compiling without support for runtime type information!"); } /** * TraceGC wrapper around $(REF _d_newarrayU, core,internal.array.construction). */ T[] _d_newarrayUTrace(T)(size_t length, bool isShared, string file = __FILE__, int line = __LINE__, string funcname = __FUNCTION__) @trusted { version (D_TypeInfo) { import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure; mixin(TraceHook!("T", "_d_newarrayU")); return _d_newarrayUPureNothrow!T(length, isShared); } else assert(0, "Cannot create new array if compiling without support for runtime type information!"); }} /** * Create a new multi-dimensional array. Also initalize elements if their type has an initializer. * Otherwise, not zero-initialize the array.Lines 1–500 of 694. Load more
/** This module contains compiler support for constructing dynamic arrays Copyright: Copyright Digital Mars 2000 - 2019. License: Distributed under the $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). (See accompanying file LICENSE) Source: $(DRUNTIMESRC core/internal/_array/_construction.d) */ module core.internal.array.construction; import core.internal.traits : Unqual; debug(PRINTF) { import core.stdc.stdio : printf; } /** * Does array initialization (not assignment) from another array of the same element type. * Params: * to = what array to initialize * from = what data the array should be initialized with * makeWeaklyPure = unused; its purpose is to prevent the function from becoming * strongly pure and risk being optimised out * Returns: * The created and initialized array `to` * Bugs: * This function template was ported from a much older runtime hook that bypassed safety, * purity, and throwabilty checks. To prevent breaking existing code, this function template * is temporarily declared `@trusted` until the implementation can be brought up to modern D expectations. * * The third parameter is never used, but is necessary in order for the * function be treated as weakly pure, instead of strongly pure. * This is needed because constructions such as the one below can be ignored by * the compiler if `_d_arrayctor` is believed to be pure, because purity would * mean the call to `_d_arrayctor` has no effects (no side effects and the * return value is ignored), despite it actually modifying the contents of `a`. * const S[2] b; * const S[2] a = b; // this would get lowered to _d_arrayctor(a, b) */ Tarr _d_arrayctor(Tarr : T[], T)(return scope Tarr to, scope Tarr from, char* makeWeaklyPure = null) @trusted { version (DigitalMars) pragma(inline, false); import core.internal.traits : hasElaborateCopyConstructor; import core.lifetime : copyEmplace; import core.stdc.string : memcpy; import core.stdc.stdint : uintptr_t; debug(PRINTF) printf("_d_arrayctor(from = %p,%zd) size = %zd\n", from.ptr, from.length, T.sizeof); void[] vFrom = (cast(void*) from.ptr)[0..from.length]; void[] vTo = (cast(void*) to.ptr)[0..to.length]; // Force `enforceRawArraysConformable` to remain weakly `pure` void enforceRawArraysConformable(const char[] action, const size_t elementSize, const void[] a1, const void[] a2) @trusted { import core.internal.util.array : enforceRawArraysConformableNogc; alias Type = void function(const char[] action, const size_t elementSize, const void[] a1, const void[] a2, in bool allowOverlap = false) @nogc pure nothrow; (cast(Type)&enforceRawArraysConformableNogc)(action, elementSize, a1, a2, false); } enforceRawArraysConformable("initialization", T.sizeof, vFrom, vTo); static if (__traits(hasCopyConstructor, T)) { size_t i; try { for (i = 0; i < to.length; i++) copyEmplace(from[i], to[i]); } catch (Exception o) { /* Destroy, in reverse order, what we've constructed so far */ while (i--) { auto elem = cast(Unqual!T*) &to[i]; destroy(*elem); } throw o; } } else { if (to.length) { // blit all elements at once memcpy(cast(void*) to.ptr, from.ptr, to.length * T.sizeof); // call postblits if they exist static if (__traits(hasPostblit, T)) { import core.internal.lifetime : __doPostblit; size_t i = 0; try __doPostblit(to, i); catch (Exception o) { // Destroy, in reverse order, what we've constructed so far while (i--) { auto elem = cast(Unqual!T*) &to[i]; destroy(*elem); } throw o; } } } } return to; } // postblit @safe unittest { int counter; struct S { int val; this(this) { counter++; } } S[4] arr1; S[4] arr2 = [S(0), S(1), S(2), S(3)]; _d_arrayctor(arr1[], arr2[]); assert(counter == 4); assert(arr1 == arr2); } // copy constructor @safe unittest { int counter; struct S { int val; this(int val) { this.val = val; } this(const scope ref S rhs) { val = rhs.val; counter++; } } S[4] arr1; S[4] arr2 = [S(0), S(1), S(2), S(3)]; _d_arrayctor(arr1[], arr2[]); assert(counter == 4); assert(arr1 == arr2); } @safe nothrow unittest { // Test that throwing works int counter; bool didThrow; struct Throw { int val; this(this) { counter++; if (counter == 2) throw new Exception(""); } } try { Throw[4] a; Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)]; _d_arrayctor(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[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)]; _d_arrayctor(a[], b[]); } catch (Exception) { didThrow = false; } assert(!didThrow); assert(counter == 4); } /** * Do construction of an array. * ti[count] p = value; * Params: * p = what array to initialize * value = what data to construct the array with * Bugs: * This function template was ported from a much older runtime hook that bypassed safety, * purity, and throwabilty checks. To prevent breaking existing code, this function template * is temporarily declared `@trusted` until the implementation can be brought up to modern D expectations. */ void _d_arraysetctor(Tarr : T[], T)(scope Tarr p, scope ref T value) @trusted { version (DigitalMars) pragma(inline, false); import core.lifetime : copyEmplace; size_t i; try { for (i = 0; i < p.length; i++) copyEmplace(value, p[i]); } catch (Exception o) { // Destroy, in reverse order, what we've constructed so far while (i--) { auto elem = cast(Unqual!T*)&p[i]; destroy(*elem); } throw o; } } // postblit @safe unittest { int counter; struct S { int val; this(this) { counter++; } } S[4] arr; S s = S(1234); _d_arraysetctor(arr[], s); assert(counter == arr.length); assert(arr == [S(1234), S(1234), S(1234), S(1234)]); } // copy constructor @safe unittest { int counter; struct S { int val; this(int val) { this.val = val; } this(const scope ref S rhs) { val = rhs.val; counter++; } } S[4] arr; S s = S(1234); _d_arraysetctor(arr[], s); assert(counter == arr.length); assert(arr == [S(1234), S(1234), S(1234), S(1234)]); } @safe nothrow unittest { // Test that throwing works int counter; bool didThrow; struct Throw { int val; this(this) { counter++; if (counter == 2) throw new Exception("Oh no."); } } try { Throw[4] a; Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)]; _d_arrayctor(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_arraysetctor(a[], b); foreach (ref e; a) assert(e == NoThrow(1)); } catch (Exception) { didThrow = false; } assert(!didThrow); assert(counter == 4); } /** * Allocate an array with the garbage collector. Also initalize elements if * their type has an initializer. Otherwise, not zero-initialize the array. * * Has three variants: * `_d_newarrayU` leaves elements uninitialized * `_d_newarrayT` initializes to 0 or based on initializer * * Params: * length = `.length` of resulting array * * Returns: * newly allocated array */ T[] _d_newarrayUPureNothrow(T)(size_t length, bool isShared=false) pure nothrow @trusted { alias PureType = T[] function(size_t length, bool isShared) pure nothrow @trusted; return (cast(PureType) &_d_newarrayU!T)(length, isShared); } T[] _d_newarrayU(T)(size_t length, bool isShared=false) @trusted { import core.checkedint : mulu; import core.exception : onOutOfMemoryError; import core.internal.traits : Unqual; import core.internal.array.utils : __arrayAlloc; alias UnqT = Unqual!T; size_t elemSize = T.sizeof; debug(PRINTF) printf("_d_newarrayU(length = x%zu, size = %zu)\n", length, elemSize); if (length == 0 || elemSize == 0) return null; bool overflow = false; const arraySize = mulu(elemSize, length, overflow); if (!overflow) { if (auto arr = __arrayAlloc!UnqT(arraySize)) { debug(PRINTF) printf("p = %p\n", arr.ptr); return (cast(T*) arr.ptr)[0 .. length]; } } onOutOfMemoryError(); assert(0); } /// ditto T[] _d_newarrayT(T)(size_t length, bool isShared=false) @trusted { T[] result = _d_newarrayU!T(length, isShared); static if (__traits(isZeroInit, T)) { import core.stdc.string : memset; memset(result.ptr, 0, length * T.sizeof); } else { import core.internal.lifetime : emplaceInitializer; foreach (ref elem; result) emplaceInitializer(elem); } return result; } unittest { { // zero-initialization struct S { int x, y; } S[] s = _d_newarrayT!S(10); assert(s !is null); assert(s.length == 10); foreach (ref elem; s) { assert(elem.x == 0); assert(elem.y == 0); } } { // S.init struct S { int x = 2, y = 3; } S[] s = _d_newarrayT!S(10); assert(s.length == 10); foreach (ref elem; s) { assert(elem.x == 2); assert(elem.y == 3); } } } unittest { int pblits; struct S { this(this) { pblits++; } } S[] s = _d_newarrayT!S(2); assert(s.length == 2); assert(pblits == 0); } version (D_ProfileGC) { /** * TraceGC wrapper around $(REF _d_newarrayT, core,internal.array.construction). */ T[] _d_newarrayTTrace(T)(size_t length, bool isShared, string file = __FILE__, int line = __LINE__, string funcname = __FUNCTION__) @trusted { version (D_TypeInfo) { import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure; mixin(TraceHook!("T", "_d_newarrayT")); return _d_newarrayT!T(length, isShared); } else assert(0, "Cannot create new array if compiling without support for runtime type information!"); } /** * TraceGC wrapper around $(REF _d_newarrayU, core,internal.array.construction). */ T[] _d_newarrayUTrace(T)(size_t length, bool isShared, string file = __FILE__, int line = __LINE__, string funcname = __FUNCTION__) @trusted { version (D_TypeInfo) { import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure; mixin(TraceHook!("T", "_d_newarrayU")); return _d_newarrayUPureNothrow!T(length, isShared); } else assert(0, "Cannot create new array if compiling without support for runtime type information!"); } } /** * Create a new multi-dimensional array. Also initalize elements if their type has an initializer. * Otherwise, not zero-initialize the array.