OpenTTD Source 20260218-master-g2123fca5ea
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:
77 /* Do not explicitly initialize. */
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
111 virtual ~PoolBase();
112
116 virtual void CleanPool() = 0;
117
118private:
124 PoolBase(const PoolBase &other);
125};
126
136template <class Titem, typename Tindex, size_t Tgrowth_step, PoolType Tpool_type = PoolType::Normal, bool Tcache = false>
137requires std::is_base_of_v<PoolIDBase, Tindex>
138struct Pool : PoolBase {
139public:
140 static constexpr size_t MAX_SIZE = Tindex::End().base();
141
142 using IndexType = Tindex;
143 using BitmapStorage = size_t;
144 static constexpr size_t BITMAP_SIZE = std::numeric_limits<BitmapStorage>::digits;
145
146 const std::string_view name{};
147
148 size_t first_free = 0;
149 size_t first_unused = 0;
150 size_t items = 0;
151#ifdef WITH_ASSERT
152 size_t checked = 0;
153#endif /* WITH_ASSERT */
154 bool cleaning = false;
155
156 std::vector<Titem *> data{};
157 std::vector<BitmapStorage> used_bitmap{};
158
159 Pool(std::string_view name) : PoolBase(Tpool_type), name(name) {}
160 void CleanPool() override;
161
168 inline Titem *Get(size_t index)
169 {
170 assert(index < this->first_unused);
171 return this->data[index];
172 }
173
179 inline bool IsValidID(size_t index)
180 {
181 return index < this->first_unused && this->Get(index) != nullptr;
182 }
183
189 inline bool CanAllocate(size_t n = 1)
190 {
191 bool ret = this->items <= MAX_SIZE - n;
192#ifdef WITH_ASSERT
193 this->checked = ret ? n : 0;
194#endif /* WITH_ASSERT */
195 return ret;
196 }
197
202 template <class T>
203 struct PoolIterator {
204 typedef T value_type;
205 typedef T *pointer;
206 typedef T &reference;
207 typedef size_t difference_type;
208 typedef std::forward_iterator_tag iterator_category;
209
210 explicit PoolIterator(size_t index) : index(index)
211 {
212 this->ValidateIndex();
213 };
214
215 bool operator==(const PoolIterator &other) const { return this->index == other.index; }
216 T * operator*() const { return T::Get(this->index); }
217 PoolIterator & operator++() { this->index++; this->ValidateIndex(); return *this; }
218
219 private:
220 size_t index;
221 void ValidateIndex()
222 {
223 while (this->index < T::GetPoolSize() && !(T::IsValidID(this->index))) this->index++;
224 if (this->index >= T::GetPoolSize()) this->index = T::Pool::MAX_SIZE;
225 }
226 };
227
228 /*
229 * Iterable ensemble of all valid T
230 * @tparam T Type of the class/struct that is going to be iterated
231 */
232 template <class T>
233 struct IterateWrapper {
234 size_t from;
235 IterateWrapper(size_t from = 0) : from(from) {}
236 PoolIterator<T> begin() { return PoolIterator<T>(this->from); }
237 PoolIterator<T> end() { return PoolIterator<T>(T::Pool::MAX_SIZE); }
238 bool empty() { return this->begin() == this->end(); }
239 };
240
245 template <class T, class F>
246 struct PoolIteratorFiltered {
247 typedef T value_type;
248 typedef T *pointer;
249 typedef T &reference;
250 typedef size_t difference_type;
251 typedef std::forward_iterator_tag iterator_category;
252
253 explicit PoolIteratorFiltered(size_t index, F filter) : index(index), filter(filter)
254 {
255 this->ValidateIndex();
256 };
257
258 bool operator==(const PoolIteratorFiltered &other) const { return this->index == other.index; }
259 T * operator*() const { return T::Get(this->index); }
260 PoolIteratorFiltered & operator++() { this->index++; this->ValidateIndex(); return *this; }
261
262 private:
263 size_t index;
264 F filter;
265 void ValidateIndex()
266 {
267 while (this->index < T::GetPoolSize() && !(T::IsValidID(this->index) && this->filter(this->index))) this->index++;
268 if (this->index >= T::GetPoolSize()) this->index = T::Pool::MAX_SIZE;
269 }
270 };
271
272 /*
273 * Iterable ensemble of all valid T
274 * @tparam T Type of the class/struct that is going to be iterated
275 */
276 template <class T, class F>
277 struct IterateWrapperFiltered {
278 size_t from;
279 F filter;
280 IterateWrapperFiltered(size_t from, F filter) : from(from), filter(filter) {}
281 PoolIteratorFiltered<T, F> begin() { return PoolIteratorFiltered<T, F>(this->from, this->filter); }
282 PoolIteratorFiltered<T, F> end() { return PoolIteratorFiltered<T, F>(T::Pool::MAX_SIZE, this->filter); }
283 bool empty() { return this->begin() == this->end(); }
284 };
285
290 template <struct Pool<Titem, Tindex, Tgrowth_step, Tpool_type, Tcache> *Tpool>
291 struct PoolItem {
292 const Tindex index;
293
298 PoolItem(Tindex index) : index(index) {}
299
301 typedef struct Pool<Titem, Tindex, Tgrowth_step, Tpool_type, Tcache> Pool;
302
304 inline void *operator new(size_t) = delete;
305
312 inline void operator delete(void *p, size_t size)
313 {
314 if (p == nullptr) return;
315 Titem *pn = static_cast<Titem *>(p);
316 assert(pn == Tpool->Get(Pool::GetRawIndex(pn->index)));
317 Tpool->FreeItem(size, Pool::GetRawIndex(pn->index));
318 }
319
321 inline void *operator new(size_t size, Tindex index) = delete;
322
324 inline void *operator new(size_t, void *ptr) = delete;
325
326
332 template <typename T = Titem, typename... Targs>
333 requires std::is_base_of_v<Titem, T>
334 static inline T *Create(Targs &&... args)
335 {
336 auto [data, index] = Tpool->GetNew(sizeof(T));
337 return ::new (data) T(index, std::forward<Targs&&>(args)...);
338 }
339
346 template <typename T = Titem, typename... Targs>
347 requires std::is_base_of_v<Titem, T>
348 static inline T *CreateAtIndex(Tindex index, Targs &&... args)
349 {
350 auto [data, _] = Tpool->GetNew(sizeof(T), index.base());
351 return ::new (data) T(index, std::forward<Targs&&>(args)...);
352 }
353
355
361 static inline bool CanAllocateItem(size_t n = 1)
362 {
363 return Tpool->CanAllocate(n);
364 }
365
370 static inline bool CleaningPool()
371 {
372 return Tpool->cleaning;
373 }
374
380 static inline bool IsValidID(auto index)
381 {
382 return Tpool->IsValidID(GetRawIndex(index));
383 }
384
391 static inline Titem *Get(auto index)
392 {
393 return Tpool->Get(GetRawIndex(index));
394 }
395
402 static inline Titem *GetIfValid(auto index)
403 {
404 return GetRawIndex(index) < Tpool->first_unused ? Tpool->Get(GetRawIndex(index)) : nullptr;
405 }
406
412 static inline size_t GetPoolSize()
413 {
414 return Tpool->first_unused;
415 }
416
421 static inline size_t GetNumItems()
422 {
423 return Tpool->items;
424 }
425
433 static inline void PostDestructor([[maybe_unused]] size_t index) { }
434
440 static Pool::IterateWrapper<Titem> Iterate(size_t from = 0) { return Pool::IterateWrapper<Titem>(from); }
441 };
442
443private:
444 static const size_t NO_FREE_ITEM = std::numeric_limits<size_t>::max();
445
450 struct AllocCache {
453 };
454
456 AllocCache *alloc_cache = nullptr;
457 std::allocator<uint8_t> allocator{};
458
459 AllocationResult<Tindex> AllocateItem(size_t size, size_t index);
460 void ResizeFor(size_t index);
462
463 AllocationResult<Tindex> GetNew(size_t size);
464 AllocationResult<Tindex> GetNew(size_t size, size_t index);
465
466 void FreeItem(size_t size, size_t index);
467
468 static constexpr size_t GetRawIndex(size_t index) { return index; }
469 template <typename T> requires std::is_base_of_v<PoolIDBase, T>
470 static constexpr size_t GetRawIndex(const T &index) { return index.base(); }
471};
472
473#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.
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()
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:32
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.