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,19 @@ _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, _Operation __op) + requires requires(_Operation __o) { {__o(pointer{}, size_type{})} -> _VSTD::convertible_to; } { + if (__n > capacity()) + __resize_default_init(__n); + + __erase_to_end(__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 +1065,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 +2763,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 +3493,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,108 @@ +//===----------------------------------------------------------------------===// +// +// 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" + +template +constexpr void test_exact_size(S s, S s2) { + const auto new_size = s.size() * 2; + s2.resize_and_overwrite(new_size, [&](auto* begin, size_t size) { + assert(size == new_size); + std::copy(s.begin(), s.end(), begin); + std::copy(s.begin(), s.end(), begin + s.size()); + return new_size; + }); + assert(s2 == s + s); +} + +template +constexpr void test_oversized(S s, S s2) { + const auto new_size = s.size() * 3; + const auto actual_size = s.size() * 2; + s2.resize_and_overwrite(new_size, [&](auto* begin, size_t size) { + assert(size == new_size); + std::copy(s.begin(), s.end(), begin); + std::copy(s.begin(), s.end(), begin + s.size()); + return actual_size; + }); + assert(s2.size() == actual_size); + assert(s2.capacity() >= new_size); + assert(s2 == s + s); +} + +template +constexpr void test_undersized(S s, S s2) { + const auto new_size = s.size() + s.size() / 2; + s2.resize_and_overwrite(new_size, [&](auto* begin, size_t size) { + assert(size == new_size); + 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 s1, S s2) { + test_exact_size(s1, s2); + test_oversized(s1, s2); + test_undersized(s1, s2); +} + +template +constexpr bool test_copy_strings(S2 s) { + test_all(MAKE_STRING(S, ""), s); + test_all(MAKE_STRING(S, "Banane"), s); + test_all(MAKE_STRING(S, "a+sgpion"), s); + test_all(MAKE_STRING(S, "dafgiudpfm12"), s); + test_all(MAKE_STRING(S, "adfpoguharsüoginasfdü23"), s); + test_all(MAKE_STRING(S, "asoriübsfogiabsdfgoüif24"), s); + test_all(MAKE_STRING(S, "long long string so no SSO"), s); + test_all(MAKE_STRING(S, "pioegarsipasngipnadfgipkonadfpioknadfgöpaionge48"), s); + + return true; +} + +template +constexpr bool test_overwrite_str() { + test_copy_strings>({}); + test_copy_strings>(MAKE_STRING(S, "short string")); + test_copy_strings>(MAKE_STRING(S, "long long string so no SSO")); + + return true; +} + +#define CONSTEXPR_TEST(...) \ + __VA_ARGS__; \ + static_assert(__VA_ARGS__) + +void test() { + CONSTEXPR_TEST(test_overwrite_str()); + CONSTEXPR_TEST(test_overwrite_str()); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + CONSTEXPR_TEST(test_overwrite_str()); +#endif + CONSTEXPR_TEST(test_overwrite_str()); + CONSTEXPR_TEST(test_overwrite_str()); +} + +int main(int, char**) { + test(); + + return 0; +}