pool_func.hpp

Go to the documentation of this file.
00001 /* $Id: pool_func.hpp 17839 2009-10-21 19:38:50Z rubidium $ */
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 
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); // 'delete NULL;' is very valid
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 /* POOL_FUNC_HPP */

Generated on Sat Jun 5 21:52:03 2010 for OpenTTD by  doxygen 1.6.1