Make std.array.insertInPlace @safe for some cases

This commit is contained in:
Tomoya Tanjo 2013-12-16 20:56:23 +09:00
parent 899604e5a6
commit d9dc269747

View file

@ -872,8 +872,14 @@ private void copyBackwards(T)(T[] src, T[] dest)
{ {
import core.stdc.string; import core.stdc.string;
assert(src.length == dest.length); assert(src.length == dest.length);
void trustedMemmove(void* d, const void* s, size_t len) @trusted
{
memmove(d, s, len);
}
if (!__ctfe) if (!__ctfe)
memmove(dest.ptr, src.ptr, src.length * T.sizeof); trustedMemmove(dest.ptr, src.ptr, src.length * T.sizeof);
else else
{ {
immutable len = src.length; immutable len = src.length;
@ -903,6 +909,35 @@ void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
{ {
static if(allSatisfy!(isInputRangeWithLengthOrConvertible!T, U)) static if(allSatisfy!(isInputRangeWithLengthOrConvertible!T, U))
{ {
import core.stdc.string;
void assign(E)(ref T dest, ref E src)
{
static if (is(typeof(dest.opAssign(src))) ||
!is(typeof(dest = src)))
{
// this should be in-place construction
emplace(&dest, src);
}
else
{
dest = src;
}
}
auto trustedAllocateArray(size_t n) @trusted nothrow
{
return uninitializedArray!(T[])(n);
}
void trustedMemcopy(T[] dest, T[] src) @trusted
{
assert(src.length == dest.length);
if (!__ctfe)
memcpy(dest.ptr, src.ptr, src.length * T.sizeof);
else
{
dest[] = src[];
}
}
immutable oldLen = array.length; immutable oldLen = array.length;
size_t to_insert = 0; size_t to_insert = 0;
foreach (i, E; U) foreach (i, E; U)
@ -912,21 +947,25 @@ void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
else else
to_insert += stuff[i].length; to_insert += stuff[i].length;
} }
array.length += to_insert; auto tmp = trustedAllocateArray(to_insert);
copyBackwards(array[pos..oldLen], array[pos+to_insert..$]); auto j = 0;
auto ptr = array.ptr + pos;
foreach (i, E; U) foreach (i, E; U)
{ {
static if (is(E : T)) //ditto static if (is(E : T)) //ditto
{ {
emplace(ptr++, stuff[i]); assign(tmp[j++], stuff[i]);
} }
else else
{ {
foreach (v; stuff[i]) foreach (v; stuff[i])
emplace(ptr++, v); {
assign(tmp[j++], v);
}
} }
} }
array.length += to_insert;
copyBackwards(array[pos..oldLen], array[pos+to_insert..$]);
trustedMemcopy(array[pos..pos+to_insert], tmp);
} }
else else
{ {
@ -1048,7 +1087,7 @@ private template isInputRangeOrConvertible(E)
//Verify Example. //Verify Example.
unittest @safe unittest
{ {
int[] a = [ 1, 2, 3, 4 ]; int[] a = [ 1, 2, 3, 4 ];
a.insertInPlace(2, [ 1, 2 ]); a.insertInPlace(2, [ 1, 2 ]);
@ -1164,20 +1203,20 @@ unittest
} }
~this() ~this()
{ {
*payload = 0; //'destroy' it if (payload)
*payload = 0; //'destroy' it
} }
@property int getPayload(){ return *payload; } @property int getPayload(){ return *payload; }
alias getPayload this; alias getPayload this;
} }
Int[] arr;// = [Int(1), Int(4), Int(5)]; //@@BUG 8740 Int[] arr = [Int(1), Int(4), Int(5)];
arr ~= [Int(1), Int(4), Int(5)];
assert(arr[0] == 1); assert(arr[0] == 1);
insertInPlace(arr, 1, Int(2), Int(3)); insertInPlace(arr, 1, Int(2), Int(3));
assert(equal(arr, [1, 2, 3, 4, 5])); //check it works with postblit assert(equal(arr, [1, 2, 3, 4, 5])); //check it works with postblit
} }
unittest @safe unittest
{ {
assertCTFEable!( assertCTFEable!(
{ {