Skip to content

Instantly share code, notes, and snippets.

@CaseyCarter
Created November 19, 2015 18:28
Show Gist options
  • Select an option

  • Save CaseyCarter/784067122e7d7de4b665 to your computer and use it in GitHub Desktop.

Select an option

Save CaseyCarter/784067122e7d7de4b665 to your computer and use it in GitHub Desktop.
We can't require [i,s) equals [i,t) to imply s == t
#include <experimental/ranges/algorithm>
#include <cassert>
using namespace std::experimental::ranges;
struct S {
int limit;
#if FOO
friend bool operator==(const S& a, const S& b) { return true; }
friend bool operator!=(const S& a, const S& b) { return false; }
#else
friend bool operator==(const S& a, const S& b) { return a.limit == b.limit; }
friend bool operator!=(const S& a, const S& b) { return !(a == b); }
#endif
template <InputIterator I>
requires
StrictTotallyOrdered<int, value_type_t<I>>()
friend bool operator==(const I& i, const S& s) { return *i >= s.limit; }
template <InputIterator I>
requires
StrictTotallyOrdered<int, value_type_t<I>>()
friend bool operator==(const S& s, const I& i) { return i == s; }
template <InputIterator I>
requires
StrictTotallyOrdered<int, value_type_t<I>>()
friend bool operator!=(const I& i, const S& s) { return !(i == s); }
template <InputIterator I>
requires
StrictTotallyOrdered<int, value_type_t<I>>()
friend bool operator!=(const S& s, const I& i) { return !(i == s); }
};
namespace std { namespace experimental { namespace ranges {
template <InputIterator I>
requires StrictTotallyOrdered<int, value_type_t<I>>()
struct common_type<I, ::S> : meta::id<common_iterator<I, ::S>> {};
template <InputIterator I>
requires StrictTotallyOrdered<int, value_type_t<I>>()
struct common_type<::S, I> : meta::id<common_iterator<I, ::S>> {};
}}}
static_assert(models::Sentinel<S,int*>);
int main() {
#if FOO
int some_ints[] = {0,1,2,3,5,9,42};
auto s1 = S{5};
auto s2 = S{8};
// s1 and s2 are equal
assert(s1 == s2);
// So I can substitute them in equality preserving
// expressions and get equal results
assert(some_ints + 4 == s1);
assert(some_ints + 4 == s2 && "Oops again.");
#else
int some_ints[] = {0,1,2,3,42};
auto r1 = ext::make_range(some_ints, S{5});
auto r2 = ext::make_range(some_ints, S{8});
// r1 and r2 have the same type
static_assert(models::Same<decltype(r1),decltype(r2)>);
// They are in fact RandomAccessRanges
using R = decltype(r1);
static_assert(models::RandomAccessRange<R>);
// r1 and r2 are equal ranges
assert(distance(r1) == distance(r2));
assert(equal(r1, r2));
// They have equal begin iterators
assert(begin(r1) == begin(r2));
// Since int* satisfies ForwardIterator, its increment
// operation is equality preserving. Therefore every
// iterator in these two ranges must be equal, i.e.,
// they denote the same elements, up to/ and including
// the past-the-end iterators
auto i1 = begin(r1), i2 = begin(r2);
while (true) {
assert(i1 == i2);
if (i1 == end(r1)) {
assert(i2 == end(r2));
break;
}
++i1, ++i2;
}
// Both i1 and i2 compare equal to both end(r1) and end(r2)
assert(i1 == end(r1));
assert(i1 == end(r2));
assert(i2 == end(r1));
assert(i2 == end(r2));
// So by EqualityComparable, end(r1) == end(r2)
assert(end(r1) == end(r2) && "Oops. They aren't equal.");
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment