src/oldpool.h
branchnoai
changeset 9694 e72987579514
parent 9505 9711235f5693
child 9701 d1ac22c62f64
equal deleted inserted replaced
9693:31fcaa5375a1 9694:e72987579514
     2 
     2 
     3 /** @file oldpool.h */
     3 /** @file oldpool.h */
     4 
     4 
     5 #ifndef OLDPOOL_H
     5 #ifndef OLDPOOL_H
     6 #define OLDPOOL_H
     6 #define OLDPOOL_H
     7 
       
     8 struct OldMemoryPool;
       
     9 
     7 
    10 /* The function that is called after a new block is added
     8 /* The function that is called after a new block is added
    11      start_item is the first item of the new made block */
     9      start_item is the first item of the new made block */
    12 typedef void OldMemoryPoolNewBlock(uint start_item);
    10 typedef void OldMemoryPoolNewBlock(uint start_item);
    13 /* The function that is called before a block is cleaned up */
    11 /* The function that is called before a block is cleaned up */
    15 
    13 
    16 /**
    14 /**
    17  * Stuff for dynamic vehicles. Use the wrappers to access the OldMemoryPool
    15  * Stuff for dynamic vehicles. Use the wrappers to access the OldMemoryPool
    18  *  please try to avoid manual calls!
    16  *  please try to avoid manual calls!
    19  */
    17  */
    20 struct OldMemoryPool {
    18 struct OldMemoryPoolBase {
       
    19 	void CleanPool();
       
    20 	bool AddBlockToPool();
       
    21 	bool AddBlockIfNeeded(uint index);
       
    22 
       
    23 protected:
       
    24 	OldMemoryPoolBase(const char *name, uint max_blocks, uint block_size_bits, uint item_size,
       
    25 				OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) :
       
    26 		name(name), max_blocks(max_blocks), block_size_bits(block_size_bits),
       
    27 		new_block_proc(new_block_proc), clean_block_proc(clean_block_proc), current_blocks(0),
       
    28 		total_items(0), item_size(item_size), first_free_index(0), blocks(NULL) {}
       
    29 
    21 	const char* name;     ///< Name of the pool (just for debugging)
    30 	const char* name;     ///< Name of the pool (just for debugging)
    22 
    31 
    23 	uint max_blocks;      ///< The max amount of blocks this pool can have
    32 	const uint max_blocks;      ///< The max amount of blocks this pool can have
    24 	uint block_size_bits; ///< The size of each block in bits
    33 	const uint block_size_bits; ///< The size of each block in bits
    25 	uint item_size;       ///< How many bytes one block is
       
    26 
    34 
    27 	/// Pointer to a function that is called after a new block is added
    35 	/// Pointer to a function that is called after a new block is added
    28 	OldMemoryPoolNewBlock *new_block_proc;
    36 	OldMemoryPoolNewBlock *new_block_proc;
    29 	/// Pointer to a function that is called to clean a block
    37 	/// Pointer to a function that is called to clean a block
    30 	OldMemoryPoolCleanBlock *clean_block_proc;
    38 	OldMemoryPoolCleanBlock *clean_block_proc;
    31 
    39 
    32 	uint current_blocks;        ///< How many blocks we have in our pool
    40 	uint current_blocks;        ///< How many blocks we have in our pool
    33 	uint total_items;           ///< How many items we now have in this pool
    41 	uint total_items;           ///< How many items we now have in this pool
    34 
    42 
       
    43 public:
       
    44 	const uint item_size;       ///< How many bytes one block is
       
    45 	uint first_free_index;      ///< The index of the first free pool item in this pool
    35 	byte **blocks;              ///< An array of blocks (one block hold all the items)
    46 	byte **blocks;              ///< An array of blocks (one block hold all the items)
       
    47 
       
    48 	/**
       
    49 	 * Get the size of this pool, i.e. the total number of items you
       
    50 	 * can put into it at the current moment; the pool might still
       
    51 	 * be able to increase the size of the pool.
       
    52 	 * @return the size of the pool
       
    53 	 */
       
    54 	inline uint GetSize() const
       
    55 	{
       
    56 		return this->total_items;
       
    57 	}
       
    58 
       
    59 	/**
       
    60 	 * Can this pool allocate more blocks, i.e. is the maximum amount
       
    61 	 * of allocated blocks not yet reached?
       
    62 	 * @return the if and only if the amount of allocable blocks is
       
    63 	 *         less than the amount of allocated blocks.
       
    64 	 */
       
    65 	inline bool CanAllocateMoreBlocks() const
       
    66 	{
       
    67 		return this->current_blocks < this->max_blocks;
       
    68 	}
       
    69 
       
    70 	/**
       
    71 	 * Get the maximum number of allocable blocks.
       
    72 	 * @return the numebr of blocks
       
    73 	 */
       
    74 	inline uint GetBlockCount() const
       
    75 	{
       
    76 		return this->current_blocks;
       
    77 	}
       
    78 
       
    79 	/**
       
    80 	 * Get the name of this pool.
       
    81 	 * @return the name
       
    82 	 */
       
    83 	inline const char *GetName() const
       
    84 	{
       
    85 		return this->name;
       
    86 	}
    36 };
    87 };
    37 
    88 
       
    89 template <typename T>
       
    90 struct OldMemoryPool : public OldMemoryPoolBase {
       
    91 	OldMemoryPool(const char *name, uint max_blocks, uint block_size_bits, uint item_size,
       
    92 				OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) :
       
    93 		OldMemoryPoolBase(name, max_blocks, block_size_bits, item_size, new_block_proc, clean_block_proc) {}
       
    94 
       
    95 	/**
       
    96 	 * Get the pool entry at the given index.
       
    97 	 * @param index the index into the pool
       
    98 	 * @pre index < this->GetSize()
       
    99 	 * @return the pool entry.
       
   100 	 */
       
   101 	inline T *Get(uint index) const
       
   102 	{
       
   103 		assert(index < this->GetSize());
       
   104 		return (T*)(this->blocks[index >> this->block_size_bits] +
       
   105 				(index & ((1 << this->block_size_bits) - 1)) * this->item_size);
       
   106 	}
       
   107 };
       
   108 
    38 /**
   109 /**
    39  * Those are the wrappers:
   110  * Generic function to initialize a new block in a pool.
    40  *   CleanPool cleans the pool up, but you can use AddBlockToPool directly again
   111  * @param start_item the first item that needs to be initialized
    41  *     (no need to call CreatePool!)
       
    42  *   AddBlockToPool adds 1 more block to the pool. Returns false if there is no
       
    43  *     more room
       
    44  */
   112  */
    45 void CleanPool(OldMemoryPool *array);
   113 template <typename T, OldMemoryPool<T> *Tpool>
    46 bool AddBlockToPool(OldMemoryPool *array);
   114 static void PoolNewBlock(uint start_item)
       
   115 {
       
   116 	for (T *t = Tpool->Get(start_item); t != NULL; t = (t->index + 1U < Tpool->GetSize()) ? Tpool->Get(t->index + 1U) : NULL) {
       
   117 		t = new (t) T();
       
   118 		t->index = start_item++;
       
   119 	}
       
   120 }
    47 
   121 
    48 /**
   122 /**
    49  * Adds blocks to the pool if needed (and possible) till index fits inside the pool
   123  * Generic function to free a new block in a pool.
    50  *
   124  * This function uses QuickFree that is intended to only free memory that would be lost if the pool is freed.
    51  * @return Returns false if adding failed
   125  * @param start_item the first item that needs to be cleaned
       
   126  * @param end_item   the last item that needs to be cleaned
    52  */
   127  */
    53 bool AddBlockIfNeeded(OldMemoryPool *array, uint index);
   128 template <typename T, OldMemoryPool<T> *Tpool>
       
   129 static void PoolCleanBlock(uint start_item, uint end_item)
       
   130 {
       
   131 	for (uint i = start_item; i <= end_item; i++) {
       
   132 		T *t = Tpool->Get(i);
       
   133 		if (t->IsValid()) {
       
   134 			t->QuickFree();
       
   135 		}
       
   136 	}
       
   137 }
       
   138 
       
   139 
       
   140 /**
       
   141  * Generalization for all pool items that are saved in the savegame.
       
   142  * It specifies all the mechanics to access the pool easily.
       
   143  */
       
   144 template <typename T, typename Tid, OldMemoryPool<T> *Tpool>
       
   145 struct PoolItem {
       
   146 	/**
       
   147 	 * The pool-wide index of this object.
       
   148 	 */
       
   149 	Tid index;
       
   150 
       
   151 	/**
       
   152 	 * We like to have the correct class destructed.
       
   153 	 */
       
   154 	virtual ~PoolItem()
       
   155 	{
       
   156 		if (this->index < Tpool->first_free_index) Tpool->first_free_index = this->index;
       
   157 	}
       
   158 
       
   159 	/**
       
   160 	 * Called on each object when the pool is being destroyed, so one
       
   161 	 * can free allocated memory without the need for freeing for
       
   162 	 * example orders.
       
   163 	 */
       
   164 	virtual void QuickFree()
       
   165 	{
       
   166 	}
       
   167 
       
   168 	/**
       
   169 	 * An overriden version of new that allocates memory on the pool.
       
   170 	 * @param size the size of the variable (unused)
       
   171 	 * @return the memory that is 'allocated'
       
   172 	 */
       
   173 	void *operator new(size_t size)
       
   174 	{
       
   175 		return AllocateRaw();
       
   176 	}
       
   177 
       
   178 	/**
       
   179 	 * 'Free' the memory allocated by the overriden new.
       
   180 	 * @param p the memory to 'free'
       
   181 	 */
       
   182 	void operator delete(void *p)
       
   183 	{
       
   184 	}
       
   185 
       
   186 	/**
       
   187 	 * An overriden version of new, so you can directly allocate a new object with
       
   188 	 * the correct index when one is loading the savegame.
       
   189 	 * @param size  the size of the variable (unused)
       
   190 	 * @param index the index of the object
       
   191 	 * @return the memory that is 'allocated'
       
   192 	 */
       
   193 	void *operator new(size_t size, int index)
       
   194 	{
       
   195 		if (!Tpool->AddBlockIfNeeded(index)) error("%s: failed loading savegame: too many %s", Tpool->GetName(), Tpool->GetName());
       
   196 
       
   197 		return Tpool->Get(index);
       
   198 	}
       
   199 
       
   200 	/**
       
   201 	 * 'Free' the memory allocated by the overriden new.
       
   202 	 * @param p     the memory to 'free'
       
   203 	 * @param index the original parameter given to create the memory
       
   204 	 */
       
   205 	void operator delete(void *p, int index)
       
   206 	{
       
   207 	}
       
   208 
       
   209 	/**
       
   210 	 * An overriden version of new, so you can use the vehicle instance
       
   211 	 * instead of a newly allocated piece of memory.
       
   212 	 * @param size the size of the variable (unused)
       
   213 	 * @param pn   the already existing object to use as 'storage' backend
       
   214 	 * @return the memory that is 'allocated'
       
   215 	 */
       
   216 	void *operator new(size_t size, T *pn)
       
   217 	{
       
   218 		return pn;
       
   219 	}
       
   220 
       
   221 	/**
       
   222 	 * 'Free' the memory allocated by the overriden new.
       
   223 	 * @param p  the memory to 'free'
       
   224 	 * @param pn the pointer that was given to 'new' on creation.
       
   225 	 */
       
   226 	void operator delete(void *p, T *pn)
       
   227 	{
       
   228 	}
       
   229 
       
   230 	/**
       
   231 	 * Is this a valid object or not?
       
   232 	 * @return true if and only if it is valid
       
   233 	 */
       
   234 	virtual bool IsValid() const
       
   235 	{
       
   236 		return false;
       
   237 	}
       
   238 
       
   239 protected:
       
   240 	/**
       
   241 	 * Allocate a pool item; possibly allocate a new block in the pool.
       
   242 	 * @return the allocated pool item (or NULL when the pool is full).
       
   243 	 */
       
   244 	static T *AllocateRaw()
       
   245 	{
       
   246 		return AllocateRaw(Tpool->first_free_index);
       
   247 	}
       
   248 
       
   249 	/**
       
   250 	 * Allocate a pool item; possibly allocate a new block in the pool.
       
   251 	 * @param first the first pool item to start searching
       
   252 	 * @return the allocated pool item (or NULL when the pool is full).
       
   253 	 */
       
   254 	static T *AllocateRaw(uint &first)
       
   255 	{
       
   256 		uint last_minus_one = Tpool->GetSize() - 1;
       
   257 
       
   258 		for (T *t = Tpool->Get(first); t != NULL; t = (t->index < last_minus_one) ? Tpool->Get(t->index + 1U) : NULL) {
       
   259 			if (!t->IsValid()) {
       
   260 				first = t->index;
       
   261 				Tid index = t->index;
       
   262 
       
   263 				memset(t, 0, Tpool->item_size);
       
   264 				t->index = index;
       
   265 				return t;
       
   266 			}
       
   267 		}
       
   268 
       
   269 		/* Check if we can add a block to the pool */
       
   270 		if (Tpool->AddBlockToPool()) return AllocateRaw(first);
       
   271 
       
   272 		return NULL;
       
   273 	}
       
   274 };
    54 
   275 
    55 
   276 
    56 #define OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
   277 #define OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
    57 	enum { \
   278 	enum { \
    58 		name##_POOL_BLOCK_SIZE_BITS = block_size_bits, \
   279 		name##_POOL_BLOCK_SIZE_BITS = block_size_bits, \
    59 		name##_POOL_MAX_BLOCKS      = max_blocks \
   280 		name##_POOL_MAX_BLOCKS      = max_blocks \
    60 	};
   281 	};
    61 
   282 
    62 
   283 
    63 #define OLD_POOL_ACCESSORS(name, type) \
   284 #define OLD_POOL_ACCESSORS(name, type) \
    64 	static inline type* Get##name(uint index) \
   285 	static inline type* Get##name(uint index) { return _##name##_pool.Get(index);  } \
    65 	{ \
   286 	static inline uint Get##name##PoolSize()  { return _##name##_pool.GetSize(); }
    66 		assert(index < _##name##_pool.total_items); \
       
    67 		return (type*)( \
       
    68 			_##name##_pool.blocks[index >> name##_POOL_BLOCK_SIZE_BITS] + \
       
    69 			(index & ((1 << name##_POOL_BLOCK_SIZE_BITS) - 1)) * sizeof(type) \
       
    70 		); \
       
    71 	} \
       
    72 \
       
    73 	static inline uint Get##name##PoolSize() \
       
    74 	{ \
       
    75 		return _##name##_pool.total_items; \
       
    76 	}
       
    77 
   287 
    78 
   288 
    79 #define DECLARE_OLD_POOL(name, type, block_size_bits, max_blocks) \
   289 #define DECLARE_OLD_POOL(name, type, block_size_bits, max_blocks) \
    80 	OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
   290 	OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
    81 	extern OldMemoryPool _##name##_pool; \
   291 	extern OldMemoryPool<type> _##name##_pool; \
    82 	OLD_POOL_ACCESSORS(name, type)
   292 	OLD_POOL_ACCESSORS(name, type)
    83 
   293 
    84 
   294 
    85 #define DEFINE_OLD_POOL(name, type, new_block_proc, clean_block_proc) \
   295 #define DEFINE_OLD_POOL(name, type, new_block_proc, clean_block_proc) \
    86 	OldMemoryPool _##name##_pool = { \
   296 	OldMemoryPool<type> _##name##_pool( \
    87 		#name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \
   297 		#name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \
    88 		new_block_proc, clean_block_proc, \
   298 		new_block_proc, clean_block_proc);
    89 		0, 0, NULL \
   299 
    90 	};
   300 #define DEFINE_OLD_POOL_GENERIC(name, type) \
       
   301 	OldMemoryPool<type> _##name##_pool( \
       
   302 		#name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \
       
   303 		PoolNewBlock<type, &_##name##_pool>, PoolCleanBlock<type, &_##name##_pool>);
    91 
   304 
    92 
   305 
    93 #define STATIC_OLD_POOL(name, type, block_size_bits, max_blocks, new_block_proc, clean_block_proc) \
   306 #define STATIC_OLD_POOL(name, type, block_size_bits, max_blocks, new_block_proc, clean_block_proc) \
    94 	OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
   307 	OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
    95 	static DEFINE_OLD_POOL(name, type, new_block_proc, clean_block_proc) \
   308 	static DEFINE_OLD_POOL(name, type, new_block_proc, clean_block_proc) \