//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // // A growable memory class. This memory class does *not* store all // of its memory in a contiguous block, and but it does guarantee to not // reallocate it. Note the strange interface... ints are used instead of void*s // to make this look as similar as possible to CUtlMemory. //=============================================================================// #ifndef UTLFIXEDMEMORY_H #define UTLFIXEDMEMORY_H #ifdef _WIN32 #pragma once #endif #include "tier0/dbg.h" #include <string.h> #include <new.h> #include "tier0/platform.h" #include "tier0/memdbgon.h" #pragma warning (disable:4100) #pragma warning (disable:4514) //----------------------------------------------------------------------------- // The CUtlFixedMemory class: // A growable memory class which doubles in size by default. //----------------------------------------------------------------------------- template< class T > class CUtlFixedMemory { public: // constructor, destructor CUtlFixedMemory( int nGrowSize = 0, int nInitSize = 0 ); ~CUtlFixedMemory(); // element access T& operator[]( int i ); T const& operator[]( int i ) const; T& Element( int i ); T const& Element( int i ) const; // Can we use this index? bool IsIdxValid( int i ) const; // Size int AllocationCount() const; // Allocate, free a single element int Alloc(); void Remove( int i ); void RemoveAll( ); // Makes sure we've got at least this much memory void EnsureCapacity( int num ); // Memory deallocation void Purge(); // is the memory externally allocated? bool IsExternallyAllocated() const; // Set the size by which the memory grows void SetGrowSize( int size ); // Used to iterate over all elements int FirstElement(); int NextElement( int i ); private: enum { EXTERNAL_BUFFER_MARKER = -1, }; struct BlockHeader_t { BlockHeader_t *m_pNext; int m_nBlockCount; }; private: void SetupFreeList( BlockHeader_t *pHeader ); void Grow( int num = 1 ); private: BlockHeader_t *m_pMemory; int m_nAllocationCount; int m_nGrowSize; T *m_pFirstFree; }; //----------------------------------------------------------------------------- // constructor, destructor //----------------------------------------------------------------------------- template< class T > CUtlFixedMemory<T>::CUtlFixedMemory( int nGrowSize, int nInitAllocationCount ) : m_pMemory(0), m_pFirstFree(0), m_nAllocationCount( nInitAllocationCount ), m_nGrowSize( nGrowSize ) { // T must be at least as big as a pointer or the free list fails COMPILE_TIME_ASSERT( sizeof(T) >= 4 ); Assert( (nGrowSize >= 0) && (nGrowSize != EXTERNAL_BUFFER_MARKER) ); if (m_nAllocationCount) { MEM_ALLOC_CREDIT_CLASS(); m_pMemory = (BlockHeader_t*)malloc( sizeof(BlockHeader_t) + m_nAllocationCount * sizeof(T) ); m_pMemory->m_pNext = NULL; m_pMemory->m_nBlockCount = m_nAllocationCount; SetupFreeList( m_pMemory ); } } template< class T > CUtlFixedMemory<T>::~CUtlFixedMemory() { Purge(); } //----------------------------------------------------------------------------- // Sets up the free list //----------------------------------------------------------------------------- template< class T > void CUtlFixedMemory<T>::SetupFreeList( BlockHeader_t *pHeader ) { T* pPrev = m_pFirstFree; m_pFirstFree = (T*)( pHeader + 1 ); T* pCurr = m_pFirstFree + pHeader->m_nBlockCount; while ( --pCurr >= m_pFirstFree ) { // Treat the first four *((T**)pCurr) = pPrev; pPrev = pCurr; } } //----------------------------------------------------------------------------- // Used to iterate over all elements. Not particularly fast. //----------------------------------------------------------------------------- template< class T > int CUtlFixedMemory<T>::FirstElement() { return m_pMemory ? (int)(m_pMemory + 1) : 0; } template< class T > int CUtlFixedMemory<T>::NextElement( int i ) { T* pTest = (T*)i; BlockHeader_t *pCheck = m_pMemory; while (pCheck) { T* pBase = (T*)(pCheck + 1); T* pLast = pBase + pCheck->m_nBlockCount; if ( (i >= (int)pBase) && ( i < (int)pLast ) ) { ++pTest; if ( pTest >= pLast ) { pTest = (T*)(pCheck->m_pNext + 1); return (int)pTest; } } pCheck = pCheck->m_pNext; } return 0; } //----------------------------------------------------------------------------- // element access //----------------------------------------------------------------------------- template< class T > inline T& CUtlFixedMemory<T>::operator[]( int i ) { // Indices are actually pointers here return *(T*)i; } template< class T > inline T const& CUtlFixedMemory<T>::operator[]( int i ) const { return *(T*)i; } template< class T > inline T& CUtlFixedMemory<T>::Element( int i ) { // Indices are actually pointers here return *(T*)i; } template< class T > inline T const& CUtlFixedMemory<T>::Element( int i ) const { // Indices are actually pointers here return *(T*)i; } //----------------------------------------------------------------------------- // Sets the grow size //----------------------------------------------------------------------------- template< class T > void CUtlFixedMemory<T>::SetGrowSize( int nSize ) { Assert( nSize >= 0 ); m_nGrowSize = nSize; } //----------------------------------------------------------------------------- // Number allocated //----------------------------------------------------------------------------- template< class T > inline int CUtlFixedMemory<T>::AllocationCount() const { return m_nAllocationCount; } //----------------------------------------------------------------------------- // Is element index valid? //----------------------------------------------------------------------------- template< class T > inline bool CUtlFixedMemory<T>::IsIdxValid( int i ) const { #ifdef _DEBUG BlockHeader_t *pCheck = m_pMemory; while (pCheck) { T* pBase = &pCheck->m_Data; T* pLast = pBase + pCheck->m_nBlockCount; if ( (i >= (int)pBase) && ( i < (int)pLast ) ) return true; pCheck = pCheck->m_pNext; } #endif return ( i != 0 ); } //----------------------------------------------------------------------------- // Allocate, free a single element //----------------------------------------------------------------------------- template< class T > int CUtlFixedMemory<T>::Alloc( ) { if (!m_pFirstFree) { Grow(); } int nRetVal = (int)m_pFirstFree; m_pFirstFree = *((T**)m_pFirstFree); return nRetVal; } template< class T > void CUtlFixedMemory<T>::Remove( int i ) { Assert( IsIdxValid(i) ); *((T**)i) = m_pFirstFree; m_pFirstFree = (T*)i; } template< class T > void CUtlFixedMemory<T>::RemoveAll( ) { m_pFirstFree = 0; BlockHeader_t *pHeader; for ( pHeader = m_pMemory; pHeader; pHeader = pHeader->m_pNext ) { SetupFreeList( pHeader ); } } //----------------------------------------------------------------------------- // Grows the memory //----------------------------------------------------------------------------- template< class T > void CUtlFixedMemory<T>::Grow( int num ) { int nOldAllocation = m_nAllocationCount; int nAllocationRequested = m_nAllocationCount + num; while (m_nAllocationCount < nAllocationRequested) { if (m_nGrowSize) { m_nAllocationCount += m_nGrowSize; } else { if ( m_nAllocationCount != 0 ) { m_nAllocationCount += m_nAllocationCount; } else { // Compute an allocation which is at least as big as a cache line... m_nAllocationCount = (31 + sizeof(T)) / sizeof(T); Assert(m_nAllocationCount != 0); } } } // Make sure we have at least numallocated + num allocations. // Use the grow rules specified for this memory (in m_nGrowSize) int nNewAllocationCount = m_nAllocationCount - nOldAllocation; MEM_ALLOC_CREDIT_CLASS(); BlockHeader_t *pHeader = (BlockHeader_t*)malloc( sizeof(BlockHeader_t) + nNewAllocationCount * sizeof(T) ); pHeader->m_pNext = NULL; pHeader->m_nBlockCount = nNewAllocationCount; SetupFreeList( pHeader ); pHeader->m_pNext = m_pMemory; m_pMemory = pHeader; } //----------------------------------------------------------------------------- // Makes sure we've got at least this much memory //----------------------------------------------------------------------------- template< class T > inline void CUtlFixedMemory<T>::EnsureCapacity( int num ) { if (m_nAllocationCount < num) { Grow( num - m_nAllocationCount ); } } //----------------------------------------------------------------------------- // Memory deallocation //----------------------------------------------------------------------------- template< class T > void CUtlFixedMemory<T>::Purge() { BlockHeader_t *pHeader, *pNext; for ( pHeader = m_pMemory; pHeader; pHeader = pNext ) { pNext = pHeader->m_pNext; free( pHeader ); } m_pMemory = NULL; m_pFirstFree = NULL; m_nAllocationCount = 0; } #include "tier0/memdbgoff.h" #endif // UTLFIXEDMEMORY_H
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 5821 | Knut Wikstrom |
Added Valve Source code. This is NOT to be commited to other than new code from Valve. |