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/chunks.h"
31#include "pw_multibuf/internal/byte_iterator.h"
32#include "pw_multibuf/internal/entry.h"
33#include "pw_multibuf/observer.h"
34#include "pw_multibuf/properties.h"
82namespace multibuf::internal {
206 using size_type =
typename Deque::size_type;
207 using difference_type =
typename Deque::difference_type;
210 using const_iterator =
212 using pointer = iterator::pointer;
213 using const_pointer = const_iterator::pointer;
214 using reference = iterator::reference;
215 using const_reference = const_iterator::reference;
216 using value_type = std::conditional_t<
is_const(),
217 const_iterator::value_type,
218 iterator::value_type>;
247 InvalidCopyOrMove<>();
250 BasicMultiBuf& operator=(
const BasicMultiBuf&) { InvalidCopyOrMove<>(); }
253 BasicMultiBuf& operator=(
const BasicMultiBuf<kOtherProperties...>&) {
254 InvalidCopyOrMove<>();
257 BasicMultiBuf(BasicMultiBuf&&) { InvalidCopyOrMove<>(); }
259 BasicMultiBuf& operator=(BasicMultiBuf&&) { InvalidCopyOrMove<>(); }
263 template <
typename OtherMultiBuf>
264 constexpr OtherMultiBuf& as() & {
265 multibuf::internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
266 return generic().
template as<OtherMultiBuf>();
269 template <
typename OtherMultiBuf>
270 constexpr const OtherMultiBuf& as() const& {
271 multibuf::internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
272 return generic().
template as<OtherMultiBuf>();
275 template <
typename OtherMultiBuf>
276 constexpr OtherMultiBuf&& as() && {
277 multibuf::internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
278 return std::move(generic().
template as<OtherMultiBuf>());
281 template <
typename OtherMultiBuf>
282 constexpr const OtherMultiBuf&& as() const&& {
283 multibuf::internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
284 return std::move(generic().
template as<OtherMultiBuf>());
287 template <
typename OtherMultiBuf,
288 typename = multibuf::internal::EnableIfConvertible<BasicMultiBuf,
290 constexpr operator OtherMultiBuf&() & {
291 return as<OtherMultiBuf>();
294 template <
typename OtherMultiBuf,
295 typename = multibuf::internal::EnableIfConvertible<BasicMultiBuf,
297 constexpr operator const OtherMultiBuf&()
const& {
298 return as<OtherMultiBuf>();
301 template <
typename OtherMultiBuf,
302 typename = multibuf::internal::EnableIfConvertible<BasicMultiBuf,
304 constexpr operator OtherMultiBuf&&() && {
305 return std::move(as<OtherMultiBuf>());
308 template <
typename OtherMultiBuf,
309 typename = multibuf::internal::EnableIfConvertible<BasicMultiBuf,
311 constexpr operator const OtherMultiBuf&&()
const&& {
312 return std::move(as<OtherMultiBuf>());
323 constexpr size_t size()
const {
return generic().
size(); }
336 template <
bool kMutable = !is_const()>
337 std::enable_if_t<kMutable, reference> at(
size_t index) {
338 return *(begin() +
static_cast<int>(index));
340 const_reference at(
size_t index)
const {
341 return *(begin() +
static_cast<int>(index));
344 template <
bool kMutable = !is_const()>
345 std::enable_if_t<kMutable, reference> operator[](
size_t index) {
348 const_reference operator[](
size_t index)
const {
return at(index); }
362 template <
bool kMutable = !is_const()>
363 constexpr std::enable_if_t<kMutable, multibuf::Chunks<Deque>> Chunks() {
364 return generic().Chunks();
366 constexpr multibuf::ConstChunks<Deque> Chunks()
const {
367 return generic().ConstChunks();
369 constexpr multibuf::ConstChunks<Deque> ConstChunks()
const {
370 return generic().ConstChunks();
386 template <
bool kMutable = !is_const()>
387 constexpr std::enable_if_t<kMutable, iterator> begin() {
388 return generic().begin();
390 constexpr const_iterator begin()
const {
return cbegin(); }
391 constexpr const_iterator cbegin()
const {
return generic().cbegin(); }
404 template <
bool kMutable = !is_const()>
405 constexpr std::enable_if_t<kMutable, iterator> end() {
406 return generic().end();
408 constexpr const_iterator end()
const {
return cend(); }
409 constexpr const_iterator cend()
const {
return generic().cend(); }
439 bool IsCompatible(
const UniquePtr<
const std::byte[]>& bytes)
const {
452 bool IsCompatible(
const SharedPtr<std::byte[]>& bytes)
const {
455 bool IsCompatible(
const SharedPtr<
const std::byte[]>& bytes)
const {
495 int&... kExplicitGuard,
498 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>,
int>>
559 int&... kExplicitGuard,
562 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>,
int>>
576 Insert(pos, std::move(bytes), 0);
578 void Insert(const_iterator pos,
UniquePtr<
const std::byte[]>&& bytes) {
579 Insert(pos, std::move(bytes), 0);
595 void Insert(const_iterator pos,
596 UniquePtr<std::byte[]>&& bytes,
598 size_t length = dynamic_extent);
599 void Insert(const_iterator pos,
600 UniquePtr<
const std::byte[]>&& bytes,
602 size_t length = dynamic_extent);
615 void Insert(const_iterator pos,
const SharedPtr<std::byte[]>& bytes) {
618 void Insert(const_iterator pos,
const SharedPtr<
const std::byte[]>& bytes) {
635 void Insert(const_iterator pos,
636 const SharedPtr<std::byte[]>& bytes,
638 size_t length = dynamic_extent);
639 void Insert(const_iterator pos,
640 const SharedPtr<
const std::byte[]>& bytes,
642 size_t length = dynamic_extent);
664 int&... kExplicitGuard,
667 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>,
int>>
681 const UniquePtr<
const std::byte[]>& bytes);
695 const SharedPtr<
const std::byte[]>& bytes);
716 int&... kExplicitGuard,
719 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>,
int>>
750 void PushBack(UniquePtr<std::byte[]>&& bytes,
752 size_t length = dynamic_extent);
754 void PushBack(UniquePtr<
const std::byte[]>&& bytes,
756 size_t length = dynamic_extent);
769 void PushBack(
const SharedPtr<
const std::byte[]>& bytes) {
785 void PushBack(
const SharedPtr<std::byte[]>& bytes,
787 size_t length = dynamic_extent);
788 void PushBack(
const SharedPtr<
const std::byte[]>& bytes,
790 size_t length = dynamic_extent);
921 return generic().
CopyTo(dst, offset);
934 "`CopyFrom` may only be called on mutable MultiBufs");
935 return generic().
CopyFrom(src, offset);
955 return generic().
Get(
copy, offset);
973 template <
int&... kExplicitGuard,
typename Visitor>
975 return visitor(
Get(
copy, offset));
993 "`observer` may only be called on observable MultiBufs");
994 return generic().observer_;
1005 "`set_observer` may only be called on observable MultiBufs");
1019 "`NumFragments` may only be called on layerable MultiBufs");
1028 "`NumLayers` may only be called on layerable MultiBufs");
1040 size_t num_chunks = 1) {
1063 [[nodiscard]]
bool AddLayer(
size_t offset,
size_t length = dynamic_extent) {
1065 "`AddLayer` may only be called on layerable MultiBufs");
1066 return generic().
AddLayer(offset, length);
1073 "`SealTopLayer` may only be called on layerable MultiBufs");
1081 "`UnsealTopLayer` may only be called on layerable MultiBufs");
1089 "`IsTopLayerSealed` may only be called on layerable MultiBufs");
1104 "`TruncateTopLayer` may only be called on layerable MultiBufs");
1116 "`SetTopLayer` may only be called on mutable, layerable "
1118 PW_ASSERT(src.size() <=
size());
1133 "`PopLayer` may only be called on layerable MultiBufs");
1138 constexpr BasicMultiBuf() { multibuf::internal::PropertiesAreValid(); }
1141 template <
bool kVal
idCopyOrMove = false>
1142 static constexpr void InvalidCopyOrMove() {
1143 static_assert(kValidCopyOrMove,
1144 "Only copies and moves from `BasicMultiBuf<...>::Instance`"
1145 "to `BasicMultiBuf<...>&` or another "
1146 "`BasicMultiBuf<...>::Instance` are valid.");
1150 friend class BasicMultiBuf;
1152 constexpr GenericMultiBuf&
generic() {
1153 return static_cast<GenericMultiBuf&
>(*this);
1155 constexpr const GenericMultiBuf&
generic()
const {
1156 return static_cast<const GenericMultiBuf&
>(*this);
1164namespace multibuf::internal {
1184 Property::kLayerable,
1185 Property::kObservable> {
1187 using ControlBlock = allocator::internal::ControlBlock;
1209 *
this = std::move(other);
1215 friend class ::pw::BasicMultiBuf;
1222 : deque_(allocator) {}
1224 template <
typename MultiBufType>
1225 constexpr MultiBufType& as() {
1229 template <
typename MultiBufType>
1230 constexpr const MultiBufType& as()
const {
1237 constexpr bool empty()
const {
return deque_.empty(); }
1240 constexpr size_t size()
const {
1241 return static_cast<size_t>(cend() - cbegin());
1245 constexpr bool has_deallocator()
const {
1246 return memory_tag_ == MemoryTag::kDeallocator || has_control_block();
1250 constexpr bool has_control_block()
const {
1251 return memory_tag_ == MemoryTag::kControlBlock;
1277 bool IsCompatible(
const Deallocator* other)
const;
1278 bool IsCompatible(
const ControlBlock* other)
const;
1281 [[nodiscard]]
bool TryReserveChunks(
size_t num_chunks);
1287 [[nodiscard]]
bool TryReserveForInsert(
const_iterator pos,
size_t size);
1293 const ControlBlock* control_block);
1309 ControlBlock* control_block);
1313 [[nodiscard]]
bool IsRemovable(
const_iterator pos,
size_t size)
const;
1337 size_t CopyTo(
ByteSpan dst,
size_t offset)
const;
1351 size_type NumFragments()
const;
1354 constexpr size_type NumLayers()
const {
return depth_ - 1; }
1357 [[nodiscard]]
bool TryReserveLayers(
size_t num_layers,
size_t num_chunks = 1);
1360 [[nodiscard]]
bool AddLayer(
size_t offset,
size_t length = dynamic_extent);
1363 void SealTopLayer();
1366 void UnsealTopLayer();
1369 void TruncateTopLayer(
size_t length);
1383 static size_t CheckRange(
size_t offset,
size_t length,
size_t size);
1386 constexpr std::byte* GetData(size_type index)
const {
1387 return deque_[index].data;
1392 constexpr bool IsOwned(size_type index)
const {
1393 return deque_[index + 1].base_view.owned;
1398 constexpr bool IsShared(size_type index)
const {
1399 return deque_[index + 1].base_view.shared;
1403 constexpr bool IsSealed(size_type index)
const {
1404 return depth_ == 2 ? false : deque_[index + depth_ - 1].view.sealed;
1409 constexpr bool IsBoundary(size_type index)
const {
1410 return depth_ == 2 ? true : deque_[index + depth_ - 1].view.boundary;
1416 constexpr size_type GetOffset(size_type index, uint16_t layer)
const {
1417 return layer == 1 ? deque_[index + 1].base_view.offset
1418 : deque_[index + layer].view.offset;
1422 constexpr size_type GetOffset(size_type index)
const {
1423 return GetOffset(index, NumLayers());
1428 constexpr size_type GetRelativeOffset(size_type index)
const {
1429 uint16_t layer = NumLayers();
1431 return GetOffset(index, layer);
1433 return GetOffset(index, layer) - GetOffset(index, layer - 1);
1437 constexpr size_type GetLength(size_type index)
const {
1438 return depth_ == 2 ? deque_[index + 1].base_view.length
1439 : deque_[index + depth_ - 1].view.length;
1443 constexpr ByteSpan GetView(size_type index)
const {
1444 return ByteSpan(GetData(index) + GetOffset(index), GetLength(index));
1454 ControlBlock* GetControlBlock()
const;
1457 void SetControlBlock(ControlBlock* control_block);
1463 void ClearMemoryContext();
1468 std::pair<size_type, size_type> GetIndexAndOffset(
const_iterator pos)
const;
1475 bool TryReserveEntries(
const_iterator pos, size_type num_entries);
1476 bool TryReserveEntries(size_type num_entries,
bool split =
false);
1481 size_type InsertEntries(
const_iterator pos, size_type num_entries);
1499 void SplitBase(size_type index,
Deque& out_deque, size_type out_index);
1506 void SplitBefore(size_type index,
1509 size_type out_index);
1513 void SplitBefore(size_type index, size_type split);
1520 void SplitAfter(size_type index,
1523 size_type out_index);
1527 void SplitAfter(size_type index, size_type split);
1562 size_type FindShared(size_type index, size_type start);
1566 size_t CopyToImpl(
ByteSpan dst,
size_t offset, size_type start)
const;
1569 [[nodiscard]]
bool IsTopLayerSealed()
const;
1573 void SetLayer(
size_t offset,
size_t length);
1594 size_type depth_ = 2;
1612 enum class MemoryTag : uint8_t {
1616 } memory_tag_ = MemoryTag::kEmpty;
1618 union MemoryContext {
1620 ControlBlock* control_block;
1621 } memory_context_ = {.deallocator =
nullptr};
1647template <
typename MultiBufType>
1670 constexpr Instance(MultiBufType&& mb)
1673 constexpr Instance& operator=(MultiBufType&& mb) {
1681 internal::AssertIsConvertible<
BasicMultiBuf<kProperties...>,
1687 internal::AssertIsConvertible<
BasicMultiBuf<kProperties...>,
1693 constexpr MultiBufType* operator->() {
return &base_.as<MultiBufType>(); }
1694 constexpr const MultiBufType* operator->()
const {
1695 return &base_.as<MultiBufType>();
1698 constexpr MultiBufType& operator*() & {
return base_.as<MultiBufType>(); }
1699 constexpr const MultiBufType& operator*()
const& {
1700 return base_.as<MultiBufType>();
1703 constexpr MultiBufType&& operator*() && {
1704 return std::move(base_.as<MultiBufType>());
1706 constexpr const MultiBufType&& operator*()
const&& {
1707 return std::move(base_.as<MultiBufType>());
1710 constexpr operator MultiBufType&() & {
return base_.as<MultiBufType>(); }
1711 constexpr operator const MultiBufType&()
const& {
1712 return base_.as<MultiBufType>();
1715 constexpr operator MultiBufType&&() && {
1716 return std::move(base_.as<MultiBufType>());
1718 constexpr operator const MultiBufType&&()
const&& {
1719 return std::move(base_.as<MultiBufType>());
1725 template <
bool kMoveOnly = false>
1726 static constexpr void MoveOnly() {
1727 static_assert(kMoveOnly,
1728 "Instances can only be created from existing MultiBufs using "
1729 "move-construction or move-assignment.");
1743 multibuf::internal::AssertIsConvertible<
BasicMultiBuf<kOtherProperties...>,
1745 return generic().TryReserveForInsert(pos,
1750template <
int&... kExplicitGuard,
typename T,
typename>
1753 using data_ptr_type =
decltype(std::data(std::declval<T&>()));
1754 static_assert(std::is_same_v<data_ptr_type, std::byte*> || is_const(),
1755 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1756 return generic().TryReserveForInsert(pos, bytes.size());
1761 const_iterator pos,
const UniquePtr<std::byte[]>& bytes) {
1762 return generic().TryReserveForInsert(pos, bytes.size(), bytes.deallocator());
1767 const_iterator pos,
const UniquePtr<
const std::byte[]>& bytes) {
1768 static_assert(is_const(),
1769 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1770 return generic().TryReserveForInsert(pos, bytes.size(), bytes.deallocator());
1775 const_iterator pos,
const SharedPtr<std::byte[]>& bytes) {
1776 return generic().TryReserveForInsert(
1777 pos, bytes.size(), bytes.control_block());
1782 const_iterator pos,
const SharedPtr<
const std::byte[]>& bytes) {
1783 static_assert(is_const(),
1784 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1785 return generic().TryReserveForInsert(
1786 pos, bytes.size(), bytes.control_block());
1793 multibuf::internal::AssertIsConvertible<
BasicMultiBuf<kOtherProperties...>,
1795 generic().Insert(pos, std::move(mb.generic()));
1799template <
int&... kExplicitGuard,
typename T,
typename>
1801 using data_ptr_type =
decltype(std::data(std::declval<T&>()));
1802 static_assert(std::is_same_v<data_ptr_type, std::byte*> || is_const(),
1803 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1804 generic().Insert(pos, bytes);
1813 generic().Insert(pos, chunk, offset, length, bytes.deallocator());
1819 UniquePtr<
const std::byte[]>&& bytes,
1822 static_assert(is_const(),
1823 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1824 ConstByteSpan chunk(bytes.get(), bytes.size());
1825 generic().Insert(pos, chunk, offset, length, bytes.deallocator());
1831 const SharedPtr<std::byte[]>& bytes,
1834 ConstByteSpan chunk(bytes.get(), bytes.size());
1835 generic().Insert(pos, chunk, offset, length, bytes.control_block());
1841 const SharedPtr<
const std::byte[]>& bytes,
1844 static_assert(is_const(),
1845 "Cannot `Insert` read-only bytes into mutable MultiBuf");
1846 ConstByteSpan chunk(bytes.get(), bytes.size());
1847 generic().Insert(pos, chunk, offset, length, bytes.control_block());
1854 return TryReserveForInsert(end(), mb);
1858template <
int&... kExplicitGuard,
typename T,
typename>
1860 using data_ptr_type =
decltype(std::data(std::declval<T&>()));
1861 static_assert(std::is_same_v<data_ptr_type, std::byte*> || is_const(),
1862 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1863 return TryReserveForInsert(end(), bytes);
1869 return TryReserveForInsert(end(), std::move(bytes));
1874 const UniquePtr<
const std::byte[]>& bytes) {
1875 static_assert(is_const(),
1876 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1877 return TryReserveForInsert(end(), std::move(bytes));
1882 const SharedPtr<std::byte[]>& bytes) {
1883 return TryReserveForInsert(end(), bytes);
1888 const SharedPtr<
const std::byte[]>& bytes) {
1889 static_assert(is_const(),
1890 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1891 return TryReserveForInsert(end(), bytes);
1898 Insert(end(), std::move(mb));
1902template <
int&... kExplicitGuard,
typename T,
typename>
1904 using data_ptr_type =
decltype(std::data(std::declval<T&>()));
1905 static_assert(std::is_same_v<data_ptr_type, std::byte*> || is_const(),
1906 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1907 Insert(end(), bytes);
1914 Insert(end(), std::move(bytes), offset, length);
1919 UniquePtr<
const std::byte[]>&& bytes,
size_t offset,
size_t length) {
1920 static_assert(is_const(),
1921 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1922 Insert(end(), std::move(bytes), offset, length);
1927 const SharedPtr<std::byte[]>& bytes,
size_t offset,
size_t length) {
1928 Insert(end(), bytes, offset, length);
1933 const SharedPtr<
const std::byte[]>& bytes,
size_t offset,
size_t length) {
1934 static_assert(is_const(),
1935 "Cannot `PushBack` read-only bytes into mutable MultiBuf");
1936 Insert(end(), bytes, offset, length);
1940Result<multibuf::internal::Instance<BasicMultiBuf<kProperties...>>>
1942 auto result =
generic().Remove(pos, size);
1944 return result.status();
1946 return Instance(std::move(*result));
1952 auto result =
generic().PopFrontFragment();
1954 return result.status();
1956 return Instance(std::move(*result));
1963 if constexpr (is_const()) {
1977 generic().GetControlBlock());
Definition: allocator.h:36
bool IsTopLayerSealed()
Returns whether the "sealed" flag is set in the top layer.
Definition: multibuf_v2.h:1086
bool AddLayer(size_t offset, size_t length=dynamic_extent)
Definition: multibuf_v2.h:1063
void Insert(const_iterator pos, BasicMultiBuf< kOtherProperties... > &&mb)
Definition: multibuf_v2.h:1791
bool TryReserveForPushBack(const T &bytes)
Definition: multibuf_v2.h:1859
void SealTopLayer()
Definition: multibuf_v2.h:1071
static constexpr bool is_layerable()
Returns whether additional views can be layered on the MultiBuf.
Definition: multibuf_v2.h:197
void UnsealTopLayer()
Definition: multibuf_v2.h:1079
SharedPtr< value_type[]> Share(const_iterator pos)
Definition: multibuf_v2.h:1975
void Insert(const_iterator pos, const T &bytes)
Definition: multibuf_v2.h:1800
void TruncateTopLayer(size_t length)
Definition: multibuf_v2.h:1101
void SetTopLayer(ConstByteSpan src)
Definition: multibuf_v2.h:1114
void PushBack(const T &bytes)
Definition: multibuf_v2.h:1903
static constexpr bool is_const()
Returns whether the MultiBuf data is immutable.
Definition: multibuf_v2.h:192
void PopLayer()
Definition: multibuf_v2.h:1131
void Clear()
Definition: multibuf_v2.h:983
ConstByteSpan Get(ByteSpan copy, size_t offset=0) const
Definition: multibuf_v2.h:954
void set_observer(multibuf::Observer *observer)
Definition: multibuf_v2.h:1003
UniquePtr< value_type[]> Release(const_iterator pos)
Definition: multibuf_v2.h:1961
bool TryReserveChunks(size_t num_chunks)
Definition: multibuf_v2.h:462
size_t CopyTo(ByteSpan dst, size_t offset=0) const
Definition: multibuf_v2.h:920
size_t CopyFrom(ConstByteSpan src, size_t offset=0)
Definition: multibuf_v2.h:932
constexpr multibuf::Observer * observer() const
Definition: multibuf_v2.h:991
bool TryReserveForPushBack(const BasicMultiBuf< kOtherProperties... > &mb)
Definition: multibuf_v2.h:1852
Result< Instance > PopFrontFragment()
Definition: multibuf_v2.h:1951
Result< Instance > Remove(const_iterator pos, size_t size)
Definition: multibuf_v2.h:1941
static constexpr bool is_observable()
Returns whether an observer can be registered on the MultiBuf.
Definition: multibuf_v2.h:202
constexpr size_t size() const
Definition: multibuf_v2.h:323
bool TryReserveLayers(size_t num_layers, size_t num_chunks=1)
Definition: multibuf_v2.h:1039
bool IsShareable(const_iterator pos) const
Definition: multibuf_v2.h:892
constexpr size_type NumLayers() const
Definition: multibuf_v2.h:1026
constexpr bool empty() const
Definition: multibuf_v2.h:319
Result< const_iterator > Discard(const_iterator pos, size_t size)
Definition: multibuf_v2.h:862
bool IsReleasable(const_iterator pos) const
Definition: multibuf_v2.h:870
bool IsRemovable(const_iterator pos, size_t size) const
Definition: multibuf_v2.h:802
bool TryReserveForInsert(const_iterator pos, const BasicMultiBuf< kOtherProperties... > &mb)
Definition: multibuf_v2.h:1741
size_type NumFragments() const
Definition: multibuf_v2.h:1017
void PushBack(BasicMultiBuf< kOtherProperties... > &&mb)
Definition: multibuf_v2.h:1896
auto Visit(Visitor visitor, ByteSpan copy, size_t offset)
Definition: multibuf_v2.h:974
bool TryReserveForInsert(const_iterator pos, const T &bytes)
Definition: multibuf_v2.h:1751
bool IsCompatible(const BasicMultiBuf &mb) const
Definition: multibuf_v2.h:423
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: dynamic_deque.h:60
Definition: shared_ptr.h:59
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
Definition: observer.h:29
Definition: byte_iterator.h:44
Definition: multibuf_v2.h:1185
Definition: multibuf_v2.h:1648
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:348
Property
Basic properties of a MultiBuf.
Definition: properties.h:25
Result(T value) -> Result< T >
Deduction guide to allow Result(v) rather than Result<T>(v).
The Pigweed namespace.
Definition: alignment.h:27