diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -931,9 +931,11 @@ {return __is_long() ? __get_long_size() : __get_short_size();} _LIBCPP_INLINE_VISIBILITY size_type length() const _NOEXCEPT {return size();} _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT; - _LIBCPP_INLINE_VISIBILITY size_type capacity() const _NOEXCEPT - {return (__is_long() ? __get_long_cap() - : static_cast(__min_cap)) - 1;} + + _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT { + // We store the capacity including the null-terminator, but capacity() does not include the null-terminator. + return (__is_long() ? __get_long_cap() : static_cast(__min_cap)) - 1; + } void resize(size_type __n, value_type __c); _LIBCPP_INLINE_VISIBILITY void resize(size_type __n) {resize(__n, value_type());} @@ -1491,6 +1493,7 @@ void __set_size(size_type __s) _NOEXCEPT {if (__is_long()) __set_long_size(__s); else __set_short_size(__s);} + // Note that the capacity we store always includes the null-terminator. _LIBCPP_INLINE_VISIBILITY void __set_long_cap(size_type __s) _NOEXCEPT {__r_.first().__l.__cap_ = __long_mask | __s;} @@ -1533,15 +1536,19 @@ size_type __align_it(size_type __s) _NOEXCEPT {return (__s + (__a-1)) & ~(__a-1);} enum {__alignment = 16}; + + // Returns the recommended capacity to store a string of size __s, *including* the null-terminator + // Note that, unlike __recommend(), basic_string::capacity() returns the capacity *excluding* the null-terminator static _LIBCPP_INLINE_VISIBILITY size_type __recommend(size_type __s) _NOEXCEPT - { - if (__s < __min_cap) return static_cast(__min_cap) - 1; - size_type __guess = __align_it (__s+1) - 1; - if (__guess == __min_cap) ++__guess; + { + if (__s < __min_cap) + return static_cast(__min_cap); + size_type __guess = __align_it(__s + 1); + if (__guess == __min_cap + 1) + ++__guess; return __guess; - } + } inline void __init(const value_type* __s, size_type __sz, size_type __reserve); @@ -1834,9 +1841,9 @@ else { size_type __cap = __recommend(__reserve); - __p = __alloc_traits::allocate(__alloc(), __cap+1); + __p = __alloc_traits::allocate(__alloc(), __cap); __set_long_pointer(__p); - __set_long_cap(__cap+1); + __set_long_cap(__cap); __set_long_size(__sz); } traits_type::copy(_VSTD::__to_address(__p), __s, __sz); @@ -1858,9 +1865,9 @@ else { size_type __cap = __recommend(__sz); - __p = __alloc_traits::allocate(__alloc(), __cap+1); + __p = __alloc_traits::allocate(__alloc(), __cap); __set_long_pointer(__p); - __set_long_cap(__cap+1); + __set_long_cap(__cap); __set_long_size(__sz); } traits_type::copy(_VSTD::__to_address(__p), __s, __sz); @@ -1933,9 +1940,9 @@ if (__sz > max_size()) __throw_length_error(); size_t __cap = __recommend(__sz); - __p = __alloc_traits::allocate(__alloc(), __cap + 1); + __p = __alloc_traits::allocate(__alloc(), __cap); __set_long_pointer(__p); - __set_long_cap(__cap + 1); + __set_long_cap(__cap); __set_long_size(__sz); } traits_type::copy(_VSTD::__to_address(__p), __s, __sz + 1); @@ -1997,9 +2004,9 @@ else { size_type __cap = __recommend(__n); - __p = __alloc_traits::allocate(__alloc(), __cap+1); + __p = __alloc_traits::allocate(__alloc(), __cap); __set_long_pointer(__p); - __set_long_cap(__cap+1); + __set_long_cap(__cap); __set_long_size(__n); } traits_type::assign(_VSTD::__to_address(__p), __n, __c); @@ -2128,9 +2135,9 @@ else { size_type __cap = __recommend(__sz); - __p = __alloc_traits::allocate(__alloc(), __cap+1); + __p = __alloc_traits::allocate(__alloc(), __cap); __set_long_pointer(__p); - __set_long_cap(__cap+1); + __set_long_cap(__cap); __set_long_size(__sz); } @@ -2222,7 +2229,7 @@ size_type __cap = __old_cap < __ms / 2 - __alignment ? __recommend(_VSTD::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; - pointer __p = __alloc_traits::allocate(__alloc(), __cap+1); + pointer __p = __alloc_traits::allocate(__alloc(), __cap); __invalidate_all_iterators(); if (__n_copy != 0) traits_type::copy(_VSTD::__to_address(__p), @@ -2236,7 +2243,7 @@ if (__old_cap+1 != __min_cap) __alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1); __set_long_pointer(__p); - __set_long_cap(__cap+1); + __set_long_cap(__cap); __old_sz = __n_copy + __n_add + __sec_cp_sz; __set_long_size(__old_sz); traits_type::assign(__p[__old_sz], value_type()); @@ -2254,7 +2261,7 @@ size_type __cap = __old_cap < __ms / 2 - __alignment ? __recommend(_VSTD::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1; - pointer __p = __alloc_traits::allocate(__alloc(), __cap+1); + pointer __p = __alloc_traits::allocate(__alloc(), __cap); __invalidate_all_iterators(); if (__n_copy != 0) traits_type::copy(_VSTD::__to_address(__p), @@ -2267,7 +2274,7 @@ if (__old_cap+1 != __min_cap) __alloc_traits::deallocate(__alloc(), __old_p, __old_cap+1); __set_long_pointer(__p); - __set_long_cap(__cap+1); + __set_long_cap(__cap); } // assign @@ -3236,7 +3243,8 @@ size_type __target_capacity = _VSTD::max(__requested_capacity, size()); __target_capacity = __recommend(__target_capacity); - if (__target_capacity == capacity()) return; + if (__target_capacity == capacity() + 1) // __recommend() includes the null-terminator, while capacity() doesn't + return; __shrink_or_extend(__target_capacity); } @@ -3247,7 +3255,8 @@ basic_string<_CharT, _Traits, _Allocator>::shrink_to_fit() _NOEXCEPT { size_type __target_capacity = __recommend(size()); - if (__target_capacity == capacity()) return; + if (__target_capacity == capacity() + 1) // __recommend() includes the null-terminator, while capacity() doesn't + return; __shrink_or_extend(__target_capacity); } @@ -3262,7 +3271,7 @@ pointer __new_data, __p; bool __was_long, __now_long; - if (__target_capacity == __min_cap - 1) + if (__target_capacity == __min_cap) { __was_long = true; __now_long = false; @@ -3272,14 +3281,14 @@ else { if (__target_capacity > __cap) - __new_data = __alloc_traits::allocate(__alloc(), __target_capacity+1); + __new_data = __alloc_traits::allocate(__alloc(), __target_capacity); else { #ifndef _LIBCPP_NO_EXCEPTIONS try { #endif // _LIBCPP_NO_EXCEPTIONS - __new_data = __alloc_traits::allocate(__alloc(), __target_capacity+1); + __new_data = __alloc_traits::allocate(__alloc(), __target_capacity); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) @@ -3301,7 +3310,7 @@ __alloc_traits::deallocate(__alloc(), __p, __cap+1); if (__now_long) { - __set_long_cap(__target_capacity+1); + __set_long_cap(__target_capacity); __set_long_size(__sz); __set_long_pointer(__new_data); }