Skip to content

Commit d4b0d1e

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

File tree

1 file changed

+88
-6
lines changed

1 file changed

+88
-6
lines changed

libcxx/include/variant

Lines changed: 88 additions & 6 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;
@@ -1576,22 +1580,100 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __throw_if_valueless(_Vs&&... __vs) {
15761580
}
15771581
}
15781582

1583+
# define _LIBCPP_VARIANT_DISPATCH_COUNT 11 // Speed up compilation for the common cases
1584+
15791585
template < class _Visitor, class... _Vs, typename>
15801586
_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)...);
1587+
using __variant_type = decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()...));
1588+
constexpr size_t __variant_size =
1589+
conditional_t<is_void_v<__variant_type>,
1590+
std::integral_constant<size_t, variant_npos>,
1591+
variant_size<__variant_type>>::value;
1592+
if constexpr (__variant_size <= _LIBCPP_VARIANT_DISPATCH_COUNT) {
1593+
using __variant_detail::__access::__variant;
1594+
# define _LIBCPP_VARIANT_DISPATCH_INDEX(_I) \
1595+
case _I: \
1596+
if constexpr (_I < __variant_size) { \
1597+
return std::__invoke( \
1598+
std::forward<_Visitor>(__visitor), __variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
1599+
} \
1600+
[[__fallthrough__]]
1601+
switch ((..., __vs.__variant_type::index())) {
1602+
enum : size_t { _I0 = __LINE__ + 1 }; // 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+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1611+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1612+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1613+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1614+
static_assert(__LINE__ - _I0 == _LIBCPP_VARIANT_DISPATCH_COUNT, "index count mismatch");
1615+
default:
1616+
std::__throw_bad_variant_access();
1617+
}
1618+
# undef _LIBCPP_VARIANT_DISPATCH_INDEX
1619+
} else {
1620+
using __variant_detail::__visitation::__variant;
1621+
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
1622+
return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
1623+
}
15841624
}
15851625

15861626
# if _LIBCPP_STD_VER >= 20
15871627
template < class _Rp, class _Visitor, class... _Vs, typename>
15881628
_LIBCPP_HIDE_FROM_ABI constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) {
1589-
using __variant_detail::__visitation::__variant;
1590-
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
1591-
return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
1629+
using __variant_type = decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()...));
1630+
constexpr size_t __variant_size =
1631+
conditional_t<is_void_v<__variant_type>,
1632+
std::integral_constant<size_t, variant_npos>,
1633+
variant_size<__variant_type>>::value;
1634+
if constexpr (__variant_size <= _LIBCPP_VARIANT_DISPATCH_COUNT) {
1635+
using __variant_detail::__access::__variant;
1636+
# define _LIBCPP_VARIANT_DISPATCH_INDEX(_I) \
1637+
case _I: \
1638+
if constexpr (_I < __variant_size) { \
1639+
if constexpr (std::is_void_v<_Rp>) { \
1640+
std::__invoke( \
1641+
std::forward<_Visitor>(__visitor), __variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
1642+
break; \
1643+
} else { \
1644+
return std::__invoke( \
1645+
std::forward<_Visitor>(__visitor), __variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
1646+
} \
1647+
} \
1648+
[[__fallthrough__]]
1649+
switch ((..., __vs.__variant_type::index())) {
1650+
enum : size_t { _I0 = __LINE__ + 1 }; // New line required
1651+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1652+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1653+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1654+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1655+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1656+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1657+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1658+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1659+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1660+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1661+
_LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
1662+
static_assert(__LINE__ - _I0 == _LIBCPP_VARIANT_DISPATCH_COUNT, "index count mismatch");
1663+
default:
1664+
std::__throw_bad_variant_access();
1665+
}
1666+
# undef _LIBCPP_VARIANT_DISPATCH_INDEX
1667+
} else {
1668+
using __variant_detail::__visitation::__variant;
1669+
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
1670+
return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
1671+
}
15921672
}
15931673
# endif
15941674

1675+
# undef _LIBCPP_VARIANT_DISPATCH_COUNT
1676+
15951677
template <class... _Types>
15961678
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 auto
15971679
swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) noexcept(noexcept(__lhs.swap(__rhs)))

0 commit comments

Comments
 (0)