diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /sp/src/public/tier1/utlfixedmemory.h | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'sp/src/public/tier1/utlfixedmemory.h')
| -rw-r--r-- | sp/src/public/tier1/utlfixedmemory.h | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/sp/src/public/tier1/utlfixedmemory.h b/sp/src/public/tier1/utlfixedmemory.h new file mode 100644 index 00000000..3d92d679 --- /dev/null +++ b/sp/src/public/tier1/utlfixedmemory.h @@ -0,0 +1,354 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+// A growable memory class.
+//===========================================================================//
+
+#ifndef UTLFIXEDMEMORY_H
+#define UTLFIXEDMEMORY_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/dbg.h"
+#include "tier0/platform.h"
+
+#include "tier0/memalloc.h"
+#include "tier0/memdbgon.h"
+
+#pragma warning (disable:4100)
+#pragma warning (disable:4514)
+
+//-----------------------------------------------------------------------------
+
+#ifdef UTLFIXEDMEMORY_TRACK
+#define UTLFIXEDMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
+#define UTLFIXEDMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
+#else
+#define UTLFIXEDMEMORY_TRACK_ALLOC() ((void)0)
+#define UTLFIXEDMEMORY_TRACK_FREE() ((void)0)
+#endif
+
+
+//-----------------------------------------------------------------------------
+// The CUtlFixedMemory class:
+// A growable memory class that allocates non-sequential blocks, but is indexed sequentially
+//-----------------------------------------------------------------------------
+template< class T >
+class CUtlFixedMemory
+{
+public:
+ // constructor, destructor
+ CUtlFixedMemory( int nGrowSize = 0, int nInitSize = 0 );
+ ~CUtlFixedMemory();
+
+ // Set the size by which the memory grows
+ void Init( int nGrowSize = 0, int nInitSize = 0 );
+
+ // here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL
+ T* Base() { return NULL; }
+ const T* Base() const { return NULL; }
+
+protected:
+ struct BlockHeader_t;
+
+public:
+ class Iterator_t
+ {
+ public:
+ Iterator_t( BlockHeader_t *p, int i ) : m_pBlockHeader( p ), m_nIndex( i ) {}
+ BlockHeader_t *m_pBlockHeader;
+ intp m_nIndex;
+
+ bool operator==( const Iterator_t it ) const { return m_pBlockHeader == it.m_pBlockHeader && m_nIndex == it.m_nIndex; }
+ bool operator!=( const Iterator_t it ) const { return m_pBlockHeader != it.m_pBlockHeader || m_nIndex != it.m_nIndex; }
+ };
+ Iterator_t First() const { return m_pBlocks ? Iterator_t( m_pBlocks, 0 ) : InvalidIterator(); }
+ Iterator_t Next( const Iterator_t &it ) const
+ {
+ Assert( IsValidIterator( it ) );
+ if ( !IsValidIterator( it ) )
+ return InvalidIterator();
+
+ BlockHeader_t * RESTRICT pHeader = it.m_pBlockHeader;
+ if ( it.m_nIndex + 1 < pHeader->m_nBlockSize )
+ return Iterator_t( pHeader, it.m_nIndex + 1 );
+
+ return pHeader->m_pNext ? Iterator_t( pHeader->m_pNext, 0 ) : InvalidIterator();
+ }
+ intp GetIndex( const Iterator_t &it ) const
+ {
+ Assert( IsValidIterator( it ) );
+ if ( !IsValidIterator( it ) )
+ return InvalidIndex();
+
+ return ( intp )( HeaderToBlock( it.m_pBlockHeader ) + it.m_nIndex );
+ }
+ bool IsIdxAfter( intp i, const Iterator_t &it ) const
+ {
+ Assert( IsValidIterator( it ) );
+ if ( !IsValidIterator( it ) )
+ return false;
+
+ if ( IsInBlock( i, it.m_pBlockHeader ) )
+ return i > GetIndex( it );
+
+ for ( BlockHeader_t * RESTRICT pbh = it.m_pBlockHeader->m_pNext; pbh; pbh = pbh->m_pNext )
+ {
+ if ( IsInBlock( i, pbh ) )
+ return true;
+ }
+ return false;
+ }
+ bool IsValidIterator( const Iterator_t &it ) const { return it.m_pBlockHeader && it.m_nIndex >= 0 && it.m_nIndex < it.m_pBlockHeader->m_nBlockSize; }
+ Iterator_t InvalidIterator() const { return Iterator_t( NULL, INVALID_INDEX ); }
+
+ // element access
+ T& operator[]( intp i );
+ const T& operator[]( intp i ) const;
+ T& Element( intp i );
+ const T& Element( intp i ) const;
+
+ // Can we use this index?
+ bool IsIdxValid( intp i ) const;
+
+ // Specify the invalid ('null') index that we'll only return on failure
+ static const intp INVALID_INDEX = 0; // For use with COMPILE_TIME_ASSERT
+ static intp InvalidIndex() { return INVALID_INDEX; }
+
+ // Size
+ int NumAllocated() const;
+ int Count() const { return NumAllocated(); }
+
+ // Grows memory by max(num,growsize), and returns the allocation index/ptr
+ void Grow( int num = 1 );
+
+ // Makes sure we've got at least this much memory
+ void EnsureCapacity( int num );
+
+ // Memory deallocation
+ void Purge();
+
+protected:
+ // Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
+ void Swap( CUtlFixedMemory< T > &mem );
+
+ bool IsInBlock( intp i, BlockHeader_t *pBlockHeader ) const
+ {
+ T *p = ( T* )i;
+ const T *p0 = HeaderToBlock( pBlockHeader );
+ return p >= p0 && p < p0 + pBlockHeader->m_nBlockSize;
+ }
+
+ struct BlockHeader_t
+ {
+ BlockHeader_t *m_pNext;
+ intp m_nBlockSize;
+ };
+
+ const T *HeaderToBlock( const BlockHeader_t *pHeader ) const { return ( T* )( pHeader + 1 ); }
+ const BlockHeader_t *BlockToHeader( const T *pBlock ) const { return ( BlockHeader_t* )( pBlock ) - 1; }
+
+ BlockHeader_t* m_pBlocks;
+ int m_nAllocationCount;
+ int m_nGrowSize;
+};
+
+//-----------------------------------------------------------------------------
+// constructor, destructor
+//-----------------------------------------------------------------------------
+
+template< class T >
+CUtlFixedMemory<T>::CUtlFixedMemory( int nGrowSize, int nInitAllocationCount )
+: m_pBlocks( 0 ), m_nAllocationCount( 0 ), m_nGrowSize( 0 )
+{
+ Init( nGrowSize, nInitAllocationCount );
+}
+
+template< class T >
+CUtlFixedMemory<T>::~CUtlFixedMemory()
+{
+ Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
+//-----------------------------------------------------------------------------
+template< class T >
+void CUtlFixedMemory<T>::Swap( CUtlFixedMemory< T > &mem )
+{
+ V_swap( m_pBlocks, mem.m_pBlocks );
+ V_swap( m_nAllocationCount, mem.m_nAllocationCount );
+ V_swap( m_nGrowSize, mem.m_nGrowSize );
+}
+
+
+//-----------------------------------------------------------------------------
+// Set the size by which the memory grows - round up to the next power of 2
+//-----------------------------------------------------------------------------
+template< class T >
+void CUtlFixedMemory<T>::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ )
+{
+ Purge();
+
+ m_nGrowSize = nGrowSize;
+
+ Grow( nInitSize );
+}
+
+//-----------------------------------------------------------------------------
+// element access
+//-----------------------------------------------------------------------------
+template< class T >
+inline T& CUtlFixedMemory<T>::operator[]( intp i )
+{
+ Assert( IsIdxValid(i) );
+ return *( T* )i;
+}
+
+template< class T >
+inline const T& CUtlFixedMemory<T>::operator[]( intp i ) const
+{
+ Assert( IsIdxValid(i) );
+ return *( T* )i;
+}
+
+template< class T >
+inline T& CUtlFixedMemory<T>::Element( intp i )
+{
+ Assert( IsIdxValid(i) );
+ return *( T* )i;
+}
+
+template< class T >
+inline const T& CUtlFixedMemory<T>::Element( intp i ) const
+{
+ Assert( IsIdxValid(i) );
+ return *( T* )i;
+}
+
+
+//-----------------------------------------------------------------------------
+// Size
+//-----------------------------------------------------------------------------
+template< class T >
+inline int CUtlFixedMemory<T>::NumAllocated() const
+{
+ return m_nAllocationCount;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is element index valid?
+//-----------------------------------------------------------------------------
+template< class T >
+inline bool CUtlFixedMemory<T>::IsIdxValid( intp i ) const
+{
+#ifdef _DEBUG
+ for ( BlockHeader_t *pbh = m_pBlocks; pbh; pbh = pbh->m_pNext )
+ {
+ if ( IsInBlock( i, pbh ) )
+ return true;
+ }
+ return false;
+#else
+ return i != InvalidIndex();
+#endif
+}
+
+template< class T >
+void CUtlFixedMemory<T>::Grow( int num )
+{
+ if ( num <= 0 )
+ return;
+
+ int nBlockSize = m_nGrowSize;
+ if ( nBlockSize == 0 )
+ {
+ if ( m_nAllocationCount )
+ {
+ nBlockSize = m_nAllocationCount;
+ }
+ else
+ {
+ // Compute an allocation which is at least as big as a cache line...
+ nBlockSize = ( 31 + sizeof( T ) ) / sizeof( T );
+ Assert( nBlockSize );
+ }
+ }
+ if ( nBlockSize < num )
+ {
+ int n = ( num + nBlockSize -1 ) / nBlockSize;
+ Assert( n * nBlockSize >= num );
+ Assert( ( n - 1 ) * nBlockSize < num );
+ nBlockSize *= n;
+ }
+ m_nAllocationCount += nBlockSize;
+
+ MEM_ALLOC_CREDIT_CLASS();
+ BlockHeader_t * RESTRICT pBlockHeader = ( BlockHeader_t* )malloc( sizeof( BlockHeader_t ) + nBlockSize * sizeof( T ) );
+ if ( !pBlockHeader )
+ {
+ Error( "CUtlFixedMemory overflow!\n" );
+ }
+ pBlockHeader->m_pNext = NULL;
+ pBlockHeader->m_nBlockSize = nBlockSize;
+
+ if ( !m_pBlocks )
+ {
+ m_pBlocks = pBlockHeader;
+ }
+ else
+ {
+#if 1 // IsIdxAfter assumes that newly allocated blocks are at the end
+ BlockHeader_t * RESTRICT pbh = m_pBlocks;
+ while ( pbh->m_pNext )
+ {
+ pbh = pbh->m_pNext;
+ }
+ pbh->m_pNext = pBlockHeader;
+#else
+ pBlockHeader = m_pBlocks;
+ pBlockHeader->m_pNext = m_pBlocks;
+#endif
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Makes sure we've got at least this much memory
+//-----------------------------------------------------------------------------
+template< class T >
+inline void CUtlFixedMemory<T>::EnsureCapacity( int num )
+{
+ Grow( num - NumAllocated() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Memory deallocation
+//-----------------------------------------------------------------------------
+template< class T >
+void CUtlFixedMemory<T>::Purge()
+{
+ if ( !m_pBlocks )
+ return;
+
+ for ( BlockHeader_t *pbh = m_pBlocks; pbh; )
+ {
+ BlockHeader_t *pFree = pbh;
+ pbh = pbh->m_pNext;
+ free( pFree );
+ }
+ m_pBlocks = NULL;
+ m_nAllocationCount = 0;
+}
+
+#include "tier0/memdbgoff.h"
+
+#endif // UTLFIXEDMEMORY_H
|