API Reference#

pw_string: Efficient, easy, and safe string manipulation

Overview#

This module provides two types of strings and utility functions for working with strings.

pw::StringBuilder

pw::StringBuilder facilitates creating formatted strings in a fixed-sized buffer or in a pw::InlineString. It is designed to give the flexibility of std::ostringstream, but with a small footprint.

pw::InlineString

pw::InlineBasicString and pw::InlineString are safer alternatives to std::basic_string and std::string.

String utility functions

The pw::string::* functions provide safer alternatives to C++ standard library string functions.

UTF-8 Helpers

pw::StringBuilder#

pw::StringBuilder facilitates creating formatted strings in a fixed-sized buffer or in a pw::InlineString. It is designed to give the flexibility of std::ostringstream, but with a small footprint.

class StringBuilder#

pw::StringBuilder instances are always null-terminated (unless they are constructed with an empty buffer) and never overflow. Status is tracked for each operation and an overall status is maintained, which reflects the most recent error.

pw::StringBuilder does not own the buffer it writes to. It can be used to write strings to any buffer. The pw::StringBuffer template class, defined below, allocates a buffer alongside a pw::StringBuilder.

pw::StringBuilder supports C++-style << output, similar to std::ostringstream. It also supports append functions like std::string and printf-style output.

Support for custom types is added by overloading operator<< in the same namespace as the custom type. For example:

namespace my_project {

struct MyType {
  int foo;
  const char* bar;
};

pw::StringBuilder& operator<<(pw::StringBuilder& sb, const MyType& value)
{
  return sb << "MyType(" << value.foo << ", " << value.bar << ')';
}

}  // namespace my_project

The ToString template function can be specialized to support custom types with pw::StringBuilder, though overloading operator<< is generally preferred. For example:

namespace pw {

template <>
StatusWithSize ToString<MyStatus>(MyStatus value, span<char> buffer) {
  return Copy(MyStatusString(value), buffer);
}

}  // namespace pw

Subclassed by pw::StringBuffer< kSizeBytes >

Public Functions

inline explicit constexpr StringBuilder(span<char> buffer)#

Creates an empty pw::StringBuilder.

StringBuilder(const StringBuilder&) = delete#

Disallow copy/assign to avoid confusion about where the string is actually stored. pw::StringBuffer instances may be copied into one another.

inline const char *c_str() const#

Returns the contents of the string buffer. Always null-terminated.

inline std::string_view view() const#

Returns a std::string_view of the contents of this pw::StringBuilder. The std::string_view is invalidated if the pw::StringBuilder contents change.

inline operator std::string_view() const#

Allow implicit conversions to std::string_view so pw::StringBuilder instances can be passed into functions that take a std::string_view.

inline span<const std::byte> as_bytes() const#

Returns a span<const std::byte> representation of this pw::StringBuffer.

inline Status status() const#

Returns the status of pw::StringBuilder, which reflects the most recent error that occurred while updating the string. After an update fails, the status remains non-OK until it is cleared with pw::StringBuilder::clear() or pw::StringBuilder::clear_status().

Returns:

Code

Description

OK

No errors have occurred.

RESOURCE_EXHAUSTED

Output to the StringBuilder was truncated.

INVALID_ARGUMENT

printf-style formatting failed.

OUT_OF_RANGE

An operation outside the buffer was attempted.

inline StatusWithSize status_with_size() const#

Returns status() and size() as a StatusWithSize.

inline Status last_status() const#

The status from the last operation. May be OK while status() is not OK.

inline bool ok() const#

True if status() is OkStatus().

inline bool empty() const#

True if the string is empty.

inline size_t size() const#

Returns the current length of the string, excluding the null terminator.

inline size_t max_size() const#

Returns the maximum length of the string, excluding the null terminator.

void clear()#

Clears the string and resets its error state.

inline void clear_status()#

Sets the statuses to OkStatus();.

inline void push_back(char ch)#

Appends a single character. Sets the status to RESOURCE_EXHAUSTED if the character cannot be added because the buffer is full.

inline void pop_back()#

Removes the last character. Sets the status to OUT_OF_RANGE if the buffer is empty (in which case the unsigned overflow is intentional).

StringBuilder &append(size_t count, char ch)#

Appends the provided character count times.

StringBuilder &append(const char *str, size_t count)#

Appends count characters from str to the end of the StringBuilder. If count exceeds the remaining space in the StringBuffer, max_size() - size() characters are appended and the status is set to RESOURCE_EXHAUSTED.

str is not considered null-terminated and may contain null characters.

StringBuilder &append(const char *str)#

Appends characters from the null-terminated string to the end of the StringBuilder. If the string’s length exceeds the remaining space in the buffer, max_size() - size() characters are copied and the status is set to RESOURCE_EXHAUSTED.

This function uses string::Length instead of std::strlen to avoid unbounded reads if the string is not null-terminated.

StringBuilder &append(std::string_view str)#

Appends a std::string_view to the end of the StringBuilder.

StringBuilder &append(std::string_view str, size_t pos, size_t count = std::string_view::npos)#

Appends a substring from the std::string_view to the StringBuilder. Copies up to count characters starting from pos to the end of the StringBuilder. If pos > str.size(), sets the status to OUT_OF_RANGE.

template<typename T>
inline StringBuilder &operator<<(const T &value)#

Appends to the end of the StringBuilder using the << operator. This enables C++ stream-style formatted to StringBuilder instances.

inline StringBuilder &operator<<(bool value)#

Provide a few additional operator<< overloads that reduce code size.

StringBuilder &Format(const char *format, ...)#

Appends a printf-style string to the end of the StringBuilder. If the formatted string does not fit, the results are truncated and the status is set to RESOURCE_EXHAUSTED.

Note

Internally, calls string::Format, which calls std::vsnprintf.

Parameters:
  • format – The format string

  • ... – Arguments for format specification

Returns:

StringBuilder&

StringBuilder &FormatVaList(const char *format, va_list args)#

Appends a vsnprintf-style string with va_list arguments to the end of the StringBuilder. If the formatted string does not fit, the results are truncated and the status is set to RESOURCE_EXHAUSTED.

Note

Internally, calls string::Format, which calls std::vsnprintf.

void resize(size_t new_size)#

Sets the size of the StringBuilder. This function only truncates; if new_size > size(), it sets status to OUT_OF_RANGE and does nothing.

pw::InlineString#

template<typename T, size_t kCapacity = string_impl::kGeneric>
class InlineBasicString#

pw::InlineBasicString is a fixed-capacity version of std::basic_string. In brief:

  • It is always null-terminated.

  • It stores the string contents inline and uses no dynamic memory.

  • It implements mostly the same API as std::basic_string, but the capacity of the string is fixed at construction and cannot grow. Attempting to increase the size beyond the capacity triggers an assert.

pw::InlineBasicString is efficient and compact. The current size and capacity are stored in a single word. Accessing its contents is a simple array access within the object, with no pointer indirection, even when working from a generic reference pw::InlineBasicString<T> where the capacity is not specified as a template argument. A string object can be used safely without the need to know its capacity.

See also pw::InlineString, which is an alias of pw::InlineBasicString<char> and is equivalent to std::string.

template<size_t kCapacity = string_impl::kGeneric>
using pw::InlineString = InlineBasicString<char, kCapacity>#

pw::InlineString is an alias of pw::InlineBasicString<char> and is equivalent to std::string.

String utility functions#

pw::string::Assign()#

inline Status pw::string::Assign(InlineString<> &string, std::string_view view)#

Assigns a std::string_view to a pw::InlineString, truncating if it does not fit. The assign() function of pw::InlineString asserts if the string’s requested size exceeds its capacity; pw::string::Assign() returns a Status instead.

Returns:

Code

Description

OK

The entire std::string_view was copied to the end of the pw::InlineString.

RESOURCE_EXHAUSTED

The std::string_view was truncated to fit.

pw::string::Append()#

inline Status pw::string::Append(InlineString<> &string, std::string_view view)#

Appends a std::string_view to a pw::InlineString, truncating if it does not fit. The append() function of pw::InlineString asserts if the string’s requested size exceeds its capacity; pw::string::Append() returns a Status instead.

Returns:

Code

Description

OK

The entire std::string_view was assigned.

RESOURCE_EXHAUSTED

The std::string_view was truncated to fit.

pw::string::ClampedCString()#

constexpr std::string_view pw::string::ClampedCString(const char *str, size_t max_len)#
constexpr std::string_view pw::string::ClampedCString(span<const char> str)#

Safe alternative to the string_view constructor that avoids the risk of an unbounded implicit or explicit use of strlen.

This is strongly recommended over using something like C11’s strnlen_s as a string_view does not require null-termination.

pw::string::Copy()#

inline StatusWithSize pw::string::Copy(const char *source, char *dest, size_t num)#
template<typename Span>
inline StatusWithSize pw::string::Copy(const char *source, Span &&dest)#
template<typename Span>
inline StatusWithSize pw::string::Copy(std::string_view source, Span &&dest)#

pw::string::Copy is a safer alternative to std::strncpy as it always null-terminates whenever the destination buffer has a non-zero size.

Copies the source string to the dest, truncating if the full string does not fit. Always null terminates if dest.size() or num is greater than 0.

Pre:

The destination and source shall not overlap. The source shall be a valid pointer.

Returns:

Code

Description

OK

Returns the number of characters written, excluding the null terminator.

RESOURCE_EXHAUSTED

The string is truncated.

It also has variants that provide a destination of pw::Vector<char> (see pw_containers for details) that do not store the null terminator in the vector.

StatusWithSize Copy(std::string_view source, pw::Vector<char> &dest)#
StatusWithSize Copy(const char *source, pw::Vector<char> &dest)#

pw::string::Format()#

The pw::string::Format functions are safer alternatives to std::snprintf and std::vsnprintf. The snprintf return value is awkward to interpret, and misinterpreting it can lead to serious bugs.

These functions return a pw::StatusWithSize. The pw::Status is set to reflect any errors and the return value is always the number of characters written before the null terminator.

StatusWithSize pw::string::Format(span<char> buffer, const char *format, ...)#

Writes a printf-style formatted string to the provided buffer, similarly to std::snprintf().

The std::snprintf() return value is awkward to interpret, and misinterpreting it can lead to serious bugs.

Returns:

Code

Description

OK

Returns the number of characters written, excluding the null terminator. The buffer is always null-terminated unless it is empty.

RESOURCE_EXHAUSTED

The buffer was too small to fit the output.

INVALID_ARGUMENT

There was a formatting error.

StatusWithSize pw::string::FormatVaList(span<char> buffer, const char *format, va_list args)#

Writes a printf-style formatted string with va_list-packed arguments to the provided buffer, similarly to std::vsnprintf().

Returns:

See pw::string::Format().

Status pw::string::Format(InlineString<> &string, const char *format, ...)#

Appends a printf-style formatted string to the provided pw::InlineString, similarly to std::snprintf().

Returns:

See pw::string::Format().

Status pw::string::FormatVaList(InlineString<> &string, const char *format, va_list args)#

Appends a printf-style formatted string with va_list-packed arguments to the provided InlineString, similarly to std::vsnprintf().

Returns:

See pw::string::Format().

Status pw::string::FormatOverwrite(InlineString<> &string, const char *format, ...)#

Writes a printf-style format string to the provided InlineString, overwriting any contents.

Returns:

See pw::string::Format().

inline Status pw::string::FormatOverwriteVaList(InlineString<> &string, const char *format, va_list args)#

Writes a printf-style formatted string with va_list-packed arguments to the provided InlineString, overwriting any contents.

Returns:

See pw::string::Format().

pw::string::NullTerminatedLength()#

constexpr Result<size_t> pw::string::NullTerminatedLength(const char *str, size_t max_len)#
constexpr Result<size_t> pw::string::NullTerminatedLength(span<const char> str)#

pw::string::NullTerminatedLength is a safer alternative to strlen for calculating the null-terminated length of the string within the specified span, excluding the null terminator.

Like strnlen_s in C11, the scan for the null-terminator is bounded.

Pre:

The string shall be at a valid pointer.

Returns:

Code

Description

OK

Returns the null-terminated length of the string excluding the null terminator.

OUT_OF_RANGE

The string is not null-terminated.

pw::string::PrintableCopy()#

inline StatusWithSize pw::string::PrintableCopy(std::string_view source, span<char> dest)#

Provides a safe, printable copy of a string.

Copies the source string to the dest string with same behavior as pw::string::Copy, with the difference that any non-printable characters are changed to ..

UTF-8 Helpers#

constexpr Result<EncodedCodePoint> pw::utf8::EncodeCodePoint(uint32_t code_point)#

Encodes a single code point as UTF-8.

UTF-8 encodes as 1-4 bytes from a range of [0, 0x10FFFF].

1-byte encoding has a top bit of zero:

[0, 0x7F] 1-bytes: b0xxx xxxx
N-bytes sequences are denoted by annotating the top N+1 bits of the leading byte and then using a 2-bit continuation marker on the following bytes.
[0x00080, 0x0007FF] 2-bytes: b110x xxxx 10xx xxxx
[0x00800, 0x00FFFF] 3-bytes: b1110 xxxx 10xx xxxx 10xx xxxx
[0x10000, 0x10FFFF] 4-bytes: b1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx

Returns:

Code

Description

OK

The codepoint encoded as UTF-8.

OUT_OF_RANGE

The code point was not in the valid range for UTF-8 encoding.

Status pw::utf8::WriteCodePoint(uint32_t code_point, pw::StringBuilder &output)#

Helper that writes a code point to the provided pw::StringBuilder.

constexpr pw::Result<utf::CodePointAndSize> pw::utf8::ReadCodePoint(std::string_view str)#

Reads the first code point from a UTF-8 encoded str.

This is a very basic decoder without much thought for performance and very basic validation that the correct number of bytes are available and that each byte of a multibyte sequence has a continuation character. See pw::utf8::EncodeCharacter() for encoding details.

Returns:

Code

Description

OK

The decoded code point and the number of bytes read.

INVALID_ARGUMENT

The string was empty or malformed.

OUT_OF_RANGE

The decoded code point was not in the valid range.