Fix moveEmplace for static arrays

This commit is contained in:
Eugen Wissner 2017-11-01 14:27:39 +01:00
parent 12fb9ff9f6
commit e06cc5a071
2 changed files with 66 additions and 22 deletions

View File

@ -17,6 +17,37 @@ module tanya.algorithm.mutation;
import tanya.memory.op; import tanya.memory.op;
import tanya.meta.trait; import tanya.meta.trait;
private void deinitialize(bool zero, T)(ref T value)
{
static if (is(T == U[S], U, size_t S))
{
foreach (ref e; value)
{
deinitialize!zero(e);
}
}
else
{
static if (isNested!T)
{
// Don't override the context pointer.
enum size_t size = T.sizeof - (void*).sizeof;
}
else
{
enum size_t size = T.sizeof;
}
static if (zero)
{
fill!0((cast(void*) &value)[0 .. size]);
}
else
{
copy(typeid(T).initializer()[0 .. size], (&value)[0 .. 1]);
}
}
}
/** /**
* Moves $(D_PARAM source) into $(D_PARAM target) assuming that * Moves $(D_PARAM source) into $(D_PARAM target) assuming that
* $(D_PARAM target) isn't initialized. * $(D_PARAM target) isn't initialized.
@ -48,30 +79,19 @@ in
} }
body body
{ {
static if (is(T == struct)) static if (is(T == struct) || isStaticArray!T)
{ {
copy((&source)[0 .. 1], (&target)[0 .. 1]); copy((&source)[0 .. 1], (&target)[0 .. 1]);
static if (hasElaborateCopyConstructor!T || hasElaborateDestructor!T) static if (hasElaborateCopyConstructor!T || hasElaborateDestructor!T)
{ {
static if (isNested!T) if (typeid(T).initializer().ptr is null)
{ {
// Don't override the context pointer. deinitialize!true(source);
enum size_t size = T.sizeof - (void*).sizeof;
} }
else else
{ {
enum size_t size = T.sizeof; deinitialize!false(source);
}
const(void)[] init = typeid(T).initializer();
if (init.ptr is null)
{
fill!0((cast(void*) &source)[0 .. size]);
}
else
{
copy(init[0 .. size], (&source)[0 .. 1]);
} }
} }
} }
@ -129,6 +149,28 @@ body
assert(source == target); assert(source == target);
} }
// Emplaces static arrays.
@nogc nothrow pure @system unittest
{
static struct S
{
size_t member;
this(size_t i) @nogc nothrow pure @safe
{
this.member = i;
}
~this() @nogc nothrow pure @safe
{
}
}
S[2] source = [ S(5), S(5) ], target = void;
moveEmplace(source, target);
assert(source[0].member == 0);
assert(target[0].member == 5);
assert(source[1].member == 0);
assert(target[1].member == 5);
}
/** /**
* Moves $(D_PARAM source) into $(D_PARAM target) assuming that * Moves $(D_PARAM source) into $(D_PARAM target) assuming that
* $(D_PARAM target) isn't initialized. * $(D_PARAM target) isn't initialized.

View File

@ -514,7 +514,6 @@ struct Array(T)
{ {
allocator.deallocate(buf); allocator.deallocate(buf);
} }
const T* end = this.data + this.length_;
for (T* src = this.data, dest = cast(T*) buf; src != end; ++src, ++dest) for (T* src = this.data, dest = cast(T*) buf; src != end; ++src, ++dest)
{ {
moveEmplace(*src, *dest); moveEmplace(*src, *dest);
@ -640,6 +639,11 @@ struct Array(T)
assert(v.removeBack(3) == 0); assert(v.removeBack(3) == 0);
} }
private @property inout(T)* end() inout
{
return this.data + this.length_;
}
/** /**
* Remove all elements beloning to $(D_PARAM r). * Remove all elements beloning to $(D_PARAM r).
* *
@ -660,12 +664,10 @@ struct Array(T)
} }
body body
{ {
auto end = this.data + this.length; auto target = r.begin;
auto source = Range(this, r.end, end); for (auto source = r.end; source != end; ++source, ++target)
auto target = Range(this, r.begin, end);
for (; !source.empty; source.popFront(), target.popFront())
{ {
move(source.front, target.front); move(*source, *target);
} }
length = length - r.length; length = length - r.length;
return Range(this, r.begin, this.data + length); return Range(this, r.begin, this.data + length);
@ -696,7 +698,7 @@ struct Array(T)
if (isImplicitlyConvertible!(R, T)) if (isImplicitlyConvertible!(R, T))
{ {
reserve(this.length + 1); reserve(this.length + 1);
moveEmplace(el, *(this.data + this.length_)); moveEmplace(el, *end);
++this.length_; ++this.length_;
} }