Skip to content

Commit 7c2dc1c

Browse files
authored
Merge pull request #4957 from RazvanN7/Issue_16724
Fix Issue 16724 - RandomCover.popFront is a no-op for the first call
2 parents cf07aed + 17e3e64 commit 7c2dc1c

File tree

1 file changed

+39
-23
lines changed

1 file changed

+39
-23
lines changed

std/random.d

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2160,16 +2160,21 @@ struct RandomCover(Range, UniformRNG = void)
21602160
private bool[] _chosen;
21612161
private size_t _current;
21622162
private size_t _alreadyChosen = 0;
2163+
private bool _isEmpty = false;
21632164

21642165
static if (is(UniformRNG == void))
21652166
{
21662167
this(Range input)
21672168
{
21682169
_input = input;
21692170
_chosen.length = _input.length;
2170-
if (_chosen.length == 0)
2171+
if (_input.empty)
21712172
{
2172-
_alreadyChosen = 1;
2173+
_isEmpty = true;
2174+
}
2175+
else
2176+
{
2177+
_current = uniform(0, _chosen.length);
21732178
}
21742179
}
21752180
}
@@ -2182,9 +2187,13 @@ struct RandomCover(Range, UniformRNG = void)
21822187
_input = input;
21832188
_rng = rng;
21842189
_chosen.length = _input.length;
2185-
if (_chosen.length == 0)
2190+
if (_input.empty)
2191+
{
2192+
_isEmpty = true;
2193+
}
2194+
else
21862195
{
2187-
_alreadyChosen = 1;
2196+
_current = uniform(0, _chosen.length, rng);
21882197
}
21892198
}
21902199

@@ -2198,39 +2207,32 @@ struct RandomCover(Range, UniformRNG = void)
21982207
{
21992208
@property size_t length()
22002209
{
2201-
if (_alreadyChosen == 0)
2202-
{
2203-
return _input.length;
2204-
}
2205-
else
2206-
{
2207-
return (1 + _input.length) - _alreadyChosen;
2208-
}
2210+
return _input.length - _alreadyChosen;
22092211
}
22102212
}
22112213

22122214
@property auto ref front()
22132215
{
2214-
if (_alreadyChosen == 0)
2215-
{
2216-
popFront();
2217-
}
2216+
assert(!_isEmpty);
22182217
return _input[_current];
22192218
}
22202219

22212220
void popFront()
22222221
{
2223-
if (_alreadyChosen >= _input.length)
2222+
assert(!_isEmpty);
2223+
2224+
size_t k = _input.length - _alreadyChosen - 1;
2225+
if (k == 0)
22242226
{
2225-
// No more elements
2226-
++_alreadyChosen; // means we're done
2227+
_isEmpty = true;
2228+
++_alreadyChosen;
22272229
return;
22282230
}
2229-
size_t k = _input.length - _alreadyChosen;
2231+
22302232
size_t i;
22312233
foreach (e; _input)
22322234
{
2233-
if (_chosen[i]) { ++i; continue; }
2235+
if (_chosen[i] || i == _current) { ++i; continue; }
22342236
// Roll a dice with k faces
22352237
static if (is(UniformRNG == void))
22362238
{
@@ -2243,7 +2245,7 @@ struct RandomCover(Range, UniformRNG = void)
22432245
assert(k > 1 || chooseMe);
22442246
if (chooseMe)
22452247
{
2246-
_chosen[i] = true;
2248+
_chosen[_current] = true;
22472249
_current = i;
22482250
++_alreadyChosen;
22492251
return;
@@ -2264,7 +2266,7 @@ struct RandomCover(Range, UniformRNG = void)
22642266
}
22652267
}
22662268

2267-
@property bool empty() { return _alreadyChosen > _input.length; }
2269+
@property bool empty() { return _isEmpty; }
22682270
}
22692271

22702272
/// Ditto
@@ -2286,6 +2288,7 @@ auto randomCover(Range)(Range r)
22862288
import std.algorithm;
22872289
import std.conv;
22882290
int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ];
2291+
int[] c;
22892292
foreach (UniformRNG; std.meta.AliasSeq!(void, PseudoRngTypes))
22902293
{
22912294
static if (is(UniformRNG == void))
@@ -2302,6 +2305,8 @@ auto randomCover(Range)(Range r)
23022305
// check for constructor passed a value-type RNG
23032306
auto rc2 = RandomCover!(int[], UniformRNG)(a, UniformRNG(unpredictableSeed));
23042307
static assert(isForwardRange!(typeof(rc2)));
2308+
auto rcEmpty = randomCover(c, rng);
2309+
assert(rcEmpty.length == 0);
23052310
}
23062311

23072312
int[] b = new int[9];
@@ -2323,6 +2328,17 @@ auto randomCover(Range)(Range r)
23232328
auto rc = randomCover(r);
23242329
assert(rc.length == 0);
23252330
assert(rc.empty);
2331+
2332+
// Bugzilla 16724
2333+
import std.range : iota;
2334+
auto range = iota(10);
2335+
auto randy = range.randomCover;
2336+
2337+
for (int i=1; i<=range.length; i++)
2338+
{
2339+
randy.popFront;
2340+
assert(randy.length == range.length - i);
2341+
}
23262342
}
23272343

23282344
// RandomSample

0 commit comments

Comments
 (0)