Buffer Algorithms
Counting Bytes
buffer_size returns the total number of bytes across every buffer in a sequence:
auto buf1 = capy::make_buffer("hello"sv); // 5 bytes
auto buf2 = capy::make_buffer("world"sv); // 5 bytes
auto buf3 = capy::make_buffer(""sv); // 0 bytes
auto combined = std::array{buf1, buf2, buf3};
assert(capy::buffer_size(combined) == 10);
buffers_empty reports whether a sequence carries no data,
either because it holds no buffers or because every buffer has size zero.
It is a shorthand for buffer_size(bufseq) == 0.
auto buf = capy::make_buffer(""sv); // 0 bytes
assert(capy::buffers_empty(buf));
Capy allows passing zero-size buffers to read and write operations. This is to cover the situations where the size of the buffer is determined dynamically, based on incoming messages. A protocol may require that a sender first communicates the size of a message, and then the bytes of the message. In such protocols, having nothing to send may be correctly represented by sending the number zero, followed by no bytes. This would translate into later using a zero-size buffer.
|
The following two functions have similar names but return different values:
A three-buffer sequence of 100 bytes each has a |
Copying Bytes
buffer_copy copies bytes from one buffer sequence to another and returns the number of bytes copied:
const char source_data[] = "hello world";
char dest_data[20];
capy::const_buffer src(source_data, 11);
capy::mutable_buffer dst(dest_data, 20);
std::size_t copied = capy::buffer_copy(dst, src);
assert(copied == 11);
The number of copied bytes is the smaller byte count of the source and target buffer sequences:
void copy_test(capy::MutableBufferSequence auto target,
capy::ConstBufferSequence auto source)
{
size_t smaller_count = std::min(capy::buffer_size(target),
capy::buffer_size(source));
std::size_t copied = capy::buffer_copy(target, source);
assert(copied == smaller_count);
}
You can additionally cap the number of copied bytes in the third function argument, which is useful for protocols with size limits:
std::size_t copied = capy::buffer_copy(dst, src, 4);
assert(copied == 4);
Source and target need not have the same shape:
// Source: 3 buffers
std::array<capy::const_buffer, 3> src = {buf1, buf2, buf3};
// Target: 2 buffers with different sizes
std::array<capy::mutable_buffer, 2> dst = {large_buf, small_buf};
// Copies across buffer boundaries as needed
std::size_t copied = capy::buffer_copy(dst, src);
The algorithm fills target buffers in order, reading from source buffers as needed. It handles a source buffer spanning several targets, and the reverse.
Capy creates and manages buffer handles on your behalf, such as the descriptors a type-erased stream passes to the OS. Each is valid only for the window its API documents.
Custom Buffer Types
You can define your own type satisfying the concepts:
class chunked_buffer_sequence
{
std::vector<std::vector<char>> chunks_;
public:
auto begin() const { return chunk_iterator(chunks_.begin()); }
auto end() const { return chunk_iterator(chunks_.end()); }
};
// Satisfies ConstBufferSequence—works with all algorithms
Here chunk_iterator is a small bidirectional iterator whose operator* returns each chunk as a const_buffer.