[libcxx-commits] [libcxx] c4566ca - [libc++][spaceship] Implement std::variant::operator<=>
Kent Ross via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Aug 14 16:17:37 PDT 2022
Author: Kent Ross
Date: 2022-08-14T16:16:52-07:00
New Revision: c4566cac490cf81c141e7deb84008b2cc1de48b7
URL: https://github.com/llvm/llvm-project/commit/c4566cac490cf81c141e7deb84008b2cc1de48b7
DIFF: https://github.com/llvm/llvm-project/commit/c4566cac490cf81c141e7deb84008b2cc1de48b7.diff
LOG: [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
Added:
libcxx/test/std/utilities/variant/variant.relops/three_way.pass.cpp
Modified:
libcxx/docs/Status/SpaceshipProjects.csv
libcxx/include/__variant/monostate.h
libcxx/include/variant
libcxx/test/std/utilities/variant/variant.monostate.relops/relops.pass.cpp
libcxx/test/support/test_comparisons.h
Removed:
################################################################################
diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index efb38b3e662f..ee077dccb5b1 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -25,7 +25,7 @@ Section,Description,Dependencies,Assignee,Complete
| nullopt",None,Kent Ross,|In Progress|
"| `[variant.relops] <https://wg21.link/variant.relops>`_
| `[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|
| `[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|
diff --git a/libcxx/include/__variant/monostate.h b/libcxx/include/__variant/monostate.h
index b389c3b56b36..b3b4597dd985 100644
--- 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 <cstddef>
@@ -24,31 +25,34 @@ _LIBCPP_BEGIN_NAMESPACE_STD
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<monostate> {
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
index 8a86e4c1aed7..69ff0e5b6ed9 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -165,6 +165,10 @@ namespace std {
template <class... 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
template <class Visitor, class... Variants>
constexpr see below visit(Visitor&&, Variants&&...);
@@ -176,12 +180,13 @@ namespace std {
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 <class... Types>
@@ -201,6 +206,9 @@ namespace std {
#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>
@@ -262,7 +270,7 @@ struct __farray {
};
_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
@@ -373,7 +381,7 @@ __as_variant(const variant<_Types...>&& __vs) noexcept {
namespace __find_detail {
template <class _Tp, class... _Types>
-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;
@@ -418,7 +426,7 @@ constexpr _Trait __trait =
? _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) {
@@ -457,13 +465,13 @@ namespace __access {
struct __union {
template <class _Vp>
- 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 <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>) {
return __get_alt(_VSTD::forward<_Vp>(__v).__tail, in_place_index<_Ip - 1>);
}
@@ -471,7 +479,7 @@ struct __union {
struct __base {
template <size_t _Ip, class _Vp>
- 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>);
@@ -480,7 +488,7 @@ struct __base {
struct __variant {
template <size_t _Ip, class _Vp>
- 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);
}
@@ -492,7 +500,7 @@ namespace __visitation {
struct __base {
template <class _Visitor, class... _Vs>
- 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 =
@@ -503,7 +511,7 @@ struct __base {
}
template <class _Visitor, class... _Vs>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor,
_Vs&&... __vs) {
constexpr auto __fmatrix =
@@ -516,11 +524,11 @@ struct __base {
private:
template <class _Tp>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
static constexpr const _Tp& __at(const _Tp& __elem) { return __elem; }
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,
size_t __index, _Indices... __indices) {
return __at(__elems[__index], __indices...);
@@ -534,7 +542,7 @@ private:
}
template <class... _Fs>
- 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<common_type_t<__uncvref_t<_Fs>...>, sizeof...(_Fs)>;
@@ -544,7 +552,7 @@ private:
template <size_t... _Is>
struct __dispatcher {
template <class _Fp, class... _Vs>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) __dispatch(_Fp __f, _Vs... __vs) {
return _VSTD::__invoke(
static_cast<_Fp>(__f),
@@ -553,26 +561,26 @@ private:
};
template <class _Fp, class... _Vs, size_t... _Is>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
static constexpr auto __make_dispatch(index_sequence<_Is...>) {
return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>;
}
template <size_t _Ip, class _Fp, class... _Vs>
- 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 <class _Fp, class... _Vs, size_t... _Is>
- 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 <class _Fp, class _Vp, class... _Vs>
- 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);
@@ -580,13 +588,13 @@ private:
}
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) {
return __make_dispatch<_Fp, _Vs...>(__is);
}
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...>,
index_sequence<_Js...>,
_Ls... __ls) {
@@ -595,7 +603,7 @@ private:
}
template <class _Fp, class... _Vs>
- 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()>{}...);
@@ -604,7 +612,7 @@ private:
struct __variant {
template <class _Visitor, class... _Vs>
- 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,
@@ -613,7 +621,7 @@ struct __variant {
}
template <class _Visitor, class... _Vs>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor,
_Vs&&... __vs) {
return __base::__visit_alt(
@@ -622,7 +630,7 @@ struct __variant {
}
template <class _Visitor, class... _Vs>
- 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(
@@ -632,7 +640,7 @@ struct __variant {
}
template <class _Visitor, class... _Vs>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
static constexpr decltype(auto) __visit_value(_Visitor&& __visitor,
_Vs&&... __vs) {
return __visit_alt(
@@ -642,7 +650,7 @@ struct __variant {
#if _LIBCPP_STD_VER > 17
template <class _Rp, class _Visitor, class... _Vs>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
static constexpr _Rp __visit_value(_Visitor&& __visitor,
_Vs&&... __vs) {
return __visit_alt(
@@ -661,7 +669,7 @@ private:
template <class _Visitor>
struct __value_visitor {
template <class... _Alts>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
constexpr decltype(auto) operator()(_Alts&&... __alts) const {
__std_visit_exhaustive_visitor_check<
_Visitor,
@@ -676,7 +684,7 @@ private:
template <class _Rp, class _Visitor>
struct __value_visitor_return_type {
template <class... _Alts>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
constexpr _Rp operator()(_Alts&&... __alts) const {
__std_visit_exhaustive_visitor_check<
_Visitor,
@@ -696,14 +704,14 @@ private:
#endif
template <class _Visitor>
- 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 <class _Rp, class _Visitor>
- 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)};
}
@@ -717,7 +725,7 @@ struct _LIBCPP_TEMPLATE_VIS __alt {
using __value_type = _Tp;
template <class... _Args>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
explicit constexpr __alt(in_place_t, _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) \
template <size_t _Index, class _Tp, class... _Types> \
- union _LIBCPP_TEMPLATE_VIS __union<destructible_trait, \
+ union _LIBCPP_TEMPLATE_VIS __union<destructible_trait, \
_Index, \
_Tp, \
_Types...> { \
public: \
- inline _LIBCPP_INLINE_VISIBILITY \
+ _LIBCPP_HIDE_FROM_ABI \
explicit constexpr __union(__valueless_t) noexcept : __dummy{} {} \
\
template <class... _Args> \
- 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 <size_t _Ip, class... _Args> \
- 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)...) {} \
\
@@ -777,41 +785,41 @@ class _LIBCPP_TEMPLATE_VIS __base {
public:
using __index_t = __variant_index_t<sizeof...(_Types)>;
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
explicit constexpr __base(__valueless_t __tag) noexcept
: __data(__tag), __index(__variant_npos<__index_t>) {}
template <size_t _Ip, class... _Args>
- 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;
@@ -843,7 +851,7 @@ class _LIBCPP_TEMPLATE_VIS __dtor;
__dtor& operator=(__dtor&&) = default; \
\
protected: \
- inline _LIBCPP_INLINE_VISIBILITY \
+ inline _LIBCPP_HIDE_FROM_ABI \
destroy \
}
@@ -884,7 +892,7 @@ public:
protected:
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) {
::new ((void*)_VSTD::addressof(__a))
__alt<_Ip, _Tp>(in_place, _VSTD::forward<_Args>(__args)...);
@@ -892,7 +900,7 @@ protected:
}
template <class _Rhs>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
static void __generic_construct(__ctor& __lhs, _Rhs&& __rhs) {
__lhs.__destroy();
if (!__rhs.valueless_by_exception()) {
@@ -955,7 +963,7 @@ class _LIBCPP_TEMPLATE_VIS __copy_constructor;
#define _LIBCPP_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, \
copy_constructor) \
template <class... _Types> \
- 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...>>; \
@@ -997,7 +1005,7 @@ public:
using __base_type::operator=;
template <size_t _Ip, class... _Args>
- 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),
@@ -1008,7 +1016,7 @@ public:
protected:
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) {
if (this->index() == _Ip) {
__a.__value = _VSTD::forward<_Arg>(__arg);
@@ -1029,7 +1037,7 @@ protected:
}
template <class _That>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
void __generic_assign(_That&& __that) {
if (this->valueless_by_exception() && __that.valueless_by_exception()) {
// do nothing.
@@ -1054,7 +1062,7 @@ class _LIBCPP_TEMPLATE_VIS __move_assignment;
#define _LIBCPP_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, \
move_assignment) \
template <class... _Types> \
- 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...>>; \
@@ -1095,7 +1103,7 @@ class _LIBCPP_TEMPLATE_VIS __copy_assignment;
#define _LIBCPP_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, \
copy_assignment) \
template <class... _Types> \
- 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...>>; \
@@ -1141,13 +1149,13 @@ public:
__impl& operator=(__impl&&) = default;
template <size_t _Ip, class _Arg>
- 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.
@@ -1193,7 +1201,7 @@ public:
}
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()];
@@ -1299,7 +1307,7 @@ public:
enable_if_t<__dependent_type<is_default_constructible<__first_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>) {}
@@ -1315,7 +1323,7 @@ public:
size_t _Ip =
__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
constexpr variant(_Arg&& __arg) noexcept(
is_nothrow_constructible_v<_Tp, _Arg>)
: __impl(in_place_index<_Ip>, _VSTD::forward<_Arg>(__arg)) {}
@@ -1324,7 +1332,7 @@ public:
class = enable_if_t<(_Ip < sizeof...(_Types)), int>,
class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
enable_if_t<is_constructible_v<_Tp, _Args...>, 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...>)
@@ -1338,7 +1346,7 @@ public:
class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
int> = 0>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
explicit constexpr variant(
in_place_index_t<_Ip>,
initializer_list<_Up> __il,
@@ -1352,7 +1360,7 @@ public:
size_t _Ip =
__find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
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(
is_nothrow_constructible_v<_Tp, _Args...>)
: __impl(in_place_index<_Ip>, _VSTD::forward<_Args>(__args)...) {}
@@ -1365,7 +1373,7 @@ public:
__find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
int> = 0>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
explicit constexpr variant(
in_place_type_t<_Tp>,
initializer_list<_Up> __il,
@@ -1386,7 +1394,7 @@ public:
__find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_assignable_v<_Tp&, _Arg> && 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>) {
@@ -1400,7 +1408,7 @@ public:
enable_if_t<(_Ip < sizeof...(_Types)), int> = 0,
class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
_Tp& emplace(_Args&&... __args) {
return __impl.template __emplace<_Ip>(_VSTD::forward<_Args>(__args)...);
}
@@ -1413,7 +1421,7 @@ public:
class _Tp = variant_alternative_t<_Ip, variant<_Types...>>,
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _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)...);
}
@@ -1424,7 +1432,7 @@ public:
size_t _Ip =
__find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
- inline _LIBCPP_INLINE_VISIBILITY
+ _LIBCPP_HIDE_FROM_ABI
_Tp& emplace(_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,
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _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 <
@@ -1457,7 +1465,7 @@ public:
__dependent_type<is_move_constructible<_Types>, _Dummy>::value &&
__dependent_type<is_swappable<_Types>, _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) {
@@ -1472,19 +1480,19 @@ private:
};
template <size_t _Ip, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept {
return __v.index() == _Ip;
}
template <class _Tp, class... _Types>
-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 <size_t _Ip, class _Vp>
-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;
@@ -1495,7 +1503,7 @@ constexpr auto&& __generic_get(_Vp&& __v) {
}
template <size_t _Ip, class... _Types>
-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) {
@@ -1505,7 +1513,7 @@ constexpr variant_alternative_t<_Ip, variant<_Types...>>& get(
}
template <size_t _Ip, class... _Types>
-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) {
@@ -1515,7 +1523,7 @@ constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get(
}
template <size_t _Ip, class... _Types>
-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) {
@@ -1525,7 +1533,7 @@ constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get(
}
template <size_t _Ip, class... _Types>
-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) {
@@ -1535,7 +1543,7 @@ constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get(
}
template <class _Tp, class... _Types>
-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>);
@@ -1543,7 +1551,7 @@ constexpr _Tp& get(variant<_Types...>& __v) {
}
template <class _Tp, class... _Types>
-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>);
@@ -1552,7 +1560,7 @@ constexpr _Tp&& get(variant<_Types...>&& __v) {
}
template <class _Tp, class... _Types>
-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>);
@@ -1560,7 +1568,7 @@ constexpr const _Tp& get(const variant<_Types...>& __v) {
}
template <class _Tp, class... _Types>
-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>);
@@ -1569,7 +1577,7 @@ constexpr const _Tp&& get(const variant<_Types...>&& __v) {
}
template <size_t _Ip, class _Vp>
-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)
@@ -1578,7 +1586,7 @@ constexpr auto* __generic_get_if(_Vp* __v) noexcept {
}
template <size_t _Ip, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
constexpr add_pointer_t<variant_alternative_t<_Ip, variant<_Types...>>>
get_if(variant<_Types...>* __v) noexcept {
static_assert(_Ip < sizeof...(_Types));
@@ -1587,7 +1595,7 @@ get_if(variant<_Types...>* __v) noexcept {
}
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...>>>
get_if(const variant<_Types...>* __v) noexcept {
static_assert(_Ip < sizeof...(_Types));
@@ -1596,7 +1604,7 @@ get_if(const variant<_Types...>* __v) noexcept {
}
template <class _Tp, class... _Types>
-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>);
@@ -1604,7 +1612,7 @@ get_if(variant<_Types...>* __v) noexcept {
}
template <class _Tp, class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
constexpr add_pointer_t<const _Tp>
get_if(const variant<_Types...>* __v) noexcept {
static_assert(!is_void_v<_Tp>);
@@ -1614,7 +1622,8 @@ get_if(const variant<_Types...>* __v) noexcept {
template <class _Operator>
struct __convert_to_bool {
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,
"the relational operator does not return a type which is implicitly convertible to bool");
return _Operator{}(_VSTD::forward<_T1>(__t1), _VSTD::forward<_T2>(__t2));
@@ -1622,7 +1631,7 @@ struct __convert_to_bool {
};
template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
constexpr bool operator==(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) {
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);
}
+# if _LIBCPP_STD_VER > 17
+
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,
const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant;
@@ -1643,7 +1673,7 @@ constexpr bool operator!=(const variant<_Types...>& __lhs,
}
template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
constexpr bool operator<(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant;
@@ -1655,7 +1685,7 @@ constexpr bool operator<(const variant<_Types...>& __lhs,
}
template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
constexpr bool operator>(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant;
@@ -1667,7 +1697,7 @@ constexpr bool operator>(const variant<_Types...>& __lhs,
}
template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
constexpr bool operator<=(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant;
@@ -1680,7 +1710,7 @@ constexpr bool operator<=(const variant<_Types...>& __lhs,
}
template <class... _Types>
-inline _LIBCPP_INLINE_VISIBILITY
+_LIBCPP_HIDE_FROM_ABI
constexpr bool operator>=(const variant<_Types...>& __lhs,
const variant<_Types...>& __rhs) {
using __variant_detail::__visitation::__variant;
@@ -1693,9 +1723,9 @@ constexpr bool operator>=(const variant<_Types...>& __lhs,
}
template <class... _Vs>
-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) {
@@ -1706,9 +1736,9 @@ inline _LIBCPP_INLINE_VISIBILITY
template <
class _Visitor, class... _Vs,
typename = void_t<decltype(_VSTD::__as_variant(declval<_Vs>()))...> >
-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),
@@ -1719,9 +1749,9 @@ inline _LIBCPP_INLINE_VISIBILITY
template <
class _Rp, class _Visitor, class... _Vs,
typename = void_t<decltype(_VSTD::__as_variant(declval<_Vs>()))...> >
-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),
@@ -1730,7 +1760,7 @@ inline _LIBCPP_INLINE_VISIBILITY
#endif
template <class... _Types>
-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))
@@ -1742,7 +1772,7 @@ struct _LIBCPP_TEMPLATE_VIS hash<
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 =
@@ -1764,20 +1794,20 @@ struct _LIBCPP_TEMPLATE_VIS hash<
// type whereas std::get will throw or returning nullptr. This makes it faster than
// std::get.
template <size_t _Ip, class _Vp>
-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 <class _Tp, class... _Types>
-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 <class _Tp, class... _Types>
-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
index 6e4e3116fa0e..fab67be3e4b5 100644
--- 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 <cassert>
-#include <type_traits>
#include <variant>
-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<M>();
+
+#if TEST_STD_VER > 17
+ assert(testOrder(m1, m2, std::strong_ordering::equal));
+ AssertOrderAreNoexcept<M>();
+#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
index 000000000000..f851c535e40a
--- /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
+
+// <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;
+}
diff --git a/libcxx/test/support/test_comparisons.h b/libcxx/test/support/test_comparisons.h
index e4bb4196543b..8187a7c1a215 100644
--- 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 <type_traits>
#include <cassert>
#include <concepts>
+#include <type_traits>
+#include <utility>
+
#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>
-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 @@ TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t
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 @@ TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t
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 @@ TEST_NODISCARD TEST_CONSTEXPR_CXX14 bool testComparisons(const T& t1, const U& t
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 <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.
template <class T, class Param>
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 <class T, class U = T>
@@ -138,10 +158,11 @@ constexpr void AssertOrderReturn() {
template <class Order, class T, class U = T>
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 <class T, class Param>
More information about the libcxx-commits
mailing list