diff --git a/source/tanya/algorithm/mutation.d b/source/tanya/algorithm/mutation.d index 2543cf9..5d09379 100644 --- a/source/tanya/algorithm/mutation.d +++ b/source/tanya/algorithm/mutation.d @@ -17,6 +17,37 @@ module tanya.algorithm.mutation; import tanya.memory.op; 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 * $(D_PARAM target) isn't initialized. @@ -48,30 +79,19 @@ in } body { - static if (is(T == struct)) + static if (is(T == struct) || isStaticArray!T) { copy((&source)[0 .. 1], (&target)[0 .. 1]); static if (hasElaborateCopyConstructor!T || hasElaborateDestructor!T) { - static if (isNested!T) + if (typeid(T).initializer().ptr is null) { - // Don't override the context pointer. - enum size_t size = T.sizeof - (void*).sizeof; + deinitialize!true(source); } else { - enum size_t size = T.sizeof; - } - - 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]); + deinitialize!false(source); } } } @@ -129,6 +149,28 @@ body 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 * $(D_PARAM target) isn't initialized. diff --git a/source/tanya/container/array.d b/source/tanya/container/array.d index ee0667c..409b57b 100644 --- a/source/tanya/container/array.d +++ b/source/tanya/container/array.d @@ -514,7 +514,6 @@ struct Array(T) { allocator.deallocate(buf); } - const T* end = this.data + this.length_; for (T* src = this.data, dest = cast(T*) buf; src != end; ++src, ++dest) { moveEmplace(*src, *dest); @@ -640,6 +639,11 @@ struct Array(T) assert(v.removeBack(3) == 0); } + private @property inout(T)* end() inout + { + return this.data + this.length_; + } + /** * Remove all elements beloning to $(D_PARAM r). * @@ -660,12 +664,10 @@ struct Array(T) } body { - auto end = this.data + this.length; - auto source = Range(this, r.end, end); - auto target = Range(this, r.begin, end); - for (; !source.empty; source.popFront(), target.popFront()) + auto target = r.begin; + for (auto source = r.end; source != end; ++source, ++target) { - move(source.front, target.front); + move(*source, *target); } length = length - r.length; return Range(this, r.begin, this.data + length); @@ -696,7 +698,7 @@ struct Array(T) if (isImplicitlyConvertible!(R, T)) { reserve(this.length + 1); - moveEmplace(el, *(this.data + this.length_)); + moveEmplace(el, *end); ++this.length_; }