pool_type.hpp

Go to the documentation of this file.
00001 /* $Id: pool_type.hpp 26333 2014-02-11 20:34:48Z frosch $ */
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   /* Ensure Tmax_size is within the bounds of Tindex. */
00085   assert_compile((uint64)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0);
00086 
00087   static const size_t MAX_SIZE = Tmax_size; 
00088 
00089   const char * const name; 
00090 
00091   size_t size;         
00092   size_t first_free;   
00093   size_t first_unused; 
00094   size_t items;        
00095 #ifdef OTTD_ASSERT
00096   size_t checked;      
00097 #endif /* OTTD_ASSERT */
00098   bool cleaning;       
00099 
00100   Titem **data;        
00101 
00102   Pool(const char *name);
00103   virtual void CleanPool();
00104 
00111   inline Titem *Get(size_t index)
00112   {
00113     assert(index < this->first_unused);
00114     return this->data[index];
00115   }
00116 
00122   inline bool IsValidID(size_t index)
00123   {
00124     return index < this->first_unused && this->Get(index) != NULL;
00125   }
00126 
00132   inline bool CanAllocate(size_t n = 1)
00133   {
00134     bool ret = this->items <= Tmax_size - n;
00135 #ifdef OTTD_ASSERT
00136     this->checked = ret ? n : 0;
00137 #endif /* OTTD_ASSERT */
00138     return ret;
00139   }
00140 
00145   template <struct Pool<Titem, Tindex, Tgrowth_step, Tmax_size, Tpool_type, Tcache, Tzero> *Tpool>
00146   struct PoolItem {
00147     Tindex index; 
00148 
00155     inline void *operator new(size_t size)
00156     {
00157       return Tpool->GetNew(size);
00158     }
00159 
00165     inline void operator delete(void *p)
00166     {
00167       if (p == NULL) return;
00168       Titem *pn = (Titem *)p;
00169       assert(pn == Tpool->Get(pn->index));
00170       Tpool->FreeItem(pn->index);
00171     }
00172 
00181     inline void *operator new(size_t size, size_t index)
00182     {
00183       return Tpool->GetNew(size, index);
00184     }
00185 
00194     inline void *operator new(size_t size, void *ptr)
00195     {
00196       for (size_t i = 0; i < Tpool->first_unused; i++) {
00197         /* Don't allow creating new objects over existing.
00198          * Even if we called the destructor and reused this memory,
00199          * we don't know whether 'size' and size of currently allocated
00200          * memory are the same (because of possible inheritance).
00201          * Use { size_t index = item->index; delete item; new (index) item; }
00202          * instead to make sure destructor is called and no memory leaks. */
00203         assert(ptr != Tpool->data[i]);
00204       }
00205       return ptr;
00206     }
00207 
00208 
00216     static inline bool CanAllocateItem(size_t n = 1)
00217     {
00218       return Tpool->CanAllocate(n);
00219     }
00220 
00225     static inline bool CleaningPool()
00226     {
00227       return Tpool->cleaning;
00228     }
00229 
00235     static inline bool IsValidID(size_t index)
00236     {
00237       return Tpool->IsValidID(index);
00238     }
00239 
00246     static inline Titem *Get(size_t index)
00247     {
00248       return Tpool->Get(index);
00249     }
00250 
00257     static inline Titem *GetIfValid(size_t index)
00258     {
00259       return index < Tpool->first_unused ? Tpool->Get(index) : NULL;
00260     }
00261 
00267     static inline size_t GetPoolSize()
00268     {
00269       return Tpool->first_unused;
00270     }
00271 
00276     static inline size_t GetNumItems()
00277     {
00278       return Tpool->items;
00279     }
00280 
00288     static inline void PostDestructor(size_t index) { }
00289   };
00290 
00291 private:
00292   static const size_t NO_FREE_ITEM = MAX_UVALUE(size_t); 
00293 
00298   struct AllocCache {
00300     AllocCache *next;
00301   };
00302 
00304   AllocCache *alloc_cache;
00305 
00306   void *AllocateItem(size_t size, size_t index);
00307   void ResizeFor(size_t index);
00308   size_t FindFirstFree();
00309 
00310   void *GetNew(size_t size);
00311   void *GetNew(size_t size, size_t index);
00312 
00313   void FreeItem(size_t index);
00314 };
00315 
00316 #define FOR_ALL_ITEMS_FROM(type, iter, var, start) \
00317   for (size_t iter = start; var = NULL, iter < type::GetPoolSize(); iter++) \
00318     if ((var = type::Get(iter)) != NULL)
00319 
00320 #define FOR_ALL_ITEMS(type, iter, var) FOR_ALL_ITEMS_FROM(type, iter, var, 0)
00321 
00322 #endif /* POOL_TYPE_HPP */