123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- //===----------------------------------------------------------------------===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is dual licensed under the MIT and the University of Illinois Open
- // Source Licenses. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- // UNSUPPORTED: libcpp-no-exceptions
- // <algorithm>
- // template <class _Compare> struct __debug_less
- // __debug_less checks that a comparator actually provides a strict-weak ordering.
- struct DebugException {};
- #define _LIBCPP_DEBUG 0
- #define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : throw ::DebugException())
- #include <algorithm>
- #include <cassert>
- template <int ID>
- struct MyType {
- int value;
- explicit MyType(int xvalue = 0) : value(xvalue) {}
- };
- template <int ID1, int ID2>
- bool operator<(MyType<ID1> const& LHS, MyType<ID2> const& RHS) {
- return LHS.value < RHS.value;
- }
- struct CompareBase {
- static int called;
- static void reset() {
- called = 0;
- }
- };
- int CompareBase::called = 0;
- template <class ValueType>
- struct GoodComparator : public CompareBase {
- bool operator()(ValueType const& lhs, ValueType const& rhs) const {
- ++CompareBase::called;
- return lhs < rhs;
- }
- };
- template <class ValueType>
- struct BadComparator : public CompareBase {
- bool operator()(ValueType const&, ValueType const&) const {
- ++CompareBase::called;
- return true;
- }
- };
- template <class T1, class T2>
- struct TwoWayHomoComparator : public CompareBase {
- bool operator()(T1 const& lhs, T2 const& rhs) const {
- ++CompareBase::called;
- return lhs < rhs;
- }
- bool operator()(T2 const& lhs, T1 const& rhs) const {
- ++CompareBase::called;
- return lhs < rhs;
- }
- };
- template <class T1, class T2>
- struct OneWayHomoComparator : public CompareBase {
- bool operator()(T1 const& lhs, T2 const& rhs) const {
- ++CompareBase::called;
- return lhs < rhs;
- }
- };
- using std::__debug_less;
- typedef MyType<0> MT0;
- typedef MyType<1> MT1;
- void test_passing() {
- int& called = CompareBase::called;
- called = 0;
- MT0 one(1);
- MT0 two(2);
- MT1 three(3);
- MT1 four(4);
- {
- typedef GoodComparator<MT0> C;
- typedef __debug_less<C> D;
- C c;
- D d(c);
- assert(d(one, two) == true);
- assert(called == 2);
- called = 0;
- assert(d(one, one) == false);
- assert(called == 1);
- called = 0;
- assert(d(two, one) == false);
- assert(called == 1);
- called = 0;
- }
- {
- typedef TwoWayHomoComparator<MT0, MT1> C;
- typedef __debug_less<C> D;
- C c;
- D d(c);
- assert(d(one, three) == true);
- assert(called == 2);
- called = 0;
- assert(d(three, one) == false);
- assert(called == 1);
- called = 0;
- }
- {
- typedef OneWayHomoComparator<MT0, MT1> C;
- typedef __debug_less<C> D;
- C c;
- D d(c);
- assert(d(one, three) == true);
- assert(called == 1);
- called = 0;
- }
- }
- void test_failing() {
- int& called = CompareBase::called;
- called = 0;
- MT0 one(1);
- MT0 two(2);
- {
- typedef BadComparator<MT0> C;
- typedef __debug_less<C> D;
- C c;
- D d(c);
- try {
- d(one, two);
- assert(false);
- } catch (DebugException const&) {
- }
- assert(called == 2);
- called = 0;
- }
- }
- template <int>
- struct Tag {
- explicit Tag(int v) : value(v) {}
- int value;
- };
- template <class = void>
- struct FooImp {
- explicit FooImp(int x) : x_(x) {}
- int x_;
- };
- template <class T>
- inline bool operator<(FooImp<T> const& x, Tag<0> y) {
- return x.x_ < y.value;
- }
- template <class T>
- inline bool operator<(Tag<0>, FooImp<T> const&) {
- static_assert(sizeof(FooImp<T>) != sizeof(FooImp<T>), "should not be instantiated");
- }
- template <class T>
- inline bool operator<(Tag<1> x, FooImp<T> const& y) {
- return x.value < y.x_;
- }
- template <class T>
- inline bool operator<(FooImp<T> const&, Tag<1>) {
- static_assert(sizeof(FooImp<T>) != sizeof(FooImp<T>), "should not be instantiated");
- }
- typedef FooImp<> Foo;
- // Test that we don't attempt to call the comparator with the arguments reversed
- // for upper_bound and lower_bound since the comparator or type is not required
- // to support it, nor does it require the range to have a strict weak ordering.
- // See llvm.org/PR39458
- void test_upper_and_lower_bound() {
- Foo table[] = {Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)};
- {
- Foo* iter = std::lower_bound(std::begin(table), std::end(table), Tag<0>(3));
- assert(iter == (table + 2));
- }
- {
- Foo* iter = std::upper_bound(std::begin(table), std::end(table), Tag<1>(3));
- assert(iter == (table + 3));
- }
- }
- int main() {
- test_passing();
- test_failing();
- test_upper_and_lower_bound();
- }
|