pool_type.hpp

Go to the documentation of this file.
00001 /* $Id: pool_type.hpp 25887 2013-10-20 13:35:35Z fonsinchen $ */
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_TYPE_HPP
00013 #define POOL_TYPE_HPP
00014 
00015 #include "smallvec_type.hpp"
00016 #include "enum_type.hpp"
00017 
00019 enum PoolType {
00020   PT_NONE    = 0x00, 
00021   PT_NORMAL  = 0x01, 
00022   PT_NCLIENT = 0x02, 
00023   PT_NADMIN  = 0x04, 
00024   PT_DATA    = 0x08, 
00025   PT_ALL     = 0x0F, 
00026 };
00027 DECLARE_ENUM_AS_BIT_SET(PoolType)
00028 
00029 typedef SmallVector<struct PoolBase *, 4> PoolVector; 
00030 
00032 struct PoolBase {
00033   const PoolType type; 
00034 
00039   static PoolVector *GetPools()
00040   {
00041     static PoolVector *pools = new PoolVector();
00042     return pools;
00043   }
00044 
00045   static void Clean(PoolType);
00046 
00051   PoolBase(PoolType pt) : type(pt)
00052   {
00053     *PoolBase::GetPools()->Append() = this;
00054   }
00055 
00056   virtual ~PoolBase();
00057 
00061   virtual void CleanPool() = 0;
00062 
00063 private:
00068   PoolBase(const PoolBase &other);
00069 };
00070 
00082 template <class Titem, typename Tindex, size_t Tgrowth_step, size_t Tmax_size, PoolType Tpool_type = PT_NORMAL, bool Tcache = false, bool Tzero = true>
00083 struct Pool : PoolBase {
00084   static const size_t MAX_SIZE = Tmax_size; 
00085 
00086   const char * const name; 
00087 
00088   size_t size;         
00089   size_t first_free;   
00090   size_t first_unused; 
00091   size_t items;        
00092 #ifdef OTTD_ASSERT
00093   size_t checked;      
00094 #endif /* OTTD_ASSERT */
00095   bool cleaning;       
00096 
00097   Titem **data;        
00098 
00099   Pool(const char *name);
00100   virtual void CleanPool();
00101 
00108   inline Titem *Get(size_t index)
00109   {
00110     assert(index < this->first_unused);
00111     return this->data[index];
00112   }
00113 
00119   inline bool IsValidID(size_t index)
00120   {
00121     return index < this->first_unused && this->Get(index) != NULL;
00122   }
00123 
00129   inline bool CanAllocate(size_t n = 1)
00130   {
00131     bool ret = this->items <= Tmax_size - n;
00132 #ifdef OTTD_ASSERT
00133     this->checked = ret ? n : 0;
00134 #endif /* OTTD_ASSERT */
00135     return ret;
00136   }
00137 
00142   template <struct Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero> *Tpool>
00143   struct PoolItem {
00144     Tindex index; 
00145 
00152     inline void *operator new(size_t size)
00153     {
00154       return Tpool->GetNew(size);
00155     }
00156 
00162     inline void operator delete(void *p)
00163     {
00164       if (p == NULL) return;
00165       Titem *pn = (Titem *)p;
00166       assert(pn == Tpool->Get(pn->index));
00167       Tpool->FreeItem(pn->index);
00168     }
00169 
00178     inline void *operator new(size_t size, size_t index)
00179     {
00180       return Tpool->GetNew(size, index);
00181     }
00182 
00191     inline void *operator new(size_t size, void *ptr)
00192     {
00193       for (size_t i = 0; i < Tpool->first_unused; i++) {
00194         /* Don't allow creating new objects over existing.
00195          * Even if we called the destructor and reused this memory,
00196          * we don't know whether 'size' and size of currently allocated
00197          * memory are the same (because of possible inheritance).
00198          * Use { size_t index = item->index; delete item; new (index) item; }
00199          * instead to make sure destructor is called and no memory leaks. */
00200         assert(ptr != Tpool->data[i]);
00201       }
00202       return ptr;
00203     }
00204 
00205 
00213     static inline bool CanAllocateItem(size_t n = 1)
00214     {
00215       return Tpool->CanAllocate(n);
00216     }
00217 
00222     static inline bool CleaningPool()
00223     {
00224       return Tpool->cleaning;
00225     }
00226 
00232     static inline bool IsValidID(size_t index)
00233     {
00234       return Tpool->IsValidID(index);
00235     }
00236 
00243     static inline Titem *Get(size_t index)
00244     {
00245       return Tpool->Get(index);
00246     }
00247 
00254     static inline Titem *GetIfValid(size_t index)
00255     {
00256       return index < Tpool->first_unused ? Tpool->Get(index) : NULL;
00257     }
00258 
00264     static inline size_t GetPoolSize()
00265     {
00266       return Tpool->first_unused;
00267     }
00268 
00273     static inline size_t GetNumItems()
00274     {
00275       return Tpool->items;
00276     }
00277 
00285     static inline void PostDestructor(size_t index) { }
00286   };
00287 
00288 private:
00289   static const size_t NO_FREE_ITEM = MAX_UVALUE(size_t); 
00290 
00295   struct AllocCache {
00297     AllocCache *next;
00298   };
00299 
00301   AllocCache *alloc_cache;
00302 
00303   void *AllocateItem(size_t size, size_t index);
00304   void ResizeFor(size_t index);
00305   size_t FindFirstFree();
00306 
00307   void *GetNew(size_t size);
00308   void *GetNew(size_t size, size_t index);
00309 
00310   void FreeItem(size_t index);
00311 };
00312 
00313 #define FOR_ALL_ITEMS_FROM(type, iter, var, start) \
00314   for (size_t iter = start; var = NULL, iter < type::GetPoolSize(); iter++) \
00315     if ((var = type::Get(iter)) != NULL)
00316 
00317 #define FOR_ALL_ITEMS(type, iter, var) FOR_ALL_ITEMS_FROM(type, iter, var, 0)
00318 
00319 #endif /* POOL_TYPE_HPP */