OpenTTD Source 20250205-master-gfd85ab1e2c
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 "alloc_func.hpp"
14#include "bitmath_func.hpp"
15#include "mem_func.hpp"
16#include "pool_type.hpp"
17#include "../error_func.h"
18
19#include "../saveload/saveload_error.hpp" // SlErrorCorruptFmt
20
25#define DEFINE_POOL_METHOD(type) \
26 template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type, bool Tcache, bool Tzero> \
27 type Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero>
28
33DEFINE_POOL_METHOD(inline)::Pool(const char *name) :
34 PoolBase(Tpool_type),
35 name(name),
36 first_free(0),
37 first_unused(0),
38 items(0),
39#ifdef WITH_ASSERT
40 checked(0),
41#endif /* WITH_ASSERT */
42 cleaning(false),
43 alloc_cache(nullptr)
44{ }
45
52DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
53{
54 assert(index >= this->data.size());
55 assert(index < Tmax_size);
56
57 size_t old_size = this->data.size();
58 size_t new_size = std::min(Tmax_size, Align(index + 1, Tgrowth_step));
59
60 this->data.resize(new_size);
61 this->used_bitmap.resize(Align(new_size, BITMAP_SIZE) / BITMAP_SIZE);
62 if (old_size % BITMAP_SIZE != 0) {
63 /* Already-allocated bits above old size are now unused. */
64 this->used_bitmap[old_size / BITMAP_SIZE] &= ~((~static_cast<BitmapStorage>(0)) << (old_size % BITMAP_SIZE));
65 }
66 if (new_size % BITMAP_SIZE != 0) {
67 /* Bits above new size are considered used. */
68 this->used_bitmap[new_size / BITMAP_SIZE] |= (~static_cast<BitmapStorage>(0)) << (new_size % BITMAP_SIZE);
69 }
70}
71
76DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
77{
78 for (auto it = std::next(std::begin(this->used_bitmap), this->first_free / BITMAP_SIZE); it != std::end(this->used_bitmap); ++it) {
79 BitmapStorage available = ~(*it);
80 if (available == 0) continue;
81 return std::distance(std::begin(this->used_bitmap), it) * BITMAP_SIZE + FindFirstBit(available);
82 }
83
84 assert(this->first_unused == this->data.size());
85
86 if (this->first_unused < Tmax_size) {
87 this->ResizeFor(this->first_unused);
88 return this->first_unused;
89 }
90
91 assert(this->first_unused == Tmax_size);
92
93 return NO_FREE_ITEM;
94}
95
103DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
104{
105 assert(this->data[index] == nullptr);
106
107 this->first_unused = std::max(this->first_unused, index + 1);
108 this->items++;
109
110 Titem *item;
111 if (Tcache && this->alloc_cache != nullptr) {
112 assert(sizeof(Titem) == size);
113 item = reinterpret_cast<Titem *>(this->alloc_cache);
114 this->alloc_cache = this->alloc_cache->next;
115 if (Tzero) {
116 /* Explicitly casting to (void *) prevents a clang warning -
117 * we are actually memsetting a (not-yet-constructed) object */
118 memset(static_cast<void *>(item), 0, sizeof(Titem));
119 }
120 } else if (Tzero) {
121 item = reinterpret_cast<Titem *>(CallocT<uint8_t>(size));
122 } else {
123 item = reinterpret_cast<Titem *>(MallocT<uint8_t>(size));
124 }
125 this->data[index] = item;
126 SetBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
127 item->index = (Tindex)(uint)index;
128 return item;
129}
130
137DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
138{
139 size_t index = this->FindFirstFree();
140
141#ifdef WITH_ASSERT
142 assert(this->checked != 0);
143 this->checked--;
144#endif /* WITH_ASSERT */
145 if (index == NO_FREE_ITEM) {
146 FatalError("{}: no more free items", this->name);
147 }
148
149 this->first_free = index + 1;
150 return this->AllocateItem(size, index);
151}
152
160DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
161{
162 if (index >= Tmax_size) {
163 SlErrorCorruptFmt("{} index {} out of range ({})", this->name, index, Tmax_size);
164 }
165
166 if (index >= this->data.size()) this->ResizeFor(index);
167
168 if (this->data[index] != nullptr) {
169 SlErrorCorruptFmt("{} index {} already in use", this->name, index);
170 }
171
172 return this->AllocateItem(size, index);
173}
174
181DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
182{
183 assert(index < this->data.size());
184 assert(this->data[index] != nullptr);
185 if (Tcache) {
186 AllocCache *ac = reinterpret_cast<AllocCache *>(this->data[index]);
187 ac->next = this->alloc_cache;
188 this->alloc_cache = ac;
189 } else {
190 free(this->data[index]);
191 }
192 this->data[index] = nullptr;
193 this->first_free = std::min(this->first_free, index);
194 this->items--;
195 if (!this->cleaning) {
196 ClrBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
197 Titem::PostDestructor(index);
198 }
199}
200
202DEFINE_POOL_METHOD(void)::CleanPool()
203{
204 this->cleaning = true;
205 for (size_t i = 0; i < this->first_unused; i++) {
206 delete this->Get(i); // 'delete nullptr;' is very valid
207 }
208 assert(this->items == 0);
209 this->data.clear();
210 this->data.shrink_to_fit();
211 this->used_bitmap.clear();
212 this->used_bitmap.shrink_to_fit();
213 this->first_unused = this->first_free = 0;
214 this->cleaning = false;
215
216 if (Tcache) {
217 while (this->alloc_cache != nullptr) {
218 AllocCache *ac = this->alloc_cache;
219 this->alloc_cache = ac->next;
220 free(ac);
221 }
222 }
223}
224
225#undef DEFINE_POOL_METHOD
226
232#define INSTANTIATE_POOL_METHODS(name) \
233 template void * name ## Pool::GetNew(size_t size); \
234 template void * name ## Pool::GetNew(size_t size, size_t index); \
235 template void name ## Pool::FreeItem(size_t index); \
236 template void name ## Pool::CleanPool();
237
238#endif /* POOL_FUNC_HPP */
Functions related to the allocation of memory.
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.
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
Definition math_func.hpp:37
Functions related to memory operations.
#define DEFINE_POOL_METHOD(type)
Helper for defining the method's signature.
Definition pool_func.hpp:25
Definition of Pool, structure used to access PoolItems, and PoolItem, base structure for Vehicle,...
void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition stdafx.h:331
Base class for base of all pools.
Definition pool_type.hpp:28
Base class for all pools.
Definition pool_type.hpp:79