[libcxx-commits] [libcxx] Speed up compilation of common uses of std::visit() (PR #164196)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Nov 29 08:21:32 PST 2025
https://github.com/higher-performance updated https://github.com/llvm/llvm-project/pull/164196
>From d4b0d1e2cf905010ee961af1712607f618aefa89 Mon Sep 17 00:00:00 2001
From: higher-performance <higher.performance.github at gmail.com>
Date: Fri, 28 Nov 2025 10:48:16 -0500
Subject: [PATCH] Speed up compilation of std::visit() by hard-coding the most
common cases
---
libcxx/include/variant | 94 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 88 insertions(+), 6 deletions(-)
diff --git a/libcxx/include/variant b/libcxx/include/variant
index df587ccf23843..edf198c0e5cf6 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1323,6 +1323,10 @@ private:
friend struct __variant_detail::__visitation::__variant;
};
+template <class... _Types>
+variant<_Types...> __upcast_to_variant(const volatile variant<_Types...>*);
+void __upcast_to_variant(...);
+
template <size_t _Ip, class... _Types>
_LIBCPP_HIDE_FROM_ABI constexpr bool __holds_alternative(const variant<_Types...>& __v) noexcept {
return __v.index() == _Ip;
@@ -1576,22 +1580,100 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __throw_if_valueless(_Vs&&... __vs) {
}
}
+# define _LIBCPP_VARIANT_DISPATCH_COUNT 11 // Speed up compilation for the common cases
+
template < class _Visitor, class... _Vs, typename>
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
- using __variant_detail::__visitation::__variant;
- std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
- return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
+ using __variant_type = decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()...));
+ constexpr size_t __variant_size =
+ conditional_t<is_void_v<__variant_type>,
+ std::integral_constant<size_t, variant_npos>,
+ variant_size<__variant_type>>::value;
+ if constexpr (__variant_size <= _LIBCPP_VARIANT_DISPATCH_COUNT) {
+ using __variant_detail::__access::__variant;
+# define _LIBCPP_VARIANT_DISPATCH_INDEX(_I) \
+ case _I: \
+ if constexpr (_I < __variant_size) { \
+ return std::__invoke( \
+ std::forward<_Visitor>(__visitor), __variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
+ } \
+ [[__fallthrough__]]
+ switch ((..., __vs.__variant_type::index())) {
+ enum : size_t { _I0 = __LINE__ + 1 }; // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ static_assert(__LINE__ - _I0 == _LIBCPP_VARIANT_DISPATCH_COUNT, "index count mismatch");
+ default:
+ std::__throw_bad_variant_access();
+ }
+# undef _LIBCPP_VARIANT_DISPATCH_INDEX
+ } else {
+ using __variant_detail::__visitation::__variant;
+ std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
+ return __variant::__visit_value(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
+ }
}
# if _LIBCPP_STD_VER >= 20
template < class _Rp, class _Visitor, class... _Vs, typename>
_LIBCPP_HIDE_FROM_ABI constexpr _Rp visit(_Visitor&& __visitor, _Vs&&... __vs) {
- using __variant_detail::__visitation::__variant;
- std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
- return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
+ using __variant_type = decltype(std::__upcast_to_variant(std::declval<remove_reference_t<_Vs>*>()...));
+ constexpr size_t __variant_size =
+ conditional_t<is_void_v<__variant_type>,
+ std::integral_constant<size_t, variant_npos>,
+ variant_size<__variant_type>>::value;
+ if constexpr (__variant_size <= _LIBCPP_VARIANT_DISPATCH_COUNT) {
+ using __variant_detail::__access::__variant;
+# define _LIBCPP_VARIANT_DISPATCH_INDEX(_I) \
+ case _I: \
+ if constexpr (_I < __variant_size) { \
+ if constexpr (std::is_void_v<_Rp>) { \
+ std::__invoke( \
+ std::forward<_Visitor>(__visitor), __variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
+ break; \
+ } else { \
+ return std::__invoke( \
+ std::forward<_Visitor>(__visitor), __variant::__get_alt<_I>(std::forward<_Vs>(__vs)...).__value); \
+ } \
+ } \
+ [[__fallthrough__]]
+ switch ((..., __vs.__variant_type::index())) {
+ enum : size_t { _I0 = __LINE__ + 1 }; // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ _LIBCPP_VARIANT_DISPATCH_INDEX(__LINE__ - _I0); // New line required
+ static_assert(__LINE__ - _I0 == _LIBCPP_VARIANT_DISPATCH_COUNT, "index count mismatch");
+ default:
+ std::__throw_bad_variant_access();
+ }
+# undef _LIBCPP_VARIANT_DISPATCH_INDEX
+ } else {
+ using __variant_detail::__visitation::__variant;
+ std::__throw_if_valueless(std::forward<_Vs>(__vs)...);
+ return __variant::__visit_value<_Rp>(std::forward<_Visitor>(__visitor), std::forward<_Vs>(__vs)...);
+ }
}
# endif
+# undef _LIBCPP_VARIANT_DISPATCH_COUNT
+
template <class... _Types>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 auto
swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs) noexcept(noexcept(__lhs.swap(__rhs)))
More information about the libcxx-commits
mailing list