Newer
Older
#ifndef __VEREIGN_BYTES_BUFFER_HH
#define __VEREIGN_BYTES_BUFFER_HH
#include <vereign/bytes/view.hh>
#include <cstring>
namespace vereign::bytes {
/**
* Dynamically expandable memory buffer.
*
* The buffer is a 3-tuple - pointer, size and capacity.
* Typically used in functions for output parameters and return values.
* Provides API that is easy to use with C APIs.
*
* The buffer is move only.
*/
/**
* Creates a buffer with reserved memory capacity.
*
* The size of the buffer is zero.
*
* @param cap The capacity of the buffer.
*
* @throws std::bad_alloc when memory reservation fails.
*/
/**
* Creates a buffer by copying from source bytes view.
*
* @param src The source that will be copied from.
*
* @throws std::bad_alloc when memory reservation fails.
*/
Buffer(Buffer&& other) noexcept;
auto operator=(Buffer&& other) noexcept -> Buffer&;
// disable copying
Buffer(const Buffer&) = delete;
auto operator=(const Buffer&) -> Buffer& = delete;
/**
* Returns a pointer to the first byte of the buffer.
*
* Buffer::begin(), Buffer::end() pair is useful for range loops.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("foo")};
* for (const auto& byte : buf) {
* byte = 'x';
* }
*
* assert(buf.View().String() == "xxx");
* @endcode
*/
/**
* Returns a pointer to the first byte of the buffer.
*
* Buffer::begin(), Buffer::end() pair is useful for range loops.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("foo bar")};
* std::string s;
*
* for (const auto& byte : buf) {
* s += byte;
* }
*
* assert(s == "foo bar");
* @endcode
*/
auto begin() const noexcept -> const uint8_t*;
/**
* Returns a pointer to the byte following the last byte in the buffer.
*
* Note that this is the last byte in the range [0, size).
* It is often used when calling C APIs.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("foo bar")};
*
* buf.Reserve(4);
* std::strncpy((char*)buf.end(), " baz", 4);
* buf.IncSize(4);
*
* assert(buf.View().String() == "foo bar baz");
* @endcode
*/
/**
* Returns a read only pointer to the byte following the last byte in the buffer.
*
* Note that this is the last byte in the range [0, size).
*/
auto end() const noexcept -> const uint8_t*;
/**
* Access a byte in the range of [0, cap).
*
* @param index The index of the byte to access.
*
* @throws std::runtime_error when the passed index is out of bounds.
*/
/**
* Read only access a byte in the range of [0, cap).
*
* @param index The index of the byte to access.
*
* @throws std::runtime_error when the passed index is out of bounds.
*/
auto operator[](std::size_t index) const -> const uint8_t&;
/**
* Retrieve buffer size.
*
* @returns the buffer size.
*/
/**
* Retrieve buffer capacity.
*
* @returns the buffer capacity.
*/
/**
* Reserve memory, so that there is at least `size` free capacity.
*
* If there is already enough free capacity, no memory allocation is done.
* The allocated memory may be bigger than what is needed.
*
* If the call is successful then it is guaranteed that `this->FreeCap() >= size`.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("foo bar")};
*
* buf.Reserve(4); // ensure there will be a free capacity for 4 bytes
* std::strncpy((char*)buf.end(), " baz", 4); // copy the bytes
* buf.IncSize(4); // update the buffer size with the newly written bytes
*
* assert(buf.View().String() == "foo bar baz");
* @endcode
*
* @param size The desired free capacity.
*
* @throws std::bad_alloc when memory allocation fails.
*/
/**
* Sets the buffer size to zero.
*
* This does not free any memory, so the capacity stays the intact, and the buffer can be reused.
*/
/**
* Increments the size of the buffer.
*
* It is typically used after some function has written bytes to the end of the buffer.
*
* @param val The value that will be added to the current size.
*/
void IncSize(std::size_t val);
/**
* Retrieve the buffer free capacity.
*
* This is equal to `this->Cap() - this->Size()`.
*/
/**
* Adds bytes up to the currently available buffer capacity.
*
* After the operation succeeds, the buffer size will be incremented with the number of bytes
* that have been copied.
*
* Example:
* @code
* auto buf = bytes::Buffer{3};
* buf.WriteWithinCap(bytes::View("foo bar"));
*
* // only 3 bytes are written
* assert(buf.View.String() == "foo");
* @endcode
*
* @param src The source that will be appended to the buffer.
* @returns The amount of bytes that were actually copied into the buffer.
*/
auto WriteWithinCap(bytes::View src) noexcept -> std::size_t;
/**
* Adds a source view of bytes to the buffer.
*
* If the buffer does not have enough capacity, it will be expanded.
*
* Example:
* @code
* auto buf = bytes::Buffer{3};
* buf.WriteWithinCap(bytes::View("foo bar"));
*
* // all bytes are written
* assert(buf.View.String() == "foo bar");
* @endcode
*
* @param The source that will be appended to the buffer.
* @returns The amount of bytes that were copied into the buffer. That is equal to src.Size().
*/
/**
* Retrieve a read only view of the buffer.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("123")};
* assert(buf.View().String() == "123");
* @endcode
*
* @returns a read only view range [0, this->Size()).
*/
/**
* Retrieve a read only view of the buffer staring from a given offset.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("123")};
* assert(buf.View(1).String() == "23");
* @endcode
*
* @returns a read only view range [start, this->Size()).
*/