Rework the way the ReinitSeparation command is called. The old way was way too danger...
[openttd-joker.git] / src / core / pool_func.hpp
blob2829faeac4a10de92d636b711a889ab4335d9dcf
1 /* $Id: pool_func.hpp 26057 2013-11-23 13:12:19Z rubidium $ */
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 */
10 /** @file pool_func.hpp Some methods of Pool are placed here in order to reduce compilation time and binary size. */
12 #ifndef POOL_FUNC_HPP
13 #define POOL_FUNC_HPP
15 #include "alloc_func.hpp"
16 #include "mem_func.hpp"
17 #include "pool_type.hpp"
19 /**
20 * Helper for defining the method's signature.
21 * @param type The return type of the method.
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>
27 /**
28 * Create a clean pool.
29 * @param name The name for the pool.
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(nullptr),
43 alloc_cache(nullptr)
44 { }
46 /**
47 * Resizes the pool so 'index' can be addressed
48 * @param index index we will allocate later
49 * @pre index >= this->size
50 * @pre index < Tmax_size
52 DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
54 assert(index >= this->size);
55 assert(index < Tmax_size);
57 size_t new_size = min(Tmax_size, Align(index + 1, Tgrowth_step));
59 this->data = ReallocT(this->data, new_size);
60 MemSetT(this->data + this->size, 0, new_size - this->size);
62 this->size = new_size;
65 /**
66 * Searches for first free index
67 * @return first free index, NO_FREE_ITEM on failure
69 DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
71 size_t index = this->first_free;
73 for (; index < this->first_unused; index++) {
74 if (this->data[index] == nullptr) return index;
77 if (index < this->size) {
78 return index;
81 assert(index == this->size);
82 assert(this->first_unused == this->size);
84 if (index < Tmax_size) {
85 this->ResizeFor(index);
86 return index;
89 assert(this->items == Tmax_size);
91 return NO_FREE_ITEM;
94 /**
95 * Makes given index valid
96 * @param size size of item
97 * @param index index of item
98 * @pre index < this->size
99 * @pre this->Get(index) == nullptr
101 DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
103 assert(this->data[index] == nullptr);
105 this->first_unused = max(this->first_unused, index + 1);
106 this->items++;
108 Titem *item;
109 if (Tcache && this->alloc_cache != nullptr) {
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));
118 } else if (Tzero) {
119 item = (Titem *)CallocT<byte>(size);
120 } else {
121 item = (Titem *)MallocT<byte>(size);
123 this->data[index] = item;
124 item->index = (Tindex)(uint)index;
125 return item;
129 * Allocates new item
130 * @param size size of item
131 * @return pointer to allocated item
132 * @note error() on failure! (no free item)
134 DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
136 size_t index = this->FindFirstFree();
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);
146 this->first_free = index + 1;
147 return this->AllocateItem(size, index);
151 * Allocates new item with given index
152 * @param size size of item
153 * @param index index of item
154 * @return pointer to allocated item
155 * @note usererror() on failure! (index out of range or already used)
157 DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
159 if (index >= Tmax_size) {
160 usererror("failed loading savegame: %s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
163 if (index >= this->size) this->ResizeFor(index);
165 if (this->data[index] != nullptr) {
166 usererror("failed loading savegame: %s index " PRINTF_SIZE " already in use", this->name, index);
169 return this->AllocateItem(size, index);
173 * Deallocates memory used by this index and marks item as free
174 * @param index item to deallocate
175 * @pre unit is allocated (non-nullptr)
176 * @note 'delete nullptr' doesn't cause call of this function, so it is safe
178 DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
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]);
189 this->data[index] = nullptr;
190 this->first_free = min(this->first_free, index);
191 this->items--;
192 if (!this->cleaning) Titem::PostDestructor(index);
195 /** Destroys all items in the pool and resets all member variables. */
196 DEFINE_POOL_METHOD(void)::CleanPool()
198 this->cleaning = true;
199 Titem::PreCleanPool();
200 for (size_t i = 0; i < this->first_unused; i++) {
201 delete this->Get(i); // 'delete nullptr;' is very valid
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;
209 if (Tcache) {
210 while (this->alloc_cache != nullptr) {
211 AllocCache *ac = this->alloc_cache;
212 this->alloc_cache = ac->next;
213 free(ac);
218 #undef DEFINE_POOL_METHOD
221 * Force instantiation of pool methods so we don't get linker errors.
222 * Only methods accessed from methods defined in pool.hpp need to be
223 * forcefully instantiated.
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();
231 #endif /* POOL_FUNC_HPP */