1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
15 #include "pw_allocator/freelist.h"
17 namespace pw::allocator {
19 Status FreeList::AddChunk(std::span<std::byte> chunk) {
20 // Check that the size is enough to actually store what we need
21 if (chunk.size() < sizeof(FreeListNode)) {
22 return Status::OutOfRange();
30 aliased.bytes = chunk.data();
32 size_t chunk_ptr = FindChunkPtrForSize(chunk.size(), false);
34 // Add it to the correct list.
35 aliased.node->size = chunk.size();
36 aliased.node->next = chunks_[chunk_ptr];
37 chunks_[chunk_ptr] = aliased.node;
42 std::span<std::byte> FreeList::FindChunk(size_t size) const {
44 return std::span<std::byte>();
47 size_t chunk_ptr = FindChunkPtrForSize(size, true);
49 // Check that there's data. This catches the case where we run off the
51 if (chunks_[chunk_ptr] == nullptr) {
52 return std::span<std::byte>();
55 // Now iterate up the buckets, walking each list to find a good candidate
56 for (size_t i = chunk_ptr; i < chunks_.size(); i++) {
61 aliased.node = chunks_[i];
63 while (aliased.node != nullptr) {
64 if (aliased.node->size >= size) {
65 return std::span<std::byte>(aliased.data, aliased.node->size);
68 aliased.node = aliased.node->next;
72 // If we get here, we've checked every block in every bucket. There's
73 // nothing that can support this allocation.
74 return std::span<std::byte>();
77 Status FreeList::RemoveChunk(std::span<std::byte> chunk) {
78 size_t chunk_ptr = FindChunkPtrForSize(chunk.size(), true);
80 // Walk that list, finding the chunk.
84 } aliased, aliased_next;
87 if (chunks_[chunk_ptr] == nullptr) {
88 return Status::NotFound();
91 aliased.node = chunks_[chunk_ptr];
92 if (aliased.data == chunk.data()) {
93 chunks_[chunk_ptr] = aliased.node->next;
98 // No? Walk the nodes.
99 aliased.node = chunks_[chunk_ptr];
101 while (aliased.node->next != nullptr) {
102 aliased_next.node = aliased.node->next;
103 if (aliased_next.data == chunk.data()) {
104 // Found it, remove this node out of the chain
105 aliased.node->next = aliased_next.node->next;
109 aliased.node = aliased.node->next;
112 return Status::NotFound();
115 size_t FreeList::FindChunkPtrForSize(size_t size, bool non_null) const {
116 size_t chunk_ptr = 0;
117 for (chunk_ptr = 0; chunk_ptr < sizes_.size(); chunk_ptr++) {
118 if (sizes_[chunk_ptr] >= size &&
119 (!non_null || chunks_[chunk_ptr] != nullptr)) {
127 } // namespace pw::allocator