1//===----------------------------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// UNSUPPORTED: libcpp-no-exceptions
11
12// <algorithm>
13
14// template <class _Compare> struct __debug_less
15
16// __debug_less checks that a comparator actually provides a strict-weak ordering.
17
18struct DebugException {};
19
20#define _LIBCPP_DEBUG 0
21#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : throw ::DebugException())
22
23#include <algorithm>
24#include <cassert>
25
26template <int ID>
27struct MyType {
28    int value;
29    explicit MyType(int xvalue = 0) : value(xvalue) {}
30};
31
32template <int ID1, int ID2>
33bool operator<(MyType<ID1> const& LHS, MyType<ID2> const& RHS) {
34    return LHS.value < RHS.value;
35}
36
37struct CompareBase {
38    static int called;
39    static void reset() {
40        called = 0;
41    }
42};
43
44int CompareBase::called = 0;
45
46template <class ValueType>
47struct GoodComparator : public CompareBase {
48    bool operator()(ValueType const& lhs, ValueType const& rhs) const {
49        ++CompareBase::called;
50        return lhs < rhs;
51    }
52};
53
54template <class ValueType>
55struct BadComparator : public CompareBase {
56    bool operator()(ValueType const&, ValueType const&) const {
57        ++CompareBase::called;
58        return true;
59    }
60};
61
62template <class T1, class T2>
63struct TwoWayHomoComparator : public CompareBase {
64    bool operator()(T1 const& lhs, T2 const& rhs) const {
65        ++CompareBase::called;
66        return lhs < rhs;
67    }
68
69    bool operator()(T2 const& lhs, T1 const& rhs) const {
70        ++CompareBase::called;
71        return lhs < rhs;
72    }
73};
74
75template <class T1, class T2>
76struct OneWayHomoComparator : public CompareBase {
77    bool operator()(T1 const& lhs, T2 const& rhs) const {
78        ++CompareBase::called;
79        return lhs < rhs;
80    }
81};
82
83using std::__debug_less;
84
85typedef MyType<0> MT0;
86typedef MyType<1> MT1;
87
88void test_passing() {
89    int& called = CompareBase::called;
90    called = 0;
91    MT0 one(1);
92    MT0 two(2);
93    MT1 three(3);
94    MT1 four(4);
95
96    {
97        typedef GoodComparator<MT0> C;
98        typedef __debug_less<C> D;
99
100        C c;
101        D d(c);
102
103        assert(d(one, two) == true);
104        assert(called == 2);
105        called = 0;
106
107        assert(d(one, one) == false);
108        assert(called == 1);
109        called = 0;
110
111        assert(d(two, one) == false);
112        assert(called == 1);
113        called = 0;
114    }
115    {
116        typedef TwoWayHomoComparator<MT0, MT1> C;
117        typedef __debug_less<C> D;
118        C c;
119        D d(c);
120
121        assert(d(one, three) == true);
122        assert(called == 2);
123        called = 0;
124
125        assert(d(three, one) == false);
126        assert(called == 1);
127        called = 0;
128    }
129    {
130        typedef OneWayHomoComparator<MT0, MT1> C;
131        typedef __debug_less<C> D;
132        C c;
133        D d(c);
134
135        assert(d(one, three) == true);
136        assert(called == 1);
137        called = 0;
138    }
139}
140
141void test_failing() {
142    int& called = CompareBase::called;
143    called = 0;
144    MT0 one(1);
145    MT0 two(2);
146
147    {
148        typedef BadComparator<MT0> C;
149        typedef __debug_less<C> D;
150        C c;
151        D d(c);
152
153        try {
154            d(one, two);
155            assert(false);
156        } catch (DebugException const&) {
157        }
158
159        assert(called == 2);
160        called = 0;
161    }
162}
163
164int main() {
165    test_passing();
166    test_failing();
167}
168