263 lines
7.2 KiB
D
263 lines
7.2 KiB
D
|
/**
|
||
|
* Implementation of array assignment support routines.
|
||
|
*
|
||
|
*
|
||
|
* Copyright: Copyright Digital Mars 2010 - 2016.
|
||
|
* License: Distributed under the
|
||
|
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
|
||
|
* Authors: Walter Bright, Kenji Hara
|
||
|
* Source: $(DRUNTIMESRC rt/_arrayassign.d)
|
||
|
*/
|
||
|
|
||
|
module rt.arrayassign;
|
||
|
|
||
|
private
|
||
|
{
|
||
|
import core.internal.util.array;
|
||
|
import core.stdc.string;
|
||
|
import core.stdc.stdlib;
|
||
|
debug(PRINTF) import core.stdc.stdio;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Keep for backward binary compatibility. This function can be removed in the future.
|
||
|
*/
|
||
|
extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to)
|
||
|
{
|
||
|
debug(PRINTF) printf("_d_arrayassign(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize);
|
||
|
|
||
|
immutable elementSize = ti.tsize;
|
||
|
|
||
|
// Need a temporary buffer tmp[] big enough to hold one element
|
||
|
void[16] buf = void;
|
||
|
void* ptmp = (elementSize > buf.sizeof) ? malloc(elementSize) : buf.ptr;
|
||
|
scope (exit)
|
||
|
{
|
||
|
if (ptmp != buf.ptr)
|
||
|
free(ptmp);
|
||
|
}
|
||
|
return _d_arrayassign_l(ti, from, to, ptmp);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Does array assignment (not construction) from another
|
||
|
* lvalue array of the same element type.
|
||
|
* Handles overlapping copies.
|
||
|
* Input:
|
||
|
* ti TypeInfo of the element type.
|
||
|
* dst Points target memory. Its .length is equal to the element count, not byte length.
|
||
|
* src Points source memory. Its .length is equal to the element count, not byte length.
|
||
|
* ptmp Temporary memory for element swapping.
|
||
|
*/
|
||
|
extern (C) void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp)
|
||
|
{
|
||
|
debug(PRINTF) printf("_d_arrayassign_l(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize);
|
||
|
|
||
|
immutable elementSize = ti.tsize;
|
||
|
|
||
|
enforceRawArraysConformable("copy", elementSize, src, dst, true);
|
||
|
|
||
|
if (src.ptr < dst.ptr && dst.ptr < src.ptr + elementSize * src.length)
|
||
|
{
|
||
|
// If dst is in the middle of src memory, use reverse order.
|
||
|
for (auto i = dst.length; i--; )
|
||
|
{
|
||
|
void* pdst = dst.ptr + i * elementSize;
|
||
|
void* psrc = src.ptr + i * elementSize;
|
||
|
memcpy(ptmp, pdst, elementSize);
|
||
|
memcpy(pdst, psrc, elementSize);
|
||
|
ti.postblit(pdst);
|
||
|
ti.destroy(ptmp);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Otherwise, use normal order.
|
||
|
foreach (i; 0 .. dst.length)
|
||
|
{
|
||
|
void* pdst = dst.ptr + i * elementSize;
|
||
|
void* psrc = src.ptr + i * elementSize;
|
||
|
memcpy(ptmp, pdst, elementSize);
|
||
|
memcpy(pdst, psrc, elementSize);
|
||
|
ti.postblit(pdst);
|
||
|
ti.destroy(ptmp);
|
||
|
}
|
||
|
}
|
||
|
return dst;
|
||
|
}
|
||
|
|
||
|
unittest // Bugzilla 14024
|
||
|
{
|
||
|
string op;
|
||
|
|
||
|
struct S
|
||
|
{
|
||
|
char x = 'x';
|
||
|
this(this) { op ~= x-0x20; } // upper case
|
||
|
~this() { op ~= x; } // lower case
|
||
|
}
|
||
|
|
||
|
S[4] mem;
|
||
|
ref S[2] slice(int a, int b) { return mem[a .. b][0 .. 2]; }
|
||
|
|
||
|
op = null;
|
||
|
mem[0].x = 'a';
|
||
|
mem[1].x = 'b';
|
||
|
mem[2].x = 'x';
|
||
|
mem[3].x = 'y';
|
||
|
slice(0, 2) = slice(2, 4); // [ab] = [xy]
|
||
|
assert(op == "XaYb", op);
|
||
|
|
||
|
op = null;
|
||
|
mem[0].x = 'x';
|
||
|
mem[1].x = 'y';
|
||
|
mem[2].x = 'a';
|
||
|
mem[3].x = 'b';
|
||
|
slice(2, 4) = slice(0, 2); // [ab] = [xy]
|
||
|
assert(op == "XaYb", op);
|
||
|
|
||
|
op = null;
|
||
|
mem[0].x = 'a';
|
||
|
mem[1].x = 'b';
|
||
|
mem[2].x = 'c';
|
||
|
slice(0, 2) = slice(1, 3); // [ab] = [bc]
|
||
|
assert(op == "BaCb", op);
|
||
|
|
||
|
op = null;
|
||
|
mem[0].x = 'x';
|
||
|
mem[1].x = 'y';
|
||
|
mem[2].x = 'z';
|
||
|
slice(1, 3) = slice(0, 2); // [yz] = [xy]
|
||
|
assert(op == "YzXy", op);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Does array assignment (not construction) from another
|
||
|
* rvalue array of the same element type.
|
||
|
* Input:
|
||
|
* ti TypeInfo of the element type.
|
||
|
* dst Points target memory. Its .length is equal to the element count, not byte length.
|
||
|
* src Points source memory. Its .length is equal to the element count, not byte length.
|
||
|
* It is always allocated on stack and never overlapping with dst.
|
||
|
* ptmp Temporary memory for element swapping.
|
||
|
*/
|
||
|
extern (C) void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp)
|
||
|
{
|
||
|
debug(PRINTF) printf("_d_arrayassign_r(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize);
|
||
|
|
||
|
immutable elementSize = ti.tsize;
|
||
|
|
||
|
enforceRawArraysConformable("copy", elementSize, src, dst, false);
|
||
|
|
||
|
// Always use normal order, because we can assume that
|
||
|
// the rvalue src has no overlapping with dst.
|
||
|
foreach (i; 0 .. dst.length)
|
||
|
{
|
||
|
void* pdst = dst.ptr + i * elementSize;
|
||
|
void* psrc = src.ptr + i * elementSize;
|
||
|
memcpy(ptmp, pdst, elementSize);
|
||
|
memcpy(pdst, psrc, elementSize);
|
||
|
ti.destroy(ptmp);
|
||
|
}
|
||
|
return dst;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Does array initialization (not assignment) from another
|
||
|
* array of the same element type.
|
||
|
* ti is the element type.
|
||
|
*/
|
||
|
extern (C) void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to)
|
||
|
{
|
||
|
debug(PRINTF) printf("_d_arrayctor(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize);
|
||
|
|
||
|
|
||
|
auto element_size = ti.tsize;
|
||
|
|
||
|
enforceRawArraysConformable("initialization", element_size, from, to);
|
||
|
|
||
|
size_t i;
|
||
|
try
|
||
|
{
|
||
|
for (i = 0; i < to.length; i++)
|
||
|
{
|
||
|
// Copy construction is defined as bit copy followed by postblit.
|
||
|
memcpy(to.ptr + i * element_size, from.ptr + i * element_size, element_size);
|
||
|
ti.postblit(to.ptr + i * element_size);
|
||
|
}
|
||
|
}
|
||
|
catch (Throwable o)
|
||
|
{
|
||
|
/* Destroy, in reverse order, what we've constructed so far
|
||
|
*/
|
||
|
while (i--)
|
||
|
{
|
||
|
ti.destroy(to.ptr + i * element_size);
|
||
|
}
|
||
|
|
||
|
throw o;
|
||
|
}
|
||
|
return to;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Do assignment to an array.
|
||
|
* p[0 .. count] = value;
|
||
|
*/
|
||
|
extern (C) void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti)
|
||
|
{
|
||
|
void* pstart = p;
|
||
|
|
||
|
auto element_size = ti.tsize;
|
||
|
|
||
|
// Need a temporary buffer tmp[] big enough to hold one element
|
||
|
immutable maxAllocaSize = 512;
|
||
|
void *ptmp = (element_size > maxAllocaSize) ? malloc(element_size) : alloca(element_size);
|
||
|
|
||
|
foreach (i; 0 .. count)
|
||
|
{
|
||
|
memcpy(ptmp, p, element_size);
|
||
|
memcpy(p, value, element_size);
|
||
|
ti.postblit(p);
|
||
|
ti.destroy(ptmp);
|
||
|
p += element_size;
|
||
|
}
|
||
|
if (element_size > maxAllocaSize)
|
||
|
free(ptmp);
|
||
|
return pstart;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Do construction of an array.
|
||
|
* ti[count] p = value;
|
||
|
*/
|
||
|
extern (C) void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti)
|
||
|
{
|
||
|
void* pstart = p;
|
||
|
auto element_size = ti.tsize;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
foreach (i; 0 .. count)
|
||
|
{
|
||
|
// Copy construction is defined as bit copy followed by postblit.
|
||
|
memcpy(p, value, element_size);
|
||
|
ti.postblit(p);
|
||
|
p += element_size;
|
||
|
}
|
||
|
}
|
||
|
catch (Throwable o)
|
||
|
{
|
||
|
// Destroy, in reverse order, what we've constructed so far
|
||
|
while (p > pstart)
|
||
|
{
|
||
|
p -= element_size;
|
||
|
ti.destroy(p);
|
||
|
}
|
||
|
|
||
|
throw o;
|
||
|
}
|
||
|
return pstart;
|
||
|
}
|