diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv --- a/libcxx/docs/Status/SpaceshipProjects.csv +++ b/libcxx/docs/Status/SpaceshipProjects.csv @@ -25,7 +25,7 @@ | nullopt",None,Kent Ross,|In Progress| "| `[variant.relops] `_ | `[variant.monostate.relops] `_","| `monostate `_ -| `variant `_",None,Kent Ross,|In Progress| +| `variant `_",None,Kent Ross,|Complete| | `[unique.ptr.special] `_,| `unique_ptr `_,[comparisons.three.way],Adrian Vogelsgesang,|Complete| | `[util.smartptr.shared.cmp] `_,| `shared_ptr `_,[comparisons.three.way],Adrian Vogelsgesang,|Complete| | `[type.index.members] `_,| `type_index `_,None,Adrian Vogelsgesang,|Complete| diff --git a/libcxx/include/__variant/monostate.h b/libcxx/include/__variant/monostate.h --- a/libcxx/include/__variant/monostate.h +++ b/libcxx/include/__variant/monostate.h @@ -10,6 +10,7 @@ #ifndef _LIBCPP___VARIANT_MONOSTATE_H #define _LIBCPP___VARIANT_MONOSTATE_H +#include <__compare/ordering.h> #include <__config> #include <__functional/hash.h> #include @@ -24,31 +25,34 @@ struct _LIBCPP_TEMPLATE_VIS monostate {}; -inline _LIBCPP_INLINE_VISIBILITY -constexpr bool operator<(monostate, monostate) noexcept { return false; } +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(monostate, monostate) noexcept { return true; } -inline _LIBCPP_INLINE_VISIBILITY -constexpr bool operator>(monostate, monostate) noexcept { return false; } +# if _LIBCPP_STD_VER > 17 -inline _LIBCPP_INLINE_VISIBILITY -constexpr bool operator<=(monostate, monostate) noexcept { return true; } +_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(monostate, monostate) noexcept { + return strong_ordering::equal; +} -inline _LIBCPP_INLINE_VISIBILITY -constexpr bool operator>=(monostate, monostate) noexcept { return true; } +# else // _LIBCPP_STD_VER > 17 -inline _LIBCPP_INLINE_VISIBILITY -constexpr bool operator==(monostate, monostate) noexcept { return true; } +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(monostate, monostate) noexcept { return false; } -inline _LIBCPP_INLINE_VISIBILITY -constexpr bool operator!=(monostate, monostate) noexcept { return false; } +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(monostate, monostate) noexcept { return false; } + +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(monostate, monostate) noexcept { return false; } + +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(monostate, monostate) noexcept { return true; } + +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(monostate, monostate) noexcept { return true; } + +# endif // _LIBCPP_STD_VER > 17 template <> struct _LIBCPP_TEMPLATE_VIS hash { using argument_type = monostate; using result_type = size_t; - inline _LIBCPP_INLINE_VISIBILITY - result_type operator()(const argument_type&) const _NOEXCEPT { + inline _LIBCPP_HIDE_FROM_ABI result_type operator()(const argument_type&) const _NOEXCEPT { return 66740831; // return a fundamentally attractive random value. } }; diff --git a/libcxx/include/variant b/libcxx/include/variant --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -165,6 +165,10 @@ template constexpr bool operator>=(const variant&, const variant&); + template + constexpr common_comparison_category_t...> + operator<=>(const variant&, const variant&); // since C++20 + // 20.7.6, visitation template constexpr see below visit(Visitor&&, Variants&&...); @@ -176,12 +180,13 @@ struct monostate; // 20.7.8, monostate relational operators - constexpr bool operator<(monostate, monostate) noexcept; - constexpr bool operator>(monostate, monostate) noexcept; - constexpr bool operator<=(monostate, monostate) noexcept; - constexpr bool operator>=(monostate, monostate) noexcept; constexpr bool operator==(monostate, monostate) noexcept; - constexpr bool operator!=(monostate, monostate) noexcept; + constexpr bool operator!=(monostate, monostate) noexcept; // until C++20 + constexpr bool operator<(monostate, monostate) noexcept; // until C++20 + constexpr bool operator>(monostate, monostate) noexcept; // until C++20 + constexpr bool operator<=(monostate, monostate) noexcept; // until C++20 + constexpr bool operator>=(monostate, monostate) noexcept; // until C++20 + constexpr strong_ordering operator<=>(monostate, monostate) noexcept; // since C++20 // 20.7.9, specialized algorithms template @@ -201,6 +206,9 @@ #include <__assert> // all public C++ headers provide the assertion handler #include <__availability> +#include <__compare/common_comparison_category.h> +#include <__compare/compare_three_way_result.h> +#include <__compare/three_way_comparable.h> #include <__config> #include <__functional/hash.h> #include <__functional/operations.h> @@ -261,7 +269,7 @@ }; _LIBCPP_NORETURN -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS void __throw_bad_variant_access() { #ifndef _LIBCPP_NO_EXCEPTIONS @@ -372,7 +380,7 @@ namespace __find_detail { template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr size_t __find_index() { constexpr bool __matches[] = {is_same_v<_Tp, _Types>...}; size_t __result = __not_found; @@ -417,7 +425,7 @@ ? _Trait::_TriviallyAvailable : _IsAvailable<_Tp>::value ? _Trait::_Available : _Trait::_Unavailable; -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr _Trait __common_trait(initializer_list<_Trait> __traits) { _Trait __result = _Trait::_TriviallyAvailable; for (_Trait __t : __traits) { @@ -456,13 +464,13 @@ struct __union { template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<0>) { return _VSTD::forward<_Vp>(__v).__head; } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<_Ip>) { return __get_alt(_VSTD::forward<_Vp>(__v).__tail, in_place_index<_Ip - 1>); } @@ -470,7 +478,7 @@ struct __base { template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto&& __get_alt(_Vp&& __v) { return __union::__get_alt(_VSTD::forward<_Vp>(__v).__data, in_place_index<_Ip>); @@ -479,7 +487,7 @@ struct __variant { template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto&& __get_alt(_Vp&& __v) { return __base::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v).__impl); } @@ -491,7 +499,7 @@ struct __base { template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { constexpr auto __fdiagonal = @@ -502,7 +510,7 @@ } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, _Vs&&... __vs) { constexpr auto __fmatrix = @@ -515,11 +523,11 @@ private: template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr const _Tp& __at(const _Tp& __elem) { return __elem; } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto&& __at(const __farray<_Tp, _Np>& __elems, size_t __index, _Indices... __indices) { return __at(__elems[__index], __indices...); @@ -533,7 +541,7 @@ } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto __make_farray(_Fs&&... __fs) { __std_visit_visitor_return_type_check<__uncvref_t<_Fs>...>(); using __result = __farray...>, sizeof...(_Fs)>; @@ -543,7 +551,7 @@ template struct __dispatcher { template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __dispatch(_Fp __f, _Vs... __vs) { return _VSTD::__invoke( static_cast<_Fp>(__f), @@ -552,26 +560,26 @@ }; template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto __make_dispatch(index_sequence<_Is...>) { return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>; } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto __make_fdiagonal_impl() { return __make_dispatch<_Fp, _Vs...>( index_sequence<((void)__type_identity<_Vs>{}, _Ip)...>{}); } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto __make_fdiagonal_impl(index_sequence<_Is...>) { return __base::__make_farray(__make_fdiagonal_impl<_Is, _Fp, _Vs...>()...); } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto __make_fdiagonal() { constexpr size_t _Np = __uncvref_t<_Vp>::__size(); static_assert(__all<(_Np == __uncvref_t<_Vs>::__size())...>::value); @@ -579,13 +587,13 @@ } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto __make_fmatrix_impl(index_sequence<_Is...> __is) { return __make_dispatch<_Fp, _Vs...>(__is); } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto __make_fmatrix_impl(index_sequence<_Is...>, index_sequence<_Js...>, _Ls... __ls) { @@ -594,7 +602,7 @@ } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto __make_fmatrix() { return __make_fmatrix_impl<_Fp, _Vs...>( index_sequence<>{}, make_index_sequence<__uncvref_t<_Vs>::__size()>{}...); @@ -603,7 +611,7 @@ struct __variant { template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { return __base::__visit_alt_at(__index, @@ -612,7 +620,7 @@ } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, _Vs&&... __vs) { return __base::__visit_alt( @@ -621,7 +629,7 @@ } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __visit_value_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { return __visit_alt_at( @@ -631,7 +639,7 @@ } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __visit_value(_Visitor&& __visitor, _Vs&&... __vs) { return __visit_alt( @@ -641,7 +649,7 @@ #if _LIBCPP_STD_VER > 17 template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr _Rp __visit_value(_Visitor&& __visitor, _Vs&&... __vs) { return __visit_alt( @@ -660,7 +668,7 @@ template struct __value_visitor { template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Alts&&... __alts) const { __std_visit_exhaustive_visitor_check< _Visitor, @@ -675,7 +683,7 @@ template struct __value_visitor_return_type { template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr _Rp operator()(_Alts&&... __alts) const { __std_visit_exhaustive_visitor_check< _Visitor, @@ -695,14 +703,14 @@ #endif template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto __make_value_visitor(_Visitor&& __visitor) { return __value_visitor<_Visitor>{_VSTD::forward<_Visitor>(__visitor)}; } #if _LIBCPP_STD_VER > 17 template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr auto __make_value_visitor(_Visitor&& __visitor) { return __value_visitor_return_type<_Rp, _Visitor>{_VSTD::forward<_Visitor>(__visitor)}; } @@ -716,7 +724,7 @@ using __value_type = _Tp; template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI explicit constexpr __alt(in_place_t, _Args&&... __args) : __value(_VSTD::forward<_Args>(__args)...) {} @@ -731,21 +739,21 @@ #define _LIBCPP_VARIANT_UNION(destructible_trait, destructor) \ template \ - union _LIBCPP_TEMPLATE_VIS __union { \ public: \ - inline _LIBCPP_INLINE_VISIBILITY \ + _LIBCPP_HIDE_FROM_ABI \ explicit constexpr __union(__valueless_t) noexcept : __dummy{} {} \ \ template \ - inline _LIBCPP_INLINE_VISIBILITY \ + _LIBCPP_HIDE_FROM_ABI \ explicit constexpr __union(in_place_index_t<0>, _Args&&... __args) \ : __head(in_place, _VSTD::forward<_Args>(__args)...) {} \ \ template \ - inline _LIBCPP_INLINE_VISIBILITY \ + _LIBCPP_HIDE_FROM_ABI \ explicit constexpr __union(in_place_index_t<_Ip>, _Args&&... __args) \ : __tail(in_place_index<_Ip - 1>, _VSTD::forward<_Args>(__args)...) {} \ \ @@ -776,41 +784,41 @@ public: using __index_t = __variant_index_t; - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI explicit constexpr __base(__valueless_t __tag) noexcept : __data(__tag), __index(__variant_npos<__index_t>) {} template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI explicit constexpr __base(in_place_index_t<_Ip>, _Args&&... __args) : __data(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...), __index(_Ip) {} - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr bool valueless_by_exception() const noexcept { return index() == variant_npos; } - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr size_t index() const noexcept { return __index == __variant_npos<__index_t> ? variant_npos : __index; } protected: - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr auto&& __as_base() & { return *this; } - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr auto&& __as_base() && { return _VSTD::move(*this); } - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr auto&& __as_base() const & { return *this; } - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr auto&& __as_base() const && { return _VSTD::move(*this); } - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static constexpr size_t __size() { return sizeof...(_Types); } __union<_DestructibleTrait, 0, _Types...> __data; @@ -842,7 +850,7 @@ __dtor& operator=(__dtor&&) = default; \ \ protected: \ - inline _LIBCPP_INLINE_VISIBILITY \ + inline _LIBCPP_HIDE_FROM_ABI \ destroy \ } @@ -883,7 +891,7 @@ protected: template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static _Tp& __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) { ::new ((void*)_VSTD::addressof(__a)) __alt<_Ip, _Tp>(in_place, _VSTD::forward<_Args>(__args)...); @@ -891,7 +899,7 @@ } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI static void __generic_construct(__ctor& __lhs, _Rhs&& __rhs) { __lhs.__destroy(); if (!__rhs.valueless_by_exception()) { @@ -954,7 +962,7 @@ #define _LIBCPP_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, \ copy_constructor) \ template \ - class _LIBCPP_TEMPLATE_VIS __copy_constructor<__traits<_Types...>, \ + class _LIBCPP_TEMPLATE_VIS __copy_constructor<__traits<_Types...>, \ copy_constructible_trait> \ : public __move_constructor<__traits<_Types...>> { \ using __base_type = __move_constructor<__traits<_Types...>>; \ @@ -996,7 +1004,7 @@ using __base_type::operator=; template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI auto& __emplace(_Args&&... __args) { this->__destroy(); auto& __res = this->__construct_alt(__access::__base::__get_alt<_Ip>(*this), @@ -1007,7 +1015,7 @@ protected: template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) { if (this->index() == _Ip) { __a.__value = _VSTD::forward<_Arg>(__arg); @@ -1028,7 +1036,7 @@ } template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI void __generic_assign(_That&& __that) { if (this->valueless_by_exception() && __that.valueless_by_exception()) { // do nothing. @@ -1053,7 +1061,7 @@ #define _LIBCPP_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, \ move_assignment) \ template \ - class _LIBCPP_TEMPLATE_VIS __move_assignment<__traits<_Types...>, \ + class _LIBCPP_TEMPLATE_VIS __move_assignment<__traits<_Types...>, \ move_assignable_trait> \ : public __assignment<__traits<_Types...>> { \ using __base_type = __assignment<__traits<_Types...>>; \ @@ -1094,7 +1102,7 @@ #define _LIBCPP_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, \ copy_assignment) \ template \ - class _LIBCPP_TEMPLATE_VIS __copy_assignment<__traits<_Types...>, \ + class _LIBCPP_TEMPLATE_VIS __copy_assignment<__traits<_Types...>, \ copy_assignable_trait> \ : public __move_assignment<__traits<_Types...>> { \ using __base_type = __move_assignment<__traits<_Types...>>; \ @@ -1140,13 +1148,13 @@ __impl& operator=(__impl&&) = default; template - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI void __assign(_Arg&& __arg) { this->__assign_alt(__access::__base::__get_alt<_Ip>(*this), _VSTD::forward<_Arg>(__arg)); } - inline _LIBCPP_INLINE_VISIBILITY + inline _LIBCPP_HIDE_FROM_ABI void __swap(__impl& __that) { if (this->valueless_by_exception() && __that.valueless_by_exception()) { // do nothing. @@ -1192,7 +1200,7 @@ } private: - inline _LIBCPP_INLINE_VISIBILITY + inline _LIBCPP_HIDE_FROM_ABI bool __move_nothrow() const { constexpr bool __results[] = {is_nothrow_move_constructible_v<_Types>...}; return this->valueless_by_exception() || __results[this->index()]; @@ -1298,7 +1306,7 @@ enable_if_t<__dependent_type, _Dummy>::value, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr variant() noexcept(is_nothrow_default_constructible_v<__first_type>) : __impl(in_place_index<0>) {} @@ -1314,7 +1322,7 @@ size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, enable_if_t, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr variant(_Arg&& __arg) noexcept( is_nothrow_constructible_v<_Tp, _Arg>) : __impl(in_place_index<_Ip>, _VSTD::forward<_Arg>(__arg)) {} @@ -1323,7 +1331,7 @@ class = enable_if_t<(_Ip < sizeof...(_Types)), int>, class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, enable_if_t, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI explicit constexpr variant( in_place_index_t<_Ip>, _Args&&... __args) noexcept(is_nothrow_constructible_v<_Tp, _Args...>) @@ -1337,7 +1345,7 @@ class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, enable_if_t&, _Args...>, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI explicit constexpr variant( in_place_index_t<_Ip>, initializer_list<_Up> __il, @@ -1351,7 +1359,7 @@ size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, enable_if_t, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI explicit constexpr variant(in_place_type_t<_Tp>, _Args&&... __args) noexcept( is_nothrow_constructible_v<_Tp, _Args...>) : __impl(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...) {} @@ -1364,7 +1372,7 @@ __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, enable_if_t&, _Args...>, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI explicit constexpr variant( in_place_type_t<_Tp>, initializer_list<_Up> __il, @@ -1385,7 +1393,7 @@ __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, enable_if_t && is_constructible_v<_Tp, _Arg>, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI variant& operator=(_Arg&& __arg) noexcept( is_nothrow_assignable_v<_Tp&, _Arg> && is_nothrow_constructible_v<_Tp, _Arg>) { @@ -1399,7 +1407,7 @@ enable_if_t<(_Ip < sizeof...(_Types)), int> = 0, class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, enable_if_t, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI _Tp& emplace(_Args&&... __args) { return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); } @@ -1412,7 +1420,7 @@ class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, enable_if_t&, _Args...>, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); } @@ -1423,7 +1431,7 @@ size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, enable_if_t, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI _Tp& emplace(_Args&&... __args) { return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); } @@ -1436,17 +1444,17 @@ __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, enable_if_t&, _Args...>, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); } - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr bool valueless_by_exception() const noexcept { return __impl.valueless_by_exception(); } - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI constexpr size_t index() const noexcept { return __impl.index(); } template < @@ -1456,7 +1464,7 @@ __dependent_type, _Dummy>::value && __dependent_type, _Dummy>::value)...>::value, int> = 0> - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI void swap(variant& __that) noexcept( __all<(is_nothrow_move_constructible_v<_Types> && is_nothrow_swappable_v<_Types>)...>::value) { @@ -1471,19 +1479,19 @@ }; template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept { return __v.index() == _Ip; } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept { return __holds_alternative<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr auto&& __generic_get(_Vp&& __v) { using __variant_detail::__access::__variant; @@ -1494,7 +1502,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr variant_alternative_t<_Ip, variant<_Types...>>& get( variant<_Types...>& __v) { @@ -1504,7 +1512,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get( variant<_Types...>&& __v) { @@ -1514,7 +1522,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get( const variant<_Types...>& __v) { @@ -1524,7 +1532,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get( const variant<_Types...>&& __v) { @@ -1534,7 +1542,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Tp& get(variant<_Types...>& __v) { static_assert(!is_void_v<_Tp>); @@ -1542,7 +1550,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Tp&& get(variant<_Types...>&& __v) { static_assert(!is_void_v<_Tp>); @@ -1551,7 +1559,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr const _Tp& get(const variant<_Types...>& __v) { static_assert(!is_void_v<_Tp>); @@ -1559,7 +1567,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr const _Tp&& get(const variant<_Types...>&& __v) { static_assert(!is_void_v<_Tp>); @@ -1568,7 +1576,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr auto* __generic_get_if(_Vp* __v) noexcept { using __variant_detail::__access::__variant; return __v && __holds_alternative<_Ip>(*__v) @@ -1577,7 +1585,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t>> get_if(variant<_Types...>* __v) noexcept { static_assert(_Ip < sizeof...(_Types)); @@ -1586,7 +1594,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t>> get_if(const variant<_Types...>* __v) noexcept { static_assert(_Ip < sizeof...(_Types)); @@ -1595,7 +1603,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> get_if(variant<_Types...>* __v) noexcept { static_assert(!is_void_v<_Tp>); @@ -1603,7 +1611,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t get_if(const variant<_Types...>* __v) noexcept { static_assert(!is_void_v<_Tp>); @@ -1613,7 +1621,8 @@ template struct __convert_to_bool { template - _LIBCPP_INLINE_VISIBILITY constexpr bool operator()(_T1 && __t1, _T2&& __t2) const { + _LIBCPP_HIDE_FROM_ABI + constexpr bool operator()(_T1 && __t1, _T2&& __t2) const { static_assert(is_convertible(__t1), _VSTD::forward<_T2>(__t2))), bool>::value, "the relational operator does not return a type which is implicitly convertible to bool"); return _Operator{}(_VSTD::forward<_T1>(__t1), _VSTD::forward<_T2>(__t2)); @@ -1621,7 +1630,7 @@ }; template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; @@ -1630,8 +1639,29 @@ return __variant::__visit_value_at(__lhs.index(), __convert_to_bool>{}, __lhs, __rhs); } +# if _LIBCPP_STD_VER > 17 + template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr common_comparison_category_t...> +operator<=>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { + using __variant_detail::__visitation::__variant; + using __result_t = common_comparison_category_t...>; + if (__lhs.valueless_by_exception() && __rhs.valueless_by_exception()) + return strong_ordering::equal; + if (__lhs.valueless_by_exception()) + return strong_ordering::less; + if (__rhs.valueless_by_exception()) + return strong_ordering::greater; + if (auto __c = __lhs.index() <=> __rhs.index(); __c != 0) + return __c; + auto __three_way = [](const _Type& __v, const _Type& __w) -> __result_t { return __v <=> __w; }; + return __variant::__visit_value_at(__lhs.index(), __three_way, __lhs, __rhs); +} + +# endif // _LIBCPP_STD_VER > 17 + +template +_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; @@ -1642,7 +1672,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; @@ -1654,7 +1684,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; @@ -1666,7 +1696,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; @@ -1679,7 +1709,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) { using __variant_detail::__visitation::__variant; @@ -1692,9 +1722,9 @@ } template -inline _LIBCPP_INLINE_VISIBILITY - _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void - __throw_if_valueless(_Vs&&... __vs) { +_LIBCPP_HIDE_FROM_ABI +_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS +constexpr void __throw_if_valueless(_Vs&&... __vs) { const bool __valueless = (... || _VSTD::__as_variant(__vs).valueless_by_exception()); if (__valueless) { @@ -1705,9 +1735,9 @@ template < class _Visitor, class... _Vs, typename = void_t()))...> > -inline _LIBCPP_INLINE_VISIBILITY - _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr - decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { +_LIBCPP_HIDE_FROM_ABI +_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS +constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; _VSTD::__throw_if_valueless(_VSTD::forward<_Vs>(__vs)...); return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor), @@ -1718,9 +1748,9 @@ template < class _Rp, class _Visitor, class... _Vs, typename = void_t()))...> > -inline _LIBCPP_INLINE_VISIBILITY - _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp - visit(_Visitor&& __visitor, _Vs&&... __vs) { +_LIBCPP_HIDE_FROM_ABI +_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS +constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; _VSTD::__throw_if_valueless(_VSTD::forward<_Vs>(__vs)...); return __variant::__visit_value<_Rp>(_VSTD::forward<_Visitor>(__visitor), @@ -1729,7 +1759,7 @@ #endif template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI auto swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) noexcept(noexcept(__lhs.swap(__rhs))) -> decltype( __lhs.swap(__rhs)) @@ -1741,7 +1771,7 @@ using argument_type = variant<_Types...>; using result_type = size_t; - inline _LIBCPP_INLINE_VISIBILITY + _LIBCPP_HIDE_FROM_ABI result_type operator()(const argument_type& __v) const { using __variant_detail::__visitation::__variant; size_t __res = @@ -1763,20 +1793,20 @@ // type whereas std::get will throw or returning nullptr. This makes it faster than // std::get. template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr auto&& __unchecked_get(_Vp&& __v) noexcept { using __variant_detail::__access::__variant; return __variant::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v)).__value; } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr auto&& __unchecked_get(const variant<_Types...>& __v) noexcept { return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template -inline _LIBCPP_INLINE_VISIBILITY +_LIBCPP_HIDE_FROM_ABI constexpr auto&& __unchecked_get(variant<_Types...>& __v) noexcept { return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } diff --git a/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp b/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp --- a/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp +++ b/libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp @@ -16,40 +16,32 @@ // constexpr bool operator>=(monostate, monostate) noexcept { return true; } // constexpr bool operator==(monostate, monostate) noexcept { return true; } // constexpr bool operator!=(monostate, monostate) noexcept { return false; } +// constexpr strong_ordering operator<=>(monostate, monostate) noexcept { return strong_ordering::equal; } // since C++20 -#include "test_macros.h" #include -#include #include -int main(int, char**) { +#include "test_comparisons.h" +#include "test_macros.h" + +constexpr bool test() { using M = std::monostate; constexpr M m1{}; constexpr M m2{}; - { - static_assert((m1 < m2) == false, ""); - ASSERT_NOEXCEPT(m1 < m2); - } - { - static_assert((m1 > m2) == false, ""); - ASSERT_NOEXCEPT(m1 > m2); - } - { - static_assert((m1 <= m2) == true, ""); - ASSERT_NOEXCEPT(m1 <= m2); - } - { - static_assert((m1 >= m2) == true, ""); - ASSERT_NOEXCEPT(m1 >= m2); - } - { - static_assert((m1 == m2) == true, ""); - ASSERT_NOEXCEPT(m1 == m2); - } - { - static_assert((m1 != m2) == false, ""); - ASSERT_NOEXCEPT(m1 != m2); - } + assert(testComparisons(m1, m2, /*isEqual*/ true, /*isLess*/ false)); + AssertComparisonsAreNoexcept(); + +#if TEST_STD_VER > 17 + assert(testOrder(m1, m2, std::strong_ordering::equal)); + AssertOrderAreNoexcept(); +#endif // TEST_STD_VER > 17 + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); return 0; } diff --git a/libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp b/libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp @@ -0,0 +1,198 @@ +//===----------------------------------------------------------------------===// +// +// 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 class variant; + +// template +// constexpr std::common_comparison_category_t< +// std::compare_three_way_result_t...> +// operator<=>(const variant& t, const variant& u); + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_comparisons.h" + +#ifndef TEST_HAS_NO_EXCEPTIONS +// MakeEmptyT throws in operator=(&&), so we can move to it to create valueless-by-exception variants. +struct MakeEmptyT { + MakeEmptyT() = default; + MakeEmptyT(MakeEmptyT&&) { throw 42; } + MakeEmptyT& operator=(MakeEmptyT&&) { throw 42; } +}; +inline bool operator==(const MakeEmptyT&, const MakeEmptyT&) { + assert(false); + return false; +} +inline std::weak_ordering operator<=>(const MakeEmptyT&, const MakeEmptyT&) { + assert(false); + return std::weak_ordering::equivalent; +} + +template +void makeEmpty(Variant& v) { + Variant v2(std::in_place_type); + try { + v = std::move(v2); + assert(false); + } catch (...) { + assert(v.valueless_by_exception()); + } +} + +void test_empty() { + { + using V = std::variant; + V v1; + V v2; + makeEmpty(v2); + assert(testOrder(v1, v2, std::weak_ordering::greater)); + } + { + using V = std::variant; + V v1; + makeEmpty(v1); + V v2; + assert(testOrder(v1, v2, std::weak_ordering::less)); + } + { + using V = std::variant; + V v1; + makeEmpty(v1); + V v2; + makeEmpty(v2); + assert(testOrder(v1, v2, std::weak_ordering::equivalent)); + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +template +constexpr bool test_with_types() { + using V = std::variant; + AssertOrderReturn(); + { // same index, same value + constexpr V v1(std::in_place_index<0>, T1{1}); + constexpr V v2(std::in_place_index<0>, T1{1}); + assert(testOrder(v1, v2, Order::equivalent)); + } + { // same index, value < other_value + constexpr V v1(std::in_place_index<0>, T1{0}); + constexpr V v2(std::in_place_index<0>, T1{1}); + assert(testOrder(v1, v2, Order::less)); + } + { // same index, value > other_value + constexpr V v1(std::in_place_index<0>, T1{1}); + constexpr V v2(std::in_place_index<0>, T1{0}); + assert(testOrder(v1, v2, Order::greater)); + } + { // LHS.index() < RHS.index() + constexpr V v1(std::in_place_index<0>, T1{0}); + constexpr V v2(std::in_place_index<1>, T2{0}); + assert(testOrder(v1, v2, Order::less)); + } + { // LHS.index() > RHS.index() + constexpr V v1(std::in_place_index<1>, T2{0}); + constexpr V v2(std::in_place_index<0>, T1{0}); + assert(testOrder(v1, v2, Order::greater)); + } + + return true; +} + +constexpr bool test_three_way() { + assert((test_with_types())); + assert((test_with_types())); + + { + using V = std::variant; + constexpr double nan = std::numeric_limits::quiet_NaN(); + { + constexpr V v1(std::in_place_type, 1); + constexpr V v2(std::in_place_type, nan); + assert(testOrder(v1, v2, std::partial_ordering::less)); + } + { + constexpr V v1(std::in_place_type, nan); + constexpr V v2(std::in_place_type, 2); + assert(testOrder(v1, v2, std::partial_ordering::greater)); + } + { + constexpr V v1(std::in_place_type, nan); + constexpr V v2(std::in_place_type, nan); + assert(testOrder(v1, v2, std::partial_ordering::unordered)); + } + } + + return true; +} + +// SFINAE tests +template +concept has_three_way_op = requires (T& t, U& u) { t <=> u; }; + +// std::three_way_comparable is a more stringent requirement that demands +// operator== and a few other things. +using std::three_way_comparable; + +struct HasSimpleOrdering { + constexpr bool operator==(const HasSimpleOrdering&) const; + constexpr bool operator<(const HasSimpleOrdering&) const; +}; + +struct HasOnlySpaceship { + constexpr bool operator==(const HasOnlySpaceship&) const = delete; + constexpr std::weak_ordering operator<=>(const HasOnlySpaceship&) const; +}; + +struct HasFullOrdering { + constexpr bool operator==(const HasFullOrdering&) const; + constexpr std::weak_ordering operator<=>(const HasFullOrdering&) const; +}; + +// operator<=> must resolve the return types of all its union types' +// operator<=>s to determine its own return type, so it is detectable by SFINAE +static_assert(!has_three_way_op); +static_assert(!has_three_way_op>); + +static_assert(!three_way_comparable); +static_assert(!three_way_comparable>); + +static_assert( has_three_way_op); +static_assert( has_three_way_op>); + +// variants containing types with unavailable operator== still exist but will +// generate a compilation error if their operator== is invoked, so the variant +// type here participates when asked for operator== and operator<=> even though +// it would actually fail. +static_assert(!three_way_comparable); +static_assert( three_way_comparable>); + +static_assert( has_three_way_op); +static_assert( has_three_way_op>); + +static_assert( three_way_comparable); +static_assert( three_way_comparable>); + +int main(int, char**) { + test_three_way(); + static_assert(test_three_way()); + +#ifndef TEST_HAS_NO_EXCEPTIONS + test_empty(); +#endif // TEST_HAS_NO_EXCEPTIONS + + return 0; +} diff --git a/libcxx/test/support/test_comparisons.h b/libcxx/test/support/test_comparisons.h --- a/libcxx/test/support/test_comparisons.h +++ b/libcxx/test/support/test_comparisons.h @@ -23,18 +23,20 @@ #ifndef TEST_COMPARISONS_H #define TEST_COMPARISONS_H -#include #include #include +#include +#include + #include "test_macros.h" -// Test all six comparison operations for sanity +// Test the consistency of the six basic comparison operators for values that are ordered or unordered. template -TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t2, bool isEqual, bool isLess) -{ - assert(!(isEqual && isLess) && "isEqual and isLess cannot be both true"); - if (isEqual) - { +TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool +testComparisonsComplete(const T& t1, const U& t2, bool isEqual, bool isLess, bool isGreater) { + assert(((isEqual ? 1 : 0) + (isLess ? 1 : 0) + (isGreater ? 1 : 0) <= 1) && + "at most one of isEqual, isLess, and isGreater can be true"); + if (isEqual) { if (!(t1 == t2)) return false; if (!(t2 == t1)) return false; if ( (t1 != t2)) return false; @@ -47,9 +49,7 @@ if ( (t2 > t1)) return false; if (!(t1 >= t2)) return false; if (!(t2 >= t1)) return false; - } - else if (isLess) - { + } else if (isLess) { if ( (t1 == t2)) return false; if ( (t2 == t1)) return false; if (!(t1 != t2)) return false; @@ -62,9 +62,7 @@ if (!(t2 > t1)) return false; if ( (t1 >= t2)) return false; if (!(t2 >= t1)) return false; - } - else /* greater */ - { + } else if (isGreater) { if ( (t1 == t2)) return false; if ( (t2 == t1)) return false; if (!(t1 != t2)) return false; @@ -77,19 +75,41 @@ if ( (t2 > t1)) return false; if (!(t1 >= t2)) return false; if ( (t2 >= t1)) return false; - } + } else { // unordered + if ( (t1 == t2)) return false; + if ( (t2 == t1)) return false; + if (!(t1 != t2)) return false; + if (!(t2 != t1)) return false; + if ( (t1 < t2)) return false; + if ( (t2 < t1)) return false; + if ( (t1 <= t2)) return false; + if ( (t2 <= t1)) return false; + if ( (t1 > t2)) return false; + if ( (t2 > t1)) return false; + if ( (t1 >= t2)) return false; + if ( (t2 >= t1)) return false; + } return true; } +// Test the six basic comparison operators for ordered values. +template +TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t2, bool isEqual, bool isLess) { + assert(!(isEqual && isLess) && "isEqual and isLess cannot be both true"); + bool isGreater = !isEqual && !isLess; + return testComparisonsComplete(t1, t2, isEqual, isLess, isGreater); +} + // Easy call when you can init from something already comparable. template TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisonsValues(Param val1, Param val2) { - const bool isEqual = val1 == val2; - const bool isLess = val1 < val2; + const bool isEqual = val1 == val2; + const bool isLess = val1 < val2; + const bool isGreater = val1 > val2; - return testComparisons(T(val1), T(val2), isEqual, isLess); + return testComparisonsComplete(T(val1), T(val2), isEqual, isLess, isGreater); } template @@ -138,10 +158,11 @@ template TEST_NODISCARD constexpr bool testOrder(const T& t1, const U& t2, Order order) { - bool equal = order == Order::equivalent; - bool less = order == Order::less; + bool equal = order == Order::equivalent; + bool less = order == Order::less; + bool greater = order == Order::greater; - return (t1 <=> t2 == order) && testComparisons(t1, t2, equal, less); + return (t1 <=> t2 == order) && testComparisonsComplete(t1, t2, equal, less, greater); } template