diff --git a/include/algorithm b/include/algorithm index 7a6db7abd..25e95ac44 100644 --- a/include/algorithm +++ b/include/algorithm @@ -749,14 +749,28 @@ struct __debug_less { _Compare __comp_; __debug_less(_Compare& __c) : __comp_(__c) {} + template bool operator()(const _Tp& __x, const _Up& __y) { bool __r = __comp_(__x, __y); if (__r) - _LIBCPP_ASSERT(!__comp_(__y, __x), "Comparator does not induce a strict weak ordering"); + __do_compare_assert(0, __y, __x); return __r; } + + template + 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 + inline _LIBCPP_INLINE_VISIBILITY + void __do_compare_assert(long, _LHS const&, _RHS const&) {} }; #endif // _LIBCPP_DEBUG diff --git a/test/libcxx/algorithms/debug_less.pass.cpp b/test/libcxx/algorithms/debug_less.pass.cpp new file mode 100644 index 000000000..2e875ff27 --- /dev/null +++ b/test/libcxx/algorithms/debug_less.pass.cpp @@ -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 + +// + +// template 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 +#include + +template +struct MyType { + int value; + explicit MyType(int xvalue = 0) : value(xvalue) {} +}; + +template +bool operator<(MyType const& LHS, MyType const& RHS) { + return LHS.value < RHS.value; +} + +struct CompareBase { + static int called; + static void reset() { + called = 0; + } +}; + +int CompareBase::called = 0; + +template +struct GoodComparator : public CompareBase { + bool operator()(ValueType const& lhs, ValueType const& rhs) const { + ++CompareBase::called; + return lhs < rhs; + } +}; + +template +struct BadComparator : public CompareBase { + bool operator()(ValueType const&, ValueType const&) const { + ++CompareBase::called; + return true; + } +}; + +template +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 +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 C; + typedef __debug_less 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 C; + typedef __debug_less 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 C; + typedef __debug_less 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 C; + typedef __debug_less 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(); +} \ No newline at end of file