tron@2186: /* $Id$ */ tron@2186: rubidium@9111: /** @file oldpool.h Base for the old pool. */ belugas@6351: matthijs@5224: #ifndef OLDPOOL_H matthijs@5224: #define OLDPOOL_H truelight@1259: rubidium@8113: #include "core/math_func.hpp" rubidium@8113: 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@7375: struct OldMemoryPoolBase { rubidium@7375: void CleanPool(); rubidium@7375: bool AddBlockToPool(); rubidium@7375: bool AddBlockIfNeeded(uint index); rubidium@7375: rubidium@7375: protected: rubidium@7375: OldMemoryPoolBase(const char *name, uint max_blocks, uint block_size_bits, uint item_size, rubidium@7375: OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) : rubidium@7385: name(name), max_blocks(max_blocks), block_size_bits(block_size_bits), rubidium@7375: new_block_proc(new_block_proc), clean_block_proc(clean_block_proc), current_blocks(0), rubidium@7413: total_items(0), cleaning_pool(false), item_size(item_size), first_free_index(0), blocks(NULL) {} rubidium@7375: rubidium@5587: const char* name; ///< Name of the pool (just for debugging) truelight@1259: rubidium@7377: const uint max_blocks; ///< The max amount of blocks this pool can have rubidium@7377: 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@7383: OldMemoryPoolNewBlock *new_block_proc; peter1138@3585: /// Pointer to a function that is called to clean a block rubidium@7383: 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@7413: bool cleaning_pool; ///< Are we currently cleaning the pool? rubidium@7375: public: rubidium@7385: const uint item_size; ///< How many bytes one block is rubidium@7378: 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@7375: rubidium@7377: /** smatz@7974: * Check if the index of pool item being deleted is lower than cached first_free_index smatz@7974: * @param index index of pool item smatz@7974: * @note usage of min() will result in better code on some architectures smatz@7974: */ smatz@7974: inline void UpdateFirstFreeIndex(uint index) smatz@7974: { smatz@7974: first_free_index = min(first_free_index, index); smatz@7974: } smatz@7974: smatz@7974: /** rubidium@7377: * Get the size of this pool, i.e. the total number of items you rubidium@7377: * can put into it at the current moment; the pool might still rubidium@7377: * be able to increase the size of the pool. rubidium@7377: * @return the size of the pool rubidium@7377: */ rubidium@7377: inline uint GetSize() const rubidium@7375: { rubidium@7375: return this->total_items; rubidium@7375: } rubidium@7375: rubidium@7377: /** rubidium@7377: * Can this pool allocate more blocks, i.e. is the maximum amount rubidium@7377: * of allocated blocks not yet reached? rubidium@7377: * @return the if and only if the amount of allocable blocks is rubidium@7377: * less than the amount of allocated blocks. rubidium@7377: */ rubidium@7377: inline bool CanAllocateMoreBlocks() const rubidium@7375: { rubidium@7375: return this->current_blocks < this->max_blocks; rubidium@7375: } rubidium@7375: rubidium@7377: /** rubidium@7377: * Get the maximum number of allocable blocks. rubidium@7377: * @return the numebr of blocks rubidium@7377: */ rubidium@7377: inline uint GetBlockCount() const rubidium@7375: { rubidium@7375: return this->current_blocks; rubidium@7375: } rubidium@7377: rubidium@7377: /** rubidium@7377: * Get the name of this pool. rubidium@7377: * @return the name rubidium@7377: */ rubidium@7377: inline const char *GetName() const rubidium@7377: { rubidium@7377: return this->name; rubidium@7377: } rubidium@7413: rubidium@7413: /** rubidium@7413: * Is the pool in the cleaning phase? rubidium@7413: * @return true if it is rubidium@7413: */ rubidium@7413: inline bool CleaningPool() const rubidium@7413: { rubidium@7413: return this->cleaning_pool; rubidium@7413: } rubidium@7375: }; rubidium@7375: rubidium@7375: template rubidium@7375: struct OldMemoryPool : public OldMemoryPoolBase { rubidium@7375: OldMemoryPool(const char *name, uint max_blocks, uint block_size_bits, uint item_size, rubidium@7375: OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) : rubidium@7375: OldMemoryPoolBase(name, max_blocks, block_size_bits, item_size, new_block_proc, clean_block_proc) {} rubidium@7375: rubidium@7377: /** rubidium@7377: * Get the pool entry at the given index. rubidium@7377: * @param index the index into the pool rubidium@7377: * @pre index < this->GetSize() rubidium@7377: * @return the pool entry. rubidium@7377: */ rubidium@7377: inline T *Get(uint index) const rubidium@7375: { rubidium@7375: assert(index < this->GetSize()); rubidium@7375: return (T*)(this->blocks[index >> this->block_size_bits] + rubidium@7385: (index & ((1 << this->block_size_bits) - 1)) * this->item_size); rubidium@7375: } truelight@1259: }; truelight@1259: truelight@1259: /** rubidium@7376: * Generic function to initialize a new block in a pool. rubidium@7376: * @param start_item the first item that needs to be initialized rubidium@7376: */ rubidium@7376: template *Tpool> rubidium@7376: static void PoolNewBlock(uint start_item) rubidium@7376: { rubidium@7376: for (T *t = Tpool->Get(start_item); t != NULL; t = (t->index + 1U < Tpool->GetSize()) ? Tpool->Get(t->index + 1U) : NULL) { rubidium@7377: t = new (t) T(); rubidium@7376: t->index = start_item++; rubidium@7376: } rubidium@7376: } rubidium@7376: rubidium@7376: /** rubidium@7376: * Generic function to free a new block in a pool. rubidium@7376: * @param start_item the first item that needs to be cleaned rubidium@7376: * @param end_item the last item that needs to be cleaned rubidium@7376: */ rubidium@7376: template *Tpool> rubidium@7376: static void PoolCleanBlock(uint start_item, uint end_item) rubidium@7376: { rubidium@7376: for (uint i = start_item; i <= end_item; i++) { rubidium@7376: T *t = Tpool->Get(i); rubidium@7413: delete t; rubidium@7376: } rubidium@7376: } rubidium@7376: rubidium@7376: rubidium@7377: /** rubidium@7377: * Generalization for all pool items that are saved in the savegame. rubidium@7377: * It specifies all the mechanics to access the pool easily. rubidium@7377: */ rubidium@7377: template *Tpool> rubidium@7377: struct PoolItem { rubidium@7377: /** rubidium@7377: * The pool-wide index of this object. rubidium@7377: */ rubidium@7377: Tid index; rubidium@7377: rubidium@7377: /** rubidium@7377: * We like to have the correct class destructed. smatz@7974: * @warning It is called even for object allocated on stack, smatz@7974: * so it is not present in the TPool! smatz@7974: * Then, index is undefined, not associated with TPool in any way. smatz@7974: * @note The idea is to free up allocated memory etc. rubidium@7377: */ rubidium@7377: virtual ~PoolItem() rubidium@7377: { smatz@7974: smatz@7974: } smatz@7974: smatz@7974: /** smatz@7974: * Constructor of given class. smatz@7974: * @warning It is called even for object allocated on stack, smatz@7974: * so it may not be present in TPool! smatz@7974: * Then, index is undefined, not associated with TPool in any way. smatz@7974: * @note The idea is to initialize variables (except index) smatz@7974: */ smatz@7974: PoolItem() smatz@7974: { smatz@7974: rubidium@7377: } rubidium@7377: rubidium@7377: /** rubidium@7377: * An overriden version of new that allocates memory on the pool. rubidium@7377: * @param size the size of the variable (unused) rubidium@7377: * @return the memory that is 'allocated' rubidium@7377: */ rubidium@7381: void *operator new(size_t size) rubidium@7377: { rubidium@7377: return AllocateRaw(); rubidium@7377: } rubidium@7377: rubidium@7377: /** rubidium@7377: * 'Free' the memory allocated by the overriden new. rubidium@7377: * @param p the memory to 'free' smatz@7974: * @note we only update Tpool->first_free_index rubidium@7377: */ rubidium@7377: void operator delete(void *p) rubidium@7377: { smatz@7974: Tpool->UpdateFirstFreeIndex(((T*)p)->index); rubidium@7377: } rubidium@7377: rubidium@7377: /** rubidium@7377: * An overriden version of new, so you can directly allocate a new object with rubidium@7377: * the correct index when one is loading the savegame. rubidium@7377: * @param size the size of the variable (unused) rubidium@7377: * @param index the index of the object rubidium@7377: * @return the memory that is 'allocated' rubidium@7377: */ rubidium@7381: void *operator new(size_t size, int index) rubidium@7377: { rubidium@7377: if (!Tpool->AddBlockIfNeeded(index)) error("%s: failed loading savegame: too many %s", Tpool->GetName(), Tpool->GetName()); rubidium@7377: rubidium@7377: return Tpool->Get(index); rubidium@7377: } rubidium@7377: rubidium@7377: /** rubidium@7377: * 'Free' the memory allocated by the overriden new. rubidium@7377: * @param p the memory to 'free' rubidium@7377: * @param index the original parameter given to create the memory smatz@7974: * @note we only update Tpool->first_free_index rubidium@7377: */ rubidium@7377: void operator delete(void *p, int index) rubidium@7377: { smatz@7974: Tpool->UpdateFirstFreeIndex(index); rubidium@7377: } rubidium@7377: rubidium@7377: /** rubidium@7377: * An overriden version of new, so you can use the vehicle instance rubidium@7377: * instead of a newly allocated piece of memory. rubidium@7377: * @param size the size of the variable (unused) rubidium@7377: * @param pn the already existing object to use as 'storage' backend rubidium@7377: * @return the memory that is 'allocated' rubidium@7377: */ rubidium@7377: void *operator new(size_t size, T *pn) rubidium@7377: { rubidium@7377: return pn; rubidium@7377: } rubidium@7377: rubidium@7377: /** rubidium@7377: * 'Free' the memory allocated by the overriden new. rubidium@7377: * @param p the memory to 'free' rubidium@7377: * @param pn the pointer that was given to 'new' on creation. smatz@7974: * @note we only update Tpool->first_free_index rubidium@7377: */ rubidium@7377: void operator delete(void *p, T *pn) rubidium@7377: { smatz@7974: Tpool->UpdateFirstFreeIndex(pn->index); rubidium@7377: } rubidium@7377: rubidium@7426: private: smatz@8847: static T *AllocateSafeRaw(uint &first); rubidium@7413: rubidium@7426: protected: rubidium@7426: /** rubidium@7426: * Allocate a pool item; possibly allocate a new block in the pool. rubidium@7426: * @return the allocated pool item (or NULL when the pool is full). rubidium@7426: */ rubidium@7426: static inline T *AllocateRaw() rubidium@7426: { rubidium@7426: return AllocateSafeRaw(Tpool->first_free_index); rubidium@7426: } rubidium@7426: rubidium@7426: /** rubidium@7426: * Allocate a pool item; possibly allocate a new block in the pool. rubidium@7426: * @param first the first pool item to start searching rubidium@7426: * @return the allocated pool item (or NULL when the pool is full). rubidium@7426: */ rubidium@7426: static inline T *AllocateRaw(uint &first) rubidium@7426: { rubidium@7426: if (first >= Tpool->GetSize() && !Tpool->AddBlockToPool()) return NULL; rubidium@7426: rubidium@7426: return AllocateSafeRaw(first); rubidium@7426: } rubidium@7426: rubidium@7413: /** rubidium@7413: * Are we cleaning this pool? rubidium@7413: * @return true if we are rubidium@7413: */ rubidium@7413: static inline bool CleaningPool() rubidium@7413: { rubidium@7413: return Tpool->CleaningPool(); rubidium@7413: } rubidium@9036: rubidium@9036: public: rubidium@9038: static bool CanAllocateItem(); rubidium@7377: }; rubidium@7377: rubidium@7376: 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@7375: static inline type* Get##name(uint index) { return _##name##_pool.Get(index); } \ rubidium@7375: 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@7375: 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@7375: OldMemoryPool _##name##_pool( \ tron@4970: #name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \ rubidium@7375: new_block_proc, clean_block_proc); tron@4970: rubidium@7376: #define DEFINE_OLD_POOL_GENERIC(name, type) \ rubidium@7376: OldMemoryPool _##name##_pool( \ rubidium@7376: #name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \ smatz@8847: PoolNewBlock, PoolCleanBlock); \ smatz@8847: template type *PoolItem::AllocateSafeRaw(uint &first); rubidium@7376: 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 */