Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifndef POOL_FUNC_HPP
00013 #define POOL_FUNC_HPP
00014
00015 #include "alloc_func.hpp"
00016 #include "mem_func.hpp"
00017 #include "pool_type.hpp"
00018
00023 #define DEFINE_POOL_METHOD(type) \
00024 template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type, bool Tcache, bool Tzero> \
00025 type Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero>
00026
00031 DEFINE_POOL_METHOD(inline)::Pool(const char *name) :
00032 PoolBase(Tpool_type),
00033 name(name),
00034 size(0),
00035 first_free(0),
00036 first_unused(0),
00037 items(0),
00038 #ifdef OTTD_ASSERT
00039 checked(0),
00040 #endif
00041 cleaning(false),
00042 data(NULL),
00043 alloc_cache(NULL)
00044 { }
00045
00052 DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
00053 {
00054 assert(index >= this->size);
00055 assert(index < Tmax_size);
00056
00057 size_t new_size = min(Tmax_size, Align(index + 1, Tgrowth_step));
00058
00059 this->data = ReallocT(this->data, new_size);
00060 MemSetT(this->data + this->size, 0, new_size - this->size);
00061
00062 this->size = new_size;
00063 }
00064
00069 DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
00070 {
00071 size_t index = this->first_free;
00072
00073 for (; index < this->first_unused; index++) {
00074 if (this->data[index] == NULL) return index;
00075 }
00076
00077 if (index < this->size) {
00078 return index;
00079 }
00080
00081 assert(index == this->size);
00082 assert(this->first_unused == this->size);
00083
00084 if (index < Tmax_size) {
00085 this->ResizeFor(index);
00086 return index;
00087 }
00088
00089 assert(this->items == Tmax_size);
00090
00091 return NO_FREE_ITEM;
00092 }
00093
00101 DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
00102 {
00103 assert(this->data[index] == NULL);
00104
00105 this->first_unused = max(this->first_unused, index + 1);
00106 this->items++;
00107
00108 Titem *item;
00109 if (Tcache && this->alloc_cache != NULL) {
00110 assert(sizeof(Titem) == size);
00111 item = (Titem *)this->alloc_cache;
00112 this->alloc_cache = this->alloc_cache->next;
00113 if (Tzero) {
00114
00115
00116 memset((void *)item, 0, sizeof(Titem));
00117 }
00118 } else if (Tzero) {
00119 item = (Titem *)CallocT<byte>(size);
00120 } else {
00121 item = (Titem *)MallocT<byte>(size);
00122 }
00123 this->data[index] = item;
00124 item->index = (uint)index;
00125 return item;
00126 }
00127
00134 DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
00135 {
00136 size_t index = this->FindFirstFree();
00137
00138 #ifdef OTTD_ASSERT
00139 assert(this->checked != 0);
00140 this->checked--;
00141 #endif
00142 if (index == NO_FREE_ITEM) {
00143 error("%s: no more free items", this->name);
00144 }
00145
00146 this->first_free = index + 1;
00147 return this->AllocateItem(size, index);
00148 }
00149
00157 DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
00158 {
00159 if (index >= Tmax_size) {
00160 usererror("failed loading savegame: %s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
00161 }
00162
00163 if (index >= this->size) this->ResizeFor(index);
00164
00165 if (this->data[index] != NULL) {
00166 usererror("failed loading savegame: %s index " PRINTF_SIZE " already in use", this->name, index);
00167 }
00168
00169 return this->AllocateItem(size, index);
00170 }
00171
00178 DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
00179 {
00180 assert(index < this->size);
00181 assert(this->data[index] != NULL);
00182 if (Tcache) {
00183 AllocCache *ac = (AllocCache *)this->data[index];
00184 ac->next = this->alloc_cache;
00185 this->alloc_cache = ac;
00186 } else {
00187 free(this->data[index]);
00188 }
00189 this->data[index] = NULL;
00190 this->first_free = min(this->first_free, index);
00191 this->items--;
00192 if (!this->cleaning) Titem::PostDestructor(index);
00193 }
00194
00196 DEFINE_POOL_METHOD(void)::CleanPool()
00197 {
00198 this->cleaning = true;
00199 for (size_t i = 0; i < this->first_unused; i++) {
00200 delete this->Get(i);
00201 }
00202 assert(this->items == 0);
00203 free(this->data);
00204 this->first_unused = this->first_free = this->size = 0;
00205 this->data = NULL;
00206 this->cleaning = false;
00207
00208 if (Tcache) {
00209 while (this->alloc_cache != NULL) {
00210 AllocCache *ac = this->alloc_cache;
00211 this->alloc_cache = ac->next;
00212 free(ac);
00213 }
00214 }
00215 }
00216
00217 #undef DEFINE_POOL_METHOD
00218
00224 #define INSTANTIATE_POOL_METHODS(name) \
00225 template void * name ## Pool::GetNew(size_t size); \
00226 template void * name ## Pool::GetNew(size_t size, size_t index); \
00227 template void name ## Pool::FreeItem(size_t index); \
00228 template void name ## Pool::CleanPool();
00229
00230 #endif