.. _module-pw_string-design: ================ pw_string design ================ ``pw_string`` provides string classes and utility functions designed to prioritize safety and static allocation. The APIs are broadly similar to those of the string classes in the C++ standard library, so familiarity with those classes will provide some context around ``pw_string`` design decisions. ------------ InlineString ------------ :cpp:type:`pw::InlineString` / :cpp:class:`pw::InlineBasicString` are designed to match the ``std::string`` / ``std::basic_string`` API as closely as possible, but with key differences to improve performance on embedded systems: - **Fixed capacity:** Operations that add characters to the string beyond its capacity are an error. These trigger a ``PW_ASSERT`` at runtime. When detectable, these situations trigger a ``static_assert`` at compile time. - **Minimal overhead:** :cpp:type:`pw::InlineString` operations never allocate. Reading the contents of the string is a direct memory access within the string object, without pointer indirection. - **Constexpr support:** :cpp:type:`pw::InlineString` works in ``constexpr`` contexts, which is not supported by ``std::string`` until C++20. We don't aim to provide complete API compatibility with ``std::string`` / ``std::basic_string``. Some areas of deviation include: - **Compile-time capacity checks:** :cpp:type:`InlineString` provides overloads specific to character arrays. These perform compile-time capacity checks and are used for class template argument deduction. - **Implicit conversions from** ``std::string_view`` **:** Specifying the capacity parameter is cumbersome, so implicit conversions are helpful. Also, implicitly creating a :cpp:type:`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``. - **No dynamic allocation functions:** Functions that allocate memory, like ``reserve()``, ``shrink_to_fit()``, and ``get_allocator()``, are simply not present. Capacity ======== :cpp:type:`InlineBasicString` has a template parameter for the capacity, but the capacity does not need to be known by the user to use the string safely. The :cpp:type:`InlineBasicString` template inherits from a :cpp:type:`InlineBasicString` specialization with capacity of the reserved value ``pw::InlineString<>::npos``. The actual capacity is stored in a single word alongside the size. This allows code to work with strings of any capacity through a ``InlineString<>`` or ``InlineBasicString`` reference. Exceeding the capacity ---------------------- Any :cpp:type:`pw::InlineString` operations that exceed the string's capacity fail an assertion, resulting in a crash. Helpers are provided in ``pw_string/util.h`` that return ``pw::Status::ResourceExhausted()`` instead of failing an assert when the capacity would be exceeded. ------------------------ String utility functions ------------------------ Safe length checking ==================== This module provides two safer alternatives to ``std::strlen`` in case the string is extremely long and/or potentially not null-terminated. First, a constexpr alternative to C11's ``strnlen_s`` is offerred through :cpp:func:`pw::string::ClampedCString`. This does not return a length by design and instead returns a string_view which does not require null-termination. Second, a constexpr specialized form is offered where null termination is required through :cpp:func:`pw::string::NullTerminatedLength`. This will only return a length if the string is null-terminated.