/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : WWLib * * * * $Archive:: /Commando/Code/wwlib/mempool.h $* * * * Author:: Greg Hjelstrom * * * * $Modtime:: 9/26/01 3:11p $* * * * $Revision:: 9 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * ObjectPoolClass::ObjectPoolClass -- constructor for ObjectPoolClass * * ObjectPoolClass::~ObjectPoolClass -- destructor for ObjectPoolClass * * ObjectPoolClass::Allocate_Object -- allocates an object for the user * * ObjectPoolClass::Free_Object -- releases obj back into the pool * * ObjectPoolClass::Allocate_Object_Memory -- internal function which returns memory for an * * ObjectPoolClass::Free_Object_Memory -- internal function, returns object's memory to the * * AutoPoolClass::operator new -- overriden new which calls the internal ObjectPool * * AutoPoolClass::operator delete -- overriden delete which calls the internal ObjectPool * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #if defined(_MSC_VER) #pragma once #endif #ifndef MEMPOOL_H #define MEMPOOL_H #include "bittype.h" #include "wwdebug.h" #include "mutex.h" #include #include #include /********************************************************************************************** ** ObjectPoolClass ** ** This class is designed to allocate blocks of objects of type T and then dole them out ** to you individually. The motivation for it is the situation where you are allocating ** and freeing lots of little objects directly off the heap. Through the use of this ** class, far fewer allocations will be actually made. ** ** Example Usage: ** ** ObjectPoolClass NodePool; ** ListNodeClass * node = NodePool.Allocate_Object(); ** NodePool.Free_Object(node); ** **********************************************************************************************/ template class ObjectPoolClass { public: ObjectPoolClass(void); ~ObjectPoolClass(void); T * Allocate_Object(void); void Free_Object(T * obj); T * Allocate_Object_Memory(void); void Free_Object_Memory(T * obj); protected: T * FreeListHead; uint32 * BlockListHead; int FreeObjectCount; int TotalObjectCount; FastCriticalSectionClass ObjectPoolCS; }; /********************************************************************************************** ** AutoPoolClass ** ** This class is designed to be derived from in order to give your class built-in ** object pool behavior. The new and delete operators for your class will call ** to the internal ObjectPoolClass for fast allocation and de-allocation. This ** is very well suited to being the base class for a list node class for example. ** ** Notes: ** - The array forms of new and delete are not supported ** - You must define the instance of the static object pool (Allocator) ** - You can't derive a class from a class that is derived from AutoPoolClass ** because its size won't match but it will try to use the same pool... ** ** Example Usage: ** -------------- ** ** ListNode.h: ** class ListNodeClass : public AutoPoolClass ** { ** ListNodeClass * Next; ** void * Data; ** }; ** ** ListNode.cpp: ** DEFINE_AUTO_POOL(ListNodeClass); ** ** function do_stuff(void) { ** ListNodeClass * node = new ListNodeClass; ** delete node; ** } ** **********************************************************************************************/ template class AutoPoolClass { public: static void * operator new(size_t size); static void operator delete(void * memory); private: // not implemented static void * operator new [] (size_t size); static void operator delete[] (void * memory); // This must be staticly declared by user static ObjectPoolClass Allocator; }; /* ** DEFINE_AUTO_POOL(T,BLOCKSIZE) ** Macro to declare the allocator for your class. Put this in the cpp file for ** the class. */ #define DEFINE_AUTO_POOL(T,BLOCKSIZE) \ ObjectPoolClass AutoPoolClass::Allocator; /*********************************************************************************************** * ObjectPoolClass::ObjectPoolClass -- constructor for ObjectPoolClass * * * * Initializes the object pool to the empty state * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * *=============================================================================================*/ template ObjectPoolClass::ObjectPoolClass(void) : FreeListHead(NULL), BlockListHead(NULL), FreeObjectCount(0), TotalObjectCount(0) { } /*********************************************************************************************** * ObjectPoolClass::~ObjectPoolClass -- destructor for ObjectPoolClass * * * * deletes the blocks of memory in use by the object pool. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * *=============================================================================================*/ template ObjectPoolClass::~ObjectPoolClass(void) { // assert that the user gave back all of the memory he was using WWASSERT(FreeObjectCount == TotalObjectCount); // delete all of the blocks we allocated int block_count = 0; while (BlockListHead != NULL) { uint32 * next_block = *(uint32 **)BlockListHead; ::operator delete(BlockListHead); BlockListHead = next_block; block_count++; } WWASSERT(block_count == TotalObjectCount / BLOCK_SIZE); } /*********************************************************************************************** * ObjectPoolClass::Allocate_Object -- allocates an object for the user * * * * If there are no free objects, another block of objects will be allocated. * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/29/99 GTH : Created. * *=============================================================================================*/ template T * ObjectPoolClass::Allocate_Object(void) { // allocate memory for the object T * obj = Allocate_Object_Memory(); // construct the object in-place return new (obj) T; } /*********************************************************************************************** * ObjectPoolClass::Free_Object -- releases obj back into the pool * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/29/99 GTH : Created. * *=============================================================================================*/ template void ObjectPoolClass::Free_Object(T * obj) { // destruct the object obj->T::~T(); // release the memory Free_Object_Memory(obj); } /*********************************************************************************************** * ObjectPoolClass::Allocate_Object_Memory -- internal function which returns memory for an in * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/29/99 GTH : Created. * *=============================================================================================*/ template T * ObjectPoolClass::Allocate_Object_Memory(void) { FastCriticalSectionClass::LockClass lock(ObjectPoolCS); if ( FreeListHead == 0 ) { // No free objects, allocate another block uint32 * tmp_block_head = BlockListHead; BlockListHead = (uint32*)::operator new( sizeof(T) * BLOCK_SIZE + sizeof(uint32 *)); // Link this block into the block list *(void **)BlockListHead = tmp_block_head; // Link the objects in the block into the free object list FreeListHead = (T*)(BlockListHead + 1); for ( int i = 0; i < BLOCK_SIZE; i++ ) { *(T**)(&(FreeListHead[i])) = &(FreeListHead[i+1]); // link up the elements } *(T**)(&(FreeListHead[BLOCK_SIZE-1])) = 0; // Mark the end FreeObjectCount += BLOCK_SIZE; TotalObjectCount += BLOCK_SIZE; } T * obj = FreeListHead; // Get the next free object FreeListHead = *(T**)(FreeListHead); // Bump the Head FreeObjectCount--; return obj; } /*********************************************************************************************** * ObjectPoolClass::Free_Object_Memory -- internal function, returns object's memory to the po * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/29/99 GTH : Created. * *=============================================================================================*/ template void ObjectPoolClass::Free_Object_Memory(T * obj) { FastCriticalSectionClass::LockClass lock(ObjectPoolCS); WWASSERT(obj != NULL); *(T**)(obj) = FreeListHead; // Link to the Head FreeListHead = obj; // Set the Head FreeObjectCount++; } /*********************************************************************************************** * AutoPoolClass::operator new -- overriden new which calls the internal ObjectPool * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/29/99 GTH : Created. * *=============================================================================================*/ template void * AutoPoolClass::operator new( size_t size ) { WWASSERT(size == sizeof(T)); return (void *)(Allocator.Allocate_Object_Memory()); } /*********************************************************************************************** * AutoPoolClass::operator delete -- overriden delete which calls the internal ObjectPool * * * * INPUT: * * * * OUTPUT: * * * * WARNINGS: * * * * HISTORY: * * 7/29/99 GTH : Created. * *=============================================================================================*/ template void AutoPoolClass::operator delete( void * memory ) { if ( memory == 0 ) return; Allocator.Free_Object_Memory((T*)memory); } #endif // MEMPOOL_H