Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 87 additions & 6 deletions libcxx/include/variant
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,10 @@ private:
friend struct __variant_detail::__visitation::__variant;
};

template <class... _Types>
variant<_Types...> __upcast_to_variant(const volatile variant<_Types...>*);
void __upcast_to_variant(...);

template <size_t _Ip, class... _Types>
_LIBCPP_HIDE_FROM_ABI constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept {
return __v.index() == _Ip;
Expand Down Expand Up @@ -1576,22 +1580,99 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __throw_if_valueless(_Vs&&... __vs) {
}
}

# define _LIBCPP_VARIANT_DISPATCH_COUNT 11 // Speed up compilation for the common cases

template < class _Visitor, class... _Vs, typename>
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
using __variant_detail::__visitation::__variant;
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
using __variant_type = decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()...));
constexpr size_t __variant_size =
conditional_t<is_void_v<__variant_type>,
std::integral_constant<size_t, variant_npos>,
variant_size<__variant_type>>::value;
if constexpr (__variant_size <= _LIBCPP_VARIANT_DISPATCH_COUNT) {
using __variant_detail::__access::__variant;
# define _LIBCPP_VARIANT_DISPATCH_INDEX(_I) \
case _I: \
if constexpr (_I < __variant_size) { \
return std::__invoke( \
std::forward<_Visitor>(__visitor), __variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
} \
[[__fallthrough__]]
switch ((..., __vs.__variant_type::index())) {
enum : size_t { _I0 = __LINE__ + 1 }; // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
static_assert(__LINE__ - _I0 == _LIBCPP_VARIANT_DISPATCH_COUNT, "index count mismatch");
default:
std::__throw_bad_variant_access();
}
# undef _LIBCPP_VARIANT_DISPATCH_INDEX
} else {
using __variant_detail::__visitation::__variant;
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
}
}

# if _LIBCPP_STD_VER >= 20
template < class _Rp, class _Visitor, class... _Vs, typename>
_LIBCPP_HIDE_FROM_ABI constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) {
using __variant_detail::__visitation::__variant;
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
using __variant_type = decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()...));
constexpr size_t __variant_size =
conditional_t<is_void_v<__variant_type>,
std::integral_constant<size_t, variant_npos>,
variant_size<__variant_type>>::value;
if constexpr (__variant_size <= _LIBCPP_VARIANT_DISPATCH_COUNT) {
using __variant_detail::__access::__variant;
# define _LIBCPP_VARIANT_DISPATCH_INDEX(_I) \
case _I: \
if constexpr (_I < __variant_size) { \
if constexpr (std::is_void_v<_Rp>) { \
return (void)std::__invoke( \
std::forward<_Visitor>(__visitor), __variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
} else { \
return std::__invoke( \
std::forward<_Visitor>(__visitor), __variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
} \
} \
[[__fallthrough__]]
switch ((..., __vs.__variant_type::index())) {
enum : size_t { _I0 = __LINE__ + 1 }; // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
static_assert(__LINE__ - _I0 == _LIBCPP_VARIANT_DISPATCH_COUNT, "index count mismatch");
default:
std::__throw_bad_variant_access();
}
# undef _LIBCPP_VARIANT_DISPATCH_INDEX
} else {
using __variant_detail::__visitation::__variant;
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
}
}
# endif

# undef _LIBCPP_VARIANT_DISPATCH_COUNT

template <class... _Types>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 auto
swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) noexcept(noexcept(__lhs.swap(__rhs)))
Expand Down
Loading