Pigweed
 
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
33 : public containers::future::IntrusiveList<SequencedItem>::Item {};
34
41template <typename BlockType>
42class SequencedBucket : public internal::BucketBase<SequencedBucket<BlockType>,
43 BlockType,
44 SequencedItem> {
45 private:
46 using Base = internal::
47 BucketBase<SequencedBucket<BlockType>, BlockType, SequencedItem>;
48 friend Base;
49
50 public:
52
53 constexpr size_t threshold() const { return threshold_; }
54
61 void set_threshold(size_t threshold) { threshold_ = threshold; }
62
63 private:
65 void DoAdd(BlockType& block) {
66 auto* item_to_add = new (block.UsableSpace()) SequencedItem();
67 containers::future::IntrusiveList<SequencedItem>::iterator iter;
68 if (block.InnerSize() < threshold_) {
69 // Search from back.
70 auto r_iter = std::find_if(
71 items_.rbegin(), items_.rend(), [item_to_add](SequencedItem& item) {
72 return &item < item_to_add;
73 });
74
75 // If r_iter dereferences to the last address that is before than the
76 // item to add, then the corresponding forward iterator points to the
77 // first address that is after the item to add.
78 iter = r_iter.base();
79
80 } else {
81 // Search from front.
82 iter = std::find_if(
83 items_.begin(), items_.end(), [item_to_add](SequencedItem& item) {
84 return item_to_add < &item;
85 });
86 }
87 items_.insert(iter, *item_to_add);
88 }
89
91 BlockType* DoRemoveAny() {
92 SequencedItem& item = items_.front();
93 items_.pop_front();
94 return BlockType::FromUsableSpace(&item);
95 }
96
98 bool DoRemove(BlockType& block) {
99 SequencedItem& item_to_remove = Base::GetItemFrom(block);
100 if (block.InnerSize() >= threshold_) {
101 // Search from front and remove.
102 return items_.remove(item_to_remove);
103 }
104 // Search from back and remove.
105 auto iter = std::find_if(
106 items_.rbegin(), items_.rend(), [&item_to_remove](SequencedItem& item) {
107 return &item_to_remove == &item;
108 });
109 if (iter == items_.rend()) {
110 return false;
111 }
112 items_.erase(*iter);
113 return true;
114 }
115
117 BlockType* DoRemoveCompatible(Layout layout) {
118 auto predicate = Base::MakeCanAllocPredicate(layout);
119 SequencedItem* item = nullptr;
120 if (layout.size() < threshold_) {
121 // Search from back.
122 auto iter = std::find_if(items_.rbegin(), items_.rend(), predicate);
123 item = iter != items_.rend() ? &(*iter) : nullptr;
124 } else {
125 // Search from front.
126 auto iter = std::find_if(items_.begin(), items_.end(), predicate);
127 item = iter != items_.end() ? &(*iter) : nullptr;
128 }
129 if (item == nullptr) {
130 return nullptr;
131 }
132 auto* block = BlockType::FromUsableSpace(item);
133 items_.erase(*item);
134 return block;
135 }
136
137 containers::future::IntrusiveList<SequencedItem> items_;
138 size_t threshold_ = 0;
139};
140
141} // namespace pw::allocator
Definition: sequenced.h:44
void set_threshold(size_t threshold)
Definition: sequenced.h:61
Definition: sequenced.h:33
void Clear()
Removes all blocks from this bucket.
Definition: base.h:124
Definition: intrusive_list.h:82