diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -3276,9 +3276,11 @@ basic_string<_CharT, _Traits, _Allocator>::resize(size_type __n, value_type __c) { size_type __sz = size(); - if (__n > __sz) + if (__n > __sz) { + if (__n > capacity()) + __shrink_or_extend(__recommend(__n)); append(__n - __sz, __c); - else + } else __erase_to_end(__n); } @@ -3288,7 +3290,9 @@ { size_type __sz = size(); if (__n > __sz) { - __append_default_init(__n - __sz); + if (__n > capacity()) + __shrink_or_extend(__recommend(__n)); + __append_default_init(__n - __sz); } else __erase_to_end(__n); } diff --git a/libcxx/test/libcxx/strings/basic.string/string.capacity/resize.exact.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.capacity/resize.exact.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/strings/basic.string/string.capacity/resize.exact.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// void resize(size_type); + +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" + +bool is_between(size_t c, size_t low, size_t hi) { return c >= low && c <= hi; } + +// basic_string uses buffers whose lengths are multiples of this alignment. +template +size_t GetBufferAlign() { + const size_t kSsoSize = S().capacity(); + S s; + s.reserve(kSsoSize + 1); + const size_t prev_cap = s.capacity(); + s.reserve(prev_cap + 1); + return s.capacity() - prev_cap; +} + +template +void test() { + // Tests that resize() uses exact growth rather than exponential growth. + const size_t kSsoSize = S().capacity(); + const size_t kAlign = GetBufferAlign(); + for (size_t i = kSsoSize + 1; i < 1024; ++i) { + S s; + s.resize(i); + assert(s.size() == i); + assert(is_between(s.capacity(), i, i + kAlign)); + } + for (size_t i = kSsoSize + 1; i < 1024; ++i) { + S s; + for (size_t j = 0; j < i; ++j) { + s.push_back(typename S::value_type()); + } + assert(s.size() == i); + const size_t prev_cap = s.capacity(); + s.resize(prev_cap + 10); + assert(is_between(s.capacity(), prev_cap + 10, prev_cap + 10 + kAlign)); + } +} + +int main(int, char**) { + { + typedef std::string S; + test(); + } + { + typedef std::wstring S; + test(); + } +#if TEST_STD_VER >= 11 + { + typedef min_allocator A; + typedef std::basic_string, A> S; + test(); + } +#endif + + return 0; +}