Skip to content

Commit 59fa7b6

Browse files
Speed up compilation of std::visit() by ~8x by hard-coding the most common cases
1 parent b9e2f7a commit 59fa7b6

File tree

1 file changed

+38
-4
lines changed

1 file changed

+38
-4
lines changed

libcxx/include/variant

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,10 @@ private:
13251325
friend struct __variant_detail::__visitation::__variant;
13261326
};
13271327

1328+
template <class... _Types>
1329+
variant<_Types...> __upcast_to_variant(const volatile variant<_Types...>*);
1330+
void __upcast_to_variant(...);
1331+
13281332
template <size_t _Ip, class... _Types>
13291333
_LIBCPP_HIDE_FROM_ABI constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept {
13301334
return __v.index() == _Ip;
@@ -1578,11 +1582,41 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __throw_if_valueless(_Vs&&... __vs) {
15781582
}
15791583
}
15801584

1581-
template < class _Visitor, class... _Vs, typename>
1585+
template <class _Visitor, class... _Vs, typename>
15821586
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
1583-
using __variant_detail::__visitation::__variant;
1584-
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
1585-
return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
1587+
# define _XDispatchIndex(_I) \
1588+
case _I: \
1589+
if constexpr (__variant_size::value > _I) { \
1590+
return std::forward<_Visitor>(__visitor)(__variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
1591+
} \
1592+
[[__fallthrough__]]
1593+
# define _XDispatchCount 8 // Speed up compilation for the common cases
1594+
using __variant_size = variant_size<decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()...))>;
1595+
if constexpr (sizeof...(_Vs) == 1 &&
1596+
conditional_t<is_same_v<variant_size<void>, __variant_size>,
1597+
std::integral_constant<size_t, variant_npos>,
1598+
__variant_size>::value < _XDispatchCount) {
1599+
using __variant_detail::__access::__variant;
1600+
const size_t __indexes[] = {__vs.index()...};
1601+
switch (__indexes[0]) {
1602+
_XDispatchIndex(_XDispatchCount - 8);
1603+
_XDispatchIndex(_XDispatchCount - 7);
1604+
_XDispatchIndex(_XDispatchCount - 6);
1605+
_XDispatchIndex(_XDispatchCount - 5);
1606+
_XDispatchIndex(_XDispatchCount - 4);
1607+
_XDispatchIndex(_XDispatchCount - 3);
1608+
_XDispatchIndex(_XDispatchCount - 2);
1609+
_XDispatchIndex(_XDispatchCount - 1);
1610+
default:
1611+
__throw_bad_variant_access();
1612+
}
1613+
} else {
1614+
using __variant_detail::__visitation::__variant;
1615+
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
1616+
return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
1617+
}
1618+
# undef _XDispatchCount
1619+
# undef _XDispatchIndex
15861620
}
15871621

15881622
# if _LIBCPP_STD_VER >= 20

0 commit comments

Comments
 (0)