Disallow known empty ranges to be compared against a range with incompatible front

This commit is contained in:
Nick Treleaven 2016-10-22 16:24:18 +01:00
parent 2a45a145e8
commit 52a381320f

View file

@ -710,7 +710,6 @@ Compares two ranges for equality, as defined by predicate $(D pred)
*/ */
template equal(alias pred = "a == b") template equal(alias pred = "a == b")
{ {
/// Internal template - returns true if `R.empty == true`.
enum isEmptyRange(R) = enum isEmptyRange(R) =
isInputRange!R && __traits(compiles, {static assert(R.empty);}); isInputRange!R && __traits(compiles, {static assert(R.empty);});
@ -722,9 +721,6 @@ template equal(alias pred = "a == b")
evaluates to $(D bool). evaluates to $(D bool).
Performs $(BIGOH min(r1.length, r2.length)) evaluations of $(D pred). Performs $(BIGOH min(r1.length, r2.length)) evaluations of $(D pred).
Alternatively, if `Range1` or `Range2` satisfy $(LREF isEmptyRange),
`pred(r1.front, r2.front)` will $(B not) be evaluated.
Params: Params:
r1 = The first range to be compared. r1 = The first range to be compared.
r2 = The second range to be compared. r2 = The second range to be compared.
@ -738,8 +734,7 @@ template equal(alias pred = "a == b")
+/ +/
bool equal(Range1, Range2)(Range1 r1, Range2 r2) bool equal(Range1, Range2)(Range1 r1, Range2 r2)
if (isInputRange!Range1 && isInputRange!Range2 && if (isInputRange!Range1 && isInputRange!Range2 &&
(is(typeof(binaryFun!pred(r1.front, r2.front))) || is(typeof(binaryFun!pred(r1.front, r2.front))))
isEmptyRange!Range1 || isEmptyRange!Range2))
{ {
static assert(!(isInfinite!Range1 && isInfinite!Range2), static assert(!(isInfinite!Range1 && isInfinite!Range2),
"Both ranges are known to be infinite"); "Both ranges are known to be infinite");
@ -924,22 +919,19 @@ range of range (of range...) comparisons.
@safe pure unittest @safe pure unittest
{ {
struct R(T, bool _empty) { struct R(bool _empty) {
enum empty = _empty; enum empty = _empty;
@property T front(){assert(0);} @property char front(){assert(0);}
void popFront(){assert(0);} void popFront(){assert(0);}
} }
alias I = R!(char, false); alias I = R!false;
// infinite R1 should have compatible elements even with R2.length defined
static assert(!__traits(compiles, I().equal([cast(void*)null])));
static assert(!__traits(compiles, I().equal(I()))); static assert(!__traits(compiles, I().equal(I())));
// strings have fixed length so don't compare elements // strings have fixed length so don't need to compare elements
assert(!I().equal("foo")); assert(!I().equal("foo"));
assert(!"bar".equal(I())); assert(!"bar".equal(I()));
alias E = R!(void*, true); alias E = R!true;
assert(E().equal(E())); assert(E().equal(E()));
// incompatible front types should work with E
assert(E().equal("")); assert(E().equal(""));
assert("".equal(E())); assert("".equal(E()));
assert(!E().equal("foo")); assert(!E().equal("foo"));