C/C++ API Reference
Loading...
Searching...
No Matches
multibuf.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#include <cstddef>
17#include <optional>
18#include <tuple>
19
20#include "pw_bytes/span.h"
21#include "pw_multibuf/v1_adapter/chunk.h"
22#include "pw_multibuf/v2/chunks.h"
23#include "pw_multibuf/v2/multibuf.h"
24#include "pw_status/status_with_size.h"
25
26namespace pw::multibuf::v1_adapter {
27
29
39 private:
41 using Mutability = v2::internal::Mutability;
42 using Deque = Entry::Deque;
43
46 template <Mutability kMutability>
47 class Iterator {
48 public:
49 using size_type = Deque::size_type;
50 using difference_type = Deque::difference_type;
51 using value_type = std::
52 conditional_t<kMutability == Mutability::kConst, const Chunk, Chunk>;
53 using reference = value_type&;
54 using pointer = value_type*;
55 using iterator_category = std::forward_iterator_tag;
56
57 constexpr Iterator() = default;
58
59 // Support converting non-const iterators to const_iterators.
60 operator Iterator<Mutability::kConst>() const {
61 return mbv2_ == nullptr ? Iterator<Mutability::kConst>()
62 : Iterator<Mutability::kConst>(*mbv2_, index_);
63 }
64
65 constexpr reference operator*() const {
66 PW_ASSERT(chunk_.has_value());
67 return const_cast<reference>(*chunk_);
68 }
69 constexpr pointer operator->() const {
70 PW_ASSERT(chunk_.has_value());
71 return const_cast<pointer>(&(*chunk_));
72 }
73
74 constexpr Iterator& operator++() {
75 ++index_;
76 Update();
77 return *this;
78 }
79
80 constexpr Iterator operator++(int) {
81 Iterator tmp = *this;
82 ++(*this);
83 return tmp;
84 }
85
86 constexpr bool operator==(const Iterator& other) const {
87 return mbv2_ == other.mbv2_ && index_ == other.index_;
88 }
89
90 constexpr bool operator!=(const Iterator& other) const {
91 return !(*this == other);
92 }
93
94 private:
95 friend class MultiBufChunks;
96
97 constexpr Iterator(const v2::MultiBuf& mbv2, size_type chunk)
98 : mbv2_(&(mbv2.generic())),
99 index_(std::min(chunk, mbv2.generic().num_chunks())) {
100 Update();
101 }
102
103 constexpr void Update() {
104 // Check if this iterator is valid.
105 if (mbv2_ == nullptr || index_ >= mbv2_->num_chunks()) {
106 chunk_ = std::nullopt;
107 return;
108 }
109
110 // Check if the last chunk of the v2 multibuf is empty.
111 auto pos = mbv2_->MakeIterator(index_);
112 if (pos == mbv2_->cend()) {
113 chunk_ = Chunk(mbv2_->get_allocator(), SharedPtr<std::byte[]>());
114 return;
115 }
116
117 // Make a Chunk that corresponds to the v2 chunk.
118 chunk_ = Chunk(mbv2_->get_allocator(), mbv2_->Share(pos));
119 size_type start = mbv2_->GetOffset(index_);
120 size_type end = start + mbv2_->GetLength(index_);
121 chunk_->Slice(start, end);
122 }
123
124 const v2::internal::GenericMultiBuf* mbv2_ = nullptr;
125 size_type index_;
126 std::optional<Chunk> chunk_;
127 };
128
129 public:
130 using iterator = Iterator<Mutability::kMutable>;
131 using const_iterator = Iterator<Mutability::kConst>;
132
133 constexpr MultiBufChunks() = default;
134 constexpr size_t size() const {
135 const auto& mbv2 = mbv2_->generic();
136 if (mbv2_ == nullptr) {
137 return 0;
138 }
139 size_t size = 0;
140 for (Entry::size_type i = 0; i < mbv2.num_chunks(); ++i) {
141 if (mbv2.GetLength(i) != 0) {
142 ++size;
143 }
144 }
145 return size;
146 }
147
148 iterator begin() const {
149 return mbv2_ == nullptr ? iterator() : iterator(*mbv2_, 0);
150 }
151 iterator end() const {
152 return mbv2_ == nullptr
153 ? iterator()
154 : iterator(*mbv2_,
155 std::numeric_limits<iterator::size_type>::max());
156 }
157
158 const_iterator cbegin() const { return begin(); }
159 const_iterator cend() const { return end(); }
160
161 private:
162 friend class MultiBuf;
163
164 constexpr explicit MultiBufChunks(const v2::MultiBuf& mbv2) : mbv2_(&mbv2) {}
165
166 const v2::MultiBuf* mbv2_ = nullptr;
167};
168
184class MultiBuf final {
185 private:
187
188 public:
189 using size_type = v2::MultiBuf::size_type;
190 using difference_type = v2::MultiBuf::difference_type;
191 using iterator = v2::MultiBuf::iterator;
193 using pointer = v2::MultiBuf::pointer;
194 using const_pointer = v2::MultiBuf::const_pointer;
195 using reference = v2::MultiBuf::reference;
196 using const_reference = v2::MultiBuf::const_reference;
197 using value_type = v2::MultiBuf::value_type;
198
199 MultiBuf(const MultiBuf& other) = delete;
200 MultiBuf& operator=(const MultiBuf& other) = delete;
201
202 MultiBuf(MultiBuf&& other) noexcept = default;
203 MultiBuf& operator=(MultiBuf&& other) noexcept = default;
204
205 ~MultiBuf() { Release(); }
206
220 constexpr v2::TrackedMultiBuf* v2() {
221 return mbv2_.has_value() ? &(**mbv2_) : nullptr;
222 }
223 constexpr const v2::TrackedMultiBuf* v2() const {
224 return mbv2_.has_value() ? &(**mbv2_) : nullptr;
225 }
226
227 // v1 API ////////////////////////////////////////////////////////////////////
228
231
232 constexpr MultiBuf() = default;
233
235 void Release() noexcept;
236
238 [[nodiscard]] constexpr size_t size() const {
239 return mbv2_.has_value() ? (*mbv2_)->size() : 0;
240 }
241
243 [[nodiscard]] constexpr bool empty() const {
244 // `v2::MultiBuf::empty()` returns true for multibufs that only have one or
245 // more empty chunks, so use `size()` instead.
246 // NOLINTNEXTLINE(readability-container-size-empty)
247 return size() == 0;
248 }
249
251 [[nodiscard]] bool IsContiguous() const {
252 return ContiguousSpan().has_value();
253 }
254
256 std::optional<ByteSpan> ContiguousSpan();
257 std::optional<ConstByteSpan> ContiguousSpan() const;
258
260 constexpr iterator begin() {
261 return mbv2_.has_value() ? (*mbv2_)->begin() : iterator();
262 }
263 constexpr const_iterator begin() const {
264 return mbv2_.has_value() ? (*mbv2_)->begin() : const_iterator();
265 }
266 constexpr const_iterator cbegin() const {
267 return mbv2_.has_value() ? (*mbv2_)->cbegin() : const_iterator();
268 }
269
271 constexpr iterator end() {
272 return mbv2_.has_value() ? (*mbv2_)->end() : iterator();
273 }
274 constexpr const_iterator end() const {
275 return mbv2_.has_value() ? (*mbv2_)->end() : const_iterator();
276 }
277 constexpr const_iterator cend() const {
278 return mbv2_.has_value() ? (*mbv2_)->end() : const_iterator();
279 }
280
282 [[nodiscard]] bool ClaimPrefix(size_t bytes_to_claim);
283
285 [[nodiscard]] bool ClaimSuffix(size_t bytes_to_claim);
286
288 void DiscardPrefix(size_t bytes_to_discard);
289
291 void Slice(size_t begin, size_t end);
292
294 void Truncate(size_t len);
295
297 void TruncateAfter(iterator pos);
298
300 std::optional<MultiBuf> TakePrefix(size_t bytes_to_take);
301
303 std::optional<MultiBuf> TakeSuffix(size_t bytes_to_take);
304
306 void PushPrefix(MultiBuf&& front);
307
309 void PushSuffix(MultiBuf&& tail);
310
312 StatusWithSize CopyTo(ByteSpan dest, size_t position = 0) const;
313
315 StatusWithSize CopyFrom(ConstByteSpan source, size_t position = 0);
316
319
322
325
328 return std::get<OwnedChunk>(TakeChunk(Chunks().begin()));
329 }
330
332 MultiBufChunks::iterator InsertChunk(MultiBufChunks::iterator position,
333 OwnedChunk&& chunk);
334
336 std::tuple<MultiBufChunks::iterator, OwnedChunk> TakeChunk(
337 MultiBufChunks::iterator position);
338
340 constexpr MultiBufChunks Chunks() {
341 return mbv2_.has_value() ? MultiBufChunks(**mbv2_) : MultiBufChunks();
342 }
343
344 constexpr const MultiBufChunks Chunks() const { return ConstChunks(); }
345
347 constexpr const MultiBufChunks ConstChunks() const {
348 return mbv2_.has_value() ? MultiBufChunks(**mbv2_) : MultiBufChunks();
349 }
350
351 // v2 API ////////////////////////////////////////////////////////////////////
352
353 constexpr explicit MultiBuf(Allocator& allocator)
354 : mbv2_(std::in_place, allocator) {}
355
356 template <v2::Property... kProperties>
357 constexpr MultiBuf(v2::BasicMultiBuf<kProperties...>&& mb) {
358 *this = std::move(mb);
359 }
360
361 template <v2::Property... kProperties>
362 constexpr MultiBuf& operator=(v2::BasicMultiBuf<kProperties...>&& mb) {
363 mbv2_ = std::move(mb);
364 return *this;
365 }
366
367 template <typename MultiBufType>
368 constexpr MultiBuf(v2::internal::Instance<MultiBufType>&& mbi) {
369 *this = std::move(mbi);
370 }
371
372 template <typename MultiBufType>
373 constexpr MultiBuf& operator=(v2::internal::Instance<MultiBufType>&& mbi) {
374 mbv2_ = std::move(*mbi);
375 return *this;
376 }
377
378 constexpr v2::TrackedMultiBuf* operator->() {
379 PW_ASSERT(mbv2_.has_value());
380 return &(**mbv2_);
381 }
382 constexpr const v2::TrackedMultiBuf* operator->() const {
383 PW_ASSERT(mbv2_.has_value());
384 return &(**mbv2_);
385 }
386
387 constexpr v2::TrackedMultiBuf& operator*() & {
388 PW_ASSERT(mbv2_.has_value());
389 return **mbv2_;
390 }
391 constexpr const v2::TrackedMultiBuf& operator*() const& {
392 PW_ASSERT(mbv2_.has_value());
393 return **mbv2_;
394 }
395
396 constexpr v2::TrackedMultiBuf&& operator*() && {
397 PW_ASSERT(mbv2_.has_value());
398 return std::move(**mbv2_);
399 }
400 constexpr const v2::TrackedMultiBuf&& operator*() const&& {
401 PW_ASSERT(mbv2_.has_value());
402 return std::move(**mbv2_);
403 }
404
405 template <typename MultiBufType>
406 constexpr operator MultiBufType&() & {
407 PW_ASSERT(mbv2_.has_value());
408 return **mbv2_;
409 }
410 template <typename MultiBufType>
411 constexpr operator const MultiBufType&() const& {
412 PW_ASSERT(mbv2_.has_value());
413 return **mbv2_;
414 }
415
416 template <typename MultiBufType>
417 constexpr operator MultiBufType&&() && {
418 PW_ASSERT(mbv2_.has_value());
419 return std::move(**mbv2_);
420 }
421 template <typename MultiBufType>
422 constexpr operator const MultiBufType&&() const&& {
423 PW_ASSERT(mbv2_.has_value());
424 return std::move(**mbv2_);
425 }
426
427 private:
429 iterator ToByteIterator(const MultiBufChunks::iterator& position);
430
432 MultiBufChunks::iterator ToChunksIterator(const const_iterator& position);
433
434 std::optional<v2::TrackedMultiBuf::Instance> mbv2_;
435 size_t offset_ = 0;
436};
437
439
440} // namespace pw::multibuf::v1_adapter
Definition: allocator.h:45
Definition: dynamic_deque.h:60
Definition: shared_ptr.h:68
Definition: status_with_size.h:51
Definition: chunk.h:50
Definition: multibuf.h:184
void PushBackChunk(OwnedChunk &&chunk)
bool ClaimPrefix(size_t bytes_to_claim)
std::optional< ByteSpan > ContiguousSpan()
void DiscardPrefix(size_t bytes_to_discard)
constexpr MultiBufChunks Chunks()
Returns a Chunk-oriented view of this MultiBuf.
Definition: multibuf.h:340
StatusWithSize CopyTo(ByteSpan dest, size_t position=0) const
std::optional< MultiBuf > TakeSuffix(size_t bytes_to_take)
OwnedChunk TakeFrontChunk()
Definition: multibuf.h:327
constexpr iterator begin()
Returns an iterator pointing to the first byte of this MultiBuf.
Definition: multibuf.h:260
StatusWithSize CopyFromAndTruncate(ConstByteSpan source, size_t position=0)
MultiBufChunks::iterator InsertChunk(MultiBufChunks::iterator position, OwnedChunk &&chunk)
void Slice(size_t begin, size_t end)
constexpr bool empty() const
Definition: multibuf.h:243
constexpr v2::TrackedMultiBuf * v2()
Definition: multibuf.h:220
std::tuple< MultiBufChunks::iterator, OwnedChunk > TakeChunk(MultiBufChunks::iterator position)
std::optional< MultiBuf > TakePrefix(size_t bytes_to_take)
constexpr size_t size() const
Definition: multibuf.h:238
void PushSuffix(MultiBuf &&tail)
StatusWithSize CopyFrom(ConstByteSpan source, size_t position=0)
constexpr const MultiBufChunks ConstChunks() const
Returns a const Chunk-oriented view of this MultiBuf.
Definition: multibuf.h:347
void PushFrontChunk(OwnedChunk &&chunk)
static MultiBuf FromChunk(OwnedChunk &&chunk)
bool ClaimSuffix(size_t bytes_to_claim)
bool IsContiguous() const
Definition: multibuf.h:251
void PushPrefix(MultiBuf &&front)
constexpr iterator end()
Returns an iterator pointing to the end of this MultiBuf.
Definition: multibuf.h:271
Byte iterator templated on the const-ness of the bytes it references.
Definition: byte_iterator.h:85
Property
Basic properties of a MultiBuf.
Definition: properties.h:24
BasicMultiBuf< Property::kLayerable, Property::kObservable > TrackedMultiBuf
Definition: multibuf.h:80
Definition: entry.h:47