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
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";
240 using NCT =
typename std::remove_const_t<T>;
266 template <
typename U = T,
267 typename std::enable_if_t<!std::is_const_v<U>,
int> = 0>
285 template <
typename U = T,
286 typename std::enable_if_t<!std::is_const_v<U>,
int> = 0>
721 template <
typename B>
729 template <
typename T_>
753 virtual void resize(
const size_t new_capacity);
773 template <
typename U = T,
774 typename std::enable_if_t<!std::is_const_v<U>,
int> = 0>
873namespace BufAllocFlags {
934 template <
typename T_>
988 const size_t min_capacity,
997 template <
typename T_>
1006 template <
typename T_>
1015 template <
typename T_>
1078 void resize(
const size_t new_capacity)
override;
1100template <
typename T>
1103 static_assert(std::is_nothrow_move_constructible_v<ConstBufferType>,
1104 "class ConstBufferType not noexcept move constructable");
1106 offset_ = size_ = capacity_ = 0;
1109template <
typename T>
1113template <
typename T>
1114template <
typename U,
typename std::enable_if_t<!std::is_const_v<U>,
int>>
1118template <
typename T>
1122 size_(filled ? size : 0),
1125template <
typename T>
1126template <
typename U,
typename std::enable_if_t<!std::is_const_v<U>,
int>>
1130template <
typename T>
1135 return c_data()[index];
1138template <
typename T>
1143 if constexpr (std::is_same_v<ConstBufferType<T>,
decltype(*this)>)
1144 return c_data()[index];
1146 return data()[index];
1149template <
typename T>
1152 if (headroom > capacity_)
1158template <
typename T>
1161 const size_t size = size_ + offset_ - offset;
1162 if (offset > capacity_ || size > capacity_ || offset + size > capacity_)
1168template <
typename T>
1174template <
typename T>
1177 offset_ = size_ = 0;
1180template <
typename T>
1186template <
typename T>
1192template <
typename T>
1195 return data_ + offset_;
1198template <
typename T>
1201 return data_ + offset_ + size_;
1204template <
typename T>
1210template <
typename T>
1216template <
typename T>
1222template <
typename T>
1228template <
typename T>
1231 return data_ !=
nullptr;
1234template <
typename T>
1240template <
typename T>
1246template <
typename T>
1251 return *(c_data() + (--size_));
1254template <
typename T>
1263template <
typename T>
1269template <
typename T>
1272 return (*
this)[size_ - 1];
1275template <
typename T>
1284template <
typename T>
1287 const T *end = c_data_end();
1288 for (
const T *p = c_data(); p < end; ++p)
1296template <
typename T>
1299 const T *end = c_data_end();
1300 for (
const T *p = c_data(); p < end; ++p)
1308#ifndef OPENVPN_NO_IO
1310template <
typename T>
1313 return openvpn_io::const_buffer(c_data(), size());
1316template <
typename T>
1322template <
typename T>
1325 return openvpn_io::const_buffer(c_data(), std::min(
buf_clamp_write(size()), limit));
1329template <
typename T>
1332 std::memcpy(data, read_alloc(size), size *
sizeof(T));
1335template <
typename T>
1338 read((
NCT *)data, size);
1341template <
typename T>
1348 if constexpr (std::is_const_v<retT>)
1359template <
typename T>
1365 retT
ret(data_, offset_, size, capacity_);
1373template <
typename T>
1376 const size_t r = capacity_ - offset_;
1377 return r <= capacity_ ? r : 0;
1380template <
typename T>
1383 if (size > max_size())
1388template <
typename T>
1391 set_size(size_ + delta);
1394template <
typename T>
1397 if (offset + len > size())
1399 if (offset < size())
1400 len = size() - offset;
1407template <
typename T>
1412 return &c_data()[index];
1415template <
typename T>
1416template <
typename T_>
1419 std::swap(other.
data_, data_);
1420 std::swap(other.
offset_, offset_);
1421 std::swap(other.
size_, size_);
1425template <
typename T>
1428 if (size_ != other.
size_)
1430 return std::memcmp(c_data(), other.
c_data(), size_) == 0;
1433template <
typename T>
1436 return !(*
this == other);
1439template <
typename T>
1446template <
typename T>
1449 return data_ + offset_;
1452template <
typename T>
1455 return data_ + offset_ + size_;
1458template <
typename T>
1464template <
typename T>
1467 const size_t r = capacity_ - (offset_ + size_ + tailroom);
1468 return r <= capacity_ ? r : 0;
1471template <
typename T>
1474 const size_t r = capacity_ - (offset_ + tailroom);
1475 return r <= capacity_ ? r : 0;
1478template <
typename T>
1482 resize(offset_ + size_ + 1);
1483 *(data() + size_++) = value;
1486template <
typename T>
1496template <
typename T>
1500 resize(offset_ + size_ + 1);
1501 *(data() + size_) = value;
1504template <
typename T>
1507 if (empty() || back())
1511template <
typename T>
1516 return &data()[index];
1520#ifndef OPENVPN_NO_IO
1522template <
typename T>
1525 return openvpn_io::mutable_buffer(data(), max_size_tailroom(tailroom));
1528template <
typename T>
1531 return openvpn_io::mutable_buffer(data_end(), remaining(tailroom));
1534template <
typename T>
1537 return openvpn_io::mutable_buffer(data(),
buf_clamp_read(max_size_tailroom(tailroom)));
1540template <
typename T>
1543 return openvpn_io::mutable_buffer(data_end(),
buf_clamp_read(remaining(tailroom)));
1547template <
typename T>
1550 if (headroom != offset_)
1552 if (headroom + size_ > capacity_)
1554 std::memmove(data_ + headroom, data_ + offset_, size_);
1559template <
typename T>
1562 std::memcpy(write_alloc(size), data, size *
sizeof(T));
1565template <
typename T>
1568 write((
const T *)data, size);
1571template <
typename T>
1574 std::memcpy(prepend_alloc(size), data, size *
sizeof(T));
1577template <
typename T>
1580 prepend((
const T *)data, size);
1583template <
typename T>
1586 if (size > remaining())
1587 resize(offset_ + size_ + size);
1588 T *
ret = data() + size_;
1593template <
typename T>
1596 if (request_size > offset())
1597 realign(request_size);
1599 offset_ -= request_size;
1600 size_ += request_size;
1605template <
typename T>
1608 if (min_capacity > capacity_)
1609 reset_impl(min_capacity,
flags);
1612template <
typename T>
1614 const size_t min_capacity,
1617 reset(min_capacity,
flags);
1618 init_headroom(headroom);
1621template <
typename T>
1622template <
typename B>
1625 write(other.c_data(), other.size());
1628template <
typename T>
1634template <
typename T>
1637 if (new_capacity > capacity_)
1638 buffer_full_error(new_capacity,
false);
1641template <
typename T>
1644#ifdef OPENVPN_BUFFER_ABORT
1647 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));
1651template <
typename T>
1653 : data_(data), offset_(offset), size_(size), capacity_(capacity){};
1655template <
typename T>
1656template <
typename U,
typename std::enable_if_t<!std::is_const_v<U>,
int>>
1664template <
typename T>
1667 const size_t capacity,
1669 :
BufferType<T>(capacity ? new T[capacity] : nullptr, offset, size, capacity), flags_(
flags)
1675template <
typename T>
1679 static_assert(std::is_nothrow_move_constructible_v<BufferAllocatedType>,
1680 "class BufferAllocatedType not noexcept move constructable");
1683template <
typename T>
1687 (
flags & BufAllocFlags::ARRAY ? capacity : 0),
1691template <
typename T>
1701template <
typename T>
1709template <
typename T>
1710template <
typename T_>
1715 static_assert(
sizeof(T) ==
sizeof(T_),
"size inconsistency");
1720template <
typename T>
1730 std::memcpy(tempBuffer.data(), other.
c_data(), tempBuffer.size() *
sizeof(T));
1735template <
typename T>
1742template <
typename T>
1749template <
typename T>
1752 if (newcap > capacity())
1753 realloc_(newcap, offset());
1756template <
typename T>
1759 if (headroom != offset())
1761 if (headroom + size() > capacity())
1762 realloc_(headroom + size(), headroom);
1769template <
typename T>
1772 if (min_capacity > capacity())
1773 init(min_capacity,
flags);
1776template <
typename T>
1778 const size_t min_capacity,
1781 reset(min_capacity,
flags);
1782 init_headroom(headroom);
1785template <
typename T>
1786template <
typename T_>
1794template <
typename T>
1795template <
typename T_>
1799 std::swap(flags_, other.
flags_);
1802template <
typename T>
1803template <
typename T_>
1810template <
typename T>
1820template <
typename T>
1827template <
typename T>
1830 return flags_ &
flags;
1833template <
typename T>
1839template <
typename T>
1845template <
typename T>
1852template <
typename T>
1855 init(min_capacity,
flags);
1858template <
typename T>
1861 const size_t newcap = std::max(new_capacity, capacity() * 2);
1862 if (newcap > capacity())
1865 realloc_(newcap, offset());
1867 buffer_full_error(newcap,
true);
1871template <
typename T>
1876 std::memcpy(tempBuffer.data(), c_data(), size() *
sizeof(T));
1880template <
typename T>
1884 std::memset(data_raw(), 0, capacity() *
sizeof(T));
1885 delete[] data_raw();
1909template <
typename T_>
1916template <
typename T>
1922template <
typename T>
1939template <
typename AlignT,
typename T>
1953 auto data_ptr =
reinterpret_cast<uintptr_t
>(buf.
c_data());
1954 auto align_ptr = data_ptr & ~(
alignof(AlignT) - 1);
1955 auto raw_data_ptr =
reinterpret_cast<uintptr_t
>(buf.
c_data_raw());
1957 if (align_ptr != data_ptr && align_ptr >= raw_data_ptr)
1958 buf.
realign(align_ptr - raw_data_ptr);
1960 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.
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.
typename std::remove_const_t< T > NCT
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 DESTRUCT_ZERO(1U<< 1)
if enabled, destructor will zero data before deletion
constexpr BufferFlags ARRAY(1U<< 3)
if enabled, use as array
constexpr BufferFlags CONSTRUCT_ZERO(1U<< 0)
if enabled, constructors/init will zero allocated space
constexpr BufferFlags NO_FLAGS(0U)
no flags set
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)