• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _module-pw_string:
2
3---------
4pw_string
5---------
6String manipulation is a very common operation, but the standard C and C++
7string libraries have drawbacks. The C++ functions are easy-to-use and powerful,
8but require too much flash and memory for many embedded projects. The C string
9functions are lighter weight, but can be difficult to use correctly. Mishandling
10of null terminators or buffer sizes can result in serious bugs.
11
12The ``pw_string`` module provides the flexibility, ease-of-use, and safety of
13C++-style string manipulation, but with no dynamic memory allocation and a much
14smaller binary size impact. Using ``pw_string`` in place of the standard C
15functions eliminates issues related to buffer overflow or missing null
16terminators.
17
18Compatibility
19=============
20C++17
21
22pw::string::Format
23==================
24The ``pw::string::Format`` and ``pw::string::FormatVaList`` functions provide
25safer alternatives to ``std::snprintf`` and ``std::vsnprintf``. The snprintf
26return value is awkward to interpret, and misinterpreting it can lead to serious
27bugs.
28
29Size report: replacing snprintf with pw::string::Format
30-------------------------------------------------------
31The ``Format`` functions have a small, fixed code size cost. However, relative
32to equivalent ``std::snprintf`` calls, there is no incremental code size cost to
33using ``Format``.
34
35.. include:: format_size_report
36
37pw::StringBuilder
38=================
39``pw::StringBuilder`` facilitates building formatted strings in a fixed-size
40buffer. It is designed to give the flexibility of ``std::string`` and
41``std::ostringstream``, but with a small footprint.
42
43Supporting custom types with StringBuilder
44------------------------------------------
45As with ``std::ostream``, StringBuilder supports printing custom types by
46overriding the ``<<`` operator. This is is done by defining ``operator<<`` in
47the same namespace as the custom type. For example:
48
49.. code-block:: cpp
50
51  namespace my_project {
52
53  struct MyType {
54    int foo;
55    const char* bar;
56  };
57
58  pw::StringBuilder& operator<<(pw::StringBuilder& sb, const MyType& value) {
59    return sb << "MyType(" << value.foo << ", " << value.bar << ')';
60  }
61
62  }  // namespace my_project
63
64Internally, ``StringBuilder`` uses the ``ToString`` function to print. The
65``ToString`` template function can be specialized to support custom types with
66``StringBuilder``, though it is recommended to overload ``operator<<`` instead.
67This example shows how to specialize ``pw::ToString``:
68
69.. code-block:: cpp
70
71  #include "pw_string/to_string.h"
72
73  namespace pw {
74
75  template <>
76  StatusWithSize ToString<MyStatus>(MyStatus value, std::span<char> buffer) {
77    return CopyString(MyStatusString(value), buffer);
78  }
79
80  }  // namespace pw
81
82Size report: replacing snprintf with pw::StringBuilder
83------------------------------------------------------
84StringBuilder is safe, flexible, and results in much smaller code size than
85using ``std::ostringstream``. However, applications sensitive to code size
86should use StringBuilder with care.
87
88The fixed code size cost of StringBuilder is significant, though smaller than
89``std::snprintf``. Using StringBuilder's << and append methods exclusively in
90place of ``snprintf`` reduces code size, but ``snprintf`` may be difficult to
91avoid.
92
93The incremental code size cost of StringBuilder is comparable to ``snprintf`` if
94errors are handled. Each argument to StringBuilder's ``<<`` expands to a
95function call, but one or two StringBuilder appends may have a smaller code size
96impact than a single ``snprintf`` call.
97
98.. include:: string_builder_size_report
99
100Future work
101===========
102* StringBuilder's fixed size cost can be dramatically reduced by limiting
103  support for 64-bit integers.
104* Consider integrating with the tokenizer module.
105