]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Use constexpr-if for std::basic_string::_S_copy_chars
authorJonathan Wakely <jwakely@redhat.com>
Thu, 10 Apr 2025 11:21:26 +0000 (12:21 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 11 Apr 2025 12:17:15 +0000 (13:17 +0100)
For C++11 and later we can remove four overloads of _S_copy_chars and
use constexpr-if in the generic _S_copy_chars. This simplifies overload
resolution for _S_copy_chars, and also means that we use the optimized
memcpy path for other iterators such as std::vector<char>::iterator.

We still need all the _S_copy_chars overloads to be part of the explicit
instantiation definition, so make them depend on the macro that is
defined by src/c++11/string-inst.cc for that purpose.

For C++98 the _S_copy_chars  overloads are still needed, but the macros
_GLIBCXX_NOEXCEPT and _GLIBCXX20_CONSTEXPR do nothing for C++98, so this
change removes them from those overloads.  When instantiated in
src/c++11/string-inst.cc the removed _GLIBCXX_NOEXCEPT macros would
expand to 'noexcept', but in practice that doesn't make any difference
for those instantiations. At -O2 the instantiations inline all the calls
to _S_copy_chars and the presence or absence of noexcept doesn't change
anything in the generated code.

libstdc++-v3/ChangeLog:

* include/bits/basic_string.h (_S_copy_chars): Replace overloads
with constexpr-if and extend optimization to all contiguous
iterators.
* src/c++11/string-inst.cc: Extend comment.

Reviewed-by: Tomasz Kaminski <tkaminsk@redhat.com>
libstdc++-v3/include/bits/basic_string.h
libstdc++-v3/src/c++11/string-inst.cc

index 630ff1af8d3f5b6d3d25e12c9da25537b4ddd54a..9c431c765ab48d1c1e4dac1b48fbd307f5637faa 100644 (file)
@@ -473,6 +473,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
          traits_type::assign(__d, __n, __c);
       }
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
       // _S_copy_chars is a separate template to permit specialization
       // to optimize for the common case of pointers as iterators.
       template<class _Iterator>
@@ -480,31 +482,44 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
         static void
         _S_copy_chars(_CharT* __p, _Iterator __k1, _Iterator __k2)
         {
+#if __cplusplus >= 201103L
+         using _IterBase = decltype(std::__niter_base(__k1));
+         if constexpr (__or_<is_same<_IterBase, _CharT*>,
+                             is_same<_IterBase, const _CharT*>>::value)
+           _S_copy(__p, std::__niter_base(__k1), __k2 - __k1);
+#if __cpp_lib_concepts
+         else if constexpr (contiguous_iterator<_Iterator>
+                              && is_same_v<iter_value_t<_Iterator>, _CharT>)
+           {
+             const auto __d = __k2 - __k1;
+             (void) (__k1 + __d); // See P3349R1
+             _S_copy(__p, std::to_address(__k1), static_cast<size_type>(__d));
+           }
+#endif
+         else
+#endif
          for (; __k1 != __k2; ++__k1, (void)++__p)
            traits_type::assign(*__p, *__k1); // These types are off.
        }
+#pragma GCC diagnostic pop
 
-      _GLIBCXX20_CONSTEXPR
+#if __cplusplus < 201103L || defined _GLIBCXX_DEFINING_STRING_INSTANTIATIONS
       static void
-      _S_copy_chars(_CharT* __p, iterator __k1, iterator __k2) _GLIBCXX_NOEXCEPT
+      _S_copy_chars(_CharT* __p, iterator __k1, iterator __k2)
       { _S_copy_chars(__p, __k1.base(), __k2.base()); }
 
-      _GLIBCXX20_CONSTEXPR
       static void
       _S_copy_chars(_CharT* __p, const_iterator __k1, const_iterator __k2)
-      _GLIBCXX_NOEXCEPT
       { _S_copy_chars(__p, __k1.base(), __k2.base()); }
 
-      _GLIBCXX20_CONSTEXPR
       static void
-      _S_copy_chars(_CharT* __p, _CharT* __k1, _CharT* __k2) _GLIBCXX_NOEXCEPT
+      _S_copy_chars(_CharT* __p, _CharT* __k1, _CharT* __k2)
       { _S_copy(__p, __k1, __k2 - __k1); }
 
-      _GLIBCXX20_CONSTEXPR
       static void
       _S_copy_chars(_CharT* __p, const _CharT* __k1, const _CharT* __k2)
-      _GLIBCXX_NOEXCEPT
       { _S_copy(__p, __k1, __k2 - __k1); }
+#endif
 
 #if __glibcxx_containers_ranges // C++ >= 23
       // pre: __n == ranges::distance(__rg). __p+[0,__n) is a valid range.
index c4864794d40b476dfebc05931216ff6ae5042fd4..34df909b31a2012f90632c192e35243c043d7ff0 100644 (file)
@@ -40,7 +40,8 @@
 // replaced by constrained function templates, so that we instantiate the
 // pre-C++17 definitions.
 // This also causes the instantiation of the non-standard C++0x-era
-// insert(iterator, initializer_list<C>) overload, see PR libstdc++/83328
+// insert(iterator, initializer_list<C>) overload, see PR libstdc++/83328,
+// and overloads of _S_copy_chars for string iterators and pointers.
 #define _GLIBCXX_DEFINING_STRING_INSTANTIATIONS 1
 
 #include <string>