58#ifdef OPENVPN_BUFFER_ABORT
59#define OPENVPN_BUFFER_THROW(exc) \
64#define OPENVPN_BUFFER_THROW(exc) \
66 throw BufferException(BufferException::exc); \
143 const char *
what() const noexcept
override
163 return "buffer_full";
165 return "buffer_headroom";
167 return "buffer_underflow";
169 return "buffer_overflow";
171 return "buffer_offset";
173 return "buffer_index";
175 return "buffer_const_index";
177 return "buffer_push_front_headroom";
179 return "buffer_no_reset_impl";
181 return "buffer_pop_back";
183 return "buffer_set_size";
185 return "buffer_range";
234 typedef typename std::remove_const_t<T>
NCT;
260 template <
typename U = T,
261 typename std::enable_if_t<!std::is_const_v<U>,
int> = 0>
279 template <
typename U = T,
280 typename std::enable_if_t<!std::is_const_v<U>,
int> = 0>
700 void reset(
const size_t min_capacity,
const unsigned int flags);
708 void reset(
const size_t headroom,
const size_t min_capacity,
const unsigned int flags);
715 template <
typename B>
723 template <
typename T_>
746 virtual void resize(
const size_t new_capacity);
766 template <
typename U = T,
767 typename std::enable_if_t<!std::is_const_v<U>,
int> = 0>
929 template <
typename T_>
973 void reset(
const size_t min_capacity,
const unsigned int flags);
981 void reset(
const size_t headroom,
const size_t min_capacity,
const unsigned int flags);
989 template <
typename T_>
998 template <
typename T_>
1007 template <
typename T_>
1049 const unsigned int flags);
1062 void resize(
const size_t new_capacity)
override;
1084template <
typename T>
1087 static_assert(std::is_nothrow_move_constructible_v<ConstBufferType>,
1088 "class ConstBufferType not noexcept move constructable");
1090 offset_ = size_ = capacity_ = 0;
1093template <
typename T>
1097template <
typename T>
1098template <
typename U,
typename std::enable_if_t<!std::is_const_v<U>,
int>>
1102template <
typename T>
1106 size_(filled ? size : 0),
1109template <
typename T>
1110template <
typename U,
typename std::enable_if_t<!std::is_const_v<U>,
int>>
1114template <
typename T>
1119 return c_data()[index];
1122template <
typename T>
1127 if constexpr (std::is_same_v<ConstBufferType<T>,
decltype(*this)>)
1128 return c_data()[index];
1130 return data()[index];
1133template <
typename T>
1136 if (headroom > capacity_)
1142template <
typename T>
1145 const size_t size = size_ + offset_ - offset;
1146 if (offset > capacity_ || size > capacity_ || offset + size > capacity_)
1152template <
typename T>
1158template <
typename T>
1161 offset_ = size_ = 0;
1164template <
typename T>
1170template <
typename T>
1176template <
typename T>
1179 return data_ + offset_;
1182template <
typename T>
1185 return data_ + offset_ + size_;
1188template <
typename T>
1194template <
typename T>
1200template <
typename T>
1206template <
typename T>
1212template <
typename T>
1215 return data_ !=
nullptr;
1218template <
typename T>
1224template <
typename T>
1230template <
typename T>
1235 return *(c_data() + (--size_));
1238template <
typename T>
1247template <
typename T>
1253template <
typename T>
1256 return (*
this)[size_ - 1];
1259template <
typename T>
1268template <
typename T>
1271 const T *end = c_data_end();
1272 for (
const T *p = c_data(); p < end; ++p)
1280template <
typename T>
1283 const T *end = c_data_end();
1284 for (
const T *p = c_data(); p < end; ++p)
1292#ifndef OPENVPN_NO_IO
1294template <
typename T>
1297 return openvpn_io::const_buffer(c_data(), size());
1300template <
typename T>
1306template <
typename T>
1309 return openvpn_io::const_buffer(c_data(), std::min(
buf_clamp_write(size()), limit));
1313template <
typename T>
1316 std::memcpy(data, read_alloc(size), size *
sizeof(T));
1319template <
typename T>
1322 read((
NCT *)data, size);
1325template <
typename T>
1332 if constexpr (std::is_const_v<retT>)
1344template <
typename T>
1350 retT
ret(data_, offset_, size, capacity_);
1359template <
typename T>
1362 const size_t r = capacity_ - offset_;
1363 return r <= capacity_ ? r : 0;
1366template <
typename T>
1369 if (size > max_size())
1374template <
typename T>
1377 set_size(size_ + delta);
1380template <
typename T>
1383 if (offset + len > size())
1385 if (offset < size())
1386 len = size() - offset;
1393template <
typename T>
1398 return &c_data()[index];
1401template <
typename T>
1402template <
typename T_>
1405 std::swap(other.
data_, data_);
1406 std::swap(other.
offset_, offset_);
1407 std::swap(other.
size_, size_);
1411template <
typename T>
1414 if (size_ != other.
size_)
1416 return std::memcmp(c_data(), other.
c_data(), size_) == 0;
1419template <
typename T>
1422 return !(*
this == other);
1425template <
typename T>
1432template <
typename T>
1435 return data_ + offset_;
1438template <
typename T>
1441 return data_ + offset_ + size_;
1444template <
typename T>
1450template <
typename T>
1453 const size_t r = capacity_ - (offset_ + size_ + tailroom);
1454 return r <= capacity_ ? r : 0;
1457template <
typename T>
1460 const size_t r = capacity_ - (offset_ + tailroom);
1461 return r <= capacity_ ? r : 0;
1464template <
typename T>
1468 resize(offset_ + size_ + 1);
1469 *(data() + size_++) = value;
1472template <
typename T>
1482template <
typename T>
1486 resize(offset_ + size_ + 1);
1487 *(data() + size_) = value;
1490template <
typename T>
1493 if (empty() || back())
1497template <
typename T>
1502 return &data()[index];
1506#ifndef OPENVPN_NO_IO
1508template <
typename T>
1511 return openvpn_io::mutable_buffer(data(), max_size_tailroom(tailroom));
1514template <
typename T>
1517 return openvpn_io::mutable_buffer(data_end(), remaining(tailroom));
1520template <
typename T>
1523 return openvpn_io::mutable_buffer(data(),
buf_clamp_read(max_size_tailroom(tailroom)));
1526template <
typename T>
1529 return openvpn_io::mutable_buffer(data_end(),
buf_clamp_read(remaining(tailroom)));
1533template <
typename T>
1536 if (headroom != offset_)
1538 if (headroom + size_ > capacity_)
1540 std::memmove(data_ + headroom, data_ + offset_, size_);
1545template <
typename T>
1548 std::memcpy(write_alloc(size), data, size *
sizeof(T));
1551template <
typename T>
1554 write((
const T *)data, size);
1557template <
typename T>
1560 std::memcpy(prepend_alloc(size), data, size *
sizeof(T));
1563template <
typename T>
1566 prepend((
const T *)data, size);
1569template <
typename T>
1572 if (size > remaining())
1573 resize(offset_ + size_ + size);
1574 T *
ret = data() + size_;
1579template <
typename T>
1582 if (request_size > offset())
1583 realign(request_size);
1585 offset_ -= request_size;
1586 size_ += request_size;
1591template <
typename T>
1594 if (min_capacity > capacity_)
1595 reset_impl(min_capacity,
flags);
1598template <
typename T>
1601 reset(min_capacity,
flags);
1602 init_headroom(headroom);
1605template <
typename T>
1606template <
typename B>
1609 write(other.c_data(), other.size());
1612template <
typename T>
1618template <
typename T>
1621 if (new_capacity > capacity_)
1622 buffer_full_error(new_capacity,
false);
1625template <
typename T>
1628#ifdef OPENVPN_BUFFER_ABORT
1631 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));
1635template <
typename T>
1637 : data_(data), offset_(offset), size_(size), capacity_(capacity){};
1639template <
typename T>
1640template <
typename U,
typename std::enable_if_t<!std::is_const_v<U>,
int>>
1648template <
typename T>
1650 :
BufferType<T>(capacity ? new T[capacity] : nullptr, offset, size, capacity), flags_(
flags)
1656template <
typename T>
1660 static_assert(std::is_nothrow_move_constructible_v<BufferAllocatedType>,
1661 "class BufferAllocatedType not noexcept move constructable");
1664template <
typename T>
1668template <
typename T>
1676template <
typename T>
1684template <
typename T>
1685template <
typename T_>
1689 static_assert(
sizeof(T) ==
sizeof(T_),
"size inconsistency");
1694template <
typename T>
1701 std::memcpy(tempBuffer.data(), other.
c_data(), tempBuffer.size() *
sizeof(T));
1706template <
typename T>
1713template <
typename T>
1720template <
typename T>
1723 if (newcap > capacity())
1724 realloc_(newcap, offset());
1727template <
typename T>
1730 if (headroom != offset())
1732 if (headroom + size() > capacity())
1733 realloc_(headroom + size(), headroom);
1740template <
typename T>
1743 if (min_capacity > capacity())
1744 init(min_capacity,
flags);
1747template <
typename T>
1750 reset(min_capacity,
flags);
1751 init_headroom(headroom);
1754template <
typename T>
1755template <
typename T_>
1763template <
typename T>
1764template <
typename T_>
1768 std::swap(flags_, other.
flags_);
1771template <
typename T>
1772template <
typename T_>
1779template <
typename T>
1789template <
typename T>
1796template <
typename T>
1802template <
typename T>
1808template <
typename T>
1815template <
typename T>
1818 init(min_capacity,
flags);
1821template <
typename T>
1824 const size_t newcap = std::max(new_capacity, capacity() * 2);
1825 if (newcap > capacity())
1828 realloc_(newcap, offset());
1830 buffer_full_error(newcap,
true);
1834template <
typename T>
1839 std::memcpy(tempBuffer.data(), c_data(), size() *
sizeof(T));
1843template <
typename T>
1847 std::memset(data_raw(), 0, capacity() *
sizeof(T));
1848 delete[] data_raw();
1872template <
typename T>
1878template <
typename T>
#define OPENVPN_BUFFER_THROW(exc)
friend class BufferAllocatedType
void reset(const size_t headroom, const size_t min_capacity, const unsigned int flags)
Resets the buffer with the specified headroom, minimum capacity, and flags.
BufferAllocatedType(const size_t capacity, const unsigned int flags)
Constructs a BufferAllocatedType with the specified capacity and flags.
void clear()
Clears the contents of the buffer.
void and_flags(const unsigned int flags)
Clears the specified flags for the buffer.
BufferAllocatedType(const size_t offset, const size_t size, const size_t capacity, const unsigned int flags)
Private constructor.
BufferAllocatedType & operator=(BufferAllocatedType &&other) noexcept
Move assignment operator.
void init(const size_t capacity, const unsigned int flags)
Initializes the buffer with the specified capacity and flags.
BufferAllocatedType(const T *data, const size_t size, const unsigned int flags)
Constructs a BufferAllocatedType with the specified data, size, and flags.
~BufferAllocatedType()
Destructor.
void reset(const size_t min_capacity, const unsigned int flags)
Resets the buffer with the specified minimum capacity and flags.
void resize(const size_t new_capacity) override
Resizes the buffer to the specified new capacity.
void or_flags(const unsigned int 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 unsigned int flags) override
Resets the buffer implementation with the specified minimum capacity 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 BufferAllocatedType &other)
Copy constructor.
BufferAllocatedType(const BufferType< T_ > &other, const unsigned int flags)
Constructs a BufferAllocatedType from a BufferType object with the specified flags.
BufferAllocatedType(BufferAllocatedType< T_ > &&other) noexcept
Move constructor.
void init(const T *data, const size_t size, const unsigned int flags)
Initializes the buffer with the specified data, size, and flags.
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.
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.
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.
void reset(const size_t headroom, const size_t min_capacity, const unsigned int flags)
Reset the buffer with the specified headroom, minimum capacity, and flags.
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 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().
void reset(const size_t min_capacity, const unsigned int flags)
Reset the buffer with the specified minimum capacity and flags.
virtual void reset_impl(const size_t min_capacity, const unsigned int flags)
Called when the reset method needs to expand the buffer size.
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.
Support deferred server-side state creation when client connects.
ConstBufferType< T > & const_buffer_ref(BufferType< T > &src)
size_t buf_clamp_read(const size_t size)
size_t buf_clamp_write(const size_t size)
@ DESTRUCT_ZERO
if enabled, destructor will zero data before deletion
@ ARRAY
if enabled, use as array
@ GROW
if enabled, buffer will grow (otherwise buffer_full exception will be thrown)
@ CONSTRUCT_ZERO
if enabled, constructors/init will zero allocated space