C/C++ API Reference
Loading...
Searching...
No Matches
multibuf_v2.h
1// Copyright 2025 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16// NOTE: MultiBuf version 2 is in a nearly stable state, but may still change.
17// The Pigweed team will announce breaking changes in the API. It is strongly
18// recommended to coordinate with the Pigweed team if you want to start using
19// this code.
20
21#include <cstddef>
22#include <cstdint>
23#include <numeric>
24#include <type_traits>
25
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"
35
36namespace pw {
37
38// Forward declarations.
39template <multibuf::Property...>
40class BasicMultiBuf;
41
43
44// Type aliases of the BasicMultiBuf interface types for each different
45// combination of propeties, listed here for easier discoverability.
46
49
52
56
61
65
70
75
81
82namespace multibuf::internal {
83
84class GenericMultiBuf;
85
86template <typename>
87class Instance;
88
89} // namespace multibuf::internal
90
184template <multibuf::Property... kProperties>
186 protected:
189
190 public:
192 [[nodiscard]] static constexpr bool is_const() {
193 return ((kProperties == multibuf::Property::kConst) || ...);
194 }
195
197 [[nodiscard]] static constexpr bool is_layerable() {
198 return ((kProperties == multibuf::Property::kLayerable) || ...);
199 }
200
202 [[nodiscard]] static constexpr bool is_observable() {
203 return ((kProperties == multibuf::Property::kObservable) || ...);
204 }
205
206 using size_type = typename Deque::size_type;
207 using difference_type = typename Deque::difference_type;
208 using iterator =
209 multibuf::internal::ByteIterator<size_type, /*kIsConst=*/false>;
210 using const_iterator =
211 multibuf::internal::ByteIterator<size_type, /*kIsConst=*/true>;
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>;
219
240
241 // Interfaces are not copyable or movable; copy and move `Instance`s instead.
242
243 BasicMultiBuf(const BasicMultiBuf&) { InvalidCopyOrMove<>(); }
244
245 template <multibuf::Property... kOtherProperties>
247 InvalidCopyOrMove<>();
248 }
249
250 BasicMultiBuf& operator=(const BasicMultiBuf&) { InvalidCopyOrMove<>(); }
251
252 template <multibuf::Property... kOtherProperties>
253 BasicMultiBuf& operator=(const BasicMultiBuf<kOtherProperties...>&) {
254 InvalidCopyOrMove<>();
255 }
256
257 BasicMultiBuf(BasicMultiBuf&&) { InvalidCopyOrMove<>(); }
258
259 BasicMultiBuf& operator=(BasicMultiBuf&&) { InvalidCopyOrMove<>(); }
260
261 // Conversions
262
263 template <typename OtherMultiBuf>
264 constexpr OtherMultiBuf& as() & {
265 multibuf::internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
266 return generic().template as<OtherMultiBuf>();
267 }
268
269 template <typename OtherMultiBuf>
270 constexpr const OtherMultiBuf& as() const& {
271 multibuf::internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
272 return generic().template as<OtherMultiBuf>();
273 }
274
275 template <typename OtherMultiBuf>
276 constexpr OtherMultiBuf&& as() && {
277 multibuf::internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
278 return std::move(generic().template as<OtherMultiBuf>());
279 }
280
281 template <typename OtherMultiBuf>
282 constexpr const OtherMultiBuf&& as() const&& {
283 multibuf::internal::AssertIsConvertible<BasicMultiBuf, OtherMultiBuf>();
284 return std::move(generic().template as<OtherMultiBuf>());
285 }
286
287 template <typename OtherMultiBuf,
288 typename = multibuf::internal::EnableIfConvertible<BasicMultiBuf,
289 OtherMultiBuf>>
290 constexpr operator OtherMultiBuf&() & {
291 return as<OtherMultiBuf>();
292 }
293
294 template <typename OtherMultiBuf,
295 typename = multibuf::internal::EnableIfConvertible<BasicMultiBuf,
296 OtherMultiBuf>>
297 constexpr operator const OtherMultiBuf&() const& {
298 return as<OtherMultiBuf>();
299 }
300
301 template <typename OtherMultiBuf,
302 typename = multibuf::internal::EnableIfConvertible<BasicMultiBuf,
303 OtherMultiBuf>>
304 constexpr operator OtherMultiBuf&&() && {
305 return std::move(as<OtherMultiBuf>());
306 }
307
308 template <typename OtherMultiBuf,
309 typename = multibuf::internal::EnableIfConvertible<BasicMultiBuf,
310 OtherMultiBuf>>
311 constexpr operator const OtherMultiBuf&&() const&& {
312 return std::move(as<OtherMultiBuf>());
313 }
314
315 // Accessors
316
319 constexpr bool empty() const { return generic().empty(); }
320
323 constexpr size_t size() const { return generic().size(); }
324
336 template <bool kMutable = !is_const()>
337 std::enable_if_t<kMutable, reference> at(size_t index) {
338 return *(begin() + static_cast<int>(index));
339 }
340 const_reference at(size_t index) const {
341 return *(begin() + static_cast<int>(index));
342 }
343
344 template <bool kMutable = !is_const()>
345 std::enable_if_t<kMutable, reference> operator[](size_t index) {
346 return at(index);
347 }
348 const_reference operator[](size_t index) const { return at(index); }
350
362 template <bool kMutable = !is_const()>
363 constexpr std::enable_if_t<kMutable, multibuf::Chunks<Deque>> Chunks() {
364 return generic().Chunks();
365 }
366 constexpr multibuf::ConstChunks<Deque> Chunks() const {
367 return generic().ConstChunks();
368 }
369 constexpr multibuf::ConstChunks<Deque> ConstChunks() const {
370 return generic().ConstChunks();
371 }
373
374 // Iterators.
375
386 template <bool kMutable = !is_const()>
387 constexpr std::enable_if_t<kMutable, iterator> begin() {
388 return generic().begin();
389 }
390 constexpr const_iterator begin() const { return cbegin(); }
391 constexpr const_iterator cbegin() const { return generic().cbegin(); }
393
404 template <bool kMutable = !is_const()>
405 constexpr std::enable_if_t<kMutable, iterator> end() {
406 return generic().end();
407 }
408 constexpr const_iterator end() const { return cend(); }
409 constexpr const_iterator cend() const { return generic().cend(); }
411
412 // Other methods
413
423 bool IsCompatible(const BasicMultiBuf& mb) const {
424 return generic().IsCompatible(mb.generic());
425 }
426
436 bool IsCompatible(const UniquePtr<std::byte[]>& bytes) const {
437 return generic().IsCompatible(bytes.deallocator());
438 }
439 bool IsCompatible(const UniquePtr<const std::byte[]>& bytes) const {
440 return generic().IsCompatible(bytes.deallocator());
441 }
443
452 bool IsCompatible(const SharedPtr<std::byte[]>& bytes) const {
453 return generic().IsCompatible(bytes.control_block());
454 }
455 bool IsCompatible(const SharedPtr<const std::byte[]>& bytes) const {
456 return generic().IsCompatible(bytes.control_block());
457 }
459
462 [[nodiscard]] bool TryReserveChunks(size_t num_chunks) {
463 return generic().TryReserveChunks(num_chunks);
464 }
465
466 // Mutators
467
479 template <multibuf::Property... kOtherProperties>
480 [[nodiscard]] bool TryReserveForInsert(
482
494 template <
495 int&... kExplicitGuard,
496 typename T,
497 typename =
498 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>, int>>
499 [[nodiscard]] bool TryReserveForInsert(const_iterator pos, const T& bytes);
500
514 [[nodiscard]] bool TryReserveForInsert(const_iterator pos,
515 const UniquePtr<std::byte[]>& bytes);
516 [[nodiscard]] bool TryReserveForInsert(
517 const_iterator pos, const UniquePtr<const std::byte[]>& bytes);
519
533 [[nodiscard]] bool TryReserveForInsert(const_iterator pos,
534 const SharedPtr<std::byte[]>& bytes);
535 [[nodiscard]] bool TryReserveForInsert(
536 const_iterator pos, const SharedPtr<const std::byte[]>& bytes);
538
547 template <multibuf::Property... kOtherProperties>
549
558 template <
559 int&... kExplicitGuard,
560 typename T,
561 typename =
562 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>, int>>
563 void Insert(const_iterator pos, const T& bytes);
564
575 void Insert(const_iterator pos, UniquePtr<std::byte[]>&& bytes) {
576 Insert(pos, std::move(bytes), 0);
577 }
578 void Insert(const_iterator pos, UniquePtr<const std::byte[]>&& bytes) {
579 Insert(pos, std::move(bytes), 0);
580 }
582
595 void Insert(const_iterator pos,
596 UniquePtr<std::byte[]>&& bytes,
597 size_t offset,
598 size_t length = dynamic_extent);
599 void Insert(const_iterator pos,
600 UniquePtr<const std::byte[]>&& bytes,
601 size_t offset,
602 size_t length = dynamic_extent);
604
615 void Insert(const_iterator pos, const SharedPtr<std::byte[]>& bytes) {
616 Insert(pos, bytes, 0);
617 }
618 void Insert(const_iterator pos, const SharedPtr<const std::byte[]>& bytes) {
619 Insert(pos, bytes, 0);
620 }
622
635 void Insert(const_iterator pos,
636 const SharedPtr<std::byte[]>& bytes,
637 size_t offset,
638 size_t length = dynamic_extent);
639 void Insert(const_iterator pos,
640 const SharedPtr<const std::byte[]>& bytes,
641 size_t offset,
642 size_t length = dynamic_extent);
644
652 template <multibuf::Property... kOtherProperties>
653 [[nodiscard]] bool TryReserveForPushBack(
655
663 template <
664 int&... kExplicitGuard,
665 typename T,
666 typename =
667 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>, int>>
668 [[nodiscard]] bool TryReserveForPushBack(const T& bytes);
669
679 [[nodiscard]] bool TryReserveForPushBack(const UniquePtr<std::byte[]>& bytes);
680 [[nodiscard]] bool TryReserveForPushBack(
681 const UniquePtr<const std::byte[]>& bytes);
683
693 [[nodiscard]] bool TryReserveForPushBack(const SharedPtr<std::byte[]>& bytes);
694 [[nodiscard]] bool TryReserveForPushBack(
695 const SharedPtr<const std::byte[]>& bytes);
697
705 template <multibuf::Property... kOtherProperties>
707
715 template <
716 int&... kExplicitGuard,
717 typename T,
718 typename =
719 std::enable_if_t<std::is_constructible_v<ConstByteSpan, T>, int>>
720 void PushBack(const T& bytes);
721
731 void PushBack(UniquePtr<std::byte[]>&& bytes) {
732 PushBack(std::move(bytes), 0);
733 }
734 void PushBack(UniquePtr<const std::byte[]>&& bytes) {
735 PushBack(std::move(bytes), 0);
736 }
738
750 void PushBack(UniquePtr<std::byte[]>&& bytes,
751 size_t offset,
752 size_t length = dynamic_extent);
753
754 void PushBack(UniquePtr<const std::byte[]>&& bytes,
755 size_t offset,
756 size_t length = dynamic_extent);
758
768 void PushBack(const SharedPtr<std::byte[]>& bytes) { PushBack(bytes, 0); }
769 void PushBack(const SharedPtr<const std::byte[]>& bytes) {
770 PushBack(bytes, 0);
771 }
773
785 void PushBack(const SharedPtr<std::byte[]>& bytes,
786 size_t offset,
787 size_t length = dynamic_extent);
788 void PushBack(const SharedPtr<const std::byte[]>& bytes,
789 size_t offset,
790 size_t length = dynamic_extent);
792
802 [[nodiscard]] bool IsRemovable(const_iterator pos, size_t size) const {
803 return generic().IsRemovable(pos, size);
804 }
805
826
838
839 // clang-format off
861 // clang-format on
863 return generic().Discard(pos, size);
864 }
865
870 [[nodiscard]] bool IsReleasable(const_iterator pos) const {
871 return generic().IsReleasable(pos);
872 }
873
887
892 [[nodiscard]] bool IsShareable(const_iterator pos) const {
893 return generic().IsShareable(pos);
894 }
895
911
920 size_t CopyTo(ByteSpan dst, size_t offset = 0) const {
921 return generic().CopyTo(dst, offset);
922 }
923
932 size_t CopyFrom(ConstByteSpan src, size_t offset = 0) {
933 static_assert(!is_const(),
934 "`CopyFrom` may only be called on mutable MultiBufs");
935 return generic().CopyFrom(src, offset);
936 }
937
954 ConstByteSpan Get(ByteSpan copy, size_t offset = 0) const {
955 return generic().Get(copy, offset);
956 }
957
973 template <int&... kExplicitGuard, typename Visitor>
974 auto Visit(Visitor visitor, ByteSpan copy, size_t offset) {
975 return visitor(Get(copy, offset));
976 }
977
983 void Clear() { generic().Clear(); }
984
985 // Observable methods.
986
991 constexpr multibuf::Observer* observer() const {
992 static_assert(is_observable(),
993 "`observer` may only be called on observable MultiBufs");
994 return generic().observer_;
995 }
996
1004 static_assert(is_observable(),
1005 "`set_observer` may only be called on observable MultiBufs");
1006 generic().observer_ = observer;
1007 }
1008
1009 // Layerable methods.
1010
1017 size_type NumFragments() const {
1018 static_assert(is_layerable(),
1019 "`NumFragments` may only be called on layerable MultiBufs");
1020 return generic().NumFragments();
1021 }
1022
1026 constexpr size_type NumLayers() const {
1027 static_assert(is_layerable(),
1028 "`NumLayers` may only be called on layerable MultiBufs");
1029 return generic().NumLayers();
1030 }
1031
1039 [[nodiscard]] bool TryReserveLayers(size_t num_layers,
1040 size_t num_chunks = 1) {
1041 return generic().TryReserveLayers(num_layers, num_chunks);
1042 }
1043
1063 [[nodiscard]] bool AddLayer(size_t offset, size_t length = dynamic_extent) {
1064 static_assert(is_layerable(),
1065 "`AddLayer` may only be called on layerable MultiBufs");
1066 return generic().AddLayer(offset, length);
1067 }
1068
1072 static_assert(is_layerable(),
1073 "`SealTopLayer` may only be called on layerable MultiBufs");
1074 return generic().SealTopLayer();
1075 }
1076
1080 static_assert(is_layerable(),
1081 "`UnsealTopLayer` may only be called on layerable MultiBufs");
1082 return generic().UnsealTopLayer();
1083 }
1084
1086 [[nodiscard]] bool IsTopLayerSealed() {
1087 static_assert(
1088 is_layerable(),
1089 "`IsTopLayerSealed` may only be called on layerable MultiBufs");
1090 return generic().IsTopLayerSealed();
1091 }
1092
1101 void TruncateTopLayer(size_t length) {
1102 static_assert(
1103 is_layerable(),
1104 "`TruncateTopLayer` may only be called on layerable MultiBufs");
1105 generic().TruncateTopLayer(length);
1106 }
1107
1115 static_assert(!is_const() && is_layerable(),
1116 "`SetTopLayer` may only be called on mutable, layerable "
1117 "MultiBufs");
1118 PW_ASSERT(src.size() <= size());
1119 CopyFrom(src);
1120 TruncateTopLayer(src.size());
1121 }
1122
1131 void PopLayer() {
1132 static_assert(is_layerable(),
1133 "`PopLayer` may only be called on layerable MultiBufs");
1134 generic().PopLayer();
1135 }
1136
1137 protected:
1138 constexpr BasicMultiBuf() { multibuf::internal::PropertiesAreValid(); }
1139
1140 private:
1141 template <bool kValidCopyOrMove = 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.");
1147 }
1148
1149 template <multibuf::Property...>
1150 friend class BasicMultiBuf;
1151
1152 constexpr GenericMultiBuf& generic() {
1153 return static_cast<GenericMultiBuf&>(*this);
1154 }
1155 constexpr const GenericMultiBuf& generic() const {
1156 return static_cast<const GenericMultiBuf&>(*this);
1157 }
1158};
1159
1161
1163
1164namespace multibuf::internal {
1165
1166// A generic MultiBuf implementation that provides the functionality of any
1167// `BasicMultiBuf<kProperties>` type.
1168//
1169// This class should not be instantiated directly. Instead, use `Instance` as
1170// described below. This is the base class for all `Instance` types, and derives
1171// from every supported `BasicMultiBuf` type. It implements the MultiBuf
1172// behavior in one type, and allows for performing conversions from `Instance`s
1173// and `BasicMultiBuf`s to `BasicMultiBuf`s with different yet compatible
1174// propreties.
1176 : private BasicMultiBuf<>,
1183 private BasicMultiBuf<Property::kConst,
1184 Property::kLayerable,
1185 Property::kObservable> {
1186 private:
1187 using ControlBlock = allocator::internal::ControlBlock;
1188 using typename BasicMultiBuf<>::Deque;
1189
1190 public:
1191 using typename BasicMultiBuf<>::const_iterator;
1192 using typename BasicMultiBuf<>::const_pointer;
1193 using typename BasicMultiBuf<>::const_reference;
1194 using typename BasicMultiBuf<>::difference_type;
1195 using typename BasicMultiBuf<>::iterator;
1196 using typename BasicMultiBuf<>::pointer;
1197 using typename BasicMultiBuf<>::reference;
1198 using typename BasicMultiBuf<>::size_type;
1199
1200 ~GenericMultiBuf() { Clear(); }
1201
1202 // Not copyable.
1203 GenericMultiBuf(const GenericMultiBuf&) = delete;
1204 GenericMultiBuf& operator=(const GenericMultiBuf&) = delete;
1205
1206 // Movable.
1208 : GenericMultiBuf(other.deque_.get_allocator()) {
1209 *this = std::move(other);
1210 }
1211 GenericMultiBuf& operator=(GenericMultiBuf&& other);
1212
1213 private:
1214 template <::pw::multibuf::Property...>
1215 friend class ::pw::BasicMultiBuf;
1216
1217 template <typename>
1218 friend class Instance;
1219
1221 constexpr explicit GenericMultiBuf(Allocator& allocator)
1222 : deque_(allocator) {}
1223
1224 template <typename MultiBufType>
1225 constexpr MultiBufType& as() {
1226 return *this;
1227 }
1228
1229 template <typename MultiBufType>
1230 constexpr const MultiBufType& as() const {
1231 return *this;
1232 }
1233
1234 // Accessors.
1235
1237 constexpr bool empty() const { return deque_.empty(); }
1238
1240 constexpr size_t size() const {
1241 return static_cast<size_t>(cend() - cbegin());
1242 }
1243
1245 constexpr bool has_deallocator() const {
1246 return memory_tag_ == MemoryTag::kDeallocator || has_control_block();
1247 }
1248
1250 constexpr bool has_control_block() const {
1251 return memory_tag_ == MemoryTag::kControlBlock;
1252 }
1253
1254 // Iterators.
1255
1256 constexpr multibuf::Chunks<Deque> Chunks() {
1257 return multibuf::Chunks<Deque>(deque_, depth_);
1258 }
1259 constexpr multibuf::ConstChunks<Deque> ConstChunks() const {
1260 return multibuf::ConstChunks<Deque>(deque_, depth_);
1261 }
1262
1263 constexpr iterator begin() { return iterator(Chunks().begin(), 0); }
1264 constexpr const_iterator cbegin() const {
1265 return const_iterator(ConstChunks().cbegin(), 0);
1266 }
1267
1268 constexpr iterator end() { return iterator(Chunks().end(), 0); }
1269 constexpr const_iterator cend() const {
1270 return const_iterator(ConstChunks().cend(), 0);
1271 }
1272
1273 // Mutators.
1274
1276 bool IsCompatible(const GenericMultiBuf& other) const;
1277 bool IsCompatible(const Deallocator* other) const;
1278 bool IsCompatible(const ControlBlock* other) const;
1279
1281 [[nodiscard]] bool TryReserveChunks(size_t num_chunks);
1282
1285 [[nodiscard]] bool TryReserveForInsert(const_iterator pos,
1286 const GenericMultiBuf& mb);
1287 [[nodiscard]] bool TryReserveForInsert(const_iterator pos, size_t size);
1288 [[nodiscard]] bool TryReserveForInsert(const_iterator pos,
1289 size_t size,
1290 const Deallocator* deallocator);
1291 [[nodiscard]] bool TryReserveForInsert(const_iterator pos,
1292 size_t size,
1293 const ControlBlock* control_block);
1295
1298 void Insert(const_iterator pos, GenericMultiBuf&& mb);
1299 void Insert(const_iterator pos, ConstByteSpan bytes);
1300 void Insert(const_iterator pos,
1301 ConstByteSpan bytes,
1302 size_t offset,
1303 size_t length,
1304 Deallocator* deallocator);
1305 void Insert(const_iterator pos,
1306 ConstByteSpan bytes,
1307 size_t offset,
1308 size_t length,
1309 ControlBlock* control_block);
1311
1313 [[nodiscard]] bool IsRemovable(const_iterator pos, size_t size) const;
1314
1316 Result<GenericMultiBuf> Remove(const_iterator pos, size_t size);
1317
1319 Result<GenericMultiBuf> PopFrontFragment();
1320
1322 Result<const_iterator> Discard(const_iterator pos, size_t size);
1323
1325 [[nodiscard]] bool IsReleasable(const_iterator pos) const;
1326
1329
1331 [[nodiscard]] bool IsShareable(const_iterator pos) const;
1332
1334 std::byte* Share(const_iterator pos);
1335
1337 size_t CopyTo(ByteSpan dst, size_t offset) const;
1338
1340 size_t CopyFrom(ConstByteSpan src, size_t offset);
1341
1343 ConstByteSpan Get(ByteSpan copy, size_t offset) const;
1344
1346 void Clear();
1347
1348 // Layerable methods.
1349
1351 size_type NumFragments() const;
1352
1354 constexpr size_type NumLayers() const { return depth_ - 1; }
1355
1357 [[nodiscard]] bool TryReserveLayers(size_t num_layers, size_t num_chunks = 1);
1358
1360 [[nodiscard]] bool AddLayer(size_t offset, size_t length = dynamic_extent);
1361
1363 void SealTopLayer();
1364
1366 void UnsealTopLayer();
1367
1369 void TruncateTopLayer(size_t length);
1370
1372 void PopLayer();
1373
1374 // Implementation methods.
1375 //
1376 // These methods are used to implement the methods above, and should not be
1377 // called directly by BasicMultiBuf<>.
1378
1383 static size_t CheckRange(size_t offset, size_t length, size_t size);
1384
1386 constexpr std::byte* GetData(size_type index) const {
1387 return deque_[index].data;
1388 }
1389
1392 constexpr bool IsOwned(size_type index) const {
1393 return deque_[index + 1].base_view.owned;
1394 }
1395
1398 constexpr bool IsShared(size_type index) const {
1399 return deque_[index + 1].base_view.shared;
1400 }
1401
1403 constexpr bool IsSealed(size_type index) const {
1404 return depth_ == 2 ? false : deque_[index + depth_ - 1].view.sealed;
1405 }
1406
1409 constexpr bool IsBoundary(size_type index) const {
1410 return depth_ == 2 ? true : deque_[index + depth_ - 1].view.boundary;
1411 }
1412
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;
1419 }
1420
1422 constexpr size_type GetOffset(size_type index) const {
1423 return GetOffset(index, NumLayers());
1424 }
1425
1428 constexpr size_type GetRelativeOffset(size_type index) const {
1429 uint16_t layer = NumLayers();
1430 if (layer == 1) {
1431 return GetOffset(index, layer);
1432 }
1433 return GetOffset(index, layer) - GetOffset(index, layer - 1);
1434 }
1435
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;
1440 }
1441
1443 constexpr ByteSpan GetView(size_type index) const {
1444 return ByteSpan(GetData(index) + GetOffset(index), GetLength(index));
1445 }
1446
1448 Deallocator* GetDeallocator() const;
1449
1451 void SetDeallocator(Deallocator* deallocator);
1452
1454 ControlBlock* GetControlBlock() const;
1455
1457 void SetControlBlock(ControlBlock* control_block);
1458
1460 void CopyMemoryContext(const GenericMultiBuf& other);
1461
1463 void ClearMemoryContext();
1464
1468 std::pair<size_type, size_type> GetIndexAndOffset(const_iterator pos) const;
1469
1475 bool TryReserveEntries(const_iterator pos, size_type num_entries);
1476 bool TryReserveEntries(size_type num_entries, bool split = false);
1478
1481 size_type InsertEntries(const_iterator pos, size_type num_entries);
1482
1485 size_type Insert(const_iterator pos,
1486 ConstByteSpan bytes,
1487 size_t offset,
1488 size_t length);
1489
1499 void SplitBase(size_type index, Deque& out_deque, size_type out_index);
1500
1506 void SplitBefore(size_type index,
1507 size_type split,
1508 Deque& out_deque,
1509 size_type out_index);
1510
1513 void SplitBefore(size_type index, size_type split);
1514
1520 void SplitAfter(size_type index,
1521 size_type split,
1522 Deque& out_deque,
1523 size_type out_index);
1524
1527 void SplitAfter(size_type index, size_type split);
1528
1539 [[nodiscard]] bool TryReserveForRemove(const_iterator pos,
1540 size_t size,
1541 GenericMultiBuf* out);
1542
1547 void CopyRange(const_iterator pos, size_t size, GenericMultiBuf& out);
1548
1552 void ClearRange(const_iterator pos, size_t size);
1553
1558 void EraseRange(const_iterator pos, size_t size);
1559
1562 size_type FindShared(size_type index, size_type start);
1563
1566 size_t CopyToImpl(ByteSpan dst, size_t offset, size_type start) const;
1567
1569 [[nodiscard]] bool IsTopLayerSealed() const;
1570
1573 void SetLayer(size_t offset, size_t length);
1574
1575 // Describes the memory and views to that in a one-dimensional sequence.
1576 // Every `depth_`-th entry holds a pointer to memory, each entry for a given
1577 // offset less than `depth_` after that entry is a view that is part of the
1578 // same "layer" in the MultiBuf.
1579 //
1580 // This base type will always have 0 or 2 layers, but derived classes may add
1581 // more.
1582 //
1583 // For example, a MultiBuf that has had 3 `Chunk`s and two additional layers
1584 // added would have a `deque_` resembling the following:
1585 //
1586 // buffer 0: buffer 1: buffer 2:
1587 // layer 3: deque_[0x3].view deque_[0x7].view deque_[0xB].view
1588 // layer 2: deque_[0x2].view deque_[0x6].view deque_[0xA].view
1589 // layer 1: deque_[0x1].view deque_[0x5].view deque_[0x9].view
1590 // layer 0: deque_[0x0].data deque_[0x4].data deque_[0x8].data
1591 Deque deque_;
1592
1593 // Number of entries per chunk in this MultiBuf.
1594 size_type depth_ = 2;
1595
1612 enum class MemoryTag : uint8_t {
1613 kEmpty,
1614 kDeallocator,
1615 kControlBlock,
1616 } memory_tag_ = MemoryTag::kEmpty;
1617
1618 union MemoryContext {
1619 Deallocator* deallocator;
1620 ControlBlock* control_block;
1621 } memory_context_ = {.deallocator = nullptr};
1623
1626 Observer* observer_ = nullptr;
1627};
1628
1647template <typename MultiBufType>
1649 public:
1650 constexpr explicit Instance(Allocator& allocator) : base_(allocator) {}
1651
1652 constexpr Instance(Instance&&) = default;
1653 constexpr Instance& operator=(Instance&&) = default;
1654
1655 // Provide a more helpful compile-time error when a user tries to
1656 // copy-construct an interface type.
1657 template <Property... kProperties>
1658 constexpr Instance(const BasicMultiBuf<kProperties...>&)
1659 : base_(allocator::GetNullAllocator()) {
1660 MoveOnly<>();
1661 }
1662
1663 // Provide a more helpful compile-time error when a user tries to copy-assign
1664 // an interface type.
1665 template <Property... kProperties>
1666 constexpr Instance& operator=(const BasicMultiBuf<kProperties...>&) {
1667 MoveOnly<>();
1668 }
1669
1670 constexpr Instance(MultiBufType&& mb)
1671 : base_(std::move(static_cast<GenericMultiBuf&>(mb))) {}
1672
1673 constexpr Instance& operator=(MultiBufType&& mb) {
1674 base_ = std::move(static_cast<GenericMultiBuf&>(mb));
1675 return *this;
1676 }
1677
1678 template <Property... kProperties>
1680 : base_(std::move(static_cast<internal::GenericMultiBuf&>(mb))) {
1681 internal::AssertIsConvertible<BasicMultiBuf<kProperties...>,
1682 MultiBufType>();
1683 }
1684
1685 template <Property... kProperties>
1686 constexpr Instance& operator=(BasicMultiBuf<kProperties...>&& mb) {
1687 internal::AssertIsConvertible<BasicMultiBuf<kProperties...>,
1688 MultiBufType>();
1689 base_ = std::move(static_cast<internal::GenericMultiBuf&>(mb));
1690 return *this;
1691 }
1692
1693 constexpr MultiBufType* operator->() { return &base_.as<MultiBufType>(); }
1694 constexpr const MultiBufType* operator->() const {
1695 return &base_.as<MultiBufType>();
1696 }
1697
1698 constexpr MultiBufType& operator*() & { return base_.as<MultiBufType>(); }
1699 constexpr const MultiBufType& operator*() const& {
1700 return base_.as<MultiBufType>();
1701 }
1702
1703 constexpr MultiBufType&& operator*() && {
1704 return std::move(base_.as<MultiBufType>());
1705 }
1706 constexpr const MultiBufType&& operator*() const&& {
1707 return std::move(base_.as<MultiBufType>());
1708 }
1709
1710 constexpr operator MultiBufType&() & { return base_.as<MultiBufType>(); }
1711 constexpr operator const MultiBufType&() const& {
1712 return base_.as<MultiBufType>();
1713 }
1714
1715 constexpr operator MultiBufType&&() && {
1716 return std::move(base_.as<MultiBufType>());
1717 }
1718 constexpr operator const MultiBufType&&() const&& {
1719 return std::move(base_.as<MultiBufType>());
1720 }
1721
1722 private:
1723 // Helper functions to provide a more helpful compile-time error when a this
1724 // type is used incorrectly.
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.");
1730 }
1731
1732 GenericMultiBuf base_;
1733};
1734
1735} // namespace multibuf::internal
1736
1737// Template method implementations.
1738
1739template <multibuf::Property... kProperties>
1740template <multibuf::Property... kOtherProperties>
1743 multibuf::internal::AssertIsConvertible<BasicMultiBuf<kOtherProperties...>,
1744 BasicMultiBuf>();
1745 return generic().TryReserveForInsert(pos,
1746 static_cast<const GenericMultiBuf&>(mb));
1747}
1748
1749template <multibuf::Property... kProperties>
1750template <int&... kExplicitGuard, typename T, typename>
1752 const T& bytes) {
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());
1757}
1758
1759template <multibuf::Property... kProperties>
1761 const_iterator pos, const UniquePtr<std::byte[]>& bytes) {
1762 return generic().TryReserveForInsert(pos, bytes.size(), bytes.deallocator());
1763}
1764
1765template <multibuf::Property... kProperties>
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());
1771}
1772
1773template <multibuf::Property... kProperties>
1775 const_iterator pos, const SharedPtr<std::byte[]>& bytes) {
1776 return generic().TryReserveForInsert(
1777 pos, bytes.size(), bytes.control_block());
1778}
1779
1780template <multibuf::Property... kProperties>
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());
1787}
1788
1789template <multibuf::Property... kProperties>
1790template <multibuf::Property... kOtherProperties>
1793 multibuf::internal::AssertIsConvertible<BasicMultiBuf<kOtherProperties...>,
1794 BasicMultiBuf>();
1795 generic().Insert(pos, std::move(mb.generic()));
1796}
1797
1798template <multibuf::Property... kProperties>
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);
1805}
1806
1807template <multibuf::Property... kProperties>
1808void BasicMultiBuf<kProperties...>::Insert(const_iterator pos,
1809 UniquePtr<std::byte[]>&& bytes,
1810 size_t offset,
1811 size_t length) {
1812 ConstByteSpan chunk(bytes.get(), bytes.size());
1813 generic().Insert(pos, chunk, offset, length, bytes.deallocator());
1814 bytes.Release();
1815}
1816
1817template <multibuf::Property... kProperties>
1818void BasicMultiBuf<kProperties...>::Insert(const_iterator pos,
1819 UniquePtr<const std::byte[]>&& bytes,
1820 size_t offset,
1821 size_t length) {
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());
1826 bytes.Release();
1827}
1828
1829template <multibuf::Property... kProperties>
1830void BasicMultiBuf<kProperties...>::Insert(const_iterator pos,
1831 const SharedPtr<std::byte[]>& bytes,
1832 size_t offset,
1833 size_t length) {
1834 ConstByteSpan chunk(bytes.get(), bytes.size());
1835 generic().Insert(pos, chunk, offset, length, bytes.control_block());
1836}
1837
1838template <multibuf::Property... kProperties>
1840 const_iterator pos,
1841 const SharedPtr<const std::byte[]>& bytes,
1842 size_t offset,
1843 size_t length) {
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());
1848}
1849
1850template <multibuf::Property... kProperties>
1851template <multibuf::Property... kOtherProperties>
1854 return TryReserveForInsert(end(), mb);
1855}
1856
1857template <multibuf::Property... kProperties>
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);
1864}
1865
1866template <multibuf::Property... kProperties>
1868 const UniquePtr<std::byte[]>& bytes) {
1869 return TryReserveForInsert(end(), std::move(bytes));
1870}
1871
1872template <multibuf::Property... kProperties>
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));
1878}
1879
1880template <multibuf::Property... kProperties>
1882 const SharedPtr<std::byte[]>& bytes) {
1883 return TryReserveForInsert(end(), bytes);
1884}
1885
1886template <multibuf::Property... kProperties>
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);
1892}
1893
1894template <multibuf::Property... kProperties>
1895template <multibuf::Property... kOtherProperties>
1898 Insert(end(), std::move(mb));
1899}
1900
1901template <multibuf::Property... kProperties>
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);
1908}
1909
1910template <multibuf::Property... kProperties>
1911void BasicMultiBuf<kProperties...>::PushBack(UniquePtr<std::byte[]>&& bytes,
1912 size_t offset,
1913 size_t length) {
1914 Insert(end(), std::move(bytes), offset, length);
1915}
1916
1917template <multibuf::Property... kProperties>
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);
1923}
1924
1925template <multibuf::Property... kProperties>
1927 const SharedPtr<std::byte[]>& bytes, size_t offset, size_t length) {
1928 Insert(end(), bytes, offset, length);
1929}
1930
1931template <multibuf::Property... kProperties>
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);
1937}
1938
1939template <multibuf::Property... kProperties>
1940Result<multibuf::internal::Instance<BasicMultiBuf<kProperties...>>>
1942 auto result = generic().Remove(pos, size);
1943 if (!result.ok()) {
1944 return result.status();
1945 }
1946 return Instance(std::move(*result));
1947}
1948
1949template <multibuf::Property... kProperties>
1952 auto result = generic().PopFrontFragment();
1953 if (!result.ok()) {
1954 return result.status();
1955 }
1956 return Instance(std::move(*result));
1957}
1958
1959template <multibuf::Property... kProperties>
1960UniquePtr<typename BasicMultiBuf<kProperties...>::value_type[]>
1962 UniquePtr<std::byte[]> bytes = generic().Release(pos);
1963 if constexpr (is_const()) {
1964 UniquePtr<const std::byte[]> const_bytes(
1965 bytes.get(), bytes.size(), *(bytes.deallocator()));
1966 bytes.Release();
1967 return const_bytes;
1968 } else {
1969 return bytes;
1970 }
1971}
1972
1973template <multibuf::Property... kProperties>
1974SharedPtr<typename BasicMultiBuf<kProperties...>::value_type[]>
1976 return SharedPtr<value_type[]>(generic().Share(pos),
1977 generic().GetControlBlock());
1978}
1979
1980} // namespace pw
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: result.h:143
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: chunks.h:79
Definition: chunks.h:123
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