pw_string: Implement pw::InlineString::resize_and_overwrite()
Implement resize_and_overwrite(), based on C++23's
std::string::resize_and_overwrite().
Bug: b/239996007
Change-Id: Iba005c35b3076edbe6f8c7e05f6005ae7f884694
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/111470
Commit-Queue: Wyatt Hepler <hepler@google.com>
Reviewed-by: Erik Gilling <konkers@google.com>
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
diff --git a/pw_string/docs.rst b/pw_string/docs.rst
index f7d1206..fb1e7e2 100644
--- a/pw_string/docs.rst
+++ b/pw_string/docs.rst
@@ -57,10 +57,22 @@
API reference
-------------
:cpp:type:`pw::InlineString` / :cpp:class:`pw::InlineBasicString` follows the
-``std::string`` / ``std::basic_string<T>`` API as closely as possible.
-:cpp:class:`pw::InlineBasicString` is intended to support all
-``std::basic_string<T>`` operations, except those having to do with dynamic
-memory allocation (``reserve()``, ``shrink_to_fit()``, ``get_allocator()``).
+``std::string`` / ``std::basic_string<T>`` API, with a few variations:
+
+- Assigning and constructing from character literals or arrays uses the size of
+ the literal or array, rather than treating it as a null-terminated string.
+ This allows for compile-time capacity checks and class template argument
+ deduction.
+- :cpp:type:`pw::InlineString` allows implicit conversions from
+ ``std::string_view``. Specifying the capacity parameter is cumbersome, so
+ implicit conversions are helpful. Also, implicitly creating a
+ :cpp:type:`pw::InlineString` is less costly than creating a ``std::string``.
+ As with ``std::string``, explicit conversions are required from types that
+ convert to ``std::string_view``.
+- Functions related to dynamic memory allocation are not present (``reserve()``,
+ ``shrink_to_fit()``, ``get_allocator()``).
+- ``resize_and_overwrite()`` only takes the ``Operation`` argument, since the
+ underlying string buffer cannot be resized.
.. cpp:class:: template <typename T, unsigned short kCapacity> pw::InlineBasicString
@@ -72,6 +84,9 @@
Represents a fixed-capacity string of ``char`` characters. Equivalent to
``std::string``. Always null (``'\0'``) terminated.
+See the `std::string documentation
+<https://en.cppreference.com/w/cpp/string/basic_string>`_ for full details.
+
Usage
-----
:cpp:type:`pw::InlineString` objects must be constructed by specifying a fixed
diff --git a/pw_string/public/pw_string/internal/string_common_functions.inc b/pw_string/public/pw_string/internal/string_common_functions.inc
index daebfd0..a72ace9 100644
--- a/pw_string/public/pw_string/internal/string_common_functions.inc
+++ b/pw_string/public/pw_string/internal/string_common_functions.inc
@@ -299,10 +299,16 @@
return Resize(data(), new_size, ch);
}
-// TODO(b/239996007): Implement other std::string functions:
-//
-// - resize_and_overwrite
-// - swap
+// resize_and_overwrite() only takes the callable object since the underlying
+// buffer has a fixed size.
+template <typename Operation>
+constexpr void resize_and_overwrite(Operation operation) {
+ const auto new_size = std::move(operation)(data(), max_size());
+ PW_ASSERT(static_cast<size_t>(new_size) <= max_size());
+ SetSizeAndTerminate(data(), new_size);
+}
+
+// TODO(b/239996007): Implement swap
// Search
diff --git a/pw_string/string_test.cc b/pw_string/string_test.cc
index d1890db..aa2f45b 100644
--- a/pw_string/string_test.cc
+++ b/pw_string/string_test.cc
@@ -1573,7 +1573,70 @@
// - replace
// - substr
// - copy
-// - resize
+
+TEST(InlineString, Resize) {
+ TEST_STRING(InlineString<10>(), str.resize(0), "");
+ TEST_STRING(InlineString<10>(), str.resize(5), "\0\0\0\0\0");
+ TEST_STRING(InlineString<10>(), str.resize(10), "\0\0\0\0\0\0\0\0\0\0");
+ TEST_STRING(InlineString<10>(), str.resize(0, 'a'), "");
+ TEST_STRING(InlineString<10>(), str.resize(5, 'a'), "aaaaa");
+ TEST_STRING(InlineString<10>(), str.resize(10, 'a'), "aaaaaaaaaa");
+
+ TEST_STRING(InlineString<10>("ABCDE"), str.resize(0), "");
+ TEST_STRING(InlineString<10>("ABCDE"), str.resize(4), "ABCD");
+ TEST_STRING(InlineString<10>("ABCDE"), str.resize(5), "ABCDE");
+ TEST_STRING(InlineString<10>("ABCDE"), str.resize(10), "ABCDE\0\0\0\0\0");
+ TEST_STRING(InlineString<10>("ABCDE"), str.resize(0, 'a'), "");
+ TEST_STRING(InlineString<10>("ABCDE"), str.resize(3, 'a'), "ABC");
+ TEST_STRING(InlineString<10>("ABCDE"), str.resize(5, 'a'), "ABCDE");
+ TEST_STRING(InlineString<10>("ABCDE"), str.resize(10, 'a'), "ABCDEaaaaa");
+
+#if PW_NC_TEST(Resize_LargerThanCapacity)
+ PW_NC_EXPECT("PW_ASSERT\(new_size <= max_size\(\)\)");
+ [[maybe_unused]] constexpr auto fail = [] {
+ InlineString<4> str("123");
+ str.resize(5);
+ return str;
+ }();
+#endif // PW_NC_TEST
+}
+
+TEST(InlineString, ResizeAndOverwrite) {
+ TEST_STRING(InlineString<2>(),
+ str.resize_and_overwrite([](char* out, size_t) {
+ out[0] = '\0';
+ out[1] = '?';
+ return 2;
+ }),
+ "\0?");
+ TEST_STRING(InlineString<10>("ABCDE"),
+ str.resize_and_overwrite([](char* out, size_t size) {
+ out[1] = '?';
+ for (size_t i = 5; i < size; ++i) {
+ out[i] = static_cast<char>('0' + i);
+ }
+ return size - 1; // chop off the last character
+ }),
+ "A?CDE5678");
+
+#if PW_NC_TEST(ResizeAndOverwrite_LargerThanCapacity)
+ PW_NC_EXPECT("PW_ASSERT\(static_cast<size_t>\(new_size\) <= max_size\(\)\)");
+ [[maybe_unused]] constexpr auto fail = [] {
+ InlineString<4> str("123");
+ str.resize_and_overwrite([](char*, size_t) { return 5; });
+ return str;
+ }();
+#elif PW_NC_TEST(ResizeAndOverwrite_NegativeSize)
+ PW_NC_EXPECT("PW_ASSERT\(static_cast<size_t>\(new_size\) <= max_size\(\)\)");
+ [[maybe_unused]] constexpr auto fail = [] {
+ InlineString<4> str("123");
+ str.resize_and_overwrite([](char*, size_t) { return -1; });
+ return str;
+ }();
+#endif // PW_NC_TEST
+}
+
+// TODO(b/239996007): Test other pw::InlineString functions:
// - swap
//