diff options
Diffstat (limited to 'libstdc++-v3/include/bits/basic_string.h')
| -rw-r--r-- | libstdc++-v3/include/bits/basic_string.h | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 886e7e6b19e..7670bace479 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -51,6 +51,11 @@ # include <string_view> #endif +#if __glibcxx_ranges_to_container // C++ >= 23 +# include <bits/ranges_algobase.h> // ranges::copy +# include <bits/ranges_util.h> // ranges::subrange +#endif + #if __cplusplus > 202302L # include <charconv> #endif @@ -501,6 +506,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NOEXCEPT { _S_copy(__p, __k1, __k2 - __k1); } +#if __glibcxx_ranges_to_container // C++ >= 23 + // pre: __n == ranges::distance(__rg). __p+[0,__n) is a valid range. + template<typename _Rg> + static constexpr void + _S_copy_range(pointer __p, _Rg&& __rg, size_type __n) + { + if constexpr (ranges::contiguous_range<_Rg> + && is_same_v<ranges::range_value_t<_Rg>, _CharT>) + _S_copy(__p, ranges::data(std::forward<_Rg>(__rg)), __n); + else + for (auto&& __e : __rg) + traits_type::assign(*__p++, std::forward<decltype(__e)>(__e)); + } +#endif + _GLIBCXX20_CONSTEXPR static int _S_compare(size_type __n1, size_type __n2) _GLIBCXX_NOEXCEPT @@ -717,6 +737,33 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 __str._M_set_length(0); } +#if __glibcxx_ranges_to_container // C++ >= 23 + /** + * @brief Construct a string from a range. + * @since C++23 + */ + template<__detail::__container_compatible_range<_CharT> _Rg> + constexpr + basic_string(from_range_t, _Rg&& __rg, const _Alloc& __a = _Alloc()) + : basic_string(__a) + { + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) + { + const auto __n = static_cast<size_type>(ranges::distance(__rg)); + reserve(__n); + _S_copy_range(_M_data(), std::forward<_Rg>(__rg), __n); + _M_set_length(__n); + } + else + { + auto __first = ranges::begin(__rg); + const auto __last = ranges::end(__rg); + for (; __first != __last; ++__first) + push_back(*__first); + } + } +#endif + /** * @brief Construct string from an initializer %list. * @param __l std::initializer_list of characters. @@ -1526,6 +1573,58 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 append(size_type __n, _CharT __c) { return _M_replace_aux(this->size(), size_type(0), __n, __c); } +#if __glibcxx_ranges_to_container // C++ >= 23 + /** + * @brief Append a range to the string. + * @param __rg A range of values that are convertible to `value_type`. + * @since C++23 + * + * The range `__rg` is allowed to overlap with `*this`. + */ + template<__detail::__container_compatible_range<_CharT> _Rg> + constexpr basic_string& + append_range(_Rg&& __rg) + { + // N.B. __rg may overlap with *this, so we must copy from __rg before + // existing elements or iterators referring to *this are invalidated. + // e.g. in s.append_range(views::concat(s, str)), rg overlaps s. + if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>) + { + const auto __len = size_type(ranges::distance(__rg)); + + // Don't care if this addition wraps around, we check it below: + const size_type __newlen = size() + __len; + + if ((capacity() - size()) >= __len) + _S_copy_range(_M_data() + size(), std::forward<_Rg>(__rg), + __len); + else + { + _M_check_length(0, __len, "basic_string::append_range"); + basic_string __s(_M_get_allocator()); + __s.reserve(__newlen); + _S_copy_range(__s._M_data() + size(), std::forward<_Rg>(__rg), + __len); + _S_copy(__s._M_data(), _M_data(), size()); + if (!_M_is_local()) + _M_destroy(_M_allocated_capacity); + _M_data(__s._M_data()); + _M_capacity(__s._M_allocated_capacity); + __s._M_data(__s._M_local_data()); + __s._M_length(0); + } + _M_set_length(__newlen); // adds null-terminator + } + else + { + basic_string __s(from_range, std::forward<_Rg>(__rg), + _M_get_allocator()); + append(__s); + } + return *this; + } +#endif + #if __cplusplus >= 201103L /** * @brief Append an initializer_list of characters. @@ -1785,6 +1884,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { return this->replace(begin(), end(), __first, __last); } #endif +#if __glibcxx_ranges_to_container // C++ >= 23 + /** + * @brief Assign a range to the string. + * @param __rg A range of values that are convertible to `value_type`. + * @since C++23 + * + * The range `__rg` is allowed to overlap with `*this`. + */ + template<__detail::__container_compatible_range<_CharT> _Rg> + constexpr basic_string& + assign_range(_Rg&& __rg) + { + basic_string __s(from_range, std::forward<_Rg>(__rg), + _M_get_allocator()); + assign(std::move(__s)); + return *this; + } +#endif + #if __cplusplus >= 201103L /** * @brief Set value to an initializer_list of characters. @@ -1934,6 +2052,37 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { this->replace(__p, __p, __beg, __end); } #endif +#if __glibcxx_ranges_to_container // C++ >= 23 + /** + * @brief Insert a range into the string. + * @param __rg A range of values that are convertible to `value_type`. + * @since C++23 + * + * The range `__rg` is allowed to overlap with `*this`. + */ + template<__detail::__container_compatible_range<_CharT> _Rg> + constexpr iterator + insert_range(const_iterator __p, _Rg&& __rg) + { + auto __pos = __p - cbegin(); + + if constexpr (ranges::forward_range<_Rg>) + if (ranges::empty(__rg)) + return begin() + __pos; + + + if (__p == cend()) + append_range(std::forward<_Rg>(__rg)); + else + { + basic_string __s(from_range, std::forward<_Rg>(__rg), + _M_get_allocator()); + insert(__pos, __s); + } + return begin() + __pos; + } +#endif + #if __cplusplus >= 201103L /** * @brief Insert an initializer_list of characters. @@ -2522,6 +2671,30 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 __k1.base(), __k2 - __k1); } +#if __glibcxx_ranges_to_container // C++ >= 23 + /** + * @brief Replace part of the string with a range. + * @param __rg A range of values that are convertible to `value_type`. + * @since C++23 + * + * The range `__rg` is allowed to overlap with `*this`. + */ + template<__detail::__container_compatible_range<_CharT> _Rg> + constexpr basic_string& + replace_with_range(const_iterator __i1, const_iterator __i2, _Rg&& __rg) + { + if (__i1 == cend()) + append_range(std::forward<_Rg>(__rg)); + else + { + basic_string __s(from_range, std::forward<_Rg>(__rg), + _M_get_allocator()); + replace(__i1, __i2, __s); + } + return *this; + } +#endif + #if __cplusplus >= 201103L /** * @brief Replace range of characters with initializer_list. @@ -3599,6 +3772,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 typename basic_string<_CharT, _Traits, _Allocator>::size_type, const _Allocator& = _Allocator()) -> basic_string<_CharT, _Traits, _Allocator>; + +#if __glibcxx_ranges_to_container // C++ >= 23 + template<ranges::input_range _Rg, + typename _Allocator = allocator<ranges::range_value_t<_Rg>>> + basic_string(from_range_t, _Rg&&, _Allocator = _Allocator()) + -> basic_string<ranges::range_value_t<_Rg>, + char_traits<ranges::range_value_t<_Rg>>, + _Allocator>; +#endif _GLIBCXX_END_NAMESPACE_CXX11 #endif |
