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/ordering.h __compare/synth_three_way.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) + +struct _LIBCPP_TEMPLATE_VIS compare_three_way +{ + template + requires three_way_comparable_with<_T1, _T2> + constexpr _LIBCPP_INLINE_VISIBILITY + 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) + +_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; + // [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/ordering.h> #include <__compare/three_way_comparable.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 ordering { private header "__compare/ordering.h" } module synth_three_way { private header "__compare/synth_three_way.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,16 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// 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,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 + +// +// + +// compare_three_way + +#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== + +constexpr bool test() +{ + ASSERT_SAME_TYPE(decltype(std::compare_three_way()(1, 1)), std::strong_ordering); + assert(std::compare_three_way()(1, 1) == std::strong_ordering::equal); + assert(std::compare_three_way()(1, 2) == std::strong_ordering::less); + assert(std::compare_three_way()(2, 1) == std::strong_ordering::greater); + + ASSERT_SAME_TYPE(decltype(std::compare_three_way()(1.0, 1.0)), std::partial_ordering); + assert(std::compare_three_way()(1.0, 1.0) == std::partial_ordering::equivalent); + assert(std::compare_three_way()(1.0, 2.0) == std::partial_ordering::less); + assert(std::compare_three_way()(2.0, 1.0) == std::partial_ordering::greater); + + // 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); + + 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/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; }