OpenTTD Source 20250312-master-gcdcc6b491d
pool_func.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_FUNC_HPP
11#define POOL_FUNC_HPP
12
13#include "bitmath_func.hpp"
14#include "math_func.hpp"
15#include "pool_type.hpp"
16#include "../error_func.h"
17
18#include "../saveload/saveload_error.hpp" // SlErrorCorruptFmt
19
24#define DEFINE_POOL_METHOD(type) \
25 template <class Titem, typename Tindex, size_t Tgrowth_step, PoolType Tpool_type, bool Tcache> \
26 requires std::is_base_of_v<PoolIDBase, Tindex> \
27 type Pool<Titem, Tindex, Tgrowth_step, Tpool_type, Tcache>
28
35DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
36{
37 assert(index >= this->data.size());
38 assert(index < MAX_SIZE);
39
40 size_t old_size = this->data.size();
41 size_t new_size = std::min(MAX_SIZE, Align(index + 1, Tgrowth_step));
42
43 this->data.resize(new_size);
44 this->used_bitmap.resize(Align(new_size, BITMAP_SIZE) / BITMAP_SIZE);
45 if (old_size % BITMAP_SIZE != 0) {
46 /* Already-allocated bits above old size are now unused. */
47 this->used_bitmap[old_size / BITMAP_SIZE] &= ~((~static_cast<BitmapStorage>(0)) << (old_size % BITMAP_SIZE));
48 }
49 if (new_size % BITMAP_SIZE != 0) {
50 /* Bits above new size are considered used. */
51 this->used_bitmap[new_size / BITMAP_SIZE] |= (~static_cast<BitmapStorage>(0)) << (new_size % BITMAP_SIZE);
52 }
53}
54
59DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
60{
61 for (auto it = std::next(std::begin(this->used_bitmap), this->first_free / BITMAP_SIZE); it != std::end(this->used_bitmap); ++it) {
62 BitmapStorage available = ~(*it);
63 if (available == 0) continue;
64 return std::distance(std::begin(this->used_bitmap), it) * BITMAP_SIZE + FindFirstBit(available);
65 }
66
67 assert(this->first_unused == this->data.size());
68
69 if (this->first_unused < MAX_SIZE) {
70 this->ResizeFor(this->first_unused);
71 return this->first_unused;
72 }
73
74 assert(this->first_unused == MAX_SIZE);
75
76 return NO_FREE_ITEM;
77}
78
86DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
87{
88 assert(this->data[index] == nullptr);
89
90 this->first_unused = std::max(this->first_unused, index + 1);
91 this->items++;
92
93 Titem *item;
94 if (Tcache && this->alloc_cache != nullptr) {
95 assert(sizeof(Titem) == size);
96 item = reinterpret_cast<Titem *>(this->alloc_cache);
97 this->alloc_cache = this->alloc_cache->next;
98 } else {
99 item = reinterpret_cast<Titem *>(this->allocator.allocate(size));
100 }
101 this->data[index] = item;
102 SetBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
103 /* MSVC complains about casting to narrower type, so first cast to the base type... then to the strong type. */
104 item->index = static_cast<Tindex>(static_cast<Tindex::BaseType>(index));
105 return item;
106}
107
114DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
115{
116 size_t index = this->FindFirstFree();
117
118#ifdef WITH_ASSERT
119 assert(this->checked != 0);
120 this->checked--;
121#endif /* WITH_ASSERT */
122 if (index == NO_FREE_ITEM) {
123 FatalError("{}: no more free items", this->name);
124 }
125
126 this->first_free = index + 1;
127 return this->AllocateItem(size, index);
128}
129
137DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
138{
139 if (index >= MAX_SIZE) {
140 SlErrorCorruptFmt("{} index {} out of range ({})", this->name, index, MAX_SIZE);
141 }
142
143 if (index >= this->data.size()) this->ResizeFor(index);
144
145 if (this->data[index] != nullptr) {
146 SlErrorCorruptFmt("{} index {} already in use", this->name, index);
147 }
148
149 return this->AllocateItem(size, index);
150}
151
159DEFINE_POOL_METHOD(void)::FreeItem(size_t size, size_t index)
160{
161 assert(index < this->data.size());
162 assert(this->data[index] != nullptr);
163 if (Tcache) {
164 AllocCache *ac = reinterpret_cast<AllocCache *>(this->data[index]);
165 ac->next = this->alloc_cache;
166 this->alloc_cache = ac;
167 } else {
168 this->allocator.deallocate(reinterpret_cast<uint8_t*>(this->data[index]), size);
169 }
170 this->data[index] = nullptr;
171 this->first_free = std::min(this->first_free, index);
172 this->items--;
173 if (!this->cleaning) {
174 ClrBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
175 Titem::PostDestructor(index);
176 }
177}
178
180DEFINE_POOL_METHOD(void)::CleanPool()
181{
182 this->cleaning = true;
183 for (size_t i = 0; i < this->first_unused; i++) {
184 delete this->Get(i); // 'delete nullptr;' is very valid
185 }
186 assert(this->items == 0);
187 this->data.clear();
188 this->data.shrink_to_fit();
189 this->used_bitmap.clear();
190 this->used_bitmap.shrink_to_fit();
191 this->first_unused = this->first_free = 0;
192 this->cleaning = false;
193
194 if (Tcache) {
195 while (this->alloc_cache != nullptr) {
196 AllocCache *ac = this->alloc_cache;
197 this->alloc_cache = ac->next;
198 this->allocator.deallocate(reinterpret_cast<uint8_t*>(ac), sizeof(Titem));
199 }
200 }
201}
202
203#undef DEFINE_POOL_METHOD
204
210#define INSTANTIATE_POOL_METHODS(name) \
211 template void * name ## Pool::GetNew(size_t size); \
212 template void * name ## Pool::GetNew(size_t size, size_t index); \
213 template void name ## Pool::FreeItem(size_t size, size_t index); \
214 template void name ## Pool::CleanPool();
215
216#endif /* POOL_FUNC_HPP */
Functions related to bit mathematics.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
Integer math functions.
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
Definition math_func.hpp:37
#define DEFINE_POOL_METHOD(type)
Helper for defining the method's signature.
Definition pool_func.hpp:24
Definition of Pool, structure used to access PoolItems, and PoolItem, base structure for Vehicle,...