diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -244,7 +244,7 @@ "`3320 `__","``span::cbegin/cend``\ methods produce different results than ``std::[ranges::]cbegin/cend``\ ","Prague","|Complete|","" "`3321 `__","``uninitialized_construct_using_allocator``\ should use ``construct_at``\ ","Prague","","" "`3323 `__","``*has-tuple-element*``\ helper concept needs ``convertible_to``\ ","Prague","","","|ranges|" -"`3324 `__","Special-case ``std::strong/weak/partial_order``\ for pointers","Prague","","","|spaceship|" +"`3324 `__","Special-case ``std::strong/weak/partial_order``\ for pointers","Prague","|Complete|","14.0","|spaceship|" "`3325 `__","Constrain return type of transformation function for ``transform_view``\ ","Prague","","","|ranges|" "`3326 `__","``enable_view``\ has false positives","Prague","|In progress|","","|ranges|" "`3327 `__","Format alignment specifiers vs. text direction","Prague","|Nothing To Do|","","|format|" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -107,8 +107,11 @@ __compare/compare_three_way_result.h __compare/is_eq.h __compare/ordering.h + __compare/partial_order.h + __compare/strong_order.h __compare/synth_three_way.h __compare/three_way_comparable.h + __compare/weak_order.h __concepts/arithmetic.h __concepts/assignable.h __concepts/boolean_testable.h @@ -334,6 +337,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/partial_order.h b/libcxx/include/__compare/partial_order.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/partial_order.h @@ -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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___COMPARE_PARTIAL_ORDER +#define _LIBCPP___COMPARE_PARTIAL_ORDER + +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> +#include <__compare/weak_order.h> +#include <__config> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> +#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_CONCEPTS) + +// [cmp.alg] +namespace __partial_order { + struct __fn { + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Tp&& __t, _Up&& __u, __priority_tag<2>) + noexcept(noexcept(partial_ordering(partial_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))) + -> decltype( partial_ordering(partial_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))) + { return partial_ordering(partial_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) + noexcept(noexcept(partial_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))) + -> decltype( partial_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))) + { return partial_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) + noexcept(noexcept(partial_ordering(_VSTD::weak_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))) + -> decltype( partial_ordering(_VSTD::weak_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))) + { return partial_ordering(_VSTD::weak_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(__go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>()))) + -> decltype( __go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>())) + { return __go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>()); } + }; +} // namespace __partial_order + +inline namespace __cpo { + inline constexpr auto partial_order = __partial_order::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_PARTIAL_ORDER diff --git a/libcxx/include/__compare/strong_order.h b/libcxx/include/__compare/strong_order.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/strong_order.h @@ -0,0 +1,136 @@ +//===----------------------------------------------------------------------===// +// +// 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_STRONG_ORDER +#define _LIBCPP___COMPARE_STRONG_ORDER + +#include <__bit/bit_cast.h> +#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_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +// [cmp.alg] +namespace __strong_order { + struct __fn { + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Tp&& __t, _Up&& __u, __priority_tag<2>) + noexcept(noexcept(strong_ordering(strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))) + -> decltype( strong_ordering(strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))) + { return strong_ordering(strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); } + + template> + requires is_same_v<_Dp, decay_t<_Up>> && is_floating_point_v<_Dp> + _LIBCPP_HIDE_FROM_ABI static constexpr strong_ordering + __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) noexcept + { + if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int32_t)) { + int32_t __rx = _VSTD::bit_cast(__t); + int32_t __ry = _VSTD::bit_cast(__u); + __rx = (__rx < 0) ? (numeric_limits::min() - __rx - 1) : __rx; + __ry = (__ry < 0) ? (numeric_limits::min() - __ry - 1) : __ry; + return (__rx <=> __ry); + } else if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int64_t)) { + int64_t __rx = _VSTD::bit_cast(__t); + int64_t __ry = _VSTD::bit_cast(__u); + __rx = (__rx < 0) ? (numeric_limits::min() - __rx - 1) : __rx; + __ry = (__ry < 0) ? (numeric_limits::min() - __ry - 1) : __ry; + return (__rx <=> __ry); + } else if (__t < __u) { + return strong_ordering::less; + } else if (__t > __u) { + return strong_ordering::greater; + } else if (__t == __u) { + if constexpr (numeric_limits<_Dp>::radix == 2) { + return _VSTD::signbit(__u) <=> _VSTD::signbit(__t); + } else { + // This is bullet 3 of the IEEE754 algorithm, relevant + // only for decimal floating-point; + // see https://stackoverflow.com/questions/69068075/ + if (__t == 0 || _VSTD::isinf(__t)) { + return _VSTD::signbit(__u) <=> _VSTD::signbit(__t); + } else { + int __texp, __uexp; + (void)_VSTD::frexp(__t, &__texp); + (void)_VSTD::frexp(__u, &__uexp); + return (__t < 0) ? (__texp <=> __uexp) : (__uexp <=> __texp); + } + } + } else { + // They're unordered, so one of them must be a NAN. + // The order is -QNAN, -SNAN, numbers, +SNAN, +QNAN. + bool __t_is_nan = _VSTD::isnan(__t); + bool __u_is_nan = _VSTD::isnan(__u); + bool __t_is_negative = _VSTD::signbit(__t); + bool __u_is_negative = _VSTD::signbit(__u); + using _IntType = std::conditional_t< + sizeof(__t) == sizeof(int32_t), int32_t, std::conditional_t< + sizeof(__t) == sizeof(int64_t), int64_t, void> + >; + if constexpr (std::is_same_v<_IntType, void>) { + static_assert(sizeof(_Dp) == 0, "std::strong_order is unimplemented for this floating-point type"); + } else if (__t_is_nan && __u_is_nan) { + // Order by sign bit, then by "payload bits" (we'll just use bit_cast). + if (__t_is_negative != __u_is_negative) { + return (__u_is_negative <=> __t_is_negative); + } else { + return _VSTD::bit_cast<_IntType>(__t) <=> _VSTD::bit_cast<_IntType>(__u); + } + } else if (__t_is_nan) { + return __t_is_negative ? strong_ordering::less : strong_ordering::greater; + } else { + return __u_is_negative ? strong_ordering::greater : strong_ordering::less; + } + } + } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) + noexcept(noexcept(strong_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))) + -> decltype( strong_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))) + { return strong_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(__go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>()))) + -> decltype( __go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<2>())) + { return __go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<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_CONCEPTS) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___COMPARE_STRONG_ORDER diff --git a/libcxx/include/__compare/weak_order.h b/libcxx/include/__compare/weak_order.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__compare/weak_order.h @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// 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_WEAK_ORDER +#define _LIBCPP___COMPARE_WEAK_ORDER + +#include <__compare/compare_three_way.h> +#include <__compare/ordering.h> +#include <__compare/strong_order.h> +#include <__config> +#include <__utility/forward.h> +#include <__utility/priority_tag.h> +#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_CONCEPTS) + +// [cmp.alg] +namespace __weak_order { + struct __fn { + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Tp&& __t, _Up&& __u, __priority_tag<3>) + noexcept(noexcept(weak_ordering(weak_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))) + -> decltype( weak_ordering(weak_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))) + { return weak_ordering(weak_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); } + + template> + requires is_same_v<_Dp, decay_t<_Up>> && is_floating_point_v<_Dp> + _LIBCPP_HIDE_FROM_ABI static constexpr weak_ordering + __go(_Tp&& __t, _Up&& __u, __priority_tag<2>) noexcept + { + std::partial_ordering __po = (__t <=> __u); + if (__po == std::partial_ordering::less) { + return std::weak_ordering::less; + } else if (__po == std::partial_ordering::equivalent) { + return std::weak_ordering::equivalent; + } else if (__po == std::partial_ordering::greater) { + return std::weak_ordering::greater; + } else { + // Otherwise, at least one of them is a NaN. + bool __t_is_nan = _VSTD::isnan(__t); + bool __u_is_nan = _VSTD::isnan(__u); + bool __t_is_negative = _VSTD::signbit(__t); + bool __u_is_negative = _VSTD::signbit(__u); + if (__t_is_nan && __u_is_nan) { + return (__u_is_negative <=> __t_is_negative); + } else if (__t_is_nan) { + return __t_is_negative ? weak_ordering::less : weak_ordering::greater; + } else { + return __u_is_negative ? weak_ordering::greater : weak_ordering::less; + } + } + } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) + noexcept(noexcept(weak_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))) + -> decltype( weak_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))) + { return weak_ordering(compare_three_way()(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); } + + template + requires is_same_v, decay_t<_Up>> + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __go(_Tp&& __t, _Up&& __u, __priority_tag<0>) + noexcept(noexcept(weak_ordering(_VSTD::strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))) + -> decltype( weak_ordering(_VSTD::strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u)))) + { return weak_ordering(_VSTD::strong_order(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))); } + + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(__go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<3>()))) + -> decltype( __go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<3>())) + { return __go(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u), __priority_tag<3>()); } + }; +} // namespace __weak_order + +inline namespace __cpo { + inline constexpr auto weak_order = __weak_order::__fn{}; +} // namespace __cpo + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___COMPARE_WEAK_ORDER 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 __priority_tag : __priority_tag<_Ip - 1> {}; +template<> struct __priority_tag<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 @@ -140,25 +140,10 @@ #include <__compare/compare_three_way_result.h> #include <__compare/is_eq.h> #include <__compare/ordering.h> +#include <__compare/partial_order.h> +#include <__compare/strong_order.h> #include <__compare/three_way_comparable.h> +#include <__compare/weak_order.h> #include <__config> -#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -#pragma GCC system_header -#endif - -_LIBCPP_BEGIN_NAMESPACE_STD - -#if _LIBCPP_STD_VER > 17 - -// [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 - -_LIBCPP_END_NAMESPACE_STD - #endif // _LIBCPP_COMPARE diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -377,8 +377,11 @@ 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" } + module partial_order { private header "__compare/partial_order.h" } + module strong_order { private header "__compare/strong_order.h" } module synth_three_way { private header "__compare/synth_three_way.h" } module three_way_comparable { private header "__compare/three_way_comparable.h" } + module weak_order { private header "__compare/weak_order.h" } } } module complex { @@ -883,6 +886,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 @@ -227,6 +227,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/partial_order.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/partial_order.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/partial_order.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/partial_order.h'}} +#include <__compare/partial_order.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/compare/strong_order.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/strong_order.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/strong_order.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/strong_order.h'}} +#include <__compare/strong_order.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/compare/weak_order.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/weak_order.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/weak_order.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/weak_order.h'}} +#include <__compare/weak_order.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,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: '__utility/priority_tag.h'}} +#include <__utility/priority_tag.h> diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/cmp/cmp.alg/partial_order.pass.cpp @@ -0,0 +1,255 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template constexpr partial_ordering partial_order(const T& a, const T& b); + +#include + +#include +#include +#include // std::size +#include +#include +#include + +#include "test_macros.h" + +template +constexpr auto has_partial_order(T&& t, U&& u) + -> decltype(std::partial_order(static_cast(t), static_cast(u)), true) +{ + return true; +} + +constexpr bool has_partial_order(...) { + return false; +} + +namespace N11 { + struct A {}; + struct B {}; + std::strong_ordering partial_order(const A&, const A&) { return std::strong_ordering::less; } + std::strong_ordering partial_order(const A&, const B&); +} + +void test_1_1() +{ + // If the decayed types of E and F differ, partial_order(E, F) is ill-formed. + + static_assert( has_partial_order(1, 2)); + static_assert(!has_partial_order(1, (short)2)); + static_assert(!has_partial_order(1, 2.0)); + static_assert(!has_partial_order(1.0f, 2.0)); + + static_assert( has_partial_order((int*)nullptr, (int*)nullptr)); + static_assert(!has_partial_order((int*)nullptr, (const int*)nullptr)); + static_assert(!has_partial_order((const int*)nullptr, (int*)nullptr)); + static_assert( has_partial_order((const int*)nullptr, (const int*)nullptr)); + + N11::A a; + N11::B b; + static_assert( has_partial_order(a, a)); + static_assert(!has_partial_order(a, b)); +} + +namespace N12 { + struct A {}; + std::strong_ordering partial_order(A&, A&&) { return std::strong_ordering::less; } + std::weak_ordering partial_order(A&&, A&&) { return std::weak_ordering::equivalent; } + std::strong_ordering partial_order(const A&, const A&); + + struct B { + friend int partial_order(B, B); + }; + + struct PartialOrder { + explicit operator std::partial_ordering() const { return std::partial_ordering::less; } + }; + struct C { + bool touched = false; + friend PartialOrder partial_order(C& lhs, C&) { lhs.touched = true; return PartialOrder(); } + }; +} + +void test_1_2() +{ + // Otherwise, partial_ordering(partial_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::partial_order. + + // Test that partial_order does not const-qualify the forwarded arguments. + N12::A a; + assert(std::partial_order(a, std::move(a)) == std::partial_ordering::less); + assert(std::partial_order(std::move(a), std::move(a)) == std::partial_ordering::equivalent); + + // The type of partial_order(e,f) must be explicitly convertible to partial_ordering. + N12::B b; + static_assert(!has_partial_order(b, b)); + + N12::C c1, c2; + ASSERT_SAME_TYPE(decltype(std::partial_order(c1, c2)), std::partial_ordering); + assert(std::partial_order(c1, c2) == std::partial_ordering::less); + assert(c1.touched); + assert(!c2.touched); +} + +namespace N13 { + // Compare to N12::A. + struct A {}; + bool operator==(const A&, const A&); + constexpr std::partial_ordering operator<=>(A&, A&&) { return std::partial_ordering::less; } + constexpr std::partial_ordering operator<=>(A&&, A&&) { return std::partial_ordering::equivalent; } + std::partial_ordering operator<=>(const A&, const A&); + static_assert(std::three_way_comparable); + + struct B { + std::partial_ordering operator<=>(const B&) const; // lacks operator== + }; + static_assert(!std::three_way_comparable); + + struct C { + bool *touched; + bool operator==(const C&) const; + constexpr std::partial_ordering operator<=>(const C& rhs) const { + *rhs.touched = true; + return std::partial_ordering::equivalent; + } + }; + static_assert(std::three_way_comparable); +} + +constexpr bool test_1_3() +{ + // Otherwise, partial_ordering(compare_three_way()(E, F)) if it is a well-formed expression. + + // Test neither partial_order nor compare_three_way const-qualify the forwarded arguments. + N13::A a; + assert(std::partial_order(a, std::move(a)) == std::partial_ordering::less); + assert(std::partial_order(std::move(a), std::move(a)) == std::partial_ordering::equivalent); + + N13::B b; + static_assert(!has_partial_order(b, b)); + + // Test that the arguments are passed to <=> in the correct order. + bool c1_touched = false; + bool c2_touched = false; + N13::C c1 = {&c1_touched}; + N13::C c2 = {&c2_touched}; + assert(std::partial_order(c1, c2) == std::partial_ordering::equivalent); + assert(!c1_touched); + assert(c2_touched); + + // For partial_order, this bullet point takes care of floating-point types; + // they receive their natural partial order. + { + using F = float; + F nan = std::numeric_limits::quiet_NaN(); + assert(std::partial_order(F(1), F(2)) == std::partial_ordering::less); + assert(std::partial_order(F(0), -F(0)) == std::partial_ordering::equivalent); +#ifndef TEST_COMPILER_GCC // GCC can't compare NaN to non-NaN in a constant-expression + assert(std::partial_order(nan, F(1)) == std::partial_ordering::unordered); +#endif + assert(std::partial_order(nan, nan) == std::partial_ordering::unordered); + } + { + using F = double; + F nan = std::numeric_limits::quiet_NaN(); + assert(std::partial_order(F(1), F(2)) == std::partial_ordering::less); + assert(std::partial_order(F(0), -F(0)) == std::partial_ordering::equivalent); +#ifndef TEST_COMPILER_GCC + assert(std::partial_order(nan, F(1)) == std::partial_ordering::unordered); +#endif + assert(std::partial_order(nan, nan) == std::partial_ordering::unordered); + } + { + using F = long double; + F nan = std::numeric_limits::quiet_NaN(); + assert(std::partial_order(F(1), F(2)) == std::partial_ordering::less); + assert(std::partial_order(F(0), -F(0)) == std::partial_ordering::equivalent); +#ifndef TEST_COMPILER_GCC + assert(std::partial_order(nan, F(1)) == std::partial_ordering::unordered); +#endif + assert(std::partial_order(nan, nan) == std::partial_ordering::unordered); + } + + return true; +} + +namespace N14 { + struct A {}; + constexpr std::strong_ordering weak_order(A&, A&&) { return std::strong_ordering::less; } + constexpr std::strong_ordering weak_order(A&&, A&&) { return std::strong_ordering::equal; } + std::strong_ordering weak_order(const A&, const A&); + + struct B { + friend std::partial_ordering weak_order(B, B); + }; + + struct StrongOrder { + operator std::strong_ordering() const { return std::strong_ordering::less; } + }; + struct C { + friend StrongOrder weak_order(C& lhs, C&); + }; + + struct WeakOrder { + constexpr explicit operator std::weak_ordering() const { return std::weak_ordering::less; } + operator std::partial_ordering() const = delete; + }; + struct D { + bool touched = false; + friend constexpr WeakOrder weak_order(D& lhs, D&) { lhs.touched = true; return WeakOrder(); } + }; +} + +constexpr bool test_1_4() +{ + // Otherwise, partial_ordering(weak_order(E, F)) [that is, std::weak_order] + // if it is a well-formed expression. + + // Test that partial_order and weak_order do not const-qualify the forwarded arguments. + N14::A a; + assert(std::partial_order(a, std::move(a)) == std::partial_ordering::less); + assert(std::partial_order(std::move(a), std::move(a)) == std::partial_ordering::equivalent); + + // The type of ADL weak_order(e,f) must be explicitly convertible to weak_ordering + // (not just to partial_ordering), or else std::weak_order(e,f) won't exist. + N14::B b; + static_assert(!has_partial_order(b, b)); + + // The type of ADL weak_order(e,f) must be explicitly convertible to weak_ordering + // (not just to strong_ordering), or else std::weak_order(e,f) won't exist. + N14::C c; + static_assert(!has_partial_order(c, c)); + + N14::D d1, d2; + ASSERT_SAME_TYPE(decltype(std::partial_order(d1, d2)), std::partial_ordering); + assert(std::partial_order(d1, d2) == std::partial_ordering::less); + assert(d1.touched); + assert(!d2.touched); + + return true; +} + +int main(int, char**) +{ + test_1_1(); + test_1_2(); + test_1_3(); + test_1_4(); + + static_assert(test_1_3()); + static_assert(test_1_4()); + + return 0; +} 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,467 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template constexpr strong_ordering strong_order(const T& a, const T& b); + +#include + +#include +#include +#include // std::size +#include +#include +#include + +#include "test_macros.h" + +#if defined(__i386__) + #define TEST_BUGGY_SIGNALING_NAN +#endif + +template +constexpr auto has_strong_order(T&& t, U&& u) + -> decltype(std::strong_order(static_cast(t), static_cast(u)), true) +{ + return true; +} + +constexpr bool has_strong_order(...) { + return false; +} + +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 StrongOrder { + explicit operator std::strong_ordering() const { return std::strong_ordering::less; } + }; + struct C { + bool touched = false; + friend StrongOrder strong_order(C& lhs, C&) { lhs.touched = true; return StrongOrder(); } + }; +} + +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_ordering. + 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 +constexpr bool 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); + + ASSERT_SAME_TYPE(decltype(std::strong_order(F(0), F(0))), std::strong_ordering); + + F v[] = { + -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(), + }; + + static_assert(std::size(v) == 14); + + // Sanity-check that array 'v' is indeed in the right order. + for (int i=0; i < 14; ++i) { + for (int j=0; j < 14; ++j) { + auto naturalOrder = (v[i] <=> v[j]); + if (v[i] == 0 && v[j] == 0) { + assert(naturalOrder == std::partial_ordering::equivalent); + } else { + assert(naturalOrder == std::partial_ordering::unordered || naturalOrder == (i <=> j)); + } + } + } + + assert(std::strong_order(v[0], v[0]) == std::strong_ordering::equal); + assert(std::strong_order(v[0], v[1]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[2]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[3]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[4]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[5]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[0], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[1], v[1]) == std::strong_ordering::equal); + assert(std::strong_order(v[1], v[2]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[3]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[4]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[5]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[1], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[2], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[2], v[2]) == std::strong_ordering::equal); + assert(std::strong_order(v[2], v[3]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[4]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[5]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[2], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[3], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[3], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[3], v[3]) == std::strong_ordering::equal); + assert(std::strong_order(v[3], v[4]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[5]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[3], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[4], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[4], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[4], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[4], v[4]) == std::strong_ordering::equal); + assert(std::strong_order(v[4], v[5]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[4], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[5], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[5], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[5], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[5], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[5], v[5]) == std::strong_ordering::equal); + assert(std::strong_order(v[5], v[6]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[5], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[6], v[6]) == std::strong_ordering::equal); + assert(std::strong_order(v[6], v[7]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[6], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[7], v[7]) == std::strong_ordering::equal); + assert(std::strong_order(v[7], v[8]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[7], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[8], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[8], v[8]) == std::strong_ordering::equal); + assert(std::strong_order(v[8], v[9]) == std::strong_ordering::less); + assert(std::strong_order(v[8], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[8], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[8], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[8], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[9], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[8]) == std::strong_ordering::greater); + assert(std::strong_order(v[9], v[9]) == std::strong_ordering::equal); + assert(std::strong_order(v[9], v[10]) == std::strong_ordering::less); + assert(std::strong_order(v[9], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[9], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[9], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[10], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[8]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[9]) == std::strong_ordering::greater); + assert(std::strong_order(v[10], v[10]) == std::strong_ordering::equal); + assert(std::strong_order(v[10], v[11]) == std::strong_ordering::less); + assert(std::strong_order(v[10], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[10], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[11], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[8]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[9]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[10]) == std::strong_ordering::greater); + assert(std::strong_order(v[11], v[11]) == std::strong_ordering::equal); + assert(std::strong_order(v[11], v[12]) == std::strong_ordering::less); + assert(std::strong_order(v[11], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[12], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[8]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[9]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[10]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[11]) == std::strong_ordering::greater); + assert(std::strong_order(v[12], v[12]) == std::strong_ordering::equal); + assert(std::strong_order(v[12], v[13]) == std::strong_ordering::less); + assert(std::strong_order(v[13], v[0]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[1]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[2]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[3]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[4]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[5]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[6]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[7]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[8]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[9]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[10]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[11]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[12]) == std::strong_ordering::greater); + assert(std::strong_order(v[13], v[13]) == std::strong_ordering::equal); + + + // There's no way to produce a specifically positive or negative NAN + // at compile-time, so the NAN-related tests must be runtime-only. + // Also, x86-32 (x87 floating point) cannot handle signaling NANs; + // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57484 for context. + + if (!std::is_constant_evaluated()) { + F nq = _VSTD::copysign(std::numeric_limits::quiet_NaN(), F(-1)); + F ns = _VSTD::copysign(std::numeric_limits::signaling_NaN(), F(-1)); + F ps = _VSTD::copysign(std::numeric_limits::signaling_NaN(), F(+1)); + F pq = _VSTD::copysign(std::numeric_limits::quiet_NaN(), F(+1)); + + assert(std::strong_order(nq, nq) == std::strong_ordering::equal); +#ifndef TEST_BUGGY_SIGNALING_NAN + assert(std::strong_order(nq, ns) == std::strong_ordering::less); +#endif + for (int i=0; i < 14; ++i) { + assert(std::strong_order(nq, v[i]) == std::strong_ordering::less); + } + assert(std::strong_order(nq, ps) == std::strong_ordering::less); + assert(std::strong_order(nq, pq) == std::strong_ordering::less); + +#ifndef TEST_BUGGY_SIGNALING_NAN + assert(std::strong_order(ns, nq) == std::strong_ordering::greater); +#endif + assert(std::strong_order(ns, ns) == std::strong_ordering::equal); + for (int i=0; i < 14; ++i) { + assert(std::strong_order(ns, v[i]) == std::strong_ordering::less); + } + assert(std::strong_order(ns, ps) == std::strong_ordering::less); + assert(std::strong_order(ns, pq) == std::strong_ordering::less); + + assert(std::strong_order(ps, nq) == std::strong_ordering::greater); + assert(std::strong_order(ps, ns) == std::strong_ordering::greater); + for (int i=0; i < 14; ++i) { + assert(std::strong_order(ps, v[i]) == std::strong_ordering::greater); + } + assert(std::strong_order(ps, ps) == std::strong_ordering::equal); +#ifndef TEST_BUGGY_SIGNALING_NAN + assert(std::strong_order(ps, pq) == std::strong_ordering::less); +#endif + + assert(std::strong_order(pq, nq) == std::strong_ordering::greater); + assert(std::strong_order(pq, ns) == std::strong_ordering::greater); + for (int i=0; i < 14; ++i) { + assert(std::strong_order(pq, v[i]) == std::strong_ordering::greater); + } +#ifndef TEST_BUGGY_SIGNALING_NAN + assert(std::strong_order(pq, ps) == std::strong_ordering::greater); +#endif + assert(std::strong_order(pq, pq) == std::strong_ordering::equal); + } + + return true; +} + +namespace N14 { + // Compare to N12::A. + struct A {}; + bool operator==(const A&, const A&); + constexpr std::strong_ordering operator<=>(A&, A&&) { return std::strong_ordering::less; } + constexpr 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 { + bool *touched; + bool operator==(const C&) const; + constexpr 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)); + + // Test that the arguments are passed to <=> in the correct order. + bool c1_touched = false; + bool c2_touched = false; + N14::C c1 = {&c1_touched}; + N14::C c2 = {&c2_touched}; + 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(); // UNIMPLEMENTED + test_1_4(); + + static_assert(test_1_3()); + static_assert(test_1_3()); + // static_assert(test_1_3()); // UNIMPLEMENTED + static_assert(test_1_4()); + + return 0; +} diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/strong_order_long_double.verify.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/strong_order_long_double.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/cmp/cmp.alg/strong_order_long_double.verify.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// The following platforms have sizeof(long double) == sizeof(double), so this test doesn't apply to them. +// UNSUPPORTED: target={{arm64|armv8|armv7|powerpc|powerpc64}}-{{.+}} +// UNSUPPORTED: target=x86_64-pc-windows-{{.+}} + +// + +// template constexpr strong_ordering strong_order(const T& a, const T& b); + +// libc++ does not support strong_order(long double, long double) quite yet. +// This test verifies the error message we give for that case. +// TODO: remove this test once long double is properly supported. + +#include + +#include "test_macros.h" + +void f() { + long double ld = 3.14; + (void)std::strong_order(ld, ld); // expected-error@*:* {{std::strong_order is unimplemented for this floating-point type}} +} diff --git a/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp b/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/language.support/cmp/cmp.alg/weak_order.pass.cpp @@ -0,0 +1,514 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template constexpr weak_ordering weak_order(const T& a, const T& b); + +#include + +#include +#include +#include // std::size +#include +#include +#include + +#include "test_macros.h" + +template +constexpr auto has_weak_order(T&& t, U&& u) + -> decltype(std::weak_order(static_cast(t), static_cast(u)), true) +{ + return true; +} + +constexpr bool has_weak_order(...) { + return false; +} + +namespace N11 { + struct A {}; + struct B {}; + std::strong_ordering weak_order(const A&, const A&) { return std::strong_ordering::less; } + std::strong_ordering weak_order(const A&, const B&); +} + +void test_1_1() +{ + // If the decayed types of E and F differ, weak_order(E, F) is ill-formed. + + static_assert( has_weak_order(1, 2)); + static_assert(!has_weak_order(1, (short)2)); + static_assert(!has_weak_order(1, 2.0)); + static_assert(!has_weak_order(1.0f, 2.0)); + + static_assert( has_weak_order((int*)nullptr, (int*)nullptr)); + static_assert(!has_weak_order((int*)nullptr, (const int*)nullptr)); + static_assert(!has_weak_order((const int*)nullptr, (int*)nullptr)); + static_assert( has_weak_order((const int*)nullptr, (const int*)nullptr)); + + N11::A a; + N11::B b; + static_assert( has_weak_order(a, a)); + static_assert(!has_weak_order(a, b)); +} + +namespace N12 { + struct A {}; + std::strong_ordering weak_order(A&, A&&) { return std::strong_ordering::less; } + std::strong_ordering weak_order(A&&, A&&) { return std::strong_ordering::equal; } + std::strong_ordering weak_order(const A&, const A&); + + struct B { + friend std::partial_ordering weak_order(B&, B&); + }; + + struct WeakOrder { + explicit operator std::weak_ordering() const { return std::weak_ordering::less; } + }; + struct C { + bool touched = false; + friend WeakOrder weak_order(C& lhs, C&) { lhs.touched = true; return WeakOrder(); } + }; +} + +void test_1_2() +{ + // Otherwise, weak_ordering(weak_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::weak_order. + + // Test that weak_order does not const-qualify the forwarded arguments. + N12::A a; + assert(std::weak_order(a, std::move(a)) == std::weak_ordering::less); + assert(std::weak_order(std::move(a), std::move(a)) == std::weak_ordering::equivalent); + + // The type of weak_order(e,f) must be explicitly convertible to weak_ordering. + N12::B b; + static_assert(!has_weak_order(b, b)); + + N12::C c1, c2; + ASSERT_SAME_TYPE(decltype(std::weak_order(c1, c2)), std::weak_ordering); + assert(std::weak_order(c1, c2) == std::weak_ordering::less); + assert(c1.touched); + assert(!c2.touched); +} + +template +constexpr bool test_1_3() +{ + // Otherwise, if the decayed type T of E is a floating-point type, + // yields a value of type weak_ordering that is consistent with + // the ordering observed by T's comparison operators and strong_order, + // and if numeric_limits::is_iec559 is true, is additionally consistent with + // the following equivalence classes... + + // std::numeric_limits::is_iec559 is usually true. + // It is false for F=long double on AIX; but this test is still expected + // to pass (e.g. std::weak_order(+0, -0) == weak_ordering::equivalent, + // even on AIX). + + ASSERT_SAME_TYPE(decltype(std::weak_order(F(0), F(0))), std::weak_ordering); + + F v[] = { + -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(), + }; + + static_assert(std::size(v) == 14); + + // Sanity-check that array 'v' is indeed in the right order. + for (int i=0; i < 14; ++i) { + for (int j=0; j < 14; ++j) { + auto naturalOrder = (v[i] <=> v[j]); + if (v[i] == 0 && v[j] == 0) { + assert(naturalOrder == std::partial_ordering::equivalent); + } else { + assert(naturalOrder == std::partial_ordering::unordered || naturalOrder == (i <=> j)); + } + } + } + + assert(std::weak_order(v[0], v[0]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[0], v[1]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[2]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[3]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[4]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[5]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[6]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[7]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[8]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[9]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[10]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[0], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[1], v[1]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[1], v[2]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[3]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[4]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[5]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[6]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[7]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[8]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[9]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[10]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[1], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[2], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[2], v[2]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[2], v[3]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[4]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[5]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[6]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[7]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[8]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[9]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[10]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[2], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[3], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[3], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[3], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[3], v[3]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[3], v[4]) == std::weak_ordering::less); + assert(std::weak_order(v[3], v[5]) == std::weak_ordering::less); + assert(std::weak_order(v[3], v[6]) == std::weak_ordering::less); + assert(std::weak_order(v[3], v[7]) == std::weak_ordering::less); + assert(std::weak_order(v[3], v[8]) == std::weak_ordering::less); + assert(std::weak_order(v[3], v[9]) == std::weak_ordering::less); + assert(std::weak_order(v[3], v[10]) == std::weak_ordering::less); + assert(std::weak_order(v[3], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[3], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[3], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[4], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[4], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[4], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[4], v[3]) == std::weak_ordering::greater); + assert(std::weak_order(v[4], v[4]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[4], v[5]) == std::weak_ordering::less); + assert(std::weak_order(v[4], v[6]) == std::weak_ordering::less); + assert(std::weak_order(v[4], v[7]) == std::weak_ordering::less); + assert(std::weak_order(v[4], v[8]) == std::weak_ordering::less); + assert(std::weak_order(v[4], v[9]) == std::weak_ordering::less); + assert(std::weak_order(v[4], v[10]) == std::weak_ordering::less); + assert(std::weak_order(v[4], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[4], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[4], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[5], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[5], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[5], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[5], v[3]) == std::weak_ordering::greater); + assert(std::weak_order(v[5], v[4]) == std::weak_ordering::greater); + assert(std::weak_order(v[5], v[5]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[5], v[6]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[5], v[7]) == std::weak_ordering::less); + assert(std::weak_order(v[5], v[8]) == std::weak_ordering::less); + assert(std::weak_order(v[5], v[9]) == std::weak_ordering::less); + assert(std::weak_order(v[5], v[10]) == std::weak_ordering::less); + assert(std::weak_order(v[5], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[5], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[5], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[6], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[6], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[6], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[6], v[3]) == std::weak_ordering::greater); + assert(std::weak_order(v[6], v[4]) == std::weak_ordering::greater); + assert(std::weak_order(v[6], v[5]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[6], v[6]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[6], v[7]) == std::weak_ordering::less); + assert(std::weak_order(v[6], v[8]) == std::weak_ordering::less); + assert(std::weak_order(v[6], v[9]) == std::weak_ordering::less); + assert(std::weak_order(v[6], v[10]) == std::weak_ordering::less); + assert(std::weak_order(v[6], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[6], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[6], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[7], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[7], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[7], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[7], v[3]) == std::weak_ordering::greater); + assert(std::weak_order(v[7], v[4]) == std::weak_ordering::greater); + assert(std::weak_order(v[7], v[5]) == std::weak_ordering::greater); + assert(std::weak_order(v[7], v[6]) == std::weak_ordering::greater); + assert(std::weak_order(v[7], v[7]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[7], v[8]) == std::weak_ordering::less); + assert(std::weak_order(v[7], v[9]) == std::weak_ordering::less); + assert(std::weak_order(v[7], v[10]) == std::weak_ordering::less); + assert(std::weak_order(v[7], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[7], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[7], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[8], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[8], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[8], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[8], v[3]) == std::weak_ordering::greater); + assert(std::weak_order(v[8], v[4]) == std::weak_ordering::greater); + assert(std::weak_order(v[8], v[5]) == std::weak_ordering::greater); + assert(std::weak_order(v[8], v[6]) == std::weak_ordering::greater); + assert(std::weak_order(v[8], v[7]) == std::weak_ordering::greater); + assert(std::weak_order(v[8], v[8]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[8], v[9]) == std::weak_ordering::less); + assert(std::weak_order(v[8], v[10]) == std::weak_ordering::less); + assert(std::weak_order(v[8], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[8], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[8], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[9], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[9], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[9], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[9], v[3]) == std::weak_ordering::greater); + assert(std::weak_order(v[9], v[4]) == std::weak_ordering::greater); + assert(std::weak_order(v[9], v[5]) == std::weak_ordering::greater); + assert(std::weak_order(v[9], v[6]) == std::weak_ordering::greater); + assert(std::weak_order(v[9], v[7]) == std::weak_ordering::greater); + assert(std::weak_order(v[9], v[8]) == std::weak_ordering::greater); + assert(std::weak_order(v[9], v[9]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[9], v[10]) == std::weak_ordering::less); + assert(std::weak_order(v[9], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[9], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[9], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[10], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[10], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[10], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[10], v[3]) == std::weak_ordering::greater); + assert(std::weak_order(v[10], v[4]) == std::weak_ordering::greater); + assert(std::weak_order(v[10], v[5]) == std::weak_ordering::greater); + assert(std::weak_order(v[10], v[6]) == std::weak_ordering::greater); + assert(std::weak_order(v[10], v[7]) == std::weak_ordering::greater); + assert(std::weak_order(v[10], v[8]) == std::weak_ordering::greater); + assert(std::weak_order(v[10], v[9]) == std::weak_ordering::greater); + assert(std::weak_order(v[10], v[10]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[10], v[11]) == std::weak_ordering::less); + assert(std::weak_order(v[10], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[10], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[11], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[3]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[4]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[5]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[6]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[7]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[8]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[9]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[10]) == std::weak_ordering::greater); + assert(std::weak_order(v[11], v[11]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[11], v[12]) == std::weak_ordering::less); + assert(std::weak_order(v[11], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[12], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[3]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[4]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[5]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[6]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[7]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[8]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[9]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[10]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[11]) == std::weak_ordering::greater); + assert(std::weak_order(v[12], v[12]) == std::weak_ordering::equivalent); + assert(std::weak_order(v[12], v[13]) == std::weak_ordering::less); + assert(std::weak_order(v[13], v[0]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[1]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[2]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[3]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[4]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[5]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[6]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[7]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[8]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[9]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[10]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[11]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[12]) == std::weak_ordering::greater); + assert(std::weak_order(v[13], v[13]) == std::weak_ordering::equivalent); + + + // There's no way to produce a specifically positive or negative NAN + // at compile-time, so the NAN-related tests must be runtime-only. + + if (!std::is_constant_evaluated()) { + F nq = _VSTD::copysign(std::numeric_limits::quiet_NaN(), F(-1)); + F ns = _VSTD::copysign(std::numeric_limits::signaling_NaN(), F(-1)); + F ps = _VSTD::copysign(std::numeric_limits::signaling_NaN(), F(+1)); + F pq = _VSTD::copysign(std::numeric_limits::quiet_NaN(), F(+1)); + + assert(std::weak_order(nq, nq) == std::weak_ordering::equivalent); + assert(std::weak_order(nq, ns) == std::weak_ordering::equivalent); + for (int i=0; i < 14; ++i) { + assert(std::weak_order(nq, v[i]) == std::weak_ordering::less); + } + assert(std::weak_order(nq, ps) == std::weak_ordering::less); + assert(std::weak_order(nq, pq) == std::weak_ordering::less); + + assert(std::weak_order(ns, nq) == std::weak_ordering::equivalent); + assert(std::weak_order(ns, ns) == std::weak_ordering::equivalent); + for (int i=0; i < 14; ++i) { + assert(std::weak_order(ns, v[i]) == std::weak_ordering::less); + } + assert(std::weak_order(ns, ps) == std::weak_ordering::less); + assert(std::weak_order(ns, pq) == std::weak_ordering::less); + + assert(std::weak_order(ps, nq) == std::weak_ordering::greater); + assert(std::weak_order(ps, ns) == std::weak_ordering::greater); + for (int i=0; i < 14; ++i) { + assert(std::weak_order(ps, v[i]) == std::weak_ordering::greater); + } + assert(std::weak_order(ps, ps) == std::weak_ordering::equivalent); + assert(std::weak_order(ps, pq) == std::weak_ordering::equivalent); + + assert(std::weak_order(pq, nq) == std::weak_ordering::greater); + assert(std::weak_order(pq, ns) == std::weak_ordering::greater); + for (int i=0; i < 14; ++i) { + assert(std::weak_order(pq, v[i]) == std::weak_ordering::greater); + } + assert(std::weak_order(pq, ps) == std::weak_ordering::equivalent); + assert(std::weak_order(pq, pq) == std::weak_ordering::equivalent); + } + + return true; +} + +namespace N14 { + // Compare to N12::A. + struct A {}; + bool operator==(const A&, const A&); + constexpr std::weak_ordering operator<=>(A&, A&&) { return std::weak_ordering::less; } + constexpr std::weak_ordering operator<=>(A&&, A&&) { return std::weak_ordering::equivalent; } + std::weak_ordering operator<=>(const A&, const A&); + static_assert(std::three_way_comparable); + + struct B { + std::weak_ordering operator<=>(const B&) const; // lacks operator== + }; + static_assert(!std::three_way_comparable); + + struct C { + bool *touched; + bool operator==(const C&) const; + constexpr std::weak_ordering operator<=>(const C& rhs) const { + *rhs.touched = true; + return std::weak_ordering::equivalent; + } + }; + static_assert(std::three_way_comparable); +} + +constexpr bool test_1_4() +{ + // Otherwise, weak_ordering(compare_three_way()(E, F)) if it is a well-formed expression. + + // Test neither weak_order nor compare_three_way const-qualify the forwarded arguments. + N14::A a; + assert(std::weak_order(a, std::move(a)) == std::weak_ordering::less); + assert(std::weak_order(std::move(a), std::move(a)) == std::weak_ordering::equivalent); + + N14::B b; + static_assert(!has_weak_order(b, b)); + + // Test that the arguments are passed to <=> in the correct order. + bool c1_touched = false; + bool c2_touched = false; + N14::C c1 = {&c1_touched}; + N14::C c2 = {&c2_touched}; + assert(std::weak_order(c1, c2) == std::weak_ordering::equivalent); + assert(!c1_touched); + assert(c2_touched); + + return true; +} + +namespace N15 { + struct A {}; + constexpr std::strong_ordering strong_order(A&, A&&) { return std::strong_ordering::less; } + constexpr 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 WeakOrder { + operator std::weak_ordering() const { return std::weak_ordering::less; } + }; + struct C { + friend WeakOrder strong_order(C& lhs, C&); + }; + + struct StrongOrder { + constexpr explicit operator std::strong_ordering() const { return std::strong_ordering::less; } + operator std::weak_ordering() const = delete; + }; + struct D { + bool touched = false; + friend constexpr StrongOrder strong_order(D& lhs, D&) { lhs.touched = true; return StrongOrder(); } + }; +} + +constexpr bool test_1_5() +{ + // Otherwise, weak_ordering(strong_order(E, F)) [that is, std::strong_order] + // if it is a well-formed expression. + + // Test that weak_order and strong_order do not const-qualify the forwarded arguments. + N15::A a; + assert(std::weak_order(a, std::move(a)) == std::weak_ordering::less); + assert(std::weak_order(std::move(a), std::move(a)) == std::weak_ordering::equivalent); + + // The type of ADL strong_order(e,f) must be explicitly convertible to strong_ordering + // (not just to weak_ordering), or else std::strong_order(e,f) won't exist. + N15::B b; + static_assert(!has_weak_order(b, b)); + + // The type of ADL strong_order(e,f) must be explicitly convertible to strong_ordering + // (not just to weak_ordering), or else std::strong_order(e,f) won't exist. + N15::C c; + static_assert(!has_weak_order(c, c)); + + N15::D d1, d2; + ASSERT_SAME_TYPE(decltype(std::weak_order(d1, d2)), std::weak_ordering); + assert(std::weak_order(d1, d2) == std::weak_ordering::less); + assert(d1.touched); + assert(!d2.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(); + test_1_5(); + + static_assert(test_1_3()); + static_assert(test_1_3()); + static_assert(test_1_3()); + static_assert(test_1_4()); + static_assert(test_1_5()); + + return 0; +}