OpenVPN 3 Core Library
Loading...
Searching...
No Matches
buffer.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// These templates define the fundamental data buffer classes used by the
13// OpenVPN core. Normally OpenVPN uses buffers of unsigned chars, but the
14// templatization of the classes would allow buffers of other types to
15// be defined.
16//
17// Fundamentally a buffer is an object with 4 fields:
18//
19// 1. a pointer to underlying data array
20// 2. the capacity of the underlying data array
21// 3. an offset into the data array
22// 4. the size of the referenced data within the array
23//
24// The BufferType template is the lowest-level buffer class template. It refers
25// to a buffer but without any notion of ownership of the underlying data.
26//
27// The BufferAllocatedType template is a higher-level template that inherits
28// from BufferType but which asserts ownership over the resources of the buffer --
29// for example, it will free the underlying buffer in its destructor.
30//
31// Since most of the time, we want our buffers to be made out of unsigned chars,
32// some typedefs at the end of the file define common instantations for the
33// BufferType and BufferAllocatedType templates.
34//
35// Buffer : a simple buffer of unsigned char without ownership semantics
36// ConstBuffer : like buffer but where the data pointed to by the buffer is read-only
37// BufferAllocated : an allocated Buffer with ownership semantics
38// BufferPtr : a smart, reference-counted pointer to a BufferAllocatedRc
39
40#pragma once
41
42#include <string>
43#include <cstdlib> // defines std::abort()
44#include <cstring>
45#include <algorithm>
46#include <type_traits> // for std::is_nothrow_move_constructible_v, std::remove_const, std::enable_if_t, and std::is_const_v
47
48#ifndef OPENVPN_NO_IO
49#include <openvpn/io/io.hpp>
50#endif
51
54#include <openvpn/common/rc.hpp>
58
59#ifdef OPENVPN_BUFFER_ABORT
60#define OPENVPN_BUFFER_THROW(exc) \
61 { \
62 std::abort(); \
63 }
64#else
65#define OPENVPN_BUFFER_THROW(exc) \
66 { \
67 throw BufferException(BufferException::exc); \
68 }
69#endif
70
71namespace openvpn {
72// ===============================================================================================
73// special-purpose exception class for Buffer classes
74// ===============================================================================================
75
114class BufferException : public std::exception
115{
116 public:
132
134 : status_(status)
135 {
136 }
137
138 BufferException(Status status, const std::string &msg)
139 : status_(status),
140 msg_(std::string(status_string(status)) + " : " + msg)
141 {
142 }
143
144 const char *what() const noexcept override
145 {
146 if (!msg_.empty())
147 return msg_.c_str();
148 return status_string(status_);
149 }
150
152 {
153 return status_;
154 }
155 virtual ~BufferException() noexcept = default;
156
157 private:
158 static const char *status_string(const Status status)
159 {
160 switch (status)
161 {
162 case buffer_full:
163 return "buffer_full";
164 case buffer_headroom:
165 return "buffer_headroom";
166 case buffer_underflow:
167 return "buffer_underflow";
168 case buffer_overflow:
169 return "buffer_overflow";
170 case buffer_offset:
171 return "buffer_offset";
172 case buffer_index:
173 return "buffer_index";
175 return "buffer_const_index";
177 return "buffer_push_front_headroom";
179 return "buffer_no_reset_impl";
180 case buffer_pop_back:
181 return "buffer_pop_back";
182 case buffer_set_size:
183 return "buffer_set_size";
184 case buffer_range:
185 return "buffer_range";
186 default:
187 return "buffer_???";
188 }
189 }
190
192 std::string msg_;
193};
194
195// ===============================================================================================
196// ===============================================================================================
197
198template <typename T>
200
201template <typename T>
202class BufferType;
203
204// Allocation and security for the buffer
205struct BufferFlags : IntrinsicType<BufferFlags, unsigned int>
206{
207 using IntrinsicType<BufferFlags, unsigned int>::IntrinsicType;
208};
209
210// ===============================================================================================
211// class ConstBufferType
212// ===============================================================================================
233template <typename T>
235{
236 public:
237 using value_type = T;
238 using type = T *;
239 using const_type = const T *;
240 using NCT = typename std::remove_const_t<T>;
241
246
257 ConstBufferType(void *data, const size_t size, const bool filled);
258
266 template <typename U = T,
267 typename std::enable_if_t<!std::is_const_v<U>, int> = 0>
268 ConstBufferType(const void *data, const size_t size, const bool filled);
269
276 ConstBufferType(T *data, const size_t size, const bool filled);
277
285 template <typename U = T,
286 typename std::enable_if_t<!std::is_const_v<U>, int> = 0>
287 ConstBufferType(const U *data, const size_t size, const bool filled);
288
293 virtual ~ConstBufferType() = default;
294
300 const auto &operator[](const size_t index) const;
301
307 auto &operator[](const size_t index);
308
313 void init_headroom(const size_t headroom);
314
319 void reset_offset(const size_t offset);
320
325
330
335 const T *c_str() const;
336
341 size_t length() const;
342
347 const T *c_data() const;
348
353 const T *c_data_end() const;
354
359 const T *c_data_raw() const;
360
365 size_t capacity() const;
366
371 size_t offset() const;
372
377 bool defined() const;
378
383 bool allocated() const;
384
389 bool empty() const;
390
395 size_t size() const;
396
402
408
413 T front() const;
414
419 T back() const;
420
425 void advance(const size_t delta);
426
431 bool contains_null() const;
432
437 bool is_zeroed() const;
438
439#ifndef OPENVPN_NO_IO
444 openvpn_io::const_buffer const_buffer() const;
445
455 openvpn_io::const_buffer const_buffer_clamp() const;
456
467 openvpn_io::const_buffer const_buffer_limit(const size_t limit) const;
468#endif
469
475 void read(NCT *data, const size_t size);
476
482 void read(void *data, const size_t size);
483
489 auto *read_alloc(const size_t size);
490
496 auto read_alloc_buf(const size_t size);
497
502 size_t max_size() const;
503
508 void set_size(const size_t size);
509
514 void inc_size(const size_t delta);
515
522 ConstBufferType range(size_t offset, size_t len) const;
523
529 const T *c_index(const size_t index) const;
530
536 bool operator==(const ConstBufferType &other) const;
537
543 bool operator!=(const ConstBufferType &other) const;
544
545 protected: // mutable implementations are only available to derived classes
550 void reserve(const size_t n);
551
556 T *data();
557
563
569
575 size_t remaining(const size_t tailroom = 0) const;
576
582 size_t max_size_tailroom(const size_t tailroom) const;
583
588 void push_back(const T &value);
589
594 void push_front(const T &value);
595
603 void set_trailer(const T &value);
604
610
616 T *index(const size_t index);
617
618#ifndef OPENVPN_NO_IO
624 openvpn_io::mutable_buffer mutable_buffer(const size_t tailroom = 0);
625
631 openvpn_io::mutable_buffer mutable_buffer_append(const size_t tailroom = 0);
632
638 openvpn_io::mutable_buffer mutable_buffer_clamp(const size_t tailroom = 0);
639
645 openvpn_io::mutable_buffer mutable_buffer_append_clamp(const size_t tailroom = 0);
646#endif
647
654 void realign(size_t headroom);
655
661 void write(const T *data, const size_t size);
662
668 void write(const void *data, const size_t size);
669
675 void prepend(const T *data, const size_t size);
676
682 void prepend(const void *data, const size_t size);
683
689 T *write_alloc(const size_t size);
690
699 T *prepend_alloc(const size_t size);
700
706 void reset(const size_t min_capacity, const BufferFlags flags);
707
714 void reset(const size_t headroom, const size_t min_capacity, const BufferFlags flags);
715
721 template <typename B>
722 void append(const B &other);
723
729 template <typename T_>
731
737 void buffer_full_error(const size_t newcap, const bool allocated) const;
738
745 virtual void reset_impl(const size_t min_capacity, const BufferFlags flags);
746
753 virtual void resize(const size_t new_capacity);
754
762 ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity);
763
773 template <typename U = T,
774 typename std::enable_if_t<!std::is_const_v<U>, int> = 0>
775 ConstBufferType(const U *data, const size_t offset, const size_t size, const size_t capacity);
776
777 private:
778 // Even though *data_ is declared as non-const, within ConstBufferType
779 // we MUST always treat it as const. But derived classes may treat it
780 // as non-const as long as they passed in non-const data to begin with.
781 T *data_; // pointer to data
782 size_t offset_; // offset from data_ of beginning of T array (to allow for headroom)
783 size_t size_; // number of T objects in array starting at data_ + offset_
784 size_t capacity_; // maximum number of array objects of type T for which memory is allocated, starting at data_
785};
786
787// ===============================================================================================
788// class BufferType
789// ===============================================================================================
790
791template <typename T>
793{
794 private:
795 template <typename>
796 friend class ConstBufferType;
797
798 public:
799 using ConstBufferType<T>::empty;
802 using ConstBufferType<T>::back;
804 using ConstBufferType<T>::operator[];
806 using ConstBufferType<T>::data;
815 using ConstBufferType<T>::index;
816#ifndef OPENVPN_NO_IO
821#endif
823 using ConstBufferType<T>::write;
827 using ConstBufferType<T>::reset;
832
836 BufferType() = default;
837
844 BufferType(void *data, const size_t size, const bool filled)
845 : ConstBufferType<T>(data, size, filled) {};
846
853 BufferType(T *data, const size_t size, const bool filled)
854 : ConstBufferType<T>(data, size, filled) {};
855
863 protected:
864 BufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
866};
867
868// ===============================================================================================
869// class BufferAllocatedType
870// ===============================================================================================
871
872// Flag constants
873namespace BufAllocFlags {
874constexpr BufferFlags NO_FLAGS(0U);
875constexpr BufferFlags CONSTRUCT_ZERO(1U << 0);
876constexpr BufferFlags DESTRUCT_ZERO(1U << 1);
877constexpr BufferFlags GROW(1U << 2);
878constexpr BufferFlags ARRAY(1U << 3);
879} // namespace BufAllocFlags
880
881template <typename T>
883{
884 private:
885 // Friend to all specializations of this template allows access to other.data_
886 template <typename>
888
889 public:
892 using BufferType<T>::size;
893 using BufferType<T>::capacity;
894 using BufferType<T>::offset;
895 using BufferType<T>::data_raw;
896 using BufferType<T>::c_data_raw;
897 using BufferType<T>::data;
898 using BufferType<T>::c_data;
899 using BufferType<T>::swap;
900
905
911 explicit BufferAllocatedType(const size_t capacity,
913
920 explicit BufferAllocatedType(const T *data, const size_t size, const BufferFlags flags);
921
927
934 template <typename T_>
937
942 void operator=(const BufferAllocatedType &other);
943
950
957 void init(const T *data, const size_t size, const BufferFlags flags);
958
963 void realloc(const size_t newcap);
964
972 BufferAllocatedType &realign(const size_t headroom);
973
979 void reset(const size_t min_capacity, const BufferFlags flags = BufAllocFlags::NO_FLAGS);
980
987 void reset(const size_t headroom,
988 const size_t min_capacity,
990
997 template <typename T_>
999
1006 template <typename T_>
1008
1015 template <typename T_>
1017
1024
1028 void clear();
1029
1035 bool test_flags(const BufferFlags flags) const noexcept;
1036
1042
1049
1054
1063 const size_t size,
1064 const size_t capacity,
1065 const BufferFlags flags);
1066
1072 void reset_impl(const size_t min_capacity, const BufferFlags flags) override;
1073
1078 void resize(const size_t new_capacity) override;
1079
1085 void realloc_(const size_t newcap, size_t new_offset);
1086
1091
1092 private:
1094};
1095
1096// ===============================================================================================
1097// ConstBufferType<T> member function definitions
1098// ===============================================================================================
1099
1100template <typename T>
1102{
1103 static_assert(std::is_nothrow_move_constructible_v<ConstBufferType>,
1104 "class ConstBufferType not noexcept move constructable");
1105 data_ = nullptr;
1106 offset_ = size_ = capacity_ = 0;
1107}
1108
1109template <typename T>
1110ConstBufferType<T>::ConstBufferType(void *data, const size_t size, const bool filled)
1111 : ConstBufferType((T *)data, size, filled){};
1112
1113template <typename T>
1114template <typename U, typename std::enable_if_t<!std::is_const_v<U>, int>>
1115ConstBufferType<T>::ConstBufferType(const void *data, const size_t size, const bool filled)
1116 : ConstBufferType(const_cast<void *>(data), size, filled){};
1117
1118template <typename T>
1119ConstBufferType<T>::ConstBufferType(T *data, const size_t size, const bool filled)
1120 : data_(data),
1121 offset_(0),
1122 size_(filled ? size : 0),
1123 capacity_(size){};
1124
1125template <typename T>
1126template <typename U, typename std::enable_if_t<!std::is_const_v<U>, int>>
1127ConstBufferType<T>::ConstBufferType(const U *data, const size_t size, const bool filled)
1128 : ConstBufferType(const_cast<U *>(data), size, filled){};
1129
1130template <typename T>
1131const auto &ConstBufferType<T>::operator[](const size_t index) const
1132{
1133 if (index >= size_)
1134 OPENVPN_BUFFER_THROW(buffer_const_index);
1135 return c_data()[index];
1136}
1137
1138template <typename T>
1139auto &ConstBufferType<T>::operator[](const size_t index)
1140{
1141 if (index >= size_)
1142 OPENVPN_BUFFER_THROW(buffer_const_index);
1143 if constexpr (std::is_same_v<ConstBufferType<T>, decltype(*this)>)
1144 return c_data()[index];
1145 else
1146 return data()[index];
1147}
1148
1149template <typename T>
1150void ConstBufferType<T>::init_headroom(const size_t headroom)
1151{
1152 if (headroom > capacity_)
1153 OPENVPN_BUFFER_THROW(buffer_headroom);
1154 offset_ = headroom;
1155 size_ = 0;
1156}
1157
1158template <typename T>
1159void ConstBufferType<T>::reset_offset(const size_t offset)
1160{
1161 const size_t size = size_ + offset_ - offset;
1162 if (offset > capacity_ || size > capacity_ || offset + size > capacity_)
1163 OPENVPN_BUFFER_THROW(buffer_offset);
1164 offset_ = offset;
1165 size_ = size;
1166}
1167
1168template <typename T>
1170{
1171 size_ = 0;
1172}
1173
1174template <typename T>
1176{
1177 offset_ = size_ = 0;
1178}
1179
1180template <typename T>
1182{
1183 return c_data();
1184}
1185
1186template <typename T>
1188{
1189 return size();
1190}
1191
1192template <typename T>
1194{
1195 return data_ + offset_;
1196}
1197
1198template <typename T>
1200{
1201 return data_ + offset_ + size_;
1202}
1203
1204template <typename T>
1206{
1207 return data_;
1208}
1209
1210template <typename T>
1212{
1213 return capacity_;
1214}
1215
1216template <typename T>
1218{
1219 return offset_;
1220}
1221
1222template <typename T>
1224{
1225 return size_ > 0;
1226}
1227
1228template <typename T>
1230{
1231 return data_ != nullptr;
1232}
1233
1234template <typename T>
1236{
1237 return !size_;
1238}
1239
1240template <typename T>
1242{
1243 return size_;
1244}
1245
1246template <typename T>
1248{
1249 if (!size_)
1250 OPENVPN_BUFFER_THROW(buffer_pop_back);
1251 return *(c_data() + (--size_));
1252}
1253
1254template <typename T>
1256{
1257 T ret = (*this)[0];
1258 ++offset_;
1259 --size_;
1260 return ret;
1261}
1262
1263template <typename T>
1265{
1266 return (*this)[0];
1267}
1268
1269template <typename T>
1271{
1272 return (*this)[size_ - 1];
1273}
1274
1275template <typename T>
1276void ConstBufferType<T>::advance(const size_t delta)
1277{
1278 if (delta > size_)
1279 OPENVPN_BUFFER_THROW(buffer_overflow);
1280 offset_ += delta;
1281 size_ -= delta;
1282}
1283
1284template <typename T>
1286{
1287 const T *end = c_data_end();
1288 for (const T *p = c_data(); p < end; ++p)
1289 {
1290 if (!*p)
1291 return true;
1292 }
1293 return false;
1294}
1295
1296template <typename T>
1298{
1299 const T *end = c_data_end();
1300 for (const T *p = c_data(); p < end; ++p)
1301 {
1302 if (*p)
1303 return false;
1304 }
1305 return true;
1306}
1307
1308#ifndef OPENVPN_NO_IO
1309
1310template <typename T>
1311openvpn_io::const_buffer ConstBufferType<T>::const_buffer() const
1312{
1313 return openvpn_io::const_buffer(c_data(), size());
1314}
1315
1316template <typename T>
1317openvpn_io::const_buffer ConstBufferType<T>::const_buffer_clamp() const
1318{
1319 return openvpn_io::const_buffer(c_data(), buf_clamp_write(size()));
1320}
1321
1322template <typename T>
1323openvpn_io::const_buffer ConstBufferType<T>::const_buffer_limit(const size_t limit) const
1324{
1325 return openvpn_io::const_buffer(c_data(), std::min(buf_clamp_write(size()), limit));
1326}
1327#endif
1328
1329template <typename T>
1330void ConstBufferType<T>::read(NCT *data, const size_t size)
1331{
1332 std::memcpy(data, read_alloc(size), size * sizeof(T));
1333}
1334
1335template <typename T>
1336void ConstBufferType<T>::read(void *data, const size_t size)
1337{
1338 read((NCT *)data, size);
1339}
1340
1341template <typename T>
1342auto *ConstBufferType<T>::read_alloc(const size_t size)
1343{
1344 if (size <= size_)
1345 {
1346 using retT = std::conditional_t<std::is_same_v<decltype(*this), ConstBufferType<T>>, const value_type, value_type>;
1347 retT *ret;
1348 if constexpr (std::is_const_v<retT>)
1349 ret = c_data();
1350 else
1351 ret = data();
1352 offset_ += size;
1353 size_ -= size;
1354 return ret;
1355 }
1356 OPENVPN_BUFFER_THROW(buffer_underflow);
1357}
1358
1359template <typename T>
1361{
1362 if (size <= size_)
1363 {
1364 using retT = std::conditional_t<std::is_same_v<decltype(*this), ConstBufferType<T>>, ConstBufferType<T>, BufferType<T>>;
1365 retT ret(data_, offset_, size, capacity_);
1366 offset_ += size;
1367 size_ -= size;
1368 return ret;
1369 }
1370 OPENVPN_BUFFER_THROW(buffer_underflow);
1371}
1372
1373template <typename T>
1375{
1376 const size_t r = capacity_ - offset_;
1377 return r <= capacity_ ? r : 0;
1378}
1379
1380template <typename T>
1381void ConstBufferType<T>::set_size(const size_t size)
1382{
1383 if (size > max_size())
1384 OPENVPN_BUFFER_THROW(buffer_set_size);
1385 size_ = size;
1386}
1387
1388template <typename T>
1389void ConstBufferType<T>::inc_size(const size_t delta)
1390{
1391 set_size(size_ + delta);
1392}
1393
1394template <typename T>
1395ConstBufferType<T> ConstBufferType<T>::range(size_t offset, size_t len) const
1396{
1397 if (offset + len > size())
1398 {
1399 if (offset < size())
1400 len = size() - offset;
1401 else
1402 len = 0;
1403 }
1404 return ConstBufferType(c_data(), offset, len, len);
1405}
1406
1407template <typename T>
1408const T *ConstBufferType<T>::c_index(const size_t index) const
1409{
1410 if (index >= size_)
1411 OPENVPN_BUFFER_THROW(buffer_const_index);
1412 return &c_data()[index];
1413}
1414
1415template <typename T>
1416template <typename T_>
1418{
1419 std::swap(other.data_, data_);
1420 std::swap(other.offset_, offset_);
1421 std::swap(other.size_, size_);
1422 std::swap(other.capacity_, capacity_);
1423}
1424
1425template <typename T>
1427{
1428 if (size_ != other.size_)
1429 return false;
1430 return std::memcmp(c_data(), other.c_data(), size_) == 0;
1431}
1432
1433template <typename T>
1435{
1436 return !(*this == other);
1437}
1438
1439template <typename T>
1441{
1442 if (n > capacity_)
1443 resize(n);
1444}
1445
1446template <typename T>
1448{
1449 return data_ + offset_;
1450}
1451
1452template <typename T>
1454{
1455 return data_ + offset_ + size_;
1456}
1457
1458template <typename T>
1460{
1461 return data_;
1462}
1463
1464template <typename T>
1465size_t ConstBufferType<T>::remaining(const size_t tailroom) const
1466{
1467 const size_t r = capacity_ - (offset_ + size_ + tailroom);
1468 return r <= capacity_ ? r : 0;
1469}
1470
1471template <typename T>
1472size_t ConstBufferType<T>::max_size_tailroom(const size_t tailroom) const
1473{
1474 const size_t r = capacity_ - (offset_ + tailroom);
1475 return r <= capacity_ ? r : 0;
1476}
1477
1478template <typename T>
1480{
1481 if (!remaining())
1482 resize(offset_ + size_ + 1);
1483 *(data() + size_++) = value;
1484}
1485
1486template <typename T>
1488{
1489 if (!offset_)
1490 OPENVPN_BUFFER_THROW(buffer_push_front_headroom);
1491 --offset_;
1492 ++size_;
1493 *data() = value;
1494}
1495
1496template <typename T>
1498{
1499 if (!remaining())
1500 resize(offset_ + size_ + 1);
1501 *(data() + size_) = value;
1502}
1503
1504template <typename T>
1506{
1507 if (empty() || back())
1508 push_back(0);
1509}
1510
1511template <typename T>
1512T *ConstBufferType<T>::index(const size_t index)
1513{
1514 if (index >= size_)
1515 OPENVPN_BUFFER_THROW(buffer_index);
1516 return &data()[index];
1517}
1518
1519
1520#ifndef OPENVPN_NO_IO
1521
1522template <typename T>
1523openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer(const size_t tailroom)
1524{
1525 return openvpn_io::mutable_buffer(data(), max_size_tailroom(tailroom));
1526}
1527
1528template <typename T>
1529openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_append(const size_t tailroom)
1530{
1531 return openvpn_io::mutable_buffer(data_end(), remaining(tailroom));
1532}
1533
1534template <typename T>
1535openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_clamp(const size_t tailroom)
1536{
1537 return openvpn_io::mutable_buffer(data(), buf_clamp_read(max_size_tailroom(tailroom)));
1538}
1539
1540template <typename T>
1541openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_append_clamp(const size_t tailroom)
1542{
1543 return openvpn_io::mutable_buffer(data_end(), buf_clamp_read(remaining(tailroom)));
1544}
1545#endif
1546
1547template <typename T>
1548void ConstBufferType<T>::realign(size_t headroom)
1549{
1550 if (headroom != offset_)
1551 {
1552 if (headroom + size_ > capacity_)
1553 OPENVPN_BUFFER_THROW(buffer_headroom);
1554 std::memmove(data_ + headroom, data_ + offset_, size_);
1555 offset_ = headroom;
1556 }
1557}
1558
1559template <typename T>
1560void ConstBufferType<T>::write(const T *data, const size_t size)
1561{
1562 std::memcpy(write_alloc(size), data, size * sizeof(T));
1563}
1564
1565template <typename T>
1566void ConstBufferType<T>::write(const void *data, const size_t size)
1567{
1568 write((const T *)data, size);
1569}
1570
1571template <typename T>
1572void ConstBufferType<T>::prepend(const T *data, const size_t size)
1573{
1574 std::memcpy(prepend_alloc(size), data, size * sizeof(T));
1575}
1576
1577template <typename T>
1578void ConstBufferType<T>::prepend(const void *data, const size_t size)
1579{
1580 prepend((const T *)data, size);
1581}
1582
1583template <typename T>
1585{
1586 if (size > remaining())
1587 resize(offset_ + size_ + size);
1588 T *ret = data() + size_;
1589 size_ += size;
1590 return ret;
1591}
1592
1593template <typename T>
1594T *ConstBufferType<T>::prepend_alloc(const size_t request_size)
1595{
1596 if (request_size > offset())
1597 realign(request_size);
1598
1599 offset_ -= request_size;
1600 size_ += request_size;
1601
1602 return data();
1603}
1604
1605template <typename T>
1606void ConstBufferType<T>::reset(const size_t min_capacity, const BufferFlags flags)
1607{
1608 if (min_capacity > capacity_)
1609 reset_impl(min_capacity, flags);
1610}
1611
1612template <typename T>
1613void ConstBufferType<T>::reset(const size_t headroom,
1614 const size_t min_capacity,
1615 const BufferFlags flags)
1616{
1617 reset(min_capacity, flags);
1618 init_headroom(headroom);
1619}
1620
1621template <typename T>
1622template <typename B>
1623void ConstBufferType<T>::append(const B &other)
1624{
1625 write(other.c_data(), other.size());
1626}
1627
1628template <typename T>
1629void ConstBufferType<T>::reset_impl(const size_t min_capacity, const BufferFlags flags)
1630{
1631 OPENVPN_BUFFER_THROW(buffer_no_reset_impl);
1632}
1633
1634template <typename T>
1635void ConstBufferType<T>::resize(const size_t new_capacity)
1636{
1637 if (new_capacity > capacity_)
1638 buffer_full_error(new_capacity, false);
1639}
1640
1641template <typename T>
1642void ConstBufferType<T>::buffer_full_error(const size_t newcap, const bool allocated) const
1643{
1644#ifdef OPENVPN_BUFFER_ABORT
1645 std::abort();
1646#else
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));
1648#endif
1649}
1650
1651template <typename T>
1652ConstBufferType<T>::ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
1653 : data_(data), offset_(offset), size_(size), capacity_(capacity){};
1654
1655template <typename T>
1656template <typename U, typename std::enable_if_t<!std::is_const_v<U>, int>>
1657ConstBufferType<T>::ConstBufferType(const U *data, const size_t offset, const size_t size, const size_t capacity)
1658 : ConstBufferType(const_cast<U *>(data), offset, size, capacity){};
1659
1660// ===============================================================================================
1661// BufferAllocatedType<T> member function definitions
1662// ===============================================================================================
1663
1664template <typename T>
1666 const size_t size,
1667 const size_t capacity,
1668 const BufferFlags flags)
1669 : BufferType<T>(capacity ? new T[capacity] : nullptr, offset, size, capacity), flags_(flags)
1670{
1672 std::memset(data_raw(), 0, capacity * sizeof(T));
1673}
1674
1675template <typename T>
1677 : BufferAllocatedType(0, 0, 0, BufAllocFlags::NO_FLAGS)
1678{
1679 static_assert(std::is_nothrow_move_constructible_v<BufferAllocatedType>,
1680 "class BufferAllocatedType not noexcept move constructable");
1681}
1682
1683template <typename T>
1685 const BufferFlags flags)
1687 (flags & BufAllocFlags::ARRAY ? capacity : 0),
1688 capacity,
1689 flags){};
1690
1691template <typename T>
1693 const size_t size,
1694 const BufferFlags flags)
1695 : BufferAllocatedType(0, size, size, flags)
1696{
1697 if (size && data)
1698 std::memcpy(data_raw(), data, size * sizeof(T));
1699}
1700
1701template <typename T>
1703 : BufferAllocatedType(other.offset(), other.size(), other.capacity(), other.flags_)
1704{
1705 if (size())
1706 std::memcpy(data(), other.c_data(), size() * sizeof(T));
1707}
1708
1709template <typename T>
1710template <typename T_>
1712 const BufferFlags flags)
1713 : BufferAllocatedType(other.offset(), other.size(), other.capacity(), flags)
1714{
1715 static_assert(sizeof(T) == sizeof(T_), "size inconsistency");
1716 if (size())
1717 std::memcpy(data(), other.c_data(), size() * sizeof(T));
1718}
1719
1720template <typename T>
1722{
1723 if (this != &other)
1724 {
1725 auto tempBuffer = BufferAllocatedType(other.offset(),
1726 other.size(),
1727 other.capacity(),
1728 other.flags_);
1729 if (other.size())
1730 std::memcpy(tempBuffer.data(), other.c_data(), tempBuffer.size() * sizeof(T));
1731 swap(tempBuffer);
1732 }
1733}
1734
1735template <typename T>
1736void BufferAllocatedType<T>::init(const size_t capacity, const BufferFlags flags)
1737{
1738 auto tempBuffer = BufferAllocatedType(capacity, flags);
1739 swap(tempBuffer);
1740}
1741
1742template <typename T>
1743void BufferAllocatedType<T>::init(const T *data, const size_t size, const BufferFlags flags)
1744{
1745 auto tempBuffer = BufferAllocatedType(data, size, flags);
1746 swap(tempBuffer);
1747}
1748
1749template <typename T>
1750void BufferAllocatedType<T>::realloc(const size_t newcap)
1751{
1752 if (newcap > capacity())
1753 realloc_(newcap, offset());
1754}
1755
1756template <typename T>
1758{
1759 if (headroom != offset())
1760 {
1761 if (headroom + size() > capacity())
1762 realloc_(headroom + size(), headroom);
1763 else
1764 BufferType<T>::realign(headroom);
1765 }
1766 return *this;
1767}
1768
1769template <typename T>
1770void BufferAllocatedType<T>::reset(const size_t min_capacity, const BufferFlags flags)
1771{
1772 if (min_capacity > capacity())
1773 init(min_capacity, flags);
1774}
1775
1776template <typename T>
1777void BufferAllocatedType<T>::reset(const size_t headroom,
1778 const size_t min_capacity,
1779 const BufferFlags flags)
1780{
1781 reset(min_capacity, flags);
1782 init_headroom(headroom);
1783}
1784
1785template <typename T>
1786template <typename T_>
1788{
1789 auto temp = BufferAllocatedType();
1790 swap(other);
1791 other.swap(temp);
1792}
1793
1794template <typename T>
1795template <typename T_>
1797{
1798 BufferType<T>::swap(other);
1799 std::swap(flags_, other.flags_);
1800}
1801
1802template <typename T>
1803template <typename T_>
1806{
1807 move(other);
1808}
1809
1810template <typename T>
1812{
1813 if (this != &other)
1814 {
1815 move(other);
1816 }
1817 return *this;
1818}
1819
1820template <typename T>
1822{
1823 auto tempBuffer = BufferAllocatedType(0, 0, 0, BufAllocFlags::NO_FLAGS);
1824 swap(tempBuffer);
1825}
1826
1827template <typename T>
1829{
1830 return flags_ & flags;
1831}
1832
1833template <typename T>
1835{
1836 flags_ |= flags;
1837}
1838
1839template <typename T>
1841{
1842 flags_ &= ~flags;
1843}
1844
1845template <typename T>
1847{
1848 if (data_raw())
1849 free_data();
1850}
1851
1852template <typename T>
1853void BufferAllocatedType<T>::reset_impl(const size_t min_capacity, const BufferFlags flags)
1854{
1855 init(min_capacity, flags);
1856}
1857
1858template <typename T>
1859void BufferAllocatedType<T>::resize(const size_t new_capacity)
1860{
1861 const size_t newcap = std::max(new_capacity, capacity() * 2);
1862 if (newcap > capacity())
1863 {
1864 if (flags_ & BufAllocFlags::GROW)
1865 realloc_(newcap, offset());
1866 else
1867 buffer_full_error(newcap, true);
1868 }
1869}
1870
1871template <typename T>
1872void BufferAllocatedType<T>::realloc_(const size_t newcap, size_t new_offset)
1873{
1874 auto tempBuffer = BufferAllocatedType(new_offset, size(), newcap, flags_);
1875 if (size())
1876 std::memcpy(tempBuffer.data(), c_data(), size() * sizeof(T));
1877 swap(tempBuffer);
1878}
1879
1880template <typename T>
1882{
1883 if (size() && (flags_ & BufAllocFlags::DESTRUCT_ZERO))
1884 std::memset(data_raw(), 0, capacity() * sizeof(T));
1885 delete[] data_raw();
1886}
1887
1888// ===============================================================================================
1889// specializations of BufferType for unsigned char
1890// ===============================================================================================
1891
1897
1898// ===============================================================================================
1899// BufferAllocated + RC with thread-safe refcount
1900// ===============================================================================================
1901
1904
1905// ===============================================================================================
1906// Deduction guide - needed to deduce converting ctor
1907// ===============================================================================================
1908
1909template <typename T_>
1911
1912// ===============================================================================================
1913// cast BufferType<T> to ConstBufferType<T>
1914// ===============================================================================================
1915
1916template <typename T>
1918{
1919 return src;
1920}
1921
1922template <typename T>
1924{
1925 return src;
1926}
1927
1928// ===============================================================================================
1929// Buffer related utilities - consider moving to a separate file
1930// ===============================================================================================
1931
1939template <typename AlignT, typename T>
1940inline AlignT *align_as(BufferAllocatedType<T> &buf) // TODO: Could be implemented noexcept
1941{
1942 /* The standard requires that alignof(T) is a power of 2, and that any allocation will be
1943 aligned to at least alignof(std::max_align_t), so I assume offset zero in a buffer is
1944 aligned and therefore there is no need to check for alignment of the buffer itself.
1945
1946 This means a suitable address exists in the first alignof(std::max_align_t) so we never have
1947 to increase the offset at all. This is a simplification that might not hold in all cases,
1948 but it is a reasonable assumption for now. Given that, we can just align the buffer by
1949 masking out the lower bits of the current data address (computation of align_ptr below)
1950 and then realign the buffer to that address if needed. This will preserve as much of the
1951 headroom as possible.
1952 */
1953 auto data_ptr = reinterpret_cast<uintptr_t>(buf.c_data()); // Current data address in integral form
1954 auto align_ptr = data_ptr & ~(alignof(AlignT) - 1); // 'Previous' aligned address
1955 auto raw_data_ptr = reinterpret_cast<uintptr_t>(buf.c_data_raw()); // Start of allocated buffer
1956
1957 if (align_ptr != data_ptr && align_ptr >= raw_data_ptr)
1958 buf.realign(align_ptr - raw_data_ptr);
1959
1960 return reinterpret_cast<AlignT *>(buf.data()); // unsigned char is type accessible by all types
1961}
1962
1963} // namespace openvpn
#define OPENVPN_BUFFER_THROW(exc)
Definition buffer.hpp:65
BufferAllocatedType(const size_t offset, const size_t size, const size_t capacity, const BufferFlags flags)
Private constructor.
Definition buffer.hpp:1665
friend class BufferAllocatedType
Definition buffer.hpp:887
void clear()
Clears the contents of the buffer.
Definition buffer.hpp:1821
BufferAllocatedType & operator=(BufferAllocatedType &&other) noexcept
Move assignment operator.
Definition buffer.hpp:1811
void reset(const size_t min_capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Resets the buffer with the specified minimum capacity and flags.
Definition buffer.hpp:1770
void init(const size_t capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Initializes the buffer with the specified capacity and flags.
Definition buffer.hpp:1736
void clear_flags(const BufferFlags flags)
Clears the specified flags for the buffer.
Definition buffer.hpp:1840
BufferAllocatedType(const size_t capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Constructs a BufferAllocatedType with the specified capacity and flags.
Definition buffer.hpp:1684
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.
Definition buffer.hpp:1777
~BufferAllocatedType()
Destructor.
Definition buffer.hpp:1846
void resize(const size_t new_capacity) override
Resizes the buffer to the specified new capacity.
Definition buffer.hpp:1859
bool test_flags(const BufferFlags flags) const noexcept
Test if the buffer has the specified flags.
Definition buffer.hpp:1828
void add_flags(const BufferFlags flags)
Sets the specified flags for the buffer.
Definition buffer.hpp:1834
void move(BufferAllocatedType< T_ > &other)
Moves the contents of another BufferAllocatedType object into this object.
Definition buffer.hpp:1787
BufferAllocatedType()
Default constructor.
Definition buffer.hpp:1676
void realloc(const size_t newcap)
Reallocates the buffer to the specified new capacity.
Definition buffer.hpp:1750
void operator=(const BufferAllocatedType &other)
Assignment operator.
Definition buffer.hpp:1721
void reset_impl(const size_t min_capacity, const BufferFlags flags) override
Resets the buffer implementation with the specified minimum capacity and flags.
Definition buffer.hpp:1853
void init(const T *data, const size_t size, const BufferFlags flags)
Initializes the buffer with the specified data, size, and flags.
Definition buffer.hpp:1743
void realloc_(const size_t newcap, size_t new_offset)
Reallocates the buffer to the specified new capacity.
Definition buffer.hpp:1872
BufferAllocatedType & realign(const size_t headroom)
Realign the buffer with the specified headroom.
Definition buffer.hpp:1757
void free_data()
Frees the data associated with the buffer.
Definition buffer.hpp:1881
void swap(BufferAllocatedType< T_ > &other)
Swaps the contents of this BufferAllocatedType object with another BufferAllocatedType object.
Definition buffer.hpp:1796
BufferAllocatedType(const T *data, const size_t size, const BufferFlags flags)
Constructs a BufferAllocatedType with the specified data, size, and flags.
Definition buffer.hpp:1692
BufferAllocatedType(const BufferAllocatedType &other)
Copy constructor.
Definition buffer.hpp:1702
BufferAllocatedType(const BufferType< T_ > &other, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Constructs a BufferAllocatedType from a BufferType object with the specified flags.
Definition buffer.hpp:1711
BufferAllocatedType(BufferAllocatedType< T_ > &&other) noexcept
Move constructor.
Definition buffer.hpp:1804
report various types of exceptions or errors that may occur when working with buffers
Definition buffer.hpp:115
const char * what() const noexcept override
Definition buffer.hpp:144
virtual ~BufferException() noexcept=default
BufferException(Status status)
Definition buffer.hpp:133
Status status() const
Definition buffer.hpp:151
BufferException(Status status, const std::string &msg)
Definition buffer.hpp:138
static const char * status_string(const Status status)
Definition buffer.hpp:158
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.
Definition buffer.hpp:864
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...
Definition buffer.hpp:853
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...
Definition buffer.hpp:844
Immutable buffer with double ended access and adjustable free space at both ends.
Definition buffer.hpp:235
bool defined() const
Returns true if the buffer is not empty.
Definition buffer.hpp:1223
void set_trailer(const T &value)
Place a T object after the last object in the array, with possible resize to contain it....
Definition buffer.hpp:1497
const T * c_data() const
Returns a const pointer to the start of the buffer.
Definition buffer.hpp:1193
T * prepend_alloc(const size_t size)
Allocate space for prepending data to the buffer.
Definition buffer.hpp:1594
ConstBufferType(void *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a void pointer and size.
Definition buffer.hpp:1110
T * data_end()
Get a mutable pointer to the end of the array.
Definition buffer.hpp:1453
void append(const B &other)
Append data from another buffer to this buffer.
Definition buffer.hpp:1623
void init_headroom(const size_t headroom)
Initializes the headroom (offset) of the buffer.
Definition buffer.hpp:1150
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_...
Definition buffer.hpp:1389
size_t length() const
Returns the length of the buffer.
Definition buffer.hpp:1187
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().
Definition buffer.hpp:1523
size_t max_size() const
Return the maximum allowable size value in T objects given the current offset (without considering re...
Definition buffer.hpp:1374
openvpn_io::const_buffer const_buffer_limit(const size_t limit) const
Return a const_buffer object with a specified size limit.
Definition buffer.hpp:1323
T front() const
Returns the first element of the buffer.
Definition buffer.hpp:1264
virtual void reset_impl(const size_t min_capacity, const BufferFlags flags)
Called when the reset method needs to expand the buffer size.
Definition buffer.hpp:1629
ConstBufferType()
Default constructor for ConstBufferType.
Definition buffer.hpp:1101
openvpn_io::const_buffer const_buffer() const
Return an openvpn_io::const_buffer object used by asio write methods.
Definition buffer.hpp:1311
void push_back(const T &value)
Append a T object to the end of the array, resizing the array if necessary.
Definition buffer.hpp:1479
void reset(const size_t min_capacity, const BufferFlags flags)
Reset the buffer with the specified minimum capacity and flags.
Definition buffer.hpp:1606
T back() const
Returns the last element of the buffer.
Definition buffer.hpp:1270
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 ...
Definition buffer.hpp:1127
openvpn_io::mutable_buffer mutable_buffer_append_clamp(const size_t tailroom=0)
Clamped version of mutable_buffer_append().
Definition buffer.hpp:1541
ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
Construct a ConstBufferType object.
Definition buffer.hpp:1652
bool operator!=(const ConstBufferType &other) const
Inequality operator to compare this buffer with another ConstBufferType object.
Definition buffer.hpp:1434
ConstBufferType(T *data, const size_t size, const bool filled)
Constructs a ConstBufferType from a pointer to T and size.
Definition buffer.hpp:1119
void write(const void *data, const size_t size)
Write data to the buffer.
Definition buffer.hpp:1566
ConstBufferType range(size_t offset, size_t len) const
Get a range of the buffer as a ConstBufferType object.
Definition buffer.hpp:1395
void read(void *data, const size_t size)
Read data from the buffer into the specified memory location.
Definition buffer.hpp:1336
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...
Definition buffer.hpp:1657
const T * c_str() const
Returns a const pointer to the null-terminated string representation of the buffer.
Definition buffer.hpp:1181
T * write_alloc(const size_t size)
Allocate space for writing data to the buffer.
Definition buffer.hpp:1584
void reserve(const size_t n)
Reserve additional memory for the buffer.
Definition buffer.hpp:1440
const T * c_data_end() const
Returns a const pointer to the end of the buffer.
Definition buffer.hpp:1199
auto read_alloc_buf(const size_t size)
Allocate memory and read data from the buffer into the allocated memory.
Definition buffer.hpp:1360
void prepend(const T *data, const size_t size)
Prepend data to the buffer.
Definition buffer.hpp:1572
bool allocated() const
Returns true if the data memory is defined (allocated).
Definition buffer.hpp:1229
size_t capacity() const
Returns the capacity (raw size) of the allocated buffer in T objects.
Definition buffer.hpp:1211
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1241
T * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1447
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 ...
Definition buffer.hpp:1115
T pop_back()
Removes and returns the last element from the buffer.
Definition buffer.hpp:1247
openvpn_io::const_buffer const_buffer_clamp() const
Return a clamped version of const_buffer().
Definition buffer.hpp:1317
void advance(const size_t delta)
Advances the buffer by the specified delta.
Definition buffer.hpp:1276
const auto & operator[](const size_t index) const
Const indexing operator for ConstBufferType.
Definition buffer.hpp:1131
bool operator==(const ConstBufferType &other) const
Equality operator to compare this buffer with another ConstBufferType object.
Definition buffer.hpp:1426
bool empty() const
Returns true if the buffer is empty.
Definition buffer.hpp:1235
void prepend(const void *data, const size_t size)
Prepend data to the buffer.
Definition buffer.hpp:1578
const T * c_data_raw() const
Returns a const pointer to the start of the raw data in the buffer.
Definition buffer.hpp:1205
void write(const T *data, const size_t size)
Write data to the buffer.
Definition buffer.hpp:1560
const T * c_index(const size_t index) const
Get a const pointer to the element at the specified index in the array.
Definition buffer.hpp:1408
auto * read_alloc(const size_t size)
Allocate memory and read data from the buffer into the allocated memory.
Definition buffer.hpp:1342
bool is_zeroed() const
Returns true if the buffer is zeroed (all elements are zero).
Definition buffer.hpp:1297
T pop_front()
Removes and returns the first element from the buffer.
Definition buffer.hpp:1255
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...
Definition buffer.hpp:1465
auto & operator[](const size_t index)
Non-const indexing operator for ConstBufferType.
Definition buffer.hpp:1139
T * data_raw()
Get a mutable pointer to the start of the raw data.
Definition buffer.hpp:1459
void swap(ConstBufferType< T_ > &other)
Swap the contents of this buffer with another buffer.
Definition buffer.hpp:1417
size_t offset() const
Returns the current offset (headroom) into the buffer.
Definition buffer.hpp:1217
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.
Definition buffer.hpp:1613
typename std::remove_const_t< T > NCT
Definition buffer.hpp:240
void buffer_full_error(const size_t newcap, const bool allocated) const
Throw an exception when the buffer is full.
Definition buffer.hpp:1642
void reset_offset(const size_t offset)
Resets the offset of the buffer.
Definition buffer.hpp:1159
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.
Definition buffer.hpp:1512
bool contains_null() const
Returns true if the buffer contains a null character.
Definition buffer.hpp:1285
void push_front(const T &value)
Append a T object to the array, with possible resize.
Definition buffer.hpp:1487
void set_size(const size_t size)
After an external method, operating on the array as a mutable unsigned char buffer,...
Definition buffer.hpp:1381
void reset_content()
Resets the content of the buffer.
Definition buffer.hpp:1175
virtual void resize(const size_t new_capacity)
Derived classes can implement buffer growing semantics by overloading this method....
Definition buffer.hpp:1635
void null_terminate()
Null-terminate the array.
Definition buffer.hpp:1505
void reset_size()
Resets the size of the buffer to zero.
Definition buffer.hpp:1169
void realign(size_t headroom)
Realign the buffer with the specified headroom.
Definition buffer.hpp:1548
openvpn_io::mutable_buffer mutable_buffer_clamp(const size_t tailroom=0)
Clamped version of mutable_buffer().
Definition buffer.hpp:1535
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().
Definition buffer.hpp:1529
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.
Definition buffer.hpp:1472
void read(NCT *data, const size_t size)
Read data from the buffer into the specified memory location.
Definition buffer.hpp:1330
A class template that enables reference counting for a given type.
Definition make_rc.hpp:29
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)
Definition buffer.hpp:1917
AlignT * align_as(BufferAllocatedType< T > &buf)
Aligns buffer.data() to the required value and returns a pointer to the aligned object.
Definition buffer.hpp:1940
size_t buf_clamp_read(const size_t size)
Definition bufclamp.hpp:23
size_t buf_clamp_write(const size_t size)
Definition bufclamp.hpp:32
CRTP type designed to allow creation of strong types based on intrinsics.
reroute_gw flags
server addresses push_back(address)
std::string ret
#define msg(flags,...)