Buffer Sequences
Corosio socket operations accept any buffer sequence compatible with
Boost.Buffers. Internally, the socket implementation uses a type-erased
interface (any_bufref) to avoid templating the implementation on
buffer types.
Buffer Types
Boost.Buffers provides two fundamental buffer types:
// Mutable buffer - for reading into
boost::buffers::mutable_buffer buf(ptr, size);
// Const buffer - for writing from
boost::buffers::const_buffer buf(ptr, size);
Using Buffers with Sockets
Pass buffers directly to socket operations:
char data[1024];
// Read into a single buffer
auto [ec, n] = co_await s.read_some(
boost::buffers::mutable_buffer(data, sizeof(data)));
// Write from a single buffer
auto [ec2, n2] = co_await s.write_some(
boost::buffers::const_buffer(data, n));
Buffer Sequences
A buffer sequence is any range of buffers. Use arrays or vectors for scatter/gather I/O:
// Scatter read into multiple buffers
std::array<boost::buffers::mutable_buffer, 2> read_bufs = {
boost::buffers::mutable_buffer(header, header_size),
boost::buffers::mutable_buffer(body, body_size)
};
auto [ec, n] = co_await s.read_some(read_bufs);
// Gather write from multiple buffers
std::array<boost::buffers::const_buffer, 2> write_bufs = {
boost::buffers::const_buffer(header, header_size),
boost::buffers::const_buffer(body, body_size)
};
auto [ec2, n2] = co_await s.write_some(write_bufs);
The any_bufref Interface
Internally, Corosio uses any_bufref to type-erase buffer sequences.
This allows the socket implementation to remain non-templated while
accepting any buffer sequence type.
The interface is simple:
class any_bufref
{
public:
// Construct from any const buffer sequence
template<capy::const_buffer_sequence BufferSequence>
explicit any_bufref(BufferSequence const& bs) noexcept;
// Copy buffers to an array (e.g., WSABUF array)
std::size_t copy_to(capy::mutable_buffer* dest, std::size_t n);
};
Why Type Erasure?
Without type erasure, the socket implementation would need to be templated on every buffer sequence type used:
// Without type erasure - explosion of template instantiations
template<class Buffers>
void socket_impl::read_some(Buffers const& bufs, ...);
With type erasure, the implementation is fixed:
// With type erasure - single implementation
void socket_impl::read_some(any_bufref& bufs, ...);
The cost is a virtual call when iterating buffers, which is negligible compared to I/O latency.
Custom Buffer Sequences
Any type that satisfies MutableBufferSequence or ConstBufferSequence
works with Corosio:
struct my_buffer_sequence
{
// Buffer type
using value_type = boost::buffers::mutable_buffer;
// Iterator support
auto begin() const { return buffers_.begin(); }
auto end() const { return buffers_.end(); }
private:
std::vector<boost::buffers::mutable_buffer> buffers_;
};
Performance Considerations
For maximum performance:
-
Prefer single buffers when possible—fewer iterations
-
Reuse buffers to avoid allocation
-
Size buffers appropriately—too small means more syscalls, too large wastes memory
Typical buffer sizes:
-
Small messages: 1-4 KB
-
Bulk transfers: 64 KB - 1 MB
-
High-throughput: Match TCP window size (typically 64 KB default)
Next Steps
-
Sockets — Socket read/write operations