Add heterogeneous comparator support for __debug_less. Fixes PR17147.
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@276059 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -749,14 +749,28 @@ struct __debug_less
|
|||||||
{
|
{
|
||||||
_Compare __comp_;
|
_Compare __comp_;
|
||||||
__debug_less(_Compare& __c) : __comp_(__c) {}
|
__debug_less(_Compare& __c) : __comp_(__c) {}
|
||||||
|
|
||||||
template <class _Tp, class _Up>
|
template <class _Tp, class _Up>
|
||||||
bool operator()(const _Tp& __x, const _Up& __y)
|
bool operator()(const _Tp& __x, const _Up& __y)
|
||||||
{
|
{
|
||||||
bool __r = __comp_(__x, __y);
|
bool __r = __comp_(__x, __y);
|
||||||
if (__r)
|
if (__r)
|
||||||
_LIBCPP_ASSERT(!__comp_(__y, __x), "Comparator does not induce a strict weak ordering");
|
__do_compare_assert(0, __y, __x);
|
||||||
return __r;
|
return __r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class _LHS, class _RHS>
|
||||||
|
inline _LIBCPP_INLINE_VISIBILITY
|
||||||
|
decltype((void)_VSTD::declval<_Compare&>()(
|
||||||
|
_VSTD::declval<_LHS const&>(), _VSTD::declval<_RHS const&>()))
|
||||||
|
__do_compare_assert(int, _LHS const& __l, _RHS const& __r) {
|
||||||
|
_LIBCPP_ASSERT(!__comp_(__l, __r),
|
||||||
|
"Comparator does not induce a strict weak ordering");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class _LHS, class _RHS>
|
||||||
|
inline _LIBCPP_INLINE_VISIBILITY
|
||||||
|
void __do_compare_assert(long, _LHS const&, _RHS const&) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _LIBCPP_DEBUG
|
#endif // _LIBCPP_DEBUG
|
||||||
|
|||||||
167
test/libcxx/algorithms/debug_less.pass.cpp
Normal file
167
test/libcxx/algorithms/debug_less.pass.cpp
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
test_passing();
|
||||||
|
test_failing();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user