Skip to content

Commit 6cfb3c0

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

File tree

1 file changed

+42
-5
lines changed

1 file changed

+42
-5
lines changed

libcxx/include/variant

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,11 +1578,48 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __throw_if_valueless(_Vs&&... __vs) {
15781578
}
15791579
}
15801580

1581-
template < class _Visitor, class... _Vs, typename>
1582-
_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)...);
1581+
template <class _Visitor, class... _Vs, typename>
1582+
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(_Visitor&& __visitor,
1583+
_Vs&&... __vs) {
1584+
#define _XDispatchIndex(_I) \
1585+
case _I: \
1586+
if constexpr (__variant_size::value > _I) { \
1587+
return __visitor( \
1588+
__variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
1589+
} \
1590+
[[__fallthrough__]]
1591+
#define _XDispatchMax 7 // Speed up compilation for the common cases
1592+
if constexpr (sizeof...(_Vs) == 1) {
1593+
if constexpr (variant_size<__remove_cvref_t<_Vs>...>::value <=
1594+
_XDispatchMax) {
1595+
using __variant_detail::__access::__variant;
1596+
using __variant_size = variant_size<__remove_cvref_t<_Vs>...>;
1597+
const size_t __indexes[] = {__vs.index()...};
1598+
switch (__indexes[0]) {
1599+
_XDispatchIndex(_XDispatchMax - 7);
1600+
_XDispatchIndex(_XDispatchMax - 6);
1601+
_XDispatchIndex(_XDispatchMax - 5);
1602+
_XDispatchIndex(_XDispatchMax - 4);
1603+
_XDispatchIndex(_XDispatchMax - 3);
1604+
_XDispatchIndex(_XDispatchMax - 2);
1605+
_XDispatchIndex(_XDispatchMax - 1);
1606+
_XDispatchIndex(_XDispatchMax - 0);
1607+
default:
1608+
__throw_bad_variant_access();
1609+
}
1610+
} else {
1611+
static_assert(
1612+
variant_size<__remove_cvref_t<_Vs>...>::value > _XDispatchMax,
1613+
"forgot to add dispatch case");
1614+
}
1615+
} else {
1616+
using __variant_detail::__visitation::__variant;
1617+
std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
1618+
return __variant::__visit_value(std::forward<_Visitor>(__visitor),
1619+
std::forward<_Vs>(__vs)...);
1620+
}
1621+
#undef _XDispatchMax
1622+
#undef _XDispatchIndex
15861623
}
15871624

15881625
# if _LIBCPP_STD_VER >= 20

0 commit comments

Comments
 (0)