# 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 */