aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeir Mierle <keir@google.com>2023-03-11 00:38:00 +0000
committerCQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-03-11 00:38:00 +0000
commit7485834d52a180140e8b9f381bdb3a2bf43bb621 (patch)
treed2ff5332d73a876dad7eeda995e053669d6aa664
parent85cbe67e0f3d474498a648d99b041b80e00edce4 (diff)
downloadpigweed-7485834d52a180140e8b9f381bdb3a2bf43bb621.tar.gz
pw_string: Rework Guide in docs
Change-Id: I81045bf83240bba1df6960f7d2a260f6734b9fdf Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/133610 Commit-Queue: Keir Mierle <keir@google.com> Reviewed-by: Chad Norvell <chadnorvell@google.com>
-rw-r--r--pw_string/guide.rst204
1 files changed, 128 insertions, 76 deletions
diff --git a/pw_string/guide.rst b/pw_string/guide.rst
index 38916ee52..87ceec03e 100644
--- a/pw_string/guide.rst
+++ b/pw_string/guide.rst
@@ -1,11 +1,67 @@
.. _module-pw_string-guide:
-===============
-pw_string guide
-===============
+================
+pw_string: Guide
+================
-Building strings with StringBuilder
------------------------------------
+InlineString and StringBuilder?
+===============================
+Use :cpp:type:`pw::InlineString` if you need:
+
+* Compatibility with ``std::string``
+* Storage internal to the object
+* A string object to persist in other data structures
+* Lower code size overhead
+
+Use :cpp:class:`pw::StringBuilder` if you need:
+
+* Compatibility with ``std::ostringstream``, including custom object support
+* Storage external to the object
+* Non-fatal handling of failed append/format operations
+* Tracking of the status of a series of operations
+* A temporary stack object to aid string construction
+* Medium code size overhead
+
+An example of when to prefer :cpp:type:`pw::InlineString` is wrapping a
+length-delimited string (e.g. ``std::string_view``) for APIs that require null
+termination:
+
+.. code-block:: cpp
+
+ #include <string>
+ #include "pw_log/log.h"
+ #include "pw_string/string_builder.h"
+
+ void ProcessName(std::string_view name) {
+ // %s format strings require null terminated strings, so create one on the
+ // stack with size up to kMaxNameLen, copy the string view `name` contents
+ // into it, add a null terminator, and log it.
+ PW_LOG_DEBUG("The name is %s",
+ pw::InlineString<kMaxNameLen>(name).c_str());
+ }
+
+An example of when to prefer :cpp:class:`pw::StringBuilder` is when
+constructing a string for external use.
+
+.. code-block:: cpp
+
+ #include "pw_string/string_builder.h"
+
+ pw::Status FlushSensorValueToUart(int32_t sensor_value) {
+ pw::StringBuffer<42> sb;
+ sb << "Sensor value: ";
+ sb << sensor_value; // Formats as int.
+ FlushCStringToUart(sb.c_str());
+
+ if (!sb.status().ok) {
+ format_error_metric.Increment(); // Track overflows.
+ }
+ return sb.status();
+ }
+
+
+Building strings with pw::StringBuilder
+=======================================
The following shows basic use of a :cpp:class:`pw::StringBuilder`.
.. code-block:: cpp
@@ -34,92 +90,94 @@ The following shows basic use of a :cpp:class:`pw::StringBuilder`.
return sb.status();
}
-Constructing pw::InlineString objects
--------------------------------------
+Building strings with pw::InlineString
+======================================
:cpp:type:`pw::InlineString` objects must be constructed by specifying a fixed
capacity for the string.
.. code-block:: c++
- // Initialize from a C string.
- pw::InlineString<32> inline_string = "Literally";
- inline_string.append('?', 3); // contains "Literally???"
+ #include "pw_string/string.h"
- // Supports copying into known-capacity strings.
- pw::InlineString<64> other = inline_string;
+ // Initialize from a C string.
+ pw::InlineString<32> inline_string = "Literally";
+ inline_string.append('?', 3); // contains "Literally???"
- // Supports various helpful std::string functions
- if (inline_string.starts_with("Lit") || inline_string == "not\0literally"sv) {
- other += inline_string;
- }
+ // Supports copying into known-capacity strings.
+ pw::InlineString<64> other = inline_string;
- // Like std::string, InlineString is always null terminated when accessed
- // through c_str(). InlineString can be used to null-terminate
- // length-delimited strings for APIs that expect null-terminated strings.
- std::string_view file(".gif");
- if (std::fopen(pw::InlineString<kMaxNameLen>(file).c_str(), "r") == nullptr) {
- return;
- }
+ // Supports various helpful std::string functions
+ if (inline_string.starts_with("Lit") || inline_string == "not\0literally"sv) {
+ other += inline_string;
+ }
- // pw::InlineString integrates well with std::string_view. It supports
- // implicit conversions to and from std::string_view.
- inline_string = std::string_view("not\0literally", 12);
+ // Like std::string, InlineString is always null terminated when accessed
+ // through c_str(). InlineString can be used to null-terminate
+ // length-delimited strings for APIs that expect null-terminated strings.
+ std::string_view file(".gif");
+ if (std::fopen(pw::InlineString<kMaxNameLen>(file).c_str(), "r") == nullptr) {
+ return;
+ }
- FunctionThatTakesAStringView(inline_string);
+ // pw::InlineString integrates well with std::string_view. It supports
+ // implicit conversions to and from std::string_view.
+ inline_string = std::string_view("not\0literally", 12);
- FunctionThatTakesAnInlineString(std::string_view("1234", 4));
+ FunctionThatTakesAStringView(inline_string);
-Choosing between InlineString and StringBuilder
------------------------------------------------
-:cpp:type:`pw::InlineString` is comparable to ``std::string``, while
-:cpp:class:`pw::StringBuilder` is comparable to ``std::ostringstream``.
-Because :cpp:class:`pw::StringBuilder` provides high-level stream functionality,
-it has more overhead than :cpp:type:`pw::InlineString`.
+ FunctionThatTakesAnInlineString(std::string_view("1234", 4));
-Use :cpp:type:`pw::InlineString` unless :cpp:class:`pw::StringBuilder`'s
-capabilities are needed. Features unique to :cpp:class:`pw::StringBuilder`
-include:
+Building strings inside InlineString with a StringBuilder
+=========================================================
+:cpp:class:`pw::StringBuilder` can build a string in a
+:cpp:type:`pw::InlineString`:
-* Polymorphic C++ stream-style output, potentially supporting custom types.
-* Non-fatal handling of failed append/format operations.
-* Tracking the status of a series of operations.
-* Building a string in an external buffer.
+.. code-block:: c++
-If those features are not required, use :cpp:type:`pw::InlineString`. A common
-example of when to prefer :cpp:type:`pw::InlineString` is wrapping a
-length-delimited string (e.g. ``std::string_view``) for APIs that require null
-termination.
+ #include "pw_string/string.h"
-.. code-block:: cpp
+ void DoFoo() {
+ InlineString<32> inline_str;
+ StringBuilder sb(inline_str);
+ sb << 123 << "456";
+ // inline_str contains "456"
+ }
- void ProcessName(std::string_view name) {
- PW_LOG_DEBUG("The name is %s", pw::InlineString<kMaxNameLen>(name).c_str());
+Passing InlineStrings as parameters
+===================================
+:cpp:type:`pw::InlineString` objects can be passed to non-templated functions
+via type erasure. This saves code size in most cases, since it avoids template
+expansions triggered by string size differences.
-Operating on unknown size strings
----------------------------------
-All :cpp:type:`pw::InlineString` operations may be performed on strings without
-specifying their capacity.
+Unknown size strings
+--------------------
+To operate on :cpp:type:`pw::InlineString` objects without knowing their type,
+use the ``pw::InlineString<>`` type, shown in the examples below:
.. code-block:: c++
- void RemoveSuffix(pw::InlineString<>& string, std::string_view suffix) {
- if (string.ends_with(suffix)) {
- string.resize(string.size() - suffix.size());
- }
- }
+ // Note that the first argument is a generically-sized InlineString.
+ void RemoveSuffix(pw::InlineString<>& string, std::string_view suffix) {
+ if (string.ends_with(suffix)) {
+ string.resize(string.size() - suffix.size());
+ }
+ }
- void DoStuff() {
- pw::InlineString<32> str1 = "Good morning!";
- RemoveSuffix(str1, " morning!");
+ void DoStuff() {
+ pw::InlineString<32> str1 = "Good morning!";
+ RemoveSuffix(str1, " morning!");
- pw::InlineString<40> str2 = "Good";
- RemoveSuffix(str2, " morning!");
+ pw::InlineString<40> str2 = "Good";
+ RemoveSuffix(str2, " morning!");
- PW_ASSERT(str1 == str2);
- }
+ PW_ASSERT(str1 == str2);
+ }
+
+However, generically sized :cpp:type:`pw::InlineString` objects don't work in
+``constexpr`` contexts.
-Operating on known-size strings
--------------------------------
+Known size strings
+------------------
:cpp:type:`pw::InlineString` operations on known-size strings may be used in
``constexpr`` expressions.
@@ -135,13 +193,8 @@ Operating on known-size strings
return string;
}();
-Building strings
-----------------
-:cpp:class:`pw::StringBuilder` may be used to build a string in a
-:cpp:type:`pw::InlineString`.
-
-Deducing class template arguments with pw::InlineBasicString
-------------------------------------------------------------
+Compact initialization of InlineStrings
+=======================================
:cpp:type:`pw::InlineBasicString` supports class template argument deduction
(CTAD) in C++17 and newer. Since :cpp:type:`pw::InlineString` is an alias, CTAD
is not supported until C++20.
@@ -155,9 +208,8 @@ is not supported until C++20.
// In C++20, CTAD may be used with the pw::InlineString alias.
pw::InlineString my_other_string("123456789");
-
-Printing custom types
----------------------
+Supporting custom types with StringBuilder
+==========================================
As with ``std::ostream``, StringBuilder supports printing custom types by
overriding the ``<<`` operator. This is is done by defining ``operator<<`` in
the same namespace as the custom type. For example: