OpenTTD Source 20260311-master-g511d3794ce
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#ifndef POOL_TYPE_HPP
11#define POOL_TYPE_HPP
12
13#include "enum_type.hpp"
14
22using PoolTypes = EnumBitSet<PoolType, uint8_t>;
24
25typedef std::vector<struct PoolBase *> PoolVector;
26
27template <typename Tindex>
28using AllocationResult = std::pair<void *, Tindex>;
29
30
32struct PoolIDBase {};
33
46template <typename TBaseType, typename TTag, TBaseType TEnd, TBaseType TInvalid>
47struct EMPTY_BASES PoolID : PoolIDBase {
48 using BaseType = TBaseType;
49
50 constexpr PoolID() = default;
51 constexpr PoolID(const PoolID &) = default;
52 constexpr PoolID(PoolID &&) = default;
53
54 explicit constexpr PoolID(const TBaseType &value) : value(value) {}
55
56 constexpr PoolID &operator =(const PoolID &rhs) { this->value = rhs.value; return *this; }
57 constexpr PoolID &operator =(PoolID &&rhs) { this->value = std::move(rhs.value); return *this; }
58
59 /* Only allow conversion to BaseType via method. */
60 constexpr TBaseType base() const noexcept { return this->value; }
61
62 static constexpr PoolID Begin() { return PoolID{}; }
63 static constexpr PoolID End() { return PoolID{static_cast<TBaseType>(TEnd)}; }
64 static constexpr PoolID Invalid() { return PoolID{static_cast<TBaseType>(TInvalid)}; }
65
66 constexpr auto operator++() { ++this->value; return this; }
67 constexpr auto operator+(const std::integral auto &val) const { return this->value + val; }
68 constexpr auto operator-(const std::integral auto &val) const { return this->value - val; }
69 constexpr auto operator%(const std::integral auto &val) const { return this->value % val; }
70
71 constexpr bool operator==(const PoolID<TBaseType, TTag, TEnd, TInvalid> &rhs) const { return this->value == rhs.value; }
72 constexpr auto operator<=>(const PoolID<TBaseType, TTag, TEnd, TInvalid> &rhs) const { return this->value <=> rhs.value; }
73
74 constexpr bool operator==(const size_t &rhs) const { return this->value == rhs; }
75 constexpr auto operator<=>(const size_t &rhs) const { return this->value <=> rhs; }
76private:
78 TBaseType value;
79};
80
81template <typename T> requires std::is_base_of_v<PoolIDBase, T>
82constexpr auto operator+(const std::integral auto &val, const T &pool_id) { return pool_id + val; }
83template <typename Te, typename Tp> requires std::is_enum_v<Te> && std::is_base_of_v<PoolIDBase, Tp>
84constexpr auto operator+(const Te &val, const Tp &pool_id) { return pool_id + to_underlying(val); }
85
87struct PoolBase {
88 const PoolType type;
89
95 {
96 static PoolVector *pools = new PoolVector();
97 return pools;
98 }
99
100 static void Clean(PoolTypes);
101
107 {
108 PoolBase::GetPools()->push_back(this);
109 }
110
112 virtual ~PoolBase();
113
117 virtual void CleanPool() = 0;
118
119private:
125 PoolBase(const PoolBase &other);
126};
127
137template <class Titem, typename Tindex, size_t Tgrowth_step, PoolType Tpool_type = PoolType::Normal, bool Tcache = false>
138requires std::is_base_of_v<PoolIDBase, Tindex>
139struct Pool : PoolBase {
140public:
141 static constexpr size_t MAX_SIZE = Tindex::End().base();
142
143 using IndexType = Tindex;
144 using BitmapStorage = size_t;
145 static constexpr size_t BITMAP_SIZE = std::numeric_limits<BitmapStorage>::digits;
146
147 const std::string_view name{};
148
149 size_t first_free = 0;
150 size_t first_unused = 0;
151 size_t items = 0;
152#ifdef WITH_ASSERT
153 size_t checked = 0;
154#endif /* WITH_ASSERT */
155 bool cleaning = false;
156
157 std::vector<Titem *> data{};
158 std::vector<BitmapStorage> used_bitmap{};
159
160 Pool(std::string_view name) : PoolBase(Tpool_type), name(name) {}
161 void CleanPool() override;
162
169 inline Titem *Get(size_t index)
170 {
171 assert(index < this->first_unused);
172 return this->data[index];
173 }
174
180 inline bool IsValidID(size_t index)
181 {
182 return index < this->first_unused && this->Get(index) != nullptr;
183 }
184
190 inline bool CanAllocate(size_t n = 1)
191 {
192 bool ret = this->items <= MAX_SIZE - n;
193#ifdef WITH_ASSERT
194 this->checked = ret ? n : 0;
195#endif /* WITH_ASSERT */
196 return ret;
197 }
198
203 template <class T>
204 struct PoolIterator {
205 typedef T value_type;
206 typedef T *pointer;
207 typedef T &reference;
208 typedef size_t difference_type;
209 typedef std::forward_iterator_tag iterator_category;
210
211 explicit PoolIterator(size_t index) : index(index)
212 {
213 this->ValidateIndex();
214 };
215
216 bool operator==(const PoolIterator &other) const { return this->index == other.index; }
217 T * operator*() const { return T::Get(this->index); }
218 PoolIterator & operator++() { this->index++; this->ValidateIndex(); return *this; }
219
220 private:
221 size_t index;
222 void ValidateIndex()
223 {
224 while (this->index < T::GetPoolSize() && !(T::IsValidID(this->index))) this->index++;
225 if (this->index >= T::GetPoolSize()) this->index = T::Pool::MAX_SIZE;
226 }
227 };
228
229 /*
230 * Iterable ensemble of all valid T
231 * @tparam T Type of the class/struct that is going to be iterated
232 */
233 template <class T>
234 struct IterateWrapper {
235 size_t from;
236 IterateWrapper(size_t from = 0) : from(from) {}
237 PoolIterator<T> begin() { return PoolIterator<T>(this->from); }
238 PoolIterator<T> end() { return PoolIterator<T>(T::Pool::MAX_SIZE); }
239 bool empty() { return this->begin() == this->end(); }
240 };
241
246 template <class T, class F>
247 struct PoolIteratorFiltered {
248 typedef T value_type;
249 typedef T *pointer;
250 typedef T &reference;
251 typedef size_t difference_type;
252 typedef std::forward_iterator_tag iterator_category;
253
254 explicit PoolIteratorFiltered(size_t index, F filter) : index(index), filter(filter)
255 {
256 this->ValidateIndex();
257 };
258
259 bool operator==(const PoolIteratorFiltered &other) const { return this->index == other.index; }
260 T * operator*() const { return T::Get(this->index); }
261 PoolIteratorFiltered & operator++() { this->index++; this->ValidateIndex(); return *this; }
262
263 private:
264 size_t index;
265 F filter;
266 void ValidateIndex()
267 {
268 while (this->index < T::GetPoolSize() && !(T::IsValidID(this->index) && this->filter(this->index))) this->index++;
269 if (this->index >= T::GetPoolSize()) this->index = T::Pool::MAX_SIZE;
270 }
271 };
272
273 /*
274 * Iterable ensemble of all valid T
275 * @tparam T Type of the class/struct that is going to be iterated
276 */
277 template <class T, class F>
278 struct IterateWrapperFiltered {
279 size_t from;
280 F filter;
281 IterateWrapperFiltered(size_t from, F filter) : from(from), filter(filter) {}
282 PoolIteratorFiltered<T, F> begin() { return PoolIteratorFiltered<T, F>(this->from, this->filter); }
283 PoolIteratorFiltered<T, F> end() { return PoolIteratorFiltered<T, F>(T::Pool::MAX_SIZE, this->filter); }
284 bool empty() { return this->begin() == this->end(); }
285 };
286
291 template <struct Pool<Titem, Tindex, Tgrowth_step, Tpool_type, Tcache> *Tpool>
292 struct PoolItem {
293 const Tindex index;
294
299 PoolItem(Tindex index) : index(index) {}
300
302 typedef struct Pool<Titem, Tindex, Tgrowth_step, Tpool_type, Tcache> Pool;
303
305 inline void *operator new(size_t) = delete;
306
313 inline void operator delete(void *p, size_t size)
314 {
315 if (p == nullptr) return;
316 Titem *pn = static_cast<Titem *>(p);
317 assert(pn == Tpool->Get(Pool::GetRawIndex(pn->index)));
318 Tpool->FreeItem(size, Pool::GetRawIndex(pn->index));
319 }
320
322 inline void *operator new(size_t size, Tindex index) = delete;
323
325 inline void *operator new(size_t, void *ptr) = delete;
326
327
333 template <typename T = Titem, typename... Targs>
334 requires std::is_base_of_v<Titem, T>
335 static inline T *Create(Targs &&... args)
336 {
337 auto [data, index] = Tpool->GetNew(sizeof(T));
338 return ::new (data) T(index, std::forward<Targs&&>(args)...);
339 }
340
347 template <typename T = Titem, typename... Targs>
348 requires std::is_base_of_v<Titem, T>
349 static inline T *CreateAtIndex(Tindex index, Targs &&... args)
350 {
351 auto [data, _] = Tpool->GetNew(sizeof(T), index.base());
352 return ::new (data) T(index, std::forward<Targs&&>(args)...);
353 }
354
356
362 static inline bool CanAllocateItem(size_t n = 1)
363 {
364 return Tpool->CanAllocate(n);
365 }
366
371 static inline bool CleaningPool()
372 {
373 return Tpool->cleaning;
374 }
375
381 static inline bool IsValidID(auto index)
382 {
383 return Tpool->IsValidID(GetRawIndex(index));
384 }
385
392 static inline Titem *Get(auto index)
393 {
394 return Tpool->Get(GetRawIndex(index));
395 }
396
403 static inline Titem *GetIfValid(auto index)
404 {
405 return GetRawIndex(index) < Tpool->first_unused ? Tpool->Get(GetRawIndex(index)) : nullptr;
406 }
407
413 static inline size_t GetPoolSize()
414 {
415 return Tpool->first_unused;
416 }
417
422 static inline size_t GetNumItems()
423 {
424 return Tpool->items;
425 }
426
434 static inline void PostDestructor([[maybe_unused]] size_t index) { }
435
441 static Pool::IterateWrapper<Titem> Iterate(size_t from = 0) { return Pool::IterateWrapper<Titem>(from); }
442 };
443
444private:
445 static const size_t NO_FREE_ITEM = std::numeric_limits<size_t>::max();
446
451 struct AllocCache {
454 };
455
457 AllocCache *alloc_cache = nullptr;
458 std::allocator<uint8_t> allocator{};
459
460 AllocationResult<Tindex> AllocateItem(size_t size, size_t index);
461 void ResizeFor(size_t index);
463
464 AllocationResult<Tindex> GetNew(size_t size);
465 AllocationResult<Tindex> GetNew(size_t size, size_t index);
466
467 void FreeItem(size_t size, size_t index);
468
469 static constexpr size_t GetRawIndex(size_t index) { return index; }
470 template <typename T> requires std::is_base_of_v<PoolIDBase, T>
471 static constexpr size_t GetRawIndex(const T &index) { return index.base(); }
472};
473
474#endif /* POOL_TYPE_HPP */
Enum-as-bit-set wrapper.
@ End
End marker.
Definition clear_map.h:28
@ Begin
The lowest valid value.
@ Invalid
Invalid base price.
#define T
Climate temperate.
Definition engines.h:91
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:21
constexpr enum_type & operator++(enum_type &e)
Prefix increment.
Definition enum_type.hpp:41
constexpr enum_type operator-(enum_type e, int offset)
Subtract integer.
constexpr enum_type operator+(enum_type e, int offset)
Add integer.
PoolType
Various types of a pool.
Definition pool_type.hpp:16
@ NetworkClient
Network client pools.
Definition pool_type.hpp:18
@ NetworkAdmin
Network admin pool.
Definition pool_type.hpp:19
@ Normal
Normal pool containing game objects.
Definition pool_type.hpp:17
@ Data
NewGRF or other data, that is not reset together with normal pools.
Definition pool_type.hpp:20
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:87
const PoolType type
Type of this pool.
Definition pool_type.hpp:88
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:94
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()
Ensure the destructor of the sub classes are called as well.
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:32
TBaseType value
The bare storage.
Definition pool_type.hpp:78
Helper struct to cache 'freed' PoolItems so we do not need to allocate them again.
AllocCache * next
The next in our 'cache'.
PoolItem(Tindex index)
Construct the item.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static T * CreateAtIndex(Tindex index, Targs &&... args)
Creates a new T-object in the associated pool.
static size_t GetPoolSize()
Returns first unused index.
struct Pool< Titem, Tindex, Tgrowth_step, Tpool_type, Tcache > Pool
Type of the pool this item is going to be part of.
static Titem * Get(auto index)
Returns Titem with given index.
static size_t GetNumItems()
Returns number of valid items in the pool.
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 T * Create(Targs &&... args)
Creates a new T-object in the associated pool.
const Tindex index
Index of this pool item.
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.
bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
size_t FindFirstFree()
Searches for first free index.
Definition pool_func.hpp:59
void CleanPool() override
Destroys all items in the pool and resets all member variables.
std::vector< EngineRenew * > data
AllocationResult< Tindex > AllocateItem(size_t size, size_t index)
Makes given index valid.
Definition pool_func.hpp:87
std::vector< BitmapStorage > used_bitmap
void ResizeFor(size_t index)
Resizes the pool so 'index' can be addressed.
Definition pool_func.hpp:35
Titem * Get(size_t index)
Returns Titem with given index.
AllocationResult< Tindex > GetNew(size_t size)
Allocates new item.
void FreeItem(size_t size, size_t index)
Deallocates memory used by this index and marks item as free.
AllocationResult< Tindex > GetNew(size_t size, size_t index)
Allocates new item with given index.
bool CanAllocate(size_t n=1)
Tests whether we can allocate 'n' items.