tron@2186: /* $Id$ */ tron@2186: belugas@6677: /** @file oldpool.h */ belugas@6677: matthijs@5224: #ifndef OLDPOOL_H matthijs@5224: #define OLDPOOL_H truelight@1259: rubidium@8609: #include "core/math_func.hpp" rubidium@8609: truelight@1259: /* The function that is called after a new block is added truelight@1259: start_item is the first item of the new made block */ matthijs@5216: typedef void OldMemoryPoolNewBlock(uint start_item); peter1138@3585: /* The function that is called before a block is cleaned up */ matthijs@5216: typedef void OldMemoryPoolCleanBlock(uint start_item, uint end_item); truelight@1259: truelight@1259: /** matthijs@5216: * Stuff for dynamic vehicles. Use the wrappers to access the OldMemoryPool truelight@1259: * please try to avoid manual calls! truelight@1259: */ rubidium@7871: struct OldMemoryPoolBase { rubidium@7871: void CleanPool(); rubidium@7871: bool AddBlockToPool(); rubidium@7871: bool AddBlockIfNeeded(uint index); rubidium@7871: rubidium@7871: protected: rubidium@7871: OldMemoryPoolBase(const char *name, uint max_blocks, uint block_size_bits, uint item_size, rubidium@7871: OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) : rubidium@7881: name(name), max_blocks(max_blocks), block_size_bits(block_size_bits), rubidium@7871: new_block_proc(new_block_proc), clean_block_proc(clean_block_proc), current_blocks(0), rubidium@7909: total_items(0), cleaning_pool(false), item_size(item_size), first_free_index(0), blocks(NULL) {} rubidium@7871: rubidium@5838: const char* name; ///< Name of the pool (just for debugging) truelight@1259: rubidium@7873: const uint max_blocks; ///< The max amount of blocks this pool can have rubidium@7873: const uint block_size_bits; ///< The size of each block in bits truelight@1259: peter1138@3173: /// Pointer to a function that is called after a new block is added rubidium@7879: OldMemoryPoolNewBlock *new_block_proc; peter1138@3585: /// Pointer to a function that is called to clean a block rubidium@7879: OldMemoryPoolCleanBlock *clean_block_proc; truelight@1259: peter1138@3173: uint current_blocks; ///< How many blocks we have in our pool peter1138@3173: uint total_items; ///< How many items we now have in this pool peter1138@3173: rubidium@7909: bool cleaning_pool; ///< Are we currently cleaning the pool? rubidium@7871: public: rubidium@7881: const uint item_size; ///< How many bytes one block is rubidium@7874: uint first_free_index; ///< The index of the first free pool item in this pool peter1138@3173: byte **blocks; ///< An array of blocks (one block hold all the items) rubidium@7871: rubidium@7873: /** smatz@8470: * Check if the index of pool item being deleted is lower than cached first_free_index smatz@8470: * @param index index of pool item smatz@8470: * @note usage of min() will result in better code on some architectures smatz@8470: */ smatz@8470: inline void UpdateFirstFreeIndex(uint index) smatz@8470: { smatz@8470: first_free_index = min(first_free_index, index); smatz@8470: } smatz@8470: smatz@8470: /** rubidium@7873: * Get the size of this pool, i.e. the total number of items you rubidium@7873: * can put into it at the current moment; the pool might still rubidium@7873: * be able to increase the size of the pool. rubidium@7873: * @return the size of the pool rubidium@7873: */ rubidium@7873: inline uint GetSize() const rubidium@7871: { rubidium@7871: return this->total_items; rubidium@7871: } rubidium@7871: rubidium@7873: /** rubidium@7873: * Can this pool allocate more blocks, i.e. is the maximum amount rubidium@7873: * of allocated blocks not yet reached? rubidium@7873: * @return the if and only if the amount of allocable blocks is rubidium@7873: * less than the amount of allocated blocks. rubidium@7873: */ rubidium@7873: inline bool CanAllocateMoreBlocks() const rubidium@7871: { rubidium@7871: return this->current_blocks < this->max_blocks; rubidium@7871: } rubidium@7871: rubidium@7873: /** rubidium@7873: * Get the maximum number of allocable blocks. rubidium@7873: * @return the numebr of blocks rubidium@7873: */ rubidium@7873: inline uint GetBlockCount() const rubidium@7871: { rubidium@7871: return this->current_blocks; rubidium@7871: } rubidium@7873: rubidium@7873: /** rubidium@7873: * Get the name of this pool. rubidium@7873: * @return the name rubidium@7873: */ rubidium@7873: inline const char *GetName() const rubidium@7873: { rubidium@7873: return this->name; rubidium@7873: } rubidium@7909: rubidium@7909: /** rubidium@7909: * Is the pool in the cleaning phase? rubidium@7909: * @return true if it is rubidium@7909: */ rubidium@7909: inline bool CleaningPool() const rubidium@7909: { rubidium@7909: return this->cleaning_pool; rubidium@7909: } rubidium@7871: }; rubidium@7871: rubidium@7871: template rubidium@7871: struct OldMemoryPool : public OldMemoryPoolBase { rubidium@7871: OldMemoryPool(const char *name, uint max_blocks, uint block_size_bits, uint item_size, rubidium@7871: OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) : rubidium@7871: OldMemoryPoolBase(name, max_blocks, block_size_bits, item_size, new_block_proc, clean_block_proc) {} rubidium@7871: rubidium@7873: /** rubidium@7873: * Get the pool entry at the given index. rubidium@7873: * @param index the index into the pool rubidium@7873: * @pre index < this->GetSize() rubidium@7873: * @return the pool entry. rubidium@7873: */ rubidium@7873: inline T *Get(uint index) const rubidium@7871: { rubidium@7871: assert(index < this->GetSize()); rubidium@7871: return (T*)(this->blocks[index >> this->block_size_bits] + rubidium@7881: (index & ((1 << this->block_size_bits) - 1)) * this->item_size); rubidium@7871: } truelight@1259: }; truelight@1259: truelight@1259: /** rubidium@7872: * Generic function to initialize a new block in a pool. rubidium@7872: * @param start_item the first item that needs to be initialized rubidium@7872: */ rubidium@7872: template *Tpool> rubidium@7872: static void PoolNewBlock(uint start_item) rubidium@7872: { rubidium@7872: for (T *t = Tpool->Get(start_item); t != NULL; t = (t->index + 1U < Tpool->GetSize()) ? Tpool->Get(t->index + 1U) : NULL) { rubidium@7873: t = new (t) T(); rubidium@7872: t->index = start_item++; rubidium@7872: } rubidium@7872: } rubidium@7872: rubidium@7872: /** rubidium@7872: * Generic function to free a new block in a pool. rubidium@7872: * @param start_item the first item that needs to be cleaned rubidium@7872: * @param end_item the last item that needs to be cleaned rubidium@7872: */ rubidium@7872: template *Tpool> rubidium@7872: static void PoolCleanBlock(uint start_item, uint end_item) rubidium@7872: { rubidium@7872: for (uint i = start_item; i <= end_item; i++) { rubidium@7872: T *t = Tpool->Get(i); rubidium@7909: delete t; rubidium@7872: } rubidium@7872: } rubidium@7872: rubidium@7872: rubidium@7873: /** rubidium@7873: * Generalization for all pool items that are saved in the savegame. rubidium@7873: * It specifies all the mechanics to access the pool easily. rubidium@7873: */ rubidium@7873: template *Tpool> rubidium@7873: struct PoolItem { rubidium@7873: /** rubidium@7873: * The pool-wide index of this object. rubidium@7873: */ rubidium@7873: Tid index; rubidium@7873: rubidium@7873: /** rubidium@7873: * We like to have the correct class destructed. smatz@8470: * @warning It is called even for object allocated on stack, smatz@8470: * so it is not present in the TPool! smatz@8470: * Then, index is undefined, not associated with TPool in any way. smatz@8470: * @note The idea is to free up allocated memory etc. rubidium@7873: */ rubidium@7873: virtual ~PoolItem() rubidium@7873: { smatz@8470: smatz@8470: } smatz@8470: smatz@8470: /** smatz@8470: * Constructor of given class. smatz@8470: * @warning It is called even for object allocated on stack, smatz@8470: * so it may not be present in TPool! smatz@8470: * Then, index is undefined, not associated with TPool in any way. smatz@8470: * @note The idea is to initialize variables (except index) smatz@8470: */ smatz@8470: PoolItem() smatz@8470: { smatz@8470: rubidium@7873: } rubidium@7873: rubidium@7873: /** rubidium@7873: * An overriden version of new that allocates memory on the pool. rubidium@7873: * @param size the size of the variable (unused) rubidium@7873: * @return the memory that is 'allocated' rubidium@7873: */ rubidium@7877: void *operator new(size_t size) rubidium@7873: { rubidium@7873: return AllocateRaw(); rubidium@7873: } rubidium@7873: rubidium@7873: /** rubidium@7873: * 'Free' the memory allocated by the overriden new. rubidium@7873: * @param p the memory to 'free' smatz@8470: * @note we only update Tpool->first_free_index rubidium@7873: */ rubidium@7873: void operator delete(void *p) rubidium@7873: { smatz@8470: Tpool->UpdateFirstFreeIndex(((T*)p)->index); rubidium@7873: } rubidium@7873: rubidium@7873: /** rubidium@7873: * An overriden version of new, so you can directly allocate a new object with rubidium@7873: * the correct index when one is loading the savegame. rubidium@7873: * @param size the size of the variable (unused) rubidium@7873: * @param index the index of the object rubidium@7873: * @return the memory that is 'allocated' rubidium@7873: */ rubidium@7877: void *operator new(size_t size, int index) rubidium@7873: { rubidium@7873: if (!Tpool->AddBlockIfNeeded(index)) error("%s: failed loading savegame: too many %s", Tpool->GetName(), Tpool->GetName()); rubidium@7873: rubidium@7873: return Tpool->Get(index); rubidium@7873: } rubidium@7873: rubidium@7873: /** rubidium@7873: * 'Free' the memory allocated by the overriden new. rubidium@7873: * @param p the memory to 'free' rubidium@7873: * @param index the original parameter given to create the memory smatz@8470: * @note we only update Tpool->first_free_index rubidium@7873: */ rubidium@7873: void operator delete(void *p, int index) rubidium@7873: { smatz@8470: Tpool->UpdateFirstFreeIndex(index); rubidium@7873: } rubidium@7873: rubidium@7873: /** rubidium@7873: * An overriden version of new, so you can use the vehicle instance rubidium@7873: * instead of a newly allocated piece of memory. rubidium@7873: * @param size the size of the variable (unused) rubidium@7873: * @param pn the already existing object to use as 'storage' backend rubidium@7873: * @return the memory that is 'allocated' rubidium@7873: */ rubidium@7873: void *operator new(size_t size, T *pn) rubidium@7873: { rubidium@7873: return pn; rubidium@7873: } rubidium@7873: rubidium@7873: /** rubidium@7873: * 'Free' the memory allocated by the overriden new. rubidium@7873: * @param p the memory to 'free' rubidium@7873: * @param pn the pointer that was given to 'new' on creation. smatz@8470: * @note we only update Tpool->first_free_index rubidium@7873: */ rubidium@7873: void operator delete(void *p, T *pn) rubidium@7873: { smatz@8470: Tpool->UpdateFirstFreeIndex(pn->index); rubidium@7873: } rubidium@7873: rubidium@7922: private: smatz@9343: static T *AllocateSafeRaw(uint &first); rubidium@7909: rubidium@7922: protected: rubidium@7922: /** rubidium@7922: * Allocate a pool item; possibly allocate a new block in the pool. rubidium@7922: * @return the allocated pool item (or NULL when the pool is full). rubidium@7922: */ rubidium@7922: static inline T *AllocateRaw() rubidium@7922: { rubidium@7922: return AllocateSafeRaw(Tpool->first_free_index); rubidium@7922: } rubidium@7922: rubidium@7922: /** rubidium@7922: * Allocate a pool item; possibly allocate a new block in the pool. rubidium@7922: * @param first the first pool item to start searching rubidium@7922: * @return the allocated pool item (or NULL when the pool is full). rubidium@7922: */ rubidium@7922: static inline T *AllocateRaw(uint &first) rubidium@7922: { rubidium@7922: if (first >= Tpool->GetSize() && !Tpool->AddBlockToPool()) return NULL; rubidium@7922: rubidium@7922: return AllocateSafeRaw(first); rubidium@7922: } rubidium@7922: rubidium@7909: /** rubidium@7909: * Are we cleaning this pool? rubidium@7909: * @return true if we are rubidium@7909: */ rubidium@7909: static inline bool CleaningPool() rubidium@7909: { rubidium@7909: return Tpool->CleaningPool(); rubidium@7909: } rubidium@10314: rubidium@10314: public: rubidium@10314: /** rubidium@10314: * Check whether we can allocate an item in this pool. This to prevent the rubidium@10314: * need to actually construct the object and then destructing it again, rubidium@10314: * which could be *very* costly. rubidium@10314: * @return true if and only if at least ONE item can be allocated. rubidium@10314: */ rubidium@10314: static inline bool CanAllocateItem() rubidium@10314: { rubidium@10314: return AllocateRaw() != NULL; rubidium@10314: } rubidium@7873: }; rubidium@7873: rubidium@7872: matthijs@5216: #define OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \ tron@4970: enum { \ tron@4970: name##_POOL_BLOCK_SIZE_BITS = block_size_bits, \ tron@4970: name##_POOL_MAX_BLOCKS = max_blocks \ tron@4970: }; tron@4970: tron@4970: matthijs@5216: #define OLD_POOL_ACCESSORS(name, type) \ rubidium@7871: static inline type* Get##name(uint index) { return _##name##_pool.Get(index); } \ rubidium@7871: static inline uint Get##name##PoolSize() { return _##name##_pool.GetSize(); } tron@4970: tron@4970: matthijs@5216: #define DECLARE_OLD_POOL(name, type, block_size_bits, max_blocks) \ matthijs@5216: OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \ rubidium@7871: extern OldMemoryPool _##name##_pool; \ matthijs@5216: OLD_POOL_ACCESSORS(name, type) tron@4970: tron@4970: matthijs@5216: #define DEFINE_OLD_POOL(name, type, new_block_proc, clean_block_proc) \ rubidium@7871: OldMemoryPool _##name##_pool( \ tron@4970: #name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \ rubidium@7871: new_block_proc, clean_block_proc); tron@4970: rubidium@7872: #define DEFINE_OLD_POOL_GENERIC(name, type) \ rubidium@7872: OldMemoryPool _##name##_pool( \ rubidium@7872: #name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \ smatz@9343: PoolNewBlock, PoolCleanBlock); \ smatz@9343: template type *PoolItem::AllocateSafeRaw(uint &first); rubidium@7872: tron@4970: matthijs@5216: #define STATIC_OLD_POOL(name, type, block_size_bits, max_blocks, new_block_proc, clean_block_proc) \ matthijs@5216: OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \ matthijs@5216: static DEFINE_OLD_POOL(name, type, new_block_proc, clean_block_proc) \ matthijs@5216: OLD_POOL_ACCESSORS(name, type) tron@4970: matthijs@5224: #endif /* OLDPOOL_H */