OpenTTD Source 15.0-beta2
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.
uint8_t valid
Bits indicating what variable is valid (for each bit, 0 is invalid, 1 is valid).
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.