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) \ |