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