C/C++ API Reference
Loading...
Searching...
No Matches
sequenced.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 <algorithm>
17#include <cstddef>
18#include <iterator>
19
20#include "pw_allocator/bucket/base.h"
21#include "pw_containers/intrusive_list.h"
22
23namespace pw::allocator {
24
26
35 : public containers::future::IntrusiveList<SequencedItem>::Item {};
36
43template <typename BlockType>
44class SequencedBucket final
45 : public internal::
46 BucketBase<SequencedBucket<BlockType>, BlockType, SequencedItem> {
47 private:
48 using Base = internal::
49 BucketBase<SequencedBucket<BlockType>, BlockType, SequencedItem>;
50 friend Base;
51
52 public:
54
55 constexpr size_t threshold() const { return threshold_; }
56
63 void set_threshold(size_t threshold) { threshold_ = threshold; }
64
65 private:
67 void DoAdd(BlockType& block);
68
70 const BlockType* DoFindLargest() const;
71
73 BlockType* DoRemoveAny();
74
76 bool DoRemove(BlockType& block);
77
79 BlockType* DoRemoveCompatible(Layout layout);
80
82 size_t threshold_ = 0;
83};
84
86
87// Template method implementations.
88
89template <typename BlockType>
90SequencedBucket<BlockType>::~SequencedBucket() {
91 Base::Clear();
92}
93
94template <typename BlockType>
95void SequencedBucket<BlockType>::DoAdd(BlockType& block) {
96 auto* item_to_add = new (block.UsableSpace()) SequencedItem();
97 containers::future::IntrusiveList<SequencedItem>::iterator iter;
98 if (block.InnerSize() < threshold_) {
99 // Search from back.
100 auto r_iter = std::find_if(
101 items_.rbegin(), items_.rend(), [item_to_add](SequencedItem& item) {
102 return &item < item_to_add;
103 });
104
105 // If r_iter dereferences to the last address that is before than the
106 // item to add, then the corresponding forward iterator points to the
107 // first address that is after the item to add.
108 iter = r_iter.base();
109
110 } else {
111 // Search from front.
112 iter = std::find_if(
113 items_.begin(), items_.end(), [item_to_add](SequencedItem& item) {
114 return item_to_add < &item;
115 });
116 }
117 items_.insert(iter, *item_to_add);
118}
119
120template <typename BlockType>
121const BlockType* SequencedBucket<BlockType>::DoFindLargest() const {
122 auto iter = std::max_element(items_.begin(), items_.end(), Base::Compare);
123 return BlockType::FromUsableSpace(&(*iter));
124}
125
126template <typename BlockType>
127BlockType* SequencedBucket<BlockType>::DoRemoveAny() {
128 SequencedItem& item = items_.front();
129 items_.pop_front();
130 return BlockType::FromUsableSpace(&item);
131}
132
133template <typename BlockType>
134bool SequencedBucket<BlockType>::DoRemove(BlockType& block) {
135 SequencedItem& item_to_remove = Base::GetItemFrom(block);
136 if (block.InnerSize() >= threshold_) {
137 // Search from front and remove.
138 return items_.remove(item_to_remove);
139 }
140 // Search from back and remove.
141 auto iter = std::find_if(
142 items_.rbegin(), items_.rend(), [&item_to_remove](SequencedItem& item) {
143 return &item_to_remove == &item;
144 });
145 if (iter == items_.rend()) {
146 return false;
147 }
148 items_.erase(*iter);
149 return true;
150}
151
152template <typename BlockType>
153BlockType* SequencedBucket<BlockType>::DoRemoveCompatible(Layout layout) {
154 auto predicate = Base::MakeCanAllocPredicate(layout);
155 SequencedItem* item = nullptr;
156 if (layout.size() < threshold_) {
157 // Search from back.
158 auto iter = std::find_if(items_.rbegin(), items_.rend(), predicate);
159 item = iter != items_.rend() ? &(*iter) : nullptr;
160 } else {
161 // Search from front.
162 auto iter = std::find_if(items_.begin(), items_.end(), predicate);
163 item = iter != items_.end() ? &(*iter) : nullptr;
164 }
165 if (item == nullptr) {
166 return nullptr;
167 }
168 auto* block = BlockType::FromUsableSpace(item);
169 items_.erase(*item);
170 return block;
171}
172
173} // namespace pw::allocator
Definition: layout.h:64
Definition: sequenced.h:46
void set_threshold(size_t threshold)
Definition: sequenced.h:63
Definition: sequenced.h:35
Definition: intrusive_list.h:88
SmallBlock BlockType
Default block type to use for tests.
Definition: size_report.h:32