Add support for more than two arguments to std.algorithm.setIntersection

This seems to have always been intended to work, but was left unfinished.
The old documentation, as well as the current entry in the cheat sheet,
claimed it supported any number of arguments.
This commit is contained in:
Jakob Ovrum 2013-12-20 16:22:06 +09:00
parent ce25c43b2c
commit 1791e7c39d

View file

@ -10873,36 +10873,41 @@ unittest
}
/**
Lazily computes the intersection of two input ranges $(D
rs). The ranges are assumed to be sorted by $(D less). The element
types of both ranges must have a common type.
Lazily computes the intersection of two or more input ranges $(D
ranges). The ranges are assumed to be sorted by $(D less). The element
types of the ranges must have a common type.
*/
struct SetIntersection(alias less = "a < b", Rs...)
if (allSatisfy!(isInputRange, Rs))
if (allSatisfy!(isInputRange, Rs) &&
!is(CommonType!(staticMap!(ElementType, Rs)) == void))
{
static assert(Rs.length == 2);
private:
Rs _input;
alias binaryFun!(less) comp;
alias CommonType!(staticMap!(.ElementType, Rs)) ElementType;
alias comp = binaryFun!less;
alias ElementType = CommonType!(staticMap!(.ElementType, Rs));
// Positions to the first elements that are all equal
void adjustPosition()
{
// Positions to the first two elements that are equal
outer:
while (!empty)
{
if (comp(_input[0].front, _input[1].front))
foreach (i, ref r; _input[0 .. $ - 1])
{
_input[0].popFront();
}
else if (comp(_input[1].front, _input[0].front))
{
_input[1].popFront();
}
else
{
break;
alias next = _input[i + 1];
if (comp(r.front, next.front))
{
r.popFront();
continue outer;
}
if (comp(next.front, r.front))
{
next.popFront();
continue outer;
}
}
return;
}
}
@ -10916,9 +10921,9 @@ public:
@property bool empty()
{
foreach (i, U; Rs)
foreach (ref r; _input)
{
if (_input[i].empty) return true;
if (r.empty) return true;
}
return false;
}
@ -10926,10 +10931,16 @@ public:
void popFront()
{
assert(!empty);
assert(!comp(_input[0].front, _input[1].front)
&& !comp(_input[1].front, _input[0].front));
_input[0].popFront();
_input[1].popFront();
foreach (i, ref r; _input[0 .. $ - 1])
{
alias next = _input[i + 1];
assert(!comp(r.front, next.front) && !comp(next.front, r.front));
}
foreach (ref r; _input)
{
r.popFront();
}
adjustPosition();
}
@ -10941,7 +10952,7 @@ public:
static if (allSatisfy!(isForwardRange, Rs))
{
@property auto save()
@property SetIntersection save()
{
auto ret = this;
foreach (ti, elem; _input)
@ -10956,12 +10967,12 @@ public:
/// Ditto
SetIntersection!(less, Rs) setIntersection(alias less = "a < b", Rs...)
(Rs ranges)
if (allSatisfy!(isInputRange, Rs))
if (allSatisfy!(isInputRange, Rs) &&
!is(CommonType!(staticMap!(ElementType, Rs)) == void))
{
return typeof(return)(ranges);
}
/+ setIntersection doesn't yet support more than two inputs
///
unittest
{
@ -10969,18 +10980,35 @@ unittest
int[] b = [ 0, 1, 2, 4, 7, 8 ];
int[] c = [ 0, 1, 4, 5, 7, 8 ];
assert(equal(setIntersection(a, a), a));
assert(equal(setIntersection(a, b), [1, 2, 4, 7][]));
assert(equal(setIntersection(a, b, c), [1, 4, 7][]));
assert(equal(setIntersection(a, b), [1, 2, 4, 7]));
assert(equal(setIntersection(a, b, c), [1, 4, 7]));
}
+/
///
unittest
{
int[] a = [ 1, 2, 4, 5, 7, 9 ];
int[] b = [ 0, 1, 2, 4, 7, 8 ];
int[] c = [ 0, 1, 4, 5, 7, 8 ];
int[] d = [ 1, 3, 4 ];
int[] e = [ 4, 5 ];
assert(equal(setIntersection(a, a), a));
assert(equal(setIntersection(a, b), [1, 2, 4, 7][]));
assert(equal(setIntersection(a, a, a), a));
assert(equal(setIntersection(a, b), [1, 2, 4, 7]));
assert(equal(setIntersection(a, b, c), [1, 4, 7]));
assert(equal(setIntersection(a, b, c, d), [1, 4]));
assert(equal(setIntersection(a, b, c, d, e), [4]));
auto inpA = a.filter!(_ => true), inpB = b.filter!(_ => true);
auto inpC = c.filter!(_ => true), inpD = d.filter!(_ => true);
assert(equal(setIntersection(inpA, inpB, inpC, inpD), [1, 4]));
assert(equal(setIntersection(a, b, b, a), [1, 2, 4, 7]));
assert(equal(setIntersection(a, c, b), [1, 4, 7]));
assert(equal(setIntersection(b, a, c), [1, 4, 7]));
assert(equal(setIntersection(b, c, a), [1, 4, 7]));
assert(equal(setIntersection(c, a, b), [1, 4, 7]));
assert(equal(setIntersection(c, b, a), [1, 4, 7]));
}
/**