blob: 13ec5fad40fde63125e69c9064fc533d000a890f [file] [log] [blame]
/**
This module contains support for controlling dynamic arrays' concatenation
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/_concatenation.d)
*/
module core.internal.array.concatenation;
/**
* Concatenate the arrays inside of `froms`.
* `_d_arraycatnTX(a, b, c)` means `a ~ b ~ c`.
*
* Params:
* froms = Arrays to be concatenated.
* Returns:
* A newly allocated array that contains all the elements from `froms`.
*/
Tret _d_arraycatnTX(Tret, Tarr...)(auto ref Tarr froms) @trusted
{
import core.internal.array.capacity : _d_arraysetlengthTImpl;
import core.internal.traits : hasElaborateCopyConstructor, Unqual;
import core.lifetime : copyEmplace;
import core.stdc.string : memcpy;
Tret res;
size_t totalLen;
alias T = typeof(res[0]);
enum elemSize = T.sizeof;
enum hasPostblit = __traits(hasPostblit, T);
static foreach (from; froms)
static if (is (typeof(from) : T))
totalLen++;
else
totalLen += from.length;
if (totalLen == 0)
return res;
// We cannot use this, because it refuses to work if the array type has disabled default construction.
// res.length = totalLen;
// Call the runtime function directly instead.
// TODO: once `__arrayAlloc` is templated, call that instead.
version (D_ProfileGC)
{
// TODO: forward file, line, name from _d_arraycatnTXTrace
_d_arraysetlengthTImpl!(typeof(res))._d_arraysetlengthTTrace(
res, totalLen, __FILE__, __LINE__, __FUNCTION__);
}
else
{
_d_arraysetlengthTImpl!(typeof(res))._d_arraysetlengthT(res, totalLen);
}
/* Currently, if both a postblit and a cpctor are defined, the postblit is
* used. If this changes, the condition below will have to be adapted.
*/
static if (hasElaborateCopyConstructor!T && !hasPostblit)
{
size_t i = 0;
foreach (ref from; froms)
static if (is(typeof(from) : T))
copyEmplace(cast(T) from, res[i++]);
else
{
if (from.length)
foreach (ref elem; from)
copyEmplace(cast(T) elem, res[i++]);
}
}
else
{
auto resptr = cast(Unqual!T *) res;
foreach (ref from; froms)
static if (is (typeof(from) : T))
memcpy(resptr++, cast(Unqual!T *) &from, elemSize);
else
{
const len = from.length;
if (len)
{
memcpy(resptr, cast(Unqual!T *) from, len * elemSize);
resptr += len;
}
}
static if (hasPostblit)
foreach (ref elem; res)
(cast() elem).__xpostblit();
}
return res;
}
// postblit
@safe unittest
{
int counter;
struct S
{
int val;
this(this)
{
counter++;
}
}
S[] arr1 = [S(0), S(1), S(2)];
S[] arr2 = [];
S[] arr3 = [S(6), S(7), S(8)];
S elem = S(9);
S[] result = _d_arraycatnTX!(S[])(arr1, arr2, arr3, elem);
assert(counter == 7);
assert(result == [S(0), S(1), S(2), S(6), S(7), S(8), S(9)]);
}
// copy constructor
@safe unittest
{
int counter;
struct S
{
int val;
this(ref return scope S rhs)
{
val = rhs.val;
counter++;
}
}
S[] arr1 = [S(0), S(1), S(2)];
S[] arr2 = [S(3), S(4), S(5)];
S[] arr3 = [S(6), S(7), S(8)];
S elem = S(9);
S[] result = _d_arraycatnTX!(S[])(arr1, elem, arr2, arr3);
assert(counter == 10);
assert(result == [S(0), S(1), S(2), S(9), S(3), S(4), S(5), S(6), S(7), S(8)]);
}
// throwing
@safe unittest
{
int counter;
bool didThrow;
struct S
{
int val;
this(this)
{
counter++;
if (counter == 4)
throw new Exception("");
}
}
try
{
S[] arr1 = [S(0), S(1), S(2)];
S[] arr2 = [S(3), S(4), S(5)];
_d_arraycatnTX!(S[])(arr1, arr2);
}
catch (Exception)
{
didThrow = true;
}
assert(counter == 4);
assert(didThrow);
}
version (D_ProfileGC)
{
/**
* TraceGC wrapper around $(REF _d_arraycatnTX, core,internal,array,concatenation).
*/
Tret _d_arraycatnTXTrace(Tret, Tarr...)(scope auto ref Tarr froms, string file = __FILE__, int line = __LINE__, string funcname = __FUNCTION__) @trusted
{
version (D_TypeInfo)
{
import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure;
mixin(TraceHook!(Tarr.stringof, "_d_arraycatnTX"));
import core.lifetime: forward;
return _d_arraycatnTX!Tret(forward!froms);
}
else
assert(0, "Cannot concatenate arrays if compiling without support for runtime type information!");
}
}