OpenTTD Source 20250205-master-gfd85ab1e2c
pool_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 POOL_TYPE_HPP
11#define POOL_TYPE_HPP
12
13#include "enum_type.hpp"
14
16enum class PoolType : uint8_t {
17 Normal,
20 Data,
21};
24
25typedef std::vector<struct PoolBase *> PoolVector;
26
28struct PoolBase {
29 const PoolType type;
30
36 {
37 static PoolVector *pools = new PoolVector();
38 return pools;
39 }
40
41 static void Clean(PoolTypes);
42
48 {
49 PoolBase::GetPools()->push_back(this);
50 }
51
52 virtual ~PoolBase();
53
57 virtual void CleanPool() = 0;
58
59private:
64 PoolBase(const PoolBase &other);
65};
66
78template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type = PoolType::Normal, bool Tcache = false, bool Tzero = true>
79struct Pool : PoolBase {
80private:
82 template <typename T>
83 static constexpr size_t GetMaxIndexValue(T) { return std::numeric_limits<T>::max(); }
84 template <typename T> requires std::is_enum_v<T>
85 static constexpr size_t GetMaxIndexValue(T) { return std::numeric_limits<std::underlying_type_t<T>>::max(); }
86public:
87 /* Ensure the highest possible index, i.e. Tmax_size -1, is within the bounds of Tindex. */
88 static_assert(Tmax_size - 1 <= GetMaxIndexValue(Tindex{}));
89
90 static constexpr size_t MAX_SIZE = Tmax_size;
91
92 using BitmapStorage = size_t;
93 static constexpr size_t BITMAP_SIZE = std::numeric_limits<BitmapStorage>::digits;
94
95 const char * const name;
96
97 size_t first_free;
98 size_t first_unused;
99 size_t items;
100#ifdef WITH_ASSERT
101 size_t checked;
102#endif /* WITH_ASSERT */
103 bool cleaning;
104
105 std::vector<Titem *> data;
106 std::vector<BitmapStorage> used_bitmap;
107
108 Pool(const char *name);
109 void CleanPool() override;
110
117 inline Titem *Get(size_t index)
118 {
119 assert(index < this->first_unused);
120 return this->data[index];
121 }
122
128 inline bool IsValidID(size_t index)
129 {
130 return index < this->first_unused && this->Get(index) != nullptr;
131 }
132
138 inline bool CanAllocate(size_t n = 1)
139 {
140 bool ret = this->items <= Tmax_size - n;
141#ifdef WITH_ASSERT
142 this->checked = ret ? n : 0;
143#endif /* WITH_ASSERT */
144 return ret;
145 }
146
151 template <class T>
153 typedef T value_type;
154 typedef T *pointer;
155 typedef T &reference;
156 typedef size_t difference_type;
157 typedef std::forward_iterator_tag iterator_category;
158
159 explicit PoolIterator(size_t index) : index(index)
160 {
161 this->ValidateIndex();
162 };
163
164 bool operator==(const PoolIterator &other) const { return this->index == other.index; }
165 bool operator!=(const PoolIterator &other) const { return !(*this == other); }
166 T * operator*() const { return T::Get(this->index); }
167 PoolIterator & operator++() { this->index++; this->ValidateIndex(); return *this; }
168
169 private:
170 size_t index;
171 void ValidateIndex()
172 {
173 while (this->index < T::GetPoolSize() && !(T::IsValidID(this->index))) this->index++;
174 if (this->index >= T::GetPoolSize()) this->index = T::Pool::MAX_SIZE;
175 }
176 };
177
178 /*
179 * Iterable ensemble of all valid T
180 * @tparam T Type of the class/struct that is going to be iterated
181 */
182 template <class T>
184 size_t from;
185 IterateWrapper(size_t from = 0) : from(from) {}
186 PoolIterator<T> begin() { return PoolIterator<T>(this->from); }
187 PoolIterator<T> end() { return PoolIterator<T>(T::Pool::MAX_SIZE); }
188 bool empty() { return this->begin() == this->end(); }
189 };
190
195 template <class T, class F>
197 typedef T value_type;
198 typedef T *pointer;
199 typedef T &reference;
200 typedef size_t difference_type;
201 typedef std::forward_iterator_tag iterator_category;
202
203 explicit PoolIteratorFiltered(size_t index, F filter) : index(index), filter(filter)
204 {
205 this->ValidateIndex();
206 };
207
208 bool operator==(const PoolIteratorFiltered &other) const { return this->index == other.index; }
209 bool operator!=(const PoolIteratorFiltered &other) const { return !(*this == other); }
210 T * operator*() const { return T::Get(this->index); }
211 PoolIteratorFiltered & operator++() { this->index++; this->ValidateIndex(); return *this; }
212
213 private:
214 size_t index;
215 F filter;
216 void ValidateIndex()
217 {
218 while (this->index < T::GetPoolSize() && !(T::IsValidID(this->index) && this->filter(this->index))) this->index++;
219 if (this->index >= T::GetPoolSize()) this->index = T::Pool::MAX_SIZE;
220 }
221 };
222
223 /*
224 * Iterable ensemble of all valid T
225 * @tparam T Type of the class/struct that is going to be iterated
226 */
227 template <class T, class F>
229 size_t from;
230 F filter;
231 IterateWrapperFiltered(size_t from, F filter) : from(from), filter(filter) {}
232 PoolIteratorFiltered<T, F> begin() { return PoolIteratorFiltered<T, F>(this->from, this->filter); }
233 PoolIteratorFiltered<T, F> end() { return PoolIteratorFiltered<T, F>(T::Pool::MAX_SIZE, this->filter); }
234 bool empty() { return this->begin() == this->end(); }
235 };
236
241 template <struct Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero> *Tpool>
242 struct PoolItem {
243 Tindex index;
244
246 typedef struct Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero> Pool;
247
254 inline void *operator new(size_t size)
255 {
256 return Tpool->GetNew(size);
257 }
258
264 inline void operator delete(void *p)
265 {
266 if (p == nullptr) return;
267 Titem *pn = static_cast<Titem *>(p);
268 assert(pn == Tpool->Get(pn->index));
269 Tpool->FreeItem(pn->index);
270 }
271
280 inline void *operator new(size_t size, size_t index)
281 {
282 return Tpool->GetNew(size, index);
283 }
284
292 inline void *operator new(size_t, void *ptr)
293 {
294 for (size_t i = 0; i < Tpool->first_unused; i++) {
295 /* Don't allow creating new objects over existing.
296 * Even if we called the destructor and reused this memory,
297 * we don't know whether 'size' and size of currently allocated
298 * memory are the same (because of possible inheritance).
299 * Use { size_t index = item->index; delete item; new (index) item; }
300 * instead to make sure destructor is called and no memory leaks. */
301 assert(ptr != Tpool->data[i]);
302 }
303 return ptr;
304 }
305
306
314 static inline bool CanAllocateItem(size_t n = 1)
315 {
316 return Tpool->CanAllocate(n);
317 }
318
323 static inline bool CleaningPool()
324 {
325 return Tpool->cleaning;
326 }
327
333 static inline bool IsValidID(size_t index)
334 {
335 return Tpool->IsValidID(index);
336 }
337
344 static inline Titem *Get(size_t index)
345 {
346 return Tpool->Get(index);
347 }
348
355 static inline Titem *GetIfValid(size_t index)
356 {
357 return index < Tpool->first_unused ? Tpool->Get(index) : nullptr;
358 }
359
365 static inline size_t GetPoolSize()
366 {
367 return Tpool->first_unused;
368 }
369
374 static inline size_t GetNumItems()
375 {
376 return Tpool->items;
377 }
378
386 static inline void PostDestructor([[maybe_unused]] size_t index) { }
387
393 static Pool::IterateWrapper<Titem> Iterate(size_t from = 0) { return Pool::IterateWrapper<Titem>(from); }
394 };
395
396private:
397 static const size_t NO_FREE_ITEM = std::numeric_limits<size_t>::max();
398
403 struct AllocCache {
406 };
407
410
411 void *AllocateItem(size_t size, size_t index);
412 void ResizeFor(size_t index);
413 size_t FindFirstFree();
414
415 void *GetNew(size_t size);
416 void *GetNew(size_t size, size_t index);
417
418 void FreeItem(size_t index);
419};
420
421#endif /* POOL_TYPE_HPP */
Enum-as-bit-set wrapper.
Type (helpers) for enums.
PoolType
Various types of a pool.
Definition pool_type.hpp:16
@ NetworkClient
Network client pools.
@ NetworkAdmin
Network admin pool.
@ Normal
Normal pool containing game objects.
@ Data
NewGRF or other data, that is not reset together with normal pools.
std::vector< struct PoolBase * > PoolVector
Vector of pointers to PoolBase.
Definition pool_type.hpp:25
Base class for base of all pools.
Definition pool_type.hpp:28
const PoolType type
Type of this pool.
Definition pool_type.hpp:29
virtual void CleanPool()=0
Virtual method that deletes all items in the pool.
static PoolVector * GetPools()
Function used to access the vector of all pools.
Definition pool_type.hpp:35
PoolBase(PoolType pt)
Constructor registers this object in the pool vector.
Definition pool_type.hpp:47
static void Clean(PoolTypes)
Clean all pools of given type.
Definition pool_func.cpp:30
virtual ~PoolBase()
Destructor removes this object from the pool vector and deletes the vector itself if this was the las...
Definition pool_func.cpp:19
PoolBase(const PoolBase &other)
Dummy private copy constructor to prevent compilers from copying the structure, which fails due to Ge...
Helper struct to cache 'freed' PoolItems so we do not need to allocate them again.
AllocCache * next
The next in our 'cache'.
Base class for all PoolItems.
static size_t GetPoolSize()
Returns first unused index.
Tindex index
Index of this pool item.
static void PostDestructor(size_t index)
Dummy function called after destructor of each member.
static size_t GetNumItems()
Returns number of valid items in the pool.
static bool CleaningPool()
Returns current state of pool cleaning - yes or no.
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * Get(size_t index)
Returns Titem with given index.
Iterator to iterate all valid T of a pool.
Iterator to iterate all valid T of a pool.
Base class for all pools.
Definition pool_type.hpp:79
void CleanPool() override
Virtual method that deletes all items in the pool.
size_t first_free
No item with index lower than this is free (doesn't say anything about this one!)
Definition pool_type.hpp:97
const char *const name
Name of this pool.
Definition pool_type.hpp:95
std::vector< BitmapStorage > used_bitmap
Bitmap of used indices.
size_t first_unused
This and all higher indexes are free (doesn't say anything about first_unused-1 !)
Definition pool_type.hpp:98
std::vector< Titem * > data
Pointers to Titem.
bool cleaning
True if cleaning pool (deleting all items)
size_t items
Number of used indexes (non-nullptr)
Definition pool_type.hpp:99
Titem * Get(size_t index)
Returns Titem with given index.
static constexpr size_t MAX_SIZE
Make template parameter accessible from outside.
Definition pool_type.hpp:90
AllocCache * alloc_cache
Cache of freed pointers.
bool CanAllocate(size_t n=1)
Tests whether we can allocate 'n' items.
static constexpr size_t GetMaxIndexValue(T)
Some helper functions to get the maximum value of the provided index.
Definition pool_type.hpp:83
bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static const size_t NO_FREE_ITEM
Constant to indicate we can't allocate any more items.