fix issue 155421

This commit is contained in:
somzzz 2016-12-08 09:41:07 -08:00
parent e93695e902
commit 682536d586
3 changed files with 121 additions and 4 deletions

View file

@ -3384,17 +3384,20 @@ auto topN(alias less = "a < b",
SwapStrategy ss = SwapStrategy.unstable,
Range1, Range2)(Range1 r1, Range2 r2)
if (isRandomAccessRange!(Range1) && hasLength!Range1 &&
isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2))
isInputRange!Range2 && is(ElementType!Range1 == ElementType!Range2) &&
hasLvalueElements!Range1 && hasLvalueElements!Range2)
{
import std.container : BinaryHeap;
static assert(ss == SwapStrategy.unstable,
"Stable topN not yet implemented");
auto heap = BinaryHeap!(Range1, less)(r1);
for (; !r2.empty; r2.popFront())
foreach (ref e; r2)
{
heap.conditionalInsert(r2.front);
heap.conditionalSwap(e);
}
return r1;
}
@ -3408,6 +3411,69 @@ unittest
assert(a == [0, 1, 2, 2, 3]);
}
// bug 15421
unittest
{
import std.algorithm.comparison : equal;
import std.internal.test.dummyrange;
import std.meta : AliasSeq;
alias RandomRanges = AliasSeq!(
DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random)
);
alias ReferenceRanges = AliasSeq!(
DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Forward),
DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Bidirectional),
DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random),
DummyRange!(ReturnBy.Reference, Length.No, RangeType.Forward),
DummyRange!(ReturnBy.Reference, Length.No, RangeType.Bidirectional));
foreach (T1; RandomRanges)
{
foreach (T2; ReferenceRanges)
{
import std.array;
T1 A;
T2 B;
A.reinit();
B.reinit();
topN(A, B);
// BUG(?): sort doesn't accept DummyRanges (needs Slicing and Length)
auto a = array(A);
auto b = array(B);
sort(a);
sort(b);
assert(equal(a, [ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 ]));
assert(equal(b, [ 6, 6, 7, 7, 8, 8, 9, 9, 10, 10 ]));
}
}
}
// bug 15421
unittest
{
auto a = [ 9, 8, 0, 3, 5, 25, 43, 4, 2, 0, 7 ];
auto b = [ 9, 8, 0, 3, 5, 25, 43, 4, 2, 0, 7 ];
topN(a, 4);
topN(b[0 .. 4], b[4 .. $]);
sort(a[0 .. 4]);
sort(a[4 .. $]);
sort(b[0 .. 4]);
sort(b[4 .. $]);
assert(a[0 .. 4] == b[0 .. 4]);
assert(a[4 .. $] == b[4 .. $]);
assert(a == b);
}
// bug 12987
unittest
{

View file

@ -369,14 +369,37 @@ must be collected.
insert(value);
return true;
}
// must replace the top
assert(!_store.empty, "Cannot replace front of an empty heap.");
if (!comp(value, _store.front)) return false; // value >= largest
_store.front = value;
percolate(_store[], 0, _length);
debug(BinaryHeap) assertValid();
return true;
}
/**
Swapping is allowed if the heap is full. If $(D less(value, front)), the
method exchanges store.front and value and returns $(D true). Otherwise, it
leaves the heap unaffected and returns $(D false).
*/
bool conditionalSwap(ref ElementType!Store value)
{
_payload.refCountedStore.ensureInitialized();
assert(_length == _store.length);
assert(!_store.empty, "Cannot swap front of an empty heap.");
if (!comp(value, _store.front)) return false; // value >= largest
import std.algorithm.mutation : swap;
swap(_store.front, value);
percolate(_store[], 0, _length);
debug(BinaryHeap) assertValid();
return true;
}
}
/// Example from "Introduction to Algorithms" Cormen et al, p 146
@ -409,6 +432,7 @@ initialized with $(D s) and $(D initialSize).
BinaryHeap!(Store, less) heapify(alias less = "a < b", Store)(Store s,
size_t initialSize = size_t.max)
{
return BinaryHeap!(Store, less)(s, initialSize);
}
@ -537,3 +561,25 @@ unittest
h.dup();
}));
}
unittest
{
import std.internal.test.dummyrange;
import std.algorithm.comparison : equal;
alias RefRange = DummyRange!(ReturnBy.Reference, Length.Yes, RangeType.Random);
RefRange a;
RefRange b;
a.reinit();
b.reinit();
auto heap = heapify(a);
foreach (ref elem; b)
{
heap.conditionalSwap(elem);
}
assert(equal(heap, [ 5, 5, 4, 4, 3, 3, 2, 2, 1, 1]));
assert(equal(b, [10, 9, 8, 7, 6, 6, 7, 8, 9, 10]));
}

View file

@ -169,6 +169,11 @@ struct DummyRange(ReturnBy _r, Length _l, RangeType _rt, T = uint[])
ret.arr = arr[lower..upper];
return ret;
}
typeof(this) opSlice()
{
return this;
}
}
static if (l == Length.Yes)