| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- /*
- ** 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 <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** 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 <new.h>
- #include <stdlib.h>
- #include <stddef.h>
- /**********************************************************************************************
- ** 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<ListNodeClass,256> NodePool;
- ** ListNodeClass * node = NodePool.Allocate_Object();
- ** NodePool.Free_Object(node);
- **
- **********************************************************************************************/
- template<class T,int BLOCK_SIZE = 64>
- 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,256>
- ** {
- ** ListNodeClass * Next;
- ** void * Data;
- ** };
- **
- ** ListNode.cpp:
- ** DEFINE_AUTO_POOL(ListNodeClass);
- **
- ** function do_stuff(void) {
- ** ListNodeClass * node = new ListNodeClass;
- ** delete node;
- ** }
- **
- **********************************************************************************************/
- template<class T, int BLOCK_SIZE = 64>
- 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<T,BLOCK_SIZE> 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<T,BLOCKSIZE> AutoPoolClass<T,BLOCKSIZE>::Allocator;
- /***********************************************************************************************
- * ObjectPoolClass::ObjectPoolClass -- constructor for ObjectPoolClass *
- * *
- * Initializes the object pool to the empty state *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- *=============================================================================================*/
- template<class T,int BLOCK_SIZE>
- ObjectPoolClass<T,BLOCK_SIZE>::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<class T,int BLOCK_SIZE>
- ObjectPoolClass<T,BLOCK_SIZE>::~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<class T,int BLOCK_SIZE>
- T * ObjectPoolClass<T,BLOCK_SIZE>::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<class T,int BLOCK_SIZE>
- void ObjectPoolClass<T,BLOCK_SIZE>::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<class T,int BLOCK_SIZE>
- T * ObjectPoolClass<T,BLOCK_SIZE>::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<class T,int BLOCK_SIZE>
- void ObjectPoolClass<T,BLOCK_SIZE>::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<class T, int BLOCK_SIZE>
- void * AutoPoolClass<T,BLOCK_SIZE>::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<class T, int BLOCK_SIZE>
- void AutoPoolClass<T,BLOCK_SIZE>::operator delete( void * memory )
- {
- if ( memory == 0 ) return;
- Allocator.Free_Object_Memory((T*)memory);
- }
-
- #endif // MEMPOOL_H
|