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 
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 
00027 DEFINE_POOL_METHOD(inline)::Pool(const char *name) :
00028     name(name),
00029     size(0),
00030     first_free(0),
00031     first_unused(0),
00032     items(0),
00033     cleaning(false),
00034     data(NULL),
00035     alloc_cache(NULL)
00036 { }
00037 
00044 DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
00045 {
00046   assert(index >= this->size);
00047   assert(index < Tmax_size);
00048 
00049   size_t new_size = min(Tmax_size, Align(index + 1, Tgrowth_step));
00050 
00051   this->data = ReallocT(this->data, new_size);
00052   MemSetT(this->data + this->size, 0, new_size - this->size);
00053 
00054   this->size = new_size;
00055 }
00056 
00061 DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
00062 {
00063   size_t index = this->first_free;
00064 
00065   for (; index < this->first_unused; index++) {
00066     if (this->data[index] == NULL) return index;
00067   }
00068 
00069   if (index < this->size) {
00070     return index;
00071   }
00072 
00073   assert(index == this->size);
00074   assert(this->first_unused == this->size);
00075 
00076   if (index < Tmax_size) {
00077     this->ResizeFor(index);
00078     return index;
00079   }
00080 
00081   assert(this->items == Tmax_size);
00082 
00083   return NO_FREE_ITEM;
00084 }
00085 
00093 DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
00094 {
00095   assert(this->data[index] == NULL);
00096 
00097   this->first_unused = max(this->first_unused, index + 1);
00098   this->items++;
00099 
00100   Titem *item;
00101   if (Tcache && this->alloc_cache != NULL) {
00102     assert(sizeof(Titem) == size);
00103     item = (Titem *)this->alloc_cache;
00104     this->alloc_cache = this->alloc_cache->next;
00105     if (Tzero) MemSetT(item, 0);
00106   } else if (Tzero) {
00107     item = (Titem *)CallocT<byte>(size);
00108   } else {
00109     item = (Titem *)MallocT<byte>(size);
00110   }
00111   this->data[index] = item;
00112   item->index = (uint)index;
00113   return item;
00114 }
00115 
00122 DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
00123 {
00124   size_t index = this->FindFirstFree();
00125 
00126   if (index == NO_FREE_ITEM) {
00127     error("%s: no more free items", this->name);
00128   }
00129 
00130   this->first_free = index + 1;
00131   return this->AllocateItem(size, index);
00132 }
00133 
00141 DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
00142 {
00143   if (index >= Tmax_size) {
00144     usererror("failed loading savegame: %s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);
00145   }
00146 
00147   if (index >= this->size) this->ResizeFor(index);
00148 
00149   if (this->data[index] != NULL) {
00150     usererror("failed loading savegame: %s index " PRINTF_SIZE " already in use", this->name, index);
00151   }
00152 
00153   return this->AllocateItem(size, index);
00154 }
00155 
00162 DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
00163 {
00164   assert(index < this->size);
00165   assert(this->data[index] != NULL);
00166   if (Tcache) {
00167     AllocCache *ac = (AllocCache *)this->data[index];
00168     ac->next = this->alloc_cache;
00169     this->alloc_cache = ac;
00170   } else {
00171     free(this->data[index]);
00172   }
00173   this->data[index] = NULL;
00174   this->first_free = min(this->first_free, index);
00175   this->items--;
00176   if (!this->cleaning) Titem::PostDestructor(index);
00177 }
00178 
00180 DEFINE_POOL_METHOD(void)::CleanPool()
00181 {
00182   this->cleaning = true;
00183   for (size_t i = 0; i < this->first_unused; i++) {
00184     delete this->Get(i); // 'delete NULL;' is very valid
00185   }
00186   assert(this->items == 0);
00187   free(this->data);
00188   this->first_unused = this->first_free = this->size = 0;
00189   this->data = NULL;
00190   this->cleaning = false;
00191 
00192   if (Tcache) {
00193     while (this->alloc_cache != NULL) {
00194       AllocCache *ac = this->alloc_cache;
00195       this->alloc_cache = ac->next;
00196       free(ac);
00197     }
00198   }
00199 }
00200 
00201 #undef DEFINE_POOL_METHOD
00202 
00208 #define INSTANTIATE_POOL_METHODS(name) \
00209   template void * name ## Pool::GetNew(size_t size); \
00210   template void * name ## Pool::GetNew(size_t size, size_t index); \
00211   template void name ## Pool::FreeItem(size_t index); \
00212   template void name ## Pool::CleanPool();
00213 
00214 #endif /* POOL_FUNC_HPP */

Generated on Sun Jan 23 01:49:01 2011 for OpenTTD by  doxygen 1.6.1