Pigweed
 
Loading...
Searching...
No Matches
multibuf.h
1// Copyright 2023 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 <iterator>
17#include <tuple>
18
19#include "pw_multibuf/chunk.h"
20#include "pw_preprocessor/compiler.h"
21#include "pw_status/status_with_size.h"
22
23namespace pw::multibuf {
24
25class MultiBuf;
26
29 public:
30 using element_type = Chunk;
31 using value_type = Chunk;
32 using pointer = Chunk*;
33 using reference = Chunk&;
34 using const_pointer = const Chunk*;
35 using difference_type = std::ptrdiff_t;
36 using const_reference = const Chunk&;
37 using size_type = std::size_t;
38
40 class iterator {
41 public:
42 using value_type = Chunk;
43 using difference_type = std::ptrdiff_t;
44 using reference = Chunk&;
45 using pointer = Chunk*;
46 using iterator_category = std::forward_iterator_tag;
47
48 constexpr iterator() = default;
49
50 constexpr reference operator*() const { return *chunk_; }
51 constexpr pointer operator->() const { return chunk_; }
52
53 constexpr iterator& operator++() {
54 chunk_ = chunk_->next_in_buf_;
55 return *this;
56 }
57
58 constexpr iterator operator++(int) {
59 iterator tmp = *this;
60 ++(*this);
61 return tmp;
62 }
63
64 constexpr bool operator==(const iterator& other) const {
65 return chunk_ == other.chunk_;
66 }
67
68 constexpr bool operator!=(const iterator& other) const {
69 return chunk_ != other.chunk_;
70 }
71
72 private:
73 friend class MultiBufChunks;
74 friend class MultiBuf;
75
76 constexpr iterator(Chunk* chunk) : chunk_(chunk) {}
77 static constexpr iterator end() { return iterator(nullptr); }
78 Chunk* chunk_ = nullptr;
79 };
80
83 public:
84 using value_type = const Chunk;
85 using difference_type = std::ptrdiff_t;
86 using reference = const Chunk&;
87 using pointer = const Chunk*;
88 using iterator_category = std::forward_iterator_tag;
89
90 constexpr const_iterator() = default;
91
92 constexpr reference operator*() const { return *chunk_; }
93 constexpr pointer operator->() const { return chunk_; }
94
95 constexpr const_iterator& operator++() {
96 chunk_ = chunk_->next_in_buf_;
97 return *this;
98 }
99
100 constexpr const_iterator operator++(int) {
101 const_iterator tmp = *this;
102 ++(*this);
103 return tmp;
104 }
105
106 constexpr bool operator==(const const_iterator& other) const {
107 return chunk_ == other.chunk_;
108 }
109
110 constexpr bool operator!=(const const_iterator& other) const {
111 return chunk_ != other.chunk_;
112 }
113
114 private:
115 friend class MultiBufChunks;
116 friend class MultiBuf;
117
118 constexpr const_iterator(const Chunk* chunk) : chunk_(chunk) {}
119 static constexpr const_iterator end() { return const_iterator(nullptr); }
120 const Chunk* chunk_ = nullptr;
121 };
122
123 MultiBufChunks(const MultiBufChunks&) = delete;
124 MultiBufChunks& operator=(const MultiBufChunks&) = delete;
125
129 constexpr Chunk& front() { return *first_; }
130 constexpr const Chunk& front() const { return *first_; }
131
137 Chunk& back() { return const_cast<Chunk&>(std::as_const(*this).back()); }
138 const Chunk& back() const;
139
140 constexpr iterator begin() { return iterator(first_); }
141 constexpr const_iterator begin() const { return cbegin(); }
142 constexpr const_iterator cbegin() const { return const_iterator(first_); }
143
144 constexpr iterator end() { return iterator::end(); }
145 constexpr const_iterator end() const { return cend(); }
146 constexpr const_iterator cend() const { return const_iterator::end(); }
147
149 size_t size() const {
150 return static_cast<size_t>(std::distance(begin(), end()));
151 }
152
154 size_t size_bytes() const;
155
157 [[nodiscard]] bool empty() const { return first_ == nullptr; }
158
162 void push_front(OwnedChunk&& chunk);
163
167 void push_back(OwnedChunk&& chunk);
168
173
180 //
181 // Implementation note: `Chunks().size()` should be remain relatively small,
182 // but this could be made `O(1)` in the future by adding a `prev` pointer to
183 // the `iterator`.
184 iterator insert(iterator position, OwnedChunk&& chunk);
185
192 //
193 // Implementation note: `Chunks().size()` should be remain relatively small,
194 // but this could be made `O(1)` in the future by adding a `prev` pointer to
195 // the `iterator`.
196 std::tuple<iterator, OwnedChunk> take(iterator position);
197
198 protected:
199 explicit constexpr MultiBufChunks(Chunk* first_chunk) : first_(first_chunk) {}
200
202 ~MultiBufChunks() { Release(); }
203
204 // Disable maybe-uninitialized: this check fails erroneously on Windows GCC.
206 PW_MODIFY_DIAGNOSTIC_GCC(ignored, "-Wmaybe-uninitialized");
207 constexpr MultiBufChunks(MultiBufChunks&& other) noexcept
208 : first_(other.first_) {
209 other.first_ = nullptr;
210 }
212
213 MultiBufChunks& operator=(MultiBufChunks&& other) noexcept {
214 Release();
215 first_ = other.first_;
216 other.first_ = nullptr;
217 return *this;
218 }
219
220 // Releases all chunks in the `MultiBuf`.
221 void Release() noexcept;
222
223 void PushSuffix(MultiBufChunks&& tail);
224
232 Chunk* Previous(Chunk* chunk) const;
233
234 private:
235 Chunk* first_;
236};
237
245class MultiBuf : private MultiBufChunks {
246 public:
247 class iterator;
248 class const_iterator;
249
250 constexpr MultiBuf() : MultiBufChunks(nullptr) {}
251
252 static MultiBuf FromChunk(OwnedChunk&& chunk) {
253 return MultiBuf(std::move(chunk).Take());
254 }
255
256 MultiBuf(const MultiBuf&) = delete;
257 MultiBuf& operator=(const MultiBuf&) = delete;
258
259 constexpr MultiBuf(MultiBuf&& other) noexcept = default;
260
261 MultiBuf& operator=(MultiBuf&& other) noexcept = default;
262
271 void Release() noexcept { MultiBufChunks::Release(); }
272
274 ~MultiBuf() = default;
275
279 [[nodiscard]] size_t size() const { return MultiBufChunks::size_bytes(); }
280
285 [[nodiscard]] bool empty() const;
286
293 [[nodiscard]] bool IsContiguous() const {
294 return ContiguousSpan().has_value();
295 }
296
305 std::optional<ByteSpan> ContiguousSpan() {
306 auto result = std::as_const(*this).ContiguousSpan();
307 if (result.has_value()) {
308 return span(const_cast<std::byte*>(result->data()), result->size());
309 }
310 return std::nullopt;
311 }
312 std::optional<ConstByteSpan> ContiguousSpan() const;
313
315 iterator begin() { return iterator(Chunks().begin().chunk_); }
318 return const_iterator(Chunks().begin().chunk_);
319 }
322 return const_iterator(Chunks().begin().chunk_);
323 }
324
326 iterator end() { return iterator::end(); }
328 const_iterator end() const { return const_iterator::end(); }
330 const_iterator cend() const { return const_iterator::end(); }
331
340 [[nodiscard]] bool ClaimPrefix(size_t bytes_to_claim);
341
350 [[nodiscard]] bool ClaimSuffix(size_t bytes_to_claim);
351
360 void DiscardPrefix(size_t bytes_to_discard);
361
370 void Slice(size_t begin, size_t end);
371
379 void Truncate(size_t len);
380
388
397 std::optional<MultiBuf> TakePrefix(size_t bytes_to_take);
398
407 std::optional<MultiBuf> TakeSuffix(size_t bytes_to_take);
408
413
417 void PushSuffix(MultiBuf&& tail) {
418 return MultiBufChunks::PushSuffix(std::move(tail.Chunks()));
419 }
420
439 StatusWithSize CopyTo(ByteSpan dest, size_t position = 0) const;
440
458 StatusWithSize CopyFrom(ConstByteSpan source, size_t position = 0) {
459 return CopyFromAndOptionallyTruncate(source, position, /*truncate=*/false);
460 }
461
490 size_t position = 0) {
491 return CopyFromAndOptionallyTruncate(source, position, /*truncate=*/true);
492 }
493
495 //--------------------- Chunk manipulation ----------------------//
497
500 MultiBufChunks::push_front(std::move(chunk));
501 }
502
504 void PushBackChunk(OwnedChunk&& chunk) {
505 MultiBufChunks::push_back(std::move(chunk));
506 }
507
510
513 OwnedChunk&& chunk) {
514 return MultiBufChunks::insert(position, std::move(chunk));
515 }
516
518 std::tuple<MultiBufChunks::iterator, OwnedChunk> TakeChunk(
519 MultiBufChunks::iterator position) {
520 return MultiBufChunks::take(position);
521 }
522
524 constexpr MultiBufChunks& Chunks() { return *this; }
525
527 constexpr const MultiBufChunks& Chunks() const { return *this; }
528
530 constexpr const MultiBufChunks& ConstChunks() const { return *this; }
531
533 //--------------------- Iterator details ------------------------//
535
536 using element_type = std::byte;
537 using value_type = std::byte;
538 using pointer = std::byte*;
539 using const_pointer = const std::byte*;
540 using reference = std::byte&;
541 using const_reference = const std::byte&;
542 using difference_type = std::ptrdiff_t;
543 using size_type = std::size_t;
544
547 public:
548 using value_type = std::byte;
549 using difference_type = std::ptrdiff_t;
550 using reference = const std::byte&;
551 using pointer = const std::byte*;
552 using iterator_category = std::forward_iterator_tag;
553
554 constexpr const_iterator() : chunk_(nullptr), byte_index_(0) {}
555
556 reference operator*() const { return (*chunk_)[byte_index_]; }
557 pointer operator->() const { return &(*chunk_)[byte_index_]; }
558
559 const_iterator& operator++();
560 const_iterator operator++(int) {
561 const_iterator tmp = *this;
562 ++(*this);
563 return tmp;
564 }
565 const_iterator operator+(size_t rhs) const {
566 const_iterator tmp = *this;
567 tmp += rhs;
568 return tmp;
569 }
570 const_iterator& operator+=(size_t advance);
571
572 constexpr bool operator==(const const_iterator& other) const {
573 return chunk_ == other.chunk_ && byte_index_ == other.byte_index_;
574 }
575
576 constexpr bool operator!=(const const_iterator& other) const {
577 return !(*this == other);
578 }
579
581 constexpr const Chunk* chunk() const { return chunk_; }
582
585 constexpr size_t byte_index() const { return byte_index_; }
586
587 private:
588 friend class MultiBuf;
589
590 explicit constexpr const_iterator(const Chunk* chunk, size_t byte_index = 0)
591 : chunk_(chunk), byte_index_(byte_index) {
592 AdvanceToData();
593 }
594
595 static const_iterator end() { return const_iterator(nullptr); }
596
597 constexpr void AdvanceToData() {
598 while (chunk_ != nullptr && chunk_->empty()) {
599 chunk_ = chunk_->next_in_buf_;
600 }
601 }
602
603 const Chunk* chunk_;
604 size_t byte_index_;
605 };
606
608 class iterator {
609 public:
610 using value_type = std::byte;
611 using difference_type = std::ptrdiff_t;
612 using reference = std::byte&;
613 using pointer = std::byte*;
614 using iterator_category = std::forward_iterator_tag;
615
616 constexpr iterator() = default;
617
618 reference operator*() const { return const_cast<std::byte&>(*const_iter_); }
619 pointer operator->() const { return const_cast<std::byte*>(&*const_iter_); }
620
621 iterator& operator++() {
622 const_iter_++;
623 return *this;
624 }
625 iterator operator++(int) {
626 iterator tmp = *this;
627 ++(*this);
628 return tmp;
629 }
630 iterator operator+(size_t rhs) const {
631 iterator tmp = *this;
632 tmp += rhs;
633 return tmp;
634 }
635 iterator& operator+=(size_t rhs) {
636 const_iter_ += rhs;
637 return *this;
638 }
639 constexpr bool operator==(const iterator& other) const {
640 return const_iter_ == other.const_iter_;
641 }
642 constexpr bool operator!=(const iterator& other) const {
643 return const_iter_ != other.const_iter_;
644 }
645
647 constexpr Chunk* chunk() const {
648 return const_cast<Chunk*>(const_iter_.chunk());
649 }
650
653 constexpr size_t byte_index() const { return const_iter_.byte_index(); }
654
655 private:
656 friend class MultiBuf;
657
658 explicit constexpr iterator(Chunk* chunk, size_t byte_index = 0)
659 : const_iter_(chunk, byte_index) {}
660
661 static iterator end() { return iterator(nullptr); }
662
663 const_iterator const_iter_;
664 };
665
666 private:
667 explicit constexpr MultiBuf(Chunk* first_chunk)
668 : MultiBufChunks(first_chunk) {}
669
670 StatusWithSize CopyFromAndOptionallyTruncate(ConstByteSpan source,
671 size_t position,
672 bool truncate);
673};
674
675} // namespace pw::multibuf
Definition: status_with_size.h:49
Definition: chunk.h:47
A const std::forward_iterator over the bytes of a MultiBuf.
Definition: multibuf.h:546
constexpr size_t byte_index() const
Definition: multibuf.h:585
constexpr const Chunk * chunk() const
Returns the current Chunk pointed to by this iterator.
Definition: multibuf.h:581
An std::forward_iterator over the bytes of a MultiBuf.
Definition: multibuf.h:608
constexpr size_t byte_index() const
Definition: multibuf.h:653
constexpr Chunk * chunk() const
Returns the current Chunk pointed to by this iterator.
Definition: multibuf.h:647
A const std::forward_iterator over the Chunks of a MultiBuf.
Definition: multibuf.h:82
A std::forward_iterator over the Chunks of a MultiBuf.
Definition: multibuf.h:40
A Chunk-oriented view of a MultiBuf.
Definition: multibuf.h:28
bool empty() const
Returns whether the MultiBuf contains any chunks (size() == 0).
Definition: multibuf.h:157
constexpr Chunk & front()
Definition: multibuf.h:129
std::tuple< iterator, OwnedChunk > take(iterator position)
Chunk * Previous(Chunk *chunk) const
void push_back(OwnedChunk &&chunk)
void push_front(OwnedChunk &&chunk)
iterator insert(iterator position, OwnedChunk &&chunk)
Chunk & back()
Definition: multibuf.h:137
~MultiBufChunks()
This destructor will acquire a mutex and is not IRQ safe.
Definition: multibuf.h:202
size_t size_bytes() const
Returns the total number of bytes in all Chunks.
size_t size() const
Returns the number of Chunks in this MultiBuf, including empty chunks.
Definition: multibuf.h:149
Definition: multibuf.h:245
~MultiBuf()=default
This destructor will acquire a mutex and is not IRQ safe.
void PushBackChunk(OwnedChunk &&chunk)
Definition: multibuf.h:504
constexpr MultiBufChunks & Chunks()
Returns a Chunk-oriented view of this MultiBuf.
Definition: multibuf.h:524
void Release() noexcept
Definition: multibuf.h:271
MultiBufChunks::iterator InsertChunk(MultiBufChunks::iterator position, OwnedChunk &&chunk)
Definition: multibuf.h:512
const_iterator cbegin() const
Returns a const iterator pointing to the first byte of this MultiBuf.
Definition: multibuf.h:321
void PushSuffix(MultiBuf &&tail)
Definition: multibuf.h:417
std::optional< MultiBuf > TakeSuffix(size_t bytes_to_take)
void TruncateAfter(iterator pos)
void DiscardPrefix(size_t bytes_to_discard)
void PushFrontChunk(OwnedChunk &&chunk)
Definition: multibuf.h:499
const_iterator begin() const
Returns a const iterator pointing to the first byte of this MultiBuf.
Definition: multibuf.h:317
const_iterator end() const
Returns a const iterator pointing to the end of this MultiBuf.
Definition: multibuf.h:328
StatusWithSize CopyTo(ByteSpan dest, size_t position=0) const
iterator begin()
Returns an iterator pointing to the first byte of this MultiBuf.
Definition: multibuf.h:315
StatusWithSize CopyFromAndTruncate(ConstByteSpan source, size_t position=0)
Definition: multibuf.h:489
bool IsContiguous() const
Definition: multibuf.h:293
constexpr const MultiBufChunks & ConstChunks() const
Returns a const Chunk-oriented view of this MultiBuf.
Definition: multibuf.h:530
void Truncate(size_t len)
iterator end()
Returns an iterator pointing to the end of this MultiBuf.
Definition: multibuf.h:326
StatusWithSize CopyFrom(ConstByteSpan source, size_t position=0)
Definition: multibuf.h:458
bool ClaimSuffix(size_t bytes_to_claim)
std::optional< MultiBuf > TakePrefix(size_t bytes_to_take)
std::tuple< MultiBufChunks::iterator, OwnedChunk > TakeChunk(MultiBufChunks::iterator position)
Definition: multibuf.h:518
OwnedChunk TakeFrontChunk()
Definition: multibuf.h:509
bool ClaimPrefix(size_t bytes_to_claim)
constexpr const MultiBufChunks & Chunks() const
Returns a const Chunk-oriented view of this MultiBuf.
Definition: multibuf.h:527
std::optional< ByteSpan > ContiguousSpan()
Definition: multibuf.h:305
void PushPrefix(MultiBuf &&front)
const_iterator cend() const
Returns a const iterator pointing to the end of this MultiBuf.
Definition: multibuf.h:330
size_t size() const
Definition: multibuf.h:279
void Slice(size_t begin, size_t end)
Definition: chunk.h:323
#define PW_MODIFY_DIAGNOSTICS_POP()
Definition: compiler.h:191
#define PW_MODIFY_DIAGNOSTIC_GCC(kind, option)
Definition: compiler.h:208
#define PW_MODIFY_DIAGNOSTICS_PUSH()
Definition: compiler.h:186