/*
** 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