[libcxx-commits] [libcxx] bec50db - [libc++] Implement P1072R10 (std::basic_string::resize_and_overwrite)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jan 6 15:10:41 PST 2022


Author: Nikolas Klauser
Date: 2022-01-07T00:09:16+01:00
New Revision: bec50db2edf63c37ab48b1b9ca1ebb6a9fa47a59

URL: https://github.com/llvm/llvm-project/commit/bec50db2edf63c37ab48b1b9ca1ebb6a9fa47a59
DIFF: https://github.com/llvm/llvm-project/commit/bec50db2edf63c37ab48b1b9ca1ebb6a9fa47a59.diff

LOG: [libc++] Implement P1072R10 (std::basic_string::resize_and_overwrite)

Reviewed By: Quuxplusone, #libc, Mordante

Spies: mzeren-vmw, ckennelly, arichardson, ldionne, Mordante, libcxx-commits, Quuxplusone

Differential Revision: https://reviews.llvm.org/D113013

Added: 
    libcxx/test/std/strings/basic.string/string.capacity/resize_and_overwrite.pass.cpp

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/Status/Cxx2bPapers.csv
    libcxx/include/string
    libcxx/include/version
    libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 40e755864c19b..3cfcaa662f650 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -328,6 +328,8 @@ Status
     ------------------------------------------------- -----------------
     ``__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
index 50b11c4347d88..93b2d6befff94 100644
--- a/libcxx/docs/Status/Cxx2bPapers.csv
+++ b/libcxx/docs/Status/Cxx2bPapers.csv
@@ -26,7 +26,7 @@
 "`P0288R9 <https://wg21.link/P0288R9>`__","LWG","``any_invocable``","October 2021","",""
 "`P0798R8 <https://wg21.link/P0798R8>`__","LWG","Monadic operations for ``std::optional``","October 2021","|Complete|","14.0"
 "`P0849R8 <https://wg21.link/P0849R8>`__","LWG","``auto(x)``: ``DECAY_COPY`` in the language","October 2021","|Complete|","14.0"
-"`P1072R10 <https://wg21.link/P1072R10>`__","LWG","``basic_string::resize_and_overwrite``","October 2021","",""
+"`P1072R10 <https://wg21.link/P1072R10>`__","LWG","``basic_string::resize_and_overwrite``","October 2021","|Complete|","14.0"
 "`P1147R1 <https://wg21.link/P1147R1>`__","LWG","Printing ``volatile`` Pointers","October 2021","|Complete|","14.0"
 "`P1272R4 <https://wg21.link/P1272R4>`__","LWG","Byteswapping for fun&&nuf","October 2021","|Complete|","14.0"
 "`P1675R2 <https://wg21.link/P1675R2>`__","LWG","``rethrow_exception`` must be allowed to copy","October 2021","",""

diff  --git a/libcxx/include/string b/libcxx/include/string
index 9049d7acbb9bb..1b803bb8bd803 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -158,6 +158,9 @@ public:
     void resize(size_type n, value_type c);
     void resize(size_type n);
 
+    template<class Operation>
+    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 @@ public:
     _LIBCPP_INLINE_VISIBILITY void resize(size_type __n) {resize(__n, value_type());}
 
     void reserve(size_type __requested_capacity);
+
+#if _LIBCPP_STD_VER > 20
+    template <class _Op>
+    _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
index 6774e3151a6c2..39f1b8eb19ef1 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -155,6 +155,7 @@ __cpp_lib_stacktrace                                    202011L <stacktrace>
 __cpp_lib_starts_ends_with                              201711L <string> <string_view>
 __cpp_lib_stdatomic_h                                   202011L <stdatomic.h>
 __cpp_lib_string_contains                               202011L <string> <string_view>
+__cpp_lib_string_resize_and_overwrite                   202110L <string>
 __cpp_lib_string_udls                                   201304L <string>
 __cpp_lib_string_view                                   201803L <string> <string_view>
                                                         201606L // C++17
@@ -375,6 +376,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 // # 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
index 1657440104999..21167f64294bf 100644
--- 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
index e0f225009e41b..ad50bb1c769b3 100644
--- 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
index 0000000000000..36b3a2a6c81a1
--- /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
+
+// <string>
+
+// template<class Operation>
+// void resize_and_overwrite(size_type n, Operation op)
+
+#include <cassert>
+#include <string>
+
+#include "make_string.h"
+#include "test_macros.h"
+
+template <class S>
+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 <class S>
+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 <class CharT>
+constexpr bool test() {
+  using S = std::basic_string<CharT>;
+  test_appending<S>(10, 15, 15);
+  test_appending<S>(10, 15, 20);
+  test_appending<S>(10, 40, 40);
+  test_appending<S>(10, 40, 50);
+  test_appending<S>(30, 35, 35);
+  test_appending<S>(30, 35, 45);
+  test_appending<S>(10, 15, 30);
+  test_truncating<S>(15, 10);
+  test_truncating<S>(40, 35);
+  test_truncating<S>(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<char>();
+  test<char8_t>();
+  test<char16_t>();
+  test<char32_t>();
+
+#if defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L
+  static_assert(test<char>());
+  static_assert(test<char8_t>());
+  static_assert(test<char16_t>());
+  static_assert(test<char32_t>());
+#endif
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test<wchar_t>();
+#if defined(__cpp_lib_constexpr_string) && __cpp_lib_constexpr_string >= 201907L
+  static_assert(test<wchar_t>());
+#endif
+#endif
+  return 0;
+}

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 0d43c74a69790..7047f3f4b0cc1 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -624,6 +624,10 @@ def add_version_header(tc):
     "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 },


        


More information about the libcxx-commits mailing list