pool_func.hpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
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) MemSetT(item, 0);
00111   } else if (Tzero) {
00112     item = (Titem *)CallocT<byte>(size);
00113   } else {
00114     item = (Titem *)MallocT<byte>(size);
00115   }
00116   this->data[index] = item;
00117   item->index = (uint)index;
00118   return item;
00119 }
00120 
00127 DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
00128 {
00129   size_t index = this->FindFirstFree();
00130 
00131 #ifdef OTTD_ASSERT
00132   assert(this->checked != 0);
00133   this->checked--;
00134 #endif /* OTTD_ASSERT */
00135   if (index == NO_FREE_ITEM) {
00136     error("%s: no more free items", this->name);
00137   }
00138 
00139   this->first_free = index + 1;
00140   return this->AllocateItem(size, index);
00141 }
00142 
00150 DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
00151 {
00152   if (index >= Tmax_size) {
00153     usererror("failed loading savegame: %s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
00154   }
00155 
00156   if (index >= this->size) this->ResizeFor(index);
00157 
00158   if (this->data[index] != NULL) {
00159     usererror("failed loading savegame: %s index " PRINTF_SIZE " already in use", this->name, index);
00160   }
00161 
00162   return this->AllocateItem(size, index);
00163 }
00164 
00171 DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
00172 {
00173   assert(index < this->size);
00174   assert(this->data[index] != NULL);
00175   if (Tcache) {
00176     AllocCache *ac = (AllocCache *)this->data[index];
00177     ac->next = this->alloc_cache;
00178     this->alloc_cache = ac;
00179   } else {
00180     free(this->data[index]);
00181   }
00182   this->data[index] = NULL;
00183   this->first_free = min(this->first_free, index);
00184   this->items--;
00185   if (!this->cleaning) Titem::PostDestructor(index);
00186 }
00187 
00189 DEFINE_POOL_METHOD(void)::CleanPool()
00190 {
00191   this->cleaning = true;
00192   for (size_t i = 0; i < this->first_unused; i++) {
00193     delete this->Get(i); // 'delete NULL;' is very valid
00194   }
00195   assert(this->items == 0);
00196   free(this->data);
00197   this->first_unused = this->first_free = this->size = 0;
00198   this->data = NULL;
00199   this->cleaning = false;
00200 
00201   if (Tcache) {
00202     while (this->alloc_cache != NULL) {
00203       AllocCache *ac = this->alloc_cache;
00204       this->alloc_cache = ac->next;
00205       free(ac);
00206     }
00207   }
00208 }
00209 
00210 #undef DEFINE_POOL_METHOD
00211 
00217 #define INSTANTIATE_POOL_METHODS(name) \
00218   template void * name ## Pool::GetNew(size_t size); \
00219   template void * name ## Pool::GetNew(size_t size, size_t index); \
00220   template void name ## Pool::FreeItem(size_t index); \
00221   template void name ## Pool::CleanPool();
00222 
00223 #endif /* POOL_FUNC_HPP */

Generated on Sun Jun 5 04:19:55 2011 for OpenTTD by  doxygen 1.6.1