Skip to content

Commit 3c0b47a

Browse files
authored
Merge pull request #4979 from WalterWaldron/fix16996
Fix Issue 16996 - std.algorithm.remove with SwapStrategy.unstable rem…
2 parents 29ec9ca + 99b74fb commit 3c0b47a

File tree

1 file changed

+96
-17
lines changed

1 file changed

+96
-17
lines changed

std/algorithm/mutation.d

Lines changed: 96 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,8 +1631,6 @@ if (s != SwapStrategy.stable
16311631
&& hasLength!Range
16321632
&& Offset.length >= 1)
16331633
{
1634-
import std.algorithm.comparison : min;
1635-
16361634
Tuple!(size_t, "pos", size_t, "len")[offset.length] blackouts;
16371635
foreach (i, v; offset)
16381636
{
@@ -1659,7 +1657,7 @@ if (s != SwapStrategy.stable
16591657

16601658
size_t left = 0, right = offset.length - 1;
16611659
auto tgt = range.save;
1662-
size_t steps = 0;
1660+
size_t tgtPos = 0;
16631661

16641662
while (left <= right)
16651663
{
@@ -1680,25 +1678,31 @@ if (s != SwapStrategy.stable
16801678
break;
16811679
}
16821680
// Advance to next blackout on the left
1683-
assert(blackouts[left].pos >= steps);
1684-
tgt.popFrontExactly(blackouts[left].pos - steps);
1685-
steps = blackouts[left].pos;
1686-
immutable toMove = min(
1687-
blackouts[left].len,
1688-
range.length - (blackouts[right].pos + blackouts[right].len));
1681+
assert(blackouts[left].pos >= tgtPos);
1682+
tgt.popFrontExactly(blackouts[left].pos - tgtPos);
1683+
tgtPos = blackouts[left].pos;
1684+
1685+
// Number of elements to the right of blackouts[right]
1686+
immutable tailLen = range.length - (blackouts[right].pos + blackouts[right].len);
1687+
size_t toMove = void;
1688+
if (tailLen < blackouts[left].len)
1689+
{
1690+
toMove = tailLen;
1691+
blackouts[left].pos += toMove;
1692+
blackouts[left].len -= toMove;
1693+
}
1694+
else
1695+
{
1696+
toMove = blackouts[left].len;
1697+
++left;
1698+
}
1699+
tgtPos += toMove;
16891700
foreach (i; 0 .. toMove)
16901701
{
16911702
move(range.back, tgt.front);
16921703
range.popBack();
16931704
tgt.popFront();
16941705
}
1695-
steps += toMove;
1696-
if (toMove == blackouts[left].len)
1697-
{
1698-
// Filled the entire left hole
1699-
++left;
1700-
continue;
1701-
}
17021706
}
17031707

17041708
return range;
@@ -1770,7 +1774,7 @@ if (s == SwapStrategy.stable
17701774
a = [ 0, 1, 2, 3, 4, 5 ];
17711775
assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 5, 2, 3, 4]);
17721776
a = [ 0, 1, 2, 3, 4, 5 ];
1773-
assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4)) == [0]);
1777+
assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4)) == [0, 5, 4]);
17741778
}
17751779

17761780
@safe unittest
@@ -1940,6 +1944,81 @@ if (isBidirectionalRange!Range
19401944
[ 1, 3, 3, 4, 5, 5, 6 ]);
19411945
}
19421946

1947+
@nogc unittest
1948+
{
1949+
// @nogc test
1950+
int[10] arr = [0,1,2,3,4,5,6,7,8,9];
1951+
alias pred = e => e < 5;
1952+
1953+
auto r = arr[].remove!(SwapStrategy.unstable)(0);
1954+
r = r.remove!(SwapStrategy.stable)(0);
1955+
r = r.remove!(pred, SwapStrategy.unstable);
1956+
r = r.remove!(pred, SwapStrategy.stable);
1957+
}
1958+
1959+
@safe unittest
1960+
{
1961+
import std.algorithm.comparison : min;
1962+
import std.algorithm.searching : all, any;
1963+
import std.algorithm.sorting : isStrictlyMonotonic;
1964+
import std.array : array;
1965+
import std.meta : AliasSeq;
1966+
import std.range : iota, only;
1967+
import std.typecons : Tuple;
1968+
alias S = Tuple!(int[2]);
1969+
S[] soffsets;
1970+
foreach (start; 0..5)
1971+
foreach (end; min(start+1,5) .. 5)
1972+
soffsets ~= S([start,end]);
1973+
alias D = Tuple!(int[2],int[2]);
1974+
D[] doffsets;
1975+
foreach (start1; 0..10)
1976+
foreach (end1; min(start1+1,10) .. 10)
1977+
foreach (start2; end1 ..10)
1978+
foreach (end2; min(start2+1,10) .. 10)
1979+
doffsets ~= D([start1,end1],[start2,end2]);
1980+
alias T = Tuple!(int[2],int[2],int[2]);
1981+
T[] toffsets;
1982+
foreach (start1; 0..15)
1983+
foreach (end1; min(start1+1,15) .. 15)
1984+
foreach (start2; end1..15)
1985+
foreach (end2; min(start2+1,15) .. 15)
1986+
foreach (start3; end2..15)
1987+
foreach (end3; min(start3+1,15) .. 15)
1988+
toffsets ~= T([start1,end1],[start2,end2],[start3,end3]);
1989+
1990+
static void verify(O...)(int[] r, int len, int removed, bool stable, O offsets)
1991+
{
1992+
assert(r.length == len - removed);
1993+
assert(!stable || r.isStrictlyMonotonic);
1994+
assert(r.all!(e => all!(o => e < o[0] || e >= o[1])(offsets.only)));
1995+
}
1996+
1997+
foreach (offsets; AliasSeq!(soffsets,doffsets,toffsets))
1998+
foreach (os; offsets)
1999+
{
2000+
int len = 5*os.length;
2001+
auto w = iota(0, len).array;
2002+
auto x = w.dup;
2003+
auto y = w.dup;
2004+
auto z = w.dup;
2005+
alias pred = e => any!(o => o[0] <= e && e < o[1])(only(os.expand));
2006+
w = w.remove!(SwapStrategy.unstable)(os.expand);
2007+
x = x.remove!(SwapStrategy.stable)(os.expand);
2008+
y = y.remove!(pred, SwapStrategy.unstable);
2009+
z = z.remove!(pred, SwapStrategy.stable);
2010+
int removed;
2011+
foreach (o; os)
2012+
removed += o[1] - o[0];
2013+
verify(w, len, removed, false, os[]);
2014+
verify(x, len, removed, true, os[]);
2015+
verify(y, len, removed, false, os[]);
2016+
verify(z, len, removed, true, os[]);
2017+
assert(w == y);
2018+
assert(x == z);
2019+
}
2020+
}
2021+
19432022
// reverse
19442023
/**
19452024
Reverses $(D r) in-place. Performs $(D r.length / 2) evaluations of $(D

0 commit comments

Comments
 (0)