D-Programming-Language/phobos — pull request #839 by monarchdodra (2012-10-05 16:11:40+00:00)
Title: Copy

A light re-implementation of copy. I also had this lying around

*implementation* Changes include:
*A *lighter* overlap check (just two comparions)
*A *tighter* overlap check (no need to check the *entire* target slice)
*`genericImpl` was removed and changed into the simple `put(target, source)`.

Apart from the rather big block that processes overlap, the bulk of copy is trivially simple:
*Array? opSliceAssign
*Not array? put.

New implementation
```D
Range2 copy(Range1, Range2)(Range1 source, Range2 target)
if (isInputRange!Range1 && isOutputRange!(Range2, ElementType!Range1))
{
static if (isArray!Range1 && isArray!Range2 && is(typeof(target[] = source[])))
{
//Optimization possible for arrays, because they can use "opSliceSliceAssign"
auto len = source.length;
assert(target.length >= len, "source array is smaller than target array: can not copy.");

//Check that source[] and target[0 .. len] don't overlap
//Can't use std.array.overlap because of @@@BUG@@@ 7898,
auto overlaps = !(source.ptr + len <= target.ptr ||
target.ptr + len <= source.ptr);

if (overlaps)
{
//Overlaps, see if we can copy chunk by chunk
size_t step = abs(source.ptr - target.ptr);
if (step > 1) //Anything containing 2 or more elements should profit from slice copy.
{
size_t low = 0;
for( ; low + step < len ; low += step)
target[low .. low + step] = source[low .. low + step];
target[low .. len] = source[low .. len];
}
else if (step != 0) // => step == 1
{
//Too much overlap, just copy 1 by 1.
foreach (i ; 0 .. len)
target[i] = source[i];
}
}
else
{
//No overlap. Do a straight up slice copy
target[0 .. len] = source[];
}
target = target[len .. $];
}
else
{
put(target, source);
}
return target;
}
```