C/C++ API Reference
Loading...
Searching...
No Matches
base.h
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#pragma once
15
16#include <cstddef>
17#include <limits>
18
19#include "pw_allocator/block/poisonable.h"
20#include "pw_allocator/config.h"
21#include "pw_allocator/hardening.h"
22#include "pw_allocator/layout.h"
23#include "pw_assert/assert.h"
24#include "pw_bytes/alignment.h"
25
26namespace pw::allocator::internal {
27
29
56template <typename Derived, typename BlockType_, typename ItemType_>
58 public:
59 using BlockType = BlockType_;
60 using ItemType = ItemType_;
61
62 constexpr BucketBase() {
63 if constexpr (is_poisonable_v<BlockType>) {
64 static_assert(BlockType::kPoisonOffset >= sizeof(ItemType),
65 "Block type does not reserve sufficient space for an item");
66 }
67 }
68
70 constexpr bool empty() const { return derived()->items_.empty(); }
71
73 constexpr size_t max_inner_size() const { return max_inner_size_; }
74
78 constexpr void set_max_inner_size(size_t max_inner_size) {
79 if constexpr (Hardening::kIncludesDebugChecks) {
80 PW_ASSERT(empty());
81 }
82 max_inner_size_ = max_inner_size;
83 }
84
89 [[nodiscard]] bool Add(BlockType& block) {
90 if (block.InnerSize() < sizeof(ItemType)) {
91 return false;
92 }
93 if constexpr (Hardening::kIncludesDebugChecks) {
94 PW_ASSERT(block.InnerSize() <= max_inner_size_);
95 PW_ASSERT(IsAlignedAs<ItemType>(block.UsableSpace()));
96 }
97 derived()->DoAdd(block);
98 return true;
99 }
100
103 const BlockType* FindLargest() const {
104 return empty() ? nullptr : derived()->DoFindLargest();
105 }
106
110 [[nodiscard]] BlockType* RemoveAny() {
111 return empty() ? nullptr : derived()->DoRemoveAny();
112 }
113
118 [[nodiscard]] bool Remove(BlockType& block) {
119 return block.InnerSize() >= sizeof(ItemType) && derived()->DoRemove(block);
120 }
121
129 [[nodiscard]] BlockType* RemoveCompatible(Layout layout) {
130 return derived()->DoRemoveCompatible(layout);
131 }
132
134 void Clear() { derived()->items_.clear(); }
135
136 protected:
149 template <typename Iterator, typename Predicate>
150 static Iterator FindPrevIf(Iterator before_first,
151 Iterator last,
152 Predicate predicate) {
153 Iterator prev = before_first;
154 Iterator iter = prev;
155 ++iter;
156 for (; iter != last; ++iter) {
157 if (predicate(*iter)) {
158 break;
159 }
160 prev = iter;
161 }
162 return prev;
163 }
164
169 static auto MakeCanAllocPredicate(Layout layout) {
170 return [layout](ItemType& item) {
171 auto* block = BlockType::FromUsableSpace(&item);
172 return block->CanAlloc(layout).ok();
173 };
174 }
175
178 static bool Compare(const ItemType& item1, const ItemType& item2) {
179 const BlockType* block1 = BlockType::FromUsableSpace(&item1);
180 const BlockType* block2 = BlockType::FromUsableSpace(&item2);
181 return block1->InnerSize() < block2->InnerSize();
182 }
183
186 template <typename Iterator>
187 constexpr static BlockType* GetBlockFromIterator(Iterator iter,
188 Iterator last) {
189 return iter != last ? BlockType::FromUsableSpace(&(*iter)) : nullptr;
190 }
191
194 template <typename Iterator>
195 constexpr static BlockType* GetBlockFromPrev(Iterator prev, Iterator last) {
196 return GetBlockFromIterator(++prev, last);
197 }
198
205 static ItemType& GetItemFrom(BlockType& block) {
206 return *(std::launder(reinterpret_cast<ItemType*>(block.UsableSpace())));
207 }
208
209 private:
210 constexpr Derived* derived() { return static_cast<Derived*>(this); }
211 constexpr const Derived* derived() const {
212 return static_cast<const Derived*>(this);
213 }
214
216 size_t max_inner_size_ = std::numeric_limits<size_t>::max();
217};
218
223template <typename T, typename U = size_t>
224constexpr U CountRZero(T t) {
225 return static_cast<U>(cpp20::countr_zero(t));
226}
227
232template <typename T, typename U = size_t>
233constexpr U CountLZero(T t) {
234 return static_cast<U>(cpp20::countl_zero(t));
235}
236
238
239} // namespace pw::allocator::internal
Definition: layout.h:58
static constexpr BlockType * GetBlockFromPrev(Iterator prev, Iterator last)
Definition: base.h:195
constexpr void set_max_inner_size(size_t max_inner_size)
Definition: base.h:78
bool Remove(BlockType &block)
Definition: base.h:118
static bool Compare(const ItemType &item1, const ItemType &item2)
Definition: base.h:178
constexpr size_t max_inner_size() const
Returns the configured maximum inner size for blocks in this bucket.
Definition: base.h:73
BlockType * RemoveAny()
Definition: base.h:110
const BlockType * FindLargest() const
Definition: base.h:103
static auto MakeCanAllocPredicate(Layout layout)
Definition: base.h:169
void Clear()
Removes all blocks from this bucket.
Definition: base.h:134
static ItemType & GetItemFrom(BlockType &block)
Definition: base.h:205
bool Add(BlockType &block)
Definition: base.h:89
static Iterator FindPrevIf(Iterator before_first, Iterator last, Predicate predicate)
Definition: base.h:150
static constexpr BlockType * GetBlockFromIterator(Iterator iter, Iterator last)
Definition: base.h:187
constexpr bool empty() const
Returns whether this buckets contains any free blocks.
Definition: base.h:70
BlockType * RemoveCompatible(Layout layout)
Definition: base.h:129
constexpr U CountRZero(T t)
Definition: base.h:224
constexpr U CountLZero(T t)
Definition: base.h:233