libstdc++: Use constexpr-if for std::basic_string::_S_copy_chars

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>
This commit is contained in:
Jonathan Wakely 2025-04-10 12:21:26 +01:00 committed by Jonathan Wakely
parent ae54d8cb51
commit 648d5c26e2
No known key found for this signature in database
2 changed files with 25 additions and 9 deletions

View 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.

View 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>