blob: 8453f4edf463455896464908bdf0bcf96a14353d [file] [log] [blame]
.. _module-pw_string:
.. rst-class:: with-subtitle
=========
pw_string
=========
.. pigweed-module::
:name: pw_string
:tagline: Efficient, easy, and safe string manipulation
:status: stable
:languages: C++14, C++17
:code-size-impact: 500 to 1500 bytes
:nav:
getting started: module-pw_string-get-started
design: module-pw_string-design
guides: module-pw_string-guide
api: module-pw_string-api
- **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 on embedded systems can be surprisingly challenging.
C strings are light weight but come with many pitfalls for those who don't know
the standard library deeply. C++ provides string classes that are safe and easy
to use, but they consume way too much code space and are designed to be used
with dynamic memory allocation.
Embedded systems need string functionality that is both safe and suitable for
resource-constrained platforms.
------------
Our solution
------------
``pw_string`` provides safe string handling functionality with an API that
closely matches that of ``std::string``, but without dynamic memory allocation
and with a *much* smaller :ref:`binary size impact <module-pw_string-size-reports>`.
---------------
Who this is for
---------------
``pw_string`` is useful any time you need to handle strings in embedded C++.
--------------------
Is it right for you?
--------------------
If your project written in C, ``pw_string`` is not a good fit since we don't
currently expose a C API.
For larger platforms where code space isn't in short supply and dynamic memory
allocation isn't a problem, you may find that ``std::string`` meets your needs.
.. tip::
``pw_string`` works just as well on larger embedded platforms and host
systems. Using ``pw_string`` even when you might get away with ``std:string``
gives you the flexibility to move to smaller platforms later with much less
rework.
Here are some size reports that may affect whether ``pw_string`` is right for
you.
.. _module-pw_string-size-reports:
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
Roadmap
-------
* StringBuilder's fixed size cost can be dramatically reduced by limiting
support for 64-bit integers.
* Consider integrating with the tokenizer module.
Compatibility
-------------
C++17, C++14 (:cpp:type:`pw::InlineString`)
.. _module-pw_string-get-started:
---------------
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.
-------
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`.
.. toctree::
:hidden:
:maxdepth: 1
design
guide
api