xref: /aosp_15_r20/external/pigweed/pw_multibuf/public/pw_multibuf/header_chunk_region_tracker.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 <cstddef>
17 #include <memory>
18 #include <optional>
19 
20 #include "pw_allocator/allocator.h"
21 #include "pw_bytes/span.h"
22 #include "pw_multibuf/chunk.h"
23 
24 namespace pw::multibuf {
25 
26 /// A ``ChunkRegionTracker`` which stores its ``Chunk`` and region metadata
27 /// in a ``allocator::Allocator`` allocation alongside the data.
28 ///
29 /// This is useful when testing and when there is no need for asynchronous
30 /// allocation.
31 class HeaderChunkRegionTracker final : public ChunkRegionTracker {
32  public:
33   /// Allocates a new ``Chunk`` region of ``size`` bytes  in ``alloc``.
34   ///
35   /// The underlyiing allocation will also store the
36   /// ``HeaderChunkRegionTracker`` itself. The allocated memory must not outlive
37   /// the provided allocator ``alloc``.
38   ///
39   /// Returns the newly-created ``OwnedChunk`` if successful.
AllocateRegionAsChunk(allocator::Allocator & alloc,size_t size)40   static std::optional<OwnedChunk> AllocateRegionAsChunk(
41       allocator::Allocator& alloc, size_t size) {
42     HeaderChunkRegionTracker* tracker = AllocateRegion(alloc, size);
43     if (tracker == nullptr) {
44       return std::nullopt;
45     }
46     std::optional<OwnedChunk> chunk = tracker->CreateFirstChunk();
47     if (!chunk.has_value()) {
48       tracker->Destroy();
49       return std::nullopt;
50     }
51     return chunk;
52   }
53 
54   /// Allocates a new region of ``size`` bytes  in ``alloc``.
55   ///
56   /// The underlyiing allocation will also store the
57   /// ``HeaderChunkRegionTracker`` itself. The allocated memory must not outlive
58   /// the provided allocator ``alloc``.
59   ///
60   /// Returns a pointer to the newly-created ``HeaderChunkRegionTracker``
61   /// or ``nullptr`` if the allocation failed.
AllocateRegion(allocator::Allocator & alloc,size_t size)62   static HeaderChunkRegionTracker* AllocateRegion(allocator::Allocator& alloc,
63                                                   size_t size) {
64     auto layout =
65         allocator::Layout::Of<HeaderChunkRegionTracker>().Extend(size);
66     void* ptr = alloc.Allocate(layout);
67     if (ptr == nullptr) {
68       return nullptr;
69     }
70     std::byte* data =
71         reinterpret_cast<std::byte*>(ptr) + sizeof(HeaderChunkRegionTracker);
72     return new (ptr) HeaderChunkRegionTracker(ByteSpan(data, size), alloc);
73   }
74 
Region()75   ByteSpan Region() const final { return region_; }
~HeaderChunkRegionTracker()76   ~HeaderChunkRegionTracker() final {}
77 
78  protected:
Destroy()79   void Destroy() final {
80     std::byte* ptr = reinterpret_cast<std::byte*>(this);
81     auto alloc = alloc_;
82     std::destroy_at(this);
83     alloc->Deallocate(ptr);
84   }
85 
AllocateChunkClass()86   void* AllocateChunkClass() final {
87     return alloc_->Allocate(allocator::Layout::Of<Chunk>());
88   }
89 
DeallocateChunkClass(void * ptr)90   void DeallocateChunkClass(void* ptr) final { alloc_->Deallocate(ptr); }
91 
92  private:
93   ByteSpan region_;
94   allocator::Allocator* alloc_;
95 
96   // NOTE: `region` must directly follow this `FakeChunkRegionTracker`
97   // in memory allocated by allocated by `alloc`.
HeaderChunkRegionTracker(ByteSpan region,allocator::Allocator & alloc)98   HeaderChunkRegionTracker(ByteSpan region, allocator::Allocator& alloc)
99       : region_(region), alloc_(&alloc) {}
100 };
101 
102 }  // namespace pw::multibuf
103