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
949 void init(const size_t capacity, const BufferFlags flags = BufAllocFlags::NO_FLAGS);
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
1041 void add_flags(const BufferFlags flags);
1042
1048 void clear_flags(const BufferFlags flags);
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 if (size)
1333 std::memcpy(data, read_alloc(size), size * sizeof(T));
1334}
1335
1336template <typename T>
1337void ConstBufferType<T>::read(void *data, const size_t size)
1338{
1339 read((NCT *)data, size);
1340}
1341
1342template <typename T>
1343auto *ConstBufferType<T>::read_alloc(const size_t size)
1344{
1345 if (size <= size_)
1346 {
1347 using retT = std::conditional_t<std::is_same_v<decltype(*this), ConstBufferType<T>>, const value_type, value_type>;
1348 retT *ret;
1349 if constexpr (std::is_const_v<retT>)
1350 ret = c_data();
1351 else
1352 ret = data();
1353 offset_ += size;
1354 size_ -= size;
1355 return ret;
1356 }
1357 OPENVPN_BUFFER_THROW(buffer_underflow);
1358}
1359
1360template <typename T>
1362{
1363 if (size <= size_)
1364 {
1365 using retT = std::conditional_t<std::is_same_v<decltype(*this), ConstBufferType<T>>, ConstBufferType<T>, BufferType<T>>;
1366 retT ret(data_, offset_, size, capacity_);
1367 offset_ += size;
1368 size_ -= size;
1369 return ret;
1370 }
1371 OPENVPN_BUFFER_THROW(buffer_underflow);
1372}
1373
1374template <typename T>
1376{
1377 const size_t r = capacity_ - offset_;
1378 return r <= capacity_ ? r : 0;
1379}
1380
1381template <typename T>
1382void ConstBufferType<T>::set_size(const size_t size)
1383{
1384 if (size > max_size())
1385 OPENVPN_BUFFER_THROW(buffer_set_size);
1386 size_ = size;
1387}
1388
1389template <typename T>
1390void ConstBufferType<T>::inc_size(const size_t delta)
1391{
1392 set_size(size_ + delta);
1393}
1394
1395template <typename T>
1396ConstBufferType<T> ConstBufferType<T>::range(size_t offset, size_t len) const
1397{
1398 if (offset + len > size())
1399 {
1400 if (offset < size())
1401 len = size() - offset;
1402 else
1403 len = 0;
1404 }
1405 return ConstBufferType(c_data(), offset, len, len);
1406}
1407
1408template <typename T>
1409const T *ConstBufferType<T>::c_index(const size_t index) const
1410{
1411 if (index >= size_)
1412 OPENVPN_BUFFER_THROW(buffer_const_index);
1413 return &c_data()[index];
1414}
1415
1416template <typename T>
1417template <typename T_>
1419{
1420 std::swap(other.data_, data_);
1421 std::swap(other.offset_, offset_);
1422 std::swap(other.size_, size_);
1423 std::swap(other.capacity_, capacity_);
1424}
1425
1426template <typename T>
1428{
1429 if (size_ != other.size_)
1430 return false;
1431 return std::memcmp(c_data(), other.c_data(), size_) == 0;
1432}
1433
1434template <typename T>
1436{
1437 return !(*this == other);
1438}
1439
1440template <typename T>
1442{
1443 if (n > capacity_)
1444 resize(n);
1445}
1446
1447template <typename T>
1449{
1450 return data_ + offset_;
1451}
1452
1453template <typename T>
1455{
1456 return data_ + offset_ + size_;
1457}
1458
1459template <typename T>
1461{
1462 return data_;
1463}
1464
1465template <typename T>
1466size_t ConstBufferType<T>::remaining(const size_t tailroom) const
1467{
1468 const size_t r = capacity_ - (offset_ + size_ + tailroom);
1469 return r <= capacity_ ? r : 0;
1470}
1471
1472template <typename T>
1473size_t ConstBufferType<T>::max_size_tailroom(const size_t tailroom) const
1474{
1475 const size_t r = capacity_ - (offset_ + tailroom);
1476 return r <= capacity_ ? r : 0;
1477}
1478
1479template <typename T>
1481{
1482 if (!remaining())
1483 resize(offset_ + size_ + 1);
1484 *(data() + size_++) = value;
1485}
1486
1487template <typename T>
1489{
1490 if (!offset_)
1491 OPENVPN_BUFFER_THROW(buffer_push_front_headroom);
1492 --offset_;
1493 ++size_;
1494 *data() = value;
1495}
1496
1497template <typename T>
1499{
1500 if (!remaining())
1501 resize(offset_ + size_ + 1);
1502 *(data() + size_) = value;
1503}
1504
1505template <typename T>
1507{
1508 if (empty() || back())
1509 push_back(0);
1510}
1511
1512template <typename T>
1513T *ConstBufferType<T>::index(const size_t index)
1514{
1515 if (index >= size_)
1516 OPENVPN_BUFFER_THROW(buffer_index);
1517 return &data()[index];
1518}
1519
1520
1521#ifndef OPENVPN_NO_IO
1522
1523template <typename T>
1524openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer(const size_t tailroom)
1525{
1526 return openvpn_io::mutable_buffer(data(), max_size_tailroom(tailroom));
1527}
1528
1529template <typename T>
1530openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_append(const size_t tailroom)
1531{
1532 return openvpn_io::mutable_buffer(data_end(), remaining(tailroom));
1533}
1534
1535template <typename T>
1536openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_clamp(const size_t tailroom)
1537{
1538 return openvpn_io::mutable_buffer(data(), buf_clamp_read(max_size_tailroom(tailroom)));
1539}
1540
1541template <typename T>
1542openvpn_io::mutable_buffer ConstBufferType<T>::mutable_buffer_append_clamp(const size_t tailroom)
1543{
1544 return openvpn_io::mutable_buffer(data_end(), buf_clamp_read(remaining(tailroom)));
1545}
1546#endif
1547
1548template <typename T>
1549void ConstBufferType<T>::realign(size_t headroom)
1550{
1551 if (headroom != offset_)
1552 {
1553 if (headroom + size_ > capacity_)
1554 OPENVPN_BUFFER_THROW(buffer_headroom);
1555 std::memmove(data_ + headroom, data_ + offset_, size_);
1556 offset_ = headroom;
1557 }
1558}
1559
1560template <typename T>
1561void ConstBufferType<T>::write(const T *data, const size_t size)
1562{
1563 if (size)
1564 std::memcpy(write_alloc(size), data, size * sizeof(T));
1565}
1566
1567template <typename T>
1568void ConstBufferType<T>::write(const void *data, const size_t size)
1569{
1570 write((const T *)data, size);
1571}
1572
1573template <typename T>
1574void ConstBufferType<T>::prepend(const T *data, const size_t size)
1575{
1576 if (size)
1577 std::memcpy(prepend_alloc(size), data, size * sizeof(T));
1578}
1579
1580template <typename T>
1581void ConstBufferType<T>::prepend(const void *data, const size_t size)
1582{
1583 prepend((const T *)data, size);
1584}
1585
1586template <typename T>
1588{
1589 if (size > remaining())
1590 resize(offset_ + size_ + size);
1591 T *ret = data() + size_;
1592 size_ += size;
1593 return ret;
1594}
1595
1596template <typename T>
1597T *ConstBufferType<T>::prepend_alloc(const size_t request_size)
1598{
1599 if (request_size > offset())
1600 realign(request_size);
1601
1602 offset_ -= request_size;
1603 size_ += request_size;
1604
1605 return data();
1606}
1607
1608template <typename T>
1609void ConstBufferType<T>::reset(const size_t min_capacity, const BufferFlags flags)
1610{
1611 if (min_capacity > capacity_)
1612 reset_impl(min_capacity, flags);
1613}
1614
1615template <typename T>
1616void ConstBufferType<T>::reset(const size_t headroom,
1617 const size_t min_capacity,
1618 const BufferFlags flags)
1619{
1620 reset(min_capacity, flags);
1621 init_headroom(headroom);
1622}
1623
1624template <typename T>
1625template <typename B>
1626void ConstBufferType<T>::append(const B &other)
1627{
1628 write(other.c_data(), other.size());
1629}
1630
1631template <typename T>
1632void ConstBufferType<T>::reset_impl(const size_t min_capacity, const BufferFlags flags)
1633{
1634 OPENVPN_BUFFER_THROW(buffer_no_reset_impl);
1635}
1636
1637template <typename T>
1638void ConstBufferType<T>::resize(const size_t new_capacity)
1639{
1640 if (new_capacity > capacity_)
1641 buffer_full_error(new_capacity, false);
1642}
1643
1644template <typename T>
1645void ConstBufferType<T>::buffer_full_error(const size_t newcap, const bool allocated) const
1646{
1647#ifdef OPENVPN_BUFFER_ABORT
1648 std::abort();
1649#else
1650 throw BufferException(BufferException::buffer_full, "allocated=" + std::to_string(allocated) + " size=" + std::to_string(size_) + " offset=" + std::to_string(offset_) + " capacity=" + std::to_string(capacity_) + " newcap=" + std::to_string(newcap));
1651#endif
1652}
1653
1654template <typename T>
1655ConstBufferType<T>::ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
1656 : data_(data), offset_(offset), size_(size), capacity_(capacity) {};
1657
1658template <typename T>
1659template <typename U, typename std::enable_if_t<!std::is_const_v<U>, int>>
1660ConstBufferType<T>::ConstBufferType(const U *data, const size_t offset, const size_t size, const size_t capacity)
1661 : ConstBufferType(const_cast<U *>(data), offset, size, capacity) {};
1662
1663// ===============================================================================================
1664// BufferAllocatedType<T> member function definitions
1665// ===============================================================================================
1666
1667template <typename T>
1669 const size_t size,
1670 const size_t capacity,
1671 const BufferFlags flags)
1672 : BufferType<T>(capacity ? new T[capacity] : nullptr, offset, size, capacity), flags_(flags)
1673{
1674 if (capacity && (flags & BufAllocFlags::CONSTRUCT_ZERO))
1675 std::memset(data_raw(), 0, capacity * sizeof(T));
1676}
1677
1678template <typename T>
1680 : BufferAllocatedType(0, 0, 0, BufAllocFlags::NO_FLAGS)
1681{
1682 static_assert(std::is_nothrow_move_constructible_v<BufferAllocatedType>,
1683 "class BufferAllocatedType not noexcept move constructable");
1684}
1685
1686template <typename T>
1688 const BufferFlags flags)
1690 (flags & BufAllocFlags::ARRAY ? capacity : 0),
1691 capacity,
1692 flags) {};
1693
1694template <typename T>
1696 const size_t size,
1697 const BufferFlags flags)
1698 : BufferAllocatedType(0, size, size, flags)
1699{
1700 if (size && data)
1701 std::memcpy(data_raw(), data, size * sizeof(T));
1702}
1703
1704template <typename T>
1706 : BufferAllocatedType(other.offset(), other.size(), other.capacity(), other.flags_)
1707{
1708 if (size())
1709 std::memcpy(data(), other.c_data(), size() * sizeof(T));
1710}
1711
1712template <typename T>
1713template <typename T_>
1715 const BufferFlags flags)
1716 : BufferAllocatedType(other.offset(), other.size(), other.capacity(), flags)
1717{
1718 static_assert(sizeof(T) == sizeof(T_), "size inconsistency");
1719 if (size())
1720 std::memcpy(data(), other.c_data(), size() * sizeof(T));
1721}
1722
1723template <typename T>
1725{
1726 if (this != &other)
1727 {
1728 auto tempBuffer = BufferAllocatedType(other.offset(),
1729 other.size(),
1730 other.capacity(),
1731 other.flags_);
1732 if (other.size())
1733 std::memcpy(tempBuffer.data(), other.c_data(), tempBuffer.size() * sizeof(T));
1734 swap(tempBuffer);
1735 }
1736}
1737
1738template <typename T>
1739void BufferAllocatedType<T>::init(const size_t capacity, const BufferFlags flags)
1740{
1741 auto tempBuffer = BufferAllocatedType(capacity, flags);
1742 swap(tempBuffer);
1743}
1744
1745template <typename T>
1746void BufferAllocatedType<T>::init(const T *data, const size_t size, const BufferFlags flags)
1747{
1748 auto tempBuffer = BufferAllocatedType(data, size, flags);
1749 swap(tempBuffer);
1750}
1751
1752template <typename T>
1753void BufferAllocatedType<T>::realloc(const size_t newcap)
1754{
1755 if (newcap > capacity())
1756 realloc_(newcap, offset());
1757}
1758
1759template <typename T>
1761{
1762 if (headroom != offset())
1763 {
1764 if (headroom + size() > capacity())
1765 realloc_(headroom + size(), headroom);
1766 else
1767 BufferType<T>::realign(headroom);
1768 }
1769 return *this;
1770}
1771
1772template <typename T>
1773void BufferAllocatedType<T>::reset(const size_t min_capacity, const BufferFlags flags)
1774{
1775 if (min_capacity > capacity())
1776 init(min_capacity, flags);
1777}
1778
1779template <typename T>
1780void BufferAllocatedType<T>::reset(const size_t headroom,
1781 const size_t min_capacity,
1782 const BufferFlags flags)
1783{
1784 reset(min_capacity, flags);
1785 init_headroom(headroom);
1786}
1787
1788template <typename T>
1789template <typename T_>
1791{
1792 auto temp = BufferAllocatedType();
1793 swap(other);
1794 other.swap(temp);
1795}
1796
1797template <typename T>
1798template <typename T_>
1800{
1801 BufferType<T>::swap(other);
1802 std::swap(flags_, other.flags_);
1803}
1804
1805template <typename T>
1806template <typename T_>
1809{
1810 move(other);
1811}
1812
1813template <typename T>
1815{
1816 if (this != &other)
1817 {
1818 move(other);
1819 }
1820 return *this;
1821}
1822
1823template <typename T>
1825{
1826 auto tempBuffer = BufferAllocatedType(0, 0, 0, BufAllocFlags::NO_FLAGS);
1827 swap(tempBuffer);
1828}
1829
1830template <typename T>
1831bool BufferAllocatedType<T>::test_flags(const BufferFlags flags) const noexcept
1832{
1833 return flags_ & flags;
1834}
1835
1836template <typename T>
1838{
1839 flags_ |= flags;
1840}
1841
1842template <typename T>
1844{
1845 flags_ &= ~flags;
1846}
1847
1848template <typename T>
1850{
1851 if (data_raw())
1852 free_data();
1853}
1854
1855template <typename T>
1856void BufferAllocatedType<T>::reset_impl(const size_t min_capacity, const BufferFlags flags)
1857{
1858 init(min_capacity, flags);
1859}
1860
1861template <typename T>
1862void BufferAllocatedType<T>::resize(const size_t new_capacity)
1863{
1864 const size_t newcap = std::max(new_capacity, capacity() * 2);
1865 if (newcap > capacity())
1866 {
1867 if (flags_ & BufAllocFlags::GROW)
1868 realloc_(newcap, offset());
1869 else
1870 buffer_full_error(newcap, true);
1871 }
1872}
1873
1874template <typename T>
1875void BufferAllocatedType<T>::realloc_(const size_t newcap, size_t new_offset)
1876{
1877 auto tempBuffer = BufferAllocatedType(new_offset, size(), newcap, flags_);
1878 if (size())
1879 std::memcpy(tempBuffer.data(), c_data(), size() * sizeof(T));
1880 swap(tempBuffer);
1881}
1882
1883template <typename T>
1885{
1886 if (size() && (flags_ & BufAllocFlags::DESTRUCT_ZERO))
1887 std::memset(data_raw(), 0, capacity() * sizeof(T));
1888 delete[] data_raw();
1889}
1890
1891// ===============================================================================================
1892// specializations of BufferType for unsigned char
1893// ===============================================================================================
1894
1900
1901// ===============================================================================================
1902// BufferAllocated + RC with thread-safe refcount
1903// ===============================================================================================
1904
1907
1908// ===============================================================================================
1909// Deduction guide - needed to deduce converting ctor
1910// ===============================================================================================
1911
1912template <typename T_>
1914
1915// ===============================================================================================
1916// cast BufferType<T> to ConstBufferType<T>
1917// ===============================================================================================
1918
1919template <typename T>
1921{
1922 return src;
1923}
1924
1925template <typename T>
1927{
1928 return src;
1929}
1930
1931// ===============================================================================================
1932// Buffer related utilities - consider moving to a separate file
1933// ===============================================================================================
1934
1942template <typename AlignT, typename T>
1943inline AlignT *align_as(BufferAllocatedType<T> &buf) // TODO: Could be implemented noexcept
1944{
1945 /* The standard requires that alignof(T) is a power of 2, and that any allocation will be
1946 aligned to at least alignof(std::max_align_t), so I assume offset zero in a buffer is
1947 aligned and therefore there is no need to check for alignment of the buffer itself.
1948
1949 This means a suitable address exists in the first alignof(std::max_align_t) so we never have
1950 to increase the offset at all. This is a simplification that might not hold in all cases,
1951 but it is a reasonable assumption for now. Given that, we can just align the buffer by
1952 masking out the lower bits of the current data address (computation of align_ptr below)
1953 and then realign the buffer to that address if needed. This will preserve as much of the
1954 headroom as possible.
1955 */
1956 auto data_ptr = reinterpret_cast<uintptr_t>(buf.c_data()); // Current data address in integral form
1957 auto align_ptr = data_ptr & ~(alignof(AlignT) - 1); // 'Previous' aligned address
1958 auto raw_data_ptr = reinterpret_cast<uintptr_t>(buf.c_data_raw()); // Start of allocated buffer
1959
1960 if (align_ptr != data_ptr && align_ptr >= raw_data_ptr)
1961 buf.realign(align_ptr - raw_data_ptr);
1962
1963 return reinterpret_cast<AlignT *>(buf.data()); // unsigned char is type accessible by all types
1964}
1965
1966} // 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:1668
friend class BufferAllocatedType
Definition buffer.hpp:887
void clear()
Clears the contents of the buffer.
Definition buffer.hpp:1824
BufferAllocatedType & operator=(BufferAllocatedType &&other) noexcept
Move assignment operator.
Definition buffer.hpp:1814
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:1773
void init(const size_t capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Initializes the buffer with the specified capacity and flags.
Definition buffer.hpp:1739
void clear_flags(const BufferFlags flags)
Clears the specified flags for the buffer.
Definition buffer.hpp:1843
BufferAllocatedType(const size_t capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Constructs a BufferAllocatedType with the specified capacity and flags.
Definition buffer.hpp:1687
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:1780
~BufferAllocatedType()
Destructor.
Definition buffer.hpp:1849
void resize(const size_t new_capacity) override
Resizes the buffer to the specified new capacity.
Definition buffer.hpp:1862
bool test_flags(const BufferFlags flags) const noexcept
Test if the buffer has the specified flags.
Definition buffer.hpp:1831
void add_flags(const BufferFlags flags)
Sets the specified flags for the buffer.
Definition buffer.hpp:1837
void move(BufferAllocatedType< T_ > &other)
Moves the contents of another BufferAllocatedType object into this object.
Definition buffer.hpp:1790
BufferAllocatedType()
Default constructor.
Definition buffer.hpp:1679
void realloc(const size_t newcap)
Reallocates the buffer to the specified new capacity.
Definition buffer.hpp:1753
void operator=(const BufferAllocatedType &other)
Assignment operator.
Definition buffer.hpp:1724
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:1856
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:1746
void realloc_(const size_t newcap, size_t new_offset)
Reallocates the buffer to the specified new capacity.
Definition buffer.hpp:1875
BufferAllocatedType & realign(const size_t headroom)
Realign the buffer with the specified headroom.
Definition buffer.hpp:1760
void free_data()
Frees the data associated with the buffer.
Definition buffer.hpp:1884
void swap(BufferAllocatedType< T_ > &other)
Swaps the contents of this BufferAllocatedType object with another BufferAllocatedType object.
Definition buffer.hpp:1799
BufferAllocatedType(const T *data, const size_t size, const BufferFlags flags)
Constructs a BufferAllocatedType with the specified data, size, and flags.
Definition buffer.hpp:1695
BufferAllocatedType(const BufferAllocatedType &other)
Copy constructor.
Definition buffer.hpp:1705
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:1714
BufferAllocatedType(BufferAllocatedType< T_ > &&other) noexcept
Move constructor.
Definition buffer.hpp:1807
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:1498
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:1597
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:1454
void append(const B &other)
Append data from another buffer to this buffer.
Definition buffer.hpp:1626
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:1390
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:1524
size_t max_size() const
Return the maximum allowable size value in T objects given the current offset (without considering re...
Definition buffer.hpp:1375
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:1632
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:1480
void reset(const size_t min_capacity, const BufferFlags flags)
Reset the buffer with the specified minimum capacity and flags.
Definition buffer.hpp:1609
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:1542
ConstBufferType(T *data, const size_t offset, const size_t size, const size_t capacity)
Construct a ConstBufferType object.
Definition buffer.hpp:1655
bool operator!=(const ConstBufferType &other) const
Inequality operator to compare this buffer with another ConstBufferType object.
Definition buffer.hpp:1435
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:1568
ConstBufferType range(size_t offset, size_t len) const
Get a range of the buffer as a ConstBufferType object.
Definition buffer.hpp:1396
void read(void *data, const size_t size)
Read data from the buffer into the specified memory location.
Definition buffer.hpp:1337
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:1660
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:1587
void reserve(const size_t n)
Reserve additional memory for the buffer.
Definition buffer.hpp:1441
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:1361
void prepend(const T *data, const size_t size)
Prepend data to the buffer.
Definition buffer.hpp:1574
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:1448
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:1427
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:1581
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:1561
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:1409
auto * read_alloc(const size_t size)
Allocate memory and read data from the buffer into the allocated memory.
Definition buffer.hpp:1343
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:1466
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:1460
void swap(ConstBufferType< T_ > &other)
Swap the contents of this buffer with another buffer.
Definition buffer.hpp:1418
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:1616
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:1645
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:1513
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:1488
void set_size(const size_t size)
After an external method, operating on the array as a mutable unsigned char buffer,...
Definition buffer.hpp:1382
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:1638
void null_terminate()
Null-terminate the array.
Definition buffer.hpp:1506
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:1549
openvpn_io::mutable_buffer mutable_buffer_clamp(const size_t tailroom=0)
Clamped version of mutable_buffer().
Definition buffer.hpp:1536
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:1530
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:1473
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:1920
AlignT * align_as(BufferAllocatedType< T > &buf)
Aligns buffer.data() to the required value and returns a pointer to the aligned object.
Definition buffer.hpp:1943
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.
#define msg(flags,...)