27namespace swoc {
inline namespace SWOC_VERSION_NS {
50template <
typename T>
class MemSpan {
51 using self_type = MemSpan;
66 constexpr MemSpan(self_type
const &that) =
default;
68 constexpr MemSpan(self_type &that) =
default;
89 template <auto N>
constexpr MemSpan(T (&a)[N]);
98 template <
auto N,
typename U,
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>>>>>
108 template <auto N>
constexpr MemSpan(std::array<T, N> &a);
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>>>>>
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>,
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>,
195 explicit operator bool()
const;
246 template <
typename F> self_type &
apply(F &&f);
256 template <
typename U = std::conditional_t<std::is_const_v<T>,
void const,
void>> MemSpan<U>
rebind()
const;
367 template <
typename... Args> self_type &
make(Args &&...args);
372 template <
typename U>
friend class MemSpan;
387template <>
class MemSpan<void const> {
389 template <
typename U>
friend class MemSpan;
392 using value_type =
void const;
395 void *_ptr =
nullptr;
403 constexpr MemSpan(self_type
const &that) =
default;
406 constexpr self_type &operator=(self_type
const &that) =
default;
413 template <auto N,
typename U>
constexpr MemSpan(U (&a)[N]);
433 constexpr MemSpan(value_type *ptr,
size_t n);
440 MemSpan(value_type *begin, value_type *end);
450 template <typename C, typename = std::enable_if_t<std::is_convertible_v<decltype(std::declval<C>().size()),
size_t>,
void>>
456 constexpr MemSpan(std::nullptr_t);
473 bool is_same(self_type
const &that)
const;
483 explicit operator bool()
const;
487 bool operator!()
const;
491 constexpr bool empty()
const;
494 constexpr size_t size()
const;
498 constexpr size_t count()
const;
502 constexpr size_t length()
const;
505 constexpr size_t data_size()
const;
508 constexpr value_type *data()
const;
511 value_type *data_end()
const;
518 template <
typename U> self_type &operator=(
MemSpan<U> const &that);
526 self_type &assign(value_type *ptr,
size_t n);
534 self_type &assign(value_type *first, value_type
const *last);
541 template <
typename U>
MemSpan<U> rebind()
const;
550 template <
typename U> U
const *as_ptr()
const;
556 bool contains(
void const *ptr)
const;
562 self_type prefix(
size_t n)
const;
569 self_type &remove_prefix(
size_t n);
578 self_type clip_prefix(
size_t n);
585 self_type suffix(
size_t n)
const;
592 self_type &remove_suffix(
size_t n);
601 self_type clip_suffix(
size_t n);
613 constexpr self_type subspan(
size_t offset,
size_t n)
const;
623 template <
typename T> self_type align()
const;
633 self_type align(
size_t alignment)
const;
647 self_type align(
size_t alignment,
size_t obj_size)
const;
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;
656 using value_type = void;
657 using pointer_type = value_type *;
663 constexpr MemSpan(self_type
const &that) =
default;
666 constexpr self_type &
operator=(self_type
const &that) =
default;
676 template <
typename U>
constexpr MemSpan(MemSpan<U>
const &that);
683 constexpr MemSpan(value_type *start,
size_t n);
690 MemSpan(value_type *
begin, value_type *
end);
698 template <auto N,
typename U>
constexpr MemSpan(U (&a)[N]);
703 constexpr MemSpan(std::nullptr_t);
706 constexpr value_type *
data()
const;
713 template <
typename U> self_type &
operator=(MemSpan<U>
const &that);
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>,
726 constexpr MemSpan(C
const &c);
734 self_type &
assign(value_type *ptr,
size_t n);
745 self_type
prefix(
size_t n)
const;
768 self_type
suffix(
size_t n)
const;
796 constexpr self_type
subspan(
size_t offset,
size_t n)
const;
806 template <
typename T> self_type
align()
const;
816 self_type
align(
size_t alignment)
const;
830 self_type
align(
size_t alignment,
size_t obj_size)
const;
837 template <
typename U> MemSpan<U>
rebind()
const;
846 template <
typename U> U *
as_ptr()
const;
861 MemSpan(super_type
const &super) : super_type(super) {}
869ptr_distance(
void const *first,
void const *last) {
870 return static_cast<const char *
>(last) -
static_cast<const char *
>(first);
875ptr_distance(T
const *first, T
const *last) {
880ptr_add(
void *ptr,
size_t count) {
881 return static_cast<char *
>(ptr) + count;
885ptr_add(
void const *ptr,
size_t count) {
886 return static_cast<char const *
>(ptr) + count;
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>);
915 static size_t count(
size_t size);
918template <
typename T,
typename U>
921 if (size %
sizeof(U)) {
922 throw std::invalid_argument(
"MemSpan rebind where span size is not a multiple of the element size");
924 return size /
sizeof(U);
931 static constexpr bool value = !std::is_const_v<T>;
932 static size_t count(
size_t size);
937is_span_compatible<T, void>::count(
size_t size) {
938 return sizeof(T) * size;
941template <
typename T>
struct is_span_compatible<T, void const> {
942 static constexpr bool value =
true;
943 static size_t count(
size_t size);
948is_span_compatible<T, void const>::count(
size_t size) {
949 return sizeof(T) * size;
956template class MemSpan<unsigned char>;
960memcmp(MemSpan<T>
const &lhs, MemSpan<T>
const &rhs) {
962 size_t n = lhs.size();
965 if (lhs.count() < rhs.count()) {
967 }
else if (lhs.count() > rhs.count()) {
973 int r = std::memcmp(lhs.data(), rhs.data(), n);
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())));
991memcpy(MemSpan<T> &dst, T *src) {
992 return static_cast<T *
>(std::memcpy(dst.data(), src, dst.size()));
997memcpy(T *dst, MemSpan<T> &src) {
998 return static_cast<T *
>(std::memcpy(dst, src.data(), src.size()));
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())));
1007memcpy(MemSpan<void> &span, std::string_view view) {
1008 return std::memcpy(span.data(), view.data(), std::min(view.size(), view.size()));
1020template <
typename T>
1021inline MemSpan<T>
const &
1023 for (
auto &e : dst) {
1042template <
typename D,
typename S>
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>> {
1047 std::memset(dst.data(), d, dst.size());
1052inline MemSpan<void>
const &
1053memset(MemSpan<void>
const &dst,
char c) {
1054 std::memset(dst.data(), c, dst.size());
1068template <
typename T>
template <auto N>
constexpr MemSpan<T>::MemSpan(T (&a)[N]) :
_ptr{a},
_count{N} {
1070 if constexpr (N > 0 && std::is_same_v<char const, T>) {
1071 if (a[N - 1] == 0) {
1077template <
typename T>
constexpr MemSpan<T>::MemSpan(std::nullptr_t) {}
1079template <
typename T>
1080template <auto N,
typename U,
typename META>
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>
1088template <
typename T>
1096template <
typename T>
1104template <
typename T>
1112template <
typename T>
1118template <
typename T>
1124template <
typename T>
1127 return !(*
this == that);
1130template <
typename T>
1136template <
typename T> MemSpan<T>::operator bool()
const {
1140template <
typename T>
1146template <
typename T>
1152template <
typename T>
1158template <
typename T>
1164template <
typename T>
1170template <
typename T>
1176template <
typename T>
1182template <
typename T>
1188template <
typename T>
1194template <
typename T>
1197 return _count *
sizeof(T);
1200template <
typename T>
1206template <
typename T>
1212template <
typename T>
1218template <
typename T>
1227template <
typename T>
1234template <
typename T>
1240template <
typename T>
1247template <
typename T>
1261template <
typename T>
1273template <
typename T>
1276 return offset <
_count ? self_type{this->
data() + offset, std::min(
count,
_count - offset)} : self_type{};
1279template <
typename T>
1285template <
typename T>
1291template <
typename T>
1292template <
typename F>
1293typename MemSpan<T>::self_type &
1295 for (
auto &item : *
this) {
1301template <
typename T>
1302template <
typename U>
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 *>;
1312template <
typename T>
1313template <
typename... Args>
1316 for (T *elt = this->data(), *limit = this->data_end(); elt < limit; ++elt) {
1317 new (elt) T(std::forward<Args>(args)...);
1322template <
typename T>
1325 for (T *elt = this->
data(), *limit = this->
data_end(); elt < limit; ++elt) {
1326 std::destroy_at(elt);
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.");
1339inline constexpr MemSpan<void const>::MemSpan(
MemSpan<void> const &that) : _ptr(that._ptr), _size(that.size()) {}
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) {}
1344inline MemSpan<void const>::MemSpan(value_type *begin, value_type *end)
1345 : _ptr{const_cast<void *>(begin)}, _size{detail::ptr_distance(begin, end)} {}
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)) {
1351 if constexpr (N > 0 && std::is_same_v<char const, U>) {
1352 if (a[N - 1] == 0) {
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.");
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) {}
1367inline constexpr MemSpan<void const>::MemSpan(std::nullptr_t) {}
1368inline constexpr MemSpan<void>::MemSpan(std::nullptr_t) {}
1372 return _ptr == that._ptr && _size == that._size;
1377 return _size == that._size && (_ptr == that._ptr || 0 ==
memcmp(_ptr, that._ptr, _size));
1382 return !(*
this == that);
1394inline constexpr bool
1399template <
typename U>
1403 _size =
sizeof(U) * that.size();
1407inline constexpr auto
1410 _size = that.size();
1414template <
typename U>
1417 static_assert(!std::is_const_v<U>,
"Cannot assign constant pointer to MemSpan<void>");
1418 this->super_type::operator=(that);
1424 _ptr =
const_cast<void *
>(ptr);
1437 _ptr =
const_cast<void *
>(first);
1438 _size = detail::ptr_distance(first, last);
1461inline constexpr void const *
1466inline constexpr void *
1473 return detail::ptr_add(_ptr, _size);
1478 return detail::ptr_add(
_ptr, _size);
1481inline constexpr size_t
1486inline constexpr size_t
1491inline constexpr size_t
1496inline constexpr size_t
1503 return _ptr <= ptr && ptr < this->data_end();
1508 return {_ptr, std::min(n, _size)};
1513 return {
_ptr, std::min(n, _size)};
1518 n = std::min(_size, n);
1520 _ptr = detail::ptr_add(_ptr, n);
1532 n = std::min(n, _size);
1533 return {detail::ptr_add(this->data_end(), -n), n};
1538 n = std::min(n, _size);
1539 return {detail::ptr_add(this->
data_end(), -n), n};
1544 _size -= std::min(n, _size);
1561 self_type zret{_ptr, n};
1562 _ptr = detail::ptr_add(_ptr, n);
1580 return {detail::ptr_add(_ptr, _size), n};
1588inline constexpr auto
1590 return offset <= _size ? self_type{detail::ptr_add(this->data(), offset), std::min(n, _size - offset)} : self_type{};
1593inline constexpr auto
1595 return offset <= _size ? self_type{detail::ptr_add(this->
data(), offset), std::min(n, _size - offset)} : self_type{};
1603template <
typename T>
1606 return this->align(
alignof(T),
sizeof(T));
1609template <
typename T>
1612 return this->align(
alignof(T),
sizeof(T));
1617 auto p = uintptr_t(_ptr);
1618 auto padding = p & (alignment - 1);
1620 if (_size > padding) {
1621 size = _size - padding;
1623 return {
reinterpret_cast<void *
>(p + padding), size};
1627MemSpan<void>::align(
size_t alignment)
const -> self_type {
1628 auto &&[ptr,
size] = super_type::align(alignment);
1634 auto p = uintptr_t(_ptr);
1635 auto padding = p & (alignment - 1);
1637 if (_size > padding) {
1638 size = ((_size - padding) / obj_size) * obj_size;
1640 return {
reinterpret_cast<void *
>(p + padding), size};
1644MemSpan<void>::align(
size_t alignment,
size_t obj_size)
const -> self_type {
1645 auto &&[ptr, n] = super_type::align(alignment, obj_size);
1649template <
typename U>
1652 static_assert(std::is_const_v<U>,
"Cannot rebind MemSpan<const void> to non-const type.");
1656template <
typename U>
1678 return {_ptr, _size};
1681template <
typename U>
1683MemSpan<void>::as_ptr()
const {
1684 if (_size !=
sizeof(U)) {
1685 throw std::invalid_argument(
"MemSpan::as size is not compatible with target type.");
1687 return static_cast<U *
>(
_ptr);
1690template <
typename U>
1693 if (_size !=
sizeof(U)) {
1694 throw std::invalid_argument(
"MemSpan::as size is not compatible with target type.");
1696 return static_cast<U
const *
>(_ptr);
1713 operator()(
void *ptr) {
1720template <
typename T>
using unique_malloc = std::unique_ptr<T, detail::malloc_liberator>;
1727template <
size_t IDX,
typename R>
class tuple_element<IDX, swoc::
MemSpan<R>> {
1728 static_assert(
"swoc::MemSpan tuple index out of range");
1731template <
typename R>
class tuple_element<0, swoc::
MemSpan<R>> {
1736template <
typename R>
class tuple_element<1, swoc::
MemSpan<R>> {
1738 using type = size_t;
1741template <
typename R>
class tuple_size<swoc::
MemSpan<R>> :
public std::integral_constant<size_t, 2> {};
constexpr self_type & operator=(self_type const &that)=default
Copy assignment.
constexpr value_type * data() const
Pointer to memory in the span.
self_type clip_suffix(size_t n)
self_type & clear()
Clear the span (become an empty span).
MemSpan< U > rebind() const
self_type & assign(value_type *ptr, size_t n)
self_type & operator=(MemSpan< U > const &that)
self_type & remove_suffix(size_t n)
constexpr self_type subspan(size_t offset, size_t n) const
self_type suffix(size_t n) const
self_type clip_prefix(size_t n)
self_type prefix(size_t n) const
MemSpan(super_type const &super)
value_type * data_end() const
Pointer to just after memory in the span.
constexpr MemSpan(self_type const &that)=default
Copy constructor.
self_type & remove_prefix(size_t count)
constexpr MemSpan()=default
Default constructor (empty buffer).
constexpr self_type & restrict(size_t n)
self_type clip_suffix(size_t count)
constexpr MemSpan(std::array< T, N > &a)
constexpr MemSpan(std::nullptr_t)
constexpr size_t data_size() const
Number of bytes in the span.
constexpr MemSpan(MemSpan< U > const &that)
self_type & assign(T *ptr, size_t count)
constexpr self_type suffix(size_t count) const
constexpr self_type prefix(size_t count) const
constexpr size_t count() const
T const * const_iterator
Constant iterator.
bool is_same(self_type const &that) const
self_type & remove_suffix(size_t count)
constexpr MemSpan()=default
Default constructor (empty buffer).
T & operator[](size_t idx) const
Access element at index idx.
T value_type
Element type for span.
constexpr MemSpan(T(&a)[N])
self_type & assign(T *first, T const *last)
constexpr bool operator==(self_type const &that) const
constexpr size_t length() const
Number of elements in the span.
constexpr bool operator!=(self_type const &that) const
self_type & make(Args &&...args)
self_type clip_prefix(size_t count)
constexpr T * data_end() const
self_type & operator=(self_type const &that)=default
Assignment - the span is copied, not the content.
constexpr bool empty() const
void destroy()
Destruct all elements in the span.
constexpr T * begin() const
constexpr self_type first(size_t count) const
constexpr T * end() const
MemSpan< U > rebind() const
constexpr size_t size() const
Number of elements in the span.
constexpr self_type subspan(size_t offset, size_t count) const
self_type & remove_prefix(size_t count)
constexpr self_type last(size_t count) const
constexpr MemSpan(C const &c)
self_type & clear()
Clear the span (become an empty span).
bool contains(value_type const *p) const
constexpr MemSpan(value_type *begin, value_type *end)
constexpr MemSpan(std::array< U, N > const &a)
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)
For template deduction guides.
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.
bool operator==(IPAddr const &lhs, sockaddr const *sa)
Equality.
MemSpan< T > const & memset(MemSpan< T > const &dst, T const &value)
bool operator!=(IP4Addr const &lhs, IP4Addr const &rhs)
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)
static constexpr bool value
true if the size of T is an integral multiple of the size of U or vice versa.