diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -1725,7 +1725,7 @@ } else { - __grow_by(__cap, __sz + __n - __cap, __sz, __ip, 0, __n); + __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __ip, 0, __n); __p = std::__to_address(__get_long_pointer()); } __sz += __n; @@ -1839,9 +1839,12 @@ template ::value, int> = 0> inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void __init(_ForwardIterator __first, _ForwardIterator __last); - _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_DEPRECATED_("use __grow_by_without_replace") void __grow_by(size_type __old_cap, size_type __delta_cap, size_type __old_sz, size_type __n_copy, size_type __n_del, size_type __n_add = 0); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI + void __grow_by_without_replace(size_type __old_cap, size_type __delta_cap, size_type __old_sz, + size_type __n_copy, size_type __n_del, size_type __n_add = 0); _LIBCPP_CONSTEXPR_SINCE_CXX20 void __grow_by_and_replace(size_type __old_cap, size_type __delta_cap, size_type __old_sz, size_type __n_copy, size_type __n_del, @@ -2277,9 +2280,12 @@ traits_type::assign(__p[__old_sz], value_type()); } +// __grow_by is deprecated because it does not set size. It not only may not update when size is changed, +// but also not set size at all when string was short initially, leading to unpredictable size value. +// It is not removed or changed to avoid breaking the ABI. template void -_LIBCPP_CONSTEXPR_SINCE_CXX20 +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_type __delta_cap, size_type __old_sz, size_type __n_copy, size_type __n_del, size_type __n_add) { @@ -2308,6 +2314,38 @@ __set_long_cap(__allocation.count); } +template +void _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI +basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace( + size_type __old_cap, + size_type __delta_cap, + size_type __old_sz, + size_type __n_copy, + size_type __n_del, + size_type __n_add) { + size_type __ms = max_size(); + if (__delta_cap > __ms - __old_cap) + __throw_length_error(); + pointer __old_p = __get_pointer(); + size_type __cap = + __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; + auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1); + pointer __p = __allocation.ptr; + __begin_lifetime(__p, __allocation.count); + std::__debug_db_invalidate_all(this); + if (__n_copy != 0) + traits_type::copy(std::__to_address(__p), std::__to_address(__old_p), __n_copy); + size_type __sec_cp_sz = __old_sz - __n_del - __n_copy; + if (__sec_cp_sz != 0) + traits_type::copy( + std::__to_address(__p) + __n_copy + __n_add, std::__to_address(__old_p) + __n_copy + __n_del, __sec_cp_sz); + if (__libcpp_is_constant_evaluated() || __old_cap + 1 != __min_cap) + __alloc_traits::deallocate(__alloc(), __old_p, __old_cap + 1); + __set_long_pointer(__p); + __set_long_cap(__allocation.count); + __set_long_size(__old_sz - __n_del + __n_add); +} + // assign template @@ -2367,7 +2405,7 @@ if (__cap < __n) { size_type __sz = size(); - __grow_by(__cap, __n - __cap, __sz, 0, __sz); + __grow_by_without_replace(__cap, __n - __cap, __sz, 0, __sz); } value_type* __p = std::__to_address(__get_pointer()); traits_type::assign(__p, __n, __c); @@ -2487,7 +2525,7 @@ if (__cap < __n) { size_type __sz = size(); - __grow_by(__cap, __n - __cap, __sz, 0, __sz); + __grow_by_without_replace(__cap, __n - __cap, __sz, 0, __sz); } pointer __p = __get_pointer(); for (; __first != __last; ++__p, (void) ++__first) @@ -2584,7 +2622,7 @@ size_type __cap = capacity(); size_type __sz = size(); if (__cap - __sz < __n) - __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); pointer __p = __get_pointer(); traits_type::assign(std::__to_address(__p) + __sz, __n, __c); __sz += __n; @@ -2603,7 +2641,7 @@ size_type __cap = capacity(); size_type __sz = size(); if (__cap - __sz < __n) - __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); pointer __p = __get_pointer(); __sz += __n; __set_size(__sz); @@ -2631,7 +2669,7 @@ } if (__sz == __cap) { - __grow_by(__cap, 1, __sz, __sz, 0); + __grow_by_without_replace(__cap, 1, __sz, __sz, 0); __is_short = false; // the string is always long after __grow_by } pointer __p = __get_pointer(); @@ -2664,7 +2702,7 @@ !__addr_in_range(*__first)) { if (__cap - __sz < __n) - __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); pointer __p = __get_pointer() + __sz; for (; __first != __last; ++__p, (void) ++__first) traits_type::assign(*__p, *__first); @@ -2777,7 +2815,7 @@ } else { - __grow_by(__cap, __sz + __n - __cap, __sz, __pos, 0, __n); + __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __pos, 0, __n); __p = std::__to_address(__get_long_pointer()); } traits_type::assign(__p + __pos, __n, __c); @@ -2874,7 +2912,7 @@ value_type* __p; if (__cap == __sz) { - __grow_by(__cap, 1, __sz, __ip, 0, 1); + __grow_by_without_replace(__cap, 1, __sz, __ip, 0, 1); __p = std::__to_address(__get_long_pointer()); } else @@ -2965,7 +3003,7 @@ } else { - __grow_by(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2); + __grow_by_without_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2); __p = std::__to_address(__get_long_pointer()); } traits_type::assign(__p + __pos, __n2, __c);