OpenTTD Source 20260108-master-g8ba1860eaa
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
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
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:
123 PoolBase(const PoolBase &other);
124};
125
135template <class Titem, typename Tindex, size_t Tgrowth_step, PoolType Tpool_type = PoolType::Normal, bool Tcache = false>
136requires std::is_base_of_v<PoolIDBase, Tindex>
137struct Pool : PoolBase {
138public:
139 static constexpr size_t MAX_SIZE = Tindex::End().base();
140
141 using IndexType = Tindex;
142 using BitmapStorage = size_t;
143 static constexpr size_t BITMAP_SIZE = std::numeric_limits<BitmapStorage>::digits;
144
145 const std::string_view name{};
146
147 size_t first_free = 0;
148 size_t first_unused = 0;
149 size_t items = 0;
150#ifdef WITH_ASSERT
151 size_t checked = 0;
152#endif /* WITH_ASSERT */
153 bool cleaning = false;
154
155 std::vector<Titem *> data{};
156 std::vector<BitmapStorage> used_bitmap{};
157
158 Pool(std::string_view name) : PoolBase(Tpool_type), name(name) {}
159 void CleanPool() override;
160
167 inline Titem *Get(size_t index)
168 {
169 assert(index < this->first_unused);
170 return this->data[index];
171 }
172
178 inline bool IsValidID(size_t index)
179 {
180 return index < this->first_unused && this->Get(index) != nullptr;
181 }
182
188 inline bool CanAllocate(size_t n = 1)
189 {
190 bool ret = this->items <= MAX_SIZE - n;
191#ifdef WITH_ASSERT
192 this->checked = ret ? n : 0;
193#endif /* WITH_ASSERT */
194 return ret;
195 }
196
201 template <class T>
203 typedef T value_type;
204 typedef T *pointer;
205 typedef T &reference;
206 typedef size_t difference_type;
207 typedef std::forward_iterator_tag iterator_category;
208
209 explicit PoolIterator(size_t index) : index(index)
210 {
211 this->ValidateIndex();
212 };
213
214 bool operator==(const PoolIterator &other) const { return this->index == other.index; }
215 T * operator*() const { return T::Get(this->index); }
216 PoolIterator & operator++() { this->index++; this->ValidateIndex(); return *this; }
217
218 private:
219 size_t index;
220 void ValidateIndex()
221 {
222 while (this->index < T::GetPoolSize() && !(T::IsValidID(this->index))) this->index++;
223 if (this->index >= T::GetPoolSize()) this->index = T::Pool::MAX_SIZE;
224 }
225 };
226
227 /*
228 * Iterable ensemble of all valid T
229 * @tparam T Type of the class/struct that is going to be iterated
230 */
231 template <class T>
233 size_t from;
234 IterateWrapper(size_t from = 0) : from(from) {}
235 PoolIterator<T> begin() { return PoolIterator<T>(this->from); }
236 PoolIterator<T> end() { return PoolIterator<T>(T::Pool::MAX_SIZE); }
237 bool empty() { return this->begin() == this->end(); }
238 };
239
244 template <class T, class F>
246 typedef T value_type;
247 typedef T *pointer;
248 typedef T &reference;
249 typedef size_t difference_type;
250 typedef std::forward_iterator_tag iterator_category;
251
252 explicit PoolIteratorFiltered(size_t index, F filter) : index(index), filter(filter)
253 {
254 this->ValidateIndex();
255 };
256
257 bool operator==(const PoolIteratorFiltered &other) const { return this->index == other.index; }
258 T * operator*() const { return T::Get(this->index); }
259 PoolIteratorFiltered & operator++() { this->index++; this->ValidateIndex(); return *this; }
260
261 private:
262 size_t index;
263 F filter;
264 void ValidateIndex()
265 {
266 while (this->index < T::GetPoolSize() && !(T::IsValidID(this->index) && this->filter(this->index))) this->index++;
267 if (this->index >= T::GetPoolSize()) this->index = T::Pool::MAX_SIZE;
268 }
269 };
270
271 /*
272 * Iterable ensemble of all valid T
273 * @tparam T Type of the class/struct that is going to be iterated
274 */
275 template <class T, class F>
277 size_t from;
278 F filter;
279 IterateWrapperFiltered(size_t from, F filter) : from(from), filter(filter) {}
280 PoolIteratorFiltered<T, F> begin() { return PoolIteratorFiltered<T, F>(this->from, this->filter); }
281 PoolIteratorFiltered<T, F> end() { return PoolIteratorFiltered<T, F>(T::Pool::MAX_SIZE, this->filter); }
282 bool empty() { return this->begin() == this->end(); }
283 };
284
289 template <struct Pool<Titem, Tindex, Tgrowth_step, Tpool_type, Tcache> *Tpool>
290 struct PoolItem {
291 const Tindex index;
292
297 PoolItem(Tindex index) : index(index) {}
298
300 typedef struct Pool<Titem, Tindex, Tgrowth_step, Tpool_type, Tcache> Pool;
301
303 inline void *operator new(size_t) = delete;
304
310 inline void operator delete(void *p, size_t size)
311 {
312 if (p == nullptr) return;
313 Titem *pn = static_cast<Titem *>(p);
314 assert(pn == Tpool->Get(Pool::GetRawIndex(pn->index)));
315 Tpool->FreeItem(size, Pool::GetRawIndex(pn->index));
316 }
317
319 inline void *operator new(size_t size, Tindex index) = delete;
320
322 inline void *operator new(size_t, void *ptr) = delete;
323
324
330 template <typename T = Titem, typename... Targs>
331 requires std::is_base_of_v<Titem, T>
332 static inline T *Create(Targs &&... args)
333 {
334 auto [data, index] = Tpool->GetNew(sizeof(T));
335 return ::new (data) T(index, std::forward<Targs&&>(args)...);
336 }
337
344 template <typename T = Titem, typename... Targs>
345 requires std::is_base_of_v<Titem, T>
346 static inline T *CreateAtIndex(Tindex index, Targs &&... args)
347 {
348 auto [data, _] = Tpool->GetNew(sizeof(T), index.base());
349 return ::new (data) T(index, std::forward<Targs&&>(args)...);
350 }
351
359 static inline bool CanAllocateItem(size_t n = 1)
360 {
361 return Tpool->CanAllocate(n);
362 }
363
368 static inline bool CleaningPool()
369 {
370 return Tpool->cleaning;
371 }
372
378 static inline bool IsValidID(auto index)
379 {
380 return Tpool->IsValidID(GetRawIndex(index));
381 }
382
389 static inline Titem *Get(auto index)
390 {
391 return Tpool->Get(GetRawIndex(index));
392 }
393
400 static inline Titem *GetIfValid(auto index)
401 {
402 return GetRawIndex(index) < Tpool->first_unused ? Tpool->Get(GetRawIndex(index)) : nullptr;
403 }
404
410 static inline size_t GetPoolSize()
411 {
412 return Tpool->first_unused;
413 }
414
419 static inline size_t GetNumItems()
420 {
421 return Tpool->items;
422 }
423
431 static inline void PostDestructor([[maybe_unused]] size_t index) { }
432
438 static Pool::IterateWrapper<Titem> Iterate(size_t from = 0) { return Pool::IterateWrapper<Titem>(from); }
439 };
440
441private:
442 static const size_t NO_FREE_ITEM = std::numeric_limits<size_t>::max();
443
448 struct AllocCache {
451 };
452
455 std::allocator<uint8_t> allocator{};
456
457 AllocationResult<Tindex> AllocateItem(size_t size, size_t index);
458 void ResizeFor(size_t index);
459 size_t FindFirstFree();
460
461 AllocationResult<Tindex> GetNew(size_t size);
462 AllocationResult<Tindex> GetNew(size_t size, size_t index);
463
464 void FreeItem(size_t size, size_t index);
465
466 static constexpr size_t GetRawIndex(size_t index) { return index; }
467 template <typename T> requires std::is_base_of_v<PoolIDBase, T>
468 static constexpr size_t GetRawIndex(const T &index) { return index.base(); }
469};
470
471#endif /* POOL_TYPE_HPP */
Enum-as-bit-set wrapper.
@ End
End marker.
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
constexpr enum_type operator-(enum_type e, int offset)
Sub integer.
Definition enum_type.hpp:93
constexpr enum_type operator+(enum_type e, int offset)
Add integer.
Definition enum_type.hpp:79
@ Invalid
Pseudosprite or other unusable sprite, used only internally.
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: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
Templated helper to make a PoolID a single POD value.
Definition pool_type.hpp:47
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.
PoolItem(Tindex index)
Construct the item.
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 T * Create(Targs &&... args)
Creates a new T-object in the associated pool.
static T * CreateAtIndex(Tindex index, Targs &&... args)
Creates a new T-object in the associated pool.
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.
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.
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.
const std::string_view name
Name of this 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.
@ Begin
Begin for iteration.