//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // // A growable memory class. //===========================================================================// #ifndef UTLMEMORY_H #define UTLMEMORY_H #ifdef _WIN32 #pragma once #endif #include #include #include #define ALIGN_VALUE( val, alignment ) (( val + alignment - 1 ) & ~( alignment - 1 )) #define stackalloc( _size ) alloca( ALIGN_VALUE( _size, 16 ) ) #define stackfree( _p ) 0 // Swap two of anything. template _forceinline void swap( T& x, T& y ) { T temp = x; x = y; y = temp; } template inline T AlignValue( T val, unsigned alignment ) { return (T)( ( (unsigned int)val + alignment - 1 ) & ~( alignment - 1 ) ); } //----------------------------------------------------------------------------- // Methods to invoke the constructor, copy constructor, and destructor //----------------------------------------------------------------------------- template inline void Construct( T* pMemory ) { new( pMemory ) T; } template inline void CopyConstruct( T* pMemory, T const& src ) { new( pMemory ) T(src); } template inline void Destruct( T* pMemory ) { pMemory->~T(); #ifdef _DEBUG memset( pMemory, 0xDD, sizeof(T) ); #endif } #pragma warning (disable:4100) #pragma warning (disable:4514) // identifier was truncated to '255' characters in the debug information #pragma warning(disable: 4786) //----------------------------------------------------------------------------- // The CUtlMemory class: // A growable memory class which doubles in size by default. //----------------------------------------------------------------------------- template< class T, class I = int > class CUtlMemory { public: // constructor, destructor CUtlMemory( int nGrowSize = 0, int nInitSize = 0 ); CUtlMemory( T* pMemory, int numElements ); CUtlMemory( const T* pMemory, int numElements ); ~CUtlMemory(); // Set the size by which the memory grows void Init( int nGrowSize = 0, int nInitSize = 0 ); class Iterator_t { public: Iterator_t( I i ) : index( i ) {} I index; bool operator==( const Iterator_t it ) const { return index == it.index; } bool operator!=( const Iterator_t it ) const { return index != it.index; } }; Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); } Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); } I GetIndex( const Iterator_t &it ) const { return it.index; } bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; } bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); } Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } // element access T& operator[]( I i ); const T& operator[]( I i ) const; T& Element( I i ); const T& Element( I i ) const; // Can we use this index? bool IsIdxValid( I i ) const; static I InvalidIndex() { return ( I )-1; } // Gets the base address (can change when adding elements!) T* Base(); const T* Base() const; // Attaches the buffer to external memory.... void SetExternalBuffer( T* pMemory, int numElements ); void SetExternalBuffer( const T* pMemory, int numElements ); void AssumeMemory( T *pMemory, int nSize ); // Fast swap void Swap( CUtlMemory< T, I > &mem ); // Switches the buffer from an external memory buffer to a reallocatable buffer // Will copy the current contents of the external buffer to the reallocatable buffer void ConvertToGrowableMemory( int nGrowSize ); // Size int NumAllocated() const; int Count() const; // Grows the memory, so that at least allocated + num elements are allocated void Grow( int num = 1 ); // Makes sure we've got at least this much memory void EnsureCapacity( int num ); // Memory deallocation void Purge(); // Purge all but the given number of elements void Purge( int numElements ); // is the memory externally allocated? bool IsExternallyAllocated() const; // is the memory read only? bool IsReadOnly() const; // Set the size by which the memory grows void SetGrowSize( int size ); protected: void ValidateGrowSize() { #ifdef _X360 if ( m_nGrowSize && m_nGrowSize != EXTERNAL_BUFFER_MARKER ) { // Max grow size at 128 bytes on XBOX const int MAX_GROW = 128; if ( m_nGrowSize * sizeof(T) > MAX_GROW ) { m_nGrowSize = max( 1, MAX_GROW / sizeof(T) ); } } #endif } enum { EXTERNAL_BUFFER_MARKER = -1, EXTERNAL_CONST_BUFFER_MARKER = -2, }; T* m_pMemory; int m_nAllocationCount; int m_nGrowSize; }; //----------------------------------------------------------------------------- // The CUtlMemory class: // A growable memory class which doubles in size by default. //----------------------------------------------------------------------------- template< class T, size_t SIZE, class I = int > class CUtlMemoryFixedGrowable : public CUtlMemory< T, I > { typedef CUtlMemory< T, I > BaseClass; public: CUtlMemoryFixedGrowable( int nGrowSize = 0, int nInitSize = SIZE ) : BaseClass( m_pFixedMemory, SIZE ) { assert( nInitSize == 0 || nInitSize == SIZE ); m_nMallocGrowSize = nGrowSize; } void Grow( int nCount = 1 ) { if ( this->IsExternallyAllocated() ) { this->ConvertToGrowableMemory( m_nMallocGrowSize ); } BaseClass::Grow( nCount ); } void EnsureCapacity( int num ) { if ( CUtlMemory::m_nAllocationCount >= num ) return; if ( this->IsExternallyAllocated() ) { // Can't grow a buffer whose memory was externally allocated this->ConvertToGrowableMemory( m_nMallocGrowSize ); } BaseClass::EnsureCapacity( num ); } private: int m_nMallocGrowSize; T m_pFixedMemory[ SIZE ]; }; //----------------------------------------------------------------------------- // The CUtlMemoryFixed class: // A fixed memory class //----------------------------------------------------------------------------- template< typename T, size_t SIZE, int nAlignment = 0 > class CUtlMemoryFixed { public: // constructor, destructor CUtlMemoryFixed( int nGrowSize = 0, int nInitSize = 0 ) { assert( nInitSize == 0 || nInitSize == SIZE ); } CUtlMemoryFixed( T* pMemory, int numElements ) { assert( 0 ); } // Can we use this index? bool IsIdxValid( int i ) const { return (i >= 0) && (i < SIZE); } static int InvalidIndex() { return -1; } // Gets the base address T* Base() { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); } const T* Base() const { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); } // element access T& operator[]( int i ) { assert( IsIdxValid(i) ); return Base()[i]; } const T& operator[]( int i ) const { assert( IsIdxValid(i) ); return Base()[i]; } T& Element( int i ) { assert( IsIdxValid(i) ); return Base()[i]; } const T& Element( int i ) const { assert( IsIdxValid(i) ); return Base()[i]; } // Attaches the buffer to external memory.... void SetExternalBuffer( T* pMemory, int numElements ) { assert( 0 ); } // Size int NumAllocated() const { return SIZE; } int Count() const { return SIZE; } // Grows the memory, so that at least allocated + num elements are allocated void Grow( int num = 1 ) { assert( 0 ); } // Makes sure we've got at least this much memory void EnsureCapacity( int num ) { assert( num <= SIZE ); } // Memory deallocation void Purge() {} // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryFixed) void Purge( int numElements ) { assert( 0 ); } // is the memory externally allocated? bool IsExternallyAllocated() const { return false; } // Set the size by which the memory grows void SetGrowSize( int size ) {} class Iterator_t { public: Iterator_t( int i ) : index( i ) {} int index; bool operator==( const Iterator_t it ) const { return index == it.index; } bool operator!=( const Iterator_t it ) const { return index != it.index; } }; Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); } Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); } int GetIndex( const Iterator_t &it ) const { return it.index; } bool IsIdxAfter( int i, const Iterator_t &it ) const { return i > it.index; } bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); } Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } private: char m_Memory[ SIZE*sizeof(T) + nAlignment ]; }; //----------------------------------------------------------------------------- // constructor, destructor //----------------------------------------------------------------------------- template< class T, class I > CUtlMemory::CUtlMemory( int nGrowSize, int nInitAllocationCount ) : m_pMemory(0), m_nAllocationCount( nInitAllocationCount ), m_nGrowSize( nGrowSize ) { this->ValidateGrowSize(); assert( nGrowSize >= 0 ); if (m_nAllocationCount) { m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); } } template< class T, class I > CUtlMemory::CUtlMemory( T* pMemory, int numElements ) : m_pMemory(pMemory), m_nAllocationCount( numElements ) { // Special marker indicating externally supplied modifyable memory m_nGrowSize = EXTERNAL_BUFFER_MARKER; } template< class T, class I > CUtlMemory::CUtlMemory( const T* pMemory, int numElements ) : m_pMemory( (T*)pMemory ), m_nAllocationCount( numElements ) { // Special marker indicating externally supplied modifyable memory m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; } template< class T, class I > CUtlMemory::~CUtlMemory() { Purge(); } template< class T, class I > void CUtlMemory::Init( int nGrowSize /*= 0*/, int nInitSize /*= 0*/ ) { Purge(); m_nGrowSize = nGrowSize; m_nAllocationCount = nInitSize; this->ValidateGrowSize(); assert( nGrowSize >= 0 ); if (m_nAllocationCount) { m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); } } //----------------------------------------------------------------------------- // Fast swap //----------------------------------------------------------------------------- template< class T, class I > void CUtlMemory::Swap( CUtlMemory &mem ) { swap( m_nGrowSize, mem.m_nGrowSize ); swap( m_pMemory, mem.m_pMemory ); swap( m_nAllocationCount, mem.m_nAllocationCount ); } //----------------------------------------------------------------------------- // Switches the buffer from an external memory buffer to a reallocatable buffer //----------------------------------------------------------------------------- template< class T, class I > void CUtlMemory::ConvertToGrowableMemory( int nGrowSize ) { if ( !this->IsExternallyAllocated() ) return; m_nGrowSize = nGrowSize; if (m_nAllocationCount) { int nNumBytes = m_nAllocationCount * sizeof(T); T *pMemory = (T*)malloc( nNumBytes ); memcpy( pMemory, m_pMemory, nNumBytes ); m_pMemory = pMemory; } else { m_pMemory = NULL; } } //----------------------------------------------------------------------------- // Attaches the buffer to external memory.... //----------------------------------------------------------------------------- template< class T, class I > void CUtlMemory::SetExternalBuffer( T* pMemory, int numElements ) { // Blow away any existing allocated memory Purge(); m_pMemory = pMemory; m_nAllocationCount = numElements; // Indicate that we don't own the memory m_nGrowSize = EXTERNAL_BUFFER_MARKER; } template< class T, class I > void CUtlMemory::SetExternalBuffer( const T* pMemory, int numElements ) { // Blow away any existing allocated memory Purge(); m_pMemory = const_cast( pMemory ); m_nAllocationCount = numElements; // Indicate that we don't own the memory m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; } template< class T, class I > void CUtlMemory::AssumeMemory( T* pMemory, int numElements ) { // Blow away any existing allocated memory Purge(); // Simply take the pointer but don't mark us as external m_pMemory = pMemory; m_nAllocationCount = numElements; } //----------------------------------------------------------------------------- // element access //----------------------------------------------------------------------------- template< class T, class I > inline T& CUtlMemory::operator[]( I i ) { assert( !IsReadOnly() ); assert( IsIdxValid(i) ); return m_pMemory[i]; } template< class T, class I > inline const T& CUtlMemory::operator[]( I i ) const { assert( IsIdxValid(i) ); return m_pMemory[i]; } template< class T, class I > inline T& CUtlMemory::Element( I i ) { assert( !IsReadOnly() ); assert( IsIdxValid(i) ); return m_pMemory[i]; } template< class T, class I > inline const T& CUtlMemory::Element( I i ) const { assert( IsIdxValid(i) ); return m_pMemory[i]; } //----------------------------------------------------------------------------- // is the memory externally allocated? //----------------------------------------------------------------------------- template< class T, class I > bool CUtlMemory::IsExternallyAllocated() const { return (m_nGrowSize < 0); } //----------------------------------------------------------------------------- // is the memory read only? //----------------------------------------------------------------------------- template< class T, class I > bool CUtlMemory::IsReadOnly() const { return (m_nGrowSize == EXTERNAL_CONST_BUFFER_MARKER); } template< class T, class I > void CUtlMemory::SetGrowSize( int nSize ) { assert( !this->IsExternallyAllocated() ); assert( nSize >= 0 ); m_nGrowSize = nSize; this->ValidateGrowSize(); } //----------------------------------------------------------------------------- // Gets the base address (can change when adding elements!) //----------------------------------------------------------------------------- template< class T, class I > inline T* CUtlMemory::Base() { assert( !IsReadOnly() ); return m_pMemory; } template< class T, class I > inline const T *CUtlMemory::Base() const { return m_pMemory; } //----------------------------------------------------------------------------- // Size //----------------------------------------------------------------------------- template< class T, class I > inline int CUtlMemory::NumAllocated() const { return m_nAllocationCount; } template< class T, class I > inline int CUtlMemory::Count() const { return m_nAllocationCount; } //----------------------------------------------------------------------------- // Is element index valid? //----------------------------------------------------------------------------- template< class T, class I > inline bool CUtlMemory::IsIdxValid( I i ) const { return ( ((int) i) >= 0 ) && ( ((int) i) < m_nAllocationCount ); } //----------------------------------------------------------------------------- // Grows the memory //----------------------------------------------------------------------------- inline int UtlMemory_CalcNewAllocationCount( int nAllocationCount, int nGrowSize, int nNewSize, int nBytesItem ) { if ( nGrowSize ) { nAllocationCount = ((1 + ((nNewSize - 1) / nGrowSize)) * nGrowSize); } else { if ( !nAllocationCount ) { // Compute an allocation which is at least as big as a cache line... nAllocationCount = (31 + nBytesItem) / nBytesItem; } while (nAllocationCount < nNewSize) { #ifndef _X360 nAllocationCount *= 2; #else int nNewAllocationCount = ( nAllocationCount * 9) / 8; // 12.5 % if ( nNewAllocationCount > nAllocationCount ) nAllocationCount = nNewAllocationCount; else nAllocationCount *= 2; #endif } } return nAllocationCount; } template< class T, class I > void CUtlMemory::Grow( int num ) { assert( num > 0 ); if ( this->IsExternallyAllocated() ) { // Can't grow a buffer whose memory was externally allocated assert(0); return; } // Make sure we have at least numallocated + num allocations. // Use the grow rules specified for this memory (in m_nGrowSize) int nAllocationRequested = m_nAllocationCount + num; m_nAllocationCount = UtlMemory_CalcNewAllocationCount( m_nAllocationCount, m_nGrowSize, nAllocationRequested, sizeof(T) ); // if m_nAllocationRequested wraps index type I, recalculate if ( ( int )( I )m_nAllocationCount < nAllocationRequested ) { if ( ( int )( I )m_nAllocationCount == 0 && ( int )( I )( m_nAllocationCount - 1 ) >= nAllocationRequested ) { --m_nAllocationCount; // deal w/ the common case of m_nAllocationCount == MAX_USHORT + 1 } else { if ( ( int )( I )nAllocationRequested != nAllocationRequested ) { // we've been asked to grow memory to a size s.t. the index type can't address the requested amount of memory assert( 0 ); return; } while ( ( int )( I )m_nAllocationCount < nAllocationRequested ) { m_nAllocationCount = ( m_nAllocationCount + nAllocationRequested ) / 2; } } } if (m_pMemory) { m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) ); assert( m_pMemory ); } else { m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); assert( m_pMemory ); } } //----------------------------------------------------------------------------- // Makes sure we've got at least this much memory //----------------------------------------------------------------------------- template< class T, class I > inline void CUtlMemory::EnsureCapacity( int num ) { if (m_nAllocationCount >= num) return; if ( this->IsExternallyAllocated() ) { // Can't grow a buffer whose memory was externally allocated assert(0); return; } m_nAllocationCount = num; if (m_pMemory) { m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) ); } else { m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); } } //----------------------------------------------------------------------------- // Memory deallocation //----------------------------------------------------------------------------- template< class T, class I > void CUtlMemory::Purge() { if ( !this->IsExternallyAllocated() ) { if (m_pMemory) { free( (void*)m_pMemory ); m_pMemory = 0; } m_nAllocationCount = 0; } } template< class T, class I > void CUtlMemory::Purge( int numElements ) { assert( numElements >= 0 ); if( numElements > m_nAllocationCount ) { // Ensure this isn't a grow request in disguise. assert( numElements <= m_nAllocationCount ); return; } // If we have zero elements, simply do a purge: if( numElements == 0 ) { Purge(); return; } if ( this->IsExternallyAllocated() ) { // Can't shrink a buffer whose memory was externally allocated, fail silently like purge return; } // If the number of elements is the same as the allocation count, we are done. if( numElements == m_nAllocationCount ) { return; } if( !m_pMemory ) { // Allocation count is non zero, but memory is null. assert( m_pMemory ); return; } m_nAllocationCount = numElements; // Allocation count > 0, shrink it down. m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) ); } //----------------------------------------------------------------------------- // The CUtlMemory class: // A growable memory class which doubles in size by default. //----------------------------------------------------------------------------- template< class T, int nAlignment > class CUtlMemoryAligned : public CUtlMemory { public: // constructor, destructor CUtlMemoryAligned( int nGrowSize = 0, int nInitSize = 0 ); CUtlMemoryAligned( T* pMemory, int numElements ); CUtlMemoryAligned( const T* pMemory, int numElements ); ~CUtlMemoryAligned(); // Attaches the buffer to external memory.... void SetExternalBuffer( T* pMemory, int numElements ); void SetExternalBuffer( const T* pMemory, int numElements ); // Grows the memory, so that at least allocated + num elements are allocated void Grow( int num = 1 ); // Makes sure we've got at least this much memory void EnsureCapacity( int num ); // Memory deallocation void Purge(); // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryAligned) void Purge( int numElements ) { assert( 0 ); } private: void *Align( const void *pAddr ); }; //----------------------------------------------------------------------------- // Aligns a pointer //----------------------------------------------------------------------------- template< class T, int nAlignment > void *CUtlMemoryAligned::Align( const void *pAddr ) { size_t nAlignmentMask = nAlignment - 1; return (void*)( ((size_t)pAddr + nAlignmentMask) & (~nAlignmentMask) ); } //----------------------------------------------------------------------------- // constructor, destructor //----------------------------------------------------------------------------- template< class T, int nAlignment > CUtlMemoryAligned::CUtlMemoryAligned( int nGrowSize, int nInitAllocationCount ) { CUtlMemory::m_pMemory = 0; CUtlMemory::m_nAllocationCount = nInitAllocationCount; CUtlMemory::m_nGrowSize = nGrowSize; this->ValidateGrowSize(); // Alignment must be a power of two COMPILE_TIME_ASSERT( (nAlignment & (nAlignment-1)) == 0 ); assert( (nGrowSize >= 0) && (nGrowSize != CUtlMemory::EXTERNAL_BUFFER_MARKER) ); if ( CUtlMemory::m_nAllocationCount ) { CUtlMemory::m_pMemory = (T*)_aligned_malloc( nInitAllocationCount * sizeof(T), nAlignment ); } } template< class T, int nAlignment > CUtlMemoryAligned::CUtlMemoryAligned( T* pMemory, int numElements ) { // Special marker indicating externally supplied memory CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_BUFFER_MARKER; CUtlMemory::m_pMemory = (T*)Align( pMemory ); CUtlMemory::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory ) / sizeof(T); } template< class T, int nAlignment > CUtlMemoryAligned::CUtlMemoryAligned( const T* pMemory, int numElements ) { // Special marker indicating externally supplied memory CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_CONST_BUFFER_MARKER; CUtlMemory::m_pMemory = (T*)Align( pMemory ); CUtlMemory::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory ) / sizeof(T); } template< class T, int nAlignment > CUtlMemoryAligned::~CUtlMemoryAligned() { Purge(); } //----------------------------------------------------------------------------- // Attaches the buffer to external memory.... //----------------------------------------------------------------------------- template< class T, int nAlignment > void CUtlMemoryAligned::SetExternalBuffer( T* pMemory, int numElements ) { // Blow away any existing allocated memory Purge(); CUtlMemory::m_pMemory = (T*)Align( pMemory ); CUtlMemory::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory ) / sizeof(T); // Indicate that we don't own the memory CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_BUFFER_MARKER; } template< class T, int nAlignment > void CUtlMemoryAligned::SetExternalBuffer( const T* pMemory, int numElements ) { // Blow away any existing allocated memory Purge(); CUtlMemory::m_pMemory = (T*)Align( pMemory ); CUtlMemory::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory::m_pMemory ) / sizeof(T); // Indicate that we don't own the memory CUtlMemory::m_nGrowSize = CUtlMemory::EXTERNAL_CONST_BUFFER_MARKER; } //----------------------------------------------------------------------------- // Grows the memory //----------------------------------------------------------------------------- template< class T, int nAlignment > void CUtlMemoryAligned::Grow( int num ) { assert( num > 0 ); if ( this->IsExternallyAllocated() ) { // Can't grow a buffer whose memory was externally allocated assert(0); return; } // Make sure we have at least numallocated + num allocations. // Use the grow rules specified for this memory (in m_nGrowSize) int nAllocationRequested = CUtlMemory::m_nAllocationCount + num; CUtlMemory::m_nAllocationCount = UtlMemory_CalcNewAllocationCount( CUtlMemory::m_nAllocationCount, CUtlMemory::m_nGrowSize, nAllocationRequested, sizeof(T) ); if ( CUtlMemory::m_pMemory ) { CUtlMemory::m_pMemory = (T*)_aligned_realloc( CUtlMemory::m_pMemory, CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment ); assert( CUtlMemory::m_pMemory ); } else { CUtlMemory::m_pMemory = (T*)_aligned_malloc( CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment ); assert( CUtlMemory::m_pMemory ); } } //----------------------------------------------------------------------------- // Makes sure we've got at least this much memory //----------------------------------------------------------------------------- template< class T, int nAlignment > inline void CUtlMemoryAligned::EnsureCapacity( int num ) { if ( CUtlMemory::m_nAllocationCount >= num ) return; if ( this->IsExternallyAllocated() ) { // Can't grow a buffer whose memory was externally allocated assert(0); return; } CUtlMemory::m_nAllocationCount = num; if ( CUtlMemory::m_pMemory ) { CUtlMemory::m_pMemory = (T*)_aligned_realloc( CUtlMemory::m_pMemory, CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment ); } else { CUtlMemory::m_pMemory = (T*)_aligned_malloc( CUtlMemory::m_nAllocationCount * sizeof(T), nAlignment ); } } //----------------------------------------------------------------------------- // Memory deallocation //----------------------------------------------------------------------------- template< class T, int nAlignment > void CUtlMemoryAligned::Purge() { if ( !this->IsExternallyAllocated() ) { if ( CUtlMemory::m_pMemory ) { _aligned_free( CUtlMemory::m_pMemory ); CUtlMemory::m_pMemory = 0; } CUtlMemory::m_nAllocationCount = 0; } } #endif // UTLMEMORY_H