diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -333,6 +333,9 @@ constexpr bool contains(charT c) const noexcept; // C++2b constexpr bool contains(const charT* s) const; // C++2b + template + constexpr void resize_and_overwrite(size_type n, Operation op); // since C++23 + bool __invariants() const; }; @@ -985,7 +988,18 @@ _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); - _LIBCPP_INLINE_VISIBILITY void __resize_default_init(size_type __n); + +#if _LIBCPP_STD_VER > 20 + template + _LIBCPP_HIDE_FROM_ABI constexpr + void resize_and_overwrite(size_type __n, _Op __op) { + __resize_default_init(__n); + auto __data = data(); + __erase_to_end(_VSTD::move(__op)(__data, __n)); + } +#endif + + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void __resize_default_init(size_type __n); _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_INLINE_VISIBILITY void reserve() _NOEXCEPT {shrink_to_fit();} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void shrink_to_fit() _NOEXCEPT; @@ -1050,7 +1064,7 @@ _LIBCPP_CONSTEXPR_AFTER_CXX17 basic_string& append(const value_type* __s); _LIBCPP_CONSTEXPR_AFTER_CXX17 basic_string& append(size_type __n, value_type __c); - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void __append_default_init(size_type __n); template @@ -2748,7 +2762,7 @@ } template -inline void +inline void _LIBCPP_CONSTEXPR_AFTER_CXX17 basic_string<_CharT, _Traits, _Allocator>::__append_default_init(size_type __n) { if (__n) @@ -3478,7 +3492,7 @@ } template -inline void +inline void _LIBCPP_CONSTEXPR_AFTER_CXX17 basic_string<_CharT, _Traits, _Allocator>::__resize_default_init(size_type __n) { size_type __sz = size(); 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,98 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// void resize_and_overwrite(size_type n, Operation op) + +#include +#include + +#include "make_string.h" +#include "test_macros.h" + +template +constexpr void test_appending(size_t k, size_t N, size_t resizeSize) { + assert(N > k); + assert(resizeSize >= N); + auto s = S(k, 'a'); + s.resize_and_overwrite(resizeSize, [&](auto* p, auto n) { + assert(n == resizeSize); + LIBCPP_ASSERT(s.size() == resizeSize); + LIBCPP_ASSERT(s.begin().base() == p); + assert(std::all_of(p, p + k, [](const auto ch) { return ch == 'a'; })); + std::fill(p + k, p + n, 'b'); + p[n] = 'c'; // will be overwritten + return N; + }); + const auto expected = S(k, 'a') + S(N - k, 'b'); + assert(s == expected); +} + +template +constexpr void test_truncating(size_t o, size_t N) { + assert(N < o); + auto s = S(o, 'a'); + s.resize_and_overwrite(N, [&](auto* p, auto n) { + assert(n == N); + LIBCPP_ASSERT(s.size() == n); + LIBCPP_ASSERT(s.begin().base() == p); + assert(std::all_of(p, p + n, [](const auto ch) { return ch == 'a'; })); + p[n - 1] = 'b'; + p[n] = 'c'; // will be overwritten + return n; + }); + const auto expected = S(N - 1, 'a') + S(1, 'b'); + assert(s == expected); +} + +template +constexpr bool test() { + using S = std::basic_string; + test_appending(10, 15, 15); + test_appending(10, 15, 20); + test_appending(10, 40, 40); + test_appending(10, 40, 50); + test_appending(30, 35, 35); + test_appending(30, 35, 45); + test_truncating(15, 10); + test_truncating(40, 35); + test_truncating(40, 10); + + return true; +} + +void test_value_categories() { + std::string s; + s.resize_and_overwrite(10, [](char*&, size_t&) { return 0; }); + struct RefQualified { + int operator()(char*, size_t) && { return 0; } + }; + s.resize_and_overwrite(10, RefQualified{}); +} + +int main(int, char**) { + test(); + test(); + test(); + test(); + + static_assert(test()); + static_assert(test()); + static_assert(test()); + static_assert(test()); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); + static_assert(test()); +#endif + return 0; +}