1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_string-guide: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker==================== 4*61c4878aSAndroid Build Coastguard WorkerGet Started & Guides 5*61c4878aSAndroid Build Coastguard Worker==================== 6*61c4878aSAndroid Build Coastguard Worker.. pigweed-module-subpage:: 7*61c4878aSAndroid Build Coastguard Worker :name: pw_string 8*61c4878aSAndroid Build Coastguard Worker 9*61c4878aSAndroid Build Coastguard Worker.. _module-pw_string-get-started: 10*61c4878aSAndroid Build Coastguard Worker 11*61c4878aSAndroid Build Coastguard WorkerGet Started 12*61c4878aSAndroid Build Coastguard Worker=========== 13*61c4878aSAndroid Build Coastguard Worker.. tab-set:: 14*61c4878aSAndroid Build Coastguard Worker 15*61c4878aSAndroid Build Coastguard Worker .. tab-item:: Bazel 16*61c4878aSAndroid Build Coastguard Worker 17*61c4878aSAndroid Build Coastguard Worker Add ``@pigweed//pw_string`` to the ``deps`` list in your Bazel target: 18*61c4878aSAndroid Build Coastguard Worker 19*61c4878aSAndroid Build Coastguard Worker .. code-block:: 20*61c4878aSAndroid Build Coastguard Worker 21*61c4878aSAndroid Build Coastguard Worker cc_library("...") { 22*61c4878aSAndroid Build Coastguard Worker # ... 23*61c4878aSAndroid Build Coastguard Worker deps = [ 24*61c4878aSAndroid Build Coastguard Worker # ... 25*61c4878aSAndroid Build Coastguard Worker "@pigweed//pw_string", 26*61c4878aSAndroid Build Coastguard Worker # ... 27*61c4878aSAndroid Build Coastguard Worker ] 28*61c4878aSAndroid Build Coastguard Worker } 29*61c4878aSAndroid Build Coastguard Worker 30*61c4878aSAndroid Build Coastguard Worker If only one part of the module is needed, depend only on it; for example 31*61c4878aSAndroid Build Coastguard Worker ``@pigweed//pw_string:format``. 32*61c4878aSAndroid Build Coastguard Worker 33*61c4878aSAndroid Build Coastguard Worker This assumes ``@pigweed`` is the name you pulled Pigweed into your Bazel 34*61c4878aSAndroid Build Coastguard Worker ``WORKSPACE`` as. 35*61c4878aSAndroid Build Coastguard Worker 36*61c4878aSAndroid Build Coastguard Worker .. tab-item:: GN 37*61c4878aSAndroid Build Coastguard Worker 38*61c4878aSAndroid Build Coastguard Worker Add ``$dir_pw_string`` to the ``deps`` list in your ``pw_executable()`` 39*61c4878aSAndroid Build Coastguard Worker build target: 40*61c4878aSAndroid Build Coastguard Worker 41*61c4878aSAndroid Build Coastguard Worker .. code-block:: 42*61c4878aSAndroid Build Coastguard Worker 43*61c4878aSAndroid Build Coastguard Worker pw_executable("...") { 44*61c4878aSAndroid Build Coastguard Worker # ... 45*61c4878aSAndroid Build Coastguard Worker deps = [ 46*61c4878aSAndroid Build Coastguard Worker # ... 47*61c4878aSAndroid Build Coastguard Worker "$dir_pw_string", 48*61c4878aSAndroid Build Coastguard Worker # ... 49*61c4878aSAndroid Build Coastguard Worker ] 50*61c4878aSAndroid Build Coastguard Worker } 51*61c4878aSAndroid Build Coastguard Worker 52*61c4878aSAndroid Build Coastguard Worker See `//source/BUILD.gn <https://pigweed.googlesource.com/pigweed/sample_project/+/refs/heads/main/source/BUILD.gn>`_ 53*61c4878aSAndroid Build Coastguard Worker in the Pigweed Sample Project for an example. 54*61c4878aSAndroid Build Coastguard Worker 55*61c4878aSAndroid Build Coastguard Worker .. tab-item:: CMake 56*61c4878aSAndroid Build Coastguard Worker 57*61c4878aSAndroid Build Coastguard Worker Add ``pw_string`` to your ``pw_add_library`` or similar CMake target: 58*61c4878aSAndroid Build Coastguard Worker 59*61c4878aSAndroid Build Coastguard Worker .. code-block:: 60*61c4878aSAndroid Build Coastguard Worker 61*61c4878aSAndroid Build Coastguard Worker pw_add_library(my_library STATIC 62*61c4878aSAndroid Build Coastguard Worker HEADERS 63*61c4878aSAndroid Build Coastguard Worker ... 64*61c4878aSAndroid Build Coastguard Worker PRIVATE_DEPS 65*61c4878aSAndroid Build Coastguard Worker # ... 66*61c4878aSAndroid Build Coastguard Worker pw_string 67*61c4878aSAndroid Build Coastguard Worker # ... 68*61c4878aSAndroid Build Coastguard Worker ) 69*61c4878aSAndroid Build Coastguard Worker 70*61c4878aSAndroid Build Coastguard Worker For a narrower dependency, depend on subtargets like 71*61c4878aSAndroid Build Coastguard Worker ``pw_string.builder``, etc. 72*61c4878aSAndroid Build Coastguard Worker 73*61c4878aSAndroid Build Coastguard Worker .. tab-item:: Zephyr 74*61c4878aSAndroid Build Coastguard Worker 75*61c4878aSAndroid Build Coastguard Worker There are two ways to use ``pw_string`` from a Zephyr project: 76*61c4878aSAndroid Build Coastguard Worker 77*61c4878aSAndroid Build Coastguard Worker #. Depend on ``pw_string`` in your CMake target (see CMake tab). This is 78*61c4878aSAndroid Build Coastguard Worker Pigweed Team's suggested approach since it enables precise CMake 79*61c4878aSAndroid Build Coastguard Worker dependency analysis. 80*61c4878aSAndroid Build Coastguard Worker 81*61c4878aSAndroid Build Coastguard Worker #. Add ``CONFIG_PIGWEED_STRING=y`` to the Zephyr project's configuration, 82*61c4878aSAndroid Build Coastguard Worker which causes ``pw_string`` to become a global dependency and have the 83*61c4878aSAndroid Build Coastguard Worker includes exposed to all targets. Pigweed team does not recommend this 84*61c4878aSAndroid Build Coastguard Worker approach, though it is the typical Zephyr solution. 85*61c4878aSAndroid Build Coastguard Worker 86*61c4878aSAndroid Build Coastguard WorkerChoose between pw::InlineString and pw::StringBuilder 87*61c4878aSAndroid Build Coastguard Worker===================================================== 88*61c4878aSAndroid Build Coastguard Worker`pw::InlineString` is intended to replace typical null terminated character 89*61c4878aSAndroid Build Coastguard Workerarrays in embedded data structures. Use :cpp:type:`pw::InlineString` if you 90*61c4878aSAndroid Build Coastguard Workerneed: 91*61c4878aSAndroid Build Coastguard Worker 92*61c4878aSAndroid Build Coastguard Worker* Compatibility with ``std::string`` 93*61c4878aSAndroid Build Coastguard Worker* Storage internal to the object 94*61c4878aSAndroid Build Coastguard Worker* A string object to persist in other data structures 95*61c4878aSAndroid Build Coastguard Worker* Lower code size overhead 96*61c4878aSAndroid Build Coastguard Worker 97*61c4878aSAndroid Build Coastguard Worker`pw::StringBuilder` is intended to ease constructing strings in external data; 98*61c4878aSAndroid Build Coastguard Workertypically created on the stack and disposed of in the same function. Use 99*61c4878aSAndroid Build Coastguard Worker:cpp:class:`pw::StringBuilder` if you need: 100*61c4878aSAndroid Build Coastguard Worker 101*61c4878aSAndroid Build Coastguard Worker* Compatibility with ``std::ostringstream``, including custom object support 102*61c4878aSAndroid Build Coastguard Worker* Storage external to the object 103*61c4878aSAndroid Build Coastguard Worker* Non-fatal handling of failed append/format operations 104*61c4878aSAndroid Build Coastguard Worker* Tracking of the status of a series of operations 105*61c4878aSAndroid Build Coastguard Worker* A temporary stack object to aid string construction 106*61c4878aSAndroid Build Coastguard Worker* Medium code size overhead 107*61c4878aSAndroid Build Coastguard Worker 108*61c4878aSAndroid Build Coastguard WorkerAn example of when to prefer :cpp:type:`pw::InlineString` is wrapping a 109*61c4878aSAndroid Build Coastguard Workerlength-delimited string (e.g. ``std::string_view``) for APIs that require null 110*61c4878aSAndroid Build Coastguard Workertermination: 111*61c4878aSAndroid Build Coastguard Worker 112*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 113*61c4878aSAndroid Build Coastguard Worker 114*61c4878aSAndroid Build Coastguard Worker #include <string> 115*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h" 116*61c4878aSAndroid Build Coastguard Worker #include "pw_string/string_builder.h" 117*61c4878aSAndroid Build Coastguard Worker 118*61c4878aSAndroid Build Coastguard Worker void ProcessName(std::string_view name) { 119*61c4878aSAndroid Build Coastguard Worker // %s format strings require null terminated strings, so create one on the 120*61c4878aSAndroid Build Coastguard Worker // stack with size up to kMaxNameLen, copy the string view `name` contents 121*61c4878aSAndroid Build Coastguard Worker // into it, add a null terminator, and log it. 122*61c4878aSAndroid Build Coastguard Worker PW_LOG_DEBUG("The name is %s", 123*61c4878aSAndroid Build Coastguard Worker pw::InlineString<kMaxNameLen>(name).c_str()); 124*61c4878aSAndroid Build Coastguard Worker } 125*61c4878aSAndroid Build Coastguard Worker 126*61c4878aSAndroid Build Coastguard WorkerAn example of when to prefer :cpp:class:`pw::StringBuilder` is when 127*61c4878aSAndroid Build Coastguard Workerconstructing a string for external use. 128*61c4878aSAndroid Build Coastguard Worker 129*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 130*61c4878aSAndroid Build Coastguard Worker 131*61c4878aSAndroid Build Coastguard Worker #include "pw_string/string_builder.h" 132*61c4878aSAndroid Build Coastguard Worker 133*61c4878aSAndroid Build Coastguard Worker pw::Status FlushSensorValueToUart(int32_t sensor_value) { 134*61c4878aSAndroid Build Coastguard Worker pw::StringBuffer<42> sb; 135*61c4878aSAndroid Build Coastguard Worker sb << "Sensor value: "; 136*61c4878aSAndroid Build Coastguard Worker sb << sensor_value; // Formats as int. 137*61c4878aSAndroid Build Coastguard Worker FlushCStringToUart(sb.c_str()); 138*61c4878aSAndroid Build Coastguard Worker 139*61c4878aSAndroid Build Coastguard Worker if (!sb.status().ok) { 140*61c4878aSAndroid Build Coastguard Worker format_error_metric.Increment(); // Track overflows. 141*61c4878aSAndroid Build Coastguard Worker } 142*61c4878aSAndroid Build Coastguard Worker return sb.status(); 143*61c4878aSAndroid Build Coastguard Worker } 144*61c4878aSAndroid Build Coastguard Worker 145*61c4878aSAndroid Build Coastguard Worker.. _module-pw_string-guide-stringbuilder: 146*61c4878aSAndroid Build Coastguard Worker 147*61c4878aSAndroid Build Coastguard WorkerBuild a string with pw::StringBuilder 148*61c4878aSAndroid Build Coastguard Worker===================================== 149*61c4878aSAndroid Build Coastguard WorkerThe following shows basic use of a :cpp:class:`pw::StringBuilder`. 150*61c4878aSAndroid Build Coastguard Worker 151*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 152*61c4878aSAndroid Build Coastguard Worker 153*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h" 154*61c4878aSAndroid Build Coastguard Worker #include "pw_string/string_builder.h" 155*61c4878aSAndroid Build Coastguard Worker 156*61c4878aSAndroid Build Coastguard Worker pw::Status LogProducedData(std::string_view func_name, 157*61c4878aSAndroid Build Coastguard Worker span<const std::byte> data) { 158*61c4878aSAndroid Build Coastguard Worker // pw::StringBuffer allocates a pw::StringBuilder with a built-in buffer. 159*61c4878aSAndroid Build Coastguard Worker pw::StringBuffer<42> sb; 160*61c4878aSAndroid Build Coastguard Worker 161*61c4878aSAndroid Build Coastguard Worker // Append a std::string_view to the buffer. 162*61c4878aSAndroid Build Coastguard Worker sb << func_name; 163*61c4878aSAndroid Build Coastguard Worker 164*61c4878aSAndroid Build Coastguard Worker // Append a format string to the buffer. 165*61c4878aSAndroid Build Coastguard Worker sb.Format(" produced %d bytes of data: ", static_cast<int>(data.data())); 166*61c4878aSAndroid Build Coastguard Worker 167*61c4878aSAndroid Build Coastguard Worker // Append bytes as hex to the buffer. 168*61c4878aSAndroid Build Coastguard Worker sb << data; 169*61c4878aSAndroid Build Coastguard Worker 170*61c4878aSAndroid Build Coastguard Worker // Log the final string. 171*61c4878aSAndroid Build Coastguard Worker PW_LOG_DEBUG("%s", sb.c_str()); 172*61c4878aSAndroid Build Coastguard Worker 173*61c4878aSAndroid Build Coastguard Worker // Errors encountered while mutating the string builder are tracked. 174*61c4878aSAndroid Build Coastguard Worker return sb.status(); 175*61c4878aSAndroid Build Coastguard Worker } 176*61c4878aSAndroid Build Coastguard Worker 177*61c4878aSAndroid Build Coastguard WorkerBuild a string with pw::InlineString 178*61c4878aSAndroid Build Coastguard Worker==================================== 179*61c4878aSAndroid Build Coastguard Worker:cpp:type:`pw::InlineString` objects must be constructed by specifying a fixed 180*61c4878aSAndroid Build Coastguard Workercapacity for the string. 181*61c4878aSAndroid Build Coastguard Worker 182*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 183*61c4878aSAndroid Build Coastguard Worker 184*61c4878aSAndroid Build Coastguard Worker #include "pw_string/string.h" 185*61c4878aSAndroid Build Coastguard Worker 186*61c4878aSAndroid Build Coastguard Worker // Initialize from a C string. 187*61c4878aSAndroid Build Coastguard Worker pw::InlineString<32> inline_string = "Literally"; 188*61c4878aSAndroid Build Coastguard Worker inline_string.append('?', 3); // contains "Literally???" 189*61c4878aSAndroid Build Coastguard Worker 190*61c4878aSAndroid Build Coastguard Worker // Supports copying into known-capacity strings. 191*61c4878aSAndroid Build Coastguard Worker pw::InlineString<64> other = inline_string; 192*61c4878aSAndroid Build Coastguard Worker 193*61c4878aSAndroid Build Coastguard Worker // Supports various helpful std::string functions 194*61c4878aSAndroid Build Coastguard Worker if (inline_string.starts_with("Lit") || inline_string == "not\0literally"sv) { 195*61c4878aSAndroid Build Coastguard Worker other += inline_string; 196*61c4878aSAndroid Build Coastguard Worker } 197*61c4878aSAndroid Build Coastguard Worker 198*61c4878aSAndroid Build Coastguard Worker // Like std::string, InlineString is always null terminated when accessed 199*61c4878aSAndroid Build Coastguard Worker // through c_str(). InlineString can be used to null-terminate 200*61c4878aSAndroid Build Coastguard Worker // length-delimited strings for APIs that expect null-terminated strings. 201*61c4878aSAndroid Build Coastguard Worker std::string_view file(".gif"); 202*61c4878aSAndroid Build Coastguard Worker if (std::fopen(pw::InlineString<kMaxNameLen>(file).c_str(), "r") == nullptr) { 203*61c4878aSAndroid Build Coastguard Worker return; 204*61c4878aSAndroid Build Coastguard Worker } 205*61c4878aSAndroid Build Coastguard Worker 206*61c4878aSAndroid Build Coastguard Worker // pw::InlineString integrates well with std::string_view. It supports 207*61c4878aSAndroid Build Coastguard Worker // implicit conversions to and from std::string_view. 208*61c4878aSAndroid Build Coastguard Worker inline_string = std::string_view("not\0literally", 12); 209*61c4878aSAndroid Build Coastguard Worker 210*61c4878aSAndroid Build Coastguard Worker FunctionThatTakesAStringView(inline_string); 211*61c4878aSAndroid Build Coastguard Worker 212*61c4878aSAndroid Build Coastguard Worker FunctionThatTakesAnInlineString(std::string_view("1234", 4)); 213*61c4878aSAndroid Build Coastguard Worker 214*61c4878aSAndroid Build Coastguard WorkerBuild a string inside an pw::InlineString with a pw::StringBuilder 215*61c4878aSAndroid Build Coastguard Worker================================================================== 216*61c4878aSAndroid Build Coastguard Worker:cpp:class:`pw::StringBuilder` can build a string in a 217*61c4878aSAndroid Build Coastguard Worker:cpp:type:`pw::InlineString`: 218*61c4878aSAndroid Build Coastguard Worker 219*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 220*61c4878aSAndroid Build Coastguard Worker 221*61c4878aSAndroid Build Coastguard Worker #include "pw_string/string.h" 222*61c4878aSAndroid Build Coastguard Worker 223*61c4878aSAndroid Build Coastguard Worker void DoFoo() { 224*61c4878aSAndroid Build Coastguard Worker InlineString<32> inline_str; 225*61c4878aSAndroid Build Coastguard Worker StringBuilder sb(inline_str); 226*61c4878aSAndroid Build Coastguard Worker sb << 123 << "456"; 227*61c4878aSAndroid Build Coastguard Worker // inline_str contains "456" 228*61c4878aSAndroid Build Coastguard Worker } 229*61c4878aSAndroid Build Coastguard Worker 230*61c4878aSAndroid Build Coastguard WorkerPass an pw::InlineString object as a parameter 231*61c4878aSAndroid Build Coastguard Worker============================================== 232*61c4878aSAndroid Build Coastguard Worker:cpp:type:`pw::InlineString` objects can be passed to non-templated functions 233*61c4878aSAndroid Build Coastguard Workervia type erasure. This saves code size in most cases, since it avoids template 234*61c4878aSAndroid Build Coastguard Workerexpansions triggered by string size differences. 235*61c4878aSAndroid Build Coastguard Worker 236*61c4878aSAndroid Build Coastguard WorkerUnknown size strings 237*61c4878aSAndroid Build Coastguard Worker-------------------- 238*61c4878aSAndroid Build Coastguard WorkerTo operate on :cpp:type:`pw::InlineString` objects without knowing their type, 239*61c4878aSAndroid Build Coastguard Workeruse the ``pw::InlineString<>`` type, shown in the examples below: 240*61c4878aSAndroid Build Coastguard Worker 241*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 242*61c4878aSAndroid Build Coastguard Worker 243*61c4878aSAndroid Build Coastguard Worker // Note that the first argument is a generically-sized InlineString. 244*61c4878aSAndroid Build Coastguard Worker void RemoveSuffix(pw::InlineString<>& string, std::string_view suffix) { 245*61c4878aSAndroid Build Coastguard Worker if (string.ends_with(suffix)) { 246*61c4878aSAndroid Build Coastguard Worker string.resize(string.size() - suffix.size()); 247*61c4878aSAndroid Build Coastguard Worker } 248*61c4878aSAndroid Build Coastguard Worker } 249*61c4878aSAndroid Build Coastguard Worker 250*61c4878aSAndroid Build Coastguard Worker void DoStuff() { 251*61c4878aSAndroid Build Coastguard Worker pw::InlineString<32> str1 = "Good morning!"; 252*61c4878aSAndroid Build Coastguard Worker RemoveSuffix(str1, " morning!"); 253*61c4878aSAndroid Build Coastguard Worker 254*61c4878aSAndroid Build Coastguard Worker pw::InlineString<40> str2 = "Good"; 255*61c4878aSAndroid Build Coastguard Worker RemoveSuffix(str2, " morning!"); 256*61c4878aSAndroid Build Coastguard Worker 257*61c4878aSAndroid Build Coastguard Worker PW_ASSERT(str1 == str2); 258*61c4878aSAndroid Build Coastguard Worker } 259*61c4878aSAndroid Build Coastguard Worker 260*61c4878aSAndroid Build Coastguard WorkerHowever, generically sized :cpp:type:`pw::InlineString` objects don't work in 261*61c4878aSAndroid Build Coastguard Worker``constexpr`` contexts. 262*61c4878aSAndroid Build Coastguard Worker 263*61c4878aSAndroid Build Coastguard WorkerKnown size strings 264*61c4878aSAndroid Build Coastguard Worker------------------ 265*61c4878aSAndroid Build Coastguard Worker:cpp:type:`pw::InlineString` operations on known-size strings may be used in 266*61c4878aSAndroid Build Coastguard Worker``constexpr`` expressions. 267*61c4878aSAndroid Build Coastguard Worker 268*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 269*61c4878aSAndroid Build Coastguard Worker 270*61c4878aSAndroid Build Coastguard Worker static constexpr pw::InlineString<64> kMyString = [] { 271*61c4878aSAndroid Build Coastguard Worker pw::InlineString<64> string; 272*61c4878aSAndroid Build Coastguard Worker 273*61c4878aSAndroid Build Coastguard Worker for (int i = 0; i < 10; ++i) { 274*61c4878aSAndroid Build Coastguard Worker string += "Hello"; 275*61c4878aSAndroid Build Coastguard Worker } 276*61c4878aSAndroid Build Coastguard Worker 277*61c4878aSAndroid Build Coastguard Worker return string; 278*61c4878aSAndroid Build Coastguard Worker }(); 279*61c4878aSAndroid Build Coastguard Worker 280*61c4878aSAndroid Build Coastguard WorkerInitialization of pw::InlineString objects 281*61c4878aSAndroid Build Coastguard Worker=========================================== 282*61c4878aSAndroid Build Coastguard Worker:cpp:type:`pw::InlineBasicString` supports class template argument deduction 283*61c4878aSAndroid Build Coastguard Worker(CTAD) in C++17 and newer. Since :cpp:type:`pw::InlineString` is an alias, CTAD 284*61c4878aSAndroid Build Coastguard Workeris not supported until C++20. 285*61c4878aSAndroid Build Coastguard Worker 286*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++ 287*61c4878aSAndroid Build Coastguard Worker 288*61c4878aSAndroid Build Coastguard Worker // Deduces a capacity of 5 characters to match the 5-character string literal 289*61c4878aSAndroid Build Coastguard Worker // (not counting the null terminator). 290*61c4878aSAndroid Build Coastguard Worker pw::InlineBasicString inline_string = "12345"; 291*61c4878aSAndroid Build Coastguard Worker 292*61c4878aSAndroid Build Coastguard Worker // In C++20, CTAD may be used with the pw::InlineString alias. 293*61c4878aSAndroid Build Coastguard Worker pw::InlineString my_other_string("123456789"); 294*61c4878aSAndroid Build Coastguard Worker 295*61c4878aSAndroid Build Coastguard WorkerCustom types with pw::StringBuilder 296*61c4878aSAndroid Build Coastguard Worker=================================== 297*61c4878aSAndroid Build Coastguard WorkerAs with ``std::ostream``, pw::StringBuilder supports printing custom types by 298*61c4878aSAndroid Build Coastguard Workeroverriding the ``<<`` operator. This is is done by defining ``operator<<`` in 299*61c4878aSAndroid Build Coastguard Workerthe same namespace as the custom type. For example: 300*61c4878aSAndroid Build Coastguard Worker 301*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 302*61c4878aSAndroid Build Coastguard Worker 303*61c4878aSAndroid Build Coastguard Worker namespace my_project { 304*61c4878aSAndroid Build Coastguard Worker 305*61c4878aSAndroid Build Coastguard Worker struct MyType { 306*61c4878aSAndroid Build Coastguard Worker int foo; 307*61c4878aSAndroid Build Coastguard Worker const char* bar; 308*61c4878aSAndroid Build Coastguard Worker }; 309*61c4878aSAndroid Build Coastguard Worker 310*61c4878aSAndroid Build Coastguard Worker pw::StringBuilder& operator<<(pw::StringBuilder& sb, const MyType& value) { 311*61c4878aSAndroid Build Coastguard Worker return sb << "MyType(" << value.foo << ", " << value.bar << ')'; 312*61c4878aSAndroid Build Coastguard Worker } 313*61c4878aSAndroid Build Coastguard Worker 314*61c4878aSAndroid Build Coastguard Worker } // namespace my_project 315*61c4878aSAndroid Build Coastguard Worker 316*61c4878aSAndroid Build Coastguard WorkerInternally, ``StringBuilder`` uses the ``ToString`` function to print. The 317*61c4878aSAndroid Build Coastguard Worker``ToString`` template function can be specialized to support custom types with 318*61c4878aSAndroid Build Coastguard Worker``StringBuilder``, though it is recommended to overload ``operator<<`` instead. 319*61c4878aSAndroid Build Coastguard WorkerThis example shows how to specialize ``pw::ToString``: 320*61c4878aSAndroid Build Coastguard Worker 321*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 322*61c4878aSAndroid Build Coastguard Worker 323*61c4878aSAndroid Build Coastguard Worker #include "pw_string/to_string.h" 324*61c4878aSAndroid Build Coastguard Worker 325*61c4878aSAndroid Build Coastguard Worker namespace pw { 326*61c4878aSAndroid Build Coastguard Worker 327*61c4878aSAndroid Build Coastguard Worker template <> 328*61c4878aSAndroid Build Coastguard Worker StatusWithSize ToString<MyStatus>(MyStatus value, span<char> buffer) { 329*61c4878aSAndroid Build Coastguard Worker return Copy(MyStatusString(value), buffer); 330*61c4878aSAndroid Build Coastguard Worker } 331*61c4878aSAndroid Build Coastguard Worker 332*61c4878aSAndroid Build Coastguard Worker } // namespace pw 333