diff options
| author | Eric Fiselier <eric@efcs.ca> | 2016-07-19 23:27:18 +0000 |
|---|---|---|
| committer | Eric Fiselier <eric@efcs.ca> | 2016-07-19 23:27:18 +0000 |
| commit | 331d21599dc6a1fbcb19155ae532fda7c3449b4f (patch) | |
| tree | 0000f44c4c2e539ebfbf424445287b900f893f88 | |
| parent | 7ab570ec3a229ff30aa8f0122d5df0e27eec1349 (diff) | |
| download | bcm5719-llvm-331d21599dc6a1fbcb19155ae532fda7c3449b4f.tar.gz bcm5719-llvm-331d21599dc6a1fbcb19155ae532fda7c3449b4f.zip | |
Add heterogeneous comparator support for __debug_less. Fixes PR17147.
llvm-svn: 276059
| -rw-r--r-- | libcxx/include/algorithm | 16 | ||||
| -rw-r--r-- | libcxx/test/libcxx/algorithms/debug_less.pass.cpp | 167 |
2 files changed, 182 insertions, 1 deletions
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 7a6db7abd26..25e95ac443a 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -749,14 +749,28 @@ struct __debug_less { _Compare __comp_; __debug_less(_Compare& __c) : __comp_(__c) {} + template <class _Tp, class _Up> 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 <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 diff --git a/libcxx/test/libcxx/algorithms/debug_less.pass.cpp b/libcxx/test/libcxx/algorithms/debug_less.pass.cpp new file mode 100644 index 00000000000..2e875ff277c --- /dev/null +++ b/libcxx/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 + +// <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(); +}
\ No newline at end of file |

