Index: include/string =================================================================== --- include/string +++ include/string @@ -960,13 +960,17 @@ void resize(size_type __n, value_type __c); _LIBCPP_INLINE_VISIBILITY void resize(size_type __n) {resize(__n, value_type());} +#if !defined(_LIBCPP_BUILDING_LIBRARY) + _LIBCPP_INLINE_VISIBILITY +#endif void reserve(size_type __res_arg); + _LIBCPP_INLINE_VISIBILITY void __request_capacity(size_type __capacity_arg); _LIBCPP_INLINE_VISIBILITY void __resize_default_init(size_type __n); _LIBCPP_INLINE_VISIBILITY - void reserve() _NOEXCEPT {reserve(0);} + void reserve() _NOEXCEPT {shrink_to_fit();} _LIBCPP_INLINE_VISIBILITY - void shrink_to_fit() _NOEXCEPT {reserve();} + void shrink_to_fit() _NOEXCEPT {__request_capacity(0);} _LIBCPP_INLINE_VISIBILITY void clear() _NOEXCEPT; _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY @@ -3136,20 +3140,35 @@ } template +#if !defined(_LIBCPP_BUILDING_LIBRARY) +inline +#endif void basic_string<_CharT, _Traits, _Allocator>::reserve(size_type __res_arg) { - if (__res_arg > max_size()) +#if _LIBCPP_STD_VER > 17 + size_type __cap = capacity(); + if (__res_arg <= __cap) + return; +#endif + __request_capacity(__res_arg); +} + +template +inline void +basic_string<_CharT, _Traits, _Allocator>::__request_capacity(size_type __capacity_arg) +{ + if (__capacity_arg > max_size()) this->__throw_length_error(); size_type __cap = capacity(); size_type __sz = size(); - __res_arg = _VSTD::max(__res_arg, __sz); - __res_arg = __recommend(__res_arg); - if (__res_arg != __cap) + __capacity_arg = _VSTD::max(__capacity_arg, __sz); + __capacity_arg = __recommend(__capacity_arg); + if (__capacity_arg != __cap) { pointer __new_data, __p; bool __was_long, __now_long; - if (__res_arg == __min_cap - 1) + if (__capacity_arg == __min_cap - 1) { __was_long = true; __now_long = false; @@ -3158,15 +3177,15 @@ } else { - if (__res_arg > __cap) - __new_data = __alloc_traits::allocate(__alloc(), __res_arg+1); + if (__capacity_arg > __cap) + __new_data = __alloc_traits::allocate(__alloc(), __capacity_arg+1); else { #ifndef _LIBCPP_NO_EXCEPTIONS try { #endif // _LIBCPP_NO_EXCEPTIONS - __new_data = __alloc_traits::allocate(__alloc(), __res_arg+1); + __new_data = __alloc_traits::allocate(__alloc(), __capacity_arg+1); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) @@ -3188,7 +3207,7 @@ __alloc_traits::deallocate(__alloc(), __p, __cap+1); if (__now_long) { - __set_long_cap(__res_arg+1); + __set_long_cap(__capacity_arg+1); __set_long_size(__sz); __set_long_pointer(__new_data); } Index: test/std/strings/basic.string/string.capacity/reserve.pass.cpp =================================================================== --- test/std/strings/basic.string/string.capacity/reserve.pass.cpp +++ test/std/strings/basic.string/string.capacity/reserve.pass.cpp @@ -30,6 +30,10 @@ assert(s == s0); assert(s.capacity() <= old_cap); assert(s.capacity() >= s.size()); +#if TEST_STD_VER > 17 + // reserve never shrinks as of P0966 + assert(s.capacity() == old_cap); +#endif } template @@ -46,7 +50,9 @@ assert(s.capacity() >= res_arg); assert(s.capacity() >= s.size()); #if TEST_STD_VER > 17 - assert(s.capacity() >= old_cap); // resize never shrinks as of P0966 + // reserve never shrinks as of P0966 + if (res_arg <= old_cap) + assert(s.capacity() == old_cap); #endif } #ifndef TEST_HAS_NO_EXCEPTIONS @@ -97,6 +103,24 @@ test(s, 1000); test(s, S::npos); } + { + S s; + test(s, 50); + test(s, 10); + test(s, 5); + } +#if TEST_STD_VER > 17 + { + S s; + s.reserve(100); + typename S::size_type old_cap = s.capacity(); + s.reserve(5); + // reserve never shrinks as of P0966 + assert(s.capacity() == old_cap); + s.reserve(old_cap - 1); + assert(s.capacity() == old_cap); + } +#endif } #if TEST_STD_VER >= 11 { @@ -129,6 +153,24 @@ test(s, 1000); test(s, S::npos); } + { + S s; + test(s, 50); + test(s, 10); + test(s, 5); + } +#if TEST_STD_VER > 17 + { + S s; + s.reserve(100); + typename S::size_type old_cap = s.capacity(); + s.reserve(5); + // reserve never shrinks as of P0966 + assert(s.capacity() == old_cap); + s.reserve(old_cap - 1); + assert(s.capacity() == old_cap); + } +#endif } #endif }