System I/O Integration
This section explains how buffer sequences interface with operating system I/O operations.
Prerequisites
-
Completed Buffer Sequences
-
Understanding of buffer sequence concepts
The Virtual Boundary
User-facing APIs use concepts for composition flexibility. But at type-erasure boundaries—where virtual functions are needed—concrete types are required.
Capy’s design:
-
User-facing API — Accepts
ConstBufferSequenceorMutableBufferSequenceconcepts -
Internal boundary — Converts to concrete arrays for virtual dispatch
-
OS interface — Translates to platform-specific structures
The library handles all conversions automatically.
Platform Buffer Structures
Translation Process
When you call an I/O function with a buffer sequence:
template<ConstBufferSequence Buffers>
io_result<std::size_t> write_some(Buffers const& buffers);
Internally, Capy:
-
Counts the number of buffers in the sequence
-
Allocates space for platform buffer structures (on stack for small sequences)
-
Copies buffer descriptors (pointer/size pairs) to platform structures
-
Calls the OS function with the platform array
-
Returns the result
Stack-Based Conversion
For common cases (small numbers of buffers), conversion happens on the stack:
// Pseudocode of internal implementation
template<ConstBufferSequence Buffers>
auto platform_write(Buffers const& buffers)
{
std::size_t count = buffer_length(buffers);
if (count <= 8) // Small buffer optimization
{
iovec iovecs[8];
fill_iovecs(iovecs, buffers, count);
return writev(fd, iovecs, count);
}
else // Heap fallback
{
std::vector<iovec> iovecs(count);
fill_iovecs(iovecs.data(), buffers, count);
return writev(fd, iovecs.data(), count);
}
}
Most real-world code uses fewer than 8 buffers, so heap allocation is rarely needed.
Scatter/Gather Benefits
Using vectored I/O provides:
Fewer System Calls
Without scatter/gather:
write(fd, header, header_len); // syscall 1
write(fd, body, body_len); // syscall 2
With scatter/gather:
iovec iov[2] = {{header, header_len}, {body, body_len}};
writev(fd, iov, 2); // single syscall
Registered Buffers
Advanced platforms offer registered buffer optimizations:
Writing Efficient Code
Minimize Buffer Count
Fewer buffers means less translation overhead:
// Prefer: single buffer when possible
auto buf = assemble_message(); // Build in one buffer
write(stream, buf);
// Avoid: many tiny buffers
std::array<const_buffer, 100> tiny_bufs;
write(stream, tiny_bufs); // 100-element translation
Reuse Buffer Structures
For repeated I/O with the same structure, consider caching the platform buffer array:
// Build once, use many times
struct message_buffers
{
std::array<iovec, 3> iovecs;
void set_header(void const* p, std::size_t n);
void set_body(void const* p, std::size_t n);
void set_footer(void const* p, std::size_t n);
};
Reference
The buffer sequence concepts and translation utilities are in:
#include <boost/capy/buffers.hpp>
OS-specific I/O is handled by Corosio, which builds on Capy’s buffer model.
You have now learned how buffer sequences integrate with operating system I/O. Continue to Buffer Algorithms to learn about measuring and copying buffers.