OpenTTD Source 20250521-master-g82876c25e0
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, Titem Tinvalid, Tindex Tgrowth_step, Tindex Tmax_size>
121class SmallStack : public SmallStackItem<Titem, Tindex> {
122public:
123
125
129 struct PooledSmallStack : public Item {
131 };
132
134
139 inline SmallStack(const Titem &value = Tinvalid) : Item(value, Tmax_size) {}
140
144 inline ~SmallStack()
145 {
146 while (this->next != Tmax_size) this->Pop();
147 }
148
153 inline SmallStack(const SmallStack &other) : Item(other) { this->Branch(); }
154
160 inline SmallStack &operator=(const SmallStack &other)
161 {
162 if (this == &other) return *this;
163 while (this->next != Tmax_size) this->Pop();
164 this->next = other.next;
165 this->value = other.value;
166 /* Deleting and branching are independent operations, so it's fine to
167 * acquire separate locks for them. */
168 this->Branch();
169 return *this;
170 }
171
177 inline void Push(const Titem &item)
178 {
179 if (this->value != Tinvalid) {
180 Tindex new_item = SmallStack::GetPool().Create();
181 if (new_item != Tmax_size) {
182 PooledSmallStack &pushed = SmallStack::GetPool().Get(new_item);
183 pushed.value = this->value;
184 pushed.next = this->next;
185 pushed.branch_count = 0;
186 this->next = new_item;
187 }
188 }
189 this->value = item;
190 }
191
196 inline Titem Pop()
197 {
198 Titem ret = this->value;
199 if (this->next == Tmax_size) {
200 this->value = Tinvalid;
201 } else {
202 PooledSmallStack &popped = SmallStack::GetPool().Get(this->next);
203 this->value = popped.value;
204 if (popped.branch_count == 0) {
205 SmallStack::GetPool().Destroy(this->next);
206 } else {
207 --popped.branch_count;
208 if (popped.next != Tmax_size) {
209 ++(SmallStack::GetPool().Get(popped.next).branch_count);
210 }
211 }
212 /* Accessing popped here is no problem as the pool will only set
213 * the validity flag, not actually delete the item, on Destroy(). */
214 this->next = popped.next;
215 }
216 return ret;
217 }
218
223 inline bool IsEmpty() const
224 {
225 return this->value == Tinvalid && this->next == Tmax_size;
226 }
227
233 inline bool Contains(const Titem &item) const
234 {
235 if (item == Tinvalid || item == this->value) return true;
236 if (this->next != Tmax_size) {
237 const SmallStack *in_list = this;
238 do {
239 in_list = static_cast<const SmallStack *>(
240 static_cast<const Item *>(&SmallStack::GetPool().Get(in_list->next)));
241 if (in_list->value == item) return true;
242 } while (in_list->next != Tmax_size);
243 }
244 return false;
245 }
246
247protected:
248 static SmallStackPool &GetPool()
249 {
250 static SmallStackPool pool;
251 return pool;
252 }
253
257 inline void Branch()
258 {
259 if (this->next != Tmax_size) {
260 ++(SmallStack::GetPool().Get(this->next).branch_count);
261 }
262 }
263};
264
265#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 & 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.
void Branch()
Create a branch in the pool if necessary.
Titem Pop()
Pop an item from the stack.
SmallStack(const SmallStack &other)
Shallow copy the stack, marking the first item as branched.
SmallStack(const Titem &value=Tinvalid)
Constructor for a stack with one or two items in it.
bool IsEmpty() const
Check if the stack is empty.
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.
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.