aboutsummaryrefslogtreecommitdiff
path: root/pw_string/docs.rst
blob: 7aa800044a987ada5624e753338d82e807d5b9c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
.. _module-pw_string:

=========
pw_string
=========
.. card::

   :octicon:`comment-discussion` Status:
   :bdg-secondary-line:`Experimental`
   :octicon:`chevron-right`
   :bdg-secondary-line:`Unstable`
   :octicon:`chevron-right`
   :bdg-primary:`Stable`
   :octicon:`kebab-horizontal`
   :bdg-primary:`Current`
   :octicon:`chevron-right`
   :bdg-secondary-line:`Deprecated`

Compatibility: C++17 (C++14 for :cpp:type:`pw::InlineString`)

`API reference </pw_string/api.html>`_ | `Guide </pw_string/guide.html>`_ | `Design </pw_string/design.html>`_

---------------------------------------------
Efficient, easy, and safe string manipulation
---------------------------------------------
- **Efficient**: No memory allocation, no pointer indirection.
- **Easy**: Use the string API you already know.
- **Safe**: Never worry about buffer overruns or undefined behavior.

*Pick three!* If you know how to use ``std::string``, just use
:cpp:type:`pw::InlineString` in the same way:

.. code:: cpp

   // Create a string from a C-style char array; storage is pre-allocated!
   pw::InlineString<16> my_string = "Literally";

   // We have some space left, so let's add to the string.
   my_string.append('?', 3);  // "Literally???"

   // Let's try something evil and extend this past its capacity 😈
   my_string.append('!', 8);
   // Foiled by a crash! No mysterious bugs or undefined behavior.

Need to build up a string? :cpp:type:`pw::StringBuilder` works like
``std::ostringstream``, but with most of the efficiency and memory benefits of
:cpp:type:`pw::InlineString`:

.. code:: cpp

   // Create a pw::StringBuilder with a built-in buffer
   pw::StringBuffer<32> my_string_builder = "Is it really this easy?";

   // Add to it with idiomatic C++
   my_string << " YES!";

   // Use it like any other string
   PW_LOG_DEBUG("%s", my_string_builder.c_str());


Check out :ref:`module-pw_string-guide` for more code samples.

----------
Background
----------
String manipulation is a very common operation, but the standard C and C++
string libraries have drawbacks. The C++ functions are easy-to-use and powerful,
but require too much flash and memory for many embedded projects. The C string
functions are lighter weight, but can be difficult to use correctly. Mishandling
of null terminators or buffer sizes can result in serious bugs.

------------
Our solution
------------
The ``pw_string`` module provides the flexibility, ease-of-use, and safety of
C++-style string manipulation, but with no dynamic memory allocation and a much
smaller binary size impact. Using ``pw_string`` in place of the standard C
functions eliminates issues related to buffer overflow or missing null
terminators.

---------------
Who this is for
---------------
``pw_string`` is potentially useful for anyone who is working with strings in
C++.

Is it right for you?
--------------------
Here are some size reports that may affect whether ``pw_string`` is right for
you.

Size comparison: snprintf versus pw::StringBuilder
--------------------------------------------------
:cpp:type:`pw::StringBuilder` is safe, flexible, and results in much smaller code size than
using ``std::ostringstream``. However, applications sensitive to code size
should use :cpp:type:`pw::StringBuilder` with care.

The fixed code size cost of :cpp:type:`pw::StringBuilder` is significant, though smaller than
``std::snprintf``. Using :cpp:type:`pw::StringBuilder`'s ``<<`` and ``append`` methods exclusively in
place of ``snprintf`` reduces code size, but ``snprintf`` may be difficult to
avoid.

The incremental code size cost of :cpp:type:`pw::StringBuilder` is comparable to ``snprintf`` if
errors are handled. Each argument to :cpp:type:`pw::StringBuilder`'s ``<<`` method expands to a
function call, but one or two :cpp:type:`pw::StringBuilder` appends may have a smaller code size
impact than a single ``snprintf`` call.

.. include:: string_builder_size_report

Size comparison: snprintf versus pw::string::Format
---------------------------------------------------
The ``pw::string::Format`` functions have a small, fixed code size
cost. However, relative to equivalent ``std::snprintf`` calls, there is no
incremental code size cost to using ``pw::string::Format``.

.. include:: format_size_report

---------------
Getting started
---------------

GN
--

Add ``$dir_pw_string`` to the ``deps`` list in your ``pw_executable()`` build
target:

.. code::

  pw_executable("...") {
    # ...
    deps = [
      # ...
      "$dir_pw_string",
      # ...
    ]
  }

See `//source/BUILD.gn <https://pigweed.googlesource.com/pigweed/sample_project/+/refs/heads/main/source/BUILD.gn>`_
in the Pigweed Sample Project for an example.

Zephyr
------
Add ``CONFIG_PIGWEED_STRING=y`` to the Zephyr project's configuration.

---------------------
Design considerations
---------------------
``pw_string`` is designed to prioritize safety and static allocation. It matches
the ``std::string`` API as closely as possible, but isn't intended to provide
complete API compatibility. See :ref:`module-pw_string-design` for more
details.

-------
Roadmap
-------
* The fixed size cost of :cpp:type:`pw::StringBuilder` can be dramatically reduced by
  limiting support for 64-bit integers.
* ``pw_string`` may be integrated with :ref:`module-pw_tokenizer`.

----------
Learn more
----------
.. toctree::
   :maxdepth: 1

   design
   guide
   api