diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/public/tier1/mempool.h | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/public/tier1/mempool.h')
| -rw-r--r-- | mp/src/public/tier1/mempool.h | 1102 |
1 files changed, 551 insertions, 551 deletions
diff --git a/mp/src/public/tier1/mempool.h b/mp/src/public/tier1/mempool.h index 65eeb7c9..88406fbf 100644 --- a/mp/src/public/tier1/mempool.h +++ b/mp/src/public/tier1/mempool.h @@ -1,551 +1,551 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-//
-//-----------------------------------------------------------------------------
-// $Log: $
-//
-// $NoKeywords: $
-//===========================================================================//
-
-#ifndef MEMPOOL_H
-#define MEMPOOL_H
-
-#ifdef _WIN32
-#pragma once
-#endif
-
-#include "tier0/memalloc.h"
-#include "tier0/tslist.h"
-#include "tier0/platform.h"
-#include "tier1/utlvector.h"
-#include "tier1/utlrbtree.h"
-
-//-----------------------------------------------------------------------------
-// Purpose: Optimized pool memory allocator
-//-----------------------------------------------------------------------------
-
-typedef void (*MemoryPoolReportFunc_t)( PRINTF_FORMAT_STRING char const* pMsg, ... );
-
-class CUtlMemoryPool
-{
-public:
- // Ways the memory pool can grow when it needs to make a new blob.
- enum MemoryPoolGrowType_t
- {
- GROW_NONE=0, // Don't allow new blobs.
- GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates
- // get larger and larger each time it allocates one).
- GROW_SLOW=2 // New blob size is numElements.
- };
-
- CUtlMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 );
- ~CUtlMemoryPool();
-
- void* Alloc(); // Allocate the element size you specified in the constructor.
- void* Alloc( size_t amount );
- void* AllocZero(); // Allocate the element size you specified in the constructor, zero the memory before construction
- void* AllocZero( size_t amount );
- void Free(void *pMem);
-
- // Frees everything
- void Clear();
-
- // Error reporting...
- static void SetErrorReportFunc( MemoryPoolReportFunc_t func );
-
- // returns number of allocated blocks
- int Count() { return m_BlocksAllocated; }
- int PeakCount() { return m_PeakAlloc; }
-
-protected:
- class CBlob
- {
- public:
- CBlob *m_pPrev, *m_pNext;
- int m_NumBytes; // Number of bytes in this blob.
- char m_Data[1];
- char m_Padding[3]; // to int align the struct
- };
-
- // Resets the pool
- void Init();
- void AddNewBlob();
- void ReportLeaks();
-
- int m_BlockSize;
- int m_BlocksPerBlob;
-
- int m_GrowMode; // GROW_ enum.
-
- // Put m_BlocksAllocated in front of m_pHeadOfFreeList for better
- // packing on 64-bit where pointers are 8-byte aligned.
- int m_BlocksAllocated;
- // FIXME: Change m_ppMemBlob into a growable array?
- void *m_pHeadOfFreeList;
- int m_PeakAlloc;
- unsigned short m_nAlignment;
- unsigned short m_NumBlobs;
- const char * m_pszAllocOwner;
- // CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned
- CBlob m_BlobHead;
-
- static MemoryPoolReportFunc_t g_ReportFunc;
-};
-
-
-//-----------------------------------------------------------------------------
-//
-//-----------------------------------------------------------------------------
-class CMemoryPoolMT : public CUtlMemoryPool
-{
-public:
- CMemoryPoolMT(int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner) {}
-
-
- void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); }
- void* Alloc( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc( amount ); }
- void* AllocZero() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero(); }
- void* AllocZero( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero( amount ); }
- void Free(void *pMem) { AUTO_LOCK( m_mutex ); CUtlMemoryPool::Free( pMem ); }
-
- // Frees everything
- void Clear() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Clear(); }
-private:
- CThreadFastMutex m_mutex; // @TODO: Rework to use tslist (toml 7/6/2007)
-};
-
-
-//-----------------------------------------------------------------------------
-// Wrapper macro to make an allocator that returns particular typed allocations
-// and construction and destruction of objects.
-//-----------------------------------------------------------------------------
-template< class T >
-class CClassMemoryPool : public CUtlMemoryPool
-{
-public:
- CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) :
- CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {
- #ifdef PLATFORM_64BITS
- COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 64 );
- #else
- COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 48 );
- #endif
- }
-
- T* Alloc();
- T* AllocZero();
- void Free( T *pMem );
-
- void Clear();
-};
-
-
-//-----------------------------------------------------------------------------
-// Specialized pool for aligned data management (e.g., Xbox cubemaps)
-//-----------------------------------------------------------------------------
-template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD = 4 >
-class CAlignedMemPool
-{
- enum
- {
- BLOCK_SIZE = ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) > 8 ? ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) : 8
- };
-
-public:
- CAlignedMemPool();
-
- void *Alloc();
- void Free( void *p );
-
- static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight );
- void Compact();
-
- int NumTotal() { return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); }
- int NumAllocated() { return NumTotal() - m_nFree; }
- int NumFree() { return m_nFree; }
-
- int BytesTotal() { return NumTotal() * BLOCK_SIZE; }
- int BytesAllocated() { return NumAllocated() * BLOCK_SIZE; }
- int BytesFree() { return NumFree() * BLOCK_SIZE; }
-
- int ItemSize() { return ITEM_SIZE; }
- int BlockSize() { return BLOCK_SIZE; }
- int ChunkSize() { return CHUNK_SIZE; }
-
-private:
- struct FreeBlock_t
- {
- FreeBlock_t *pNext;
- byte reserved[ BLOCK_SIZE - sizeof( FreeBlock_t *) ];
- };
-
- CUtlVector<void *> m_Chunks; // Chunks are tracked outside blocks (unlike CUtlMemoryPool) to simplify alignment issues
- FreeBlock_t * m_pFirstFree;
- int m_nFree;
- CAllocator m_Allocator;
- float m_TimeLastCompact;
-};
-
-//-----------------------------------------------------------------------------
-// Pool variant using standard allocation
-//-----------------------------------------------------------------------------
-template <typename T, int nInitialCount = 0, bool bDefCreateNewIfEmpty = true >
-class CObjectPool
-{
-public:
- CObjectPool()
- {
- int i = nInitialCount;
- while ( i-- > 0 )
- {
- m_AvailableObjects.PushItem( new T );
- }
- }
-
- ~CObjectPool()
- {
- Purge();
- }
-
- int NumAvailable()
- {
- return m_AvailableObjects.Count();
- }
-
- void Purge()
- {
- T *p;
- while ( m_AvailableObjects.PopItem( &p ) )
- {
- delete p;
- }
- }
-
- T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty )
- {
- T *p;
- if ( !m_AvailableObjects.PopItem( &p ) )
- {
- p = ( bCreateNewIfEmpty ) ? new T : NULL;
- }
- return p;
- }
-
- void PutObject( T *p )
- {
- m_AvailableObjects.PushItem( p );
- }
-
-private:
- CTSList<T *> m_AvailableObjects;
-};
-
-//-----------------------------------------------------------------------------
-
-
-template< class T >
-inline T* CClassMemoryPool<T>::Alloc()
-{
- T *pRet;
-
- {
- MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T));
- pRet = (T*)CUtlMemoryPool::Alloc();
- }
-
- if ( pRet )
- {
- Construct( pRet );
- }
- return pRet;
-}
-
-template< class T >
-inline T* CClassMemoryPool<T>::AllocZero()
-{
- T *pRet;
-
- {
- MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T));
- pRet = (T*)CUtlMemoryPool::AllocZero();
- }
-
- if ( pRet )
- {
- Construct( pRet );
- }
- return pRet;
-}
-
-template< class T >
-inline void CClassMemoryPool<T>::Free(T *pMem)
-{
- if ( pMem )
- {
- Destruct( pMem );
- }
-
- CUtlMemoryPool::Free( pMem );
-}
-
-template< class T >
-inline void CClassMemoryPool<T>::Clear()
-{
- CUtlRBTree<void *> freeBlocks;
- SetDefLessFunc( freeBlocks );
-
- void *pCurFree = m_pHeadOfFreeList;
- while ( pCurFree != NULL )
- {
- freeBlocks.Insert( pCurFree );
- pCurFree = *((void**)pCurFree);
- }
-
- for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
- {
- T *p = (T *)pCur->m_Data;
- T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes);
- while ( p < pLimit )
- {
- if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() )
- {
- Destruct( p );
- }
- p++;
- }
- }
-
- CUtlMemoryPool::Clear();
-}
-
-
-//-----------------------------------------------------------------------------
-// Macros that make it simple to make a class use a fixed-size allocator
-// Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class,
-// Put DEFINE_FIXEDSIZE_ALLOCATOR in the CPP file
-//-----------------------------------------------------------------------------
-#define DECLARE_FIXEDSIZE_ALLOCATOR( _class ) \
- public: \
- inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
- inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
- inline void operator delete( void* p ) { s_Allocator.Free(p); } \
- inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \
- private: \
- static CUtlMemoryPool s_Allocator
-
-#define DEFINE_FIXEDSIZE_ALLOCATOR( _class, _initsize, _grow ) \
- CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool")
-
-#define DEFINE_FIXEDSIZE_ALLOCATOR_ALIGNED( _class, _initsize, _grow, _alignment ) \
- CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", _alignment )
-
-#define DECLARE_FIXEDSIZE_ALLOCATOR_MT( _class ) \
- public: \
- inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
- inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
- inline void operator delete( void* p ) { s_Allocator.Free(p); } \
- inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \
- private: \
- static CMemoryPoolMT s_Allocator
-
-#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \
- CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool")
-
-//-----------------------------------------------------------------------------
-// Macros that make it simple to make a class use a fixed-size allocator
-// This version allows us to use a memory pool which is externally defined...
-// Put DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the private section of a class,
-// Put DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the CPP file
-//-----------------------------------------------------------------------------
-
-#define DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class ) \
- public: \
- inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \
- inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \
- inline void operator delete( void* p ) { s_pAllocator->Free(p); } \
- private: \
- static CUtlMemoryPool* s_pAllocator
-
-#define DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class, _allocator ) \
- CUtlMemoryPool* _class::s_pAllocator = _allocator
-
-
-template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
-inline CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::CAlignedMemPool()
- : m_pFirstFree( 0 ),
- m_nFree( 0 ),
- m_TimeLastCompact( 0 )
-{
- COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE );
- COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) );
-}
-
-template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
-inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Alloc()
-{
- if ( !m_pFirstFree )
- {
- FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE );
- Assert( (unsigned)pNew % ALIGNMENT == 0 );
- m_Chunks.AddToTail( pNew );
- m_nFree = CHUNK_SIZE / BLOCK_SIZE;
- m_pFirstFree = pNew;
- for ( int i = 0; i < m_nFree - 1; i++ )
- {
- pNew->pNext = pNew + 1;
- pNew++;
- }
- pNew->pNext = NULL;
- }
-
- void *p = m_pFirstFree;
- m_pFirstFree = m_pFirstFree->pNext;
- m_nFree--;
-
- return p;
-}
-
-template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
-inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Free( void *p )
-{
- // Insertion sort to encourage allocation clusters in chunks
- FreeBlock_t *pFree = ((FreeBlock_t *)p);
- FreeBlock_t *pCur = m_pFirstFree;
- FreeBlock_t *pPrev = NULL;
-
- while ( pCur && pFree > pCur )
- {
- pPrev = pCur;
- pCur = pCur->pNext;
- }
-
- pFree->pNext = pCur;
-
- if ( pPrev )
- {
- pPrev->pNext = pFree;
- }
- else
- {
- m_pFirstFree = pFree;
- }
- m_nFree++;
-
- if ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD )
- {
- float time = Plat_FloatTime();
- float compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0;
- if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < Plat_FloatTime() )
- {
- Compact();
- m_TimeLastCompact = time;
- }
- }
-}
-
-template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
-inline int __cdecl CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::CompareChunk( void * const *ppLeft, void * const *ppRight )
-{
- return ((unsigned)*ppLeft) - ((unsigned)*ppRight);
-}
-
-template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD >
-inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Compact()
-{
- FreeBlock_t *pCur = m_pFirstFree;
- FreeBlock_t *pPrev = NULL;
-
- m_Chunks.Sort( CompareChunk );
-
-#ifdef VALIDATE_ALIGNED_MEM_POOL
- {
- FreeBlock_t *p = m_pFirstFree;
- while ( p )
- {
- if ( p->pNext && p > p->pNext )
- {
- __asm { int 3 }
- }
- p = p->pNext;
- }
-
- for ( int i = 0; i < m_Chunks.Count(); i++ )
- {
- if ( i + 1 < m_Chunks.Count() )
- {
- if ( m_Chunks[i] > m_Chunks[i + 1] )
- {
- __asm { int 3 }
- }
- }
- }
- }
-#endif
-
- int i;
-
- for ( i = 0; i < m_Chunks.Count(); i++ )
- {
- int nBlocksPerChunk = CHUNK_SIZE / BLOCK_SIZE;
- FreeBlock_t *pChunkLimit = ((FreeBlock_t *)m_Chunks[i]) + nBlocksPerChunk;
- int nFromChunk = 0;
- if ( pCur == m_Chunks[i] )
- {
- FreeBlock_t *pFirst = pCur;
- while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit )
- {
- pCur = pCur->pNext;
- nFromChunk++;
- }
- pCur = pFirst;
-
- }
-
- while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit )
- {
- if ( nFromChunk != nBlocksPerChunk )
- {
- if ( pPrev )
- {
- pPrev->pNext = pCur;
- }
- else
- {
- m_pFirstFree = pCur;
- }
- pPrev = pCur;
- }
- else if ( pPrev )
- {
- pPrev->pNext = NULL;
- }
- else
- {
- m_pFirstFree = NULL;
- }
-
- pCur = pCur->pNext;
- }
-
- if ( nFromChunk == nBlocksPerChunk )
- {
- m_Allocator.Free( m_Chunks[i] );
- m_nFree -= nBlocksPerChunk;
- m_Chunks[i] = 0;
- }
- }
-
- for ( i = m_Chunks.Count() - 1; i >= 0 ; i-- )
- {
- if ( !m_Chunks[i] )
- {
- m_Chunks.FastRemove( i );
- }
- }
-}
-
-#endif // MEMPOOL_H
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef MEMPOOL_H +#define MEMPOOL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/memalloc.h" +#include "tier0/tslist.h" +#include "tier0/platform.h" +#include "tier1/utlvector.h" +#include "tier1/utlrbtree.h" + +//----------------------------------------------------------------------------- +// Purpose: Optimized pool memory allocator +//----------------------------------------------------------------------------- + +typedef void (*MemoryPoolReportFunc_t)( PRINTF_FORMAT_STRING char const* pMsg, ... ); + +class CUtlMemoryPool +{ +public: + // Ways the memory pool can grow when it needs to make a new blob. + enum MemoryPoolGrowType_t + { + GROW_NONE=0, // Don't allow new blobs. + GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates + // get larger and larger each time it allocates one). + GROW_SLOW=2 // New blob size is numElements. + }; + + CUtlMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 ); + ~CUtlMemoryPool(); + + void* Alloc(); // Allocate the element size you specified in the constructor. + void* Alloc( size_t amount ); + void* AllocZero(); // Allocate the element size you specified in the constructor, zero the memory before construction + void* AllocZero( size_t amount ); + void Free(void *pMem); + + // Frees everything + void Clear(); + + // Error reporting... + static void SetErrorReportFunc( MemoryPoolReportFunc_t func ); + + // returns number of allocated blocks + int Count() { return m_BlocksAllocated; } + int PeakCount() { return m_PeakAlloc; } + +protected: + class CBlob + { + public: + CBlob *m_pPrev, *m_pNext; + int m_NumBytes; // Number of bytes in this blob. + char m_Data[1]; + char m_Padding[3]; // to int align the struct + }; + + // Resets the pool + void Init(); + void AddNewBlob(); + void ReportLeaks(); + + int m_BlockSize; + int m_BlocksPerBlob; + + int m_GrowMode; // GROW_ enum. + + // Put m_BlocksAllocated in front of m_pHeadOfFreeList for better + // packing on 64-bit where pointers are 8-byte aligned. + int m_BlocksAllocated; + // FIXME: Change m_ppMemBlob into a growable array? + void *m_pHeadOfFreeList; + int m_PeakAlloc; + unsigned short m_nAlignment; + unsigned short m_NumBlobs; + const char * m_pszAllocOwner; + // CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned + CBlob m_BlobHead; + + static MemoryPoolReportFunc_t g_ReportFunc; +}; + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +class CMemoryPoolMT : public CUtlMemoryPool +{ +public: + CMemoryPoolMT(int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner) {} + + + void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); } + void* Alloc( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc( amount ); } + void* AllocZero() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero(); } + void* AllocZero( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero( amount ); } + void Free(void *pMem) { AUTO_LOCK( m_mutex ); CUtlMemoryPool::Free( pMem ); } + + // Frees everything + void Clear() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Clear(); } +private: + CThreadFastMutex m_mutex; // @TODO: Rework to use tslist (toml 7/6/2007) +}; + + +//----------------------------------------------------------------------------- +// Wrapper macro to make an allocator that returns particular typed allocations +// and construction and destruction of objects. +//----------------------------------------------------------------------------- +template< class T > +class CClassMemoryPool : public CUtlMemoryPool +{ +public: + CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) : + CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) { + #ifdef PLATFORM_64BITS + COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 64 ); + #else + COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 48 ); + #endif + } + + T* Alloc(); + T* AllocZero(); + void Free( T *pMem ); + + void Clear(); +}; + + +//----------------------------------------------------------------------------- +// Specialized pool for aligned data management (e.g., Xbox cubemaps) +//----------------------------------------------------------------------------- +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD = 4 > +class CAlignedMemPool +{ + enum + { + BLOCK_SIZE = ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) > 8 ? ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) : 8 + }; + +public: + CAlignedMemPool(); + + void *Alloc(); + void Free( void *p ); + + static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight ); + void Compact(); + + int NumTotal() { return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); } + int NumAllocated() { return NumTotal() - m_nFree; } + int NumFree() { return m_nFree; } + + int BytesTotal() { return NumTotal() * BLOCK_SIZE; } + int BytesAllocated() { return NumAllocated() * BLOCK_SIZE; } + int BytesFree() { return NumFree() * BLOCK_SIZE; } + + int ItemSize() { return ITEM_SIZE; } + int BlockSize() { return BLOCK_SIZE; } + int ChunkSize() { return CHUNK_SIZE; } + +private: + struct FreeBlock_t + { + FreeBlock_t *pNext; + byte reserved[ BLOCK_SIZE - sizeof( FreeBlock_t *) ]; + }; + + CUtlVector<void *> m_Chunks; // Chunks are tracked outside blocks (unlike CUtlMemoryPool) to simplify alignment issues + FreeBlock_t * m_pFirstFree; + int m_nFree; + CAllocator m_Allocator; + float m_TimeLastCompact; +}; + +//----------------------------------------------------------------------------- +// Pool variant using standard allocation +//----------------------------------------------------------------------------- +template <typename T, int nInitialCount = 0, bool bDefCreateNewIfEmpty = true > +class CObjectPool +{ +public: + CObjectPool() + { + int i = nInitialCount; + while ( i-- > 0 ) + { + m_AvailableObjects.PushItem( new T ); + } + } + + ~CObjectPool() + { + Purge(); + } + + int NumAvailable() + { + return m_AvailableObjects.Count(); + } + + void Purge() + { + T *p; + while ( m_AvailableObjects.PopItem( &p ) ) + { + delete p; + } + } + + T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty ) + { + T *p; + if ( !m_AvailableObjects.PopItem( &p ) ) + { + p = ( bCreateNewIfEmpty ) ? new T : NULL; + } + return p; + } + + void PutObject( T *p ) + { + m_AvailableObjects.PushItem( p ); + } + +private: + CTSList<T *> m_AvailableObjects; +}; + +//----------------------------------------------------------------------------- + + +template< class T > +inline T* CClassMemoryPool<T>::Alloc() +{ + T *pRet; + + { + MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T)); + pRet = (T*)CUtlMemoryPool::Alloc(); + } + + if ( pRet ) + { + Construct( pRet ); + } + return pRet; +} + +template< class T > +inline T* CClassMemoryPool<T>::AllocZero() +{ + T *pRet; + + { + MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T)); + pRet = (T*)CUtlMemoryPool::AllocZero(); + } + + if ( pRet ) + { + Construct( pRet ); + } + return pRet; +} + +template< class T > +inline void CClassMemoryPool<T>::Free(T *pMem) +{ + if ( pMem ) + { + Destruct( pMem ); + } + + CUtlMemoryPool::Free( pMem ); +} + +template< class T > +inline void CClassMemoryPool<T>::Clear() +{ + CUtlRBTree<void *> freeBlocks; + SetDefLessFunc( freeBlocks ); + + void *pCurFree = m_pHeadOfFreeList; + while ( pCurFree != NULL ) + { + freeBlocks.Insert( pCurFree ); + pCurFree = *((void**)pCurFree); + } + + for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) + { + T *p = (T *)pCur->m_Data; + T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes); + while ( p < pLimit ) + { + if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() ) + { + Destruct( p ); + } + p++; + } + } + + CUtlMemoryPool::Clear(); +} + + +//----------------------------------------------------------------------------- +// Macros that make it simple to make a class use a fixed-size allocator +// Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class, +// Put DEFINE_FIXEDSIZE_ALLOCATOR in the CPP file +//----------------------------------------------------------------------------- +#define DECLARE_FIXEDSIZE_ALLOCATOR( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void operator delete( void* p ) { s_Allocator.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \ + private: \ + static CUtlMemoryPool s_Allocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR( _class, _initsize, _grow ) \ + CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") + +#define DEFINE_FIXEDSIZE_ALLOCATOR_ALIGNED( _class, _initsize, _grow, _alignment ) \ + CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", _alignment ) + +#define DECLARE_FIXEDSIZE_ALLOCATOR_MT( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void operator delete( void* p ) { s_Allocator.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \ + private: \ + static CMemoryPoolMT s_Allocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \ + CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") + +//----------------------------------------------------------------------------- +// Macros that make it simple to make a class use a fixed-size allocator +// This version allows us to use a memory pool which is externally defined... +// Put DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the private section of a class, +// Put DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the CPP file +//----------------------------------------------------------------------------- + +#define DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \ + inline void operator delete( void* p ) { s_pAllocator->Free(p); } \ + private: \ + static CUtlMemoryPool* s_pAllocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class, _allocator ) \ + CUtlMemoryPool* _class::s_pAllocator = _allocator + + +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD > +inline CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::CAlignedMemPool() + : m_pFirstFree( 0 ), + m_nFree( 0 ), + m_TimeLastCompact( 0 ) +{ + COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE ); + COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) ); +} + +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD > +inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Alloc() +{ + if ( !m_pFirstFree ) + { + FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE ); + Assert( (unsigned)pNew % ALIGNMENT == 0 ); + m_Chunks.AddToTail( pNew ); + m_nFree = CHUNK_SIZE / BLOCK_SIZE; + m_pFirstFree = pNew; + for ( int i = 0; i < m_nFree - 1; i++ ) + { + pNew->pNext = pNew + 1; + pNew++; + } + pNew->pNext = NULL; + } + + void *p = m_pFirstFree; + m_pFirstFree = m_pFirstFree->pNext; + m_nFree--; + + return p; +} + +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD > +inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Free( void *p ) +{ + // Insertion sort to encourage allocation clusters in chunks + FreeBlock_t *pFree = ((FreeBlock_t *)p); + FreeBlock_t *pCur = m_pFirstFree; + FreeBlock_t *pPrev = NULL; + + while ( pCur && pFree > pCur ) + { + pPrev = pCur; + pCur = pCur->pNext; + } + + pFree->pNext = pCur; + + if ( pPrev ) + { + pPrev->pNext = pFree; + } + else + { + m_pFirstFree = pFree; + } + m_nFree++; + + if ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD ) + { + float time = Plat_FloatTime(); + float compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0; + if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < Plat_FloatTime() ) + { + Compact(); + m_TimeLastCompact = time; + } + } +} + +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD > +inline int __cdecl CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::CompareChunk( void * const *ppLeft, void * const *ppRight ) +{ + return ((unsigned)*ppLeft) - ((unsigned)*ppRight); +} + +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, int COMPACT_THRESHOLD > +inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, COMPACT_THRESHOLD>::Compact() +{ + FreeBlock_t *pCur = m_pFirstFree; + FreeBlock_t *pPrev = NULL; + + m_Chunks.Sort( CompareChunk ); + +#ifdef VALIDATE_ALIGNED_MEM_POOL + { + FreeBlock_t *p = m_pFirstFree; + while ( p ) + { + if ( p->pNext && p > p->pNext ) + { + __asm { int 3 } + } + p = p->pNext; + } + + for ( int i = 0; i < m_Chunks.Count(); i++ ) + { + if ( i + 1 < m_Chunks.Count() ) + { + if ( m_Chunks[i] > m_Chunks[i + 1] ) + { + __asm { int 3 } + } + } + } + } +#endif + + int i; + + for ( i = 0; i < m_Chunks.Count(); i++ ) + { + int nBlocksPerChunk = CHUNK_SIZE / BLOCK_SIZE; + FreeBlock_t *pChunkLimit = ((FreeBlock_t *)m_Chunks[i]) + nBlocksPerChunk; + int nFromChunk = 0; + if ( pCur == m_Chunks[i] ) + { + FreeBlock_t *pFirst = pCur; + while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit ) + { + pCur = pCur->pNext; + nFromChunk++; + } + pCur = pFirst; + + } + + while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit ) + { + if ( nFromChunk != nBlocksPerChunk ) + { + if ( pPrev ) + { + pPrev->pNext = pCur; + } + else + { + m_pFirstFree = pCur; + } + pPrev = pCur; + } + else if ( pPrev ) + { + pPrev->pNext = NULL; + } + else + { + m_pFirstFree = NULL; + } + + pCur = pCur->pNext; + } + + if ( nFromChunk == nBlocksPerChunk ) + { + m_Allocator.Free( m_Chunks[i] ); + m_nFree -= nBlocksPerChunk; + m_Chunks[i] = 0; + } + } + + for ( i = m_Chunks.Count() - 1; i >= 0 ; i-- ) + { + if ( !m_Chunks[i] ) + { + m_Chunks.FastRemove( i ); + } + } +} + +#endif // MEMPOOL_H |