Skip to content

Commit cb49b31

Browse files
Speed up compilation of std::visit() by hard-coding the most common cases
1 parent 207627f commit cb49b31

File tree

1 file changed

+40
-3
lines changed

1 file changed

+40
-3
lines changed

libcxx/include/variant

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,10 @@ private:
13231323
friend struct __variant_detail::__visitation::__variant;
13241324
};
13251325

1326+
template <class... _Types>
1327+
variant<_Types...> __upcast_to_variant(const volatile variant<_Types...>*);
1328+
void __upcast_to_variant(...);
1329+
13261330
template <size_t _Ip, class... _Types>
13271331
_LIBCPP_HIDE_FROM_ABI constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept {
13281332
return __v.index() == _Ip;
@@ -1578,9 +1582,42 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __throw_if_valueless(_Vs&&... __vs) {
15781582

15791583
template < class _Visitor, class... _Vs, typename>
15801584
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
1581-
using __variant_detail::__visitation::__variant;
1582-
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
1583-
return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
1585+
# define _LIBCPP_VARIANT_DISPATCH_INDEX(_I) \
1586+
case _I: \
1587+
if constexpr (__variant_size::value > _I) { \
1588+
return std::forward<_Visitor>(__visitor)(__variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
1589+
} \
1590+
[[__fallthrough__]]
1591+
# define _LIBCPP_VARIANT_DISPATCH_COUNT 8 // Speed up compilation for the common cases
1592+
using __variant_size = variant_size<decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()...))>;
1593+
if constexpr (sizeof...(_Vs) == 1 &&
1594+
conditional_t<is_same_v<variant_size<void>, __variant_size>,
1595+
std::integral_constant<size_t, variant_npos>,
1596+
__variant_size>::value < _LIBCPP_VARIANT_DISPATCH_COUNT) {
1597+
using __variant_detail::__access::__variant;
1598+
const size_t __indices[] = {
1599+
__vs.decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()))::index()...};
1600+
switch (__indices[0]) {
1601+
enum : size_t { _I0 = __LINE__ + 1 }; // New line required
1602+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1603+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1604+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1605+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1606+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1607+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1608+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1609+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1610+
static_assert(__LINE__ - _I0 == _LIBCPP_VARIANT_DISPATCH_COUNT, "index count mismatch");
1611+
default:
1612+
std::__throw_bad_variant_access();
1613+
}
1614+
} else {
1615+
using __variant_detail::__visitation::__variant;
1616+
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
1617+
return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
1618+
}
1619+
# undef _LIBCPP_VARIANT_DISPATCH_COUNT
1620+
# undef _LIBCPP_VARIANT_DISPATCH_INDEX
15841621
}
15851622

15861623
# if _LIBCPP_STD_VER >= 20

0 commit comments

Comments
 (0)