From 487bd3ba4f1f179be42e3bb13e009d9ff8fc053e Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 10 Dec 2025 14:26:17 +0000 Subject: [PATCH] libstdc++: Optimize compilation time for signed/unsigned integer traits MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Replace the O(n) definitions using __is_one_of with constant-time checks that look for a static member in the __is_integral_helper class template. That class template is already specialized for every signed and unsigned integer type, so we don't need to define any additional specializations. We can just add a static data member that says whether the type is a signed integer type, an unsigned integer type, or neither. The __is_signed_integer and __is_unsigned_integer traits can then inspect that value. The new enum type could be extended in future to distinguish the character types (char, wchar_t, char8_t, char16_t, and char32_t) and bool from non-integer types, but that isn't needed for now. libstdc++-v3/ChangeLog: * include/std/type_traits (_Integer_kind): New enum type. (__is_integral_helper::_S_kind): New static data member in primary template and each explicit specialization. (__is_signed_integer, __is_unsigned_integer): Use _S_kind instead of O(n) disjunction with is_same. Reviewed-by: Patrick Palka Reviewed-by: Tomasz Kamiński --- libstdc++-v3/include/std/type_traits | 159 ++++++++++++++------------- 1 file changed, 80 insertions(+), 79 deletions(-) diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 3f0bcc4e77d..8a7d123408f 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -348,78 +348,102 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public true_type { }; /// @cond undocumented + + // Every integral type is either one of the character types, one of the + // signed integer types, one of the unsigned integer types, or bool, + // or a cv-qualified version of one of those types ([basic.fundamental]). + // For now we only need to distinguish the signed/unsigned integer types. + enum class _Integer_kind { _None, _Signed, _Unsigned }; + template struct __is_integral_helper - : public false_type { }; + : public false_type + { static constexpr auto _S_kind = _Integer_kind::_None; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_None; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_None; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Signed; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Unsigned; }; // We want is_integral to be true (and make_signed/unsigned to work) // even when libc doesn't provide working and related functions, // so don't check _GLIBCXX_USE_WCHAR_T here. template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_None; }; #ifdef _GLIBCXX_USE_CHAR8_T template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_None; }; #endif template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_None; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_None; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Signed; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Unsigned; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Signed; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Unsigned; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Signed; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Unsigned; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Signed; }; template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Unsigned; }; // Conditionalizing on __STRICT_ANSI__ here will break any port that // uses one of these types for size_t. @@ -427,59 +451,88 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __extension__ template<> struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_0> - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Signed; }; __extension__ template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Unsigned; }; #endif #if defined(__GLIBCXX_TYPE_INT_N_1) __extension__ template<> struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_1> - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Signed; }; __extension__ template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Unsigned; }; #endif #if defined(__GLIBCXX_TYPE_INT_N_2) __extension__ template<> struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_2> - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Signed; }; __extension__ template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Unsigned; }; #endif #if defined(__GLIBCXX_TYPE_INT_N_3) __extension__ template<> struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_3> - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Signed; }; __extension__ template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Unsigned; }; #endif #if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__ __extension__ template<> struct __is_integral_helper<__int128> - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Signed; }; __extension__ template<> struct __is_integral_helper - : public true_type { }; + : public true_type + { static constexpr auto _S_kind = _Integer_kind::_Unsigned; }; #endif + // Check if a type is one of the signed integer types. + template + using __is_signed_integer + = __bool_constant<__is_integral_helper<_Tp>::_S_kind + == _Integer_kind::_Signed>; + + // Check if a type is one of the unsigned integer types. + template + using __is_unsigned_integer + = __bool_constant<__is_integral_helper<_Tp>::_S_kind + == _Integer_kind::_Unsigned>; + + // Check if a type is one of the signed or unsigned integer types. + // i.e. an integral type except bool, char, wchar_t, and charN_t. + template + using __is_signed_or_unsigned_integer + = __bool_constant<__is_integral_helper<_Tp>::_S_kind + != _Integer_kind::_None>; + /// @endcond /// is_integral @@ -823,58 +876,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template using __is_one_of = __or_...>; - // Check if a type is one of the signed integer types. - __extension__ - template - using __is_signed_integer = __is_one_of<_Tp, - signed char, signed short, signed int, signed long, - signed long long -#if defined(__GLIBCXX_TYPE_INT_N_0) - , signed __GLIBCXX_TYPE_INT_N_0 -#endif -#if defined(__GLIBCXX_TYPE_INT_N_1) - , signed __GLIBCXX_TYPE_INT_N_1 -#endif -#if defined(__GLIBCXX_TYPE_INT_N_2) - , signed __GLIBCXX_TYPE_INT_N_2 -#endif -#if defined(__GLIBCXX_TYPE_INT_N_3) - , signed __GLIBCXX_TYPE_INT_N_3 -#endif -#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ - , signed __int128 -#endif - >; - - // Check if a type is one of the unsigned integer types. - __extension__ - template - using __is_unsigned_integer = __is_one_of<_Tp, - unsigned char, unsigned short, unsigned int, unsigned long, - unsigned long long -#if defined(__GLIBCXX_TYPE_INT_N_0) - , unsigned __GLIBCXX_TYPE_INT_N_0 -#endif -#if defined(__GLIBCXX_TYPE_INT_N_1) - , unsigned __GLIBCXX_TYPE_INT_N_1 -#endif -#if defined(__GLIBCXX_TYPE_INT_N_2) - , unsigned __GLIBCXX_TYPE_INT_N_2 -#endif -#if defined(__GLIBCXX_TYPE_INT_N_3) - , unsigned __GLIBCXX_TYPE_INT_N_3 -#endif -#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__ - , unsigned __int128 -#endif - >; - - // Check if a type is one of the signed or unsigned integer types. - // i.e. an integral type except bool, char, wchar_t, and charN_t. - template - using __is_signed_or_unsigned_integer - = __or_<__is_signed_integer<_Tp>, __is_unsigned_integer<_Tp>>; - // __void_t (std::void_t for C++11) template using __void_t = void; /// @endcond -- 2.47.3