Fix #60: Copying overlapping array slices
This commit is contained in:
		@@ -16,6 +16,7 @@ module tanya.algorithm.mutation;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static import tanya.memory.op;
 | 
					static import tanya.memory.op;
 | 
				
			||||||
import tanya.meta.trait;
 | 
					import tanya.meta.trait;
 | 
				
			||||||
 | 
					import tanya.meta.transform;
 | 
				
			||||||
import tanya.range;
 | 
					import tanya.range;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private void deinitialize(bool zero, T)(ref T value)
 | 
					private void deinitialize(bool zero, T)(ref T value)
 | 
				
			||||||
@@ -285,10 +286,13 @@ void swap(T)(ref T a, ref T b) @trusted
 | 
				
			|||||||
 *  source = Source input range.
 | 
					 *  source = Source input range.
 | 
				
			||||||
 *  target = Target output range.
 | 
					 *  target = Target output range.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns: $(D_PARAM target) range, whose front element is the one past the
 | 
				
			||||||
 | 
					 *          last element copied.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * Precondition: $(D_PARAM target) should be large enough to accept all
 | 
					 * Precondition: $(D_PARAM target) should be large enough to accept all
 | 
				
			||||||
 *               $(D_PARAM source) elements.
 | 
					 *               $(D_PARAM source) elements.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void copy(Source, Target)(Source source, Target target)
 | 
					Target copy(Source, Target)(Source source, Target target)
 | 
				
			||||||
if (isInputRange!Source && isOutputRange!(Target, Source))
 | 
					if (isInputRange!Source && isOutputRange!(Target, Source))
 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -301,27 +305,86 @@ do
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    alias E = ElementType!Source;
 | 
					    alias E = ElementType!Source;
 | 
				
			||||||
    static if (isDynamicArray!Source
 | 
					    static if (isDynamicArray!Source
 | 
				
			||||||
            && is(Source == Target)
 | 
					            && is(Unqual!E == ElementType!Target)
 | 
				
			||||||
            && !hasElaborateCopyConstructor!E
 | 
					            && !hasElaborateCopyConstructor!E
 | 
				
			||||||
            && !hasElaborateAssign!E)
 | 
					            && !hasElaborateAssign!E
 | 
				
			||||||
 | 
					            && !hasElaborateDestructor!E)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (source.ptr < target.ptr
 | 
				
			||||||
 | 
					         && (() @trusted => (target.ptr - source.ptr) < source.length)())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            tanya.memory.op.copyBackward(source, target);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (source.ptr !is target.ptr)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            tanya.memory.op.copy(source, target);
 | 
					            tanya.memory.op.copy(source, target);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        return target[source.length .. $];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        for (; !source.empty; source.popFront())
 | 
					        for (; !source.empty; source.popFront())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            put(target, source.front);
 | 
					            put(target, source.front);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        return target;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
@nogc nothrow pure @safe unittest
 | 
					@nogc nothrow pure @safe unittest
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int[2] actual;
 | 
					    import tanya.algorithm.comparison : equal;
 | 
				
			||||||
    int[2] expected = [2, 3];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    copy(actual[], expected[]);
 | 
					    const int[2] source = [1, 2];
 | 
				
			||||||
    assert(actual == expected);
 | 
					    int[2] target = [3, 4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    copy(source[], target[]);
 | 
				
			||||||
 | 
					    assert(equal(source[], target[]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Returns advanced target
 | 
				
			||||||
 | 
					@nogc nothrow pure @safe unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int[5] input = [1, 2, 3, 4, 5];
 | 
				
			||||||
 | 
					    assert(copy(input[3 .. 5], input[]).front == 3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Copies overlapping arrays
 | 
				
			||||||
 | 
					@nogc nothrow pure @safe unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    import tanya.algorithm.comparison : equal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int[6] actual = [1, 2, 3, 4, 5, 6];
 | 
				
			||||||
 | 
					    const int[6] expected = [1, 2, 1, 2, 3, 4];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    copy(actual[0 .. 4], actual[2 .. 6]);
 | 
				
			||||||
 | 
					    assert(equal(actual[], expected[]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@nogc nothrow pure @safe unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static assert(is(typeof(copy((ubyte[]).init, (ushort[]).init))));
 | 
				
			||||||
 | 
					    static assert(!is(typeof(copy((ushort[]).init, (ubyte[]).init))));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@nogc nothrow pure @safe unittest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    static struct OutPutRange
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int value;
 | 
				
			||||||
 | 
					        void put(int value) @nogc nothrow pure @safe
 | 
				
			||||||
 | 
					        in
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            assert(this.value == 0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        do
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            this.value = value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    int[1] source = [5];
 | 
				
			||||||
 | 
					    OutPutRange target;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(copy(source[], target).value == 5);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user