Buffer Algorithms
This section covers algorithms for measuring and manipulating buffer sequences.
Prerequisites
-
Completed Buffer Sequences
-
Understanding of
ConstBufferSequenceand iteration
Measuring Buffers
buffer_size
Returns the total number of bytes across all buffers in a sequence:
template<ConstBufferSequence CB>
std::size_t buffer_size(CB const& buffers);
Example:
auto buf1 = make_buffer("hello"); // 5 bytes
auto buf2 = make_buffer("world"); // 5 bytes
auto combined = std::array{buf1, buf2};
std::size_t total = buffer_size(combined); // 10
Note: buffer_size returns the sum of bytes, not the count of buffers.
buffer_empty
Checks if a buffer sequence contains no data:
template<ConstBufferSequence CB>
bool buffer_empty(CB const& buffers);
A buffer sequence is empty if:
-
It contains no buffers, OR
-
All buffers have size zero
const_buffer empty_buf;
buffer_empty(empty_buf); // true
const_buffer non_empty("data", 4);
buffer_empty(non_empty); // false
buffer_length
Returns the number of buffers in a sequence:
template<ConstBufferSequence CB>
std::size_t buffer_length(CB const& buffers);
Example:
auto single = make_buffer("hello");
buffer_length(single); // 1
auto arr = std::array{buf1, buf2, buf3};
buffer_length(arr); // 3
Note the distinction:
-
buffer_size— total bytes (data measurement) -
buffer_length— number of buffers (sequence length)
Copying Buffers
buffer_copy
Copies data from one buffer sequence to another:
template<MutableBufferSequence Target, ConstBufferSequence Source>
std::size_t buffer_copy(Target const& target, Source const& source);
template<MutableBufferSequence Target, ConstBufferSequence Source>
std::size_t buffer_copy(Target const& target, Source const& source,
std::size_t at_most);
Returns the number of bytes copied.
Example:
char source_data[] = "hello world";
char dest_data[20];
const_buffer src(source_data, 11);
mutable_buffer dst(dest_data, 20);
std::size_t copied = buffer_copy(dst, src); // 11
Partial Copy with at_most
Limit the number of bytes copied:
std::size_t copied = buffer_copy(dst, src, 5); // Copy at most 5 bytes
This is useful for implementing protocols with size limits.
Cross-Sequence Copy
buffer_copy handles sequences with different structure:
// Source: 3 buffers
std::array<const_buffer, 3> src = {buf1, buf2, buf3};
// Target: 2 buffers with different sizes
std::array<mutable_buffer, 2> dst = {large_buf, small_buf};
// Copies across buffer boundaries as needed
std::size_t copied = buffer_copy(dst, src);
The algorithm fills target buffers sequentially, reading from source buffers as needed, handling cases where a single source buffer spans multiple target buffers or vice versa.
Real I/O Patterns
Read Loop
template<ReadStream Stream, MutableBufferSequence Buffers>
task<std::size_t> read_full(Stream& stream, Buffers buffers)
{
consuming_buffers<Buffers> remaining(buffers);
std::size_t total = 0;
while (buffer_size(remaining) > 0)
{
auto [ec, n] = co_await stream.read_some(remaining);
if (ec.failed())
co_return total; // Return partial read on error
remaining.consume(n);
total += n;
}
co_return total;
}
Write Loop
template<WriteStream Stream, ConstBufferSequence Buffers>
task<std::size_t> write_full(Stream& stream, Buffers buffers)
{
consuming_buffers<Buffers> remaining(buffers);
std::size_t total = 0;
while (buffer_size(remaining) > 0)
{
auto [ec, n] = co_await stream.write_some(remaining);
if (ec.failed())
co_return total;
remaining.consume(n);
total += n;
}
co_return total;
}
Practical Benefits of Concept-Based Design
Zero-Copy I/O
Data never moves unnecessarily. The buffer sequence points to existing data, and the OS reads directly from those locations:
std::string header = build_header();
std::vector<char> body = load_body();
// No copying—header and body are written directly
co_await write(stream, cat(make_buffer(header), make_buffer(body)));
Scatter/Gather Operations
Multiple buffers transfer in a single operation:
std::array buffers = {header_buf, separator_buf, body_buf, footer_buf};
co_await write(stream, buffers); // Single system call
Custom Allocators and Memory-Mapped Buffers
Any memory region can be a buffer:
// Memory-mapped file
void* mapped = mmap(...);
const_buffer file_buf(mapped, file_size);
co_await write(socket, file_buf); // Zero-copy network transmission
User-Defined Buffer Types
Create custom types that satisfy the concepts:
class chunked_buffer_sequence
{
std::vector<std::vector<char>> chunks_;
public:
auto begin() const { /* return iterator over chunks as buffers */ }
auto end() const { /* return end iterator */ }
};
// Satisfies ConstBufferSequence—works with all algorithms
Reference
| Header | Description |
|---|---|
|
Measurement algorithms ( |
|
Copy algorithm |
You have now learned how to measure and copy buffer sequences. Continue to Dynamic Buffers to learn about growable buffer storage.