Pigweed
Loading...
Searching...
No Matches
bucket_block_allocator.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 <array>
17
18#include "pw_allocator/block_allocator.h"
19#include "pw_allocator/bucket.h"
20#include "pw_assert/assert.h"
21#include "pw_status/try.h"
22
23namespace pw::allocator {
24
50template <typename OffsetType = uintptr_t,
51 size_t kMinBucketChunkSize = 32,
52 size_t kNumBuckets = 5,
53 size_t kAlign = std::max(alignof(OffsetType), alignof(std::byte*))>
55 : public BlockAllocator<OffsetType,
56 0,
57 std::max(kAlign, alignof(std::byte*))> {
58 public:
59 using Base =
60 BlockAllocator<OffsetType, 0, std::max(kAlign, alignof(std::byte*))>;
61 using BlockType = typename Base::BlockType;
62
64 constexpr BucketBlockAllocator() : Base() {}
65
72 explicit BucketBlockAllocator(ByteSpan region) : BucketBlockAllocator() {
73 Base::Init(region);
74 }
75
77 void Init(ByteSpan region) { Base::Init(region); }
78
80 void Init(BlockType* begin) { Base::Init(begin); }
81
83 void Init(BlockType* begin, BlockType* end) override {
84 Base::Init(begin, end);
85 internal::Bucket::Init(span(buckets_.data(), buckets_.size() - 1),
86 kMinBucketChunkSize);
87 buckets_.back().Init();
88 for (auto* block : Base::blocks()) {
89 if (!block->Used()) {
90 RecycleBlock(block);
91 }
92 }
93 }
94
95 private:
97 BlockType* ChooseBlock(Layout layout) override {
98 layout =
99 Layout(std::max(layout.size(), sizeof(internal::Bucket::Chunk)),
100 std::max(layout.alignment(), alignof(internal::Bucket::Chunk)));
101 for (auto& bucket : buckets_) {
102 if (bucket.chunk_size() < layout.size()) {
103 continue;
104 }
105 void* chosen = bucket.RemoveIf([&layout](const std::byte* chunk) {
106 const BlockType* block = BlockType::FromUsableSpace(chunk);
107 return block->CanAllocLast(layout).ok();
108 });
109 if (chosen == nullptr) {
110 continue;
111 }
112 BlockType* block = BlockType::FromUsableSpace(chosen);
113 BlockType* prev = block;
114 BlockType::AllocLast(block, layout).IgnoreError();
115
116 // If the chunk was split, what we have is the leading free block.
117 if (prev != block) {
118 RecycleBlock(prev);
119 }
120 return block;
121 }
122 return nullptr;
123 }
124
126 void ReserveBlock(BlockType* block) override {
127 PW_ASSERT(!block->Used());
128 size_t inner_size = block->InnerSize();
129 if (inner_size < sizeof(internal::Bucket::Chunk)) {
130 return;
131 }
132 internal::Bucket::Remove(block->UsableSpace());
133 }
134
136 void RecycleBlock(BlockType* block) override {
137 PW_ASSERT(!block->Used());
138 size_t inner_size = block->InnerSize();
139 if (inner_size < sizeof(internal::Bucket::Chunk)) {
140 return;
141 }
142 for (auto& bucket : buckets_) {
143 if (inner_size <= bucket.chunk_size()) {
144 bucket.Add(block->UsableSpace());
145 break;
146 }
147 }
148 }
149
150 std::array<internal::Bucket, kNumBuckets> buckets_;
151};
152
153} // namespace pw::allocator
Definition: block_allocator.h:79
void Init(ByteSpan region)
Definition: block_allocator.h:251
Range blocks() const
Returns a Range of blocks tracking the memory of this allocator.
Definition: block_allocator.h:237
Definition: block.h:108
Definition: bucket_block_allocator.h:57
void Init(BlockType *begin, BlockType *end) override
Definition: bucket_block_allocator.h:83
void Init(BlockType *begin)
Definition: bucket_block_allocator.h:80
constexpr BucketBlockAllocator()
Constexpr constructor. Callers must explicitly call Init.
Definition: bucket_block_allocator.h:64
void Init(ByteSpan region)
Definition: bucket_block_allocator.h:77
BucketBlockAllocator(ByteSpan region)
Definition: bucket_block_allocator.h:72
Definition: layout.h:39