diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -328,6 +328,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_string_contains`` ``202011L`` ------------------------------------------------- ----------------- + ``__cpp_lib_string_resize_and_overwrite`` ``202110L`` + ------------------------------------------------- ----------------- ``__cpp_lib_to_underlying`` ``202102L`` ================================================= ================= diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -26,7 +26,7 @@ "`P0288R9 `__","LWG","``any_invocable``","October 2021","","" "`P0798R8 `__","LWG","Monadic operations for ``std::optional``","October 2021","|Complete|","14.0" "`P0849R8 `__","LWG","``auto(x)``: ``DECAY_COPY`` in the language","October 2021","|Complete|","14.0" -"`P1072R10 `__","LWG","``basic_string::resize_and_overwrite``","October 2021","","" +"`P1072R10 `__","LWG","``basic_string::resize_and_overwrite``","October 2021","|Complete|","14.0" "`P1147R1 `__","LWG","Printing ``volatile`` Pointers","October 2021","|Complete|","14.0" "`P1272R4 `__","LWG","Byteswapping for fun&&nuf","October 2021","|Complete|","14.0" "`P1675R2 `__","LWG","``rethrow_exception`` must be allowed to copy","October 2021","","" diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -158,6 +158,9 @@ void resize(size_type n, value_type c); void resize(size_type n); + template + constexpr void resize_and_overwrite(size_type n, Operation op); // since C++23 + void reserve(size_type res_arg); void reserve(); // deprecated in C++20 void shrink_to_fit(); @@ -973,6 +976,17 @@ _LIBCPP_INLINE_VISIBILITY void resize(size_type __n) {resize(__n, value_type());} void reserve(size_type __requested_capacity); + +#if _LIBCPP_STD_VER > 20 + template + _LIBCPP_HIDE_FROM_ABI constexpr + void resize_and_overwrite(size_type __n, _Op __op) { + __resize_default_init(__n); + pointer __data = data(); + __erase_to_end(_VSTD::move(__op)(__data, __n)); + } +#endif + _LIBCPP_INLINE_VISIBILITY void __resize_default_init(size_type __n); _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_INLINE_VISIBILITY diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -155,6 +155,7 @@ __cpp_lib_starts_ends_with 201711L __cpp_lib_stdatomic_h 202011L __cpp_lib_string_contains 202011L +__cpp_lib_string_resize_and_overwrite 202110L __cpp_lib_string_udls 201304L __cpp_lib_string_view 201803L 201606L // C++17 @@ -375,6 +376,7 @@ // # define __cpp_lib_stacktrace 202011L // # define __cpp_lib_stdatomic_h 202011L # define __cpp_lib_string_contains 202011L +# define __cpp_lib_string_resize_and_overwrite 202110L # define __cpp_lib_to_underlying 202102L #endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp @@ -23,6 +23,7 @@ __cpp_lib_nonmember_container_access 201411L [C++17] __cpp_lib_starts_ends_with 201711L [C++20] __cpp_lib_string_contains 202011L [C++2b] + __cpp_lib_string_resize_and_overwrite 202110L [C++2b] __cpp_lib_string_udls 201304L [C++14] __cpp_lib_string_view 201606L [C++17] 201803L [C++20] @@ -61,6 +62,10 @@ # error "__cpp_lib_string_contains should not be defined before c++2b" # endif +# ifdef __cpp_lib_string_resize_and_overwrite +# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++2b" +# endif + # ifdef __cpp_lib_string_udls # error "__cpp_lib_string_udls should not be defined before c++14" # endif @@ -99,6 +104,10 @@ # error "__cpp_lib_string_contains should not be defined before c++2b" # endif +# ifdef __cpp_lib_string_resize_and_overwrite +# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++2b" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++14" # endif @@ -146,6 +155,10 @@ # error "__cpp_lib_string_contains should not be defined before c++2b" # endif +# ifdef __cpp_lib_string_resize_and_overwrite +# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++2b" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++17" # endif @@ -214,6 +227,10 @@ # error "__cpp_lib_string_contains should not be defined before c++2b" # endif +# ifdef __cpp_lib_string_resize_and_overwrite +# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++2b" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++20" # endif @@ -285,6 +302,13 @@ # error "__cpp_lib_string_contains should have the value 202011L in c++2b" # endif +# ifndef __cpp_lib_string_resize_and_overwrite +# error "__cpp_lib_string_resize_and_overwrite should be defined in c++2b" +# endif +# if __cpp_lib_string_resize_and_overwrite != 202110L +# error "__cpp_lib_string_resize_and_overwrite should have the value 202110L in c++2b" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++2b" # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -144,6 +144,7 @@ __cpp_lib_starts_ends_with 201711L [C++20] __cpp_lib_stdatomic_h 202011L [C++2b] __cpp_lib_string_contains 202011L [C++2b] + __cpp_lib_string_resize_and_overwrite 202110L [C++2b] __cpp_lib_string_udls 201304L [C++14] __cpp_lib_string_view 201606L [C++17] 201803L [C++20] @@ -676,6 +677,10 @@ # error "__cpp_lib_string_contains should not be defined before c++2b" # endif +# ifdef __cpp_lib_string_resize_and_overwrite +# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++2b" +# endif + # ifdef __cpp_lib_string_udls # error "__cpp_lib_string_udls should not be defined before c++14" # endif @@ -1309,6 +1314,10 @@ # error "__cpp_lib_string_contains should not be defined before c++2b" # endif +# ifdef __cpp_lib_string_resize_and_overwrite +# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++2b" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++14" # endif @@ -2128,6 +2137,10 @@ # error "__cpp_lib_string_contains should not be defined before c++2b" # endif +# ifdef __cpp_lib_string_resize_and_overwrite +# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++2b" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++17" # endif @@ -3274,6 +3287,10 @@ # error "__cpp_lib_string_contains should not be defined before c++2b" # endif +# ifdef __cpp_lib_string_resize_and_overwrite +# error "__cpp_lib_string_resize_and_overwrite should not be defined before c++2b" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++20" # endif @@ -4564,6 +4581,13 @@ # error "__cpp_lib_string_contains should have the value 202011L in c++2b" # endif +# ifndef __cpp_lib_string_resize_and_overwrite +# error "__cpp_lib_string_resize_and_overwrite should be defined in c++2b" +# endif +# if __cpp_lib_string_resize_and_overwrite != 202110L +# error "__cpp_lib_string_resize_and_overwrite should have the value 202110L in c++2b" +# endif + # ifndef __cpp_lib_string_udls # error "__cpp_lib_string_udls should be defined in c++2b" # endif 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,105 @@ +//===----------------------------------------------------------------------===// +// +// 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 new_capacity) { + assert(N > k); + assert(new_capacity >= N); + auto s = S(k, 'a'); + s.resize_and_overwrite(new_capacity, [&](auto* p, auto n) { + assert(n == new_capacity); + LIBCPP_ASSERT(s.size() == new_capacity); + 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 S expected = S(k, 'a') + S(N - k, 'b'); + assert(s == expected); + assert(s.c_str()[N] == '\0'); +} + +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, [](auto ch) { return ch == 'a'; })); + p[n - 1] = 'b'; + p[n] = 'c'; // will be overwritten + return n; + }); + const S expected = S(N - 1, 'a') + S(1, 'b'); + assert(s == expected); + assert(s.c_str()[N] == '\0'); +} + +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_appending(10, 15, 30); + 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(); + +#if defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L + static_assert(test()); + static_assert(test()); + static_assert(test()); + static_assert(test()); +#endif + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#if defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L + static_assert(test()); +#endif +#endif + return 0; +} diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -624,6 +624,10 @@ "name": "__cpp_lib_string_contains", "values": { "c++2b": 202011 }, "headers": ["string", "string_view"], + }, { + "name": "__cpp_lib_string_resize_and_overwrite", + "values": { "c++2b": 202110 }, + "headers": ["string"], }, { "name": "__cpp_lib_string_udls", "values": { "c++14": 201304 },