OpenTTD Source  1.11.2
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 
21 #define DEFINE_POOL_METHOD(type) \
22  template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type, bool Tcache, bool Tzero> \
23  type Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero>
24 
29 DEFINE_POOL_METHOD(inline)::Pool(const char *name) :
30  PoolBase(Tpool_type),
31  name(name),
32  size(0),
33  first_free(0),
34  first_unused(0),
35  items(0),
36 #ifdef OTTD_ASSERT
37  checked(0),
38 #endif /* OTTD_ASSERT */
39  cleaning(false),
40  data(nullptr),
41  alloc_cache(nullptr)
42 { }
43 
50 DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
51 {
52  assert(index >= this->size);
53  assert(index < Tmax_size);
54 
55  size_t new_size = std::min(Tmax_size, Align(index + 1, Tgrowth_step));
56 
57  this->data = ReallocT(this->data, new_size);
58  MemSetT(this->data + this->size, 0, new_size - this->size);
59 
60  this->size = new_size;
61 }
62 
67 DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
68 {
69  size_t index = this->first_free;
70 
71  for (; index < this->first_unused; index++) {
72  if (this->data[index] == nullptr) return index;
73  }
74 
75  if (index < this->size) {
76  return index;
77  }
78 
79  assert(index == this->size);
80  assert(this->first_unused == this->size);
81 
82  if (index < Tmax_size) {
83  this->ResizeFor(index);
84  return index;
85  }
86 
87  assert(this->items == Tmax_size);
88 
89  return NO_FREE_ITEM;
90 }
91 
99 DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
100 {
101  assert(this->data[index] == nullptr);
102 
103  this->first_unused = std::max(this->first_unused, index + 1);
104  this->items++;
105 
106  Titem *item;
107  if (Tcache && this->alloc_cache != nullptr) {
108  assert(sizeof(Titem) == size);
109  item = (Titem *)this->alloc_cache;
110  this->alloc_cache = this->alloc_cache->next;
111  if (Tzero) {
112  /* Explicitly casting to (void *) prevents a clang warning -
113  * we are actually memsetting a (not-yet-constructed) object */
114  memset((void *)item, 0, sizeof(Titem));
115  }
116  } else if (Tzero) {
117  item = (Titem *)CallocT<byte>(size);
118  } else {
119  item = (Titem *)MallocT<byte>(size);
120  }
121  this->data[index] = item;
122  item->index = (Tindex)(uint)index;
123  return item;
124 }
125 
132 DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
133 {
134  size_t index = this->FindFirstFree();
135 
136 #ifdef OTTD_ASSERT
137  assert(this->checked != 0);
138  this->checked--;
139 #endif /* OTTD_ASSERT */
140  if (index == NO_FREE_ITEM) {
141  error("%s: no more free items", this->name);
142  }
143 
144  this->first_free = index + 1;
145  return this->AllocateItem(size, index);
146 }
147 
155 DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
156 {
157  extern void NORETURN SlErrorCorruptFmt(const char *format, ...);
158 
159  if (index >= Tmax_size) {
160  SlErrorCorruptFmt("%s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
161  }
162 
163  if (index >= this->size) this->ResizeFor(index);
164 
165  if (this->data[index] != nullptr) {
166  SlErrorCorruptFmt("%s index " PRINTF_SIZE " already in use", this->name, index);
167  }
168 
169  return this->AllocateItem(size, index);
170 }
171 
178 DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
179 {
180  assert(index < this->size);
181  assert(this->data[index] != nullptr);
182  if (Tcache) {
183  AllocCache *ac = (AllocCache *)this->data[index];
184  ac->next = this->alloc_cache;
185  this->alloc_cache = ac;
186  } else {
187  free(this->data[index]);
188  }
189  this->data[index] = nullptr;
190  this->first_free = std::min(this->first_free, index);
191  this->items--;
192  if (!this->cleaning) Titem::PostDestructor(index);
193 }
194 
196 DEFINE_POOL_METHOD(void)::CleanPool()
197 {
198  this->cleaning = true;
199  for (size_t i = 0; i < this->first_unused; i++) {
200  delete this->Get(i); // 'delete nullptr;' is very valid
201  }
202  assert(this->items == 0);
203  free(this->data);
204  this->first_unused = this->first_free = this->size = 0;
205  this->data = nullptr;
206  this->cleaning = false;
207 
208  if (Tcache) {
209  while (this->alloc_cache != nullptr) {
210  AllocCache *ac = this->alloc_cache;
211  this->alloc_cache = ac->next;
212  free(ac);
213  }
214  }
215 }
216 
217 #undef DEFINE_POOL_METHOD
218 
224 #define INSTANTIATE_POOL_METHODS(name) \
225  template void * name ## Pool::GetNew(size_t size); \
226  template void * name ## Pool::GetNew(size_t size, size_t index); \
227  template void name ## Pool::FreeItem(size_t index); \
228  template void name ## Pool::CleanPool();
229 
230 #endif /* POOL_FUNC_HPP */
mem_func.hpp
PoolBase
Base class for base of all pools.
Definition: pool_type.hpp:30
Align
static T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
Definition: math_func.hpp:35
SlErrorCorruptFmt
void NORETURN SlErrorCorruptFmt(const char *format,...)
Issue an SlErrorCorrupt with a format string.
Definition: saveload.cpp:370
Pool
Base class for all pools.
Definition: pool_type.hpp:81
DEFINE_POOL_METHOD
#define DEFINE_POOL_METHOD(type)
Helper for defining the method's signature.
Definition: pool_func.hpp:21
alloc_func.hpp
ReallocT
static 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
error
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
Definition: openttd.cpp:132
MemSetT
static void MemSetT(T *ptr, byte value, size_t num=1)
Type-safe version of memset().
Definition: mem_func.hpp:49
pool_type.hpp
free
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: stdafx.h:456