Skip to content

Commit

Permalink
Fix Issue 14817 - std.algorithm.copy/std.file.copy conflict
Browse files Browse the repository at this point in the history
#2799 introduced a regression, which prevented module that imported both std.algorithm and std.file to use unqualified calls to copy(string, string). The regression was caused by the removal of template constraints, which were preventing the std.algorithm copy from being considered for overload resolution.

std.algorithm.copy has two paths: an path for array copies, and a path for all other copies. Previously they were forked using static if inside function. Now the decision is made using template constraints.
  • Loading branch information
Poita authored and Dmitry Olshansky committed Sep 12, 2015
1 parent 07ee2eb commit 1e7246b
Showing 1 changed file with 49 additions and 50 deletions.
99 changes: 49 additions & 50 deletions std/algorithm/mutation.d
Expand Up @@ -71,7 +71,7 @@ T2=$(TR $(TDNW $(LREF $1)) $(TD $+))
module std.algorithm.mutation;

import std.range.primitives;
import std.traits : isBlitAssignable, isNarrowString;
import std.traits : isArray, isBlitAssignable, isNarrowString, Unqual;
// FIXME
import std.typecons; // : tuple, Tuple;

Expand Down Expand Up @@ -283,6 +283,10 @@ Elements can be swapped across ranges of different types:
}
}

// Tests if types are arrays and support slice assign.
private enum bool areCopyCompatibleArrays(T1, T2) =
isArray!T1 && isArray!T2 && is(typeof(T2.init[] = T1.init[]));

// copy
/**
Copies the content of $(D source) into $(D target) and returns the
Expand All @@ -295,62 +299,57 @@ See_Also:
$(WEB sgi.com/tech/stl/_copy.html, STL's _copy)
*/
TargetRange copy(SourceRange, TargetRange)(SourceRange source, TargetRange target)
if (areCopyCompatibleArrays!(SourceRange, TargetRange))
{
import std.traits : isArray, Unqual;
static if (isArray!SourceRange && isArray!TargetRange &&
is(Unqual!(typeof(source[0])) == Unqual!(typeof(target[0]))))
{
const tlen = target.length;
const slen = source.length;
assert(tlen >= slen,
"Cannot copy a source range into a smaller target range.");
const tlen = target.length;
const slen = source.length;
assert(tlen >= slen,
"Cannot copy a source range into a smaller target range.");

immutable overlaps = () @trusted {
return source.ptr < target.ptr + tlen &&
target.ptr < source.ptr + slen; }();
immutable overlaps = () @trusted {
return source.ptr < target.ptr + tlen &&
target.ptr < source.ptr + slen; }();

if (overlaps)
{
foreach (idx; 0 .. slen)
target[idx] = source[idx];
return target[slen .. tlen];
}
else
{
// Array specialization. This uses optimized memory copying
// routines under the hood and is about 10-20x faster than the
// generic implementation.
target[0 .. slen] = source[];
return target[slen .. $];
}
if (overlaps)
{
foreach (idx; 0 .. slen)
target[idx] = source[idx];
return target[slen .. tlen];
}
else static if (isInputRange!SourceRange &&
isOutputRange!(TargetRange, ElementType!SourceRange))
{
// Specialize for 2 random access ranges.
// Typically 2 random access ranges are faster iterated by common
// index than by x.popFront(), y.popFront() pair
static if (isRandomAccessRange!SourceRange &&
hasLength!SourceRange &&
hasSlicing!TargetRange &&
isRandomAccessRange!TargetRange &&
hasLength!TargetRange)
{
auto len = source.length;
foreach (idx; 0 .. len)
target[idx] = source[idx];
return target[len .. $];
}
else
{
put(target, source);
return target;
}
else
{
// Array specialization. This uses optimized memory copying
// routines under the hood and is about 10-20x faster than the
// generic implementation.
target[0 .. slen] = source[];
return target[slen .. $];
}
}

/// ditto
TargetRange copy(SourceRange, TargetRange)(SourceRange source, TargetRange target)
if (!areCopyCompatibleArrays!(SourceRange, TargetRange) &&
isInputRange!SourceRange &&
isOutputRange!(TargetRange, ElementType!SourceRange))
{
// Specialize for 2 random access ranges.
// Typically 2 random access ranges are faster iterated by common
// index than by x.popFront(), y.popFront() pair
static if (isRandomAccessRange!SourceRange &&
hasLength!SourceRange &&
hasSlicing!TargetRange &&
isRandomAccessRange!TargetRange &&
hasLength!TargetRange)
{
auto len = source.length;
foreach (idx; 0 .. len)
target[idx] = source[idx];
return target[len .. $];
}
else
{
static assert(false, "Cannot copy " ~ SourceRange.stringof ~
" into " ~ TargetRange.stringof);
put(target, source);
return target;
}
}

Expand Down

0 comments on commit 1e7246b

Please sign in to comment.