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 cleaning(false),
00039 data(NULL),
00040 alloc_cache(NULL)
00041 { }
00042
00049 DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
00050 {
00051 assert(index >= this->size);
00052 assert(index < Tmax_size);
00053
00054 size_t new_size = min(Tmax_size, Align(index + 1, Tgrowth_step));
00055
00056 this->data = ReallocT(this->data, new_size);
00057 MemSetT(this->data + this->size, 0, new_size - this->size);
00058
00059 this->size = new_size;
00060 }
00061
00066 DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
00067 {
00068 size_t index = this->first_free;
00069
00070 for (; index < this->first_unused; index++) {
00071 if (this->data[index] == NULL) return index;
00072 }
00073
00074 if (index < this->size) {
00075 return index;
00076 }
00077
00078 assert(index == this->size);
00079 assert(this->first_unused == this->size);
00080
00081 if (index < Tmax_size) {
00082 this->ResizeFor(index);
00083 return index;
00084 }
00085
00086 assert(this->items == Tmax_size);
00087
00088 return NO_FREE_ITEM;
00089 }
00090
00098 DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
00099 {
00100 assert(this->data[index] == NULL);
00101
00102 this->first_unused = max(this->first_unused, index + 1);
00103 this->items++;
00104
00105 Titem *item;
00106 if (Tcache && this->alloc_cache != NULL) {
00107 assert(sizeof(Titem) == size);
00108 item = (Titem *)this->alloc_cache;
00109 this->alloc_cache = this->alloc_cache->next;
00110 if (Tzero) {
00111
00112
00113 memset((void *)item, 0, sizeof(Titem));
00114 }
00115 } else if (Tzero) {
00116 item = (Titem *)CallocT<byte>(size);
00117 } else {
00118 item = (Titem *)MallocT<byte>(size);
00119 }
00120 this->data[index] = item;
00121 item->index = (uint)index;
00122 return item;
00123 }
00124
00131 DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
00132 {
00133 size_t index = this->FindFirstFree();
00134
00135 #ifdef OTTD_ASSERT
00136 assert(this->checked != 0);
00137 this->checked--;
00138 #endif
00139 if (index == NO_FREE_ITEM) {
00140 error("%s: no more free items", this->name);
00141 }
00142
00143 this->first_free = index + 1;
00144 return this->AllocateItem(size, index);
00145 }
00146
00154 DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
00155 {
00156 if (index >= Tmax_size) {
00157 usererror("failed loading savegame: %s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
00158 }
00159
00160 if (index >= this->size) this->ResizeFor(index);
00161
00162 if (this->data[index] != NULL) {
00163 usererror("failed loading savegame: %s index " PRINTF_SIZE " already in use", this->name, index);
00164 }
00165
00166 return this->AllocateItem(size, index);
00167 }
00168
00175 DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
00176 {
00177 assert(index < this->size);
00178 assert(this->data[index] != NULL);
00179 if (Tcache) {
00180 AllocCache *ac = (AllocCache *)this->data[index];
00181 ac->next = this->alloc_cache;
00182 this->alloc_cache = ac;
00183 } else {
00184 free(this->data[index]);
00185 }
00186 this->data[index] = NULL;
00187 this->first_free = min(this->first_free, index);
00188 this->items--;
00189 if (!this->cleaning) Titem::PostDestructor(index);
00190 }
00191
00193 DEFINE_POOL_METHOD(void)::CleanPool()
00194 {
00195 this->cleaning = true;
00196 for (size_t i = 0; i < this->first_unused; i++) {
00197 delete this->Get(i);
00198 }
00199 assert(this->items == 0);
00200 free(this->data);
00201 this->first_unused = this->first_free = this->size = 0;
00202 this->data = NULL;
00203 this->cleaning = false;
00204
00205 if (Tcache) {
00206 while (this->alloc_cache != NULL) {
00207 AllocCache *ac = this->alloc_cache;
00208 this->alloc_cache = ac->next;
00209 free(ac);
00210 }
00211 }
00212 }
00213
00214 #undef DEFINE_POOL_METHOD
00215
00221 #define INSTANTIATE_POOL_METHODS(name) \
00222 template void * name ## Pool::GetNew(size_t size); \
00223 template void * name ## Pool::GetNew(size_t size, size_t index); \
00224 template void name ## Pool::FreeItem(size_t index); \
00225 template void name ## Pool::CleanPool();
00226
00227 #endif