From 879cbac08ba17566ad61ff2b9d7180bcab4a0d1e Mon Sep 17 00:00:00 2001 From: zoecarver Date: Thu, 22 Apr 2021 17:33:04 -0700 Subject: [PATCH] [libc++][ranges] Add range.cmp: equal_to, not_equal_to, less, etc. Adds the six new concept constrained comparisons. Differential Revision: https://reviews.llvm.org/D100429 --- libcxx/include/functional | 75 ++++++ .../equality_comparable.compile.pass.cpp | 2 +- .../equality_comparable_with.compile.pass.cpp | 2 +- .../totally_ordered.pass.cpp | 2 +- .../totally_ordered_with.pass.cpp | 2 +- .../comparisons/greater.pass.cpp | 2 +- .../comparisons/greater_equal.pass.cpp | 2 +- .../comparisons/less.pass.cpp | 2 +- .../comparisons/less_equal.pass.cpp | 2 +- .../pointer_comparison_test_helper.h | 39 ---- .../range.cmp/equal_to.pass.cpp | 64 +++++ .../range.cmp/greater.pass.cpp | 63 +++++ .../range.cmp/greater_equal.pass.cpp | 63 +++++ .../function.objects/range.cmp/less.pass.cpp | 63 +++++ .../range.cmp/less_equal.pass.cpp | 64 +++++ .../range.cmp/not_equal_to.pass.cpp | 75 ++++++ .../types.h => support/compare_types.h} | 220 +++++++----------- .../support/pointer_comparison_test_helper.h | 54 +++++ 18 files changed, 618 insertions(+), 178 deletions(-) delete mode 100644 libcxx/test/std/utilities/function.objects/comparisons/pointer_comparison_test_helper.h create mode 100644 libcxx/test/std/utilities/function.objects/range.cmp/equal_to.pass.cpp create mode 100644 libcxx/test/std/utilities/function.objects/range.cmp/greater.pass.cpp create mode 100644 libcxx/test/std/utilities/function.objects/range.cmp/greater_equal.pass.cpp create mode 100644 libcxx/test/std/utilities/function.objects/range.cmp/less.pass.cpp create mode 100644 libcxx/test/std/utilities/function.objects/range.cmp/less_equal.pass.cpp create mode 100644 libcxx/test/std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp rename libcxx/test/{std/concepts/concepts.compare/types.h => support/compare_types.h} (73%) create mode 100644 libcxx/test/support/pointer_comparison_test_helper.h diff --git a/libcxx/include/functional b/libcxx/include/functional index 62e9373ad14d..19d74a3ec6bb 100644 --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -507,6 +507,7 @@ POLICY: For non-variadic implementations, the number of arguments is limited */ #include <__config> +#include #include #include #include @@ -3222,6 +3223,80 @@ struct identity { }; #endif // _LIBCPP_STD_VER > 17 +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { + +struct equal_to { + template + requires equality_comparable_with<_Tp, _Up> + [[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const + noexcept(noexcept(bool(_VSTD::forward<_Tp>(__t) == _VSTD::forward<_Up>(__u)))) { + return _VSTD::forward<_Tp>(__t) == _VSTD::forward<_Up>(__u); + } + + using is_transparent = void; +}; + +struct not_equal_to { + template + requires equality_comparable_with<_Tp, _Up> + [[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const + noexcept(noexcept(bool(!(_VSTD::forward<_Tp>(__t) == _VSTD::forward<_Up>(__u))))) { + return !(_VSTD::forward<_Tp>(__t) == _VSTD::forward<_Up>(__u)); + } + + using is_transparent = void; +}; + +struct greater { + template + requires totally_ordered_with<_Tp, _Up> + [[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const + noexcept(noexcept(bool(_VSTD::forward<_Up>(__u) < _VSTD::forward<_Tp>(__t)))) { + return _VSTD::forward<_Up>(__u) < _VSTD::forward<_Tp>(__t); + } + + using is_transparent = void; +}; + +struct less { + template + requires totally_ordered_with<_Tp, _Up> + [[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const + noexcept(noexcept(bool(_VSTD::forward<_Tp>(__t) < _VSTD::forward<_Up>(__u)))) { + return _VSTD::forward<_Tp>(__t) < _VSTD::forward<_Up>(__u); + } + + using is_transparent = void; +}; + +struct greater_equal { + template + requires totally_ordered_with<_Tp, _Up> + [[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const + noexcept(noexcept(bool(!(_VSTD::forward<_Tp>(__t) < _VSTD::forward<_Up>(__u))))) { + return !(_VSTD::forward<_Tp>(__t) < _VSTD::forward<_Up>(__u)); + } + + using is_transparent = void; +}; + +struct less_equal { + template + requires totally_ordered_with<_Tp, _Up> + [[nodiscard]] constexpr bool operator()(_Tp &&__t, _Up &&__u) const + noexcept(noexcept(bool(!(_VSTD::forward<_Up>(__u) < _VSTD::forward<_Tp>(__t))))) { + return !(_VSTD::forward<_Up>(__u) < _VSTD::forward<_Tp>(__t)); + } + + using is_transparent = void; +}; + +} // namespace ranges + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_FUNCTIONAL diff --git a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable.compile.pass.cpp b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable.compile.pass.cpp index 0211ee3d531e..5290e06dc828 100644 --- a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable.compile.pass.cpp +++ b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable.compile.pass.cpp @@ -27,7 +27,7 @@ #include #include -#include "../types.h" +#include "compare_types.h" namespace fundamentals { static_assert(std::equality_comparable); diff --git a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp index a65e47f936da..a9caf8dc6e9b 100644 --- a/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp +++ b/libcxx/test/std/concepts/concepts.compare/concept.equalitycomparable/equality_comparable_with.compile.pass.cpp @@ -27,7 +27,7 @@ #include #include -#include "../types.h" +#include "compare_types.h" template constexpr bool check_equality_comparable_with() { diff --git a/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered.pass.cpp b/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered.pass.cpp index fce1efc0cd5d..03d82ec97557 100644 --- a/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered.pass.cpp +++ b/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered.pass.cpp @@ -26,7 +26,7 @@ #include #include -#include "../types.h" +#include "compare_types.h" #include "test_macros.h" // `models_totally_ordered` checks that `std::totally_ordered` subsumes diff --git a/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered_with.pass.cpp b/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered_with.pass.cpp index 345abac552fe..199f022f5883 100644 --- a/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered_with.pass.cpp +++ b/libcxx/test/std/concepts/concepts.compare/concepts.totallyordered/totally_ordered_with.pass.cpp @@ -26,7 +26,7 @@ #include #include -#include "../types.h" +#include "compare_types.h" #include "test_macros.h" template diff --git a/libcxx/test/std/utilities/function.objects/comparisons/greater.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/greater.pass.cpp index b1f1fe65667f..1f79d2351327 100644 --- a/libcxx/test/std/utilities/function.objects/comparisons/greater.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/comparisons/greater.pass.cpp @@ -30,7 +30,7 @@ int main(int, char**) { // test total ordering of int* for greater and // greater. - do_pointer_comparison_test(); + do_pointer_comparison_test(); } #if TEST_STD_VER > 11 typedef std::greater<> F2; diff --git a/libcxx/test/std/utilities/function.objects/comparisons/greater_equal.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/greater_equal.pass.cpp index 30cf7e0bca11..f259b5d27ddb 100644 --- a/libcxx/test/std/utilities/function.objects/comparisons/greater_equal.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/comparisons/greater_equal.pass.cpp @@ -30,7 +30,7 @@ int main(int, char**) { // test total ordering of int* for greater_equal and // greater_equal. - do_pointer_comparison_test(); + do_pointer_comparison_test(); } #if TEST_STD_VER > 11 typedef std::greater_equal<> F2; diff --git a/libcxx/test/std/utilities/function.objects/comparisons/less.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/less.pass.cpp index 88b7c784ea7e..c5da63c1f41e 100644 --- a/libcxx/test/std/utilities/function.objects/comparisons/less.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/comparisons/less.pass.cpp @@ -29,7 +29,7 @@ int main(int, char**) assert(f(6, 36)); { // test total ordering of int* for less and less. - do_pointer_comparison_test(); + do_pointer_comparison_test(); } #if TEST_STD_VER > 11 typedef std::less<> F2; diff --git a/libcxx/test/std/utilities/function.objects/comparisons/less_equal.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/less_equal.pass.cpp index 5aa6d799577a..fe91f2728fd8 100644 --- a/libcxx/test/std/utilities/function.objects/comparisons/less_equal.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/comparisons/less_equal.pass.cpp @@ -30,7 +30,7 @@ int main(int, char**) { // test total ordering of int* for less_equal and // less_equal. - do_pointer_comparison_test(); + do_pointer_comparison_test(); } #if TEST_STD_VER > 11 typedef std::less_equal<> F2; diff --git a/libcxx/test/std/utilities/function.objects/comparisons/pointer_comparison_test_helper.h b/libcxx/test/std/utilities/function.objects/comparisons/pointer_comparison_test_helper.h deleted file mode 100644 index ac4df550a336..000000000000 --- a/libcxx/test/std/utilities/function.objects/comparisons/pointer_comparison_test_helper.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef POINTER_COMPARISON_TEST_HELPER_H -#define POINTER_COMPARISON_TEST_HELPER_H - -#include -#include -#include -#include - -#include "test_macros.h" - -template class CompareTemplate> -void do_pointer_comparison_test() { - typedef CompareTemplate Compare; - typedef CompareTemplate UIntCompare; -#if TEST_STD_VER > 11 - typedef CompareTemplate VoidCompare; -#else - typedef Compare VoidCompare; -#endif - std::vector > pointers; - const std::size_t test_size = 100; - for (size_t i=0; i < test_size; ++i) - pointers.push_back(std::shared_ptr(new T())); - Compare comp; - UIntCompare ucomp; - VoidCompare vcomp; - for (size_t i=0; i < test_size; ++i) { - for (size_t j=0; j < test_size; ++j) { - T* lhs = pointers[i].get(); - T* rhs = pointers[j].get(); - std::uintptr_t lhs_uint = reinterpret_cast(lhs); - std::uintptr_t rhs_uint = reinterpret_cast(rhs); - assert(comp(lhs, rhs) == ucomp(lhs_uint, rhs_uint)); - assert(vcomp(lhs, rhs) == ucomp(lhs_uint, rhs_uint)); - } - } -} - -#endif // POINTER_COMPARISON_TEST_HELPER_H diff --git a/libcxx/test/std/utilities/function.objects/range.cmp/equal_to.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/equal_to.pass.cpp new file mode 100644 index 000000000000..c27159407bb5 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/equal_to.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// + +// ranges::equal_to + +#include +#include +#include + +#include "test_macros.h" +#include "compare_types.h" +#include "MoveOnly.h" +#include "pointer_comparison_test_helper.h" + +struct NotEqualityComparable { + friend bool operator==(const NotEqualityComparable&, const NotEqualityComparable&); + friend bool operator!=(const NotEqualityComparable&, const NotEqualityComparable&) = delete; +}; + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +static_assert(requires { typename std::ranges::equal_to::is_transparent; }); + +constexpr bool test() { + auto fn = std::ranges::equal_to(); + + assert(fn(MoveOnly(42), MoveOnly(42))); + + ForwardingTestObject a; + ForwardingTestObject b; + assert(!fn(a, b)); + assert(fn(std::move(a), std::move(b))); + + assert(!fn(1, 2)); + assert(!fn(2, 1)); + assert(fn(2, 2)); + + assert(!fn(2, 1L)); + + return true; +} + +int main(int, char**) { + + test(); + static_assert(test()); + + // test total ordering of int* for equal_to and equal_to. + do_pointer_comparison_test(std::ranges::equal_to()); + + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/range.cmp/greater.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/greater.pass.cpp new file mode 100644 index 000000000000..95f490d95102 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/greater.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// + +// ranges::greater + +#include +#include +#include + +#include "test_macros.h" +#include "compare_types.h" +#include "MoveOnly.h" +#include "pointer_comparison_test_helper.h" + +struct NotTotallyOrdered { + friend bool operator<(const NotTotallyOrdered&, const NotTotallyOrdered&); +}; + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +static_assert(requires { typename std::ranges::greater::is_transparent; }); + +constexpr bool test() { + auto fn = std::ranges::greater(); + + assert(fn(MoveOnly(42), MoveOnly(41))); + + ForwardingTestObject a; + ForwardingTestObject b; + assert(!fn(a, b)); + assert(fn(std::move(a), std::move(b))); + + assert(!fn(2, 2)); + assert(!fn(1, 2)); + assert(fn(2, 1)); + + assert(fn(2, 1L)); + + return true; +} + +int main(int, char**) { + + test(); + static_assert(test()); + + // test total ordering of int* for greater and greater. + do_pointer_comparison_test(std::ranges::greater()); + + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/range.cmp/greater_equal.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/greater_equal.pass.cpp new file mode 100644 index 000000000000..a3e8ff215bb7 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/greater_equal.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// + +// ranges::greater_equal + +#include +#include +#include + +#include "test_macros.h" +#include "compare_types.h" +#include "MoveOnly.h" +#include "pointer_comparison_test_helper.h" + +struct NotTotallyOrdered { + friend bool operator<(const NotTotallyOrdered&, const NotTotallyOrdered&); +}; + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +static_assert(requires { typename std::ranges::greater_equal::is_transparent; }); + +constexpr bool test() { + auto fn = std::ranges::greater_equal(); + + assert(fn(MoveOnly(42), MoveOnly(42))); + + ForwardingTestObject a; + ForwardingTestObject b; + assert(fn(a, b)); + assert(!fn(std::move(a), std::move(b))); + + assert(fn(2, 2)); + assert(fn(2, 1)); + assert(!fn(1, 2)); + + assert(fn(2, 1L)); + + return true; +} + +int main(int, char**) { + + test(); + static_assert(test()); + + // test total ordering of int* for greater_equal and greater_equal. + do_pointer_comparison_test(std::ranges::greater_equal()); + + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/range.cmp/less.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/less.pass.cpp new file mode 100644 index 000000000000..72f54b7b923f --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/less.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// + +// ranges::less + +#include +#include +#include + +#include "test_macros.h" +#include "compare_types.h" +#include "MoveOnly.h" +#include "pointer_comparison_test_helper.h" + +struct NotTotallyOrdered { + friend bool operator<(const NotTotallyOrdered&, const NotTotallyOrdered&); +}; + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +static_assert(requires { typename std::ranges::less::is_transparent; }); + +constexpr bool test() { + auto fn = std::ranges::less(); + + assert(fn(MoveOnly(41), MoveOnly(42))); + + ForwardingTestObject a; + ForwardingTestObject b; + assert(!fn(a, b)); + assert(fn(std::move(a), std::move(b))); + + assert(fn(1, 2)); + assert(!fn(2, 2)); + assert(!fn(2, 1)); + + assert(!fn(2, 1L)); + + return true; +} + +int main(int, char**) { + + test(); + static_assert(test()); + + // test total ordering of int* for less and less. + do_pointer_comparison_test(std::ranges::less()); + + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/range.cmp/less_equal.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/less_equal.pass.cpp new file mode 100644 index 000000000000..05cc56e89d40 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/less_equal.pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// + +// ranges::less_equal + +#include +#include +#include + +#include "test_macros.h" +#include "compare_types.h" +#include "MoveOnly.h" +#include "pointer_comparison_test_helper.h" + +struct NotTotallyOrdered { + friend bool operator<(const NotTotallyOrdered&, const NotTotallyOrdered&); +}; + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +static_assert(requires { typename std::ranges::less_equal::is_transparent; }); + +constexpr bool test() { + auto fn = std::ranges::less_equal(); + + assert(fn(MoveOnly(41), MoveOnly(42))); + + // These are the opposite of other tests. + ForwardingTestObject a; + ForwardingTestObject b; + assert(fn(a, b)); + assert(!fn(std::move(a), std::move(b))); + + assert(fn(1, 2)); + assert(fn(2, 2)); + assert(!fn(2, 1)); + + assert(!fn(2, 1L)); + + return true; +} + +int main(int, char**) { + + test(); + static_assert(test()); + + // test total ordering of int* for less_equal and less_equal. + do_pointer_comparison_test(std::ranges::less_equal()); + + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp b/libcxx/test/std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp new file mode 100644 index 000000000000..142aaf1f7428 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// + +// ranges::not_equal_to + +#include +#include +#include + +#include "test_macros.h" +#include "compare_types.h" +#include "MoveOnly.h" +#include "pointer_comparison_test_helper.h" + +struct NotEqualityComparable { + friend bool operator==(const NotEqualityComparable&, const NotEqualityComparable&); + friend bool operator!=(const NotEqualityComparable&, const NotEqualityComparable&) = delete; +}; + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +static_assert(requires { typename std::ranges::not_equal_to::is_transparent; }); + +struct PtrAndNotEqOperator { + constexpr operator void*() const { return nullptr; } + // We *don't* want operator!= to be picked here. + friend constexpr bool operator!=(PtrAndNotEqOperator, PtrAndNotEqOperator) { return true; } +}; + +constexpr bool test() { + auto fn = std::ranges::not_equal_to(); + + assert(fn(MoveOnly(41), MoveOnly(42))); + + // These are the opposite of other tests. + ForwardingTestObject a; + ForwardingTestObject b; + assert(fn(a, b)); + assert(!fn(std::move(a), std::move(b))); + + assert(fn(1, 2)); + assert(!fn(2, 2)); + assert(fn(2, 1)); + + assert(fn(2, 1L)); + + // Make sure that "ranges::equal_to(x, y) == !ranges::not_equal_to(x, y)", even here. + assert(!fn(PtrAndNotEqOperator(), PtrAndNotEqOperator())); + assert(std::ranges::equal_to()(PtrAndNotEqOperator(), PtrAndNotEqOperator())); + + return true; +} + +int main(int, char**) { + + test(); + static_assert(test()); + + // test total ordering of int* for not_equal_to and not_equal_to. + do_pointer_comparison_test(std::ranges::not_equal_to()); + + return 0; +} diff --git a/libcxx/test/std/concepts/concepts.compare/types.h b/libcxx/test/support/compare_types.h similarity index 73% rename from libcxx/test/std/concepts/concepts.compare/types.h rename to libcxx/test/support/compare_types.h index de816a371e45..1d448da5407e 100644 --- a/libcxx/test/std/concepts/concepts.compare/types.h +++ b/libcxx/test/support/compare_types.h @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -#ifndef TEST_STD_CONCEPTS_COMPARISON_TYPES_H -#define TEST_STD_CONCEPTS_COMPARISON_TYPES_H +#ifndef TEST_SUPPORT_COMPARE_TYPES_H +#define TEST_SUPPORT_COMPARE_TYPES_H #include #include @@ -23,8 +23,7 @@ struct cxx20_member_eq { }; struct cxx20_friend_eq { - friend bool operator==(cxx20_friend_eq const&, - cxx20_friend_eq const&) = default; + friend bool operator==(cxx20_friend_eq const&, cxx20_friend_eq const&) = default; }; struct member_three_way_comparable { @@ -32,8 +31,7 @@ struct member_three_way_comparable { }; struct friend_three_way_comparable { - friend auto operator<=>(friend_three_way_comparable const&, - friend_three_way_comparable const&) = default; + friend auto operator<=>(friend_three_way_comparable const&, friend_three_way_comparable const&) = default; }; struct explicit_operators { @@ -43,16 +41,11 @@ struct explicit_operators { friend bool operator>(explicit_operators, explicit_operators) noexcept; friend bool operator<=(explicit_operators, explicit_operators) noexcept; friend bool operator>=(explicit_operators, explicit_operators) noexcept; - friend bool operator<=>(explicit_operators, explicit_operators) noexcept; - friend bool operator==(explicit_operators const&, - equality_comparable_with_ec1 const&) noexcept; - friend bool operator==(equality_comparable_with_ec1 const&, - explicit_operators const&) noexcept; - friend bool operator!=(explicit_operators const&, - equality_comparable_with_ec1 const&) noexcept; - friend bool operator!=(equality_comparable_with_ec1 const&, - explicit_operators const&) noexcept; + friend bool operator==(explicit_operators const&, equality_comparable_with_ec1 const&) noexcept; + friend bool operator==(equality_comparable_with_ec1 const&, explicit_operators const&) noexcept; + friend bool operator!=(explicit_operators const&, equality_comparable_with_ec1 const&) noexcept; + friend bool operator!=(equality_comparable_with_ec1 const&, explicit_operators const&) noexcept; }; struct different_return_types { @@ -76,8 +69,7 @@ struct boolean { }; struct one_member_one_friend { - friend boolean operator==(one_member_one_friend, - one_member_one_friend) noexcept; + friend boolean operator==(one_member_one_friend, one_member_one_friend) noexcept; boolean operator!=(one_member_one_friend) const noexcept; operator explicit_operators() const noexcept; @@ -208,51 +200,39 @@ struct wrong_return_type { }; struct cxx20_member_eq_operator_with_deleted_ne { - bool - operator==(cxx20_member_eq_operator_with_deleted_ne const&) const = default; - bool - operator!=(cxx20_member_eq_operator_with_deleted_ne const&) const = delete; + bool operator==(cxx20_member_eq_operator_with_deleted_ne const&) const = default; + bool operator!=(cxx20_member_eq_operator_with_deleted_ne const&) const = delete; }; struct cxx20_friend_eq_operator_with_deleted_ne { - friend bool - operator==(cxx20_friend_eq_operator_with_deleted_ne const&, - cxx20_friend_eq_operator_with_deleted_ne const&) = default; - friend bool - operator!=(cxx20_friend_eq_operator_with_deleted_ne const&, - cxx20_friend_eq_operator_with_deleted_ne const&) = delete; + friend bool operator==(cxx20_friend_eq_operator_with_deleted_ne const&, + cxx20_friend_eq_operator_with_deleted_ne const&) = default; + friend bool operator!=(cxx20_friend_eq_operator_with_deleted_ne const&, + cxx20_friend_eq_operator_with_deleted_ne const&) = delete; }; struct member_three_way_comparable_with_deleted_eq { - auto operator<=>(member_three_way_comparable_with_deleted_eq const&) const = - default; - bool - operator==(member_three_way_comparable_with_deleted_eq const&) const = delete; + auto operator<=>(member_three_way_comparable_with_deleted_eq const&) const = default; + bool operator==(member_three_way_comparable_with_deleted_eq const&) const = delete; }; struct member_three_way_comparable_with_deleted_ne { - auto operator<=>(member_three_way_comparable_with_deleted_ne const&) const = - default; - bool - operator!=(member_three_way_comparable_with_deleted_ne const&) const = delete; + auto operator<=>(member_three_way_comparable_with_deleted_ne const&) const = default; + bool operator!=(member_three_way_comparable_with_deleted_ne const&) const = delete; }; struct friend_three_way_comparable_with_deleted_eq { - friend auto - operator<=>(friend_three_way_comparable_with_deleted_eq const&, - friend_three_way_comparable_with_deleted_eq const&) = default; - friend bool - operator==(friend_three_way_comparable_with_deleted_eq const&, - friend_three_way_comparable_with_deleted_eq const&) = delete; + friend auto operator<=>(friend_three_way_comparable_with_deleted_eq const&, + friend_three_way_comparable_with_deleted_eq const&) = default; + friend bool operator==(friend_three_way_comparable_with_deleted_eq const&, + friend_three_way_comparable_with_deleted_eq const&) = delete; }; struct friend_three_way_comparable_with_deleted_ne { - friend auto - operator<=>(friend_three_way_comparable_with_deleted_ne const&, - friend_three_way_comparable_with_deleted_ne const&) = default; - friend bool - operator!=(friend_three_way_comparable_with_deleted_ne const&, - friend_three_way_comparable_with_deleted_ne const&) = delete; + friend auto operator<=>(friend_three_way_comparable_with_deleted_ne const&, + friend_three_way_comparable_with_deleted_ne const&) = default; + friend bool operator!=(friend_three_way_comparable_with_deleted_ne const&, + friend_three_way_comparable_with_deleted_ne const&) = delete; }; struct one_way_eq { @@ -270,9 +250,7 @@ struct one_way_ne { operator explicit_operators() const; }; -static_assert(requires(explicit_operators const x, one_way_ne const y) { - x != y; -}); +static_assert(requires(explicit_operators const x, one_way_ne const y) { x != y; }); struct explicit_bool { explicit operator bool() const noexcept; @@ -283,10 +261,8 @@ struct totally_ordered_with_others { }; struct no_lt_not_totally_ordered_with { - [[nodiscard]] bool - operator==(no_lt_not_totally_ordered_with const&) const = default; - [[nodiscard]] auto - operator<=>(no_lt_not_totally_ordered_with const&) const = default; + [[nodiscard]] bool operator==(no_lt_not_totally_ordered_with const&) const = default; + [[nodiscard]] auto operator<=>(no_lt_not_totally_ordered_with const&) const = default; operator totally_ordered_with_others() const noexcept; [[nodiscard]] bool operator==(totally_ordered_with_others const&) const; @@ -295,10 +271,8 @@ struct no_lt_not_totally_ordered_with { }; struct no_gt_not_totally_ordered_with { - [[nodiscard]] bool - operator==(no_gt_not_totally_ordered_with const&) const = default; - [[nodiscard]] auto - operator<=>(no_gt_not_totally_ordered_with const&) const = default; + [[nodiscard]] bool operator==(no_gt_not_totally_ordered_with const&) const = default; + [[nodiscard]] auto operator<=>(no_gt_not_totally_ordered_with const&) const = default; operator totally_ordered_with_others() const noexcept; [[nodiscard]] bool operator==(totally_ordered_with_others const&) const; @@ -307,10 +281,8 @@ struct no_gt_not_totally_ordered_with { }; struct no_le_not_totally_ordered_with { - [[nodiscard]] bool - operator==(no_le_not_totally_ordered_with const&) const = default; - [[nodiscard]] auto - operator<=>(no_le_not_totally_ordered_with const&) const = default; + [[nodiscard]] bool operator==(no_le_not_totally_ordered_with const&) const = default; + [[nodiscard]] auto operator<=>(no_le_not_totally_ordered_with const&) const = default; operator totally_ordered_with_others() const noexcept; [[nodiscard]] bool operator==(totally_ordered_with_others const&) const; @@ -319,10 +291,8 @@ struct no_le_not_totally_ordered_with { }; struct no_ge_not_totally_ordered_with { - [[nodiscard]] bool - operator==(no_ge_not_totally_ordered_with const&) const = default; - [[nodiscard]] auto - operator<=>(no_ge_not_totally_ordered_with const&) const = default; + [[nodiscard]] bool operator==(no_ge_not_totally_ordered_with const&) const = default; + [[nodiscard]] auto operator<=>(no_ge_not_totally_ordered_with const&) const = default; operator totally_ordered_with_others() const noexcept; [[nodiscard]] bool operator==(totally_ordered_with_others const&) const; @@ -331,35 +301,28 @@ struct no_ge_not_totally_ordered_with { }; struct partial_ordering_totally_ordered_with { - [[nodiscard]] auto operator<=>( - partial_ordering_totally_ordered_with const&) const noexcept = default; - [[nodiscard]] std::partial_ordering - operator<=>(totally_ordered_with_others const&) const noexcept; + [[nodiscard]] auto operator<=>(partial_ordering_totally_ordered_with const&) const noexcept = default; + [[nodiscard]] std::partial_ordering operator<=>(totally_ordered_with_others const&) const noexcept; operator totally_ordered_with_others() const; }; struct weak_ordering_totally_ordered_with { - [[nodiscard]] auto operator<=>( - weak_ordering_totally_ordered_with const&) const noexcept = default; - [[nodiscard]] std::weak_ordering - operator<=>(totally_ordered_with_others const&) const noexcept; + [[nodiscard]] auto operator<=>(weak_ordering_totally_ordered_with const&) const noexcept = default; + [[nodiscard]] std::weak_ordering operator<=>(totally_ordered_with_others const&) const noexcept; operator totally_ordered_with_others() const; }; struct strong_ordering_totally_ordered_with { - [[nodiscard]] auto operator<=>( - strong_ordering_totally_ordered_with const&) const noexcept = default; - [[nodiscard]] std::strong_ordering - operator<=>(totally_ordered_with_others const&) const noexcept; + [[nodiscard]] auto operator<=>(strong_ordering_totally_ordered_with const&) const noexcept = default; + [[nodiscard]] std::strong_ordering operator<=>(totally_ordered_with_others const&) const noexcept; operator totally_ordered_with_others() const; }; struct eq_returns_explicit_bool { - friend explicit_bool operator==(eq_returns_explicit_bool, - eq_returns_explicit_bool); + friend explicit_bool operator==(eq_returns_explicit_bool, eq_returns_explicit_bool); friend bool operator!=(eq_returns_explicit_bool, eq_returns_explicit_bool); friend bool operator<(eq_returns_explicit_bool, eq_returns_explicit_bool); friend bool operator>(eq_returns_explicit_bool, eq_returns_explicit_bool); @@ -368,10 +331,8 @@ struct eq_returns_explicit_bool { operator totally_ordered_with_others() const; - friend explicit_bool operator==(eq_returns_explicit_bool, - totally_ordered_with_others); - friend explicit_bool operator==(totally_ordered_with_others, - eq_returns_explicit_bool); + friend explicit_bool operator==(eq_returns_explicit_bool, totally_ordered_with_others); + friend explicit_bool operator==(totally_ordered_with_others, eq_returns_explicit_bool); friend bool operator!=(eq_returns_explicit_bool, totally_ordered_with_others); friend bool operator!=(totally_ordered_with_others, eq_returns_explicit_bool); friend bool operator<(eq_returns_explicit_bool, totally_ordered_with_others); @@ -386,8 +347,7 @@ struct eq_returns_explicit_bool { struct ne_returns_explicit_bool { friend bool operator==(ne_returns_explicit_bool, ne_returns_explicit_bool); - friend explicit_bool operator!=(ne_returns_explicit_bool, - ne_returns_explicit_bool); + friend explicit_bool operator!=(ne_returns_explicit_bool, ne_returns_explicit_bool); friend bool operator<(ne_returns_explicit_bool, ne_returns_explicit_bool); friend bool operator>(ne_returns_explicit_bool, ne_returns_explicit_bool); friend bool operator<=(ne_returns_explicit_bool, ne_returns_explicit_bool); @@ -396,10 +356,8 @@ struct ne_returns_explicit_bool { operator totally_ordered_with_others() const; friend bool operator==(ne_returns_explicit_bool, totally_ordered_with_others); - friend explicit_bool operator!=(ne_returns_explicit_bool, - totally_ordered_with_others); - friend explicit_bool operator!=(totally_ordered_with_others, - ne_returns_explicit_bool); + friend explicit_bool operator!=(ne_returns_explicit_bool, totally_ordered_with_others); + friend explicit_bool operator!=(totally_ordered_with_others, ne_returns_explicit_bool); friend bool operator<(ne_returns_explicit_bool, totally_ordered_with_others); friend bool operator<(totally_ordered_with_others, ne_returns_explicit_bool); friend bool operator>(ne_returns_explicit_bool, totally_ordered_with_others); @@ -413,8 +371,7 @@ struct ne_returns_explicit_bool { struct lt_returns_explicit_bool { friend bool operator==(lt_returns_explicit_bool, lt_returns_explicit_bool); friend bool operator!=(lt_returns_explicit_bool, lt_returns_explicit_bool); - friend explicit_bool operator<(lt_returns_explicit_bool, - lt_returns_explicit_bool); + friend explicit_bool operator<(lt_returns_explicit_bool, lt_returns_explicit_bool); friend bool operator>(lt_returns_explicit_bool, lt_returns_explicit_bool); friend bool operator<=(lt_returns_explicit_bool, lt_returns_explicit_bool); friend bool operator>=(lt_returns_explicit_bool, lt_returns_explicit_bool); @@ -424,8 +381,7 @@ struct lt_returns_explicit_bool { friend bool operator==(lt_returns_explicit_bool, totally_ordered_with_others); friend bool operator!=(lt_returns_explicit_bool, totally_ordered_with_others); friend bool operator!=(totally_ordered_with_others, lt_returns_explicit_bool); - friend explicit_bool operator<(lt_returns_explicit_bool, - totally_ordered_with_others); + friend explicit_bool operator<(lt_returns_explicit_bool, totally_ordered_with_others); friend bool operator<(totally_ordered_with_others, lt_returns_explicit_bool); friend bool operator>(lt_returns_explicit_bool, totally_ordered_with_others); friend bool operator>(totally_ordered_with_others, lt_returns_explicit_bool); @@ -439,8 +395,7 @@ struct gt_returns_explicit_bool { friend bool operator==(gt_returns_explicit_bool, gt_returns_explicit_bool); friend bool operator!=(gt_returns_explicit_bool, gt_returns_explicit_bool); friend bool operator<(gt_returns_explicit_bool, gt_returns_explicit_bool); - friend explicit_bool operator>(gt_returns_explicit_bool, - gt_returns_explicit_bool); + friend explicit_bool operator>(gt_returns_explicit_bool, gt_returns_explicit_bool); friend bool operator<=(gt_returns_explicit_bool, gt_returns_explicit_bool); friend bool operator>=(gt_returns_explicit_bool, gt_returns_explicit_bool); @@ -451,8 +406,7 @@ struct gt_returns_explicit_bool { friend bool operator!=(totally_ordered_with_others, gt_returns_explicit_bool); friend bool operator<(gt_returns_explicit_bool, totally_ordered_with_others); friend bool operator<(totally_ordered_with_others, gt_returns_explicit_bool); - friend explicit_bool operator>(gt_returns_explicit_bool, - totally_ordered_with_others); + friend explicit_bool operator>(gt_returns_explicit_bool, totally_ordered_with_others); friend bool operator>(totally_ordered_with_others, gt_returns_explicit_bool); friend bool operator<=(gt_returns_explicit_bool, totally_ordered_with_others); friend bool operator<=(totally_ordered_with_others, gt_returns_explicit_bool); @@ -465,8 +419,7 @@ struct le_returns_explicit_bool { friend bool operator!=(le_returns_explicit_bool, le_returns_explicit_bool); friend bool operator<(le_returns_explicit_bool, le_returns_explicit_bool); friend bool operator>(le_returns_explicit_bool, le_returns_explicit_bool); - friend explicit_bool operator<=(le_returns_explicit_bool, - le_returns_explicit_bool); + friend explicit_bool operator<=(le_returns_explicit_bool, le_returns_explicit_bool); friend bool operator>=(le_returns_explicit_bool, le_returns_explicit_bool); operator totally_ordered_with_others() const; @@ -479,8 +432,7 @@ struct le_returns_explicit_bool { friend bool operator>(le_returns_explicit_bool, totally_ordered_with_others); friend bool operator>(totally_ordered_with_others, le_returns_explicit_bool); friend bool operator<=(le_returns_explicit_bool, totally_ordered_with_others); - friend explicit_bool operator<=(totally_ordered_with_others, - le_returns_explicit_bool); + friend explicit_bool operator<=(totally_ordered_with_others, le_returns_explicit_bool); friend bool operator>=(le_returns_explicit_bool, totally_ordered_with_others); friend bool operator>=(totally_ordered_with_others, le_returns_explicit_bool); }; @@ -491,8 +443,7 @@ struct ge_returns_explicit_bool { friend bool operator<(ge_returns_explicit_bool, ge_returns_explicit_bool); friend bool operator>(ge_returns_explicit_bool, ge_returns_explicit_bool); friend bool operator<=(ge_returns_explicit_bool, ge_returns_explicit_bool); - friend explicit_bool operator>=(ge_returns_explicit_bool, - ge_returns_explicit_bool); + friend explicit_bool operator>=(ge_returns_explicit_bool, ge_returns_explicit_bool); operator totally_ordered_with_others() const; @@ -506,8 +457,7 @@ struct ge_returns_explicit_bool { friend bool operator<=(ge_returns_explicit_bool, totally_ordered_with_others); friend bool operator<=(totally_ordered_with_others, ge_returns_explicit_bool); friend bool operator>=(ge_returns_explicit_bool, totally_ordered_with_others); - friend explicit_bool operator>=(totally_ordered_with_others, - ge_returns_explicit_bool); + friend explicit_bool operator>=(totally_ordered_with_others, ge_returns_explicit_bool); }; struct returns_true_type { @@ -520,30 +470,18 @@ struct returns_true_type { operator totally_ordered_with_others() const; - friend std::true_type operator==(returns_true_type, - totally_ordered_with_others); - friend std::true_type operator==(totally_ordered_with_others, - returns_true_type); - friend std::true_type operator!=(returns_true_type, - totally_ordered_with_others); - friend std::true_type operator!=(totally_ordered_with_others, - returns_true_type); - friend std::true_type operator<(returns_true_type, - totally_ordered_with_others); - friend std::true_type operator<(totally_ordered_with_others, - returns_true_type); - friend std::true_type operator>(returns_true_type, - totally_ordered_with_others); - friend std::true_type operator>(totally_ordered_with_others, - returns_true_type); - friend std::true_type operator<=(returns_true_type, - totally_ordered_with_others); - friend std::true_type operator<=(totally_ordered_with_others, - returns_true_type); - friend std::true_type operator>=(returns_true_type, - totally_ordered_with_others); - friend std::true_type operator>=(totally_ordered_with_others, - returns_true_type); + friend std::true_type operator==(returns_true_type, totally_ordered_with_others); + friend std::true_type operator==(totally_ordered_with_others, returns_true_type); + friend std::true_type operator!=(returns_true_type, totally_ordered_with_others); + friend std::true_type operator!=(totally_ordered_with_others, returns_true_type); + friend std::true_type operator<(returns_true_type, totally_ordered_with_others); + friend std::true_type operator<(totally_ordered_with_others, returns_true_type); + friend std::true_type operator>(returns_true_type, totally_ordered_with_others); + friend std::true_type operator>(totally_ordered_with_others, returns_true_type); + friend std::true_type operator<=(returns_true_type, totally_ordered_with_others); + friend std::true_type operator<=(totally_ordered_with_others, returns_true_type); + friend std::true_type operator>=(returns_true_type, totally_ordered_with_others); + friend std::true_type operator>=(totally_ordered_with_others, returns_true_type); }; struct returns_int_ptr { @@ -570,4 +508,24 @@ struct returns_int_ptr { friend int* operator>=(totally_ordered_with_others, returns_int_ptr); }; -#endif // TEST_STD_CONCEPTS_COMPARISON_TYPES_H +struct ForwardingTestObject { + constexpr bool operator<(ForwardingTestObject&&) && { return true; } + constexpr bool operator<(const ForwardingTestObject&) const& { return false; } + + constexpr bool operator==(ForwardingTestObject&&) && { return true; } + constexpr bool operator==(const ForwardingTestObject&) const& { return false; } + + constexpr bool operator!=(ForwardingTestObject&&) && { return true; } + constexpr bool operator!=(const ForwardingTestObject&) const& { return false; } + + constexpr bool operator<=(ForwardingTestObject&&) && { return true; } + constexpr bool operator<=(const ForwardingTestObject&) const& { return false; } + + constexpr bool operator>(ForwardingTestObject&&) && { return true; } + constexpr bool operator>(const ForwardingTestObject&) const& { return false; } + + constexpr bool operator>=(ForwardingTestObject&&) && { return true; } + constexpr bool operator>=(const ForwardingTestObject&) const& { return false; } +}; + +#endif // TEST_SUPPORT_COMPARE_TYPES_H diff --git a/libcxx/test/support/pointer_comparison_test_helper.h b/libcxx/test/support/pointer_comparison_test_helper.h new file mode 100644 index 000000000000..c47d9ffd90bd --- /dev/null +++ b/libcxx/test/support/pointer_comparison_test_helper.h @@ -0,0 +1,54 @@ +#ifndef POINTER_COMPARISON_TEST_HELPER_H +#define POINTER_COMPARISON_TEST_HELPER_H + +#include +#include + +#include "test_macros.h" + +template