diff --git a/libcxx/include/functional b/libcxx/include/functional --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -507,6 +507,7 @@ */ #include <__config> +#include #include #include #include @@ -3222,6 +3223,74 @@ }; #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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 --- 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 --- 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 --- 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 --- 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/pointer_comparison_test_helper.h b/libcxx/test/std/utilities/function.objects/comparisons/pointer_comparison_test_helper.h deleted file mode 100644 --- 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/equal_to.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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 constexpr bool operator==(const NotEqualityComparable&, + const NotEqualityComparable&) { + return true; + } + friend constexpr bool operator!=(const NotEqualityComparable&, + const NotEqualityComparable&) = delete; +}; + +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)); + + 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(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/greater.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// 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 constexpr bool operator<(const NotTotallyOrdered&, + const NotTotallyOrdered&) { + return true; + } +}; + +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +// We don't know what this type is, just that is should exist. +void test_is_transparent(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)); + + return true; +} + +int main(int, char**) { + + test(); + static_assert(test()); + + // test total ordering of int* for greater and greater. + do_pointer_comparison_test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/greater_equal.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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 constexpr bool operator<(const NotTotallyOrdered&, + const NotTotallyOrdered&) { + return true; + } +}; + +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +// We don't know what this type is, just that is should exist. +void test_is_transparent(std::ranges::greater_equal::is_transparent) {} + +constexpr bool test() { + auto fn = std::ranges::greater_equal(); + + assert(fn(MoveOnly(42), 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(2, 2)); + assert(fn(2, 1)); + assert(!fn(1, 2)); + + 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(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/less.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// 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 constexpr bool operator<(const NotTotallyOrdered&, + const NotTotallyOrdered&) { + return true; + } +}; + +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +// We don't know what this type is, just that is should exist. +void test_is_transparent(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)); + + return true; +} + +int main(int, char**) { + + test(); + static_assert(test()); + + // test total ordering of int* for less and less. + do_pointer_comparison_test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/less_equal.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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 constexpr bool operator<(const NotTotallyOrdered&, + const NotTotallyOrdered&) { + return true; + } +}; + +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +// We don't know what this type is, just that is should exist. +void test_is_transparent(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)); + + 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(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/range.cmp/not_equal_to.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// 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 constexpr bool operator==(const NotEqualityComparable&, + const NotEqualityComparable&) { + return true; + } + friend constexpr bool operator!=(const NotEqualityComparable&, + const NotEqualityComparable&) = delete; +}; + +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); + +// We don't know what this type is, just that is should exist. +void test_is_transparent(std::ranges::not_equal_to::is_transparent) {} + +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)); + + 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(); + + return 0; +} diff --git a/libcxx/test/std/concepts/concepts.compare/types.h b/libcxx/test/support/compare_types.h rename from libcxx/test/std/concepts/concepts.compare/types.h rename to libcxx/test/support/compare_types.h --- a/libcxx/test/std/concepts/concepts.compare/types.h +++ b/libcxx/test/support/compare_types.h @@ -570,4 +570,32 @@ friend int* operator>=(totally_ordered_with_others, returns_int_ptr); }; +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_STD_CONCEPTS_COMPARISON_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 --- /dev/null +++ b/libcxx/test/support/pointer_comparison_test_helper.h @@ -0,0 +1,39 @@ +#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 + const std::size_t test_size = 100; + std::vector > pointers(test_size); + std::generate_n(pointers.begin(), test_size, std::make_shared); + + 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