OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

pool_func.hpp
Go to the documentation of this file.
1 /* $Id: pool_func.hpp 27381 2015-08-10 20:24:13Z michi_cc $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
9
12 #ifndef POOL_FUNC_HPP
13 #define POOL_FUNC_HPP
14
15 #include "alloc_func.hpp"
16 #include "mem_func.hpp"
17 #include "pool_type.hpp"
18
23 #define DEFINE_POOL_METHOD(type) \
24 template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type, bool Tcache, bool Tzero> \
25 type Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero>
26
31 DEFINE_POOL_METHOD(inline)::Pool(const char *name) :
32 PoolBase(Tpool_type),
33 name(name),
34 size(0),
35 first_free(0),
36 first_unused(0),
37 items(0),
38 #ifdef OTTD_ASSERT
39 checked(0),
40 #endif /* OTTD_ASSERT */
41 cleaning(false),
42 data(NULL),
43 alloc_cache(NULL)
44 { }
45
52 DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
53 {
54 assert(index >= this->size);
55 assert(index < Tmax_size);
56
57 size_t new_size = min(Tmax_size, Align(index + 1, Tgrowth_step));
58
59 this->data = ReallocT(this->data, new_size);
60 MemSetT(this->data + this->size, 0, new_size - this->size);
61
62 this->size = new_size;
63 }
64
69 DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
70 {
71 size_t index = this->first_free;
72
73 for (; index < this->first_unused; index++) {
74 if (this->data[index] == NULL) return index;
75 }
76
77 if (index < this->size) {
78 return index;
79 }
80
81 assert(index == this->size);
82 assert(this->first_unused == this->size);
83
84 if (index < Tmax_size) {
85 this->ResizeFor(index);
86 return index;
87 }
88
89 assert(this->items == Tmax_size);
90
91 return NO_FREE_ITEM;
92 }
93
101 DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
102 {
103 assert(this->data[index] == NULL);
104
105 this->first_unused = max(this->first_unused, index + 1);
106 this->items++;
107
108 Titem *item;
109 if (Tcache && this->alloc_cache != NULL) {
110 assert(sizeof(Titem) == size);
111 item = (Titem *)this->alloc_cache;
112 this->alloc_cache = this->alloc_cache->next;
113 if (Tzero) {
114 /* Explicitly casting to (void *) prevents a clang warning -
115 * we are actually memsetting a (not-yet-constructed) object */
116 memset((void *)item, 0, sizeof(Titem));
117 }
118 } else if (Tzero) {
119 item = (Titem *)CallocT<byte>(size);
120 } else {
121 item = (Titem *)MallocT<byte>(size);
122 }
123 this->data[index] = item;
124 item->index = (Tindex)(uint)index;
125 return item;
126 }
127
134 DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
135 {
136 size_t index = this->FindFirstFree();
137
138 #ifdef OTTD_ASSERT
139 assert(this->checked != 0);
140 this->checked--;
141 #endif /* OTTD_ASSERT */
142 if (index == NO_FREE_ITEM) {
143 error("%s: no more free items", this->name);
144 }
145
146 this->first_free = index + 1;
147 return this->AllocateItem(size, index);
148 }
149
157 DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
158 {
159 if (index >= Tmax_size) {
160 usererror("failed loading savegame: %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] != NULL) {
166 usererror("failed loading savegame: %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] != NULL);
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] = NULL;
190 this->first_free = 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 NULL;' 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 = NULL;
206 this->cleaning = false;
207
208 if (Tcache) {
209 while (this->alloc_cache != NULL) {
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 */