On 11/05/24 02:01 -0700, Ken Matsui wrote:
This patch optimizes the compilation performance of std::is_pointer
by dispatching to the new __is_pointer built-in trait.
libstdc++-v3/ChangeLog:
* include/bits/cpp_type_traits.h (__is_pointer): Use
__is_pointer built-in trait. Optimize its implementation.
* include/std/type_traits (is_pointer): Likewise.
(is_pointer_v): Likewise.
Co-authored-by: Jonathan Wakely <jwak...@redhat.com>
Signed-off-by: Ken Matsui <kmat...@gcc.gnu.org>
---
libstdc++-v3/include/bits/cpp_type_traits.h | 31 ++++++++++++++-
libstdc++-v3/include/std/type_traits | 44 +++++++++++++++++----
2 files changed, 66 insertions(+), 9 deletions(-)
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h
b/libstdc++-v3/include/bits/cpp_type_traits.h
index 59f1a1875eb..210a9ea00da 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -363,6 +363,13 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
//
// Pointer types
//
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+ template<typename _Tp, bool _IsPtr = __is_pointer(_Tp)>
+ struct __is_pointer : __truth_type<_IsPtr>
I was worried that reusing __is_pointer this way would cause a problem
with Clang, because it has an __is_pointer built-in and the code above
causes a warning:
isp.cc:2:12: warning: keyword '__is_pointer' will be made available as an
identifier for the remainder of the translation unit [-Wkeyword-compat]
2 | struct __is_pointer
| ^
I thought this warning meant it was only available as an identifier.
But in fact it becomes available as both an identifier and as the
built-in.
This is what I tested:
template<typename T, bool IsPtr = __is_pointer(T)>
struct __is_pointer
{
enum { value = IsPtr };
};
static_assert( __is_pointer<int*>::value, "" );
template<typename T>
struct is_pointer
{
static constexpr bool value = __is_pointer(T);
};
static_assert( is_pointer<int*>::value, "" );
So the is_pointer template can still use the built-in even though the
name '__is_pointer' has been declared as an identifier.
So Clang matches GCC and it works fine. Good!
+ {
+ enum { __value = _IsPtr };
+ };
+#else
template<typename _Tp>
struct __is_pointer
{
@@ -377,6 +384,28 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
typedef __true_type __type;
};
+ template<typename _Tp>
+ struct __is_pointer<_Tp* const>
None of the other traits in bits/cpp_type_traits.h is true for
cv-qualified types, so these partial specializations make __is_pointer
the odd one out. Are they necessary?
+ {
+ enum { __value = 1 };
+ typedef __true_type __type;
+ };
+
+ template<typename _Tp>
+ struct __is_pointer<_Tp* volatile>
+ {
+ enum { __value = 1 };
+ typedef __true_type __type;
+ };
+
+ template<typename _Tp>
+ struct __is_pointer<_Tp* const volatile>
+ {
+ enum { __value = 1 };
+ typedef __true_type __type;
+ };
+#endif
+
//
// An arithmetic type is an integer type or a floating point type
//
@@ -387,7 +416,7 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
//
// A scalar type is an arithmetic type or a pointer type
- //
+ //
template<typename _Tp>
struct __is_scalar
: public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> >
diff --git a/libstdc++-v3/include/std/type_traits
b/libstdc++-v3/include/std/type_traits
index 748fa186881..ea013b4b7bc 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -542,19 +542,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public true_type { };
#endif
- template<typename>
- struct __is_pointer_helper
+ /// is_pointer
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+ template<typename _Tp>
+ struct is_pointer
+ : public __bool_constant<__is_pointer(_Tp)>
+ { };
+#else
+ template<typename _Tp>
+ struct is_pointer
: public false_type { };
template<typename _Tp>
- struct __is_pointer_helper<_Tp*>
+ struct is_pointer<_Tp*>
: public true_type { };
- /// is_pointer
template<typename _Tp>
- struct is_pointer
- : public __is_pointer_helper<__remove_cv_t<_Tp>>::type
- { };
+ struct is_pointer<_Tp* const>
+ : public true_type { };
+
+ template<typename _Tp>
+ struct is_pointer<_Tp* volatile>
+ : public true_type { };
+
+ template<typename _Tp>
+ struct is_pointer<_Tp* const volatile>
+ : public true_type { };
+#endif
/// is_lvalue_reference
template<typename>
@@ -3268,8 +3282,22 @@ template <typename _Tp, size_t _Num>
inline constexpr bool is_array_v<_Tp[_Num]> = true;
#endif
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_pointer)
+template <typename _Tp>
+ inline constexpr bool is_pointer_v = __is_pointer(_Tp);
+#else
template <typename _Tp>
- inline constexpr bool is_pointer_v = is_pointer<_Tp>::value;
+ inline constexpr bool is_pointer_v = false;
+template <typename _Tp>
+ inline constexpr bool is_pointer_v<_Tp*> = true;
+template <typename _Tp>
+ inline constexpr bool is_pointer_v<_Tp* const> = true;
+template <typename _Tp>
+ inline constexpr bool is_pointer_v<_Tp* volatile> = true;
+template <typename _Tp>
+ inline constexpr bool is_pointer_v<_Tp* const volatile> = true;
+#endif
+
template <typename _Tp>
inline constexpr bool is_lvalue_reference_v = false;
template <typename _Tp>
--
2.44.0