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);
1030template <
typename OtherMultiBuf,
typename MultiBufType>
1031constexpr OtherMultiBuf& ConstCast(
const MultiBufType& mb) {
1032 AssertIsConvertibleIgnoreConst<MultiBufType, OtherMultiBuf>();
1033 return const_cast<OtherMultiBuf&
>(mb.generic().template as<OtherMultiBuf>());
1057 using ControlBlock = allocator::internal::ControlBlock;
1058 using ControlBlockHandle = allocator::internal::ControlBlockHandle;
1080 *
this = std::move(other);
1094 template <
typename OtherMultiBuf,
typename MultiBufType>
1095 friend constexpr OtherMultiBuf& ConstCast(
const MultiBufType& mb);
1099 : deque_(allocator) {}
1101 template <
typename MultiBufType>
1102 constexpr MultiBufType& as() {
1106 template <
typename MultiBufType>
1107 constexpr const MultiBufType& as()
const {
1114 constexpr Allocator& get_allocator()
const {
return deque_.get_allocator(); }
1117 constexpr bool empty()
const {
return deque_.empty(); }
1120 constexpr bool at_capacity()
const {
1121 return deque_.size() == deque_.capacity();
1125 constexpr size_t size()
const {
1126 return static_cast<size_t>(cend() - cbegin());
1132 return v2::Chunks(deque_, entries_per_chunk_);
1138 constexpr iterator begin() {
return MakeIterator(0); }
1139 constexpr const_iterator cbegin()
const {
return MakeIterator(0); }
1140 constexpr iterator end() {
return MakeIterator(num_chunks()); }
1141 constexpr const_iterator cend()
const {
return MakeIterator(num_chunks()); }
1146 [[nodiscard]]
bool TryReserveChunks(
size_t num_chunks) {
1147 return TryReserveLayers(num_layers(), num_chunks);
1207 return Insert(pos,
UniquePtr<
const std::byte[]>(std::move(owned)));
1222 const SharedPtr<
const std::byte[]>& shared,
1241 return Insert(pos,
SharedPtr<
const std::byte[]>(shared), offset, length);
1246 size_t size)
const {
1247 return pos != cend() && size != 0 &&
1248 size <= static_cast<size_t>(cend() - pos);
1273 size_t CopyTo(
ByteSpan dst,
size_t offset)
const {
1274 return CopyToImpl(dst, offset, 0);
1292 size_type NumFragments()
const;
1295 [[nodiscard]]
bool TryReserveLayers(
size_t num_layers,
size_t num_chunks = 1);
1298 [[nodiscard]]
bool AddLayer(
size_t offset,
size_t length = dynamic_extent);
1301 void SealTopLayer();
1304 void UnsealTopLayer();
1307 void TruncateTopLayer(
size_t length);
1321 static size_t CheckRange(
size_t offset,
size_t length,
size_t size);
1324 constexpr size_type num_chunks()
const {
1325 return Entry::num_chunks(deque_, entries_per_chunk_);
1329 constexpr size_type num_layers()
const {
1330 return Entry::num_layers(entries_per_chunk_);
1334 constexpr size_type memory_context_index(size_type chunk)
const {
1335 return Entry::memory_context_index(chunk, entries_per_chunk_);
1339 constexpr size_type data_index(size_type chunk)
const {
1340 return Entry::data_index(chunk, entries_per_chunk_);
1344 constexpr size_type base_view_index(size_type chunk)
const {
1345 return Entry::base_view_index(chunk, entries_per_chunk_);
1349 constexpr size_type view_index(size_type chunk, size_type layer)
const {
1350 return Entry::view_index(chunk, entries_per_chunk_, layer);
1354 constexpr size_type top_view_index(size_type chunk)
const {
1355 return Entry::top_view_index(chunk, entries_per_chunk_);
1359 constexpr std::byte* GetData(size_type chunk)
const {
1360 return Entry::GetData(deque_, chunk, entries_per_chunk_);
1364 constexpr bool IsOwned(size_type chunk)
const {
1365 return Entry::IsOwned(deque_, chunk, entries_per_chunk_);
1369 constexpr bool IsShared(size_type chunk)
const {
1370 return Entry::IsShared(deque_, chunk, entries_per_chunk_);
1374 constexpr bool IsSealed(size_type chunk)
const {
1375 return Entry::IsSealed(deque_, chunk, entries_per_chunk_);
1380 constexpr bool IsBoundary(size_type chunk, size_type layer)
const {
1381 return Entry::IsBoundary(deque_, chunk, entries_per_chunk_, layer);
1383 constexpr bool IsBoundary(size_type chunk)
const {
1384 return Entry::IsBoundary(deque_, chunk, entries_per_chunk_);
1389 constexpr Deallocator& GetDeallocator(size_type chunk)
const {
1390 return Entry::GetDeallocator(deque_, chunk, entries_per_chunk_);
1394 constexpr ControlBlock& GetControlBlock(size_type chunk)
const {
1395 return Entry::GetControlBlock(deque_, chunk, entries_per_chunk_);
1400 constexpr size_type GetOffset(size_type chunk, size_type layer)
const {
1401 return Entry::GetOffset(deque_, chunk, entries_per_chunk_, layer);
1403 constexpr size_type GetOffset(size_type chunk)
const {
1404 return Entry::GetOffset(deque_, chunk, entries_per_chunk_);
1410 constexpr size_type GetRelativeOffset(size_type chunk,
1411 size_type layer)
const {
1412 return Entry::GetRelativeOffset(deque_, chunk, entries_per_chunk_, layer);
1414 constexpr size_type GetRelativeOffset(size_type chunk)
const {
1415 return Entry::GetRelativeOffset(deque_, chunk, entries_per_chunk_);
1421 constexpr size_type GetLength(size_type chunk, size_type layer)
const {
1422 return Entry::GetLength(deque_, chunk, entries_per_chunk_, layer);
1424 constexpr size_type GetLength(size_type chunk)
const {
1425 return Entry::GetLength(deque_, chunk, entries_per_chunk_);
1431 constexpr ByteSpan GetView(size_type chunk, size_type layer)
const {
1432 return Entry::GetView(deque_, chunk, entries_per_chunk_, layer);
1434 constexpr ByteSpan GetView(size_type chunk)
const {
1435 return Entry::GetView(deque_, chunk, entries_per_chunk_);
1440 constexpr iterator MakeIterator(size_type chunk, size_type offset = 0)
const {
1441 return iterator(deque_, chunk, entries_per_chunk_, 0) + offset;
1446 [[nodiscard]]
bool TryConvertToShared(size_type chunk);
1452 [[nodiscard]]
bool TryReserveEntries(size_type num_entries,
1453 bool split =
false);
1457 size_type InsertChunks(
const_iterator pos, size_type num_chunks);
1476 void SplitBase(size_type chunk,
Deque& out_deque, size_type out_chunk);
1483 void SplitBefore(size_type chunk,
1486 size_type out_chunk);
1490 void SplitBefore(size_type chunk, size_type split);
1497 void SplitAfter(size_type chunk,
1500 size_type out_chunk);
1504 void SplitAfter(size_type chunk, size_type split);
1539 size_t CopyToImpl(
ByteSpan dst,
size_t offset, size_type start)
const;
1542 [[nodiscard]]
bool IsTopLayerSealed()
const;
1563 size_type entries_per_chunk_ = Entry::kMinEntriesPerChunk;
1588template <
typename MultiBufType>
1611 constexpr Instance(MultiBufType&& mb)
1614 constexpr Instance& operator=(MultiBufType&& mb) {
1622 internal::AssertIsAssignable<
BasicMultiBuf<kProperties...>, MultiBufType>();
1627 internal::AssertIsAssignable<
BasicMultiBuf<kProperties...>, MultiBufType>();
1632 constexpr MultiBufType* operator->() {
return &base_.as<MultiBufType>(); }
1633 constexpr const MultiBufType* operator->()
const {
1634 return &base_.as<MultiBufType>();
1637 constexpr MultiBufType& operator*() & {
return base_.as<MultiBufType>(); }
1638 constexpr const MultiBufType& operator*()
const& {
1639 return base_.as<MultiBufType>();
1642 constexpr MultiBufType&& operator*() && {
1643 return std::move(base_.as<MultiBufType>());
1645 constexpr const MultiBufType&& operator*()
const&& {
1646 return std::move(base_.as<MultiBufType>());
1649 constexpr operator MultiBufType&() & {
return base_.as<MultiBufType>(); }
1650 constexpr operator const MultiBufType&()
const& {
1651 return base_.as<MultiBufType>();
1654 constexpr operator MultiBufType&&() && {
1655 return std::move(base_.as<MultiBufType>());
1657 constexpr operator const MultiBufType&&()
const&& {
1658 return std::move(base_.as<MultiBufType>());
1664 template <
bool kMoveOnly = false>
1665 static constexpr void MoveOnly() {
1666 static_assert(kMoveOnly,
1667 "Instances can only be created from existing MultiBufs using "
1668 "move-construction or move-assignment.");
1680 return generic().TryReserveForInsert(pos);
1684template <
Property... kOtherProperties>
1687 internal::AssertIsConvertible<
BasicMultiBuf<kOtherProperties...>,
1689 return generic().TryReserveForInsert(pos,
1694template <
Property... kOtherProperties>
1697 internal::AssertIsConvertible<
BasicMultiBuf<kOtherProperties...>,
1699 return generic().Insert(pos, std::move(mb.generic()));
1703template <
int&... kExplicitGuard,
typename T,
typename>
1706 using data_ptr_type =
decltype(std::data(std::declval<T&>()));
1707 static_assert(std::is_same_v<data_ptr_type, std::byte*> || is_const(),
1708 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1709 return generic().Insert(pos, bytes);
1716 return generic().Insert(pos, std::move(bytes));
1721 UniquePtr<
const std::byte[]>&& bytes)
1723 static_assert(is_const(),
1724 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1725 return generic().Insert(pos, std::move(bytes));
1730 const SharedPtr<std::byte[]>& bytes,
1732 size_t length) -> iterator {
1733 return generic().Insert(pos, bytes, offset, length);
1739 const SharedPtr<
const std::byte[]>& bytes,
1741 size_t length) -> iterator {
1742 static_assert(is_const(),
1743 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1744 return generic().Insert(pos, bytes, offset, length);
1748template <
Property... kOtherProperties>
1751 return generic().TryReserveForInsert(end(),
1757 return generic().TryReserveForInsert(end());
1761template <
Property... kOtherProperties>
1764 Insert(end(), std::move(mb));
1768template <
int&... kExplicitGuard,
typename T,
typename>
1770 using data_ptr_type =
decltype(std::data(std::declval<T&>()));
1771 static_assert(std::is_same_v<data_ptr_type, std::byte*> || is_const(),
1772 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1773 Insert(end(), bytes);
1778 Insert(end(), std::move(bytes));
1784 static_assert(is_const(),
1785 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1786 Insert(end(), std::move(bytes));
1791 const SharedPtr<std::byte[]>& bytes,
size_t offset,
size_t length) {
1792 Insert(end(), bytes, offset, length);
1797 const SharedPtr<
const std::byte[]>& bytes,
size_t offset,
size_t length) {
1798 static_assert(is_const(),
1799 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1800 Insert(end(), bytes, offset, length);
1804Result<internal::Instance<BasicMultiBuf<kProperties...>>>
1806 auto result =
generic().Remove(pos, size);
1808 return result.status();
1810 return Instance(std::move(*result));
1816 auto result =
generic().PopFrontFragment();
1818 return result.status();
1820 return Instance(std::move(*result));
1827 if constexpr (is_const()) {
Definition: allocator.h:42
Abstract interface for releasing memory.
Definition: deallocator.h:30
Definition: dynamic_deque.h:73
Definition: shared_ptr.h:64
Definition: unique_ptr.h:44
element_type * Release() noexcept
Definition: unique_ptr.h:266
Deallocator * deallocator() const
Returns a pointer to the object that can destroy the value.
Definition: unique_ptr.h:164
size_t size() const
Definition: unique_ptr.h:244
Definition: multibuf.h:39
Definition: multibuf.h:213
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:1769
void PushBack(BasicMultiBuf< kOtherProperties... > &&mb)
Definition: multibuf.h:1762
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:1815
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:1685
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:1839
bool IsShareable(const_iterator pos) const
Definition: multibuf.h:741
Result< Instance > Remove(const_iterator pos, size_t size)
Definition: multibuf.h:1805
bool TryReserveLayers(size_t num_layers, size_t num_chunks=1)
Definition: multibuf.h:896
bool TryReserveForInsert(const_iterator pos)
Definition: multibuf.h:1679
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:1756
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:1749
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:1825
Definition: observer.h:29
Byte iterator templated on the const-ness of the bytes it references.
Definition: byte_iterator.h:85
Definition: multibuf.h:1055
Definition: multibuf.h:1589
NullAllocator & GetNullAllocator()
Returns a reference to a 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).