xref: /llvm-project/libcxx/test/libcxx/algorithms/debug_less.pass.cpp (revision 766772342ca3c6f9df399dcddaef42a009a31cfc)
1331d2159SEric Fiselier //===----------------------------------------------------------------------===//
2331d2159SEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6331d2159SEric Fiselier //
7331d2159SEric Fiselier //===----------------------------------------------------------------------===//
8331d2159SEric Fiselier 
9331d2159SEric Fiselier // <algorithm>
10331d2159SEric Fiselier 
11331d2159SEric Fiselier // template <class _Compare> struct __debug_less
12331d2159SEric Fiselier 
13331d2159SEric Fiselier // __debug_less checks that a comparator actually provides a strict-weak ordering.
14331d2159SEric Fiselier 
15*76677234SKonstantin Varlamov // REQUIRES: has-unix-headers, libcpp-hardening-mode=debug
16*76677234SKonstantin Varlamov // UNSUPPORTED: c++03
17331d2159SEric Fiselier 
18331d2159SEric Fiselier #include <algorithm>
19331d2159SEric Fiselier #include <cassert>
2034f73804SNikolas Klauser #include <functional>
2134f73804SNikolas Klauser #include <iterator>
22331d2159SEric Fiselier 
236e4ec602SEric Fiselier #include "test_macros.h"
24f6fd1c14SLouis Dionne #include "check_assertion.h"
256e4ec602SEric Fiselier 
26331d2159SEric Fiselier template <int ID>
27331d2159SEric Fiselier struct MyType {
28331d2159SEric Fiselier     int value;
MyTypeMyType29331d2159SEric Fiselier     explicit MyType(int xvalue = 0) : value(xvalue) {}
30331d2159SEric Fiselier };
31331d2159SEric Fiselier 
32331d2159SEric Fiselier template <int ID1, int ID2>
operator <(MyType<ID1> const & LHS,MyType<ID2> const & RHS)33331d2159SEric Fiselier bool operator<(MyType<ID1> const& LHS, MyType<ID2> const& RHS) {
34331d2159SEric Fiselier     return LHS.value < RHS.value;
35331d2159SEric Fiselier }
36331d2159SEric Fiselier 
37331d2159SEric Fiselier struct CompareBase {
38331d2159SEric Fiselier     static int called;
resetCompareBase39331d2159SEric Fiselier     static void reset() {
40331d2159SEric Fiselier         called = 0;
41331d2159SEric Fiselier     }
42331d2159SEric Fiselier };
43331d2159SEric Fiselier 
44331d2159SEric Fiselier int CompareBase::called = 0;
45331d2159SEric Fiselier 
46331d2159SEric Fiselier template <class ValueType>
47331d2159SEric Fiselier struct GoodComparator : public CompareBase {
operator ()GoodComparator48331d2159SEric Fiselier     bool operator()(ValueType const& lhs, ValueType const& rhs) const {
49331d2159SEric Fiselier         ++CompareBase::called;
50331d2159SEric Fiselier         return lhs < rhs;
51331d2159SEric Fiselier     }
52331d2159SEric Fiselier };
53331d2159SEric Fiselier 
54331d2159SEric Fiselier template <class T1, class T2>
55331d2159SEric Fiselier struct TwoWayHomoComparator : public CompareBase {
operator ()TwoWayHomoComparator56331d2159SEric Fiselier     bool operator()(T1 const& lhs, T2 const& rhs) const {
57331d2159SEric Fiselier         ++CompareBase::called;
58331d2159SEric Fiselier         return lhs < rhs;
59331d2159SEric Fiselier     }
60331d2159SEric Fiselier 
operator ()TwoWayHomoComparator61331d2159SEric Fiselier     bool operator()(T2 const& lhs, T1 const& rhs) const {
62331d2159SEric Fiselier         ++CompareBase::called;
63331d2159SEric Fiselier         return lhs < rhs;
64331d2159SEric Fiselier     }
65331d2159SEric Fiselier };
66331d2159SEric Fiselier 
67331d2159SEric Fiselier template <class T1, class T2>
68331d2159SEric Fiselier struct OneWayHomoComparator : public CompareBase {
operator ()OneWayHomoComparator69331d2159SEric Fiselier     bool operator()(T1 const& lhs, T2 const& rhs) const {
70331d2159SEric Fiselier         ++CompareBase::called;
71331d2159SEric Fiselier         return lhs < rhs;
72331d2159SEric Fiselier     }
73331d2159SEric Fiselier };
74331d2159SEric Fiselier 
75331d2159SEric Fiselier using std::__debug_less;
76331d2159SEric Fiselier 
77331d2159SEric Fiselier typedef MyType<0> MT0;
78331d2159SEric Fiselier typedef MyType<1> MT1;
79331d2159SEric Fiselier 
test_passing()80331d2159SEric Fiselier void test_passing() {
81331d2159SEric Fiselier     int& called = CompareBase::called;
82331d2159SEric Fiselier     called = 0;
83331d2159SEric Fiselier     MT0 one(1);
84331d2159SEric Fiselier     MT0 two(2);
85331d2159SEric Fiselier     MT1 three(3);
86331d2159SEric Fiselier     MT1 four(4);
87331d2159SEric Fiselier 
88331d2159SEric Fiselier     {
89331d2159SEric Fiselier         typedef GoodComparator<MT0> C;
90331d2159SEric Fiselier         typedef __debug_less<C> D;
91331d2159SEric Fiselier 
92331d2159SEric Fiselier         C c;
93331d2159SEric Fiselier         D d(c);
94331d2159SEric Fiselier 
95331d2159SEric Fiselier         assert(d(one, two) == true);
96331d2159SEric Fiselier         assert(called == 2);
97331d2159SEric Fiselier         called = 0;
98331d2159SEric Fiselier 
99331d2159SEric Fiselier         assert(d(one, one) == false);
100331d2159SEric Fiselier         assert(called == 1);
101331d2159SEric Fiselier         called = 0;
102331d2159SEric Fiselier 
103331d2159SEric Fiselier         assert(d(two, one) == false);
104331d2159SEric Fiselier         assert(called == 1);
105331d2159SEric Fiselier         called = 0;
106331d2159SEric Fiselier     }
107331d2159SEric Fiselier     {
108331d2159SEric Fiselier         typedef TwoWayHomoComparator<MT0, MT1> C;
109331d2159SEric Fiselier         typedef __debug_less<C> D;
110331d2159SEric Fiselier         C c;
111331d2159SEric Fiselier         D d(c);
112331d2159SEric Fiselier 
113331d2159SEric Fiselier         assert(d(one, three) == true);
114331d2159SEric Fiselier         assert(called == 2);
115331d2159SEric Fiselier         called = 0;
116331d2159SEric Fiselier 
117331d2159SEric Fiselier         assert(d(three, one) == false);
118331d2159SEric Fiselier         assert(called == 1);
119331d2159SEric Fiselier         called = 0;
120331d2159SEric Fiselier     }
121331d2159SEric Fiselier     {
122331d2159SEric Fiselier         typedef OneWayHomoComparator<MT0, MT1> C;
123331d2159SEric Fiselier         typedef __debug_less<C> D;
124331d2159SEric Fiselier         C c;
125331d2159SEric Fiselier         D d(c);
126331d2159SEric Fiselier 
127331d2159SEric Fiselier         assert(d(one, three) == true);
128331d2159SEric Fiselier         assert(called == 1);
129331d2159SEric Fiselier         called = 0;
130331d2159SEric Fiselier     }
131331d2159SEric Fiselier }
132331d2159SEric Fiselier 
133e503a1c3SEric Fiselier template <int>
134e503a1c3SEric Fiselier struct Tag {
TagTag135e503a1c3SEric Fiselier   explicit Tag(int v) : value(v) {}
136e503a1c3SEric Fiselier   int value;
137e503a1c3SEric Fiselier };
138e503a1c3SEric Fiselier 
139e503a1c3SEric Fiselier template <class = void>
140e503a1c3SEric Fiselier struct FooImp {
FooImpFooImp141e503a1c3SEric Fiselier   explicit FooImp(int x) : x_(x) {}
142e503a1c3SEric Fiselier   int x_;
143e503a1c3SEric Fiselier };
144e503a1c3SEric Fiselier 
145e503a1c3SEric Fiselier template <class T>
operator <(FooImp<T> const & x,Tag<0> y)146e503a1c3SEric Fiselier inline bool operator<(FooImp<T> const& x, Tag<0> y) {
147e503a1c3SEric Fiselier     return x.x_ < y.value;
148e503a1c3SEric Fiselier }
149e503a1c3SEric Fiselier 
150e503a1c3SEric Fiselier template <class T>
operator <(Tag<0>,FooImp<T> const &)151e503a1c3SEric Fiselier inline bool operator<(Tag<0>, FooImp<T> const&) {
152e503a1c3SEric Fiselier     static_assert(sizeof(FooImp<T>) != sizeof(FooImp<T>), "should not be instantiated");
1531cac82cfSLouis Dionne     return false;
154e503a1c3SEric Fiselier }
155e503a1c3SEric Fiselier 
156e503a1c3SEric Fiselier template <class T>
operator <(Tag<1> x,FooImp<T> const & y)157e503a1c3SEric Fiselier inline bool operator<(Tag<1> x, FooImp<T> const& y) {
158e503a1c3SEric Fiselier     return x.value < y.x_;
159e503a1c3SEric Fiselier }
160e503a1c3SEric Fiselier 
161e503a1c3SEric Fiselier template <class T>
operator <(FooImp<T> const &,Tag<1>)162e503a1c3SEric Fiselier inline bool operator<(FooImp<T> const&, Tag<1>) {
163e503a1c3SEric Fiselier     static_assert(sizeof(FooImp<T>) != sizeof(FooImp<T>), "should not be instantiated");
1641cac82cfSLouis Dionne     return false;
165e503a1c3SEric Fiselier }
166e503a1c3SEric Fiselier 
167e503a1c3SEric Fiselier typedef FooImp<> Foo;
168e503a1c3SEric Fiselier 
169e503a1c3SEric Fiselier // Test that we don't attempt to call the comparator with the arguments reversed
170e503a1c3SEric Fiselier // for upper_bound and lower_bound since the comparator or type is not required
171e503a1c3SEric Fiselier // to support it, nor does it require the range to have a strict weak ordering.
172e503a1c3SEric Fiselier // See llvm.org/PR39458
test_upper_and_lower_bound()173e503a1c3SEric Fiselier void test_upper_and_lower_bound() {
174e503a1c3SEric Fiselier     Foo table[] = {Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)};
175e503a1c3SEric Fiselier     {
176e503a1c3SEric Fiselier         Foo* iter = std::lower_bound(std::begin(table), std::end(table), Tag<0>(3));
177e503a1c3SEric Fiselier         assert(iter == (table + 2));
178e503a1c3SEric Fiselier     }
179e503a1c3SEric Fiselier     {
180e503a1c3SEric Fiselier         Foo* iter = std::upper_bound(std::begin(table), std::end(table), Tag<1>(3));
181e503a1c3SEric Fiselier         assert(iter == (table + 3));
182e503a1c3SEric Fiselier     }
183e503a1c3SEric Fiselier }
184e503a1c3SEric Fiselier 
1856e4ec602SEric Fiselier struct NonConstArgCmp {
operator ()NonConstArgCmp1866e4ec602SEric Fiselier     bool operator()(int& x, int &y) const {
1876e4ec602SEric Fiselier         return x < y;
1886e4ec602SEric Fiselier     }
1896e4ec602SEric Fiselier };
1906e4ec602SEric Fiselier 
test_non_const_arg_cmp()1916e4ec602SEric Fiselier void test_non_const_arg_cmp() {
1926e4ec602SEric Fiselier     {
1936e4ec602SEric Fiselier         NonConstArgCmp cmp;
1946e4ec602SEric Fiselier         __debug_less<NonConstArgCmp> dcmp(cmp);
1956e4ec602SEric Fiselier         int x = 0, y = 1;
1966e4ec602SEric Fiselier         assert(dcmp(x, y));
1976e4ec602SEric Fiselier         assert(!dcmp(y, x));
1986e4ec602SEric Fiselier     }
1996e4ec602SEric Fiselier     {
2006e4ec602SEric Fiselier         NonConstArgCmp cmp;
2016e4ec602SEric Fiselier         int arr[] = {5, 4, 3, 2, 1};
2026e4ec602SEric Fiselier         std::sort(std::begin(arr), std::end(arr), cmp);
2036e4ec602SEric Fiselier         assert(std::is_sorted(std::begin(arr), std::end(arr)));
2046e4ec602SEric Fiselier     }
2056e4ec602SEric Fiselier }
2066e4ec602SEric Fiselier 
2073c3ccc00SThomas Anderson struct ValueIterator {
208e1e1bd7fSLouis Dionne     typedef std::input_iterator_tag iterator_category;
209fb855eb9SMark de Wever     typedef std::size_t value_type;
210d8681356SMark de Wever     typedef std::ptrdiff_t difference_type;
211fb855eb9SMark de Wever     typedef std::size_t reference;
212fb855eb9SMark de Wever     typedef std::size_t* pointer;
2133c3ccc00SThomas Anderson 
ValueIteratorValueIterator214e1e1bd7fSLouis Dionne     ValueIterator() { }
2153c3ccc00SThomas Anderson 
operator *ValueIterator2163c3ccc00SThomas Anderson     reference operator*() { return 0; }
operator ++ValueIterator2173c3ccc00SThomas Anderson     ValueIterator& operator++() { return *this; }
2183c3ccc00SThomas Anderson 
operator ==(ValueIterator,ValueIterator)2193c3ccc00SThomas Anderson     friend bool operator==(ValueIterator, ValueIterator) { return true; }
operator !=(ValueIterator,ValueIterator)2203c3ccc00SThomas Anderson     friend bool operator!=(ValueIterator, ValueIterator) { return false; }
2213c3ccc00SThomas Anderson };
2223c3ccc00SThomas Anderson 
test_value_iterator()2233c3ccc00SThomas Anderson void test_value_iterator() {
2243c3ccc00SThomas Anderson     // Ensure no build failures when iterators return values, not references.
225e1e1bd7fSLouis Dionne     assert(0 == std::lexicographical_compare(ValueIterator(), ValueIterator(),
226e1e1bd7fSLouis Dionne                                              ValueIterator(), ValueIterator()));
2273c3ccc00SThomas Anderson }
2283c3ccc00SThomas Anderson 
test_value_categories()2293c3ccc00SThomas Anderson void test_value_categories() {
2303c3ccc00SThomas Anderson     std::less<int> l;
2313c3ccc00SThomas Anderson     std::__debug_less<std::less<int> > dl(l);
2323c3ccc00SThomas Anderson     int lvalue = 42;
2333c3ccc00SThomas Anderson     const int const_lvalue = 101;
2343c3ccc00SThomas Anderson 
2353c3ccc00SThomas Anderson     assert(dl(lvalue, const_lvalue));
2363c3ccc00SThomas Anderson     assert(dl(/*rvalue*/1, lvalue));
2373c3ccc00SThomas Anderson     assert(dl(static_cast<int&&>(1), static_cast<const int&&>(2)));
2383c3ccc00SThomas Anderson }
2393c3ccc00SThomas Anderson 
24099e5c525SJordan Rupprecht #if TEST_STD_VER > 11
test_constexpr()2416ab51de0SThomas Anderson constexpr bool test_constexpr() {
2426ab51de0SThomas Anderson     std::less<> cmp{};
2436ab51de0SThomas Anderson     __debug_less<std::less<> > dcmp(cmp);
2446ab51de0SThomas Anderson     assert(dcmp(1, 2));
2456ab51de0SThomas Anderson     assert(!dcmp(1, 1));
2466ab51de0SThomas Anderson     return true;
2476ab51de0SThomas Anderson }
2486ab51de0SThomas Anderson #endif
2496ab51de0SThomas Anderson 
main(int,char **)2502df59c50SJF Bastien int main(int, char**) {
251331d2159SEric Fiselier     test_passing();
252e503a1c3SEric Fiselier     test_upper_and_lower_bound();
2536e4ec602SEric Fiselier     test_non_const_arg_cmp();
2543c3ccc00SThomas Anderson     test_value_iterator();
2553c3ccc00SThomas Anderson     test_value_categories();
25699e5c525SJordan Rupprecht #if TEST_STD_VER > 11
2576ab51de0SThomas Anderson     static_assert(test_constexpr(), "");
2586ab51de0SThomas Anderson #endif
2592df59c50SJF Bastien     return 0;
260331d2159SEric Fiselier }
261