[libc++][spaceship] Implement std::variant::operator<=>

Implements [variant.relops] and [variant.monostate.relops] for P1614R2

Reviewed By: Mordante, #libc, avogelsgesang

Differential Revision: https://reviews.llvm.org/D131372
This commit is contained in:
Kent Ross 2022-08-14 16:14:57 -07:00
parent b2ac153ba4
commit c4566cac49
6 changed files with 418 additions and 173 deletions

View File

@ -25,7 +25,7 @@ Section,Description,Dependencies,Assignee,Complete
| nullopt",None,Kent Ross,|In Progress| | nullopt",None,Kent Ross,|In Progress|
"| `[variant.relops] <https://wg21.link/variant.relops>`_ "| `[variant.relops] <https://wg21.link/variant.relops>`_
| `[variant.monostate.relops] <https://wg21.link/variant.monostate.relops>`_","| `monostate <https://reviews.llvm.org/D131372>`_ | `[variant.monostate.relops] <https://wg21.link/variant.monostate.relops>`_","| `monostate <https://reviews.llvm.org/D131372>`_
| `variant <https://reviews.llvm.org/D131372>`_",None,Kent Ross,|In Progress| | `variant <https://reviews.llvm.org/D131372>`_",None,Kent Ross,|Complete|
| `[unique.ptr.special] <https://wg21.link/unique.ptr.special>`_,| `unique_ptr <https://reviews.llvm.org/D130838>`_,[comparisons.three.way],Adrian Vogelsgesang,|Complete| | `[unique.ptr.special] <https://wg21.link/unique.ptr.special>`_,| `unique_ptr <https://reviews.llvm.org/D130838>`_,[comparisons.three.way],Adrian Vogelsgesang,|Complete|
| `[util.smartptr.shared.cmp] <https://wg21.link/util.smartptr.shared.cmp>`_,| `shared_ptr <https://reviews.llvm.org/D130852>`_,[comparisons.three.way],Adrian Vogelsgesang,|Complete| | `[util.smartptr.shared.cmp] <https://wg21.link/util.smartptr.shared.cmp>`_,| `shared_ptr <https://reviews.llvm.org/D130852>`_,[comparisons.three.way],Adrian Vogelsgesang,|Complete|
| `[type.index.members] <https://wg21.link/type.index.members>`_,| `type_index <https://reviews.llvm.org/D131357>`_,None,Adrian Vogelsgesang,|Complete| | `[type.index.members] <https://wg21.link/type.index.members>`_,| `type_index <https://reviews.llvm.org/D131357>`_,None,Adrian Vogelsgesang,|Complete|

1 Section Description Dependencies Assignee Complete
25 | `[array.syn] <https://wg21.link/array.syn>`_ (`general <https://wg21.link/container.requirements.general#14>`_) | array [expos.only.func] Unassigned |Not Started|
26 | `[deque.syn] <https://wg21.link/deque.syn>`_ (`general <https://wg21.link/container.requirements.general#14>`_) | deque [expos.only.func] Unassigned |Not Started|
27 | `[forward.list.syn] <https://wg21.link/forward.list.syn>`_ (`general <https://wg21.link/container.requirements.general#14>`_) | forward_list [expos.only.func] Unassigned |Not Started|
28 | `[list.syn] <https://wg21.link/list.syn>`_ (`general <https://wg21.link/container.requirements.general#14>`_) | list [expos.only.func] Unassigned |Not Started|
29 | `[vector.syn] <https://wg21.link/vector.syn>`_ (`general <https://wg21.link/container.requirements.general#14>`_) | vector [expos.only.func] Unassigned |Not Started|
30 | `[associative.map.syn] <https://wg21.link/associative.map.syn>`_ (`general <https://wg21.link/container.requirements.general#14>`_) | map | multimap [expos.only.func] Unassigned |Not Started|
31 | `[associative.set.syn] <https://wg21.link/associative.set.syn>`_ (`general <https://wg21.link/container.requirements.general#14>`_) | multiset | set [expos.only.func] Unassigned |Not Started|

View File

@ -10,6 +10,7 @@
#ifndef _LIBCPP___VARIANT_MONOSTATE_H #ifndef _LIBCPP___VARIANT_MONOSTATE_H
#define _LIBCPP___VARIANT_MONOSTATE_H #define _LIBCPP___VARIANT_MONOSTATE_H
#include <__compare/ordering.h>
#include <__config> #include <__config>
#include <__functional/hash.h> #include <__functional/hash.h>
#include <cstddef> #include <cstddef>
@ -24,31 +25,34 @@ _LIBCPP_BEGIN_NAMESPACE_STD
struct _LIBCPP_TEMPLATE_VIS monostate {}; struct _LIBCPP_TEMPLATE_VIS monostate {};
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(monostate, monostate) noexcept { return true; }
constexpr bool operator<(monostate, monostate) noexcept { return false; }
inline _LIBCPP_INLINE_VISIBILITY # if _LIBCPP_STD_VER > 17
constexpr bool operator>(monostate, monostate) noexcept { return false; }
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(monostate, monostate) noexcept {
constexpr bool operator<=(monostate, monostate) noexcept { return true; } return strong_ordering::equal;
}
inline _LIBCPP_INLINE_VISIBILITY # else // _LIBCPP_STD_VER > 17
constexpr bool operator>=(monostate, monostate) noexcept { return true; }
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(monostate, monostate) noexcept { return false; }
constexpr bool operator==(monostate, monostate) noexcept { return true; }
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(monostate, monostate) noexcept { return false; }
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 <> template <>
struct _LIBCPP_TEMPLATE_VIS hash<monostate> { struct _LIBCPP_TEMPLATE_VIS hash<monostate> {
using argument_type = monostate; using argument_type = monostate;
using result_type = size_t; using result_type = size_t;
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_HIDE_FROM_ABI result_type operator()(const argument_type&) const _NOEXCEPT {
result_type operator()(const argument_type&) const _NOEXCEPT {
return 66740831; // return a fundamentally attractive random value. return 66740831; // return a fundamentally attractive random value.
} }
}; };

View File

@ -165,6 +165,10 @@ namespace std {
template <class... Types> template <class... Types>
constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&); constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&);
template <class... Types>
constexpr common_comparison_category_t<compare_three_way_result_t<Types>...>
operator<=>(const variant<Types...>&, const variant<Types...>&); // since C++20
// 20.7.6, visitation // 20.7.6, visitation
template <class Visitor, class... Variants> template <class Visitor, class... Variants>
constexpr see below visit(Visitor&&, Variants&&...); constexpr see below visit(Visitor&&, Variants&&...);
@ -176,12 +180,13 @@ namespace std {
struct monostate; struct monostate;
// 20.7.8, monostate relational operators // 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; 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 // 20.7.9, specialized algorithms
template <class... Types> template <class... Types>
@ -201,6 +206,9 @@ namespace std {
#include <__assert> // all public C++ headers provide the assertion handler #include <__assert> // all public C++ headers provide the assertion handler
#include <__availability> #include <__availability>
#include <__compare/common_comparison_category.h>
#include <__compare/compare_three_way_result.h>
#include <__compare/three_way_comparable.h>
#include <__config> #include <__config>
#include <__functional/hash.h> #include <__functional/hash.h>
#include <__functional/operations.h> #include <__functional/operations.h>
@ -262,7 +270,7 @@ struct __farray {
}; };
_LIBCPP_NORETURN _LIBCPP_NORETURN
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
void __throw_bad_variant_access() { void __throw_bad_variant_access() {
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
@ -373,7 +381,7 @@ __as_variant(const variant<_Types...>&& __vs) noexcept {
namespace __find_detail { namespace __find_detail {
template <class _Tp, class... _Types> template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr size_t __find_index() { constexpr size_t __find_index() {
constexpr bool __matches[] = {is_same_v<_Tp, _Types>...}; constexpr bool __matches[] = {is_same_v<_Tp, _Types>...};
size_t __result = __not_found; size_t __result = __not_found;
@ -418,7 +426,7 @@ constexpr _Trait __trait =
? _Trait::_TriviallyAvailable ? _Trait::_TriviallyAvailable
: _IsAvailable<_Tp>::value ? _Trait::_Available : _Trait::_Unavailable; : _IsAvailable<_Tp>::value ? _Trait::_Available : _Trait::_Unavailable;
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr _Trait __common_trait(initializer_list<_Trait> __traits) { constexpr _Trait __common_trait(initializer_list<_Trait> __traits) {
_Trait __result = _Trait::_TriviallyAvailable; _Trait __result = _Trait::_TriviallyAvailable;
for (_Trait __t : __traits) { for (_Trait __t : __traits) {
@ -457,13 +465,13 @@ namespace __access {
struct __union { struct __union {
template <class _Vp> template <class _Vp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<0>) { static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<0>) {
return _VSTD::forward<_Vp>(__v).__head; return _VSTD::forward<_Vp>(__v).__head;
} }
template <class _Vp, size_t _Ip> template <class _Vp, size_t _Ip>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto&& __get_alt(_Vp&& __v, in_place_index_t<_Ip>) { 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>); return __get_alt(_VSTD::forward<_Vp>(__v).__tail, in_place_index<_Ip - 1>);
} }
@ -471,7 +479,7 @@ struct __union {
struct __base { struct __base {
template <size_t _Ip, class _Vp> template <size_t _Ip, class _Vp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto&& __get_alt(_Vp&& __v) { static constexpr auto&& __get_alt(_Vp&& __v) {
return __union::__get_alt(_VSTD::forward<_Vp>(__v).__data, return __union::__get_alt(_VSTD::forward<_Vp>(__v).__data,
in_place_index<_Ip>); in_place_index<_Ip>);
@ -480,7 +488,7 @@ struct __base {
struct __variant { struct __variant {
template <size_t _Ip, class _Vp> template <size_t _Ip, class _Vp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto&& __get_alt(_Vp&& __v) { static constexpr auto&& __get_alt(_Vp&& __v) {
return __base::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v).__impl); return __base::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v).__impl);
} }
@ -492,7 +500,7 @@ namespace __visitation {
struct __base { struct __base {
template <class _Visitor, class... _Vs> template <class _Visitor, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) static constexpr decltype(auto)
__visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { __visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) {
constexpr auto __fdiagonal = constexpr auto __fdiagonal =
@ -503,7 +511,7 @@ struct __base {
} }
template <class _Visitor, class... _Vs> template <class _Visitor, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor,
_Vs&&... __vs) { _Vs&&... __vs) {
constexpr auto __fmatrix = constexpr auto __fmatrix =
@ -516,11 +524,11 @@ struct __base {
private: private:
template <class _Tp> template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr const _Tp& __at(const _Tp& __elem) { return __elem; } static constexpr const _Tp& __at(const _Tp& __elem) { return __elem; }
template <class _Tp, size_t _Np, typename... _Indices> template <class _Tp, size_t _Np, typename... _Indices>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto&& __at(const __farray<_Tp, _Np>& __elems, static constexpr auto&& __at(const __farray<_Tp, _Np>& __elems,
size_t __index, _Indices... __indices) { size_t __index, _Indices... __indices) {
return __at(__elems[__index], __indices...); return __at(__elems[__index], __indices...);
@ -534,7 +542,7 @@ private:
} }
template <class... _Fs> template <class... _Fs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_farray(_Fs&&... __fs) { static constexpr auto __make_farray(_Fs&&... __fs) {
__std_visit_visitor_return_type_check<__uncvref_t<_Fs>...>(); __std_visit_visitor_return_type_check<__uncvref_t<_Fs>...>();
using __result = __farray<common_type_t<__uncvref_t<_Fs>...>, sizeof...(_Fs)>; using __result = __farray<common_type_t<__uncvref_t<_Fs>...>, sizeof...(_Fs)>;
@ -544,7 +552,7 @@ private:
template <size_t... _Is> template <size_t... _Is>
struct __dispatcher { struct __dispatcher {
template <class _Fp, class... _Vs> template <class _Fp, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) __dispatch(_Fp __f, _Vs... __vs) { static constexpr decltype(auto) __dispatch(_Fp __f, _Vs... __vs) {
return _VSTD::__invoke( return _VSTD::__invoke(
static_cast<_Fp>(__f), static_cast<_Fp>(__f),
@ -553,26 +561,26 @@ private:
}; };
template <class _Fp, class... _Vs, size_t... _Is> template <class _Fp, class... _Vs, size_t... _Is>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_dispatch(index_sequence<_Is...>) { static constexpr auto __make_dispatch(index_sequence<_Is...>) {
return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>; return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>;
} }
template <size_t _Ip, class _Fp, class... _Vs> template <size_t _Ip, class _Fp, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_fdiagonal_impl() { static constexpr auto __make_fdiagonal_impl() {
return __make_dispatch<_Fp, _Vs...>( return __make_dispatch<_Fp, _Vs...>(
index_sequence<((void)__type_identity<_Vs>{}, _Ip)...>{}); index_sequence<((void)__type_identity<_Vs>{}, _Ip)...>{});
} }
template <class _Fp, class... _Vs, size_t... _Is> template <class _Fp, class... _Vs, size_t... _Is>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_fdiagonal_impl(index_sequence<_Is...>) { static constexpr auto __make_fdiagonal_impl(index_sequence<_Is...>) {
return __base::__make_farray(__make_fdiagonal_impl<_Is, _Fp, _Vs...>()...); return __base::__make_farray(__make_fdiagonal_impl<_Is, _Fp, _Vs...>()...);
} }
template <class _Fp, class _Vp, class... _Vs> template <class _Fp, class _Vp, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_fdiagonal() { static constexpr auto __make_fdiagonal() {
constexpr size_t _Np = __uncvref_t<_Vp>::__size(); constexpr size_t _Np = __uncvref_t<_Vp>::__size();
static_assert(__all<(_Np == __uncvref_t<_Vs>::__size())...>::value); static_assert(__all<(_Np == __uncvref_t<_Vs>::__size())...>::value);
@ -580,13 +588,13 @@ private:
} }
template <class _Fp, class... _Vs, size_t... _Is> template <class _Fp, class... _Vs, size_t... _Is>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_fmatrix_impl(index_sequence<_Is...> __is) { static constexpr auto __make_fmatrix_impl(index_sequence<_Is...> __is) {
return __make_dispatch<_Fp, _Vs...>(__is); return __make_dispatch<_Fp, _Vs...>(__is);
} }
template <class _Fp, class... _Vs, size_t... _Is, size_t... _Js, class... _Ls> template <class _Fp, class... _Vs, size_t... _Is, size_t... _Js, class... _Ls>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_fmatrix_impl(index_sequence<_Is...>, static constexpr auto __make_fmatrix_impl(index_sequence<_Is...>,
index_sequence<_Js...>, index_sequence<_Js...>,
_Ls... __ls) { _Ls... __ls) {
@ -595,7 +603,7 @@ private:
} }
template <class _Fp, class... _Vs> template <class _Fp, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_fmatrix() { static constexpr auto __make_fmatrix() {
return __make_fmatrix_impl<_Fp, _Vs...>( return __make_fmatrix_impl<_Fp, _Vs...>(
index_sequence<>{}, make_index_sequence<__uncvref_t<_Vs>::__size()>{}...); index_sequence<>{}, make_index_sequence<__uncvref_t<_Vs>::__size()>{}...);
@ -604,7 +612,7 @@ private:
struct __variant { struct __variant {
template <class _Visitor, class... _Vs> template <class _Visitor, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) static constexpr decltype(auto)
__visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { __visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) {
return __base::__visit_alt_at(__index, return __base::__visit_alt_at(__index,
@ -613,7 +621,7 @@ struct __variant {
} }
template <class _Visitor, class... _Vs> template <class _Visitor, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor,
_Vs&&... __vs) { _Vs&&... __vs) {
return __base::__visit_alt( return __base::__visit_alt(
@ -622,7 +630,7 @@ struct __variant {
} }
template <class _Visitor, class... _Vs> template <class _Visitor, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) static constexpr decltype(auto)
__visit_value_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { __visit_value_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) {
return __visit_alt_at( return __visit_alt_at(
@ -632,7 +640,7 @@ struct __variant {
} }
template <class _Visitor, class... _Vs> template <class _Visitor, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) __visit_value(_Visitor&& __visitor, static constexpr decltype(auto) __visit_value(_Visitor&& __visitor,
_Vs&&... __vs) { _Vs&&... __vs) {
return __visit_alt( return __visit_alt(
@ -642,7 +650,7 @@ struct __variant {
#if _LIBCPP_STD_VER > 17 #if _LIBCPP_STD_VER > 17
template <class _Rp, class _Visitor, class... _Vs> template <class _Rp, class _Visitor, class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr _Rp __visit_value(_Visitor&& __visitor, static constexpr _Rp __visit_value(_Visitor&& __visitor,
_Vs&&... __vs) { _Vs&&... __vs) {
return __visit_alt( return __visit_alt(
@ -661,7 +669,7 @@ private:
template <class _Visitor> template <class _Visitor>
struct __value_visitor { struct __value_visitor {
template <class... _Alts> template <class... _Alts>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr decltype(auto) operator()(_Alts&&... __alts) const { constexpr decltype(auto) operator()(_Alts&&... __alts) const {
__std_visit_exhaustive_visitor_check< __std_visit_exhaustive_visitor_check<
_Visitor, _Visitor,
@ -676,7 +684,7 @@ private:
template <class _Rp, class _Visitor> template <class _Rp, class _Visitor>
struct __value_visitor_return_type { struct __value_visitor_return_type {
template <class... _Alts> template <class... _Alts>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr _Rp operator()(_Alts&&... __alts) const { constexpr _Rp operator()(_Alts&&... __alts) const {
__std_visit_exhaustive_visitor_check< __std_visit_exhaustive_visitor_check<
_Visitor, _Visitor,
@ -696,14 +704,14 @@ private:
#endif #endif
template <class _Visitor> template <class _Visitor>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_value_visitor(_Visitor&& __visitor) { static constexpr auto __make_value_visitor(_Visitor&& __visitor) {
return __value_visitor<_Visitor>{_VSTD::forward<_Visitor>(__visitor)}; return __value_visitor<_Visitor>{_VSTD::forward<_Visitor>(__visitor)};
} }
#if _LIBCPP_STD_VER > 17 #if _LIBCPP_STD_VER > 17
template <class _Rp, class _Visitor> template <class _Rp, class _Visitor>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_value_visitor(_Visitor&& __visitor) { static constexpr auto __make_value_visitor(_Visitor&& __visitor) {
return __value_visitor_return_type<_Rp, _Visitor>{_VSTD::forward<_Visitor>(__visitor)}; return __value_visitor_return_type<_Rp, _Visitor>{_VSTD::forward<_Visitor>(__visitor)};
} }
@ -717,7 +725,7 @@ struct _LIBCPP_TEMPLATE_VIS __alt {
using __value_type = _Tp; using __value_type = _Tp;
template <class... _Args> template <class... _Args>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
explicit constexpr __alt(in_place_t, _Args&&... __args) explicit constexpr __alt(in_place_t, _Args&&... __args)
: __value(_VSTD::forward<_Args>(__args)...) {} : __value(_VSTD::forward<_Args>(__args)...) {}
@ -732,21 +740,21 @@ union _LIBCPP_TEMPLATE_VIS __union<_DestructibleTrait, _Index> {};
#define _LIBCPP_VARIANT_UNION(destructible_trait, destructor) \ #define _LIBCPP_VARIANT_UNION(destructible_trait, destructor) \
template <size_t _Index, class _Tp, class... _Types> \ template <size_t _Index, class _Tp, class... _Types> \
union _LIBCPP_TEMPLATE_VIS __union<destructible_trait, \ union _LIBCPP_TEMPLATE_VIS __union<destructible_trait, \
_Index, \ _Index, \
_Tp, \ _Tp, \
_Types...> { \ _Types...> { \
public: \ public: \
inline _LIBCPP_INLINE_VISIBILITY \ _LIBCPP_HIDE_FROM_ABI \
explicit constexpr __union(__valueless_t) noexcept : __dummy{} {} \ explicit constexpr __union(__valueless_t) noexcept : __dummy{} {} \
\ \
template <class... _Args> \ template <class... _Args> \
inline _LIBCPP_INLINE_VISIBILITY \ _LIBCPP_HIDE_FROM_ABI \
explicit constexpr __union(in_place_index_t<0>, _Args&&... __args) \ explicit constexpr __union(in_place_index_t<0>, _Args&&... __args) \
: __head(in_place, _VSTD::forward<_Args>(__args)...) {} \ : __head(in_place, _VSTD::forward<_Args>(__args)...) {} \
\ \
template <size_t _Ip, class... _Args> \ template <size_t _Ip, class... _Args> \
inline _LIBCPP_INLINE_VISIBILITY \ _LIBCPP_HIDE_FROM_ABI \
explicit constexpr __union(in_place_index_t<_Ip>, _Args&&... __args) \ explicit constexpr __union(in_place_index_t<_Ip>, _Args&&... __args) \
: __tail(in_place_index<_Ip - 1>, _VSTD::forward<_Args>(__args)...) {} \ : __tail(in_place_index<_Ip - 1>, _VSTD::forward<_Args>(__args)...) {} \
\ \
@ -777,41 +785,41 @@ class _LIBCPP_TEMPLATE_VIS __base {
public: public:
using __index_t = __variant_index_t<sizeof...(_Types)>; using __index_t = __variant_index_t<sizeof...(_Types)>;
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
explicit constexpr __base(__valueless_t __tag) noexcept explicit constexpr __base(__valueless_t __tag) noexcept
: __data(__tag), __index(__variant_npos<__index_t>) {} : __data(__tag), __index(__variant_npos<__index_t>) {}
template <size_t _Ip, class... _Args> template <size_t _Ip, class... _Args>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
explicit constexpr __base(in_place_index_t<_Ip>, _Args&&... __args) explicit constexpr __base(in_place_index_t<_Ip>, _Args&&... __args)
: :
__data(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...), __data(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...),
__index(_Ip) {} __index(_Ip) {}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr bool valueless_by_exception() const noexcept { constexpr bool valueless_by_exception() const noexcept {
return index() == variant_npos; return index() == variant_npos;
} }
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr size_t index() const noexcept { constexpr size_t index() const noexcept {
return __index == __variant_npos<__index_t> ? variant_npos : __index; return __index == __variant_npos<__index_t> ? variant_npos : __index;
} }
protected: protected:
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr auto&& __as_base() & { return *this; } constexpr auto&& __as_base() & { return *this; }
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr auto&& __as_base() && { return _VSTD::move(*this); } constexpr auto&& __as_base() && { return _VSTD::move(*this); }
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr auto&& __as_base() const & { return *this; } constexpr auto&& __as_base() const & { return *this; }
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr auto&& __as_base() const && { return _VSTD::move(*this); } 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); } static constexpr size_t __size() { return sizeof...(_Types); }
__union<_DestructibleTrait, 0, _Types...> __data; __union<_DestructibleTrait, 0, _Types...> __data;
@ -843,7 +851,7 @@ class _LIBCPP_TEMPLATE_VIS __dtor;
__dtor& operator=(__dtor&&) = default; \ __dtor& operator=(__dtor&&) = default; \
\ \
protected: \ protected: \
inline _LIBCPP_INLINE_VISIBILITY \ inline _LIBCPP_HIDE_FROM_ABI \
destroy \ destroy \
} }
@ -884,7 +892,7 @@ public:
protected: protected:
template <size_t _Ip, class _Tp, class... _Args> template <size_t _Ip, class _Tp, class... _Args>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static _Tp& __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) { static _Tp& __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) {
::new ((void*)_VSTD::addressof(__a)) ::new ((void*)_VSTD::addressof(__a))
__alt<_Ip, _Tp>(in_place, _VSTD::forward<_Args>(__args)...); __alt<_Ip, _Tp>(in_place, _VSTD::forward<_Args>(__args)...);
@ -892,7 +900,7 @@ protected:
} }
template <class _Rhs> template <class _Rhs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
static void __generic_construct(__ctor& __lhs, _Rhs&& __rhs) { static void __generic_construct(__ctor& __lhs, _Rhs&& __rhs) {
__lhs.__destroy(); __lhs.__destroy();
if (!__rhs.valueless_by_exception()) { if (!__rhs.valueless_by_exception()) {
@ -955,7 +963,7 @@ class _LIBCPP_TEMPLATE_VIS __copy_constructor;
#define _LIBCPP_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, \ #define _LIBCPP_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, \
copy_constructor) \ copy_constructor) \
template <class... _Types> \ template <class... _Types> \
class _LIBCPP_TEMPLATE_VIS __copy_constructor<__traits<_Types...>, \ class _LIBCPP_TEMPLATE_VIS __copy_constructor<__traits<_Types...>, \
copy_constructible_trait> \ copy_constructible_trait> \
: public __move_constructor<__traits<_Types...>> { \ : public __move_constructor<__traits<_Types...>> { \
using __base_type = __move_constructor<__traits<_Types...>>; \ using __base_type = __move_constructor<__traits<_Types...>>; \
@ -997,7 +1005,7 @@ public:
using __base_type::operator=; using __base_type::operator=;
template <size_t _Ip, class... _Args> template <size_t _Ip, class... _Args>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
auto& __emplace(_Args&&... __args) { auto& __emplace(_Args&&... __args) {
this->__destroy(); this->__destroy();
auto& __res = this->__construct_alt(__access::__base::__get_alt<_Ip>(*this), auto& __res = this->__construct_alt(__access::__base::__get_alt<_Ip>(*this),
@ -1008,7 +1016,7 @@ public:
protected: protected:
template <size_t _Ip, class _Tp, class _Arg> template <size_t _Ip, class _Tp, class _Arg>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) { void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) {
if (this->index() == _Ip) { if (this->index() == _Ip) {
__a.__value = _VSTD::forward<_Arg>(__arg); __a.__value = _VSTD::forward<_Arg>(__arg);
@ -1029,7 +1037,7 @@ protected:
} }
template <class _That> template <class _That>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
void __generic_assign(_That&& __that) { void __generic_assign(_That&& __that) {
if (this->valueless_by_exception() && __that.valueless_by_exception()) { if (this->valueless_by_exception() && __that.valueless_by_exception()) {
// do nothing. // do nothing.
@ -1054,7 +1062,7 @@ class _LIBCPP_TEMPLATE_VIS __move_assignment;
#define _LIBCPP_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, \ #define _LIBCPP_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, \
move_assignment) \ move_assignment) \
template <class... _Types> \ template <class... _Types> \
class _LIBCPP_TEMPLATE_VIS __move_assignment<__traits<_Types...>, \ class _LIBCPP_TEMPLATE_VIS __move_assignment<__traits<_Types...>, \
move_assignable_trait> \ move_assignable_trait> \
: public __assignment<__traits<_Types...>> { \ : public __assignment<__traits<_Types...>> { \
using __base_type = __assignment<__traits<_Types...>>; \ using __base_type = __assignment<__traits<_Types...>>; \
@ -1095,7 +1103,7 @@ class _LIBCPP_TEMPLATE_VIS __copy_assignment;
#define _LIBCPP_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, \ #define _LIBCPP_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, \
copy_assignment) \ copy_assignment) \
template <class... _Types> \ template <class... _Types> \
class _LIBCPP_TEMPLATE_VIS __copy_assignment<__traits<_Types...>, \ class _LIBCPP_TEMPLATE_VIS __copy_assignment<__traits<_Types...>, \
copy_assignable_trait> \ copy_assignable_trait> \
: public __move_assignment<__traits<_Types...>> { \ : public __move_assignment<__traits<_Types...>> { \
using __base_type = __move_assignment<__traits<_Types...>>; \ using __base_type = __move_assignment<__traits<_Types...>>; \
@ -1141,13 +1149,13 @@ public:
__impl& operator=(__impl&&) = default; __impl& operator=(__impl&&) = default;
template <size_t _Ip, class _Arg> template <size_t _Ip, class _Arg>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
void __assign(_Arg&& __arg) { void __assign(_Arg&& __arg) {
this->__assign_alt(__access::__base::__get_alt<_Ip>(*this), this->__assign_alt(__access::__base::__get_alt<_Ip>(*this),
_VSTD::forward<_Arg>(__arg)); _VSTD::forward<_Arg>(__arg));
} }
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_HIDE_FROM_ABI
void __swap(__impl& __that) { void __swap(__impl& __that) {
if (this->valueless_by_exception() && __that.valueless_by_exception()) { if (this->valueless_by_exception() && __that.valueless_by_exception()) {
// do nothing. // do nothing.
@ -1193,7 +1201,7 @@ public:
} }
private: private:
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_HIDE_FROM_ABI
bool __move_nothrow() const { bool __move_nothrow() const {
constexpr bool __results[] = {is_nothrow_move_constructible_v<_Types>...}; constexpr bool __results[] = {is_nothrow_move_constructible_v<_Types>...};
return this->valueless_by_exception() || __results[this->index()]; return this->valueless_by_exception() || __results[this->index()];
@ -1299,7 +1307,7 @@ public:
enable_if_t<__dependent_type<is_default_constructible<__first_type>, enable_if_t<__dependent_type<is_default_constructible<__first_type>,
_Dummy>::value, _Dummy>::value,
int> = 0> int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr variant() noexcept(is_nothrow_default_constructible_v<__first_type>) constexpr variant() noexcept(is_nothrow_default_constructible_v<__first_type>)
: __impl(in_place_index<0>) {} : __impl(in_place_index<0>) {}
@ -1315,7 +1323,7 @@ public:
size_t _Ip = size_t _Ip =
__find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_constructible_v<_Tp, _Arg>, int> = 0> enable_if_t<is_constructible_v<_Tp, _Arg>, int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr variant(_Arg&& __arg) noexcept( constexpr variant(_Arg&& __arg) noexcept(
is_nothrow_constructible_v<_Tp, _Arg>) is_nothrow_constructible_v<_Tp, _Arg>)
: __impl(in_place_index<_Ip>, _VSTD::forward<_Arg>(__arg)) {} : __impl(in_place_index<_Ip>, _VSTD::forward<_Arg>(__arg)) {}
@ -1324,7 +1332,7 @@ public:
class = enable_if_t<(_Ip < sizeof...(_Types)), int>, class = enable_if_t<(_Ip < sizeof...(_Types)), int>,
class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0> enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
explicit constexpr variant( explicit constexpr variant(
in_place_index_t<_Ip>, in_place_index_t<_Ip>,
_Args&&... __args) noexcept(is_nothrow_constructible_v<_Tp, _Args...>) _Args&&... __args) noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
@ -1338,7 +1346,7 @@ public:
class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
int> = 0> int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
explicit constexpr variant( explicit constexpr variant(
in_place_index_t<_Ip>, in_place_index_t<_Ip>,
initializer_list<_Up> __il, initializer_list<_Up> __il,
@ -1352,7 +1360,7 @@ public:
size_t _Ip = size_t _Ip =
__find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0> enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
explicit constexpr variant(in_place_type_t<_Tp>, _Args&&... __args) noexcept( explicit constexpr variant(in_place_type_t<_Tp>, _Args&&... __args) noexcept(
is_nothrow_constructible_v<_Tp, _Args...>) is_nothrow_constructible_v<_Tp, _Args...>)
: __impl(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...) {} : __impl(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...) {}
@ -1365,7 +1373,7 @@ public:
__find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
int> = 0> int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
explicit constexpr variant( explicit constexpr variant(
in_place_type_t<_Tp>, in_place_type_t<_Tp>,
initializer_list<_Up> __il, initializer_list<_Up> __il,
@ -1386,7 +1394,7 @@ public:
__find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_assignable_v<_Tp&, _Arg> && is_constructible_v<_Tp, _Arg>, enable_if_t<is_assignable_v<_Tp&, _Arg> && is_constructible_v<_Tp, _Arg>,
int> = 0> int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
variant& operator=(_Arg&& __arg) noexcept( variant& operator=(_Arg&& __arg) noexcept(
is_nothrow_assignable_v<_Tp&, _Arg> && is_nothrow_assignable_v<_Tp&, _Arg> &&
is_nothrow_constructible_v<_Tp, _Arg>) { is_nothrow_constructible_v<_Tp, _Arg>) {
@ -1400,7 +1408,7 @@ public:
enable_if_t<(_Ip < sizeof...(_Types)), int> = 0, enable_if_t<(_Ip < sizeof...(_Types)), int> = 0,
class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0> enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_Tp& emplace(_Args&&... __args) { _Tp& emplace(_Args&&... __args) {
return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...);
} }
@ -1413,7 +1421,7 @@ public:
class _Tp = variant_alternative_t<_Ip, variant<_Types...>>, class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
int> = 0> int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) {
return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...); return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_Args>(__args)...);
} }
@ -1424,7 +1432,7 @@ public:
size_t _Ip = size_t _Ip =
__find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0> enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_Tp& emplace(_Args&&... __args) { _Tp& emplace(_Args&&... __args) {
return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...); return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...);
} }
@ -1437,17 +1445,17 @@ public:
__find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
int> = 0> int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) {
return __impl.template __emplace<_Ip>(__il, _VSTD::forward<_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 { constexpr bool valueless_by_exception() const noexcept {
return __impl.valueless_by_exception(); return __impl.valueless_by_exception();
} }
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr size_t index() const noexcept { return __impl.index(); } constexpr size_t index() const noexcept { return __impl.index(); }
template < template <
@ -1457,7 +1465,7 @@ public:
__dependent_type<is_move_constructible<_Types>, _Dummy>::value && __dependent_type<is_move_constructible<_Types>, _Dummy>::value &&
__dependent_type<is_swappable<_Types>, _Dummy>::value)...>::value, __dependent_type<is_swappable<_Types>, _Dummy>::value)...>::value,
int> = 0> int> = 0>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
void swap(variant& __that) noexcept( void swap(variant& __that) noexcept(
__all<(is_nothrow_move_constructible_v<_Types> && __all<(is_nothrow_move_constructible_v<_Types> &&
is_nothrow_swappable_v<_Types>)...>::value) { is_nothrow_swappable_v<_Types>)...>::value) {
@ -1472,19 +1480,19 @@ private:
}; };
template <size_t _Ip, class... _Types> template <size_t _Ip, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept { constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept {
return __v.index() == _Ip; return __v.index() == _Ip;
} }
template <class _Tp, class... _Types> template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept { constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept {
return __holds_alternative<__find_exactly_one_t<_Tp, _Types...>::value>(__v); return __holds_alternative<__find_exactly_one_t<_Tp, _Types...>::value>(__v);
} }
template <size_t _Ip, class _Vp> template <size_t _Ip, class _Vp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
constexpr auto&& __generic_get(_Vp&& __v) { constexpr auto&& __generic_get(_Vp&& __v) {
using __variant_detail::__access::__variant; using __variant_detail::__access::__variant;
@ -1495,7 +1503,7 @@ constexpr auto&& __generic_get(_Vp&& __v) {
} }
template <size_t _Ip, class... _Types> template <size_t _Ip, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
constexpr variant_alternative_t<_Ip, variant<_Types...>>& get( constexpr variant_alternative_t<_Ip, variant<_Types...>>& get(
variant<_Types...>& __v) { variant<_Types...>& __v) {
@ -1505,7 +1513,7 @@ constexpr variant_alternative_t<_Ip, variant<_Types...>>& get(
} }
template <size_t _Ip, class... _Types> template <size_t _Ip, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get( constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get(
variant<_Types...>&& __v) { variant<_Types...>&& __v) {
@ -1515,7 +1523,7 @@ constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get(
} }
template <size_t _Ip, class... _Types> template <size_t _Ip, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get( constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get(
const variant<_Types...>& __v) { const variant<_Types...>& __v) {
@ -1525,7 +1533,7 @@ constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get(
} }
template <size_t _Ip, class... _Types> template <size_t _Ip, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get( constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get(
const variant<_Types...>&& __v) { const variant<_Types...>&& __v) {
@ -1535,7 +1543,7 @@ constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get(
} }
template <class _Tp, class... _Types> template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
constexpr _Tp& get(variant<_Types...>& __v) { constexpr _Tp& get(variant<_Types...>& __v) {
static_assert(!is_void_v<_Tp>); static_assert(!is_void_v<_Tp>);
@ -1543,7 +1551,7 @@ constexpr _Tp& get(variant<_Types...>& __v) {
} }
template <class _Tp, class... _Types> template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
constexpr _Tp&& get(variant<_Types...>&& __v) { constexpr _Tp&& get(variant<_Types...>&& __v) {
static_assert(!is_void_v<_Tp>); static_assert(!is_void_v<_Tp>);
@ -1552,7 +1560,7 @@ constexpr _Tp&& get(variant<_Types...>&& __v) {
} }
template <class _Tp, class... _Types> template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
constexpr const _Tp& get(const variant<_Types...>& __v) { constexpr const _Tp& get(const variant<_Types...>& __v) {
static_assert(!is_void_v<_Tp>); static_assert(!is_void_v<_Tp>);
@ -1560,7 +1568,7 @@ constexpr const _Tp& get(const variant<_Types...>& __v) {
} }
template <class _Tp, class... _Types> template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
constexpr const _Tp&& get(const variant<_Types...>&& __v) { constexpr const _Tp&& get(const variant<_Types...>&& __v) {
static_assert(!is_void_v<_Tp>); static_assert(!is_void_v<_Tp>);
@ -1569,7 +1577,7 @@ constexpr const _Tp&& get(const variant<_Types...>&& __v) {
} }
template <size_t _Ip, class _Vp> template <size_t _Ip, class _Vp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr auto* __generic_get_if(_Vp* __v) noexcept { constexpr auto* __generic_get_if(_Vp* __v) noexcept {
using __variant_detail::__access::__variant; using __variant_detail::__access::__variant;
return __v && __holds_alternative<_Ip>(*__v) return __v && __holds_alternative<_Ip>(*__v)
@ -1578,7 +1586,7 @@ constexpr auto* __generic_get_if(_Vp* __v) noexcept {
} }
template <size_t _Ip, class... _Types> template <size_t _Ip, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr add_pointer_t<variant_alternative_t<_Ip, variant<_Types...>>> constexpr add_pointer_t<variant_alternative_t<_Ip, variant<_Types...>>>
get_if(variant<_Types...>* __v) noexcept { get_if(variant<_Types...>* __v) noexcept {
static_assert(_Ip < sizeof...(_Types)); static_assert(_Ip < sizeof...(_Types));
@ -1587,7 +1595,7 @@ get_if(variant<_Types...>* __v) noexcept {
} }
template <size_t _Ip, class... _Types> template <size_t _Ip, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr add_pointer_t<const variant_alternative_t<_Ip, variant<_Types...>>> constexpr add_pointer_t<const variant_alternative_t<_Ip, variant<_Types...>>>
get_if(const variant<_Types...>* __v) noexcept { get_if(const variant<_Types...>* __v) noexcept {
static_assert(_Ip < sizeof...(_Types)); static_assert(_Ip < sizeof...(_Types));
@ -1596,7 +1604,7 @@ get_if(const variant<_Types...>* __v) noexcept {
} }
template <class _Tp, class... _Types> template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr add_pointer_t<_Tp> constexpr add_pointer_t<_Tp>
get_if(variant<_Types...>* __v) noexcept { get_if(variant<_Types...>* __v) noexcept {
static_assert(!is_void_v<_Tp>); static_assert(!is_void_v<_Tp>);
@ -1604,7 +1612,7 @@ get_if(variant<_Types...>* __v) noexcept {
} }
template <class _Tp, class... _Types> template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr add_pointer_t<const _Tp> constexpr add_pointer_t<const _Tp>
get_if(const variant<_Types...>* __v) noexcept { get_if(const variant<_Types...>* __v) noexcept {
static_assert(!is_void_v<_Tp>); static_assert(!is_void_v<_Tp>);
@ -1614,7 +1622,8 @@ get_if(const variant<_Types...>* __v) noexcept {
template <class _Operator> template <class _Operator>
struct __convert_to_bool { struct __convert_to_bool {
template <class _T1, class _T2> template <class _T1, class _T2>
_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<decltype(_Operator{}(_VSTD::forward<_T1>(__t1), _VSTD::forward<_T2>(__t2))), bool>::value, static_assert(is_convertible<decltype(_Operator{}(_VSTD::forward<_T1>(__t1), _VSTD::forward<_T2>(__t2))), bool>::value,
"the relational operator does not return a type which is implicitly convertible to bool"); "the relational operator does not return a type which is implicitly convertible to bool");
return _Operator{}(_VSTD::forward<_T1>(__t1), _VSTD::forward<_T2>(__t2)); return _Operator{}(_VSTD::forward<_T1>(__t1), _VSTD::forward<_T2>(__t2));
@ -1622,7 +1631,7 @@ struct __convert_to_bool {
}; };
template <class... _Types> template <class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr bool operator==(const variant<_Types...>& __lhs, constexpr bool operator==(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) { const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant; using __variant_detail::__visitation::__variant;
@ -1631,8 +1640,29 @@ constexpr bool operator==(const variant<_Types...>& __lhs,
return __variant::__visit_value_at(__lhs.index(), __convert_to_bool<equal_to<>>{}, __lhs, __rhs); return __variant::__visit_value_at(__lhs.index(), __convert_to_bool<equal_to<>>{}, __lhs, __rhs);
} }
# if _LIBCPP_STD_VER > 17
template <class... _Types> template <class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI constexpr common_comparison_category_t<compare_three_way_result_t<_Types>...>
operator<=>(const variant<_Types...>& __lhs, const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant;
using __result_t = common_comparison_category_t<compare_three_way_result_t<_Types>...>;
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 = []<class _Type>(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 <class... _Types>
_LIBCPP_HIDE_FROM_ABI
constexpr bool operator!=(const variant<_Types...>& __lhs, constexpr bool operator!=(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) { const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant; using __variant_detail::__visitation::__variant;
@ -1643,7 +1673,7 @@ constexpr bool operator!=(const variant<_Types...>& __lhs,
} }
template <class... _Types> template <class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr bool operator<(const variant<_Types...>& __lhs, constexpr bool operator<(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) { const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant; using __variant_detail::__visitation::__variant;
@ -1655,7 +1685,7 @@ constexpr bool operator<(const variant<_Types...>& __lhs,
} }
template <class... _Types> template <class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr bool operator>(const variant<_Types...>& __lhs, constexpr bool operator>(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) { const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant; using __variant_detail::__visitation::__variant;
@ -1667,7 +1697,7 @@ constexpr bool operator>(const variant<_Types...>& __lhs,
} }
template <class... _Types> template <class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr bool operator<=(const variant<_Types...>& __lhs, constexpr bool operator<=(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) { const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant; using __variant_detail::__visitation::__variant;
@ -1680,7 +1710,7 @@ constexpr bool operator<=(const variant<_Types...>& __lhs,
} }
template <class... _Types> template <class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr bool operator>=(const variant<_Types...>& __lhs, constexpr bool operator>=(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) { const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant; using __variant_detail::__visitation::__variant;
@ -1693,9 +1723,9 @@ constexpr bool operator>=(const variant<_Types...>& __lhs,
} }
template <class... _Vs> template <class... _Vs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr void _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
__throw_if_valueless(_Vs&&... __vs) { constexpr void __throw_if_valueless(_Vs&&... __vs) {
const bool __valueless = const bool __valueless =
(... || _VSTD::__as_variant(__vs).valueless_by_exception()); (... || _VSTD::__as_variant(__vs).valueless_by_exception());
if (__valueless) { if (__valueless) {
@ -1706,9 +1736,9 @@ inline _LIBCPP_INLINE_VISIBILITY
template < template <
class _Visitor, class... _Vs, class _Visitor, class... _Vs,
typename = void_t<decltype(_VSTD::__as_variant(declval<_Vs>()))...> > typename = void_t<decltype(_VSTD::__as_variant(declval<_Vs>()))...> >
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
using __variant_detail::__visitation::__variant; using __variant_detail::__visitation::__variant;
_VSTD::__throw_if_valueless(_VSTD::forward<_Vs>(__vs)...); _VSTD::__throw_if_valueless(_VSTD::forward<_Vs>(__vs)...);
return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor), return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor),
@ -1719,9 +1749,9 @@ inline _LIBCPP_INLINE_VISIBILITY
template < template <
class _Rp, class _Visitor, class... _Vs, class _Rp, class _Visitor, class... _Vs,
typename = void_t<decltype(_VSTD::__as_variant(declval<_Vs>()))...> > typename = void_t<decltype(_VSTD::__as_variant(declval<_Vs>()))...> >
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
_LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS constexpr _Rp _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS
visit(_Visitor&& __visitor, _Vs&&... __vs) { constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) {
using __variant_detail::__visitation::__variant; using __variant_detail::__visitation::__variant;
_VSTD::__throw_if_valueless(_VSTD::forward<_Vs>(__vs)...); _VSTD::__throw_if_valueless(_VSTD::forward<_Vs>(__vs)...);
return __variant::__visit_value<_Rp>(_VSTD::forward<_Visitor>(__visitor), return __variant::__visit_value<_Rp>(_VSTD::forward<_Visitor>(__visitor),
@ -1730,7 +1760,7 @@ inline _LIBCPP_INLINE_VISIBILITY
#endif #endif
template <class... _Types> template <class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
auto swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) auto swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
noexcept(noexcept(__lhs.swap(__rhs))) noexcept(noexcept(__lhs.swap(__rhs)))
-> decltype( __lhs.swap(__rhs)) -> decltype( __lhs.swap(__rhs))
@ -1742,7 +1772,7 @@ struct _LIBCPP_TEMPLATE_VIS hash<
using argument_type = variant<_Types...>; using argument_type = variant<_Types...>;
using result_type = size_t; using result_type = size_t;
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
result_type operator()(const argument_type& __v) const { result_type operator()(const argument_type& __v) const {
using __variant_detail::__visitation::__variant; using __variant_detail::__visitation::__variant;
size_t __res = size_t __res =
@ -1764,20 +1794,20 @@ struct _LIBCPP_TEMPLATE_VIS hash<
// type whereas std::get will throw or returning nullptr. This makes it faster than // type whereas std::get will throw or returning nullptr. This makes it faster than
// std::get. // std::get.
template <size_t _Ip, class _Vp> template <size_t _Ip, class _Vp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr auto&& __unchecked_get(_Vp&& __v) noexcept { constexpr auto&& __unchecked_get(_Vp&& __v) noexcept {
using __variant_detail::__access::__variant; using __variant_detail::__access::__variant;
return __variant::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v)).__value; return __variant::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v)).__value;
} }
template <class _Tp, class... _Types> template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr auto&& __unchecked_get(const variant<_Types...>& __v) noexcept { constexpr auto&& __unchecked_get(const variant<_Types...>& __v) noexcept {
return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v);
} }
template <class _Tp, class... _Types> template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_HIDE_FROM_ABI
constexpr auto&& __unchecked_get(variant<_Types...>& __v) noexcept { constexpr auto&& __unchecked_get(variant<_Types...>& __v) noexcept {
return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v);
} }

View File

@ -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 true; } // constexpr bool operator==(monostate, monostate) noexcept { return true; }
// constexpr bool operator!=(monostate, monostate) noexcept { return false; } // 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 <cassert> #include <cassert>
#include <type_traits>
#include <variant> #include <variant>
int main(int, char**) { #include "test_comparisons.h"
#include "test_macros.h"
constexpr bool test() {
using M = std::monostate; using M = std::monostate;
constexpr M m1{}; constexpr M m1{};
constexpr M m2{}; constexpr M m2{};
{ assert(testComparisons(m1, m2, /*isEqual*/ true, /*isLess*/ false));
static_assert((m1 < m2) == false, ""); AssertComparisonsAreNoexcept<M>();
ASSERT_NOEXCEPT(m1 < m2);
} #if TEST_STD_VER > 17
{ assert(testOrder(m1, m2, std::strong_ordering::equal));
static_assert((m1 > m2) == false, ""); AssertOrderAreNoexcept<M>();
ASSERT_NOEXCEPT(m1 > m2); #endif // TEST_STD_VER > 17
}
{ return true;
static_assert((m1 <= m2) == true, ""); }
ASSERT_NOEXCEPT(m1 <= m2);
} int main(int, char**) {
{ test();
static_assert((m1 >= m2) == true, ""); static_assert(test());
ASSERT_NOEXCEPT(m1 >= m2);
}
{
static_assert((m1 == m2) == true, "");
ASSERT_NOEXCEPT(m1 == m2);
}
{
static_assert((m1 != m2) == false, "");
ASSERT_NOEXCEPT(m1 != m2);
}
return 0; return 0;
} }

View File

@ -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
// <variant>
// template <class... Types> class variant;
// template<class... Types>
// constexpr std::common_comparison_category_t<
// std::compare_three_way_result_t<Types>...>
// operator<=>(const variant<Types...>& t, const variant<Types...>& u);
#include <cassert>
#include <limits>
#include <type_traits>
#include <utility>
#include <variant>
#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 <class Variant>
void makeEmpty(Variant& v) {
Variant v2(std::in_place_type<MakeEmptyT>);
try {
v = std::move(v2);
assert(false);
} catch (...) {
assert(v.valueless_by_exception());
}
}
void test_empty() {
{
using V = std::variant<int, MakeEmptyT>;
V v1;
V v2;
makeEmpty(v2);
assert(testOrder(v1, v2, std::weak_ordering::greater));
}
{
using V = std::variant<int, MakeEmptyT>;
V v1;
makeEmpty(v1);
V v2;
assert(testOrder(v1, v2, std::weak_ordering::less));
}
{
using V = std::variant<int, MakeEmptyT>;
V v1;
makeEmpty(v1);
V v2;
makeEmpty(v2);
assert(testOrder(v1, v2, std::weak_ordering::equivalent));
}
}
#endif // TEST_HAS_NO_EXCEPTIONS
template <class T1, class T2, class Order>
constexpr bool test_with_types() {
using V = std::variant<T1, T2>;
AssertOrderReturn<Order, V>();
{ // 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<int, double, std::partial_ordering>()));
assert((test_with_types<int, long, std::strong_ordering>()));
{
using V = std::variant<int, double>;
constexpr double nan = std::numeric_limits<double>::quiet_NaN();
{
constexpr V v1(std::in_place_type<int>, 1);
constexpr V v2(std::in_place_type<double>, nan);
assert(testOrder(v1, v2, std::partial_ordering::less));
}
{
constexpr V v1(std::in_place_type<double>, nan);
constexpr V v2(std::in_place_type<int>, 2);
assert(testOrder(v1, v2, std::partial_ordering::greater));
}
{
constexpr V v1(std::in_place_type<double>, nan);
constexpr V v2(std::in_place_type<double>, nan);
assert(testOrder(v1, v2, std::partial_ordering::unordered));
}
}
return true;
}
// SFINAE tests
template <class T, class U = T>
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<HasSimpleOrdering>);
static_assert(!has_three_way_op<std::variant<int, HasSimpleOrdering>>);
static_assert(!three_way_comparable<HasSimpleOrdering>);
static_assert(!three_way_comparable<std::variant<int, HasSimpleOrdering>>);
static_assert( has_three_way_op<HasOnlySpaceship>);
static_assert( has_three_way_op<std::variant<int, HasOnlySpaceship>>);
// 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<HasOnlySpaceship>);
static_assert( three_way_comparable<std::variant<int, HasOnlySpaceship>>);
static_assert( has_three_way_op<HasFullOrdering>);
static_assert( has_three_way_op<std::variant<int, HasFullOrdering>>);
static_assert( three_way_comparable<HasFullOrdering>);
static_assert( three_way_comparable<std::variant<int, HasFullOrdering>>);
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;
}

View File

@ -23,18 +23,20 @@
#ifndef TEST_COMPARISONS_H #ifndef TEST_COMPARISONS_H
#define TEST_COMPARISONS_H #define TEST_COMPARISONS_H
#include <type_traits>
#include <cassert> #include <cassert>
#include <concepts> #include <concepts>
#include <type_traits>
#include <utility>
#include "test_macros.h" #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 <class T, class U = T> template <class T, class U = T>
TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t2, bool isEqual, bool isLess) TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool
{ testComparisonsComplete(const T& t1, const U& t2, bool isEqual, bool isLess, bool isGreater) {
assert(!(isEqual && isLess) && "isEqual and isLess cannot be both true"); assert(((isEqual ? 1 : 0) + (isLess ? 1 : 0) + (isGreater ? 1 : 0) <= 1) &&
if (isEqual) "at most one of isEqual, isLess, and isGreater can be true");
{ if (isEqual) {
if (!(t1 == t2)) return false; if (!(t1 == t2)) return false;
if (!(t2 == t1)) return false; if (!(t2 == t1)) return false;
if ( (t1 != t2)) return false; if ( (t1 != t2)) return false;
@ -47,9 +49,7 @@ TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t
if ( (t2 > t1)) return false; if ( (t2 > t1)) return false;
if (!(t1 >= t2)) return false; if (!(t1 >= t2)) return false;
if (!(t2 >= t1)) return false; if (!(t2 >= t1)) return false;
} } else if (isLess) {
else if (isLess)
{
if ( (t1 == t2)) return false; if ( (t1 == t2)) return false;
if ( (t2 == t1)) return false; if ( (t2 == t1)) return false;
if (!(t1 != t2)) return false; if (!(t1 != t2)) return false;
@ -62,9 +62,7 @@ TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t
if (!(t2 > t1)) return false; if (!(t2 > t1)) return false;
if ( (t1 >= t2)) return false; if ( (t1 >= t2)) return false;
if (!(t2 >= t1)) return false; if (!(t2 >= t1)) return false;
} } else if (isGreater) {
else /* greater */
{
if ( (t1 == t2)) return false; if ( (t1 == t2)) return false;
if ( (t2 == t1)) return false; if ( (t2 == t1)) return false;
if (!(t1 != t2)) return false; if (!(t1 != t2)) return false;
@ -77,19 +75,41 @@ TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t
if ( (t2 > t1)) return false; if ( (t2 > t1)) return false;
if (!(t1 >= t2)) return false; if (!(t1 >= t2)) return false;
if ( (t2 >= t1)) 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; return true;
} }
// Test the six basic comparison operators for ordered values.
template <class T, class U = T>
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. // Easy call when you can init from something already comparable.
template <class T, class Param> template <class T, class Param>
TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisonsValues(Param val1, Param val2) TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisonsValues(Param val1, Param val2)
{ {
const bool isEqual = val1 == val2; const bool isEqual = val1 == val2;
const bool isLess = 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 <class T, class U = T> template <class T, class U = T>
@ -138,10 +158,11 @@ constexpr void AssertOrderReturn() {
template <class Order, class T, class U = T> template <class Order, class T, class U = T>
TEST_NODISCARD constexpr bool testOrder(const T& t1, const U& t2, Order order) { TEST_NODISCARD constexpr bool testOrder(const T& t1, const U& t2, Order order) {
bool equal = order == Order::equivalent; bool equal = order == Order::equivalent;
bool less = order == Order::less; 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 <class T, class Param> template <class T, class Param>