20#include "pw_allocator/block/detailed_block.h"
21#include "pw_allocator/block_allocator.h"
22#include "pw_allocator/bucket/fast_sorted.h"
23#include "pw_allocator/bucket/sorted.h"
25namespace pw::allocator {
30template <
typename OffsetType>
84template <
typename BlockType = TlsfBlock<u
int32_t>,
85 size_t kMinSize = TlsfDefaults::kMinSize,
86 size_t kNumShelves = TlsfDefaults::kNumShelves>
91 static constexpr size_t kNumBucketsPerShelf = 16;
92 static constexpr size_t kBucketBits =
97 using Shelf = std::array<LargeBucket, kNumBucketsPerShelf>;
99 static_assert(kMinSize >= kNumBucketsPerShelf,
100 "kMinSize must be at least 16.");
103 "kMinSize must be large enough to hold a FastSortedBucket item.");
104 static_assert((kMinSize & (kMinSize - 1)) == 0,
105 "kMinSize must be a power of two.");
107 static_assert(kNumShelves <= 32,
"kNumShelves cannot be larger than 32");
147 void UpdateBitmaps(
const TlsfIndices& indices,
bool empty);
149 uint32_t shelf_bitmap_ = 0;
150 std::array<uint16_t, kNumShelves> bucket_bitmaps_;
151 std::array<Shelf, kNumShelves> shelves_;
152 SmallBucket small_bucket_;
159template <
typename BlockType,
size_t kMinSize,
size_t kNumShelves>
161 size_t size = kMinSize;
162 size_t step = kMinSize / kNumBucketsPerShelf;
163 for (Shelf& shelf : shelves_) {
166 bucket.set_max_inner_size(size - 1);
172 LargeBucket& largest = shelves_[kNumShelves - 1][kNumBucketsPerShelf - 1];
175 bucket_bitmaps_.fill(0);
178template <
typename BlockType,
size_t kMinSize,
size_t kNumShelves>
182 uint16_t bucket_bitmap = bucket_bitmaps_[shelf_index];
183 size_t bucket_index =
185 const LargeBucket& bucket = shelves_[shelf_index][bucket_index];
186 const BlockType* largest =
188 return largest ==
nullptr ? 0 : largest->InnerSize();
191template <
typename BlockType,
size_t kMinSize,
size_t kNumShelves>
195 if (layout.size() < small_bucket_.max_inner_size()) {
196 BlockType* block = small_bucket_.RemoveCompatible(layout);
197 if (block !=
nullptr) {
198 return BlockType::AllocFirst(std::move(block), layout);
203 for (
TlsfIndices indices = MapToIndices(layout.size());
204 FindNextAvailable(indices);
206 LargeBucket& bucket = shelves_[indices.shelf][indices.bucket];
208 if (block !=
nullptr) {
209 UpdateBitmaps(indices, bucket.
empty());
210 return BlockType::AllocFirst(std::move(block), layout);
218template <
typename BlockType,
size_t kMinSize,
size_t kNumShelves>
222 std::ignore = small_bucket_.Remove(block);
225 TlsfIndices indices = MapToIndices(block.InnerSize());
226 LargeBucket& large_bucket = shelves_[indices.shelf][indices.bucket];
227 if (large_bucket.
Remove(block)) {
228 UpdateBitmaps(indices, large_bucket.
empty());
232template <
typename BlockType,
size_t kMinSize,
size_t kNumShelves>
236 std::ignore = small_bucket_.Add(block);
239 TlsfIndices indices = MapToIndices(block.InnerSize());
240 LargeBucket& large_bucket = shelves_[indices.shelf][indices.bucket];
241 std::ignore = large_bucket.
Add(block);
242 UpdateBitmaps(indices,
false);
245template <
typename BlockType,
size_t kMinSize,
size_t kNumShelves>
248 if (size <= kMinSize) {
255 auto bucket =
static_cast<uint16_t
>((size >> (shelf - kBucketBits)) & 0xF);
259 if (shelf >= kNumShelves) {
260 shelf = kNumShelves - 1;
261 bucket = kNumBucketsPerShelf - 1;
263 return TlsfIndices{.shelf =
static_cast<uint32_t
>(shelf), .bucket = bucket};
266template <
typename BlockType,
size_t kMinSize,
size_t kNumShelves>
267bool TlsfAllocator<BlockType, kMinSize, kNumShelves>::FindNextAvailable(
268 TlsfIndices& indices) {
270 if (indices.bucket == kNumBucketsPerShelf) {
276 if (indices.shelf >= kNumShelves) {
281 uint16_t bucket_bitmap =
282 bucket_bitmaps_[indices.shelf] & (~uint32_t(0) << indices.bucket);
283 if (bucket_bitmap != 0) {
293 uint32_t shelf_bitmap = shelf_bitmap_ & (~uint32_t(0) << (indices.shelf + 1));
294 if (shelf_bitmap != 0) {
304template <
typename BlockType,
size_t kMinSize,
size_t kNumShelves>
305void TlsfAllocator<BlockType, kMinSize, kNumShelves>::UpdateBitmaps(
306 const TlsfIndices& indices,
bool empty) {
307 auto bucket_bitmap =
static_cast<uint16_t
>(1 << indices.bucket);
309 bucket_bitmaps_[indices.shelf] &= ~bucket_bitmap;
311 bucket_bitmaps_[indices.shelf] |= bucket_bitmap;
314 uint32_t shelf_bitmap = uint32_t(1) << indices.shelf;
315 if (bucket_bitmaps_[indices.shelf] == 0) {
316 shelf_bitmap_ &= ~shelf_bitmap;
318 shelf_bitmap_ |= shelf_bitmap;
Definition: block_allocator.h:106
void Init(ByteSpan region)
Definition: block_allocator.h:310
Definition: detailed_block.h:88
Definition: fast_sorted.h:65
Definition: fast_sorted.h:35
Definition: tlsf_allocator.h:87
size_t DoGetMaxAllocatable() override
Definition: tlsf_allocator.h:179
BlockResult< BlockType > ChooseBlock(Layout layout) override
Definition: tlsf_allocator.h:193
TlsfAllocator(ByteSpan region)
Definition: tlsf_allocator.h:118
void ReserveBlock(BlockType &block) override
Definition: tlsf_allocator.h:219
constexpr TlsfAllocator()
Constexpr constructor. Callers must explicitly call Init.
Definition: tlsf_allocator.h:160
void RecycleBlock(BlockType &block) override
Definition: tlsf_allocator.h:233
constexpr void set_max_inner_size(size_t max_inner_size)
Definition: base.h:78
bool Remove(BlockType &block)
Definition: base.h:118
const BlockType * FindLargest() const
Definition: base.h:103
bool Add(BlockType &block)
Definition: base.h:89
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
Definition: fast_sorted.h:53
Definition: tlsf_allocator.h:36
static constexpr size_t kMinSize
Definition: tlsf_allocator.h:39
static constexpr size_t kNumShelves
Definition: tlsf_allocator.h:43
Pair used to index a bucket in a two dimensional array.
Definition: tlsf_allocator.h:47