LibSWOC++ 1.5.14
Solid Wall of C++
Loading...
Searching...
No Matches
MemSpan.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright Verizon Media 2020
9
10#pragma once
11
12#include "swoc/swoc_version.h"
13#include "swoc/Scalar.h"
14
15#include <cstring>
16#include <memory>
17#include <type_traits>
18#include <ratio>
19#include <tuple>
20#include <exception>
21
23#include <array>
24#include <vector>
25#include <string_view>
26
27namespace swoc { inline namespace SWOC_VERSION_NS {
50template <typename T> class MemSpan {
51 using self_type = MemSpan;
52
53protected:
54 T *_ptr = nullptr;
55 size_t _count = 0;
56
57public:
58 using value_type = T;
59 using iterator = T *;
60 using const_iterator = T const *;
61
63 constexpr MemSpan() = default;
64
66 constexpr MemSpan(self_type const &that) = default;
68 constexpr MemSpan(self_type &that) = default;
69
75 constexpr MemSpan(value_type *ptr, size_t count);
76
83
89 template <auto N> constexpr MemSpan(T (&a)[N]);
90
98 template <auto N, typename U,
99 typename META =
100 std::enable_if_t<std::conjunction_v<std::is_const<T>, std::is_same<std::remove_const_t<U>, std::remove_const_t<T>>>>>
101 constexpr MemSpan(std::array<U, N> const &a);
102
108 template <auto N> constexpr MemSpan(std::array<T, N> &a);
109
118 template <typename U,
119 typename META = std::enable_if_t<std::conjunction_v<std::is_const<T>, std::is_same<U, std::remove_const_t<T>>>>>
120 constexpr MemSpan(MemSpan<U> const &that) : _ptr(that.data()), _count(that.count()) {}
121
135 template <typename C, typename = std::enable_if_t<std::is_convertible_v<decltype(std::declval<C>().data()), T *> &&
136 std::is_convertible_v<decltype(std::declval<C>().size()), size_t>,
137 void>>
138 constexpr MemSpan(C &c);
139
151 template <typename C, typename = std::enable_if_t<std::is_convertible_v<decltype(std::declval<C>().data()), T *> &&
152 std::is_convertible_v<decltype(std::declval<C>().size()), size_t>,
153 void>>
154 constexpr MemSpan(C const &c);
155
159 constexpr MemSpan(std::nullptr_t);
160
168 constexpr bool operator==(self_type const &that) const;
169
175 bool is_same(self_type const &that) const;
176
181 constexpr bool operator!=(self_type const &that) const;
182
184 self_type &operator=(self_type const &that) = default;
185
187 T &operator[](size_t idx) const;
188
191 bool operator!() const;
192
195 explicit operator bool() const;
196
199 constexpr bool empty() const;
200
202
203
204 constexpr T *begin() const;
205
207 constexpr T *end() const;
208
210 constexpr size_t size() const;
211
214 constexpr size_t count() const;
215
217 constexpr size_t length() const;
218
220 constexpr size_t data_size() const;
221
223 T *data() const;
224
226 constexpr T *data_end() const;
227
232 T &front();
233
238 T &back();
239
246 template <typename F> self_type &apply(F &&f);
247
256 template <typename U = std::conditional_t<std::is_const_v<T>, void const, void>> MemSpan<U> rebind() const;
257
262 self_type &assign(T *ptr,
263 size_t count
264 );
265
272 self_type &assign(T *first, T const *last);
273
275 self_type &clear();
276
278 bool contains(value_type const *p) const;
279
284 constexpr self_type prefix(size_t count) const;
285
292 constexpr self_type first(size_t count) const;
293
299 self_type &remove_prefix(size_t count);
300
308 self_type clip_prefix(size_t count);
309
315 constexpr self_type suffix(size_t count) const;
316
324 constexpr self_type last(size_t count) const;
325
331 self_type &remove_suffix(size_t count);
332
340 self_type clip_suffix(size_t count);
341
351 constexpr self_type subspan(size_t offset, size_t count) const;
352
360 constexpr self_type &restrict(size_t n);
361
367 template <typename... Args> self_type &make(Args &&...args);
368
370 void destroy();
371
372 template <typename U> friend class MemSpan;
373};
374
387template <> class MemSpan<void const> {
388 using self_type = MemSpan;
389 template <typename U> friend class MemSpan;
390
391public:
392 using value_type = void const;
393
394protected:
395 void *_ptr = nullptr;
396 size_t _size = 0;
397
398public:
400 constexpr MemSpan() = default;
401
403 constexpr MemSpan(self_type const &that) = default;
404
406 constexpr self_type &operator=(self_type const &that) = default;
407
413 template <auto N, typename U> constexpr MemSpan(U (&a)[N]);
414
416 constexpr MemSpan(MemSpan<void> const &that);
417
426 template <typename U> constexpr MemSpan(MemSpan<U> const &that);
427
433 constexpr MemSpan(value_type *ptr, size_t n);
434
440 MemSpan(value_type *begin, value_type *end);
441
450 template <typename C, typename = std::enable_if_t<std::is_convertible_v<decltype(std::declval<C>().size()), size_t>, void>>
451 constexpr MemSpan(C const &c);
452
456 constexpr MemSpan(std::nullptr_t);
457
465 bool operator==(self_type const &that) const;
466
473 bool is_same(self_type const &that) const;
474
479 bool operator!=(self_type const &that) const;
480
483 explicit operator bool() const;
484
487 bool operator!() const;
488
491 constexpr bool empty() const;
492
494 constexpr size_t size() const;
495
498 constexpr size_t count() const;
499
502 constexpr size_t length() const;
503
505 constexpr size_t data_size() const;
506
508 constexpr value_type *data() const;
509
511 value_type *data_end() const;
512
514 constexpr self_type &operator=(MemSpan<void> const &that);
515
518 template <typename U> self_type &operator=(MemSpan<U> const &that);
519
526 self_type &assign(value_type *ptr, size_t n);
527
534 self_type &assign(value_type *first, value_type const *last);
535
541 template <typename U> MemSpan<U> rebind() const;
542
550 template <typename U> U const *as_ptr() const;
551
553 self_type &clear();
554
556 bool contains(void const *ptr) const;
557
562 self_type prefix(size_t n) const;
563
569 self_type &remove_prefix(size_t n);
570
578 self_type clip_prefix(size_t n);
579
585 self_type suffix(size_t n) const;
586
592 self_type &remove_suffix(size_t n);
593
601 self_type clip_suffix(size_t n);
602
613 constexpr self_type subspan(size_t offset, size_t n) const;
614
623 template <typename T> self_type align() const;
624
633 self_type align(size_t alignment) const;
634
647 self_type align(size_t alignment, size_t obj_size) const;
648};
649
650template <> class MemSpan<void> : public MemSpan<void const> {
651 using self_type = MemSpan;
652 using super_type = MemSpan<void const>;
653 template <typename U> friend class MemSpan;
654
655public:
656 using value_type = void;
657 using pointer_type = value_type *;
658
660 constexpr MemSpan() = default;
661
663 constexpr MemSpan(self_type const &that) = default;
664
666 constexpr self_type &operator=(self_type const &that) = default;
667
676 template <typename U> constexpr MemSpan(MemSpan<U> const &that);
677
683 constexpr MemSpan(value_type *start, size_t n);
684
690 MemSpan(value_type *begin, value_type *end);
691
698 template <auto N, typename U> constexpr MemSpan(U (&a)[N]);
699
703 constexpr MemSpan(std::nullptr_t);
704
706 constexpr value_type *data() const;
707
709 value_type *data_end() const;
710
713 template <typename U> self_type &operator=(MemSpan<U> const &that);
714
723 template <typename C, typename = std::enable_if_t<!std::is_const_v<decltype(std::declval<C>().data()[0])> &&
724 std::is_convertible_v<decltype(std::declval<C>().size()), size_t>,
725 void>>
726 constexpr MemSpan(C const &c);
727
734 self_type &assign(value_type *ptr, size_t n);
735
742 self_type &assign(value_type *first, value_type const *last);
743
745 self_type prefix(size_t n) const;
746
752 self_type &remove_prefix(size_t count);
753
761 self_type clip_prefix(size_t n);
762
768 self_type suffix(size_t n) const;
769
775 self_type &remove_suffix(size_t n);
776
784 self_type clip_suffix(size_t n);
785
796 constexpr self_type subspan(size_t offset, size_t n) const;
797
806 template <typename T> self_type align() const;
807
816 self_type align(size_t alignment) const;
817
830 self_type align(size_t alignment, size_t obj_size) const;
831
837 template <typename U> MemSpan<U> rebind() const;
838
846 template <typename U> U *as_ptr() const;
847
849 self_type &clear();
850
851protected:
861 MemSpan(super_type const &super) : super_type(super) {}
862};
863
864// -- Implementation --
865
866namespace detail {
868inline size_t
869ptr_distance(void const *first, void const *last) {
870 return static_cast<const char *>(last) - static_cast<const char *>(first);
871}
872
873template <typename T>
874size_t
875ptr_distance(T const *first, T const *last) {
876 return last - first;
877}
878
879inline void *
880ptr_add(void *ptr, size_t count) {
881 return static_cast<char *>(ptr) + count;
882}
883
884inline void const *
885ptr_add(void const *ptr, size_t count) {
886 return static_cast<char const *>(ptr) + count;
887}
888
890
903template <typename T, typename U> struct is_span_compatible {
905 static constexpr bool value = (std::ratio<sizeof(T), sizeof(U)>::num == 1 || std::ratio<sizeof(U), sizeof(T)>::num == 1) &&
906 (std::is_const_v<U> || !std::is_const_v<T>); // can't lose constancy.
915 static size_t count(size_t size);
916};
917
918template <typename T, typename U>
919size_t
921 if (size % sizeof(U)) {
922 throw std::invalid_argument("MemSpan rebind where span size is not a multiple of the element size");
923 }
924 return size / sizeof(U);
925}
926
928// Must specialize for rebinding to @c void because @c sizeof doesn't work. Rebinding from @c void
929// is handled by the @c MemSpan<void>::rebind specialization and doesn't use this mechanism.
930template <typename T> struct is_span_compatible<T, void> {
931 static constexpr bool value = !std::is_const_v<T>;
932 static size_t count(size_t size);
933};
934
935template <typename T>
936size_t
937is_span_compatible<T, void>::count(size_t size) {
938 return sizeof(T) * size;
939}
940
941template <typename T> struct is_span_compatible<T, void const> {
942 static constexpr bool value = true;
943 static size_t count(size_t size);
944};
945
946template <typename T>
947size_t
948is_span_compatible<T, void const>::count(size_t size) {
949 return sizeof(T) * size;
950}
952
953} // namespace detail
954
955// --- Standard memory operations ---
956template class MemSpan<unsigned char>;
957
958template <typename T>
959int
960memcmp(MemSpan<T> const &lhs, MemSpan<T> const &rhs) {
961 int zret = 0;
962 size_t n = lhs.size();
963
964 // Seems a bit ugly but size comparisons must be done anyway to get the memcmp args.
965 if (lhs.count() < rhs.count()) {
966 zret = 1;
967 } else if (lhs.count() > rhs.count()) {
968 zret = -1;
969 n = rhs.size();
970 }
971 // else the counts are equal therefore @a n and @a zret are already correct.
972
973 int r = std::memcmp(lhs.data(), rhs.data(), n);
974 if (0 != r) { // If we got a not-equal, override the size based result.
975 zret = r;
976 }
977
978 return zret;
979}
980
981using std::memcmp;
982
983template <typename T>
984T *
985memcpy(MemSpan<T> &dst, MemSpan<T> const &src) {
986 return static_cast<T *>(std::memcpy(dst.data(), src.data(), std::min(dst.size(), src.size())));
987}
988
989template <typename T>
990T *
991memcpy(MemSpan<T> &dst, T *src) {
992 return static_cast<T *>(std::memcpy(dst.data(), src, dst.size()));
993}
994
995template <typename T>
996T *
997memcpy(T *dst, MemSpan<T> &src) {
998 return static_cast<T *>(std::memcpy(dst, src.data(), src.size()));
999}
1000
1001inline char *
1002memcpy(MemSpan<char> &span, std::string_view view) {
1003 return static_cast<char *>(std::memcpy(span.data(), view.data(), std::min(view.size(), view.size())));
1004}
1005
1006inline void *
1007memcpy(MemSpan<void> &span, std::string_view view) {
1008 return std::memcpy(span.data(), view.data(), std::min(view.size(), view.size()));
1009}
1010
1011using std::memcpy;
1012
1020template <typename T>
1021inline MemSpan<T> const &
1022memset(MemSpan<T> const &dst, T const &value) {
1023 for (auto &e : dst) {
1024 e = value;
1025 }
1026 return dst;
1027}
1028
1030
1042template <typename D, typename S>
1043auto
1044memset(MemSpan<D> const &dst, S c)
1045 -> std::enable_if_t<sizeof(D) == 1 && sizeof(S) == 1 && std::is_convertible_v<S, D>, MemSpan<D>> {
1046 D d = c;
1047 std::memset(dst.data(), d, dst.size());
1048 return dst;
1049}
1050
1051// Optimization for @c char.
1052inline MemSpan<void> const &
1053memset(MemSpan<void> const &dst, char c) {
1054 std::memset(dst.data(), c, dst.size());
1055 return dst;
1056}
1057
1059
1060using std::memset;
1061
1062// --- MemSpan<T> ---
1063
1064template <typename T> constexpr MemSpan<T>::MemSpan(T *ptr, size_t count) : _ptr{ptr}, _count{count} {}
1065
1066template <typename T> constexpr MemSpan<T>::MemSpan(T *begin, T *end) : _ptr{begin}, _count{detail::ptr_distance(begin, end)} {}
1067
1068template <typename T> template <auto N> constexpr MemSpan<T>::MemSpan(T (&a)[N]) : _ptr{a}, _count{N} {
1069 // Magic for string literals to drop the trailing nul terminator, which is almost always what is expected.
1070 if constexpr (N > 0 && std::is_same_v<char const, T>) {
1071 if (a[N - 1] == 0) {
1072 _count -= 1;
1073 }
1074 }
1075}
1076
1077template <typename T> constexpr MemSpan<T>::MemSpan(std::nullptr_t) {}
1078
1079template <typename T>
1080template <auto N, typename U, typename META>
1081constexpr MemSpan<T>::MemSpan(std::array<U, N> const &a) : _ptr{a.data()}, _count{a.size()} {}
1082template <typename T> template <auto N> constexpr MemSpan<T>::MemSpan(std::array<T, N> &a) : _ptr{a.data()}, _count{a.size()} {}
1083template <typename T> template <typename C, typename> constexpr MemSpan<T>::MemSpan(C &c) : _ptr(c.data()), _count(c.size()) {}
1084template <typename T>
1085template <typename C, typename>
1086constexpr MemSpan<T>::MemSpan(C const &c) : _ptr(c.data()), _count(c.size()) {}
1087
1088template <typename T>
1089MemSpan<T> &
1090MemSpan<T>::assign(T *ptr, size_t count) {
1091 _ptr = ptr;
1092 _count = count;
1093 return *this;
1094}
1095
1096template <typename T>
1097MemSpan<T> &
1099 _ptr = first;
1100 _count = detail::ptr_distance(first, last);
1101 return *this;
1102}
1103
1104template <typename T>
1105MemSpan<T> &
1107 _ptr = nullptr;
1108 _count = 0;
1109 return *this;
1110}
1111
1112template <typename T>
1113bool
1114MemSpan<T>::is_same(self_type const &that) const {
1115 return _ptr == that._ptr && _count == that._count;
1116}
1117
1118template <typename T>
1119constexpr bool
1120MemSpan<T>::operator==(self_type const &that) const {
1121 return _count == that._count && (_ptr == that._ptr || 0 == memcmp(_ptr, that._ptr, this->size()));
1122}
1123
1124template <typename T>
1125constexpr bool
1126MemSpan<T>::operator!=(self_type const &that) const {
1127 return !(*this == that);
1128}
1129
1130template <typename T>
1131bool
1133 return _count == 0;
1134}
1135
1136template <typename T> MemSpan<T>::operator bool() const {
1137 return _count != 0;
1138}
1139
1140template <typename T>
1141constexpr bool
1143 return _count == 0;
1144}
1145
1146template <typename T>
1147constexpr T *
1149 return _ptr;
1150}
1151
1152template <typename T>
1153T *
1155 return _ptr;
1156}
1157
1158template <typename T>
1159constexpr T *
1161 return _ptr + _count;
1162}
1163
1164template <typename T>
1165constexpr T *
1167 return _ptr + _count;
1168}
1169
1170template <typename T>
1171T &
1172MemSpan<T>::operator[](size_t idx) const {
1173 return _ptr[idx];
1174}
1175
1176template <typename T>
1177constexpr size_t
1179 return _count;
1180}
1181
1182template <typename T>
1183constexpr size_t
1185 return _count;
1186}
1187
1188template <typename T>
1189constexpr size_t
1191 return _count;
1192}
1193
1194template <typename T>
1195constexpr size_t
1197 return _count * sizeof(T);
1198}
1199
1200template <typename T>
1201bool
1202MemSpan<T>::contains(T const *ptr) const {
1203 return _ptr <= ptr && ptr < _ptr + _count;
1204}
1205
1206template <typename T>
1207constexpr auto
1208MemSpan<T>::prefix(size_t count) const -> self_type {
1209 return {_ptr, std::min(count, _count)};
1210}
1211
1212template <typename T>
1213constexpr auto
1214MemSpan<T>::first(size_t count) const -> self_type {
1215 return this->prefix(count);
1216}
1217
1218template <typename T>
1219auto
1220MemSpan<T>::remove_prefix(size_t count) -> self_type & {
1221 count = std::min(_count, count);
1222 _count -= count;
1223 _ptr += count;
1224 return *this;
1225}
1226
1227template <typename T>
1228constexpr auto
1229MemSpan<T>::suffix(size_t count) const -> self_type {
1230 count = std::min(_count, count);
1231 return {(_ptr + _count) - count, count};
1232}
1233
1234template <typename T>
1235constexpr MemSpan<T>
1237 return this->suffix(count);
1238}
1239
1240template <typename T>
1241MemSpan<T> &
1243 _count -= std::min(count, _count);
1244 return *this;
1245}
1246
1247template <typename T>
1248auto
1249MemSpan<T>::clip_prefix(size_t count) -> self_type {
1250 if (count >= _count) {
1251 auto zret = *this;
1252 _count = 0;
1253 return zret;
1254 }
1255 self_type zret{_ptr, count};
1256 _ptr += count;
1257 _count -= count;
1258 return zret;
1259}
1260
1261template <typename T>
1262auto
1263MemSpan<T>::clip_suffix(size_t count) -> self_type {
1264 if (count >= _count) {
1265 auto zret = *this;
1266 _count = 0;
1267 return zret;
1268 }
1269 _count -= count;
1270 return {_ptr + _count, count};
1271}
1272
1273template <typename T>
1274constexpr MemSpan<T>
1275MemSpan<T>::subspan(size_t offset, size_t count) const {
1276 return offset < _count ? self_type{this->data() + offset, std::min(count, _count - offset)} : self_type{};
1277}
1278
1279template <typename T>
1280T &
1282 return *_ptr;
1283}
1284
1285template <typename T>
1286T &
1288 return _ptr[_count - 1];
1289}
1290
1291template <typename T>
1292template <typename F>
1293typename MemSpan<T>::self_type &
1295 for (auto &item : *this) {
1296 f(item);
1297 }
1298 return *this;
1299}
1300
1301template <typename T>
1302template <typename U>
1305 static_assert(
1307 "MemSpan only allows rebinding between types where the sizes are such that one is an integral multiple of the other.");
1308 using VOID_PTR = std::conditional_t<std::is_const_v<U>, const void *, void *>;
1309 return {static_cast<U *>(static_cast<VOID_PTR>(_ptr)), detail::is_span_compatible<T, U>::count(this->data_size())};
1310}
1311
1312template <typename T>
1313template <typename... Args>
1314auto
1315MemSpan<T>::make(Args &&...args) -> self_type & {
1316 for (T *elt = this->data(), *limit = this->data_end(); elt < limit; ++elt) {
1317 new (elt) T(std::forward<Args>(args)...);
1318 }
1319 return *this;
1320}
1321
1322template <typename T>
1323void
1325 for (T *elt = this->data(), *limit = this->data_end(); elt < limit; ++elt) {
1326 std::destroy_at(elt);
1327 }
1328}
1329
1330// --- void specializations ---
1331
1332template <typename U>
1333constexpr MemSpan<void const>::MemSpan(MemSpan<U> const &that)
1334 : _ptr(const_cast<std::remove_const_t<U> *>(that._ptr)), _size(sizeof(U) * that.size()) {}
1335template <typename U> constexpr MemSpan<void>::MemSpan(MemSpan<U> const &that) : super_type(that) {
1336 static_assert(!std::is_const_v<U>, "MemSpan<void> does not support constant memory.");
1337}
1338
1339inline constexpr MemSpan<void const>::MemSpan(MemSpan<void> const &that) : _ptr(that._ptr), _size(that.size()) {}
1340
1341inline constexpr MemSpan<void const>::MemSpan(value_type *ptr, size_t n) : _ptr{const_cast<void *>(ptr)}, _size{n} {}
1342inline constexpr MemSpan<void>::MemSpan(value_type *ptr, size_t n) : super_type(ptr, n) {}
1343
1344inline MemSpan<void const>::MemSpan(value_type *begin, value_type *end)
1345 : _ptr{const_cast<void *>(begin)}, _size{detail::ptr_distance(begin, end)} {}
1346inline MemSpan<void>::MemSpan(value_type *begin, value_type *end) : super_type(begin, end) {}
1347
1348template <auto N, typename U>
1349constexpr MemSpan<void const>::MemSpan(U (&a)[N]) : _ptr(const_cast<std::remove_const_t<U> *>(a)), _size(N * sizeof(U)) {
1350 // Magic for string literals to drop the trailing nul terminator, which is almost always what is expected.
1351 if constexpr (N > 0 && std::is_same_v<char const, U>) {
1352 if (a[N - 1] == 0) {
1353 _size -= 1;
1354 }
1355 }
1356}
1357template <auto N, typename U> constexpr MemSpan<void>::MemSpan(U (&a)[N]) : super_type(a) {
1358 static_assert(!std::is_const_v<U>, "Error: constructing non-constant view with constant data.");
1359}
1360
1361template <typename C, typename>
1362constexpr MemSpan<void const>::MemSpan(C const &c)
1363 : _ptr(const_cast<std::remove_const_t<std::remove_reference_t<decltype(*(std::declval<C>().data()))>> *>(c.data())),
1364 _size(c.size() * sizeof(*(std::declval<C>().data()))) {}
1365template <typename C, typename> constexpr MemSpan<void>::MemSpan(C const &c) : super_type(c) {}
1366
1367inline constexpr MemSpan<void const>::MemSpan(std::nullptr_t) {}
1368inline constexpr MemSpan<void>::MemSpan(std::nullptr_t) {}
1369
1370inline bool
1371MemSpan<void const>::is_same(self_type const &that) const {
1372 return _ptr == that._ptr && _size == that._size;
1373}
1374
1375inline bool
1376MemSpan<void const>::operator==(self_type const &that) const {
1377 return _size == that._size && (_ptr == that._ptr || 0 == memcmp(_ptr, that._ptr, _size));
1378}
1379
1380inline bool
1381MemSpan<void const>::operator!=(self_type const &that) const {
1382 return !(*this == that);
1383}
1384
1385inline MemSpan<void const>::operator bool() const {
1386 return _size != 0;
1387}
1388
1389inline bool
1391 return _size == 0;
1392}
1393
1394inline constexpr bool
1396 return _size == 0;
1397}
1398
1399template <typename U>
1400auto
1401MemSpan<void const>::operator=(MemSpan<U> const &that) -> self_type & {
1402 _ptr = that._ptr;
1403 _size = sizeof(U) * that.size();
1404 return *this;
1405}
1406
1407inline constexpr auto
1408MemSpan<void const>::operator=(MemSpan<void> const &that) -> self_type & {
1409 _ptr = that._ptr;
1410 _size = that.size();
1411 return *this;
1412}
1413
1414template <typename U>
1415auto
1416MemSpan<void>::operator=(MemSpan<U> const &that) -> self_type & {
1417 static_assert(!std::is_const_v<U>, "Cannot assign constant pointer to MemSpan<void>");
1418 this->super_type::operator=(that);
1419 return *this;
1420}
1421
1422inline auto
1423MemSpan<void const>::assign(value_type *ptr, size_t n) -> self_type & {
1424 _ptr = const_cast<void *>(ptr);
1425 _size = n;
1426 return *this;
1427}
1428
1429inline auto
1430MemSpan<void>::assign(value_type *ptr, size_t n) -> self_type & {
1431 super_type::assign(ptr, n);
1432 return *this;
1433}
1434
1435inline auto
1436MemSpan<void const>::assign(value_type *first, value_type const *last) -> self_type & {
1437 _ptr = const_cast<void *>(first);
1438 _size = detail::ptr_distance(first, last);
1439 return *this;
1440}
1441
1442inline auto
1443MemSpan<void>::assign(value_type *first, value_type const *last) -> self_type & {
1445 return *this;
1446}
1447
1448inline auto
1449MemSpan<void const>::clear() -> self_type & {
1450 _ptr = nullptr;
1451 _size = 0;
1452 return *this;
1453}
1454
1455inline auto
1456MemSpan<void>::clear() -> self_type & {
1458 return *this;
1459}
1460
1461inline constexpr void const *
1463 return _ptr;
1464}
1465
1466inline constexpr void *
1468 return _ptr;
1469}
1470
1471inline void const *
1473 return detail::ptr_add(_ptr, _size);
1474}
1475
1476inline void *
1478 return detail::ptr_add(_ptr, _size);
1479}
1480
1481inline constexpr size_t
1483 return _size;
1484}
1485
1486inline constexpr size_t
1488 return _size;
1489}
1490
1491inline constexpr size_t
1493 return _size;
1494}
1495
1496inline constexpr size_t
1498 return _size;
1499}
1500
1501inline bool
1502MemSpan<void const>::contains(value_type const *ptr) const {
1503 return _ptr <= ptr && ptr < this->data_end();
1504}
1505
1506inline auto
1507MemSpan<void const>::prefix(size_t n) const -> self_type {
1508 return {_ptr, std::min(n, _size)};
1509}
1510
1511inline auto
1512MemSpan<void>::prefix(size_t n) const -> self_type {
1513 return {_ptr, std::min(n, _size)};
1514}
1515
1516inline auto
1517MemSpan<void const>::remove_prefix(size_t n) -> self_type & {
1518 n = std::min(_size, n);
1519 _size -= n;
1520 _ptr = detail::ptr_add(_ptr, n);
1521 return *this;
1522}
1523
1524inline auto
1525MemSpan<void>::remove_prefix(size_t n) -> self_type & {
1527 return *this;
1528}
1529
1530inline auto
1531MemSpan<void const>::suffix(size_t n) const -> self_type {
1532 n = std::min(n, _size);
1533 return {detail::ptr_add(this->data_end(), -n), n};
1534}
1535
1536inline auto
1537MemSpan<void>::suffix(size_t n) const -> self_type {
1538 n = std::min(n, _size);
1539 return {detail::ptr_add(this->data_end(), -n), n};
1540}
1541
1542inline auto
1543MemSpan<void const>::remove_suffix(size_t n) -> self_type & {
1544 _size -= std::min(n, _size);
1545 return *this;
1546}
1547
1548inline auto
1549MemSpan<void>::remove_suffix(size_t n) -> self_type & {
1551 return *this;
1552}
1553
1554inline auto
1555MemSpan<void const>::clip_prefix(size_t n) -> self_type {
1556 if (n >= _size) {
1557 auto zret = *this;
1558 _size = 0;
1559 return zret;
1560 }
1561 self_type zret{_ptr, n};
1562 _ptr = detail::ptr_add(_ptr, n);
1563 _size -= n;
1564 return zret;
1565}
1566
1567inline auto
1568MemSpan<void>::clip_prefix(size_t n) -> self_type {
1569 return super_type::clip_prefix(n);
1570}
1571
1572inline auto
1573MemSpan<void const>::clip_suffix(size_t n) -> self_type {
1574 if (n >= _size) {
1575 auto zret = *this;
1576 _size = 0;
1577 return zret;
1578 }
1579 _size -= n;
1580 return {detail::ptr_add(_ptr, _size), n};
1581}
1582
1583inline auto
1584MemSpan<void>::clip_suffix(size_t n) -> self_type {
1585 return super_type::clip_suffix(n);
1586}
1587
1588inline constexpr auto
1589MemSpan<void const>::subspan(size_t offset, size_t n) const -> self_type {
1590 return offset <= _size ? self_type{detail::ptr_add(this->data(), offset), std::min(n, _size - offset)} : self_type{};
1591}
1592
1593inline constexpr auto
1594MemSpan<void>::subspan(size_t offset, size_t n) const -> self_type {
1595 return offset <= _size ? self_type{detail::ptr_add(this->data(), offset), std::min(n, _size - offset)} : self_type{};
1596}
1597
1598template <typename T> constexpr auto MemSpan<T>::restrict(size_t n) -> self_type & {
1599 _count = std::min(_count, n);
1600 return *this;
1601}
1602
1603template <typename T>
1604auto
1605MemSpan<void const>::align() const -> self_type {
1606 return this->align(alignof(T), sizeof(T));
1607}
1608
1609template <typename T>
1610auto
1611MemSpan<void>::align() const -> self_type {
1612 return this->align(alignof(T), sizeof(T));
1613}
1614
1615inline auto
1616MemSpan<void const>::align(size_t alignment) const -> self_type {
1617 auto p = uintptr_t(_ptr);
1618 auto padding = p & (alignment - 1);
1619 size_t size = 0;
1620 if (_size > padding) { // if there's not enough to pad, result is zero size.
1621 size = _size - padding;
1622 }
1623 return {reinterpret_cast<void *>(p + padding), size};
1624}
1625
1626inline auto
1627MemSpan<void>::align(size_t alignment) const -> self_type {
1628 auto &&[ptr, size] = super_type::align(alignment);
1629 return {ptr, size};
1630}
1631
1632inline auto
1633MemSpan<void const>::align(size_t alignment, size_t obj_size) const -> self_type {
1634 auto p = uintptr_t(_ptr);
1635 auto padding = p & (alignment - 1);
1636 size_t size = 0;
1637 if (_size > padding) { // if there's not enough to pad, result is zero size.
1638 size = ((_size - padding) / obj_size) * obj_size;
1639 }
1640 return {reinterpret_cast<void *>(p + padding), size};
1641}
1642
1643inline auto
1644MemSpan<void>::align(size_t alignment, size_t obj_size) const -> self_type {
1645 auto &&[ptr, n] = super_type::align(alignment, obj_size);
1646 return {ptr, n};
1647}
1648
1649template <typename U>
1652 static_assert(std::is_const_v<U>, "Cannot rebind MemSpan<const void> to non-const type.");
1653 return {static_cast<U *>(_ptr), detail::is_span_compatible<value_type, U>::count(_size)};
1654}
1655
1656template <typename U>
1659 return {static_cast<U *>(_ptr), detail::is_span_compatible<value_type, U>::count(_size)};
1660}
1661
1662// Specialize so that @c void -> @c void rebinding compiles and works as expected.
1663template <>
1664inline auto
1665MemSpan<void const>::rebind() const -> self_type {
1666 return *this;
1667}
1668
1669template <>
1670inline auto
1671MemSpan<void>::rebind() const -> self_type {
1672 return *this;
1673}
1674
1675template <>
1676inline auto
1677MemSpan<void>::rebind() const -> MemSpan<void const> {
1678 return {_ptr, _size};
1679}
1680
1681template <typename U>
1682U *
1683MemSpan<void>::as_ptr() const {
1684 if (_size != sizeof(U)) {
1685 throw std::invalid_argument("MemSpan::as size is not compatible with target type.");
1686 }
1687 return static_cast<U *>(_ptr);
1688}
1689
1690template <typename U>
1691U const *
1693 if (_size != sizeof(U)) {
1694 throw std::invalid_argument("MemSpan::as size is not compatible with target type.");
1695 }
1696 return static_cast<U const *>(_ptr);
1697}
1698
1700template <typename T, size_t N> MemSpan(std::array<T, N> &) -> MemSpan<T>;
1701template <typename T, size_t N> MemSpan(std::array<T, N> const &) -> MemSpan<T const>;
1702template <size_t N> MemSpan(char (&)[N]) -> MemSpan<char>;
1703template <size_t N> MemSpan(char const (&)[N]) -> MemSpan<char const>;
1704template <typename T> MemSpan(std::vector<T> &) -> MemSpan<T>;
1705template <typename T> MemSpan(std::vector<T> const &) -> MemSpan<T const>;
1706MemSpan(std::string_view const &) -> MemSpan<char const>;
1707MemSpan(std::string &) -> MemSpan<char>;
1708MemSpan(std::string const &) -> MemSpan<char const>;
1709
1710namespace detail {
1712 void
1713 operator()(void *ptr) {
1714 ::free(ptr);
1715 }
1716};
1717} // namespace detail.
1718
1720template <typename T> using unique_malloc = std::unique_ptr<T, detail::malloc_liberator>;
1721}} // namespace swoc::SWOC_VERSION_NS
1722
1724// STL tuple support - this allows the @c MemSpan to be used as a tuple of a pointer
1725// and size.
1726namespace std {
1727template <size_t IDX, typename R> class tuple_element<IDX, swoc::MemSpan<R>> {
1728 static_assert("swoc::MemSpan tuple index out of range");
1729};
1730
1731template <typename R> class tuple_element<0, swoc::MemSpan<R>> {
1732public:
1733 using type = R *;
1734};
1735
1736template <typename R> class tuple_element<1, swoc::MemSpan<R>> {
1737public:
1738 using type = size_t;
1739};
1740
1741template <typename R> class tuple_size<swoc::MemSpan<R>> : public std::integral_constant<size_t, 2> {};
1742
1743} // namespace std
1744
constexpr self_type & operator=(self_type const &that)=default
Copy assignment.
constexpr value_type * data() const
Pointer to memory in the span.
Definition MemSpan.h:1467
self_type clip_suffix(size_t n)
Definition MemSpan.h:1584
self_type & clear()
Clear the span (become an empty span).
Definition MemSpan.h:1456
MemSpan< U > rebind() const
Definition MemSpan.h:1658
self_type & assign(value_type *ptr, size_t n)
Definition MemSpan.h:1430
self_type & operator=(MemSpan< U > const &that)
self_type & remove_suffix(size_t n)
Definition MemSpan.h:1549
constexpr self_type subspan(size_t offset, size_t n) const
Definition MemSpan.h:1594
self_type suffix(size_t n) const
Definition MemSpan.h:1537
self_type align() const
self_type clip_prefix(size_t n)
Definition MemSpan.h:1568
self_type prefix(size_t n) const
Definition MemSpan.h:1512
MemSpan(super_type const &super)
Definition MemSpan.h:861
value_type * data_end() const
Pointer to just after memory in the span.
Definition MemSpan.h:1477
constexpr MemSpan(self_type const &that)=default
Copy constructor.
self_type & remove_prefix(size_t count)
Definition MemSpan.h:1525
constexpr MemSpan()=default
Default constructor (empty buffer).
U * as_ptr() const
Definition MemSpan.h:1683
constexpr self_type & restrict(size_t n)
Definition MemSpan.h:1598
self_type clip_suffix(size_t count)
Definition MemSpan.h:1263
constexpr MemSpan(std::array< T, N > &a)
Definition MemSpan.h:1082
constexpr MemSpan(std::nullptr_t)
Definition MemSpan.h:1077
constexpr size_t data_size() const
Number of bytes in the span.
Definition MemSpan.h:1196
constexpr MemSpan(MemSpan< U > const &that)
Definition MemSpan.h:120
self_type & assign(T *ptr, size_t count)
Definition MemSpan.h:1090
constexpr self_type suffix(size_t count) const
Definition MemSpan.h:1229
constexpr self_type prefix(size_t count) const
Definition MemSpan.h:1208
constexpr size_t count() const
T const * const_iterator
Constant iterator.
Definition MemSpan.h:60
bool is_same(self_type const &that) const
Definition MemSpan.h:1114
self_type & remove_suffix(size_t count)
Definition MemSpan.h:1242
constexpr MemSpan()=default
Default constructor (empty buffer).
T & operator[](size_t idx) const
Access element at index idx.
Definition MemSpan.h:1172
T value_type
Element type for span.
Definition MemSpan.h:58
constexpr MemSpan(C &c)
Definition MemSpan.h:1083
constexpr MemSpan(T(&a)[N])
Definition MemSpan.h:1068
self_type & assign(T *first, T const *last)
Definition MemSpan.h:1098
T * iterator
Iterator.
Definition MemSpan.h:59
constexpr bool operator==(self_type const &that) const
Definition MemSpan.h:1120
constexpr size_t length() const
Number of elements in the span.
Definition MemSpan.h:1190
constexpr bool operator!=(self_type const &that) const
Definition MemSpan.h:1126
self_type & make(Args &&...args)
self_type clip_prefix(size_t count)
Definition MemSpan.h:1249
constexpr T * data_end() const
Definition MemSpan.h:1160
self_type & operator=(self_type const &that)=default
Assignment - the span is copied, not the content.
Definition MemSpan.h:1401
self_type & apply(F &&f)
Definition MemSpan.h:1294
constexpr bool empty() const
Definition MemSpan.h:1142
void destroy()
Destruct all elements in the span.
Definition MemSpan.h:1324
constexpr T * begin() const
constexpr self_type first(size_t count) const
constexpr T * end() const
MemSpan< U > rebind() const
Definition MemSpan.h:1304
constexpr size_t size() const
Number of elements in the span.
Definition MemSpan.h:1178
constexpr self_type subspan(size_t offset, size_t count) const
Definition MemSpan.h:1275
self_type & remove_prefix(size_t count)
Definition MemSpan.h:1220
constexpr self_type last(size_t count) const
bool operator!() const
Definition MemSpan.h:1132
constexpr MemSpan(C const &c)
Definition MemSpan.h:1086
self_type & clear()
Clear the span (become an empty span).
Definition MemSpan.h:1106
bool contains(value_type const *p) const
Definition MemSpan.h:1202
constexpr MemSpan(value_type *begin, value_type *end)
Definition MemSpan.h:1066
constexpr MemSpan(std::array< U, N > const &a)
Definition MemSpan.h:1081
constexpr MemSpan(self_type &that)=default
Copy constructor.
constexpr MemSpan(self_type const &that)=default
Copy constructor.
constexpr MemSpan(value_type *ptr, size_t count)
Definition MemSpan.h:1064
STL namespace.
For template deduction guides.
Definition ArenaWriter.cc:9
MemSpan(std::array< T, N > &) -> MemSpan< T >
Deduction guides.
std::unique_ptr< T, detail::malloc_liberator > unique_malloc
A variant of unique_ptr that handles memory from malloc.
Definition MemSpan.h:1720
bool operator==(IPAddr const &lhs, sockaddr const *sa)
Equality.
Definition swoc_ip.cc:650
MemSpan< T > const & memset(MemSpan< T > const &dst, T const &value)
Definition MemSpan.h:1022
bool operator!=(IP4Addr const &lhs, IP4Addr const &rhs)
Definition IPAddr.h:845
int memcmp(std::string_view const &lhs, std::string_view const &rhs)
void * memcpy(void *dst, const std::string_view &src)
static size_t count(size_t size)
Definition MemSpan.h:920
static constexpr bool value
true if the size of T is an integral multiple of the size of U or vice versa.
Definition MemSpan.h:905