OpenTTD Source 20250312-master-gcdcc6b491d
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 PoolIDBase {};
29
42template <typename TBaseType, typename TTag, TBaseType TEnd, TBaseType TInvalid>
43struct EMPTY_BASES PoolID : PoolIDBase {
44 using BaseType = TBaseType;
45
46 constexpr PoolID() = default;
47 constexpr PoolID(const PoolID &) = default;
48 constexpr PoolID(PoolID &&) = default;
49
50 explicit constexpr PoolID(const TBaseType &value) : value(value) {}
51
52 constexpr PoolID &operator =(const PoolID &rhs) { this->value = rhs.value; return *this; }
53 constexpr PoolID &operator =(PoolID &&rhs) { this->value = std::move(rhs.value); return *this; }
54
55 /* Only allow conversion to BaseType via method. */
56 constexpr TBaseType base() const noexcept { return this->value; }
57
58 static constexpr PoolID Begin() { return PoolID{}; }
59 static constexpr PoolID End() { return PoolID{static_cast<TBaseType>(TEnd)}; }
60 static constexpr PoolID Invalid() { return PoolID{static_cast<TBaseType>(TInvalid)}; }
61
62 constexpr auto operator++() { ++this->value; return this; }
63 constexpr auto operator+(const std::integral auto &val) const { return this->value + val; }
64 constexpr auto operator-(const std::integral auto &val) const { return this->value - val; }
65 constexpr auto operator%(const std::integral auto &val) const { return this->value % val; }
66
67 constexpr bool operator==(const PoolID<TBaseType, TTag, TEnd, TInvalid> &rhs) const { return this->value == rhs.value; }
68 constexpr auto operator<=>(const PoolID<TBaseType, TTag, TEnd, TInvalid> &rhs) const { return this->value <=> rhs.value; }
69
70 constexpr bool operator==(const size_t &rhs) const { return this->value == rhs; }
71 constexpr auto operator<=>(const size_t &rhs) const { return this->value <=> rhs; }
72private:
73 /* Do not explicitly initialize. */
74 TBaseType value;
75};
76
77template <typename T> requires std::is_base_of_v<PoolIDBase, T>
78constexpr auto operator+(const std::integral auto &val, const T &pool_id) { return pool_id + val; }
79template <typename Te, typename Tp> requires std::is_enum_v<Te> && std::is_base_of_v<PoolIDBase, Tp>
80constexpr auto operator+(const Te &val, const Tp &pool_id) { return pool_id + to_underlying(val); }
81
83struct PoolBase {
84 const PoolType type;
85
91 {
92 static PoolVector *pools = new PoolVector();
93 return pools;
94 }
95
96 static void Clean(PoolTypes);
97
103 {
104 PoolBase::GetPools()->push_back(this);
105 }
106
107 virtual ~PoolBase();
108
112 virtual void CleanPool() = 0;
113
114private:
119 PoolBase(const PoolBase &other);
120};
121
131template <class Titem, typename Tindex, size_t Tgrowth_step, PoolType Tpool_type = PoolType::Normal, bool Tcache = false>
132requires std::is_base_of_v<PoolIDBase, Tindex>
133struct Pool : PoolBase {
134public:
135 static constexpr size_t MAX_SIZE = Tindex::End().base();
136
137 using BitmapStorage = size_t;
138 static constexpr size_t BITMAP_SIZE = std::numeric_limits<BitmapStorage>::digits;
139
140 const char * const name = nullptr;
141
142 size_t first_free = 0;
143 size_t first_unused = 0;
144 size_t items = 0;
145#ifdef WITH_ASSERT
146 size_t checked = 0;
147#endif /* WITH_ASSERT */
148 bool cleaning = false;
149
150 std::vector<Titem *> data{};
151 std::vector<BitmapStorage> used_bitmap{};
152
153 Pool(const char *name) : PoolBase(Tpool_type), name(name) {}
154 void CleanPool() override;
155
162 inline Titem *Get(size_t index)
163 {
164 assert(index < this->first_unused);
165 return this->data[index];
166 }
167
173 inline bool IsValidID(size_t index)
174 {
175 return index < this->first_unused && this->Get(index) != nullptr;
176 }
177
183 inline bool CanAllocate(size_t n = 1)
184 {
185 bool ret = this->items <= MAX_SIZE - n;
186#ifdef WITH_ASSERT
187 this->checked = ret ? n : 0;
188#endif /* WITH_ASSERT */
189 return ret;
190 }
191
196 template <class T>
198 typedef T value_type;
199 typedef T *pointer;
200 typedef T &reference;
201 typedef size_t difference_type;
202 typedef std::forward_iterator_tag iterator_category;
203
204 explicit PoolIterator(size_t index) : index(index)
205 {
206 this->ValidateIndex();
207 };
208
209 bool operator==(const PoolIterator &other) const { return this->index == other.index; }
210 T * operator*() const { return T::Get(this->index); }
211 PoolIterator & operator++() { this->index++; this->ValidateIndex(); return *this; }
212
213 private:
214 size_t index;
215 void ValidateIndex()
216 {
217 while (this->index < T::GetPoolSize() && !(T::IsValidID(this->index))) this->index++;
218 if (this->index >= T::GetPoolSize()) this->index = T::Pool::MAX_SIZE;
219 }
220 };
221
222 /*
223 * Iterable ensemble of all valid T
224 * @tparam T Type of the class/struct that is going to be iterated
225 */
226 template <class T>
228 size_t from;
229 IterateWrapper(size_t from = 0) : from(from) {}
230 PoolIterator<T> begin() { return PoolIterator<T>(this->from); }
231 PoolIterator<T> end() { return PoolIterator<T>(T::Pool::MAX_SIZE); }
232 bool empty() { return this->begin() == this->end(); }
233 };
234
239 template <class T, class F>
241 typedef T value_type;
242 typedef T *pointer;
243 typedef T &reference;
244 typedef size_t difference_type;
245 typedef std::forward_iterator_tag iterator_category;
246
247 explicit PoolIteratorFiltered(size_t index, F filter) : index(index), filter(filter)
248 {
249 this->ValidateIndex();
250 };
251
252 bool operator==(const PoolIteratorFiltered &other) const { return this->index == other.index; }
253 T * operator*() const { return T::Get(this->index); }
254 PoolIteratorFiltered & operator++() { this->index++; this->ValidateIndex(); return *this; }
255
256 private:
257 size_t index;
258 F filter;
259 void ValidateIndex()
260 {
261 while (this->index < T::GetPoolSize() && !(T::IsValidID(this->index) && this->filter(this->index))) this->index++;
262 if (this->index >= T::GetPoolSize()) this->index = T::Pool::MAX_SIZE;
263 }
264 };
265
266 /*
267 * Iterable ensemble of all valid T
268 * @tparam T Type of the class/struct that is going to be iterated
269 */
270 template <class T, class F>
272 size_t from;
273 F filter;
274 IterateWrapperFiltered(size_t from, F filter) : from(from), filter(filter) {}
275 PoolIteratorFiltered<T, F> begin() { return PoolIteratorFiltered<T, F>(this->from, this->filter); }
276 PoolIteratorFiltered<T, F> end() { return PoolIteratorFiltered<T, F>(T::Pool::MAX_SIZE, this->filter); }
277 bool empty() { return this->begin() == this->end(); }
278 };
279
284 template <struct Pool<Titem, Tindex, Tgrowth_step, Tpool_type, Tcache> *Tpool>
285 struct PoolItem {
286 Tindex index;
287
289 typedef struct Pool<Titem, Tindex, Tgrowth_step, Tpool_type, Tcache> Pool;
290
297 inline void *operator new(size_t size)
298 {
299 return Tpool->GetNew(size);
300 }
301
307 inline void operator delete(void *p, size_t size)
308 {
309 if (p == nullptr) return;
310 Titem *pn = static_cast<Titem *>(p);
311 assert(pn == Tpool->Get(Pool::GetRawIndex(pn->index)));
312 Tpool->FreeItem(size, Pool::GetRawIndex(pn->index));
313 }
314
323 inline void *operator new(size_t size, Tindex index)
324 {
325 return Tpool->GetNew(size, index.base());
326 }
327
335 inline void *operator new(size_t, void *ptr)
336 {
337 for (size_t i = 0; i < Tpool->first_unused; i++) {
338 /* Don't allow creating new objects over existing.
339 * Even if we called the destructor and reused this memory,
340 * we don't know whether 'size' and size of currently allocated
341 * memory are the same (because of possible inheritance).
342 * Use { size_t index = item->index; delete item; new (index) item; }
343 * instead to make sure destructor is called and no memory leaks. */
344 assert(ptr != Tpool->data[i]);
345 }
346 return ptr;
347 }
348
349
357 static inline bool CanAllocateItem(size_t n = 1)
358 {
359 return Tpool->CanAllocate(n);
360 }
361
366 static inline bool CleaningPool()
367 {
368 return Tpool->cleaning;
369 }
370
376 static inline bool IsValidID(auto index)
377 {
378 return Tpool->IsValidID(GetRawIndex(index));
379 }
380
387 static inline Titem *Get(auto index)
388 {
389 return Tpool->Get(GetRawIndex(index));
390 }
391
398 static inline Titem *GetIfValid(auto index)
399 {
400 return GetRawIndex(index) < Tpool->first_unused ? Tpool->Get(GetRawIndex(index)) : nullptr;
401 }
402
408 static inline size_t GetPoolSize()
409 {
410 return Tpool->first_unused;
411 }
412
417 static inline size_t GetNumItems()
418 {
419 return Tpool->items;
420 }
421
429 static inline void PostDestructor([[maybe_unused]] size_t index) { }
430
436 static Pool::IterateWrapper<Titem> Iterate(size_t from = 0) { return Pool::IterateWrapper<Titem>(from); }
437 };
438
439private:
440 static const size_t NO_FREE_ITEM = std::numeric_limits<size_t>::max();
441
446 struct AllocCache {
449 };
450
453 std::allocator<uint8_t> allocator{};
454
455 void *AllocateItem(size_t size, size_t index);
456 void ResizeFor(size_t index);
457 size_t FindFirstFree();
458
459 void *GetNew(size_t size);
460 void *GetNew(size_t size, size_t index);
461
462 void FreeItem(size_t size, size_t index);
463
464 static constexpr size_t GetRawIndex(size_t index) { return index; }
465 template <typename T> requires std::is_base_of_v<PoolIDBase, T>
466 static constexpr size_t GetRawIndex(const T &index) { return index.base(); }
467};
468
469#endif /* POOL_TYPE_HPP */
Enum-as-bit-set wrapper.
Type (helpers) for enums.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
constexpr enum_type & operator++(enum_type &e)
Prefix increment.
Definition enum_type.hpp:30
@ Invalid
GRF is unusable with this version of OpenTTD.
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:83
const PoolType type
Type of this pool.
Definition pool_type.hpp:84
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:90
PoolBase(PoolType pt)
Constructor registers this object in the pool vector.
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...
Non-templated base for PoolID for use with type trait queries.
Definition pool_type.hpp:28
Templated helper to make a PoolID a single POD value.
Definition pool_type.hpp:43
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 Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static size_t GetPoolSize()
Returns first unused index.
static Titem * Get(auto index)
Returns Titem with given index.
static size_t GetNumItems()
Returns number of valid items in the pool.
Tindex index
Index of this pool item.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static bool CleaningPool()
Returns current state of pool cleaning - yes or no.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
static void PostDestructor(size_t index)
Dummy function called after destructor of each member.
Iterator to iterate all valid T of a pool.
Iterator to iterate all valid T of a pool.
Base class for all pools.
const char *const name
Name of this pool.
size_t first_free
No item with index lower than this is free (doesn't say anything about this one!)
static const size_t NO_FREE_ITEM
Constant to indicate we can't allocate any more items.
bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
AllocCache * alloc_cache
Cache of freed pointers.
size_t first_unused
This and all higher indexes are free (doesn't say anything about first_unused-1 !)
void CleanPool() override
Virtual method that deletes all items in the pool.
std::vector< Titem * > data
Pointers to Titem.
std::vector< BitmapStorage > used_bitmap
Bitmap of used indices.
bool cleaning
True if cleaning pool (deleting all items)
size_t items
Number of used indexes (non-nullptr)
static constexpr size_t MAX_SIZE
Make template parameter accessible from outside.
Titem * Get(size_t index)
Returns Titem with given index.
bool CanAllocate(size_t n=1)
Tests whether we can allocate 'n' items.