26#include "pw_allocator/allocator.h"
27#include "pw_allocator/null_allocator.h"
28#include "pw_bytes/span.h"
29#include "pw_multibuf/v2/chunks.h"
30#include "pw_multibuf/v2/internal/byte_iterator.h"
31#include "pw_multibuf/v2/internal/entry.h"
32#include "pw_multibuf/v2/observer.h"
33#include "pw_multibuf/v2/properties.h"
35namespace pw::multibuf {
95template <
typename OtherMultiBuf,
typename MultiBufType>
96constexpr OtherMultiBuf& ConstCast(
const MultiBufType& mb);
215 using size_type =
typename Deque::size_type;
216 using difference_type =
typename Deque::difference_type;
218 using iterator = std::conditional_t<
222 using pointer =
typename iterator::pointer;
223 using const_pointer = const_iterator::pointer;
224 using reference =
typename iterator::reference;
225 using const_reference = const_iterator::reference;
226 using value_type = std::conditional_t<
is_const(),
227 const_iterator::value_type,
228 typename iterator::value_type>;
255 template <
Property... kOtherProperties>
257 InvalidCopyOrMove<>();
260 BasicMultiBuf& operator=(
const BasicMultiBuf&) { InvalidCopyOrMove<>(); }
262 template <
Property... kOtherProperties>
263 BasicMultiBuf& operator=(
const BasicMultiBuf<kOtherProperties...>&) {
264 InvalidCopyOrMove<>();
267 BasicMultiBuf(BasicMultiBuf&&) { InvalidCopyOrMove<>(); }
269 BasicMultiBuf& operator=(BasicMultiBuf&&) { InvalidCopyOrMove<>(); }
273 template <
typename OtherMultiBuf>
274 constexpr OtherMultiBuf& as() & {
275 internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
276 return generic().
template as<OtherMultiBuf>();
279 template <
typename OtherMultiBuf>
280 constexpr const OtherMultiBuf& as() const& {
281 internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
282 return generic().
template as<OtherMultiBuf>();
285 template <
typename OtherMultiBuf>
286 constexpr OtherMultiBuf&& as() && {
287 internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
288 return std::move(generic().
template as<OtherMultiBuf>());
291 template <
typename OtherMultiBuf>
292 constexpr const OtherMultiBuf&& as() const&& {
293 internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
294 return std::move(generic().
template as<OtherMultiBuf>());
298 typename OtherMultiBuf,
299 typename = internal::EnableIfConvertible<BasicMultiBuf, OtherMultiBuf>>
300 constexpr operator OtherMultiBuf&() & {
301 return as<OtherMultiBuf>();
305 typename OtherMultiBuf,
306 typename = internal::EnableIfConvertible<BasicMultiBuf, OtherMultiBuf>>
307 constexpr operator const OtherMultiBuf&()
const& {
308 return as<OtherMultiBuf>();
312 typename OtherMultiBuf,
313 typename = internal::EnableIfConvertible<BasicMultiBuf, OtherMultiBuf>>
314 constexpr operator OtherMultiBuf&&() && {
315 return std::move(as<OtherMultiBuf>());
319 typename OtherMultiBuf,
320 typename = internal::EnableIfConvertible<BasicMultiBuf, OtherMultiBuf>>
321 constexpr operator const OtherMultiBuf&&()
const&& {
322 return std::move(as<OtherMultiBuf>());
344 constexpr size_t size()
const {
return generic().
size(); }
357 template <
bool kMutable = !is_const()>
358 std::enable_if_t<kMutable, reference> at(
size_t index) {
359 return *(begin() +
static_cast<int>(index));
361 const_reference at(
size_t index)
const {
362 return *(begin() +
static_cast<int>(index));
365 template <
bool kMutable = !is_const()>
366 std::enable_if_t<kMutable, reference> operator[](
size_t index) {
369 const_reference operator[](
size_t index)
const {
return at(index); }
383 template <
bool kMutable = !is_const()>
384 constexpr std::enable_if_t<kMutable, v2::Chunks> Chunks() {
385 return generic().Chunks();
387 constexpr const v2::ConstChunks Chunks()
const {
388 return generic().ConstChunks();
390 constexpr const v2::ConstChunks ConstChunks()
const {
391 return generic().ConstChunks();
407 template <
bool kMutable = !is_const()>
408 constexpr std::enable_if_t<kMutable, iterator> begin() {
409 return generic().begin();
411 constexpr const_iterator begin()
const {
return cbegin(); }
412 constexpr const_iterator cbegin()
const {
return generic().cbegin(); }
425 template <
bool kMutable = !is_const()>
426 constexpr std::enable_if_t<kMutable, iterator> end() {
427 return generic().end();
429 constexpr const_iterator end()
const {
return cend(); }
430 constexpr const_iterator cend()
const {
return generic().cend(); }
454 template <
Property... kOtherProperties>
478 template <
Property... kOtherProperties>
491 int&... kExplicitGuard,
494 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>,
int>>
524 return Insert(pos, bytes, 0);
526 iterator
Insert(const_iterator pos,
527 const SharedPtr<
const std::byte[]>& bytes) {
528 return Insert(pos, bytes, 0);
545 iterator
Insert(const_iterator pos,
548 size_t length = dynamic_extent);
549 iterator
Insert(const_iterator pos,
550 const SharedPtr<
const std::byte[]>& bytes,
552 size_t length = dynamic_extent);
562 template <
Property... kOtherProperties>
580 template <
Property... kOtherProperties>
591 int&... kExplicitGuard,
594 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>,
int>>
638 size_t length = dynamic_extent);
641 size_t length = dynamic_extent);
770 return generic().
CopyTo(dst, offset);
783 "`CopyFrom` may only be called on mutable MultiBufs");
784 return generic().
CopyFrom(src, offset);
804 return generic().
Get(
copy, offset);
822 template <
int&... kExplicitGuard,
typename Visitor>
824 return visitor(
Get(
copy, offset));
850 "`observer` may only be called on observable MultiBufs");
851 return generic().observer_;
862 "`set_observer` may only be called on observable MultiBufs");
876 "`NumFragments` may only be called on layerable MultiBufs");
885 "`NumLayers` may only be called on layerable MultiBufs");
886 return generic().num_layers();
897 size_t num_chunks = 1) {
920 [[nodiscard]]
bool AddLayer(
size_t offset,
size_t length = dynamic_extent) {
922 "`AddLayer` may only be called on layerable MultiBufs");
923 return generic().
AddLayer(offset, length);
930 "`SealTopLayer` may only be called on layerable MultiBufs");
938 "`UnsealTopLayer` may only be called on layerable MultiBufs");
946 "`IsTopLayerSealed` may only be called on layerable MultiBufs");
961 "`TruncateTopLayer` may only be called on layerable MultiBufs");
973 "`SetTopLayer` may only be called on mutable, layerable "
975 PW_ASSERT(src.size() <=
size());
990 "`PopLayer` may only be called on layerable MultiBufs");
995 constexpr BasicMultiBuf() { internal::PropertiesAreValid(); }
1004 template <
typename OtherMultiBuf,
typename MultiBufType>
1005 friend constexpr OtherMultiBuf& internal::ConstCast(
const MultiBufType& mb);
1007 template <
bool kVal
idCopyOrMove = false>
1008 static constexpr void InvalidCopyOrMove() {
1009 static_assert(kValidCopyOrMove,
1010 "Only copies and moves from `BasicMultiBuf<...>::Instance`"
1011 "to `BasicMultiBuf<...>&` or another "
1012 "`BasicMultiBuf<...>::Instance` are valid.");
1016 friend class BasicMultiBuf;
1018 constexpr GenericMultiBuf&
generic() {
1019 return static_cast<GenericMultiBuf&
>(*this);
1021 constexpr const GenericMultiBuf&
generic()
const {
1022 return static_cast<const GenericMultiBuf&
>(*this);
1032template <
typename OtherMultiBuf,
typename MultiBufType>
1033constexpr OtherMultiBuf& ConstCast(
const MultiBufType& mb) {
1034 AssertIsConvertibleIgnoreConst<MultiBufType, OtherMultiBuf>();
1035 return const_cast<OtherMultiBuf&
>(mb.generic().template as<OtherMultiBuf>());
1059 using ControlBlock = allocator::internal::ControlBlock;
1060 using ControlBlockHandle = allocator::internal::ControlBlockHandle;
1082 *
this = std::move(other);
1096 template <
typename OtherMultiBuf,
typename MultiBufType>
1097 friend constexpr OtherMultiBuf& ConstCast(
const MultiBufType& mb);
1101 : deque_(allocator) {}
1103 template <
typename MultiBufType>
1104 constexpr MultiBufType& as() {
1108 template <
typename MultiBufType>
1109 constexpr const MultiBufType& as()
const {
1116 constexpr Allocator& get_allocator()
const {
return deque_.get_allocator(); }
1119 constexpr bool empty()
const {
return deque_.empty(); }
1122 constexpr bool at_capacity()
const {
1123 return deque_.size() == deque_.capacity();
1127 constexpr size_t size()
const {
1128 return static_cast<size_t>(cend() - cbegin());
1134 return v2::Chunks(deque_, entries_per_chunk_);
1140 constexpr iterator begin() {
return MakeIterator(0); }
1141 constexpr const_iterator cbegin()
const {
return MakeIterator(0); }
1142 constexpr iterator end() {
return MakeIterator(num_chunks()); }
1143 constexpr const_iterator cend()
const {
return MakeIterator(num_chunks()); }
1148 [[nodiscard]]
bool TryReserveChunks(
size_t num_chunks) {
1149 return TryReserveLayers(num_layers(), num_chunks);
1165 return Insert(pos,
UniquePtr<
const std::byte[]>(std::move(owned)));
1168 const SharedPtr<
const std::byte[]>& shared,
1175 return Insert(pos,
SharedPtr<
const std::byte[]>(shared), offset, length);
1180 size_t size)
const {
1181 return pos != cend() && size != 0 &&
1182 size <= static_cast<size_t>(cend() - pos);
1207 size_t CopyTo(
ByteSpan dst,
size_t offset)
const {
1208 return CopyToImpl(dst, offset, 0);
1226 size_type NumFragments()
const;
1229 [[nodiscard]]
bool TryReserveLayers(
size_t num_layers,
size_t num_chunks = 1);
1232 [[nodiscard]]
bool AddLayer(
size_t offset,
size_t length = dynamic_extent);
1235 void SealTopLayer();
1238 void UnsealTopLayer();
1241 void TruncateTopLayer(
size_t length);
1255 static size_t CheckRange(
size_t offset,
size_t length,
size_t size);
1258 constexpr size_type num_chunks()
const {
1259 return Entry::num_chunks(deque_, entries_per_chunk_);
1263 constexpr size_type num_layers()
const {
1264 return Entry::num_layers(entries_per_chunk_);
1268 constexpr size_type memory_context_index(size_type chunk)
const {
1269 return Entry::memory_context_index(chunk, entries_per_chunk_);
1273 constexpr size_type data_index(size_type chunk)
const {
1274 return Entry::data_index(chunk, entries_per_chunk_);
1278 constexpr size_type base_view_index(size_type chunk)
const {
1279 return Entry::base_view_index(chunk, entries_per_chunk_);
1283 constexpr size_type view_index(size_type chunk, size_type layer)
const {
1284 return Entry::view_index(chunk, entries_per_chunk_, layer);
1288 constexpr size_type top_view_index(size_type chunk)
const {
1289 return Entry::top_view_index(chunk, entries_per_chunk_);
1293 constexpr std::byte* GetData(size_type chunk)
const {
1294 return Entry::GetData(deque_, chunk, entries_per_chunk_);
1298 constexpr bool IsOwned(size_type chunk)
const {
1299 return Entry::IsOwned(deque_, chunk, entries_per_chunk_);
1303 constexpr bool IsShared(size_type chunk)
const {
1304 return Entry::IsShared(deque_, chunk, entries_per_chunk_);
1308 constexpr bool IsSealed(size_type chunk)
const {
1309 return Entry::IsSealed(deque_, chunk, entries_per_chunk_);
1314 constexpr bool IsBoundary(size_type chunk, size_type layer)
const {
1315 return Entry::IsBoundary(deque_, chunk, entries_per_chunk_, layer);
1317 constexpr bool IsBoundary(size_type chunk)
const {
1318 return Entry::IsBoundary(deque_, chunk, entries_per_chunk_);
1323 constexpr Deallocator& GetDeallocator(size_type chunk)
const {
1324 return Entry::GetDeallocator(deque_, chunk, entries_per_chunk_);
1328 constexpr ControlBlock& GetControlBlock(size_type chunk)
const {
1329 return Entry::GetControlBlock(deque_, chunk, entries_per_chunk_);
1334 constexpr size_type GetOffset(size_type chunk, size_type layer)
const {
1335 return Entry::GetOffset(deque_, chunk, entries_per_chunk_, layer);
1337 constexpr size_type GetOffset(size_type chunk)
const {
1338 return Entry::GetOffset(deque_, chunk, entries_per_chunk_);
1344 constexpr size_type GetRelativeOffset(size_type chunk,
1345 size_type layer)
const {
1346 return Entry::GetRelativeOffset(deque_, chunk, entries_per_chunk_, layer);
1348 constexpr size_type GetRelativeOffset(size_type chunk)
const {
1349 return Entry::GetRelativeOffset(deque_, chunk, entries_per_chunk_);
1355 constexpr size_type GetLength(size_type chunk, size_type layer)
const {
1356 return Entry::GetLength(deque_, chunk, entries_per_chunk_, layer);
1358 constexpr size_type GetLength(size_type chunk)
const {
1359 return Entry::GetLength(deque_, chunk, entries_per_chunk_);
1365 constexpr ByteSpan GetView(size_type chunk, size_type layer)
const {
1366 return Entry::GetView(deque_, chunk, entries_per_chunk_, layer);
1368 constexpr ByteSpan GetView(size_type chunk)
const {
1369 return Entry::GetView(deque_, chunk, entries_per_chunk_);
1374 constexpr iterator MakeIterator(size_type chunk, size_type offset = 0)
const {
1375 return iterator(deque_, chunk, entries_per_chunk_, 0) + offset;
1380 [[nodiscard]]
bool TryConvertToShared(size_type chunk);
1386 [[nodiscard]]
bool TryReserveEntries(size_type num_entries,
1387 bool split =
false);
1391 size_type InsertChunks(
const_iterator pos, size_type num_chunks);
1410 void SplitBase(size_type chunk,
Deque& out_deque, size_type out_chunk);
1417 void SplitBefore(size_type chunk,
1420 size_type out_chunk);
1424 void SplitBefore(size_type chunk, size_type split);
1431 void SplitAfter(size_type chunk,
1434 size_type out_chunk);
1438 void SplitAfter(size_type chunk, size_type split);
1473 size_t CopyToImpl(
ByteSpan dst,
size_t offset, size_type start)
const;
1476 [[nodiscard]]
bool IsTopLayerSealed()
const;
1497 size_type entries_per_chunk_ = Entry::kMinEntriesPerChunk;
1522template <
typename MultiBufType>
1545 constexpr Instance(MultiBufType&& mb)
1548 constexpr Instance& operator=(MultiBufType&& mb) {
1556 internal::AssertIsAssignable<
BasicMultiBuf<kProperties...>, MultiBufType>();
1561 internal::AssertIsAssignable<
BasicMultiBuf<kProperties...>, MultiBufType>();
1566 constexpr MultiBufType* operator->() {
return &base_.as<MultiBufType>(); }
1567 constexpr const MultiBufType* operator->()
const {
1568 return &base_.as<MultiBufType>();
1571 constexpr MultiBufType& operator*() & {
return base_.as<MultiBufType>(); }
1572 constexpr const MultiBufType& operator*()
const& {
1573 return base_.as<MultiBufType>();
1576 constexpr MultiBufType&& operator*() && {
1577 return std::move(base_.as<MultiBufType>());
1579 constexpr const MultiBufType&& operator*()
const&& {
1580 return std::move(base_.as<MultiBufType>());
1583 constexpr operator MultiBufType&() & {
return base_.as<MultiBufType>(); }
1584 constexpr operator const MultiBufType&()
const& {
1585 return base_.as<MultiBufType>();
1588 constexpr operator MultiBufType&&() && {
1589 return std::move(base_.as<MultiBufType>());
1591 constexpr operator const MultiBufType&&()
const&& {
1592 return std::move(base_.as<MultiBufType>());
1598 template <
bool kMoveOnly = false>
1599 static constexpr void MoveOnly() {
1600 static_assert(kMoveOnly,
1601 "Instances can only be created from existing MultiBufs using "
1602 "move-construction or move-assignment.");
1614 return generic().TryReserveForInsert(pos);
1618template <
Property... kOtherProperties>
1621 internal::AssertIsConvertible<
BasicMultiBuf<kOtherProperties...>,
1623 return generic().TryReserveForInsert(pos,
1628template <
Property... kOtherProperties>
1631 internal::AssertIsConvertible<
BasicMultiBuf<kOtherProperties...>,
1633 return generic().Insert(pos, std::move(mb.generic()));
1637template <
int&... kExplicitGuard,
typename T,
typename>
1640 using data_ptr_type =
decltype(std::data(std::declval<T&>()));
1641 static_assert(std::is_same_v<data_ptr_type, std::byte*> || is_const(),
1642 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1643 return generic().Insert(pos, bytes);
1650 return generic().Insert(pos, std::move(bytes));
1655 UniquePtr<
const std::byte[]>&& bytes)
1657 static_assert(is_const(),
1658 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1659 return generic().Insert(pos, std::move(bytes));
1664 const SharedPtr<std::byte[]>& bytes,
1666 size_t length) -> iterator {
1667 return generic().Insert(pos, bytes, offset, length);
1673 const SharedPtr<
const std::byte[]>& bytes,
1675 size_t length) -> iterator {
1676 static_assert(is_const(),
1677 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1678 return generic().Insert(pos, bytes, offset, length);
1682template <
Property... kOtherProperties>
1685 return generic().TryReserveForInsert(end(),
1691 return generic().TryReserveForInsert(end());
1695template <
Property... kOtherProperties>
1698 Insert(end(), std::move(mb));
1702template <
int&... kExplicitGuard,
typename T,
typename>
1704 using data_ptr_type =
decltype(std::data(std::declval<T&>()));
1705 static_assert(std::is_same_v<data_ptr_type, std::byte*> || is_const(),
1706 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1707 Insert(end(), bytes);
1712 Insert(end(), std::move(bytes));
1718 static_assert(is_const(),
1719 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1720 Insert(end(), std::move(bytes));
1725 const SharedPtr<std::byte[]>& bytes,
size_t offset,
size_t length) {
1726 Insert(end(), bytes, offset, length);
1731 const SharedPtr<
const std::byte[]>& bytes,
size_t offset,
size_t length) {
1732 static_assert(is_const(),
1733 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1734 Insert(end(), bytes, offset, length);
1738Result<internal::Instance<BasicMultiBuf<kProperties...>>>
1740 auto result =
generic().Remove(pos, size);
1742 return result.status();
1744 return Instance(std::move(*result));
1750 auto result =
generic().PopFrontFragment();
1752 return result.status();
1754 return Instance(std::move(*result));
1761 if constexpr (is_const()) {
Definition: allocator.h:45
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: dynamic_deque.h:60
Definition: shared_ptr.h:68
Definition: unique_ptr.h:43
element_type * Release() noexcept
Definition: unique_ptr.h:256
Deallocator * deallocator() const
Returns a pointer to the object that can destroy the value.
Definition: unique_ptr.h:187
size_t size() const
Definition: unique_ptr.h:180
Definition: multibuf.h:38
Definition: multibuf.h:184
constexpr size_t size() const
Definition: multibuf.h:344
bool IsReleasable(const_iterator pos) const
Definition: multibuf.h:719
static constexpr bool is_observable()
Returns whether an observer can be registered on the MultiBuf.
Definition: multibuf.h:211
constexpr size_type NumLayers() const
Definition: multibuf.h:883
void PopLayer()
Definition: multibuf.h:988
bool IsTopLayerSealed()
Returns whether the "sealed" flag is set in the top layer.
Definition: multibuf.h:943
void ShrinkToFit()
Definition: multibuf.h:840
iterator Insert(const_iterator pos, BasicMultiBuf< kOtherProperties... > &&mb)
void PushBack(const T &bytes)
Definition: multibuf.h:1703
void PushBack(BasicMultiBuf< kOtherProperties... > &&mb)
Definition: multibuf.h:1696
static constexpr bool is_layerable()
Returns whether additional views can be layered on the MultiBuf.
Definition: multibuf.h:206
iterator Insert(const_iterator pos, const T &bytes)
void SealTopLayer()
Definition: multibuf.h:928
Result< Instance > PopFrontFragment()
Definition: multibuf.h:1749
Result< const_iterator > Discard(const_iterator pos, size_t size)
Definition: multibuf.h:711
constexpr bool empty() const
Definition: multibuf.h:334
void TruncateTopLayer(size_t length)
Definition: multibuf.h:958
ConstByteSpan Get(ByteSpan copy, size_t offset=0) const
Definition: multibuf.h:803
void Clear()
Definition: multibuf.h:832
bool TryReserveForInsert(const_iterator pos, const BasicMultiBuf< kOtherProperties... > &mb)
Definition: multibuf.h:1619
bool IsRemovable(const_iterator pos, size_t size) const
Definition: multibuf.h:651
constexpr Allocator & get_allocator() const
Returns the allocator used to store metadata.
Definition: multibuf.h:328
void SetTopLayer(ConstByteSpan src)
Definition: multibuf.h:971
bool TryReserveChunks(size_t num_chunks)
Definition: multibuf.h:437
constexpr Observer * observer() const
Definition: multibuf.h:848
void set_observer(Observer *observer)
Definition: multibuf.h:860
void UnsealTopLayer()
Definition: multibuf.h:936
SharedPtr< value_type[]> Share(const_iterator pos) const
Definition: multibuf.h:1773
bool IsShareable(const_iterator pos) const
Definition: multibuf.h:741
Result< Instance > Remove(const_iterator pos, size_t size)
Definition: multibuf.h:1739
bool TryReserveLayers(size_t num_layers, size_t num_chunks=1)
Definition: multibuf.h:896
bool TryReserveForInsert(const_iterator pos)
Definition: multibuf.h:1613
size_type NumFragments() const
Definition: multibuf.h:874
size_t CopyFrom(ConstByteSpan src, size_t offset=0)
Definition: multibuf.h:781
bool TryReserveForPushBack()
Definition: multibuf.h:1690
bool AddLayer(size_t offset, size_t length=dynamic_extent)
Definition: multibuf.h:920
static constexpr bool is_const()
Returns whether the MultiBuf data is immutable.
Definition: multibuf.h:201
size_t CopyTo(ByteSpan dst, size_t offset=0) const
Definition: multibuf.h:769
bool TryReserveForPushBack(const BasicMultiBuf< kOtherProperties... > &mb)
Definition: multibuf.h:1683
auto Visit(Visitor visitor, ByteSpan copy, size_t offset)
Definition: multibuf.h:823
constexpr bool at_capacity() const
Definition: multibuf.h:340
UniquePtr< value_type[]> Release(const_iterator pos)
Definition: multibuf.h:1759
Definition: observer.h:29
Byte iterator templated on the const-ness of the bytes it references.
Definition: byte_iterator.h:85
Definition: multibuf.h:1057
Definition: multibuf.h:1523
NullAllocator & GetNullAllocator()
Returns a reference to the NullAllocator singleton.
constexpr OutputIt copy(InputIt first, InputIt last, OutputIt d_first)
constexpr backport of <algorithm>'s std::copy for C++17.
Definition: algorithm.h:355
Property
Basic properties of a MultiBuf.
Definition: properties.h:24
BasicMultiBuf< Property::kLayerable > MultiBuf
Definition: multibuf.h:62
Result(T value) -> Result< T >
Deduction guide to allow Result(v) rather than Result<T>(v).