pw_multibuf#
A buffer API optimized for zero-copy messaging
Unstable C++17
Many forms of device I/O, including sending or receiving messages via RPC,
transfer, or sockets, need to deal with multiple buffers or a series of
intermediate buffers, each requiring their own copy of the data. pw_multibuf
allows data to be written once, eliminating the memory, CPU and latency
overhead of copying, and aggregates the memory regions in a manner
that is:
Flexible: Memory regions can be discontiguous and have different ownership semantics. Memory regions can be added and removed with few restrictions.
Copy-averse: Users can pass around and mutate MultiBuf instances without copying or moving data in-memory.
Compact: The sequence of memory regions and details about them are stored in only a few words of additional metadata.
1 MultiBuf::Instance mbuf(allocator);
2 // DOCSTAG: [pw_multibuf-examples-basic-allocator]
3
4 // Add some memory regions.
5 std::array<std::byte, 16> buffer;
6 mbuf->PushBack(buffer);
7 mbuf->Insert(mbuf->begin() + 8, allocator.MakeShared<std::byte[]>(16));
8 mbuf->PushBack(allocator.MakeUnique<std::byte[]>(16));
9
10 // Iterate and fill with data.
11 std::fill(mbuf->begin(), mbuf->end(), std::byte(0xFF));
12
13 // Access a discontiguous region.
14 std::array<std::byte, 16> tmp;
15 ConstByteSpan bytes = mbuf->Get(tmp, /*offset=*/16);
16 for (const auto b : bytes) {
17 EXPECT_EQ(static_cast<uint8_t>(b), 0xFF);
18 }
19
20 // Free owned memory.
21 mbuf->Clear();
For the complete example, see pw_multibuf/examples/basic.cc.
What kinds of data is this for?#
pw_multibuf
is best used in code that wants to read, write, or pass along
data which are one or more of the following:
Large: The MultiBuf type allows breaking up data into multiple chunks.
Heterogeneous: MultiBuf instances allow combining data that is uniquely owned, shared, or externally managed, and encapsulates the details of deallocating the memory it owns.
Latency-sensitive: Since they are copy-averse, MultiBuf instances are useful when working in systems that need to pass large amounts of data, or when memory usage is constrained.
Discontiguous: MultiBuf instances provide an interface to accessing and modifying memory regions that encapsulates where the memory actually resides.
Communications-oriented: Data which is being received or sent across sockets, various packets, or shared-memory protocols can benefit from the fragmentation, multiplexing, and layering features of the MultiBuf type.