diff --git a/libcxx/include/variant b/libcxx/include/variant index c58f0ac6a16989..33d5dc7dbeb123 100644 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -354,9 +354,9 @@ struct __valueless_t {}; enum class _Trait { _TriviallyAvailable, _Available, _Unavailable }; -template class _IsTriviallyAvailable, - template class _IsAvailable> +template class _IsTriviallyAvailable, + template class _IsAvailable> constexpr _Trait __trait = _IsTriviallyAvailable<_Tp>::value ? _Trait::_TriviallyAvailable @@ -373,7 +373,7 @@ constexpr _Trait __common_trait(initializer_list<_Trait> __traits) { return __result; } -template +template struct __traits { static constexpr _Trait __copy_constructible_trait = __common_trait({__trait<_Types, @@ -434,270 +434,183 @@ struct __variant { namespace __visitation { -#define _LIBCPP_VARIANT_CASES_4(_Case, _Base) \ - _Case(_Base + 0) \ - _Case(_Base + 1) \ - _Case(_Base + 2) \ - _Case(_Base + 3) - -#define _LIBCPP_VARIANT_CASES_16(_Case, _Base) \ - _LIBCPP_VARIANT_CASES_4(_Case, _Base + 4 * 0) \ - _LIBCPP_VARIANT_CASES_4(_Case, _Base + 4 * 1) \ - _LIBCPP_VARIANT_CASES_4(_Case, _Base + 4 * 2) \ - _LIBCPP_VARIANT_CASES_4(_Case, _Base + 4 * 3) - -#define _LIBCPP_VARIANT_CASES_64(_Case, _Base) \ - _LIBCPP_VARIANT_CASES_16(_Case, _Base + 16 * 0) \ - _LIBCPP_VARIANT_CASES_16(_Case, _Base + 16 * 1) \ - _LIBCPP_VARIANT_CASES_16(_Case, _Base + 16 * 2) \ - _LIBCPP_VARIANT_CASES_16(_Case, _Base + 16 * 3) - -#define _LIBCPP_VARIANT_CASES_256(_Case, _Base) \ - _LIBCPP_VARIANT_CASES_64(_Case, _Base + 64 * 0) \ - _LIBCPP_VARIANT_CASES_64(_Case, _Base + 64 * 1) \ - _LIBCPP_VARIANT_CASES_64(_Case, _Base + 64 * 2) \ - _LIBCPP_VARIANT_CASES_64(_Case, _Base + 64 * 3) - -#define _LIBCPP_VARIANT_CASES(_NumCases, _Case) \ - _LIBCPP_CONCAT(_LIBCPP_VARIANT_CASES_, _NumCases)(_Case, 0) - -#define _LIBCPP_VARIANT_SWITCH_MAX 256 - -template -inline _LIBCPP_INLINE_VISIBILITY -static constexpr void __fill_cartesian_impl( - _Iter __iter, _Fp __f, index_sequence<_Is...>) { - *__iter = __f(integral_constant{}...); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -static constexpr void __fill_cartesian_impl( - _Iter __iter, _Fp __f, index_sequence<_Is...>, index_sequence<_Js...>, _Ls... __ls) { - constexpr size_t _Mp = (1 * ... * _Ls::size()); - (__fill_cartesian_impl( - __iter + _Js * _Mp, __f, index_sequence<_Is..., _Js>{}, __ls...), ...); -} - -template -inline _LIBCPP_INLINE_VISIBILITY -static constexpr void __fill_cartesian(_Iter __iter, _Fp __f) { - __fill_cartesian_impl( - __iter, __f, index_sequence<>{}, make_index_sequence<_Ns>{}...); -} - -template -struct __multi { +struct __base { + template inline _LIBCPP_INLINE_VISIBILITY - static constexpr size_t __size = (_Np * ... * _Ns); + static constexpr decltype(auto) + __visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { + constexpr auto __fdiagonal = + __make_fdiagonal<_Visitor&&, + decltype(_VSTD::forward<_Vs>(__vs).__as_base())...>(); + return __fdiagonal[__index](_VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__as_base()...); + } + template inline _LIBCPP_INLINE_VISIBILITY - static constexpr size_t - __index(const size_t (&__is)[sizeof...(_Ns) + 1]) noexcept { - constexpr size_t __ns[] = {_Ns..., 1}; - size_t __result = 0; - for (size_t __i = 0; __i < sizeof...(_Ns) + 1; ++__i) { - if (__is[__i] == variant_npos) { - return variant_npos; - } - __result += __is[__i]; - __result *= __ns[__i]; - } - return __result; + static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, + _Vs&&... __vs) { + constexpr auto __fmatrix = + __make_fmatrix<_Visitor&&, + decltype(_VSTD::forward<_Vs>(__vs).__as_base())...>(); + return __at(__fmatrix, __vs.index()...)( + _VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__as_base()...); } -}; -template -struct __indices { +private: + template inline _LIBCPP_INLINE_VISIBILITY - static constexpr auto __value = [] { - using _Tp = array; - array<_Tp, (1 * ... * _Ns)> __result = {}; - __fill_cartesian<_Ns...>(__result.begin(), - [](auto... __is) -> _Tp { return {__is...}; }); - return __result; - }(); -}; + static constexpr const _Tp& __at(const _Tp& __elem) { return __elem; } -template -inline _LIBCPP_INLINE_VISIBILITY -static constexpr auto __make_vtable_impl(_Fp __f, _Rp (*)(_Args...)) { - array<_Rp (*)(_Args...), (1 * ... * _Ns) + 1> __result = { - [](_Args...) -> _Rp { __throw_bad_variant_access(); } - }; - __fill_cartesian<_Ns...>(__result.begin() + 1, __f); - return __result; -} + template + inline _LIBCPP_INLINE_VISIBILITY + static constexpr auto&& __at(const array<_Tp, _Np>& __elems, + size_t __index, _Indices... __indices) { + return __at(__elems[__index], __indices...); + } -template -inline _LIBCPP_INLINE_VISIBILITY -static constexpr auto __make_vtable(_Fp __f) { - using _Tp = decltype(__f(integral_constant{}...)); - return __make_vtable_impl<_Ns...>(__f, _Tp{}); -} + template + static constexpr void __std_visit_visitor_return_type_check() { + static_assert( + __all...>::value, + "`std::visit` requires the visitor to have a single return type."); + } -struct __base { - template - struct __dispatch { - template + template + inline _LIBCPP_INLINE_VISIBILITY + static constexpr auto __make_farray(_Fs&&... __fs) { + __std_visit_visitor_return_type_check<__uncvref_t<_Fs>...>(); + using __result = array...>, sizeof...(_Fs)>; + return __result{{_VSTD::forward<_Fs>(__fs)...}}; + } + + template + struct __dispatcher { + template inline _LIBCPP_INLINE_VISIBILITY - constexpr auto operator()(integral_constant...) const noexcept { - return +[](_Vis&& __vis, _Vs&&... __vs) -> decltype(auto) { + static constexpr decltype(auto) __dispatch(_Fp __f, _Vs... __vs) { return __invoke_constexpr( - _VSTD::forward<_Vis>(__vis), - __access::__base::__get_alt<_Is>(_VSTD::forward<_Vs>(__vs))...); - }; + static_cast<_Fp>(__f), + __access::__base::__get_alt<_Is>(static_cast<_Vs>(__vs))...); } }; - template + template inline _LIBCPP_INLINE_VISIBILITY - static constexpr decltype(auto) - __visit_alt_at(size_t __index, _Vis&& __vis, _Vp&& __v, _Wp&& __w) { - constexpr size_t __size = __uncvref_t<_Vp>::__size(); - static_assert(__size == __uncvref_t<_Wp>::__size()); - constexpr auto __dispatch_at = [](auto __i) { - return __dispatch<_Vis, _Vp, _Wp>{}(__i, __i); - }; -#define _LIBCPP_VARIANT_CASE(_Ip) \ - case _Ip: { \ - if constexpr (_Ip < __size) { \ - return __dispatch_at(integral_constant{})( \ - _VSTD::forward<_Vis>(__vis), \ - _VSTD::forward<_Vp>(__v), \ - _VSTD::forward<_Wp>(__w)); \ - } else { \ - _LIBCPP_UNREACHABLE(); \ - } \ + static constexpr auto __make_dispatch(index_sequence<_Is...>) { + return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>; } - if constexpr (__size <= _LIBCPP_VARIANT_SWITCH_MAX) { - switch (__index) { - _LIBCPP_VARIANT_CASES(_LIBCPP_VARIANT_SWITCH_MAX, _LIBCPP_VARIANT_CASE) - default: __throw_bad_variant_access(); - } - } else { - constexpr auto __vtable = __make_vtable<__size>(__dispatch_at); - return __vtable[__index + 1](_VSTD::forward<_Vis>(__vis), - _VSTD::forward<_Vp>(__v), - _VSTD::forward<_Wp>(__w)); - } -#undef _LIBCPP_VARIANT_CASE + + template + inline _LIBCPP_INLINE_VISIBILITY + static constexpr auto __make_fdiagonal_impl() { + return __make_dispatch<_Fp, _Vs...>( + index_sequence<(__identity<_Vs>{}, _Ip)...>{}); } - template + template inline _LIBCPP_INLINE_VISIBILITY - static constexpr decltype(auto) __visit_alt(_Vis&& __vis, _Vs&&... __vs) { - if constexpr (sizeof...(_Vs) == 0) { - return __invoke_constexpr(_VSTD::forward<_Vis>(__vis)); - } else { - return __visit_alt_impl(index_sequence_for<_Vs...>{}, - _VSTD::forward<_Vis>(__vis), - _VSTD::forward<_Vs>(__vs)...); - } + static constexpr auto __make_fdiagonal_impl(index_sequence<_Is...>) { + return __base::__make_farray(__make_fdiagonal_impl<_Is, _Fp, _Vs...>()...); } - template + template inline _LIBCPP_INLINE_VISIBILITY - static constexpr decltype(auto) - __visit_alt_impl(index_sequence<_Is...>, _Vis&& __vis, _Vs&&... __vs) { - using __multi = __multi<__uncvref_t<_Vs>::__size()...>; - constexpr __dispatch<_Vis, _Vs...> __dispatch; -#define _LIBCPP_VARIANT_CASE(_Ip) \ - case _Ip: { \ - if constexpr (_Ip < __multi::__size) { \ - return __dispatch(integral_constant{}...)( \ - _VSTD::forward<_Vis>(__vis), _VSTD::forward<_Vs>(__vs)...); \ - } else { \ - _LIBCPP_UNREACHABLE(); \ - } \ + static constexpr auto __make_fdiagonal() { + constexpr size_t _Np = __uncvref_t<_Vp>::__size(); + static_assert(__all<(_Np == __uncvref_t<_Vs>::__size())...>::value); + return __make_fdiagonal_impl<_Fp, _Vp, _Vs...>(make_index_sequence<_Np>{}); } - if constexpr (__multi::__size <= _LIBCPP_VARIANT_SWITCH_MAX) { - constexpr const auto& __itable = - __indices<__uncvref_t<_Vs>::__size()...>::__value; - switch (__multi::__index({__vs.index()...})) { - _LIBCPP_VARIANT_CASES(_LIBCPP_VARIANT_SWITCH_MAX, _LIBCPP_VARIANT_CASE) - default: __throw_bad_variant_access(); - } - } else { - constexpr auto __vtable = - __make_vtable<__uncvref_t<_Vs>::__size()...>(__dispatch); - return __vtable[__multi::__index({__vs.index()...}) + 1]( - _VSTD::forward<_Vis>(__vis), _VSTD::forward<_Vs>(__vs)...); - } -#undef _LIBCPP_VARIANT_CASE + + template + inline _LIBCPP_INLINE_VISIBILITY + static constexpr auto __make_fmatrix_impl(index_sequence<_Is...> __is) { + return __make_dispatch<_Fp, _Vs...>(__is); + } + + template + inline _LIBCPP_INLINE_VISIBILITY + static constexpr auto __make_fmatrix_impl(index_sequence<_Is...>, + index_sequence<_Js...>, + _Ls... __ls) { + return __base::__make_farray(__make_fmatrix_impl<_Fp, _Vs...>( + index_sequence<_Is..., _Js>{}, __ls...)...); + } + + template + inline _LIBCPP_INLINE_VISIBILITY + static constexpr auto __make_fmatrix() { + return __make_fmatrix_impl<_Fp, _Vs...>( + index_sequence<>{}, make_index_sequence<__uncvref_t<_Vs>::__size()>{}...); } }; struct __variant { - template + template inline _LIBCPP_INLINE_VISIBILITY static constexpr decltype(auto) - __visit_alt_at(size_t __index, _Vis&& __vis, _Vp&& __v, _Wp&& __w) { + __visit_alt_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { return __base::__visit_alt_at(__index, - _VSTD::forward<_Vis>(__vis), - _VSTD::forward<_Vp>(__v).__impl, - _VSTD::forward<_Wp>(__w).__impl); + _VSTD::forward<_Visitor>(__visitor), + _VSTD::forward<_Vs>(__vs).__impl...); } - template + template inline _LIBCPP_INLINE_VISIBILITY - static constexpr decltype(auto) __visit_alt(_Vis&& __vis, _Vs&&... __vs) { - return __base::__visit_alt(_VSTD::forward<_Vis>(__vis), + static constexpr decltype(auto) __visit_alt(_Visitor&& __visitor, + _Vs&&... __vs) { + return __base::__visit_alt(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs).__impl...); } - template + template inline _LIBCPP_INLINE_VISIBILITY static constexpr decltype(auto) - __visit_value_at(size_t __index, _Vis&& __vis, _Vp&& __v, _Wp&& __w) { - return __visit_alt_at(__index, - __make_value_visitor(_VSTD::forward<_Vis>(__vis)), - _VSTD::forward<_Vp>(__v), - _VSTD::forward<_Wp>(__w)); + __visit_value_at(size_t __index, _Visitor&& __visitor, _Vs&&... __vs) { + return __visit_alt_at( + __index, + __make_value_visitor(_VSTD::forward<_Visitor>(__visitor)), + _VSTD::forward<_Vs>(__vs)...); } - template + template inline _LIBCPP_INLINE_VISIBILITY - static constexpr decltype(auto) __visit_value(_Vis&& __vis, _Vs&&... __vs) { - return __visit_alt(__make_value_visitor(_VSTD::forward<_Vis>(__vis)), - _VSTD::forward<_Vs>(__vs)...); + static constexpr decltype(auto) __visit_value(_Visitor&& __visitor, + _Vs&&... __vs) { + return __visit_alt( + __make_value_visitor(_VSTD::forward<_Visitor>(__visitor)), + _VSTD::forward<_Vs>(__vs)...); } private: - template - inline _LIBCPP_INLINE_VISIBILITY + template static constexpr void __std_visit_exhaustive_visitor_check() { - static_assert(is_invocable_v<_Vis, _Values...>, + static_assert(is_invocable_v<_Visitor, _Values...>, "`std::visit` requires the visitor to be exhaustive."); } - template + template struct __value_visitor { template inline _LIBCPP_INLINE_VISIBILITY constexpr decltype(auto) operator()(_Alts&&... __alts) const { __std_visit_exhaustive_visitor_check< - _Vis, decltype((_VSTD::forward<_Alts>(__alts).__value))...>(); - return __invoke_constexpr(_VSTD::forward<_Vis>(__vis), + _Visitor, + decltype((_VSTD::forward<_Alts>(__alts).__value))...>(); + return __invoke_constexpr(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Alts>(__alts).__value...); } - _Vis&& __vis; + _Visitor&& __visitor; }; - template + template inline _LIBCPP_INLINE_VISIBILITY - static constexpr auto __make_value_visitor(_Vis&& __vis) { - return __value_visitor<_Vis>{_VSTD::forward<_Vis>(__vis)}; + static constexpr auto __make_value_visitor(_Visitor&& __visitor) { + return __value_visitor<_Visitor>{_VSTD::forward<_Visitor>(__visitor)}; } }; -#undef _LIBCPP_VARIANT_SWITCH_MAX -#undef _LIBCPP_VARIANT_CASES -#undef _LIBCPP_VARIANT_CASES_256 -#undef _LIBCPP_VARIANT_CASES_64 -#undef _LIBCPP_VARIANT_CASES_16 -#undef _LIBCPP_VARIANT_CASES_4 - } // namespace __visitation template @@ -720,7 +633,7 @@ union _LIBCPP_TEMPLATE_VIS __union<_DestructibleTrait, _Index> {}; #define _LIBCPP_VARIANT_UNION(destructible_trait, destructor) \ template \ - union _LIBCPP_TEMPLATE_VIS __union { \ @@ -874,9 +787,9 @@ protected: template inline _LIBCPP_INLINE_VISIBILITY static _Tp& __construct_alt(__alt<_Ip, _Tp>& __a, _Args&&... __args) { - auto* __result = ::new ((void*)_VSTD::addressof(__a)) + ::new ((void*)_VSTD::addressof(__a)) __alt<_Ip, _Tp>(in_place, _VSTD::forward<_Args>(__args)...); - return __result->__value; + return __a.__value; } template @@ -903,7 +816,7 @@ class _LIBCPP_TEMPLATE_VIS __move_constructor; #define _LIBCPP_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, \ move_constructor) \ template \ - class _LIBCPP_TEMPLATE_VIS __move_constructor<__traits<_Types...>, \ + class _LIBCPP_TEMPLATE_VIS __move_constructor<__traits<_Types...>, \ move_constructible_trait> \ : public __constructor<__traits<_Types...>> { \ using __base_type = __constructor<__traits<_Types...>>; \ @@ -943,7 +856,7 @@ class _LIBCPP_TEMPLATE_VIS __copy_constructor; #define _LIBCPP_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, \ copy_constructor) \ template \ - class _LIBCPP_TEMPLATE_VIS __copy_constructor<__traits<_Types...>, \ + class _LIBCPP_TEMPLATE_VIS __copy_constructor<__traits<_Types...>, \ copy_constructible_trait> \ : public __move_constructor<__traits<_Types...>> { \ using __base_type = __move_constructor<__traits<_Types...>>; \ @@ -989,7 +902,7 @@ public: auto& __emplace(_Args&&... __args) { this->__destroy(); auto& __res = this->__construct_alt(__access::__base::__get_alt<_Ip>(*this), - _VSTD::forward<_Args>(__args)...); + _VSTD::forward<_Args>(__args)...); this->__index = _Ip; return __res; } @@ -1042,7 +955,7 @@ class _LIBCPP_TEMPLATE_VIS __move_assignment; #define _LIBCPP_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, \ move_assignment) \ template \ - class _LIBCPP_TEMPLATE_VIS __move_assignment<__traits<_Types...>, \ + class _LIBCPP_TEMPLATE_VIS __move_assignment<__traits<_Types...>, \ move_assignable_trait> \ : public __assignment<__traits<_Types...>> { \ using __base_type = __assignment<__traits<_Types...>>; \ @@ -1083,7 +996,7 @@ class _LIBCPP_TEMPLATE_VIS __copy_assignment; #define _LIBCPP_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, \ copy_assignment) \ template \ - class _LIBCPP_TEMPLATE_VIS __copy_assignment<__traits<_Types...>, \ + class _LIBCPP_TEMPLATE_VIS __copy_assignment<__traits<_Types...>, \ copy_assignable_trait> \ : public __move_assignment<__traits<_Types...>> { \ using __base_type = __move_assignment<__traits<_Types...>>; \ @@ -1677,12 +1590,18 @@ constexpr bool operator>=(const variant<_Types...>& __lhs, __lhs.index(), __convert_to_bool>{}, __lhs, __rhs); } -template +template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS -constexpr decltype(auto) visit(_Vis&& __vis, _Vs&&... __vs) { +constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) { using __variant_detail::__visitation::__variant; - return __variant::__visit_value(_VSTD::forward<_Vis>(__vis), + bool __results[] = {__vs.valueless_by_exception()...}; + for (bool __result : __results) { + if (__result) { + __throw_bad_variant_access(); + } + } + return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor), _VSTD::forward<_Vs>(__vs)...); }