Buffer Types
This section introduces Capy’s fundamental buffer types: const_buffer and mutable_buffer.
Prerequisites
-
Completed Why Concepts, Not Spans
-
Understanding of why concept-driven buffers enable composition
Why Not std::byte?
std::byte imposes a semantic opinion. It says "this is raw bytes"—but that is itself an opinion about the data’s nature.
POSIX uses void* for buffers. This expresses semantic neutrality: "I move memory without opining on what it contains." The OS doesn’t care if the bytes represent text, integers, or compressed data—it moves them.
But std::span<void> doesn’t compile. C++ can’t express a type-agnostic buffer abstraction using span.
Capy provides const_buffer and mutable_buffer as semantically neutral buffer types with known layout.
const_buffer
const_buffer represents a contiguous region of read-only memory:
class const_buffer
{
public:
const_buffer() = default;
const_buffer(void const* data, std::size_t size) noexcept;
const_buffer(mutable_buffer const& b) noexcept; // Implicit conversion
void const* data() const noexcept;
std::size_t size() const noexcept;
const_buffer& operator+=(std::size_t n) noexcept; // Remove prefix
};
Construction
// From pointer and size
char data[] = "hello";
const_buffer buf(data, 5);
// From mutable_buffer (implicit)
mutable_buffer mbuf(data, 5);
const_buffer cbuf = mbuf; // OK: mutable -> const
mutable_buffer
mutable_buffer represents a contiguous region of writable memory:
class mutable_buffer
{
public:
mutable_buffer() = default;
mutable_buffer(void* data, std::size_t size) noexcept;
void* data() const noexcept;
std::size_t size() const noexcept;
mutable_buffer& operator+=(std::size_t n) noexcept;
};
The interface mirrors const_buffer, but data() returns non-const void*.
make_buffer
The make_buffer function creates buffers from various sources:
#include <boost/capy/buffers/make_buffer.hpp>
// From pointer and size
auto buf = make_buffer(ptr, size);
// From C array
char arr[10];
auto buf = make_buffer(arr);
// From std::array
std::array<char, 10> arr;
auto buf = make_buffer(arr);
// From std::vector
std::vector<char> vec(100);
auto buf = make_buffer(vec);
// From std::string
std::string str = "hello";
auto buf = make_buffer(str);
// From std::string_view
std::string_view sv = "hello";
auto buf = make_buffer(sv);
The returned buffer type depends on constness:
-
Non-const containers →
mutable_buffer -
Const containers,
string_view→const_buffer
Layout Compatibility
const_buffer and mutable_buffer have the same memory layout as OS buffer structures:
-
POSIX:
struct iovec { void* iov_base; size_t iov_len; } -
Windows:
struct WSABUF { ULONG len; CHAR* buf; }(note: different order)
This means conversion to OS structures is efficient—often just a reinterpret_cast for arrays of buffers.
Single Buffers as Sequences
A single buffer is a degenerate sequence—a sequence with one element. The ConstBufferSequence and MutableBufferSequence concepts recognize this:
template<ConstBufferSequence Buffers>
void write_data(Buffers const& buffers);
// All of these work:
write_data(make_buffer("hello")); // Single buffer
write_data(std::array{buf1, buf2, buf3}); // Multiple buffers
write_data(my_composite); // Custom sequence
The library provides begin() and end() functions that work uniformly:
const_buffer single;
auto it = begin(single); // Returns pointer to single
auto e = end(single); // Returns pointer past single
std::array<const_buffer, 3> multi;
auto it = begin(multi); // Returns multi.begin()
auto e = end(multi); // Returns multi.end()
Reference
| Header | Description |
|---|---|
|
Core buffer types and concepts |
|
Buffer creation utilities |
You have now learned about const_buffer and mutable_buffer. Continue to Buffer Sequences to understand how these types compose into sequences.