diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -985,6 +985,17 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void resize(size_type __n) {resize(__n, value_type());} _LIBCPP_CONSTEXPR_AFTER_CXX17 void reserve(size_type __requested_capacity); + +#if _LIBCPP_STD_VER > 20 + template + _LIBCPP_HIDE_FROM_ABI constexpr void resize_and_overwrite(size_type __n, _Operation __op) + requires requires(_Operation __o) { {__o(pointer{}, size_type{})} -> _VSTD::convertible_to; } { + if (__n > capacity()) + __shrink_or_extend(__recommend(__n)); + __erase_to_end(__op(data(), __n)); + } +#endif + _LIBCPP_INLINE_VISIBILITY void __resize_default_init(size_type __n); _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_INLINE_VISIBILITY void reserve() _NOEXCEPT {shrink_to_fit();} diff --git a/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// void resize_and_overwrite(size_type n, Operation op) + +#include +#include + +template +constexpr void test_exact_size(S s) { + S s2; + s2.resize_and_overwrite(s.size() * 2, [&](char* begin, size_t size) { + assert(size == s.size() * 2); + std::copy(s.begin(), s.end(), begin); + std::copy(s.begin(), s.end(), begin + s.size()); + return s.size() * 2; + }); + assert(s2 == s + s); +} + +template +constexpr void test_oversized(S s) { + S s2; + s2.resize_and_overwrite(s.size() * 3, [&](char* begin, size_t size) { + assert(size == s.size() * 3); + std::copy(s.begin(), s.end(), begin); + std::copy(s.begin(), s.end(), begin + s.size()); + return s.size() * 2; + }); + assert(s2.size() == s.size() * 2); + assert(s2.capacity() >= s.size() * 3); + assert(s2 == s + s); +} + +template +constexpr void test_undersized(S s) { + S s2; + s2.resize_and_overwrite(s.size() + s.size() / 2, [&](char* begin, size_t size) { + assert(size == s.size() + s.size() / 2); + std::copy(s.begin(), s.end(), begin); + std::copy(s.begin(), s.begin() + s.size() / 2, begin + s.size()); + return size; + }); + assert(s2 == s + s.substr(0, s.size() / 2)); +} + +template +constexpr void test_all(S s) { + test_exact_size(s); + test_oversized(s); + test_undersized(s); +} + +constexpr bool test() { + using S = std::string; + test_all(""); + test_all("Banane"); + test_all("a+sgpion"); + test_all("dafgiudpfm12"); + test_all("adfpoguharsüoginasfdü23"); + test_all("asoriübsfogiabsdfgoüif24"); + test_all("long long string so no SSO"); + test_all("pioegarsipasngipnadfgipkonadfpioknadfgöpaionge48"); + return true; +} + +int main() { + test(); + static_assert(test()); +}