OpenTTD Source  14.0-beta1
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 "mem_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, size_t Tmax_size, PoolType Tpool_type, bool Tcache, bool Tzero> \
26  type Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero>
27 
32 DEFINE_POOL_METHOD(inline)::Pool(const char *name) :
33  PoolBase(Tpool_type),
34  name(name),
35  size(0),
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  data(nullptr),
44  alloc_cache(nullptr)
45 { }
46 
53 DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
54 {
55  assert(index >= this->size);
56  assert(index < Tmax_size);
57 
58  size_t new_size = std::min(Tmax_size, Align(index + 1, Tgrowth_step));
59 
60  this->data = ReallocT(this->data, new_size);
61  MemSetT(this->data + this->size, 0, new_size - this->size);
62 
63  this->size = new_size;
64 }
65 
70 DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
71 {
72  size_t index = this->first_free;
73 
74  for (; index < this->first_unused; index++) {
75  if (this->data[index] == nullptr) return index;
76  }
77 
78  if (index < this->size) {
79  return index;
80  }
81 
82  assert(index == this->size);
83  assert(this->first_unused == this->size);
84 
85  if (index < Tmax_size) {
86  this->ResizeFor(index);
87  return index;
88  }
89 
90  assert(this->items == Tmax_size);
91 
92  return NO_FREE_ITEM;
93 }
94 
102 DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
103 {
104  assert(this->data[index] == nullptr);
105 
106  this->first_unused = std::max(this->first_unused, index + 1);
107  this->items++;
108 
109  Titem *item;
110  if (Tcache && this->alloc_cache != nullptr) {
111  assert(sizeof(Titem) == size);
112  item = (Titem *)this->alloc_cache;
113  this->alloc_cache = this->alloc_cache->next;
114  if (Tzero) {
115  /* Explicitly casting to (void *) prevents a clang warning -
116  * we are actually memsetting a (not-yet-constructed) object */
117  memset((void *)item, 0, sizeof(Titem));
118  }
119  } else if (Tzero) {
120  item = (Titem *)CallocT<byte>(size);
121  } else {
122  item = (Titem *)MallocT<byte>(size);
123  }
124  this->data[index] = item;
125  item->index = (Tindex)(uint)index;
126  return item;
127 }
128 
135 DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
136 {
137  size_t index = this->FindFirstFree();
138 
139 #ifdef WITH_ASSERT
140  assert(this->checked != 0);
141  this->checked--;
142 #endif /* WITH_ASSERT */
143  if (index == NO_FREE_ITEM) {
144  FatalError("{}: no more free items", this->name);
145  }
146 
147  this->first_free = index + 1;
148  return this->AllocateItem(size, index);
149 }
150 
158 DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
159 {
160  if (index >= Tmax_size) {
161  SlErrorCorruptFmt("{} index {} out of range ({})", this->name, index, Tmax_size);
162  }
163 
164  if (index >= this->size) this->ResizeFor(index);
165 
166  if (this->data[index] != nullptr) {
167  SlErrorCorruptFmt("{} index {} already in use", this->name, index);
168  }
169 
170  return this->AllocateItem(size, index);
171 }
172 
179 DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
180 {
181  assert(index < this->size);
182  assert(this->data[index] != nullptr);
183  if (Tcache) {
184  AllocCache *ac = (AllocCache *)this->data[index];
185  ac->next = this->alloc_cache;
186  this->alloc_cache = ac;
187  } else {
188  free(this->data[index]);
189  }
190  this->data[index] = nullptr;
191  this->first_free = std::min(this->first_free, index);
192  this->items--;
193  if (!this->cleaning) Titem::PostDestructor(index);
194 }
195 
197 DEFINE_POOL_METHOD(void)::CleanPool()
198 {
199  this->cleaning = true;
200  for (size_t i = 0; i < this->first_unused; i++) {
201  delete this->Get(i); // 'delete nullptr;' is very valid
202  }
203  assert(this->items == 0);
204  free(this->data);
205  this->first_unused = this->first_free = this->size = 0;
206  this->data = nullptr;
207  this->cleaning = false;
208 
209  if (Tcache) {
210  while (this->alloc_cache != nullptr) {
211  AllocCache *ac = this->alloc_cache;
212  this->alloc_cache = ac->next;
213  free(ac);
214  }
215  }
216 }
217 
218 #undef DEFINE_POOL_METHOD
219 
225 #define INSTANTIATE_POOL_METHODS(name) \
226  template void * name ## Pool::GetNew(size_t size); \
227  template void * name ## Pool::GetNew(size_t size, size_t index); \
228  template void name ## Pool::FreeItem(size_t index); \
229  template void name ## Pool::CleanPool();
230 
231 #endif /* POOL_FUNC_HPP */
mem_func.hpp
ReallocT
T * ReallocT(T *t_ptr, size_t num_elements)
Simplified reallocation function that allocates the specified number of elements of the given type.
Definition: alloc_func.hpp:111
PoolBase
Base class for base of all pools.
Definition: pool_type.hpp:29
free
void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: stdafx.h:379
Pool
Base class for all pools.
Definition: pool_type.hpp:80
DEFINE_POOL_METHOD
#define DEFINE_POOL_METHOD(type)
Helper for defining the method's signature.
Definition: pool_func.hpp:24
alloc_func.hpp
MemSetT
void MemSetT(T *ptr, byte value, size_t num=1)
Type-safe version of memset().
Definition: mem_func.hpp:49
pool_type.hpp
Align
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
Definition: math_func.hpp:37