# oldpool.h

Go to the documentation of this file.

    00001 /* $Id: oldpool.h 12864 2008-04-24 11:48:09Z rubidium $ */
    00002
    00005 #ifndef OLDPOOL_H
    00006 #define OLDPOOL_H
    00007
    00008 #include "core/math_func.hpp"
    00009
    00010 /* The function that is called after a new block is added
    00011      start_item is the first item of the new made block */
    00012 typedef void OldMemoryPoolNewBlock(uint start_item);
    00013 /* The function that is called before a block is cleaned up */
    00014 typedef void OldMemoryPoolCleanBlock(uint start_item, uint end_item);
    00015
    00020 struct OldMemoryPoolBase {
    00021   void CleanPool();
    00022   bool AddBlockToPool();
    00023   bool AddBlockIfNeeded(uint index);
    00024
    00025 protected:
    00026   OldMemoryPoolBase(const char *name, uint max_blocks, uint block_size_bits, uint item_size,
    00027         OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) :
    00028     name(name), max_blocks(max_blocks), block_size_bits(block_size_bits),
    00029     new_block_proc(new_block_proc), clean_block_proc(clean_block_proc), current_blocks(0),
    00030     total_items(0), cleaning_pool(false), item_size(item_size), first_free_index(0), blocks(NULL) {}
    00031
    00032   const char* name;
    00033
    00034   const uint max_blocks;
    00035   const uint block_size_bits;
    00036
    00038   OldMemoryPoolNewBlock *new_block_proc;
    00040   OldMemoryPoolCleanBlock *clean_block_proc;
    00041
    00042   uint current_blocks;
    00043   uint total_items;
    00044
    00045   bool cleaning_pool;
    00046 public:
    00047   const uint item_size;
    00048   uint first_free_index;
    00049   byte **blocks;
    00050
    00056   inline void UpdateFirstFreeIndex(uint index)
    00057   {
    00058     first_free_index = min(first_free_index, index);
    00059   }
    00060
    00067   inline uint GetSize() const
    00068   {
    00069     return this->total_items;
    00070   }
    00071
    00078   inline bool CanAllocateMoreBlocks() const
    00079   {
    00080     return this->current_blocks < this->max_blocks;
    00081   }
    00082
    00087   inline uint GetBlockCount() const
    00088   {
    00089     return this->current_blocks;
    00090   }
    00091
    00096   inline const char *GetName() const
    00097   {
    00098     return this->name;
    00099   }
    00100
    00105   inline bool CleaningPool() const
    00106   {
    00107     return this->cleaning_pool;
    00108   }
    00109 };
    00110
    00111 template <typename T>
    00112 struct OldMemoryPool : public OldMemoryPoolBase {
    00113   OldMemoryPool(const char *name, uint max_blocks, uint block_size_bits, uint item_size,
    00114         OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) :
    00115     OldMemoryPoolBase(name, max_blocks, block_size_bits, item_size, new_block_proc, clean_block_proc) {}
    00116
    00123   inline T *Get(uint index) const
    00124   {
    00125     assert(index < this->GetSize());
    00126     return (T*)(this->blocks[index >> this->block_size_bits] +
    00127         (index & ((1 << this->block_size_bits) - 1)) * this->item_size);
    00128   }
    00129 };
    00130
    00135 template <typename T, OldMemoryPool<T> *Tpool>
    00136 static void PoolNewBlock(uint start_item)
    00137 {
    00138   for (T *t = Tpool->Get(start_item); t != NULL; t = (t->index + 1U < Tpool->GetSize()) ? Tpool->Get(t->index + 1U) : NULL) {
    00139     t = new (t) T();
    00140     t->index = start_item++;
    00141   }
    00142 }
    00143
    00149 template <typename T, OldMemoryPool<T> *Tpool>
    00150 static void PoolCleanBlock(uint start_item, uint end_item)
    00151 {
    00152   for (uint i = start_item; i <= end_item; i++) {
    00153     T *t = Tpool->Get(i);
    00154     delete t;
    00155   }
    00156 }
    00157
    00158
    00163 template <typename T, typename Tid, OldMemoryPool<T> *Tpool>
    00164 struct PoolItem {
    00168   Tid index;
    00169
    00177   virtual ~PoolItem()
    00178   {
    00179
    00180   }
    00181
    00189   PoolItem()
    00190   {
    00191
    00192   }
    00193
    00199   void *operator new(size_t size)
    00200   {
    00201     return AllocateRaw();
    00202   }
    00203
    00209   void operator delete(void *p)
    00210   {
    00211     Tpool->UpdateFirstFreeIndex(((T*)p)->index);
    00212   }
    00213
    00221   void *operator new(size_t size, int index)
    00222   {
    00223     if (!Tpool->AddBlockIfNeeded(index)) error("%s: failed loading savegame: too many %s", Tpool->GetName(), Tpool->GetName());
    00224
    00225     return Tpool->Get(index);
    00226   }
    00227
    00234   void operator delete(void *p, int index)
    00235   {
    00236     Tpool->UpdateFirstFreeIndex(index);
    00237   }
    00238
    00246   void *operator new(size_t size, T *pn)
    00247   {
    00248     return pn;
    00249   }
    00250
    00257   void operator delete(void *p, T *pn)
    00258   {
    00259     Tpool->UpdateFirstFreeIndex(pn->index);
    00260   }
    00261
    00262 private:
    00269   static inline T *AllocateSafeRaw(uint &first)
    00270   {
    00271     uint last_minus_one = Tpool->GetSize() - 1;
    00272
    00273     for (T *t = Tpool->Get(first); t != NULL; t = (t->index < last_minus_one) ? Tpool->Get(t->index + 1U) : NULL) {
    00274       if (!t->IsValid()) {
    00275         first = t->index;
    00276         Tid index = t->index;
    00277
    00278         memset(t, 0, Tpool->item_size);
    00279         t->index = index;
    00280         return t;
    00281       }
    00282     }
    00283
    00284     /* Check if we can add a block to the pool */
    00285     if (Tpool->AddBlockToPool()) return AllocateRaw(first);
    00286
    00287     return NULL;
    00288   }
    00289
    00290 protected:
    00295   static inline T *AllocateRaw()
    00296   {
    00297     return AllocateSafeRaw(Tpool->first_free_index);
    00298   }
    00299
    00305   static inline T *AllocateRaw(uint &first)
    00306   {
    00307     if (first >= Tpool->GetSize() && !Tpool->AddBlockToPool()) return NULL;
    00308
    00309     return AllocateSafeRaw(first);
    00310   }
    00311
    00316   static inline bool CleaningPool()
    00317   {
    00318     return Tpool->CleaningPool();
    00319   }
    00320
    00321 public:
    00328   static inline bool CanAllocateItem()
    00329   {
    00330     uint last_minus_one = Tpool->GetSize() - 1;
    00331
    00332     for (T *t = Tpool->Get(Tpool->first_free_index); t != NULL; t = (t->index < last_minus_one) ? Tpool->Get(t->index + 1U) : NULL) {
    00333       if (!t->IsValid()) return true;
    00334       Tpool->first_free_index = t->index;
    00335     }
    00336
    00337     /* Check if we can add a block to the pool */
    00338     if (Tpool->AddBlockToPool()) return CanAllocateItem();
    00339
    00340     return false;
    00341   }
    00342 };
    00343
    00344
    00345 #define OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
    00346   enum { \
    00347     name##_POOL_BLOCK_SIZE_BITS = block_size_bits, \
    00348     name##_POOL_MAX_BLOCKS      = max_blocks \
    00349   };
    00350
    00351
    00352 #define OLD_POOL_ACCESSORS(name, type) \
    00353   static inline type* Get##name(uint index) { return _##name##_pool.Get(index);  } \
    00354   static inline uint Get##name##PoolSize()  { return _##name##_pool.GetSize(); }
    00355
    00356
    00357 #define DECLARE_OLD_POOL(name, type, block_size_bits, max_blocks) \
    00358   OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
    00359   extern OldMemoryPool<type> _##name##_pool; \
    00360   OLD_POOL_ACCESSORS(name, type)
    00361
    00362
    00363 #define DEFINE_OLD_POOL(name, type, new_block_proc, clean_block_proc) \
    00364   OldMemoryPool<type> _##name##_pool( \
    00365     #name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \
    00366     new_block_proc, clean_block_proc);
    00367
    00368 #define DEFINE_OLD_POOL_GENERIC(name, type) \
    00369   OldMemoryPool<type> _##name##_pool( \
    00370     #name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \
    00371     PoolNewBlock<type, &_##name##_pool>, PoolCleanBlock<type, &_##name##_pool>);
    00372
    00373
    00374 #define STATIC_OLD_POOL(name, type, block_size_bits, max_blocks, new_block_proc, clean_block_proc) \
    00375   OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
    00376   static DEFINE_OLD_POOL(name, type, new_block_proc, clean_block_proc) \
    00377   OLD_POOL_ACCESSORS(name, type)
    00378
    00379 #endif /* OLDPOOL_H */