diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -97,9 +97,12 @@ __bits __bsd_locale_defaults.h __bsd_locale_fallbacks.h + __compare/cmp_alg.h __compare/common_comparison_category.h + __compare/compare_three_way.h __compare/compare_three_way_result.h __compare/ordering.h + __compare/three_way_comparable.h __concepts/arithmetic.h __concepts/assignable.h __concepts/boolean_testable.h @@ -275,6 +278,7 @@ __utility/move.h __utility/pair.h __utility/piecewise_construct.h + __utility/priority_tag.h __utility/rel_ops.h __utility/swap.h __utility/to_underlying.h diff --git a/libcxx/include/__compare/cmp_alg.h b/libcxx/include/__compare/cmp_alg.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/cmp_alg.h @@ -0,0 +1,128 @@ +// -*- C++ -*- +//===-------------------------- compare -----------------------------------===// +// +// 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_CMP_ALG +#define _LIBCPP___COMPARE_CMP_ALG + +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> +#include <__config> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> +#include +#include +#include +#include + +#ifndef _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) + +// [cmp.alg] +namespace __strong_order { + struct __fn { + template + requires is_same_v, decay_t<_Fp>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<2>) + noexcept(noexcept( strong_ordering(strong_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) )) + -> decltype( strong_ordering(strong_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) ) + { + return strong_ordering(strong_order(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))); + } + + template> + requires is_same_v<_Dp, decay_t<_Fp>> && is_floating_point_v<_Dp> + _LIBCPP_HIDE_FROM_ABI static strong_ordering + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<1>) noexcept + { + if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(uint32_t)) { + uint32_t __rx = 0; + uint32_t __ry = 0; + _VSTD::memcpy(&__rx, &__e, sizeof(uint32_t)); + _VSTD::memcpy(&__ry, &__f, sizeof(uint32_t)); + __rx ^= numeric_limits::min(); + __ry ^= numeric_limits::min(); + if (_VSTD::signbit(__e)) __rx ^= numeric_limits::max(); + if (_VSTD::signbit(__f)) __ry ^= numeric_limits::max(); + return (__rx <=> __ry); + } else if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(uint64_t)) { + uint64_t __rx = 0; + uint64_t __ry = 0; + _VSTD::memcpy(&__rx, &__e, sizeof(uint64_t)); + _VSTD::memcpy(&__ry, &__f, sizeof(uint64_t)); + __rx ^= numeric_limits::min(); + __ry ^= numeric_limits::min(); + if (_VSTD::signbit(__e)) __rx ^= numeric_limits::max(); + if (_VSTD::signbit(__f)) __ry ^= numeric_limits::max(); + return (__rx <=> __ry); + } else if (__e < __f) { + return strong_ordering::less; + } else if (__e > __f) { + return strong_ordering::greater; + } else if (__e == __f) { + if (__e == 0) { + return _VSTD::signbit(__f) <=> _VSTD::signbit(__e); + } else if (_VSTD::isinf(__e)) { + return strong_ordering::equal; + } else { + int __eexp, __fexp; + (void)_VSTD::frexp(__e, &__eexp); + (void)_VSTD::frexp(__f, &__fexp); + return (__e < 0) ? (__eexp <=> __fexp) : (__fexp <=> __eexp); + } + } else { + // The order is -QNAN, -SNAN, numbers, +SNAN, +QNAN. + if (_VSTD::isnan(__e)) { + if (_VSTD::isnan(__f)) { + // These two NaNs should be ordered by their payload bits, + // but there's no way to get at that information portably. + return _VSTD::signbit(__f) <=> _VSTD::signbit(__e); + } else { + return _VSTD::signbit(__e) ? strong_ordering::less : strong_ordering::greater; + } + } else { + return _VSTD::signbit(__f) ? strong_ordering::greater : strong_ordering::less; + } + } + } + + template + requires is_same_v, decay_t<_Fp>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Ep&& __e, _Fp&& __f, _PriorityTag<0>) + noexcept(noexcept( strong_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) )) + -> decltype( strong_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))) ) + { + return strong_ordering(compare_three_way()(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f))); + } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Ep&& __e, _Fp&& __f) const + noexcept(noexcept( __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<2>()) )) + -> decltype( __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<2>()) ) + { + return __go(_VSTD::forward<_Ep>(__e), _VSTD::forward<_Fp>(__f), _PriorityTag<2>()); + } + }; +} // namespace __strong_order + +inline namespace __cpo { + inline constexpr auto strong_order = __strong_order::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_CMP_ALG 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/three_way_comparable.h b/libcxx/include/__compare/three_way_comparable.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/three_way_comparable.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// 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_THREE_WAY_COMPARABLE_H +#define _LIBCPP___COMPARE_THREE_WAY_COMPARABLE_H + +#include <__compare/common_comparison_category.h> +#include <__compare/ordering.h> +#include <__concepts/common_reference_with.h> +#include <__concepts/equality_comparable.h> +#include <__concepts/same_as.h> +#include <__concepts/totally_ordered.h> +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +template +concept __compares_as = + same_as, _Cat>; + +template +concept three_way_comparable = + __weakly_equality_comparable_with<_Tp, _Tp> && + __partially_ordered_with<_Tp, _Tp> && + requires (const remove_reference_t<_Tp>& __t) { + { __t <=> __t } -> __compares_as<_Cat>; + }; + +template +concept three_way_comparable_with = + three_way_comparable<_Tp, _Cat> && + three_way_comparable<_Up, _Cat> && + common_reference_with&, const remove_reference_t<_Up>&> && + three_way_comparable&, const remove_reference_t<_Up>&>, _Cat> && + __weakly_equality_comparable_with<_Tp, _Up> && + __partially_ordered_with<_Tp, _Up> && + requires (const remove_reference_t<_Tp>& __t, const remove_reference_t<_Up>& __u) { + { __t <=> __u } -> __compares_as<_Cat>; + { __u <=> __t } -> __compares_as<_Cat>; + }; + +#endif // _LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_THREE_WAY_COMPARABLE_H diff --git a/libcxx/include/__utility/priority_tag.h b/libcxx/include/__utility/priority_tag.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__utility/priority_tag.h @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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___UTILITY_PRIORITY_TAG_H +#define _LIBCPP___UTILITY_PRIORITY_TAG_H + +#include <__config> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template struct _PriorityTag : _PriorityTag<_Ip - 1> {}; +template<> struct _PriorityTag<0> {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___UTILITY_PRIORITY_TAG_H diff --git a/libcxx/include/compare b/libcxx/include/compare --- a/libcxx/include/compare +++ b/libcxx/include/compare @@ -35,12 +35,21 @@ template using common_comparison_category_t = typename common_comparison_category::type; + // [cmp.concept], concept three_way_comparable + template + concept three_way_comparable = see below; + template + concept three_way_comparable_with = see below; + // [cmp.result], result of three-way comparison template struct compare_three_way_result; 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); @@ -126,27 +135,12 @@ } */ +#include <__compare/cmp_alg.h> #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> #include <__config> -#ifndef _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) - -// [cmp.alg], comparison algorithms -// TODO: unimplemented -template constexpr strong_ordering strong_order(const _Tp& __lhs, const _Tp& __rhs); -template constexpr weak_ordering weak_order(const _Tp& __lhs, const _Tp& __rhs); -template constexpr partial_ordering partial_order(const _Tp& __lhs, const _Tp& __rhs); - -#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) - -_LIBCPP_END_NAMESPACE_STD - #endif // _LIBCPP_COMPARE 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 @@ -360,9 +360,12 @@ export * module __compare { + module cmp_alg { private header "__compare/cmp_alg.h" } 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 three_way_comparable { private header "__compare/three_way_comparable.h" } } } module complex { @@ -791,6 +794,7 @@ module move { private header "__utility/move.h" } module pair { private header "__utility/pair.h" } module piecewise_construct { private header "__utility/piecewise_construct.h" } + module priority_tag { private header "__utility/priority_tag.h" } module rel_ops { private header "__utility/rel_ops.h" } module swap { private header "__utility/swap.h" } module to_underlying { private header "__utility/to_underlying.h" } diff --git a/libcxx/include/utility b/libcxx/include/utility --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -220,6 +220,7 @@ #include <__utility/move.h> #include <__utility/pair.h> #include <__utility/piecewise_construct.h> +#include <__utility/priority_tag.h> #include <__utility/rel_ops.h> #include <__utility/swap.h> #include <__utility/to_underlying.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/compare/cmp_alg.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/cmp_alg.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/cmp_alg.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/cmp_alg.h'}} +#include <__compare/cmp_alg.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/libcxx/diagnostics/detail.headers/compare/three_way_comparable.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/three_way_comparable.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/three_way_comparable.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/three_way_comparable.h'}} +#include <__compare/three_way_comparable.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/utility/priority_tag.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/utility/priority_tag.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/utility/priority_tag.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: '__utility/priority_tag.h'}} +#include <__utility/priority_tag.h> diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/cmp/cmp.alg/strong_order.pass.cpp @@ -0,0 +1,205 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class strong_ordering + +#include +#include +#include +#include +#include +#include + +#include + +#include "test_macros.h" + +template +constexpr auto has_strong_order(T&& t, U&& u) + -> decltype(std::strong_order(static_cast(t), static_cast(u)), std::true_type()) +{ + return std::true_type(); +} + +constexpr std::false_type has_strong_order(...) { + return std::false_type(); +} + +namespace N11 { + struct A {}; + struct B {}; + std::strong_ordering strong_order(const A&, const A&) { return std::strong_ordering::less; } + std::strong_ordering strong_order(const A&, const B&); +} + +void test_1_1() +{ + // If the decayed types of E and F differ, strong_order(E, F) is ill-formed. + + static_assert( has_strong_order(1, 2)); + static_assert(!has_strong_order(1, (short)2)); + static_assert(!has_strong_order(1, 2.0)); + static_assert(!has_strong_order(1.0f, 2.0)); + + static_assert( has_strong_order((int*)nullptr, (int*)nullptr)); + static_assert(!has_strong_order((int*)nullptr, (const int*)nullptr)); + static_assert(!has_strong_order((const int*)nullptr, (int*)nullptr)); + static_assert( has_strong_order((const int*)nullptr, (const int*)nullptr)); + + N11::A a; + N11::B b; + static_assert( has_strong_order(a, a)); + static_assert(!has_strong_order(a, b)); +} + +namespace N12 { + struct A {}; + std::strong_ordering strong_order(A&, A&&) { return std::strong_ordering::less; } + std::strong_ordering strong_order(A&&, A&&) { return std::strong_ordering::equal; } + std::strong_ordering strong_order(const A&, const A&); + + struct B { + friend std::weak_ordering strong_order(B&, B&); + }; + + struct Order { + explicit operator std::strong_ordering() const { return std::strong_ordering::less; } + }; + struct C { + bool touched = false; + friend Order strong_order(C& lhs, C&) { lhs.touched = true; return Order(); } + }; +} + +void test_1_2() +{ + // Otherwise, strong_ordering(strong_order(E, F)) + // if it is a well-formed expression with overload resolution performed + // in a context that does not include a declaration of std::strong_order. + + // Test that strong_order does not const-qualify the forwarded arguments. + N12::A a; + assert(std::strong_order(a, std::move(a)) == std::strong_ordering::less); + assert(std::strong_order(std::move(a), std::move(a)) == std::strong_ordering::equal); + + // The type of strong_order(e,f) must be explicitly convertible to strong_order. + N12::B b; + static_assert(!has_strong_order(b, b)); + + N12::C c1, c2; + ASSERT_SAME_TYPE(decltype(std::strong_order(c1, c2)), std::strong_ordering); + assert(std::strong_order(c1, c2) == std::strong_ordering::less); + assert(c1.touched); + assert(!c2.touched); +} + +template +void test_1_3() +{ + // Otherwise, if the decayed type T of E is a floating-point type, + // yields a value of type strong_ordering that is consistent with + // the ordering observed by T's comparison operators, + // and if numeric_limits::is_iec559 is true, is additionally consistent with + // the totalOrder operation as specified in ISO/IEC/IEEE 60559. + + static_assert(std::numeric_limits::is_iec559); + + F values[] = { + _VSTD::copysign(std::numeric_limits::quiet_NaN(), F(-1)), + _VSTD::copysign(std::numeric_limits::signaling_NaN(), F(-1)), + -std::numeric_limits::infinity(), + std::numeric_limits::lowest(), // largest (finite) negative number + F(-1.0), F(-0.1), + -std::numeric_limits::min(), // smallest (normal) negative number + F(-0.0), // negative zero + F(0.0), + std::numeric_limits::min(), // smallest (normal) positive number + F(0.1), F(1.0), F(2.0), F(3.14), + std::numeric_limits::max(), // largest (finite) positive number + std::numeric_limits::infinity(), + _VSTD::copysign(std::numeric_limits::signaling_NaN(), F(+1)), + _VSTD::copysign(std::numeric_limits::quiet_NaN(), F(+1)), + }; + + for (const F& a : values) { + for (const F& b : values) { + auto naturalOrder = (a <=> b); + auto expectedOrder = (&a <=> &b); + auto strongOrder = std::strong_order(a, b); + ASSERT_SAME_TYPE(decltype(strongOrder), std::strong_ordering); + if (std::isnan(a) && std::isnan(b) && (sizeof(F) > sizeof(double))) { + // TODO FIXME: strong_order should order NaNs by their payload bits. + } else { + assert(strongOrder == expectedOrder); + if (naturalOrder < 0) assert(strongOrder < 0); + if (naturalOrder > 0) assert(strongOrder > 0); + } + } + } +} + +namespace N14 { + // Compare to N12::A. + struct A {}; + bool operator==(const A&, const A&); + std::strong_ordering operator<=>(A&, A&&) { return std::strong_ordering::less; } + std::strong_ordering operator<=>(A&&, A&&) { return std::strong_ordering::equal; } + std::strong_ordering operator<=>(const A&, const A&); + static_assert(std::three_way_comparable); + + struct B { + std::strong_ordering operator<=>(const B&) const; // lacks operator== + }; + static_assert(!std::three_way_comparable); + + struct C { + mutable bool touched = false; + bool operator==(const C&) const; + std::strong_ordering operator<=>(const C& rhs) const { + rhs.touched = true; + return std::strong_ordering::equal; + } + }; + static_assert(std::three_way_comparable); +} + +constexpr bool test_1_4() +{ + // Otherwise, strong_ordering(compare_three_way()(E, F)) if it is a well-formed expression. + + // Test neither strong_order nor compare_three_way const-qualify the forwarded arguments. + N14::A a; + assert(std::strong_order(a, std::move(a)) == std::strong_ordering::less); + assert(std::strong_order(std::move(a), std::move(a)) == std::strong_ordering::equal); + + N14::B b; + static_assert(!has_strong_order(b, b)); + + N14::C c1, c2; + assert(std::strong_order(c1, c2) == std::strong_ordering::equal); + assert(!c1.touched); + assert(c2.touched); + + return true; +} + +int main(int, char**) +{ + test_1_1(); + test_1_2(); + test_1_3(); + test_1_3(); + test_1_3(); + test_1_4(); + + return 0; +} diff --git a/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable.compile.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable.compile.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// concept three_way_comparable; + +#include + +#include "test_macros.h" + +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(!std::three_way_comparable); // int is not a comparison category type + +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(!std::three_way_comparable); + +struct A { + bool operator==(const A&) const; + bool operator<(const A&) const; + bool operator<=(const A&) const; + bool operator>(const A&) const; + bool operator>=(const A&) const; +}; +static_assert(std::equality_comparable); +static_assert(std::totally_ordered); +static_assert(!std::three_way_comparable); // A has no <=> +static_assert(!std::three_way_comparable); + +struct B { + bool operator==(const B&) const; + std::strong_ordering operator<=>(const B&) const; + bool operator>=(const B&) const = delete; +}; +static_assert(std::equality_comparable); +static_assert(!std::three_way_comparable); // B has <=> but no >= +static_assert(!std::three_way_comparable); + +struct C { + bool operator==(C&); + std::strong_ordering operator<=>(C&); +}; +static_assert(!std::three_way_comparable); // C is not const-comparable +static_assert(!std::three_way_comparable); + +struct D { + bool operator==(const D&) const; + std::strong_ordering operator<=>(const D&) const; +}; +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(!std::three_way_comparable); + +struct E { + bool operator==(const E&) const; + std::weak_ordering operator<=>(const E&) const; +}; +static_assert(std::three_way_comparable); +static_assert(!std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(!std::three_way_comparable); + +struct F { + bool operator==(const F&) const; + std::partial_ordering operator<=>(const F&) const; +}; +static_assert(std::three_way_comparable); +static_assert(!std::three_way_comparable); +static_assert(!std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(!std::three_way_comparable); + +struct G { + bool operator==(const G&) const; + int operator<=>(const G&) const; +}; +static_assert(!std::three_way_comparable); +static_assert(!std::three_way_comparable); +static_assert(!std::three_way_comparable); +static_assert(!std::three_way_comparable); +static_assert(std::three_way_comparable); +static_assert(!std::three_way_comparable); diff --git a/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/cmp/cmp.concept/three_way_comparable_with.compile.pass.cpp @@ -0,0 +1,147 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// concept three_way_comparable_with; + +#include +#include + +#include "test_macros.h" + +struct EnsureCommonReference { + std::strong_ordering operator<=>(const EnsureCommonReference&) const; + bool operator==(const EnsureCommonReference&) const; +}; +template class TREF, template class UREF> + requires std::is_base_of_v && + std::is_base_of_v +struct std::basic_common_reference { + using type = const EnsureCommonReference&; +}; + +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); // int is not a comparison category type + +static_assert(std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); // int is not a comparison category type + +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); + +struct A { + bool operator==(const A&) const; + bool operator<(const A&) const; + bool operator<=(const A&) const; + bool operator>(const A&) const; + bool operator>=(const A&) const; +}; +static_assert(std::equality_comparable); +static_assert(std::totally_ordered); +static_assert(!std::three_way_comparable_with); // A has no <=> +static_assert(!std::three_way_comparable_with); + +template +struct B : EnsureCommonReference { + bool operator==(const B&) const; + bool operator<(const B&) const; + bool operator<=(const B&) const; + bool operator>(const B&) const; + bool operator>=(const B&) const; + + template requires (N == 1) + std::strong_ordering operator<=>(const B&) const; + template requires (N == 1) + bool operator==(const B&) const; +}; +static_assert(std::is_same_v&, const B<2>&>, const EnsureCommonReference&>); +static_assert(std::common_reference_with&, const B<2>&>); + +static_assert(std::three_way_comparable>); +static_assert(!std::three_way_comparable>); // B2 has no <=> +static_assert(std::three_way_comparable_with, B<1>>); +static_assert(std::equality_comparable_with, B<2>>); +static_assert(std::totally_ordered_with, B<2>>); +static_assert(!std::three_way_comparable_with, B<2>>); // B2 has no <=> + +template +struct C : EnsureCommonReference { + std::strong_ordering operator<=>(const C&) const; + + template requires (N != M) + std::weak_ordering operator<=>(const C&) const; + + template + bool operator==(const C&) const; +}; +static_assert(std::three_way_comparable, std::strong_ordering>); +static_assert(std::three_way_comparable, std::strong_ordering>); +static_assert(std::three_way_comparable, C<2>>, std::strong_ordering>); +static_assert(!std::three_way_comparable_with, C<2>, std::strong_ordering>); +static_assert(std::three_way_comparable_with, C<2>, std::weak_ordering>); +static_assert(std::three_way_comparable_with, C<2>, std::partial_ordering>); +static_assert(std::three_way_comparable_with, C<2>, void>); +static_assert(!std::three_way_comparable_with, C<2>, int>); // int is not a comparison category type + +struct D { + bool operator==(const D&) const; + std::strong_ordering operator<=>(const D&) const; +}; +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); + +struct E { + bool operator==(const E&) const; + std::weak_ordering operator<=>(const E&) const; +}; +static_assert(std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); + +struct F { + bool operator==(const F&) const; + std::partial_ordering operator<=>(const F&) const; +}; +static_assert(std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); + +struct G { + bool operator==(const G&) const; + int operator<=>(const G&) const; +}; +static_assert(!std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); +static_assert(std::three_way_comparable_with); +static_assert(!std::three_way_comparable_with); diff --git a/libcxx/test/std/library/description/conventions/type.descriptions/customization.point.object/cpo.pass.cpp b/libcxx/test/std/library/description/conventions/type.descriptions/customization.point.object/cpo.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/library/description/conventions/type.descriptions/customization.point.object/cpo.pass.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// [customization.point.object] +// [range.adaptor.object] "A range adaptor object is a customization point object..." + +#include +#include +#include +#include + +template +constexpr bool test(CPO& o, Args&&...) +{ + auto p = o; + using T = decltype(p); + + // The type of a customization point object, ignoring cv-qualifiers, shall model semiregular. + static_assert(std::semiregular); + + // All instances of a specific customization point object type shall be equal. + // (However, they need not support operator==, so there's nothing to test here.) + + // The type T of a customization point object, ignoring cv-qualifiers, shall model... + static_assert(std::invocable); + static_assert(std::invocable); + static_assert(std::invocable); + static_assert(std::invocable); + + return true; +} + +int main(int, char**) +{ + int a[10]; +// int arrays[10][10]; +// std::pair pairs[10]; + + // [iterator.cust] + static_assert(test(std::ranges::iter_move, a+0)); + static_assert(test(std::ranges::iter_swap, a+0, a+1)); + + // [cmp.alg] + static_assert(test(std::strong_order, 1, 2)); +// static_assert(test(std::weak_order, 1, 2)); +// static_assert(test(std::partial_order, 1, 2)); +// static_assert(test(std::compare_strong_order_fallback, 1, 2)); +// static_assert(test(std::compare_weak_order_fallback, 1, 2)); +// static_assert(test(std::compare_partial_order_fallback, 1, 2)); + + // [range.access] + static_assert(test(std::ranges::begin, a)); + static_assert(test(std::ranges::end, a)); + static_assert(test(std::ranges::cbegin, a)); + static_assert(test(std::ranges::cend, a)); +// static_assert(test(std::ranges::rbegin, a)); +// static_assert(test(std::ranges::rend, a)); +// static_assert(test(std::ranges::crbegin, a)); +// static_assert(test(std::ranges::crend, a)); + static_assert(test(std::ranges::size, a)); + static_assert(test(std::ranges::ssize, a)); + static_assert(test(std::ranges::empty, a)); + static_assert(test(std::ranges::data, a)); +// static_assert(test(std::ranges::cdata, a)); + + // [range.factories] + // views::empty is not a CPO +// static_assert(test(std::views::single, 4)); +// static_assert(test(std::views::iota, 1)); +// static_assert(test(std::views::iota, 1, 10)); + // ranges::istream_view is not a CPO + + // [range.adaptors] + static_assert(test(std::views::all, a)); +// static_assert(test(std::views::filter, a, [](int x){ return x < 10; })); +// static_assert(test(std::views::transform, a, [](int x){ return x + 1; })); +// static_assert(test(std::views::take, a, 10)); +// static_assert(test(std::views::take_while, a, [](int x){ return x < 10; })); +// static_assert(test(std::views::drop, a, 10)); +// static_assert(test(std::views::drop_while, a, [](int x){ return x < 10; })); +// static_assert(test(std::views::join, arrays)); +// static_assert(test(std::views::lazy_split, a, 4)); +// static_assert(test(std::views::split, a, 4)); +// static_assert(test(std::views::counted, a, 10)); +// static_assert(test(std::views::common, a)); +// static_assert(test(std::views::reverse, a)); +// static_assert(test(std::views::elements<0>, pairs)); + + return 0; +} 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; }