Pigweed
 
Loading...
Searching...
No Matches
chunk.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 <optional>
17#include <utility>
18
19#include "pw_assert/assert.h"
20#include "pw_bytes/span.h"
21#include "pw_sync/mutex.h"
22
23namespace pw::multibuf {
24
25class ChunkRegionTracker;
26class OwnedChunk;
27
47class Chunk {
48 public:
49 Chunk() = delete;
50 // Not copyable or movable.
51 Chunk(Chunk&) = delete;
52 Chunk& operator=(Chunk&) = delete;
53 Chunk(Chunk&&) = delete;
54 Chunk& operator=(Chunk&&) = delete;
55
56 std::byte* data() { return span_.data(); }
57 const std::byte* data() const { return span_.data(); }
58 size_t size() const { return span_.size(); }
59 [[nodiscard]] bool empty() const { return span_.empty(); }
60
61 std::byte& operator[](size_t index) { return span_[index]; }
62 const std::byte& operator[](size_t index) const { return span_[index]; }
63
64 // Container declarations
65 using element_type = std::byte;
66 using value_type = std::byte;
67 using size_type = size_t;
68 using difference_type = ptrdiff_t;
69 using pointer = std::byte*;
70 using const_pointer = const std::byte*;
71 using reference = std::byte&;
72 using const_reference = const std::byte&;
73 using iterator = std::byte*;
74 using const_iterator = const std::byte*;
75 using reverse_iterator = std::byte*;
76 using const_reverse_iterator = const std::byte*;
77
78 std::byte* begin() { return span_.data(); }
79 const std::byte* begin() const { return cbegin(); }
80 const std::byte* cbegin() const { return span_.data(); }
81 std::byte* end() { return span_.data() + span_.size(); }
82 const std::byte* end() const { return cend(); }
83 const std::byte* cend() const { return span_.data() + span_.size(); }
84
89 [[nodiscard]] bool CanMerge(const Chunk& next_chunk) const;
90
101 bool Merge(OwnedChunk& next_chunk);
102
112 [[nodiscard]] bool ClaimPrefix(size_t bytes_to_claim);
113
122 [[nodiscard]] bool ClaimSuffix(size_t bytes_to_claim);
123
132 void DiscardPrefix(size_t bytes_to_discard);
133
142 void Slice(size_t begin, size_t end);
143
151 void Truncate(size_t len);
152
161 std::optional<OwnedChunk> TakePrefix(size_t bytes_to_take);
162
171 std::optional<OwnedChunk> TakeSuffix(size_t bytes_to_take);
172
173 private:
174 Chunk(ChunkRegionTracker* region_tracker, ByteSpan span)
175 : region_tracker_(region_tracker),
176 next_in_region_(nullptr),
177 prev_in_region_(nullptr),
178 next_in_buf_(nullptr),
179 span_(span) {}
180
181 // NOTE: these functions are logically
182 // `PW_EXCLUSIVE_LOCKS_REQUIRED(region_tracker_->lock_)`, however this
183 // annotation cannot be applied due to the forward declaration of
184 // `region_tracker_`.
185 void InsertAfterInRegionList(Chunk* new_chunk);
186 void InsertBeforeInRegionList(Chunk* new_chunk);
187 void RemoveFromRegionList();
188
198 void Free();
199
201 ChunkRegionTracker* const region_tracker_;
202
210 Chunk* next_in_region_;
211
219 Chunk* prev_in_region_;
220
227 Chunk* next_in_buf_;
228
241 ByteSpan span_;
242
243 friend class ChunkRegionTracker; // For the constructor
244 friend class OwnedChunk; // for `Free`.
245 friend class MultiBuf; // for `next_in_buf_`.
246 friend class MultiBufChunks; // for `Free` and `next_in_buf_`.
247};
248
272 public:
279 std::optional<OwnedChunk> CreateFirstChunk();
280
281 protected:
282 ChunkRegionTracker() = default;
283 virtual ~ChunkRegionTracker() = default;
284
289 virtual void Destroy() = 0;
290
299 virtual ByteSpan Region() const = 0;
300
303 virtual void* AllocateChunkClass() = 0;
304
306 virtual void DeallocateChunkClass(void*) = 0;
307
308 private:
315 pw::sync::Mutex lock_;
316 friend Chunk;
317};
318
324 public:
325 OwnedChunk() : inner_(nullptr) {}
326 OwnedChunk(OwnedChunk&& other) noexcept : inner_(other.inner_) {
327 other.inner_ = nullptr;
328 }
329 OwnedChunk& operator=(OwnedChunk&& other) noexcept {
330 inner_ = other.inner_;
331 other.inner_ = nullptr;
332 return *this;
333 }
336
337 std::byte* data() {
338 return const_cast<std::byte*>(std::as_const(*this).data());
339 }
340 const std::byte* data() const {
341 return inner_ == nullptr ? nullptr : inner_->data();
342 }
343
344 size_t size() const { return inner_ == nullptr ? 0 : inner_->size(); }
345
346 std::byte& operator[](size_t index) { return data()[index]; }
347 std::byte operator[](size_t index) const { return data()[index]; }
348
349 // Container declarations
350 using element_type = std::byte;
351 using value_type = std::byte;
352 using size_type = size_t;
353 using difference_type = ptrdiff_t;
354 using pointer = std::byte*;
355 using const_pointer = const std::byte*;
356 using reference = std::byte&;
357 using const_reference = const std::byte&;
358 using iterator = std::byte*;
359 using const_iterator = const std::byte*;
360 using reverse_iterator = std::byte*;
361 using const_reverse_iterator = const std::byte*;
362
363 std::byte* begin() { return data(); }
364 const std::byte* begin() const { return cbegin(); }
365 const std::byte* cbegin() const { return data(); }
366 std::byte* end() { return data() + size(); }
367 const std::byte* end() const { return cend(); }
368 const std::byte* cend() const { return data() + size(); }
369
370 Chunk& operator*() { return *inner_; }
371 const Chunk& operator*() const { return *inner_; }
372 Chunk* operator->() { return inner_; }
373 const Chunk* operator->() const { return inner_; }
374
384 void Release();
385
388 Chunk* Take() && {
389 Chunk* result = inner_;
390 inner_ = nullptr;
391 return result;
392 }
393
394 private:
396 OwnedChunk(Chunk* inner) : inner_(inner) {}
397
399 Chunk* inner_;
400
403 friend class Chunk;
404 friend class ChunkRegionTracker;
405 friend class MultiBuf;
406 friend class MultiBufChunks;
407};
408
409} // namespace pw::multibuf
Definition: chunk.h:47
std::optional< OwnedChunk > TakeSuffix(size_t bytes_to_take)
void DiscardPrefix(size_t bytes_to_discard)
bool Merge(OwnedChunk &next_chunk)
void Truncate(size_t len)
void Slice(size_t begin, size_t end)
bool ClaimSuffix(size_t bytes_to_claim)
bool ClaimPrefix(size_t bytes_to_claim)
std::optional< OwnedChunk > TakePrefix(size_t bytes_to_take)
bool CanMerge(const Chunk &next_chunk) const
Definition: chunk.h:271
virtual void DeallocateChunkClass(void *)=0
Deallocates a pointer returned by AllocateChunkClass.
virtual ByteSpan Region() const =0
std::optional< OwnedChunk > CreateFirstChunk()
virtual void * AllocateChunkClass()=0
A Chunk-oriented view of a MultiBuf.
Definition: multibuf.h:28
Definition: multibuf.h:245
Definition: chunk.h:323
friend class Chunk
Definition: chunk.h:403
~OwnedChunk()
This method will acquire a mutex and is not IRQ safe.
Definition: chunk.h:335
Chunk * Take() &&
Definition: chunk.h:388
Definition: mutex.h:42