OpenTTD Source 20250813-master-g5b5bdd346d
smallstack_type.hpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#ifndef SMALLSTACK_TYPE_HPP
11#define SMALLSTACK_TYPE_HPP
12
18template <typename Titem, typename Tindex, Tindex Tgrowth_step, Tindex Tmax_size>
20public:
21 inline SimplePool() : first_unused(0), first_free(0) {}
22
27 inline Titem &Get(Tindex index) { return this->data[index]; }
28
33 inline Tindex Create()
34 {
35 Tindex index = this->FindFirstFree();
36 if (index < Tmax_size) {
37 this->data[index].valid = true;
38 this->first_free = index + 1;
39 this->first_unused = std::max(this->first_unused, this->first_free);
40 }
41 return index;
42 }
43
48 inline void Destroy(Tindex index)
49 {
50 this->data[index].valid = false;
51 this->first_free = std::min(this->first_free, index);
52 }
53
54private:
55
56 inline Tindex FindFirstFree()
57 {
58 Tindex index = this->first_free;
59 for (; index < this->first_unused; index++) {
60 if (!this->data[index].valid) return index;
61 }
62
63 if (index >= this->data.size() && index < Tmax_size) {
64 this->data.resize(index + 1);
65 }
66 return index;
67 }
68
69 struct SimplePoolPoolItem : public Titem {
70 bool valid;
71 };
72
73 Tindex first_unused;
74 Tindex first_free;
75
76 std::vector<SimplePoolPoolItem> data;
77};
78
83template <typename Titem, typename Tindex>
85 Tindex next;
86 Titem value;
87
93 inline SmallStackItem(const Titem &value, Tindex next) :
94 next(next), value(value) {}
95 SmallStackItem() = default;
96};
97
120template <typename Titem, typename Tindex, auto Tinvalid_value, Tindex Tgrowth_step, Tindex Tmax_size>
121class SmallStack : public SmallStackItem<Titem, Tindex> {
122public:
123 static constexpr Titem Tinvalid{Tinvalid_value};
124
126
130 struct PooledSmallStack : public Item {
132 };
133
135
140 inline SmallStack(const Titem &value = Tinvalid) : Item(value, Tmax_size) {}
141
145 inline ~SmallStack()
146 {
147 while (this->next != Tmax_size) this->Pop();
148 }
149
154 inline SmallStack(const SmallStack &other) : Item(other) { this->Branch(); }
155
161 inline SmallStack &operator=(const SmallStack &other)
162 {
163 if (this == &other) return *this;
164 while (this->next != Tmax_size) this->Pop();
165 this->next = other.next;
166 this->value = other.value;
167 /* Deleting and branching are independent operations, so it's fine to
168 * acquire separate locks for them. */
169 this->Branch();
170 return *this;
171 }
172
178 inline void Push(const Titem &item)
179 {
180 if (this->value != Tinvalid) {
181 Tindex new_item = SmallStack::GetPool().Create();
182 if (new_item != Tmax_size) {
183 PooledSmallStack &pushed = SmallStack::GetPool().Get(new_item);
184 pushed.value = this->value;
185 pushed.next = this->next;
186 pushed.branch_count = 0;
187 this->next = new_item;
188 }
189 }
190 this->value = item;
191 }
192
197 inline Titem Pop()
198 {
199 Titem ret = this->value;
200 if (this->next == Tmax_size) {
201 this->value = Tinvalid;
202 } else {
203 PooledSmallStack &popped = SmallStack::GetPool().Get(this->next);
204 this->value = popped.value;
205 if (popped.branch_count == 0) {
206 SmallStack::GetPool().Destroy(this->next);
207 } else {
208 --popped.branch_count;
209 if (popped.next != Tmax_size) {
210 ++(SmallStack::GetPool().Get(popped.next).branch_count);
211 }
212 }
213 /* Accessing popped here is no problem as the pool will only set
214 * the validity flag, not actually delete the item, on Destroy(). */
215 this->next = popped.next;
216 }
217 return ret;
218 }
219
224 inline bool IsEmpty() const
225 {
226 return this->value == Tinvalid && this->next == Tmax_size;
227 }
228
234 inline bool Contains(const Titem &item) const
235 {
236 if (item == Tinvalid || item == this->value) return true;
237 if (this->next != Tmax_size) {
238 const SmallStack *in_list = this;
239 do {
240 in_list = static_cast<const SmallStack *>(
241 static_cast<const Item *>(&SmallStack::GetPool().Get(in_list->next)));
242 if (in_list->value == item) return true;
243 } while (in_list->next != Tmax_size);
244 }
245 return false;
246 }
247
248protected:
249 static SmallStackPool &GetPool()
250 {
251 static SmallStackPool pool;
252 return pool;
253 }
254
258 inline void Branch()
259 {
260 if (this->next != Tmax_size) {
261 ++(SmallStack::GetPool().Get(this->next).branch_count);
262 }
263 }
264};
265
266#endif
A simplified pool which stores values instead of pointers and doesn't redefine operator new/delete.
Titem & Get(Tindex index)
Get the item at position index.
Tindex Create()
Create a new item and return its index.
void Destroy(Tindex index)
Destroy (or rather invalidate) the item at the given index.
Minimal stack that uses a pool to avoid pointers.
SmallStack(const Titem &value=Tinvalid)
Constructor for a stack with one or two items in it.
SmallStack(const SmallStack &other)
Shallow copy the stack, marking the first item as branched.
void Branch()
Create a branch in the pool if necessary.
void Push(const Titem &item)
Pushes a new item onto the stack if there is still space in the underlying pool.
~SmallStack()
Remove the head of stack and all other items members that are unique to it.
Titem Pop()
Pop an item from the stack.
SmallStack & operator=(const SmallStack &other)
Shallow copy the stack, marking the first item as branched.
bool Contains(const Titem &item) const
Check if the given item is contained in the stack.
bool IsEmpty() const
Check if the stack is empty.
Base class for SmallStack.
Titem value
Value of current item.
Tindex next
Pool index of next item.
SmallStackItem(const Titem &value, Tindex next)
Create a new item.
SmallStack item that can be kept in a pool.
Tindex branch_count
Number of branches in the tree structure this item is parent of.