26#include "pw_allocator/allocator.h"
27#include "pw_allocator/null_allocator.h"
28#include "pw_bytes/span.h"
29#include "pw_containers/dynamic_deque.h"
30#include "pw_multibuf/v2/chunks.h"
31#include "pw_multibuf/v2/internal/byte_iterator.h"
32#include "pw_multibuf/v2/internal/entry.h"
33#include "pw_multibuf/v2/observer.h"
34#include "pw_multibuf/v2/properties.h"
36namespace pw::multibuf::v2 {
205 using size_type =
typename Deque::size_type;
206 using difference_type =
typename Deque::difference_type;
209 using const_iterator =
211 using pointer = iterator::pointer;
212 using const_pointer = const_iterator::pointer;
213 using reference = iterator::reference;
214 using const_reference = const_iterator::reference;
215 using value_type = std::conditional_t<
is_const(),
216 const_iterator::value_type,
217 iterator::value_type>;
247 template <
Property... kOtherProperties>
249 InvalidCopyOrMove<>();
252 BasicMultiBuf& operator=(
const BasicMultiBuf&) { InvalidCopyOrMove<>(); }
254 template <
Property... kOtherProperties>
255 BasicMultiBuf& operator=(
const BasicMultiBuf<kOtherProperties...>&) {
256 InvalidCopyOrMove<>();
259 BasicMultiBuf(BasicMultiBuf&&) { InvalidCopyOrMove<>(); }
261 BasicMultiBuf& operator=(BasicMultiBuf&&) { InvalidCopyOrMove<>(); }
265 template <
typename OtherMultiBuf>
266 constexpr OtherMultiBuf& as() & {
267 internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
268 return generic().
template as<OtherMultiBuf>();
271 template <
typename OtherMultiBuf>
272 constexpr const OtherMultiBuf& as() const& {
273 internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
274 return generic().
template as<OtherMultiBuf>();
277 template <
typename OtherMultiBuf>
278 constexpr OtherMultiBuf&& as() && {
279 internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
280 return std::move(generic().
template as<OtherMultiBuf>());
283 template <
typename OtherMultiBuf>
284 constexpr const OtherMultiBuf&& as() const&& {
285 internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
286 return std::move(generic().
template as<OtherMultiBuf>());
290 typename OtherMultiBuf,
291 typename = internal::EnableIfConvertible<BasicMultiBuf, OtherMultiBuf>>
292 constexpr operator OtherMultiBuf&() & {
293 return as<OtherMultiBuf>();
297 typename OtherMultiBuf,
298 typename = internal::EnableIfConvertible<BasicMultiBuf, OtherMultiBuf>>
299 constexpr operator const OtherMultiBuf&()
const& {
300 return as<OtherMultiBuf>();
304 typename OtherMultiBuf,
305 typename = internal::EnableIfConvertible<BasicMultiBuf, OtherMultiBuf>>
306 constexpr operator OtherMultiBuf&&() && {
307 return std::move(as<OtherMultiBuf>());
311 typename OtherMultiBuf,
312 typename = internal::EnableIfConvertible<BasicMultiBuf, OtherMultiBuf>>
313 constexpr operator const OtherMultiBuf&&()
const&& {
314 return std::move(as<OtherMultiBuf>());
331 constexpr size_t size()
const {
return generic().
size(); }
344 template <
bool kMutable = !is_const()>
345 std::enable_if_t<kMutable, reference> at(
size_t index) {
346 return *(begin() +
static_cast<int>(index));
348 const_reference at(
size_t index)
const {
349 return *(begin() +
static_cast<int>(index));
352 template <
bool kMutable = !is_const()>
353 std::enable_if_t<kMutable, reference> operator[](
size_t index) {
356 const_reference operator[](
size_t index)
const {
return at(index); }
370 template <
bool kMutable = !is_const()>
371 constexpr std::enable_if_t<kMutable, ChunksType> Chunks() {
372 return generic().Chunks();
374 constexpr ConstChunksType Chunks()
const {
return generic().ConstChunks(); }
375 constexpr ConstChunksType ConstChunks()
const {
376 return generic().ConstChunks();
392 template <
bool kMutable = !is_const()>
393 constexpr std::enable_if_t<kMutable, iterator> begin() {
394 return generic().begin();
396 constexpr const_iterator begin()
const {
return cbegin(); }
397 constexpr const_iterator cbegin()
const {
return generic().cbegin(); }
410 template <
bool kMutable = !is_const()>
411 constexpr std::enable_if_t<kMutable, iterator> end() {
412 return generic().end();
414 constexpr const_iterator end()
const {
return cend(); }
415 constexpr const_iterator cend()
const {
return generic().cend(); }
439 template <
Property... kOtherProperties>
462 template <
Property... kOtherProperties>
474 int&... kExplicitGuard,
477 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>,
int>>
507 void Insert(const_iterator pos,
const SharedPtr<
const std::byte[]>& bytes) {
524 void Insert(const_iterator pos,
527 size_t length = dynamic_extent);
528 void Insert(const_iterator pos,
529 const SharedPtr<
const std::byte[]>& bytes,
531 size_t length = dynamic_extent);
541 template <
Property... kOtherProperties>
559 template <
Property... kOtherProperties>
570 int&... kExplicitGuard,
573 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>,
int>>
617 size_t length = dynamic_extent);
620 size_t length = dynamic_extent);
749 return generic().
CopyTo(dst, offset);
762 "`CopyFrom` may only be called on mutable MultiBufs");
763 return generic().
CopyFrom(src, offset);
783 return generic().
Get(
copy, offset);
801 template <
int&... kExplicitGuard,
typename Visitor>
803 return visitor(
Get(
copy, offset));
829 "`observer` may only be called on observable MultiBufs");
830 return generic().observer_;
841 "`set_observer` may only be called on observable MultiBufs");
855 "`NumFragments` may only be called on layerable MultiBufs");
864 "`NumLayers` may only be called on layerable MultiBufs");
876 size_t num_chunks = 1) {
899 [[nodiscard]]
bool AddLayer(
size_t offset,
size_t length = dynamic_extent) {
901 "`AddLayer` may only be called on layerable MultiBufs");
902 return generic().
AddLayer(offset, length);
909 "`SealTopLayer` may only be called on layerable MultiBufs");
917 "`UnsealTopLayer` may only be called on layerable MultiBufs");
925 "`IsTopLayerSealed` may only be called on layerable MultiBufs");
940 "`TruncateTopLayer` may only be called on layerable MultiBufs");
952 "`SetTopLayer` may only be called on mutable, layerable "
954 PW_ASSERT(src.size() <=
size());
969 "`PopLayer` may only be called on layerable MultiBufs");
974 constexpr BasicMultiBuf() { internal::PropertiesAreValid(); }
977 template <
bool kVal
idCopyOrMove = false>
978 static constexpr void InvalidCopyOrMove() {
979 static_assert(kValidCopyOrMove,
980 "Only copies and moves from `BasicMultiBuf<...>::Instance`"
981 "to `BasicMultiBuf<...>&` or another "
982 "`BasicMultiBuf<...>::Instance` are valid.");
986 friend class BasicMultiBuf;
988 constexpr GenericMultiBuf&
generic() {
989 return static_cast<GenericMultiBuf&
>(*this);
991 constexpr const GenericMultiBuf&
generic()
const {
992 return static_cast<const GenericMultiBuf&
>(*this);
1023 using ControlBlock = allocator::internal::ControlBlock;
1047 *
this = std::move(other);
1053 friend class ::pw::multibuf::v2::BasicMultiBuf;
1060 : deque_(allocator) {}
1062 template <
typename MultiBufType>
1063 constexpr MultiBufType& as() {
1067 template <
typename MultiBufType>
1068 constexpr const MultiBufType& as()
const {
1075 constexpr bool empty()
const {
return deque_.empty(); }
1078 constexpr bool at_capacity()
const {
1079 return deque_.size() == deque_.capacity();
1083 constexpr size_t size()
const {
1084 return static_cast<size_t>(cend() - cbegin());
1090 return ChunksType(deque_, entries_per_chunk_);
1109 [[nodiscard]]
bool TryReserveChunks(
size_t num_chunks) {
1110 return TryReserveLayers(NumLayers(), num_chunks);
1133 ControlBlock* control_block);
1138 size_t size)
const {
1139 return pos != cend() && size != 0 &&
1140 size <= static_cast<size_t>(cend() - pos);
1165 size_t CopyTo(
ByteSpan dst,
size_t offset)
const {
1166 return CopyToImpl(dst, offset, 0);
1184 size_type NumFragments()
const;
1187 constexpr size_type NumLayers()
const {
1188 return entries_per_chunk_ - Entry::kMinEntriesPerChunk + 1;
1192 [[nodiscard]]
bool TryReserveLayers(
size_t num_layers,
size_t num_chunks = 1);
1195 [[nodiscard]]
bool AddLayer(
size_t offset,
size_t length = dynamic_extent);
1198 void SealTopLayer();
1201 void UnsealTopLayer();
1204 void TruncateTopLayer(
size_t length);
1218 static size_t CheckRange(
size_t offset,
size_t length,
size_t size);
1221 constexpr size_type num_chunks()
const {
1222 return deque_.size() / entries_per_chunk_;
1226 constexpr size_type memory_context_index(size_type chunk)
const {
1227 return Entry::memory_context_index(chunk, entries_per_chunk_);
1231 constexpr size_type data_index(size_type chunk)
const {
1232 return Entry::data_index(chunk, entries_per_chunk_);
1236 constexpr size_type base_view_index(size_type chunk)
const {
1237 return Entry::base_view_index(chunk, entries_per_chunk_);
1241 constexpr size_type view_index(size_type chunk, size_type layer)
const {
1242 return Entry::view_index(chunk, entries_per_chunk_, layer);
1246 constexpr size_type top_view_index(size_type chunk)
const {
1247 return Entry::top_view_index(chunk, entries_per_chunk_);
1251 constexpr std::byte* GetData(size_type chunk)
const {
1252 return deque_[data_index(chunk)].data;
1257 constexpr bool IsOwned(size_type chunk)
const {
1258 return deque_[base_view_index(chunk)].base_view.owned;
1263 constexpr bool IsShared(size_type chunk)
const {
1264 return deque_[base_view_index(chunk)].base_view.shared;
1268 constexpr bool IsSealed(size_type chunk)
const {
1269 return entries_per_chunk_ == Entry::kMinEntriesPerChunk
1271 : deque_[top_view_index(chunk)].view.sealed;
1275 constexpr bool IsBoundary(size_type chunk)
const {
1276 return entries_per_chunk_ == Entry::kMinEntriesPerChunk
1278 : deque_[top_view_index(chunk)].view.boundary;
1284 constexpr size_type GetOffset(size_type chunk, uint16_t layer)
const {
1285 return layer == 1 ? deque_[base_view_index(chunk)].base_view.offset
1286 : deque_[view_index(chunk, layer)].view.offset;
1290 constexpr size_type GetOffset(size_type chunk)
const {
1291 return GetOffset(chunk, NumLayers());
1295 constexpr size_type GetRelativeOffset(size_type chunk)
const {
1296 uint16_t layer = NumLayers();
1298 return GetOffset(chunk, layer);
1300 return GetOffset(chunk, layer) - GetOffset(chunk, layer - 1);
1304 constexpr size_type GetLength(size_type chunk)
const {
1305 return entries_per_chunk_ == Entry::kMinEntriesPerChunk
1306 ? deque_[base_view_index(chunk)].base_view.length
1307 : deque_[top_view_index(chunk)].view.length;
1311 constexpr ByteSpan GetView(size_type chunk)
const {
1312 return ByteSpan(GetData(chunk) + GetOffset(chunk), GetLength(chunk));
1318 std::pair<size_type, size_type> GetChunkAndOffset(
const_iterator pos)
const;
1322 [[nodiscard]]
bool TryConvertToShared(size_type chunk);
1328 [[nodiscard]]
bool TryReserveEntries(size_type num_entries,
1329 bool split =
false);
1333 size_type InsertChunks(
const_iterator pos, size_type num_chunks);
1351 void SplitBase(size_type chunk,
Deque& out_deque, size_type out_chunk);
1358 void SplitBefore(size_type chunk,
1361 size_type out_chunk);
1365 void SplitBefore(size_type chunk, size_type split);
1372 void SplitAfter(size_type chunk,
1375 size_type out_chunk);
1379 void SplitAfter(size_type chunk, size_type split);
1414 size_t CopyToImpl(
ByteSpan dst,
size_t offset, size_type start)
const;
1417 [[nodiscard]]
bool IsTopLayerSealed()
const;
1421 void SetLayer(
size_t offset,
size_t length);
1442 size_type entries_per_chunk_ = Entry::kMinEntriesPerChunk;
1467template <
typename MultiBufType>
1490 constexpr Instance(MultiBufType&& mb)
1493 constexpr Instance& operator=(MultiBufType&& mb) {
1501 internal::AssertIsConvertible<
BasicMultiBuf<kProperties...>,
1507 internal::AssertIsConvertible<
BasicMultiBuf<kProperties...>,
1513 constexpr MultiBufType* operator->() {
return &base_.as<MultiBufType>(); }
1514 constexpr const MultiBufType* operator->()
const {
1515 return &base_.as<MultiBufType>();
1518 constexpr MultiBufType& operator*() & {
return base_.as<MultiBufType>(); }
1519 constexpr const MultiBufType& operator*()
const& {
1520 return base_.as<MultiBufType>();
1523 constexpr MultiBufType&& operator*() && {
1524 return std::move(base_.as<MultiBufType>());
1526 constexpr const MultiBufType&& operator*()
const&& {
1527 return std::move(base_.as<MultiBufType>());
1530 constexpr operator MultiBufType&() & {
return base_.as<MultiBufType>(); }
1531 constexpr operator const MultiBufType&()
const& {
1532 return base_.as<MultiBufType>();
1535 constexpr operator MultiBufType&&() && {
1536 return std::move(base_.as<MultiBufType>());
1538 constexpr operator const MultiBufType&&()
const&& {
1539 return std::move(base_.as<MultiBufType>());
1545 template <
bool kMoveOnly = false>
1546 static constexpr void MoveOnly() {
1547 static_assert(kMoveOnly,
1548 "Instances can only be created from existing MultiBufs using "
1549 "move-construction or move-assignment.");
1561 return generic().TryReserveForInsert(pos);
1565template <
Property... kOtherProperties>
1568 internal::AssertIsConvertible<
BasicMultiBuf<kOtherProperties...>,
1570 return generic().TryReserveForInsert(pos,
1575template <
Property... kOtherProperties>
1578 internal::AssertIsConvertible<
BasicMultiBuf<kOtherProperties...>,
1580 generic().Insert(pos, std::move(mb.generic()));
1584template <
int&... kExplicitGuard,
typename T,
typename>
1586 using data_ptr_type =
decltype(std::data(std::declval<T&>()));
1587 static_assert(std::is_same_v<data_ptr_type, std::byte*> || is_const(),
1588 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1589 generic().Insert(pos, bytes);
1596 generic().Insert(pos, chunk, 0, bytes.size(), bytes.deallocator());
1602 const_iterator pos,
UniquePtr<
const std::byte[]>&& bytes) {
1603 static_assert(is_const(),
1604 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1606 generic().Insert(pos, chunk, 0, bytes.size(), bytes.deallocator());
1616 generic().Insert(pos, chunk, offset, length, bytes.control_block());
1622 const SharedPtr<
const std::byte[]>& bytes,
1625 static_assert(is_const(),
1626 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1627 ConstByteSpan chunk(bytes.get(), bytes.size());
1628 generic().Insert(pos, chunk, offset, length, bytes.control_block());
1632template <
Property... kOtherProperties>
1635 return generic().TryReserveForInsert(end(),
1641 return generic().TryReserveForInsert(end());
1645template <
Property... kOtherProperties>
1648 Insert(end(), std::move(mb));
1652template <
int&... kExplicitGuard,
typename T,
typename>
1654 using data_ptr_type =
decltype(std::data(std::declval<T&>()));
1655 static_assert(std::is_same_v<data_ptr_type, std::byte*> || is_const(),
1656 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1657 Insert(end(), bytes);
1662 Insert(end(), std::move(bytes));
1668 static_assert(is_const(),
1669 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1670 Insert(end(), std::move(bytes));
1675 const SharedPtr<std::byte[]>& bytes,
size_t offset,
size_t length) {
1676 Insert(end(), bytes, offset, length);
1681 const SharedPtr<
const std::byte[]>& bytes,
size_t offset,
size_t length) {
1682 static_assert(is_const(),
1683 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1684 Insert(end(), bytes, offset, length);
1688Result<internal::Instance<BasicMultiBuf<kProperties...>>>
1690 auto result =
generic().Remove(pos, size);
1692 return result.status();
1694 return Instance(std::move(*result));
1700 auto result =
generic().PopFrontFragment();
1702 return result.status();
1704 return Instance(std::move(*result));
1711 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:67
Definition: unique_ptr.h:43
element_type * Release() noexcept
Definition: unique_ptr.h:252
Deallocator * deallocator() const
Returns a pointer to the object that can destroy the value.
Definition: unique_ptr.h:183
size_t size() const
Definition: unique_ptr.h:176
constexpr size_t size() const
Definition: multibuf.h:331
bool IsReleasable(const_iterator pos) const
Definition: multibuf.h:698
static constexpr bool is_observable()
Returns whether an observer can be registered on the MultiBuf.
Definition: multibuf.h:201
constexpr size_type NumLayers() const
Definition: multibuf.h:862
void PopLayer()
Definition: multibuf.h:967
bool IsTopLayerSealed()
Returns whether the "sealed" flag is set in the top layer.
Definition: multibuf.h:922
void ShrinkToFit()
Definition: multibuf.h:819
void PushBack(const T &bytes)
Definition: multibuf.h:1653
void PushBack(BasicMultiBuf< kOtherProperties... > &&mb)
Definition: multibuf.h:1646
static constexpr bool is_layerable()
Returns whether additional views can be layered on the MultiBuf.
Definition: multibuf.h:196
void SealTopLayer()
Definition: multibuf.h:907
Result< Instance > PopFrontFragment()
Definition: multibuf.h:1699
Result< const_iterator > Discard(const_iterator pos, size_t size)
Definition: multibuf.h:690
constexpr bool empty() const
Definition: multibuf.h:321
void Insert(const_iterator pos, const T &bytes)
Definition: multibuf.h:1585
void TruncateTopLayer(size_t length)
Definition: multibuf.h:937
ConstByteSpan Get(ByteSpan copy, size_t offset=0) const
Definition: multibuf.h:782
void Clear()
Definition: multibuf.h:811
bool TryReserveForInsert(const_iterator pos, const BasicMultiBuf< kOtherProperties... > &mb)
Definition: multibuf.h:1566
bool IsRemovable(const_iterator pos, size_t size) const
Definition: multibuf.h:630
SharedPtr< value_type[]> Share(const_iterator pos)
Definition: multibuf.h:1723
void SetTopLayer(ConstByteSpan src)
Definition: multibuf.h:950
bool TryReserveChunks(size_t num_chunks)
Definition: multibuf.h:422
void Insert(const_iterator pos, BasicMultiBuf< kOtherProperties... > &&mb)
Definition: multibuf.h:1576
constexpr Observer * observer() const
Definition: multibuf.h:827
void set_observer(Observer *observer)
Definition: multibuf.h:839
void UnsealTopLayer()
Definition: multibuf.h:915
bool IsShareable(const_iterator pos) const
Definition: multibuf.h:720
Result< Instance > Remove(const_iterator pos, size_t size)
Definition: multibuf.h:1689
bool TryReserveLayers(size_t num_layers, size_t num_chunks=1)
Definition: multibuf.h:875
bool TryReserveForInsert(const_iterator pos)
Definition: multibuf.h:1560
size_type NumFragments() const
Definition: multibuf.h:853
size_t CopyFrom(ConstByteSpan src, size_t offset=0)
Definition: multibuf.h:760
bool TryReserveForPushBack()
Definition: multibuf.h:1640
bool AddLayer(size_t offset, size_t length=dynamic_extent)
Definition: multibuf.h:899
static constexpr bool is_const()
Returns whether the MultiBuf data is immutable.
Definition: multibuf.h:191
size_t CopyTo(ByteSpan dst, size_t offset=0) const
Definition: multibuf.h:748
bool TryReserveForPushBack(const BasicMultiBuf< kOtherProperties... > &mb)
Definition: multibuf.h:1633
auto Visit(Visitor visitor, ByteSpan copy, size_t offset)
Definition: multibuf.h:802
constexpr bool at_capacity() const
Definition: multibuf.h:327
UniquePtr< value_type[]> Release(const_iterator pos)
Definition: multibuf.h:1709
Definition: observer.h:29
Definition: byte_iterator.h:39
Base class for ranges of chunks.
Definition: chunks.h:33
Definition: multibuf.h:1021
Definition: multibuf.h:1468
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
Result(T value) -> Result< T >
Deduction guide to allow Result(v) rather than Result<T>(v).