Fix Issue 9702, 10930 - std.array.replace cannot simple replace an element in array

This commit is contained in:
Sebastian Wilzbach 2018-01-09 22:29:32 +01:00
parent 10a969ddaa
commit bf5dc02f1a

View file

@ -2336,21 +2336,30 @@ if (isInputRange!RoR &&
$(REF substitute, std,algorithm,iteration) for a lazy replace. $(REF substitute, std,algorithm,iteration) for a lazy replace.
+/ +/
E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to) E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to)
if (isDynamicArray!(E[]) && isForwardRange!R1 && isForwardRange!R2 if (isDynamicArray!(E[]) &&
&& (hasLength!R2 || isSomeString!R2)) ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
is(Unqual!E : Unqual!R1)))
{ {
import std.algorithm.searching : find; import std.algorithm.searching : find;
import std.range : dropOne; import std.range : dropOne;
if (from.empty) return subject; static if (isInputRange!R1)
{
if (from.empty) return subject;
alias rSave = a => a.save;
}
else
{
alias rSave = a => a;
}
auto balance = find(subject, from.save); auto balance = find(subject, rSave(from));
if (balance.empty) if (balance.empty)
return subject; return subject;
auto app = appender!(E[])(); auto app = appender!(E[])();
app.put(subject[0 .. subject.length - balance.length]); app.put(subject[0 .. subject.length - balance.length]);
app.put(to.save); app.put(rSave(to));
// replacing an element in an array is different to a range replacement // replacing an element in an array is different to a range replacement
static if (is(Unqual!E : Unqual!R1)) static if (is(Unqual!E : Unqual!R1))
replaceInto(app, balance.dropOne, from, to); replaceInto(app, balance.dropOne, from, to);
@ -2396,6 +2405,20 @@ if (isDynamicArray!(E[]) && isForwardRange!R1 && isForwardRange!R2
.replace([[0], [1, 2]], [[4]]) == [[4], [0], [3], [1, 2], [4]]); .replace([[0], [1, 2]], [[4]]) == [[4], [0], [3], [1, 2], [4]]);
} }
// https://issues.dlang.org/show_bug.cgi?id=10930
@safe unittest
{
assert([0, 1, 2].replace(1, 4) == [0, 4, 2]);
assert("äbö".replace('ä', 'a') == "abö");
}
// empty array
@safe unittest
{
int[] arr;
assert(replace(arr, 1, 2) == []);
}
/++ /++
Replace occurrences of `from` with `to` in `subject` and output the result into Replace occurrences of `from` with `to` in `subject` and output the result into
`sink`. `sink`.
@ -2410,28 +2433,36 @@ if (isDynamicArray!(E[]) && isForwardRange!R1 && isForwardRange!R2
$(REF substitute, std,algorithm,iteration) for a lazy replace. $(REF substitute, std,algorithm,iteration) for a lazy replace.
+/ +/
void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to) void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to)
if (isOutputRange!(Sink, E) && isDynamicArray!(E[]) if (isOutputRange!(Sink, E) && isDynamicArray!(E[]) &&
&& isForwardRange!R1 && isForwardRange!R2 ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
&& (hasLength!R2 || isSomeString!R2)) is(Unqual!E : Unqual!R1)))
{ {
import std.algorithm.searching : find; import std.algorithm.searching : find;
import std.range : dropOne; import std.range : dropOne;
if (from.empty) static if (isInputRange!R1)
{ {
sink.put(subject); if (from.empty)
return; {
sink.put(subject);
return;
}
alias rSave = a => a.save;
}
else
{
alias rSave = a => a;
} }
for (;;) for (;;)
{ {
auto balance = find(subject, from.save); auto balance = find(subject, rSave(from));
if (balance.empty) if (balance.empty)
{ {
sink.put(subject); sink.put(subject);
break; break;
} }
sink.put(subject[0 .. subject.length - balance.length]); sink.put(subject[0 .. subject.length - balance.length]);
sink.put(to.save); sink.put(rSave(to));
// replacing an element in an array is different to a range replacement // replacing an element in an array is different to a range replacement
static if (is(Unqual!E : Unqual!R1)) static if (is(Unqual!E : Unqual!R1))
subject = balance.dropOne; subject = balance.dropOne;
@ -2453,6 +2484,15 @@ if (isOutputRange!(Sink, E) && isDynamicArray!(E[])
assert(sink.data == [1, 4, 6, 4, 5]); assert(sink.data == [1, 4, 6, 4, 5]);
} }
// empty array
@safe unittest
{
auto sink = appender!(int[])();
int[] arr;
replaceInto(sink, arr, 1, 2);
assert(sink.data == []);
}
@safe unittest @safe unittest
{ {
import std.algorithm.comparison : cmp; import std.algorithm.comparison : cmp;
@ -2506,6 +2546,18 @@ if (isOutputRange!(Sink, E) && isDynamicArray!(E[])
}} }}
} }
// https://issues.dlang.org/show_bug.cgi?id=10930
@safe unittest
{
auto sink = appender!(int[])();
replaceInto(sink, [0, 1, 2], 1, 5);
assert(sink.data == [0, 5, 2]);
auto sink2 = appender!(dchar[])();
replaceInto(sink2, "äbö", 'ä', 'a');
assert(sink2.data == "abö");
}
/++ /++
Replaces elements from `array` with indices ranging from `from` Replaces elements from `array` with indices ranging from `from`
(inclusive) to `to` (exclusive) with the range `stuff`. (inclusive) to `to` (exclusive) with the range `stuff`.