diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv --- a/libcxx/docs/Status/SpaceshipProjects.csv +++ b/libcxx/docs/Status/SpaceshipProjects.csv @@ -4,7 +4,7 @@ | `[cmp.result] `_,| `compare_three_way_result `_,None,Arthur O'Dwyer,|Complete| | `[expos.only.func] `_,"| `synth-three-way `_ | `synth-three-way-result `_",[cmp.concept],Kent Ross,|Complete| -| `[comparisons.three.way] `_,| `compare_three_way `_,[cmp.concept],Christopher Di Bella,|In Progress| +| `[comparisons.three.way] `_,| `compare_three_way `_,[cmp.concept],Arthur O'Dwyer,|Complete| | `[cmp.alg] `_,"| `strong_order `_ | `weak_order `_ | `partial_order `_",None,Arthur O'Dwyer,|In Progress| diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -102,6 +102,7 @@ __charconv/from_chars_result.h __charconv/to_chars_result.h __compare/common_comparison_category.h + __compare/compare_three_way.h __compare/compare_three_way_result.h __compare/is_eq.h __compare/ordering.h diff --git a/libcxx/include/__compare/compare_three_way.h b/libcxx/include/__compare/compare_three_way.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/compare_three_way.h @@ -0,0 +1,41 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_COMPARE_THREE_WAY_H +#define _LIBCPP___COMPARE_COMPARE_THREE_WAY_H + +#include <__config> +#include <__compare/three_way_comparable.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +struct _LIBCPP_TEMPLATE_VIS compare_three_way +{ + template + requires three_way_comparable_with<_T1, _T2> + constexpr _LIBCPP_HIDE_FROM_ABI + auto operator()(_T1&& __t, _T2&& __u) const + noexcept(noexcept(_VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u))) + { return _VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u); } + + using is_transparent = void; +}; + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_COMPARE_THREE_WAY_H diff --git a/libcxx/include/compare b/libcxx/include/compare --- a/libcxx/include/compare +++ b/libcxx/include/compare @@ -47,6 +47,9 @@ template using compare_three_way_result_t = typename compare_three_way_result::type; + // [comparisons.three.way], class compare_three_way + struct compare_three_way; // C++20 + // [cmp.alg], comparison algorithms template constexpr strong_ordering strong_order(const T& a, const T& b); template constexpr weak_ordering weak_order(const T& a, const T& b); @@ -133,6 +136,7 @@ */ #include <__compare/common_comparison_category.h> +#include <__compare/compare_three_way.h> #include <__compare/compare_three_way_result.h> #include <__compare/is_eq.h> #include <__compare/ordering.h> diff --git a/libcxx/include/functional b/libcxx/include/functional --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -135,6 +135,9 @@ bool operator()(const T& x, const T& y) const; }; +// [comparisons.three.way], class compare_three_way +struct compare_three_way; + template // in C++14 struct logical_and { bool operator()(const T& x, const T& y) const; @@ -488,6 +491,7 @@ */ #include <__algorithm/search.h> +#include <__compare/compare_three_way.h> #include <__config> #include <__debug> #include <__functional/binary_function.h> // TODO: deprecate diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -372,6 +372,7 @@ module __compare { module common_comparison_category { private header "__compare/common_comparison_category.h" } + module compare_three_way { private header "__compare/compare_three_way.h" } module compare_three_way_result { private header "__compare/compare_three_way_result.h" } module is_eq { private header "__compare/is_eq.h" } module ordering { private header "__compare/ordering.h" } diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/compare/compare_three_way.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/compare_three_way.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/compare_three_way.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__compare/compare_three_way.h'}} +#include <__compare/compare_three_way.h> diff --git a/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// +// + +// compare_three_way + +#include +#include +#include +#include + +#include "pointer_comparison_test_helper.h" + +template +constexpr auto test_sfinae(T t, U u) + -> decltype(std::compare_three_way()(t, u), std::true_type{}) + { return std::true_type{}; } + +constexpr auto test_sfinae(...) + { return std::false_type{}; } + +struct NotThreeWayComparable { + std::strong_ordering operator<=>(const NotThreeWayComparable&) const; +}; +ASSERT_SAME_TYPE(std::compare_three_way_result_t, std::strong_ordering); +static_assert(!std::three_way_comparable); // it lacks operator== + +struct WeaklyOrdered { + int i; + friend constexpr std::weak_ordering operator<=>(const WeaklyOrdered&, const WeaklyOrdered&) = default; +}; + +constexpr bool test() +{ + ASSERT_SAME_TYPE(decltype(std::compare_three_way()(1, 1)), std::strong_ordering); + assert(std::compare_three_way()(1, 2) == std::strong_ordering::less); + assert(std::compare_three_way()(1, 1) == std::strong_ordering::equal); + assert(std::compare_three_way()(2, 1) == std::strong_ordering::greater); + + ASSERT_SAME_TYPE(decltype(std::compare_three_way()(WeaklyOrdered{1}, WeaklyOrdered{2})), std::weak_ordering); + assert(std::compare_three_way()(WeaklyOrdered{1}, WeaklyOrdered{2}) == std::weak_ordering::less); + assert(std::compare_three_way()(WeaklyOrdered{1}, WeaklyOrdered{1}) == std::weak_ordering::equivalent); + assert(std::compare_three_way()(WeaklyOrdered{2}, WeaklyOrdered{1}) == std::weak_ordering::greater); + + ASSERT_SAME_TYPE(decltype(std::compare_three_way()(1.0, 1.0)), std::partial_ordering); + double nan = std::numeric_limits::quiet_NaN(); + assert(std::compare_three_way()(1.0, 2.0) == std::partial_ordering::less); + assert(std::compare_three_way()(1.0, 1.0) == std::partial_ordering::equivalent); + assert(std::compare_three_way()(2.0, 1.0) == std::partial_ordering::greater); + assert(std::compare_three_way()(nan, nan) == std::partial_ordering::unordered); + + // Try heterogeneous comparison. + ASSERT_SAME_TYPE(decltype(std::compare_three_way()(42.0, 42)), std::partial_ordering); + assert(std::compare_three_way()(42.0, 42) == std::partial_ordering::equivalent); + ASSERT_SAME_TYPE(decltype(std::compare_three_way()(42, 42.0)), std::partial_ordering); + assert(std::compare_three_way()(42, 42.0) == std::partial_ordering::equivalent); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + do_pointer_comparison_test(std::compare_three_way()); + + static_assert(test_sfinae(1, 2)); + static_assert(!test_sfinae(1, nullptr)); + static_assert(!test_sfinae(NotThreeWayComparable(), NotThreeWayComparable())); + + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way_functional.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way_functional.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way_functional.pass.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// Test that std::compare_three_way is defined in , +// not only in . + +#include +#include + +int main(int, char**) +{ + assert(std::compare_three_way()(1, 2) < 0); + assert(std::compare_three_way()(1, 1) == 0); + assert(std::compare_three_way()(2, 1) > 0); + + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/comparisons/transparent.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/transparent.pass.cpp --- a/libcxx/test/std/utilities/function.objects/comparisons/transparent.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/comparisons/transparent.pass.cpp @@ -56,5 +56,9 @@ static_assert ( is_transparent>::value, "" ); static_assert ( is_transparent>::value, "" ); +#if TEST_STD_VER > 17 + static_assert( is_transparent::value, "" ); +#endif + return 0; }