xref: /aosp_15_r20/external/pigweed/pw_allocator/chunk_pool.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 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 
15 #include "pw_allocator/chunk_pool.h"
16 
17 #include "lib/stdcompat/bit.h"
18 #include "pw_allocator/buffer.h"
19 #include "pw_assert/check.h"
20 #include "pw_bytes/alignment.h"
21 
22 namespace pw::allocator {
23 
EnsurePointerLayout(const Layout & layout)24 static Layout EnsurePointerLayout(const Layout& layout) {
25   return Layout(std::max(layout.size(), sizeof(void*)),
26                 std::max(layout.alignment(), alignof(void*)));
27 }
28 
ChunkPool(ByteSpan region,const Layout & layout)29 ChunkPool::ChunkPool(ByteSpan region, const Layout& layout)
30     : Pool(kCapabilities, layout),
31       allocated_layout_(EnsurePointerLayout(layout)) {
32   Result<ByteSpan> result =
33       GetAlignedSubspan(region, allocated_layout_.alignment());
34   PW_CHECK_OK(result.status());
35   start_ = cpp20::bit_cast<uintptr_t>(region.data());
36   end_ = start_ + region.size() - (region.size() % allocated_layout_.size());
37   region = result.value();
38   next_ = region.data();
39   std::byte* current = next_;
40   std::byte* end = current + region.size();
41   std::byte** next = &current;
42   while (current < end) {
43     next = std::launder(reinterpret_cast<std::byte**>(current));
44     current += allocated_layout_.size();
45     *next = current;
46   }
47   *next = nullptr;
48 }
49 
DoAllocate()50 void* ChunkPool::DoAllocate() {
51   if (next_ == nullptr) {
52     return nullptr;
53   }
54   std::byte* ptr = next_;
55   next_ = *(std::launder(reinterpret_cast<std::byte**>(next_)));
56   return ptr;
57 }
58 
DoDeallocate(void * ptr)59 void ChunkPool::DoDeallocate(void* ptr) {
60   if (ptr == nullptr) {
61     return;
62   }
63   std::byte** next = std::launder(reinterpret_cast<std::byte**>(ptr));
64   *next = next_;
65   next_ = cpp20::bit_cast<std::byte*>(ptr);
66 }
67 
DoGetInfo(InfoType info_type,const void * ptr) const68 Result<Layout> ChunkPool::DoGetInfo(InfoType info_type, const void* ptr) const {
69   if (info_type == InfoType::kCapacity) {
70     return Layout(end_ - start_, allocated_layout_.alignment());
71   }
72   auto addr = cpp20::bit_cast<uintptr_t>(ptr);
73   if (addr < start_ || end_ <= addr) {
74     return Status::OutOfRange();
75   }
76   if ((addr - start_) % allocated_layout_.size() != 0) {
77     return Status::OutOfRange();
78   }
79   switch (info_type) {
80     case InfoType::kRequestedLayoutOf:
81     case InfoType::kUsableLayoutOf:
82     case InfoType::kAllocatedLayoutOf:
83       return allocated_layout_;
84     case InfoType::kRecognizes:
85       return Layout();
86     case InfoType::kCapacity:
87     default:
88       return Status::Unimplemented();
89   }
90 }
91 
92 }  // namespace pw::allocator
93