Index: libcxx/include/functional =================================================================== --- libcxx/include/functional +++ libcxx/include/functional @@ -144,6 +144,12 @@ bool operator()(const T& x, const T& y) const; }; +struct compare_three_way { + template + requires three_way_comparable_with || BUILTIN-PTR-THREE-WAY(T, U) + constexpr auto operator()(T&& t, U&& u) const; +}; + template // in C++14 struct logical_and : binary_function { @@ -506,6 +512,10 @@ #include #include +#if !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) +#include +#endif // __LIBCPP_HAS_NO_SPACESHIP_OPERATOR + #include <__functional_base> #if defined(_LIBCPP_HAS_BLOCKS_RUNTIME) && !defined(_LIBCPP_HAS_OBJC_ARC) @@ -816,6 +826,19 @@ }; #endif +#if !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) +struct compare_three_way { + template + //requires three_way_comparable_with<_T1, _T2> || BUILTIN-PTR-THREE-WAY(_T1, _T2) + // TODO(cjdb): uncomment once three_way_comparable_with is commit + constexpr auto operator()(_T1&& __t, _T2&& __u) const + _NOEXCEPT_(noexcept(_VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u))) + -> decltype (_VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u)) + { return _VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u); } + using is_transparent = void; +}; +#endif // _LIBCPP_HAS_NO_SPACESHIP_OPERATOR + #if _LIBCPP_STD_VER > 11 template Index: libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03, c++11, c++14, c++17 + +// + +// less + +#include +#include +#include +#include + +#include "test_macros.h" +#include "pointer_comparison_test_helper.h" + +template +void do_pointer_comparison_test() { + 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())); + std::compare_three_way comp; + std::less vcomp; + std::less ucomp; + 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(vcomp(lhs, rhs) == ucomp(lhs_uint, rhs_uint)); + assert((comp(lhs, rhs) == std::strong_ordering::less) == + ucomp(lhs_uint, rhs_uint)); + } + } +} + +int main(int, char**) { + typedef std::compare_three_way F; + const F f = F(); + assert(f(36, 36) == std::strong_ordering::equal); + assert(f(36, 6) == std::strong_ordering::greater); + assert(f(6, 36) == std::strong_ordering::less); + { + // test total ordering of int* for compare_three_way. + do_pointer_comparison_test(); + } + + assert(f(36, 36) == std::strong_ordering::equal); + assert(f(36, 6) == std::strong_ordering::greater); + assert(f(6, 36) == std::strong_ordering::less); + assert(f(36, 6.0) == std::partial_ordering::greater); + assert(f(36.0, 6) == std::partial_ordering::greater); + assert(f(6, 36.0) == std::partial_ordering::less); + assert(f(6.0, 36) == std::partial_ordering::less); + + constexpr std::strong_ordering foo = std::compare_three_way()(36, 36); + static_assert(foo == std::strong_ordering::equal, ""); + + constexpr std::partial_ordering bar = std::compare_three_way()(36.0, 36); + static_assert(bar == std::partial_ordering::equivalent, ""); + + return 0; +}