diff --git a/libcxx/include/__memory/allocate_at_least.h b/libcxx/include/__memory/allocate_at_least.h index 9b5a8bcbd4596..72140d0de27af 100644 --- a/libcxx/include/__memory/allocate_at_least.h +++ b/libcxx/include/__memory/allocate_at_least.h @@ -19,26 +19,31 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +struct __allocation_result { + _Pointer ptr; + _SizeT count; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __allocation_result(_Pointer __ptr, _SizeT __count) + : ptr(__ptr), count(__count) {} +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__allocation_result); + #if _LIBCPP_STD_VER >= 23 template [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto __allocate_at_least(_Alloc& __alloc, size_t __n) { - return std::allocator_traits<_Alloc>::allocate_at_least(__alloc, __n); + auto __res = std::allocator_traits<_Alloc>::allocate_at_least(__alloc, __n); + return __allocation_result{__res.ptr, __res.count}; } #else -template -struct __allocation_result { - _Pointer ptr; - size_t count; -}; - -template +template > [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI -_LIBCPP_CONSTEXPR __allocation_result::pointer> +_LIBCPP_CONSTEXPR __allocation_result __allocate_at_least(_Alloc& __alloc, size_t __n) { - return {__alloc.allocate(__n), __n}; + return __allocation_result(__alloc.allocate(__n), __n); } #endif // _LIBCPP_STD_VER >= 23 diff --git a/libcxx/include/string b/libcxx/include/string index f13a7640760f7..daa25d30ff969 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -818,12 +818,21 @@ public: using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; + using __alloc_result _LIBCPP_NODEBUG = __allocation_result; + private: static_assert(CHAR_BIT == 8, "This implementation assumes that one byte contains 8 bits"); # ifdef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT struct __long { + __long() = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __long(__alloc_result __alloc, size_type __size) + : __data_(__alloc.ptr), __size_(__size), __cap_(__alloc.count / __endian_factor), __is_long_(true) { + _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__alloc.count), "Long capacity should always be larger than the SSO"); + } + pointer __data_; size_type __size_; size_type __cap_ : sizeof(size_type) * CHAR_BIT - 1; @@ -871,6 +880,13 @@ private: // some platforms bit fields have a default size rather than the actual // size used, e.g., it is 4 bytes on AIX. See D128285 for details. struct __long { + __long() = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __long(__alloc_result __alloc, size_type __size) + : __is_long_(true), __cap_(__alloc.count / __endian_factor), __size_(__size), __data_(__alloc.ptr) { + _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__alloc.count), "Long capacity should always be larger than the SSO"); + } + struct _LIBCPP_PACKED { size_type __is_long_ : 1; size_type __cap_ : sizeof(size_type) * CHAR_BIT - 1; @@ -916,20 +932,7 @@ private: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string( __uninitialized_size_tag, size_type __size, const allocator_type& __a) : __alloc_(__a) { - if (__size > max_size()) - this->__throw_length_error(); - if (__fits_in_sso(__size)) { - __rep_ = __rep(); - __set_short_size(__size); - } else { - auto __capacity = __recommend(__size) + 1; - auto __allocation = __alloc_traits::allocate(__alloc_, __capacity); - __begin_lifetime(__allocation, __capacity); - __set_long_cap(__capacity); - __set_long_pointer(__allocation); - __set_long_size(__size); - } - __annotate_new(__size); + __init_internal_buffer(__size); } template @@ -1202,11 +1205,7 @@ public: } # endif // _LIBCPP_CXX03_LANG - inline _LIBCPP_CONSTEXPR_SINCE_CXX20 ~basic_string() { - __annotate_delete(); - if (__is_long()) - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); - } + inline _LIBCPP_CONSTEXPR_SINCE_CXX20 ~basic_string() { __reset_internal_buffer(); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 operator __self_view() const _NOEXCEPT { return __self_view(typename __self_view::__assume_valid(), data(), size()); @@ -2109,18 +2108,6 @@ private: return __rep_.__s.__is_long_; } - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __begin_lifetime(pointer __begin, size_type __n) { -# if _LIBCPP_STD_VER >= 20 - if (__libcpp_is_constant_evaluated()) { - for (size_type __i = 0; __i != __n; ++__i) - std::construct_at(std::addressof(__begin[__i])); - } -# else - (void)__begin; - (void)__n; -# endif // _LIBCPP_STD_VER >= 20 - } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI static bool __fits_in_sso(size_type __sz) { return __sz < __min_cap; } template @@ -2179,6 +2166,9 @@ private: _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator __insert_with_size(const_iterator __pos, _Iterator __first, _Sentinel __last, size_type __n); + // internal buffer accessors + // ------------------------- + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS void __set_short_size(size_type __s) _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL(__s < __min_cap, "__s should never be greater than or equal to the short string capacity"); @@ -2208,21 +2198,11 @@ private: __set_short_size(__s); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_cap(size_type __s) _NOEXCEPT { - _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__s), "Long capacity should always be larger than the SSO"); - __rep_.__l.__cap_ = __s / __endian_factor; - __rep_.__l.__is_long_ = true; - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __get_long_cap() const _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long capacity"); return __rep_.__l.__cap_ * __endian_factor; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_pointer(pointer __p) _NOEXCEPT { - __rep_.__l.__data_ = __p; - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_long_pointer() _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long pointer"); return _LIBCPP_ASAN_VOLATILE_WRAPPER(__rep_.__l.__data_); @@ -2250,6 +2230,62 @@ private: return __is_long() ? __get_long_pointer() : __get_short_pointer(); } + // Internal buffer management + // -------------------------- + // + // These functions are only responsible for managing the buffer itself, not the value inside the buffer. As such, + // none of these facilities ensure that there is a null terminator at `data()[size()]`. + + // Allocate a buffer of __capacity size with __alloc and return it + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 __long + __allocate_long_buffer(_Allocator& __alloc, size_type __capacity) { + auto __buffer = std::__allocate_at_least(__alloc, __recommend(__capacity) + 1); + + if (__libcpp_is_constant_evaluated()) { + for (size_type __i = 0; __i != __buffer.count; ++__i) + std::__construct_at(std::addressof(__buffer.ptr[__i])); + } + + return __long(__buffer, __capacity); + } + + // Deallocate the long buffer if it exists and clear the short buffer so we are an empty string + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __reset_internal_buffer() { + __annotate_delete(); + if (__is_long()) + __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); + __rep_.__s = __short(); + } + + // Replace the current buffer with __alloc; the first __size elements constitute a string + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __replace_internal_buffer(__long __alloc) { + __reset_internal_buffer(); + __rep_.__l = __alloc; + } + + // Initialize the internal buffer to hold __size elements + // The elements and null terminator have to be set by the caller + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __init_internal_buffer(size_type __size) { + if (__libcpp_is_constant_evaluated()) + __rep_ = __rep(); + + if (__size > max_size()) + __throw_length_error(); + + if (__fits_in_sso(__size)) { + __set_short_size(__size); + __annotate_new(__size); + return __get_short_pointer(); + } else { + __rep_.__l = __allocate_long_buffer(__alloc_, __size); + __annotate_new(__size); + return __get_long_pointer(); + } + } + + // ASan annotation helpers + // ----------------------- + // The following functions are no-ops outside of AddressSanitizer mode. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_contiguous_container(const void* __old_mid, const void* __new_mid) const { @@ -2392,24 +2428,14 @@ private: __alloc_ = __str.__alloc_; else { if (!__str.__is_long()) { - if (__is_long()) { - __annotate_delete(); - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); - __rep_ = __rep(); - } + __reset_internal_buffer(); __alloc_ = __str.__alloc_; } else { __annotate_delete(); - auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); - allocator_type __a = __str.__alloc_; - auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap()); - __begin_lifetime(__allocation.ptr, __allocation.count); - if (__is_long()) - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); - __alloc_ = std::move(__a); - __set_long_pointer(__allocation.ptr); - __set_long_cap(__allocation.count); - __set_long_size(__str.__get_long_size()); + auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); + auto __alloc = __str.__alloc_; + __replace_internal_buffer(__allocate_long_buffer(__alloc, __str.size())); + __alloc_ = std::move(__alloc); } } } @@ -2572,73 +2598,23 @@ basic_string(from_range_t, _Range&&, _Allocator = _Allocator()) template _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz) { - if (__libcpp_is_constant_evaluated()) - __rep_ = __rep(); - if (__sz > max_size()) - this->__throw_length_error(); - pointer __p; - if (__fits_in_sso(__sz)) { - __set_short_size(__sz); - __p = __get_short_pointer(); - } else { - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__sz) + 1); - __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __set_long_size(__sz); - } + pointer __p = __init_internal_buffer(__sz); traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); - __annotate_new(__sz); } template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(const value_type* __s, size_type __sz) { - if (__libcpp_is_constant_evaluated()) - __rep_ = __rep(); - - pointer __p; - if (__fits_in_sso(__sz)) { - __p = __get_short_pointer(); - __set_short_size(__sz); - } else { - if (__sz > max_size()) - this->__throw_length_error(); - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__sz) + 1); - __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __set_long_size(__sz); - } + pointer __p = __init_internal_buffer(__sz); traits_type::copy(std::__to_address(__p), __s, __sz + 1); - __annotate_new(__sz); } template _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c) { - if (__libcpp_is_constant_evaluated()) - __rep_ = __rep(); - - if (__n > max_size()) - this->__throw_length_error(); - pointer __p; - if (__fits_in_sso(__n)) { - __set_short_size(__n); - __p = __get_short_pointer(); - } else { - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__n) + 1); - __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __set_long_size(__n); - } + pointer __p = __init_internal_buffer(__n); traits_type::assign(std::__to_address(__p), __n, __c); traits_type::assign(__p[__n], value_type()); - __annotate_new(__n); } template @@ -2662,9 +2638,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputIterator _ push_back(*__first); # if _LIBCPP_HAS_EXCEPTIONS } catch (...) { - __annotate_delete(); - if (__is_long()) - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); + __reset_internal_buffer(); throw; } # endif // _LIBCPP_HAS_EXCEPTIONS @@ -2682,25 +2656,7 @@ template template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init_with_size(_InputIterator __first, _Sentinel __last, size_type __sz) { - if (__libcpp_is_constant_evaluated()) - __rep_ = __rep(); - - if (__sz > max_size()) - this->__throw_length_error(); - - pointer __p; - if (__fits_in_sso(__sz)) { - __set_short_size(__sz); - __p = __get_short_pointer(); - - } else { - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__sz) + 1); - __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __set_long_size(__sz); - } + pointer __p = __init_internal_buffer(__sz); # if _LIBCPP_HAS_EXCEPTIONS try { @@ -2709,12 +2665,10 @@ basic_string<_CharT, _Traits, _Allocator>::__init_with_size(_InputIterator __fir traits_type::assign(*__end, value_type()); # if _LIBCPP_HAS_EXCEPTIONS } catch (...) { - if (__is_long()) - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); + __reset_internal_buffer(); throw; } # endif // _LIBCPP_HAS_EXCEPTIONS - __annotate_new(__sz); } template @@ -2733,25 +2687,20 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__ size_type __cap = __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms; __annotate_delete(); - auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); - auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1); - pointer __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); + auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); + __long __buffer = __allocate_long_buffer(__alloc_, __cap); if (__n_copy != 0) - traits_type::copy(std::__to_address(__p), std::__to_address(__old_p), __n_copy); + traits_type::copy(std::__to_address(__buffer.__data_), std::__to_address(__old_p), __n_copy); if (__n_add != 0) - traits_type::copy(std::__to_address(__p) + __n_copy, __p_new_stuff, __n_add); + traits_type::copy(std::__to_address(__buffer.__data_) + __n_copy, __p_new_stuff, __n_add); 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 (__old_cap + 1 != __min_cap) - __alloc_traits::deallocate(__alloc_, __old_p, __old_cap + 1); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __old_sz = __n_copy + __n_add + __sec_cp_sz; - __set_long_size(__old_sz); - traits_type::assign(__p[__old_sz], value_type()); + traits_type::copy(std::__to_address(__buffer.__data_) + __n_copy + __n_add, + std::__to_address(__old_p) + __n_copy + __n_del, + __sec_cp_sz); + __buffer.__size_ = __n_copy + __n_add + __sec_cp_sz; + traits_type::assign(__buffer.__data_[__buffer.__size_], value_type()); + __replace_internal_buffer(__buffer); } // __grow_by is deprecated because it does not set the size. It may not update the size when the size is changed, and it @@ -2775,19 +2724,19 @@ _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Trait pointer __old_p = __get_pointer(); size_type __cap = __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms; - auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1); - pointer __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); + __long __buffer = __allocate_long_buffer(__alloc_, __cap); if (__n_copy != 0) - traits_type::copy(std::__to_address(__p), std::__to_address(__old_p), __n_copy); + traits_type::copy(std::__to_address(__buffer.__data_), 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 (__old_cap + 1 != __min_cap) - __alloc_traits::deallocate(__alloc_, __old_p, __old_cap + 1); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); + traits_type::copy(std::__to_address(__buffer.__data_) + __n_copy + __n_add, + std::__to_address(__old_p) + __n_copy + __n_del, + __sec_cp_sz); + + // This is -1 to make sure the caller sets the size properly, since old versions of this function didn't set the size + // at all. + __buffer.__size_ = -1; + __replace_internal_buffer(__buffer); } template @@ -2804,6 +2753,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace( _LIBCPP_SUPPRESS_DEPRECATED_PUSH __grow_by(__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add); _LIBCPP_SUPPRESS_DEPRECATED_POP + // Due to the ABI of __grow_by we have to set the size after calling it. __set_long_size(__old_sz - __n_del + __n_add); } @@ -2938,7 +2888,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr { __annotate_delete(); if (__is_long()) { - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); + __reset_internal_buffer(); # if _LIBCPP_STD_VER <= 14 if (!is_nothrow_move_assignable::value) { __set_short_size(0); @@ -3457,15 +3407,10 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re return; __annotation_guard __g(*this); - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__requested_capacity) + 1); - auto __size = size(); - __begin_lifetime(__allocation.ptr, __allocation.count); - traits_type::copy(std::__to_address(__allocation.ptr), data(), __size + 1); - if (__is_long()) - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); - __set_long_cap(__allocation.count); - __set_long_size(__size); - __set_long_pointer(__allocation.ptr); + __long __buffer = __allocate_long_buffer(__alloc_, __requested_capacity); + __buffer.__size_ = size(); + traits_type::copy(std::__to_address(__buffer.__data_), data(), __buffer.__size_ + 1); + __replace_internal_buffer(__buffer); } template @@ -3493,21 +3438,18 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat try { # endif // _LIBCPP_HAS_EXCEPTIONS __annotation_guard __g(*this); - auto __allocation = std::__allocate_at_least(__alloc_, __target_capacity + 1); + __long __buffer = __allocate_long_buffer(__alloc_, __size); // The Standard mandates shrink_to_fit() does not increase the capacity. // With equal capacity keep the existing buffer. This avoids extra work // due to swapping the elements. - if (__allocation.count - 1 >= capacity()) { - __alloc_traits::deallocate(__alloc_, __allocation.ptr, __allocation.count); + if (__buffer.__cap_ * __endian_factor - 1 >= capacity()) { + __alloc_traits::deallocate(__alloc_, __buffer.__data_, __buffer.__cap_ * __endian_factor); return; } - __begin_lifetime(__allocation.ptr, __allocation.count); - traits_type::copy(std::__to_address(__allocation.ptr), std::__to_address(__ptr), __size + 1); - __alloc_traits::deallocate(__alloc_, __ptr, __cap); - __set_long_cap(__allocation.count); - __set_long_pointer(__allocation.ptr); + traits_type::copy(std::__to_address(__buffer.__data_), std::__to_address(__get_long_pointer()), __size + 1); + __replace_internal_buffer(__buffer); # if _LIBCPP_HAS_EXCEPTIONS } catch (...) { return; diff --git a/libcxx/src/string.cpp b/libcxx/src/string.cpp index 55d19a68802b5..5028fc88fe46d 100644 --- a/libcxx/src/string.cpp +++ b/libcxx/src/string.cpp @@ -42,24 +42,12 @@ void __basic_string_common::__throw_out_of_range() const { std::__throw_ou #ifndef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION +// This initializes the string with [__s, __s + __sz), but capacity() == __reserve. Assumes that __reserve >= __sz. template void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz, size_type __reserve) { - if (__libcpp_is_constant_evaluated()) - __rep_ = __rep(); - if (__reserve > max_size()) - __throw_length_error(); - pointer __p; - if (__fits_in_sso(__reserve)) { - __set_short_size(__sz); - __p = __get_short_pointer(); - } else { - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__reserve) + 1); - __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __set_long_size(__sz); - } + pointer __p = __init_internal_buffer(__reserve); + __annotate_delete(); + __set_size(__sz); traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); __annotate_new(__sz);