59#ifdef OPENVPN_BUFFER_ABORT
60#define OPENVPN_BUFFER_THROW(exc) \
65#define OPENVPN_BUFFER_THROW(exc) \
67 throw BufferException(BufferException::exc); \
144 const char *
what() const noexcept
override
164 return "buffer_full";
166 return "buffer_headroom";
168 return "buffer_underflow";
170 return "buffer_overflow";
172 return "buffer_offset";
174 return "buffer_index";
176 return "buffer_const_index";
178 return "buffer_push_front_headroom";
180 return "buffer_no_reset_impl";
182 return "buffer_pop_back";
184 return "buffer_set_size";
186 return "buffer_range";
241 typedef typename std::remove_const_t<T>
NCT;
267 template <
typename U = T,
268 typename std::enable_if_t<!std::is_const_v<U>,
int> = 0>
286 template <
typename U = T,
287 typename std::enable_if_t<!std::is_const_v<U>,
int> = 0>
722 template <
typename B>
730 template <
typename T_>
754 virtual void resize(
const size_t new_capacity);
774 template <
typename U = T,
775 typename std::enable_if_t<!std::is_const_v<U>,
int> = 0>
874namespace BufAllocFlags {
935 template <
typename T_>
989 const size_t min_capacity,
998 template <
typename T_>
1007 template <
typename T_>
1016 template <
typename T_>
1079 void resize(
const size_t new_capacity)
override;
1101template <
typename T>
1104 static_assert(std::is_nothrow_move_constructible_v<ConstBufferType>,
1105 "class ConstBufferType not noexcept move constructable");
1107 offset_ = size_ = capacity_ = 0;
1110template <
typename T>
1114template <
typename T>
1115template <
typename U,
typename std::enable_if_t<!std::is_const_v<U>,
int>>
1119template <
typename T>
1123 size_(filled ? size : 0),
1126template <
typename T>
1127template <
typename U,
typename std::enable_if_t<!std::is_const_v<U>,
int>>
1131template <
typename T>
1136 return c_data()[index];
1139template <
typename T>
1144 if constexpr (std::is_same_v<ConstBufferType<T>,
decltype(*this)>)
1145 return c_data()[index];
1147 return data()[index];
1150template <
typename T>
1153 if (headroom > capacity_)
1159template <
typename T>
1162 const size_t size = size_ + offset_ - offset;
1163 if (offset > capacity_ || size > capacity_ || offset + size > capacity_)
1169template <
typename T>
1175template <
typename T>
1178 offset_ = size_ = 0;
1181template <
typename T>
1187template <
typename T>
1193template <
typename T>
1196 return data_ + offset_;
1199template <
typename T>
1202 return data_ + offset_ + size_;
1205template <
typename T>
1211template <
typename T>
1217template <
typename T>
1223template <
typename T>
1229template <
typename T>
1232 return data_ !=
nullptr;
1235template <
typename T>
1241template <
typename T>
1247template <
typename T>
1252 return *(c_data() + (--size_));
1255template <
typename T>
1264template <
typename T>
1270template <
typename T>
1273 return (*
this)[size_ - 1];
1276template <
typename T>
1285template <
typename T>
1288 const T *end = c_data_end();
1289 for (
const T *p = c_data(); p < end; ++p)
1297template <
typename T>
1300 const T *end = c_data_end();
1301 for (
const T *p = c_data(); p < end; ++p)
1309#ifndef OPENVPN_NO_IO
1311template <
typename T>
1314 return openvpn_io::const_buffer(c_data(), size());
1317template <
typename T>
1323template <
typename T>
1326 return openvpn_io::const_buffer(c_data(), std::min(
buf_clamp_write(size()), limit));
1330template <
typename T>
1333 std::memcpy(data, read_alloc(size), size *
sizeof(T));
1336template <
typename T>
1339 read((
NCT *)data, size);
1342template <
typename T>
1349 if constexpr (std::is_const_v<retT>)
1361template <
typename T>
1367 retT
ret(data_, offset_, size, capacity_);
1376template <
typename T>
1379 const size_t r = capacity_ - offset_;
1380 return r <= capacity_ ? r : 0;
1383template <
typename T>
1386 if (size > max_size())
1391template <
typename T>
1394 set_size(size_ + delta);
1397template <
typename T>
1400 if (offset + len > size())
1402 if (offset < size())
1403 len = size() - offset;
1410template <
typename T>
1415 return &c_data()[index];
1418template <
typename T>
1419template <
typename T_>
1422 std::swap(other.
data_, data_);
1423 std::swap(other.
offset_, offset_);
1424 std::swap(other.
size_, size_);
1428template <
typename T>
1431 if (size_ != other.
size_)
1433 return std::memcmp(c_data(), other.
c_data(), size_) == 0;
1436template <
typename T>
1439 return !(*
this == other);
1442template <
typename T>
1449template <
typename T>
1452 return data_ + offset_;
1455template <
typename T>
1458 return data_ + offset_ + size_;
1461template <
typename T>
1467template <
typename T>
1470 const size_t r = capacity_ - (offset_ + size_ + tailroom);
1471 return r <= capacity_ ? r : 0;
1474template <
typename T>
1477 const size_t r = capacity_ - (offset_ + tailroom);
1478 return r <= capacity_ ? r : 0;
1481template <
typename T>
1485 resize(offset_ + size_ + 1);
1486 *(data() + size_++) = value;
1489template <
typename T>
1499template <
typename T>
1503 resize(offset_ + size_ + 1);
1504 *(data() + size_) = value;
1507template <
typename T>
1510 if (empty() || back())
1514template <
typename T>
1519 return &data()[index];
1523#ifndef OPENVPN_NO_IO
1525template <
typename T>
1528 return openvpn_io::mutable_buffer(data(), max_size_tailroom(tailroom));
1531template <
typename T>
1534 return openvpn_io::mutable_buffer(data_end(), remaining(tailroom));
1537template <
typename T>
1540 return openvpn_io::mutable_buffer(data(),
buf_clamp_read(max_size_tailroom(tailroom)));
1543template <
typename T>
1546 return openvpn_io::mutable_buffer(data_end(),
buf_clamp_read(remaining(tailroom)));
1550template <
typename T>
1553 if (headroom != offset_)
1555 if (headroom + size_ > capacity_)
1557 std::memmove(data_ + headroom, data_ + offset_, size_);
1562template <
typename T>
1565 std::memcpy(write_alloc(size), data, size *
sizeof(T));
1568template <
typename T>
1571 write((
const T *)data, size);
1574template <
typename T>
1577 std::memcpy(prepend_alloc(size), data, size *
sizeof(T));
1580template <
typename T>
1583 prepend((
const T *)data, size);
1586template <
typename T>
1589 if (size > remaining())
1590 resize(offset_ + size_ + size);
1591 T *
ret = data() + size_;
1596template <
typename T>
1599 if (request_size > offset())
1600 realign(request_size);
1602 offset_ -= request_size;
1603 size_ += request_size;
1608template <
typename T>
1611 if (min_capacity > capacity_)
1612 reset_impl(min_capacity,
flags);
1615template <
typename T>
1617 const size_t min_capacity,
1620 reset(min_capacity,
flags);
1621 init_headroom(headroom);
1624template <
typename T>
1625template <
typename B>
1628 write(other.c_data(), other.size());
1631template <
typename T>
1637template <
typename T>
1640 if (new_capacity > capacity_)
1641 buffer_full_error(new_capacity,
false);
1644template <
typename T>
1647#ifdef OPENVPN_BUFFER_ABORT
1650 throw BufferException(
BufferException::buffer_full,
"allocated=" + std::to_string(allocated) +
" size=" + std::to_string(size_) +
" offset=" + std::to_string(offset_) +
" capacity=" + std::to_string(capacity_) +
" newcap=" + std::to_string(newcap));
1654template <
typename T>
1656 : data_(data), offset_(offset), size_(size), capacity_(capacity){};
1658template <
typename T>
1659template <
typename U,
typename std::enable_if_t<!std::is_const_v<U>,
int>>
1667template <
typename T>
1670 const size_t capacity,
1672 :
BufferType<T>(capacity ? new T[capacity] : nullptr, offset, size, capacity), flags_(
flags)
1678template <
typename T>
1682 static_assert(std::is_nothrow_move_constructible_v<BufferAllocatedType>,
1683 "class BufferAllocatedType not noexcept move constructable");
1686template <
typename T>
1690 (
flags & BufAllocFlags::ARRAY ? capacity : 0),
1694template <
typename T>
1704template <
typename T>
1712template <
typename T>
1713template <
typename T_>
1718 static_assert(
sizeof(T) ==
sizeof(T_),
"size inconsistency");
1723template <
typename T>
1733 std::memcpy(tempBuffer.data(), other.
c_data(), tempBuffer.size() *
sizeof(T));
1738template <
typename T>
1745template <
typename T>
1752template <
typename T>
1755 if (newcap > capacity())
1756 realloc_(newcap, offset());
1759template <
typename T>
1762 if (headroom != offset())
1764 if (headroom + size() > capacity())
1765 realloc_(headroom + size(), headroom);
1772template <
typename T>
1775 if (min_capacity > capacity())
1776 init(min_capacity,
flags);
1779template <
typename T>
1781 const size_t min_capacity,
1784 reset(min_capacity,
flags);
1785 init_headroom(headroom);
1788template <
typename T>
1789template <
typename T_>
1797template <
typename T>
1798template <
typename T_>
1802 std::swap(flags_, other.
flags_);
1805template <
typename T>
1806template <
typename T_>
1813template <
typename T>
1823template <
typename T>
1830template <
typename T>
1833 return flags_ &
flags;
1836template <
typename T>
1842template <
typename T>
1848template <
typename T>
1855template <
typename T>
1858 init(min_capacity,
flags);
1861template <
typename T>
1864 const size_t newcap = std::max(new_capacity, capacity() * 2);
1865 if (newcap > capacity())
1868 realloc_(newcap, offset());
1870 buffer_full_error(newcap,
true);
1874template <
typename T>
1879 std::memcpy(tempBuffer.data(), c_data(), size() *
sizeof(T));
1883template <
typename T>
1887 std::memset(data_raw(), 0, capacity() *
sizeof(T));
1888 delete[] data_raw();
1912template <
typename T_>
1919template <
typename T>
1925template <
typename T>
1942template <
typename AlignT,
typename T>
1956 auto data_ptr =
reinterpret_cast<uintptr_t
>(buf.
c_data());
1957 auto align_ptr = data_ptr & ~(
alignof(AlignT) - 1);
1958 auto raw_data_ptr =
reinterpret_cast<uintptr_t
>(buf.
c_data_raw());
1960 if (align_ptr != data_ptr && align_ptr >= raw_data_ptr)
1961 buf.
realign(align_ptr - raw_data_ptr);
1963 return reinterpret_cast<AlignT *
>(buf.
data());
#define OPENVPN_BUFFER_THROW(exc)
BufferAllocatedType(const size_t offset, const size_t size, const size_t capacity, const BufferFlags flags)
Private constructor.
friend class BufferAllocatedType
void clear()
Clears the contents of the buffer.
BufferAllocatedType & operator=(BufferAllocatedType &&other) noexcept
Move assignment operator.
void reset(const size_t min_capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Resets the buffer with the specified minimum capacity and flags.
void init(const size_t capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Initializes the buffer with the specified capacity and flags.
void clear_flags(const BufferFlags flags)
Clears the specified flags for the buffer.
BufferAllocatedType(const size_t capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Constructs a BufferAllocatedType with the specified capacity and flags.
void reset(const size_t headroom, const size_t min_capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Resets the buffer with the specified headroom, minimum capacity, and flags.
~BufferAllocatedType()
Destructor.
void resize(const size_t new_capacity) override
Resizes the buffer to the specified new capacity.
bool test_flags(const BufferFlags flags) const noexcept
Test if the buffer has the specified flags.
void add_flags(const BufferFlags flags)
Sets the specified flags for the buffer.
void move(BufferAllocatedType< T_ > &other)
Moves the contents of another BufferAllocatedType object into this object.
BufferAllocatedType()
Default constructor.
void realloc(const size_t newcap)
Reallocates the buffer to the specified new capacity.
void operator=(const BufferAllocatedType &other)
Assignment operator.
void reset_impl(const size_t min_capacity, const BufferFlags flags) override
Resets the buffer implementation with the specified minimum capacity and flags.
void init(const T *data, const size_t size, const BufferFlags flags)
Initializes the buffer with the specified data, size, and flags.
void realloc_(const size_t newcap, size_t new_offset)
Reallocates the buffer to the specified new capacity.
BufferAllocatedType & realign(const size_t headroom)
Realign the buffer with the specified headroom.
void free_data()
Frees the data associated with the buffer.
void swap(BufferAllocatedType< T_ > &other)
Swaps the contents of this BufferAllocatedType object with another BufferAllocatedType object.
BufferAllocatedType(const T *data, const size_t size, const BufferFlags flags)
Constructs a BufferAllocatedType with the specified data, size, and flags.
BufferAllocatedType(const BufferAllocatedType &other)
Copy constructor.
BufferAllocatedType(const BufferType< T_ > &other, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Constructs a BufferAllocatedType from a BufferType object with the specified flags.
BufferAllocatedType(BufferAllocatedType< T_ > &&other) noexcept
Move constructor.
report various types of exceptions or errors that may occur when working with buffers
const char * what() const noexcept override
virtual ~BufferException() noexcept=default
BufferException(Status status)
BufferException(Status status, const std::string &msg)
static const char * status_string(const Status status)
@ buffer_push_front_headroom
BufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
Protected constructor for BufferType that takes a T pointer, offset, size, and capacity.
BufferType()=default
Default constructor for BufferType.
BufferType(T *data, const size_t size, const bool filled)
Constructor for BufferType that takes a T pointer, size, and a flag indicating if the buffer is fille...
BufferType(void *data, const size_t size, const bool filled)
Constructor for BufferType that takes a void pointer, size, and a flag indicating if the buffer is fi...
Immutable buffer with double ended access and adjustable free space at both ends.
bool defined() const
Returns true if the buffer is not empty.
void set_trailer(const T &value)
Place a T object after the last object in the array, with possible resize to contain it....
const T * c_data() const
Returns a const pointer to the start of the buffer.
T * prepend_alloc(const size_t size)
Allocate space for prepending data to the buffer.
ConstBufferType(void *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a void pointer and size.
T * data_end()
Get a mutable pointer to the end of the array.
void append(const B &other)
Append data from another buffer to this buffer.
void init_headroom(const size_t headroom)
Initializes the headroom (offset) of the buffer.
void inc_size(const size_t delta)
Increment the size of the array (usually used in a similar context to set_size such as after mutable_...
size_t length() const
Returns the length of the buffer.
std::remove_const_t< T > NCT
openvpn_io::mutable_buffer mutable_buffer(const size_t tailroom=0)
Return an openvpn_io::mutable_buffer object used by asio read methods, starting from data().
size_t max_size() const
Return the maximum allowable size value in T objects given the current offset (without considering re...
openvpn_io::const_buffer const_buffer_limit(const size_t limit) const
Return a const_buffer object with a specified size limit.
T front() const
Returns the first element of the buffer.
virtual void reset_impl(const size_t min_capacity, const BufferFlags flags)
Called when the reset method needs to expand the buffer size.
ConstBufferType()
Default constructor for ConstBufferType.
openvpn_io::const_buffer const_buffer() const
Return an openvpn_io::const_buffer object used by asio write methods.
void push_back(const T &value)
Append a T object to the end of the array, resizing the array if necessary.
void reset(const size_t min_capacity, const BufferFlags flags)
Reset the buffer with the specified minimum capacity and flags.
T back() const
Returns the last element of the buffer.
ConstBufferType(const U *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a const pointer to T and size. This constructor is disabled when T ...
openvpn_io::mutable_buffer mutable_buffer_append_clamp(const size_t tailroom=0)
Clamped version of mutable_buffer_append().
ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
Construct a ConstBufferType object.
bool operator!=(const ConstBufferType &other) const
Inequality operator to compare this buffer with another ConstBufferType object.
ConstBufferType(T *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a pointer to T and size.
void write(const void *data, const size_t size)
Write data to the buffer.
ConstBufferType range(size_t offset, size_t len) const
Get a range of the buffer as a ConstBufferType object.
void read(void *data, const size_t size)
Read data from the buffer into the specified memory location.
ConstBufferType(const U *data, const size_t offset, const size_t size, const size_t capacity)
Construct a ConstBufferType object from a const U* pointer. This constructor is disabled when T is al...
const T * c_str() const
Returns a const pointer to the null-terminated string representation of the buffer.
T * write_alloc(const size_t size)
Allocate space for writing data to the buffer.
void reserve(const size_t n)
Reserve additional memory for the buffer.
const T * c_data_end() const
Returns a const pointer to the end of the buffer.
auto read_alloc_buf(const size_t size)
Allocate memory and read data from the buffer into the allocated memory.
void prepend(const T *data, const size_t size)
Prepend data to the buffer.
bool allocated() const
Returns true if the data memory is defined (allocated).
size_t capacity() const
Returns the capacity (raw size) of the allocated buffer in T objects.
size_t size() const
Returns the size of the buffer in T objects.
T * data()
Get a mutable pointer to the start of the array.
ConstBufferType(const void *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a const void pointer and size. This constructor is disabled when T ...
T pop_back()
Removes and returns the last element from the buffer.
openvpn_io::const_buffer const_buffer_clamp() const
Return a clamped version of const_buffer().
void advance(const size_t delta)
Advances the buffer by the specified delta.
const auto & operator[](const size_t index) const
Const indexing operator for ConstBufferType.
bool operator==(const ConstBufferType &other) const
Equality operator to compare this buffer with another ConstBufferType object.
bool empty() const
Returns true if the buffer is empty.
void prepend(const void *data, const size_t size)
Prepend data to the buffer.
const T * c_data_raw() const
Returns a const pointer to the start of the raw data in the buffer.
void write(const T *data, const size_t size)
Write data to the buffer.
const T * c_index(const size_t index) const
Get a const pointer to the element at the specified index in the array.
auto * read_alloc(const size_t size)
Allocate memory and read data from the buffer into the allocated memory.
bool is_zeroed() const
Returns true if the buffer is zeroed (all elements are zero).
T pop_front()
Removes and returns the first element from the buffer.
size_t remaining(const size_t tailroom=0) const
Return the number of additional T objects that can be added before capacity is reached (without consi...
auto & operator[](const size_t index)
Non-const indexing operator for ConstBufferType.
T * data_raw()
Get a mutable pointer to the start of the raw data.
void swap(ConstBufferType< T_ > &other)
Swap the contents of this buffer with another buffer.
size_t offset() const
Returns the current offset (headroom) into the buffer.
void reset(const size_t headroom, const size_t min_capacity, const BufferFlags flags)
Reset the buffer with the specified headroom, minimum capacity, and flags.
void buffer_full_error(const size_t newcap, const bool allocated) const
Throw an exception when the buffer is full.
void reset_offset(const size_t offset)
Resets the offset of the buffer.
virtual ~ConstBufferType()=default
Needed because this class has virtual member functions and is intended as a base class.
T * index(const size_t index)
Get a mutable index into the array.
bool contains_null() const
Returns true if the buffer contains a null character.
void push_front(const T &value)
Append a T object to the array, with possible resize.
void set_size(const size_t size)
After an external method, operating on the array as a mutable unsigned char buffer,...
void reset_content()
Resets the content of the buffer.
virtual void resize(const size_t new_capacity)
Derived classes can implement buffer growing semantics by overloading this method....
void null_terminate()
Null-terminate the array.
void reset_size()
Resets the size of the buffer to zero.
void realign(size_t headroom)
Realign the buffer with the specified headroom.
openvpn_io::mutable_buffer mutable_buffer_clamp(const size_t tailroom=0)
Clamped version of mutable_buffer().
openvpn_io::mutable_buffer mutable_buffer_append(const size_t tailroom=0)
Return an openvpn_io::mutable_buffer object used by asio read methods, starting from data_end().
size_t max_size_tailroom(const size_t tailroom) const
Return the maximum allowable size value in T objects, taking into account the specified tailroom.
void read(NCT *data, const size_t size)
Read data from the buffer into the specified memory location.
A class template that enables reference counting for a given type.
constexpr BufferFlags GROW(1u<< 2)
if enabled, buffer will grow (otherwise buffer_full exception will be thrown)
constexpr BufferFlags CONSTRUCT_ZERO(1u<< 0)
if enabled, constructors/init will zero allocated space
constexpr BufferFlags ARRAY(1u<< 3)
if enabled, use as array
constexpr BufferFlags NO_FLAGS(0u)
no flags set
constexpr BufferFlags DESTRUCT_ZERO(1u<< 1)
if enabled, destructor will zero data before deletion
ConstBufferType< T > & const_buffer_ref(BufferType< T > &src)
AlignT * align_as(BufferAllocatedType< T > &buf)
Aligns buffer.data() to the required value and returns a pointer to the aligned object.
size_t buf_clamp_read(const size_t size)
size_t buf_clamp_write(const size_t size)
CRTP type designed to allow creation of strong types based on intrinsics.
server addresses push_back({address, port})