pool_func.hpp
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
00019 #define DEFINE_POOL_METHOD(type) \
00020 template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, bool Tcache, bool Tzero> \
00021 type Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tcache, Tzero>
00022
00023 DEFINE_POOL_METHOD(inline)::Pool(const char *name) :
00024 name(name),
00025 size(0),
00026 first_free(0),
00027 first_unused(0),
00028 items(0),
00029 cleaning(false),
00030 data(NULL),
00031 alloc_cache(NULL)
00032 { }
00033
00034 DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
00035 {
00036 assert(index >= this->size);
00037 assert(index < Tmax_size);
00038
00039 size_t new_size = min(Tmax_size, Align(index + 1, Tgrowth_step));
00040
00041 this->data = ReallocT(this->data, new_size);
00042 MemSetT(this->data + this->size, 0, new_size - this->size);
00043
00044 this->size = new_size;
00045 }
00046
00047 DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
00048 {
00049 size_t index = this->first_free;
00050
00051 for (; index < this->first_unused; index++) {
00052 if (this->data[index] == NULL) return index;
00053 }
00054
00055 if (index < this->size) {
00056 return index;
00057 }
00058
00059 assert(index == this->size);
00060 assert(this->first_unused == this->size);
00061
00062 if (index < Tmax_size) {
00063 this->ResizeFor(index);
00064 return index;
00065 }
00066
00067 assert(this->items == Tmax_size);
00068
00069 return NO_FREE_ITEM;
00070 }
00071
00072 DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
00073 {
00074 assert(this->data[index] == NULL);
00075
00076 this->first_unused = max(this->first_unused, index + 1);
00077 this->items++;
00078
00079 Titem *item;
00080 if (Tcache && this->alloc_cache != NULL) {
00081 assert(sizeof(Titem) == size);
00082 item = (Titem *)this->alloc_cache;
00083 this->alloc_cache = this->alloc_cache->next;
00084 if (Tzero) MemSetT(item, 0);
00085 } else if (Tzero) {
00086 item = (Titem *)CallocT<byte>(size);
00087 } else {
00088 item = (Titem *)MallocT<byte>(size);
00089 }
00090 this->data[index] = item;
00091 item->index = (uint)index;
00092 return item;
00093 }
00094
00095 DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
00096 {
00097 size_t index = this->FindFirstFree();
00098
00099 if (index == NO_FREE_ITEM) {
00100 error("%s: no more free items", this->name);
00101 }
00102
00103 this->first_free = index + 1;
00104 return this->AllocateItem(size, index);
00105 }
00106
00107 DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
00108 {
00109 if (index >= Tmax_size) {
00110 usererror("failed loading savegame: %s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
00111 }
00112
00113 if (index >= this->size) this->ResizeFor(index);
00114
00115 if (this->data[index] != NULL) {
00116 usererror("failed loading savegame: %s index " PRINTF_SIZE " already in use", this->name, index);
00117 }
00118
00119 return this->AllocateItem(size, index);
00120 }
00121
00122 DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
00123 {
00124 assert(index < this->size);
00125 assert(this->data[index] != NULL);
00126 if (Tcache) {
00127 AllocCache *ac = (AllocCache *)this->data[index];
00128 ac->next = this->alloc_cache;
00129 this->alloc_cache = ac;
00130 } else {
00131 free(this->data[index]);
00132 }
00133 this->data[index] = NULL;
00134 this->first_free = min(this->first_free, index);
00135 this->items--;
00136 if (!this->cleaning) Titem::PostDestructor(index);
00137 }
00138
00139 DEFINE_POOL_METHOD(void)::CleanPool()
00140 {
00141 this->cleaning = true;
00142 for (size_t i = 0; i < this->first_unused; i++) {
00143 delete this->Get(i);
00144 }
00145 assert(this->items == 0);
00146 free(this->data);
00147 this->first_unused = this->first_free = this->size = 0;
00148 this->data = NULL;
00149 this->cleaning = false;
00150
00151 if (Tcache) {
00152 while (this->alloc_cache != NULL) {
00153 AllocCache *ac = this->alloc_cache;
00154 this->alloc_cache = ac->next;
00155 free(ac);
00156 }
00157 }
00158 }
00159
00160 #undef DEFINE_POOL_METHOD
00161
00167 #define INSTANTIATE_POOL_METHODS(name) \
00168 template void * name ## Pool::GetNew(size_t size); \
00169 template void * name ## Pool::GetNew(size_t size, size_t index); \
00170 template void name ## Pool::FreeItem(size_t index); \
00171 template void name ## Pool::CleanPool();
00172
00173 #endif