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
 
 //