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