#include <tier1/utlmemory.h>
#include "tier0/memdbgon.h"
CUtlMemoryBase::CUtlMemoryBase( int nSizeOfType, int nGrowSize, int nInitAllocationCount ) : m_pMemory(0),
m_nAllocationCount( nInitAllocationCount ), m_nGrowSize( nGrowSize ), m_unSizeOfElements( nSizeOfType )
{
Assert( m_unSizeOfElements > 0 );
Assert( nGrowSize >= 0 );
if (m_nAllocationCount)
{
UTLMEMORY_TRACK_ALLOC();
m_pMemory = PvAlloc( (size_t)m_nAllocationCount * m_unSizeOfElements );
}
}
CUtlMemoryBase::CUtlMemoryBase( int nSizeOfType, void * pMemory, int numElements ) : m_pMemory(pMemory),
m_nAllocationCount( numElements ), m_unSizeOfElements( nSizeOfType )
{
Assert( m_unSizeOfElements > 0 );
m_nGrowSize = EXTERNAL_BUFFER_MARKER;
}
CUtlMemoryBase::CUtlMemoryBase( int nSizeOfType, const void * pMemory, int numElements ) : m_pMemory( (void*)pMemory ),
m_nAllocationCount( numElements ), m_unSizeOfElements( nSizeOfType )
{
Assert( m_unSizeOfElements > 0 );
m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER;
}
#ifdef VALVE_RVALUE_REFS
CUtlMemoryBase::CUtlMemoryBase( CUtlMemoryBase&& src )
{
m_nGrowSize = 0;
m_pMemory = 0;
m_nAllocationCount = 0;
m_unSizeOfElements = src.m_unSizeOfElements;
Swap( src );
}
#endif
CUtlMemoryBase::~CUtlMemoryBase()
{
Purge();
}
void CUtlMemoryBase::Swap( CUtlMemoryBase &mem )
{
Assert( m_unSizeOfElements == mem.m_unSizeOfElements );
SWAP( m_nGrowSize, mem.m_nGrowSize );
SWAP( m_pMemory, mem.m_pMemory );
SWAP( m_nAllocationCount, mem.m_nAllocationCount );
SWAP( m_unSizeOfElements, mem.m_unSizeOfElements );
}
void *CUtlMemoryBase::Detach()
{
m_nAllocationCount = 0;
void *pMemory = m_pMemory;
m_pMemory = NULL;
return pMemory;
}
void CUtlMemoryBase::ConvertToGrowableMemory( int nGrowSize )
{
if ( !IsExternallyAllocated() )
return;
m_nGrowSize = nGrowSize;
if (m_nAllocationCount)
{
UTLMEMORY_TRACK_ALLOC();
MEM_ALLOC_CREDIT_CLASS();
size_t nNumBytes = (size_t)m_nAllocationCount * m_unSizeOfElements;
void *pMemory = PvAlloc( nNumBytes );
memcpy( pMemory, m_pMemory, nNumBytes );
m_pMemory = pMemory;
}
else
{
m_pMemory = NULL;
}
}
void CUtlMemoryBase::SetExternalBuffer( void * pMemory, int numElements )
{
Purge();
m_pMemory = pMemory;
m_nAllocationCount = numElements;
m_nGrowSize = EXTERNAL_BUFFER_MARKER;
}
void CUtlMemoryBase::SetExternalBuffer( const void* pMemory, int numElements )
{
Purge();
m_pMemory = const_cast<void*>( pMemory );
m_nAllocationCount = numElements;
m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER;
}
bool CUtlMemoryBase::IsExternallyAllocated() const
{
return (m_nGrowSize < 0);
}
bool CUtlMemoryBase::IsReadOnly() const
{
return (m_nGrowSize == EXTERNAL_CONST_BUFFER_MARKER);
}
void CUtlMemoryBase::SetGrowSize( int nSize )
{
Assert( !IsExternallyAllocated() );
Assert( nSize >= 0 );
m_nGrowSize = nSize;
}
int CUtlMemoryBase::NumAllocated() const
{
return m_nAllocationCount;
}
int CUtlMemoryBase::Count() const
{
return m_nAllocationCount;
}
bool CUtlMemoryBase::IsIdxValid( int i ) const
{
return (i >= 0) && (i < m_nAllocationCount);
}
int UtlMemory_CalcNewAllocationCount( int nAllocationCount, int nGrowSize, int nNewSize, int nBytesItem )
{
if ( nGrowSize )
{
nAllocationCount = ((1 + ((nNewSize - 1) / nGrowSize)) * nGrowSize);
}
else
{
if ( !nAllocationCount )
{
if ( nBytesItem > 0 )
{
nAllocationCount = (31 + nBytesItem) / nBytesItem;
}
else
{
AssertMsg1( false, "nBytesItem is %d in UtlMemory_CalcNewAllocationCount", nBytesItem );
nAllocationCount = 256;
}
}
int nMaxGrowStep = Max( 1, 256*1024*1024 / ( nBytesItem > 0 ? nBytesItem : 1 ) );
while (nAllocationCount < nNewSize)
{
#ifndef _XBOX
nAllocationCount += Min( nAllocationCount, nMaxGrowStep );
#else
int nNewAllocationCount = ( nAllocationCount * 9) / 8; if ( nNewAllocationCount > nAllocationCount )
nAllocationCount = nNewAllocationCount;
else
nAllocationCount *= 2;
#endif
}
}
return nAllocationCount;
}
void CUtlMemoryBase::Grow( int num )
{
Assert( num > 0 );
if ( IsExternallyAllocated() )
{
Assert(0);
return;
}
int nAllocationRequested = m_nAllocationCount + num;
UTLMEMORY_TRACK_FREE();
m_nAllocationCount = UtlMemory_CalcNewAllocationCount( m_nAllocationCount, m_nGrowSize, nAllocationRequested, m_unSizeOfElements );
UTLMEMORY_TRACK_ALLOC();
if (m_pMemory)
{
m_pMemory = PvRealloc( m_pMemory, (size_t)m_nAllocationCount * m_unSizeOfElements );
}
else
{
m_pMemory = PvAlloc( (size_t)m_nAllocationCount * m_unSizeOfElements );
}
}
void CUtlMemoryBase::EnsureCapacity( int num )
{
if (m_nAllocationCount >= num)
return;
if ( IsExternallyAllocated() )
{
Assert(0);
return;
}
UTLMEMORY_TRACK_FREE();
m_nAllocationCount = num;
UTLMEMORY_TRACK_ALLOC();
if (m_pMemory)
{
m_pMemory = PvRealloc( m_pMemory, (size_t)m_nAllocationCount * m_unSizeOfElements );
}
else
{
m_pMemory = PvAlloc( (size_t)m_nAllocationCount * m_unSizeOfElements );
}
}
void CUtlMemoryBase::Purge()
{
if ( !IsExternallyAllocated() )
{
if (m_pMemory)
{
UTLMEMORY_TRACK_FREE();
FreePv( m_pMemory );
m_pMemory = 0;
}
m_nAllocationCount = 0;
}
}
void CUtlMemoryBase::Purge( int numElements, bool bRealloc )
{
Assert( numElements >= 0 );
if( numElements > m_nAllocationCount )
{
Assert( numElements <= m_nAllocationCount );
return;
}
if( numElements == 0 )
{
Purge();
return;
}
if ( IsExternallyAllocated() )
{
return;
}
if( numElements == m_nAllocationCount )
{
return;
}
if( !m_pMemory )
{
Assert( m_pMemory );
return;
}
if ( bRealloc )
{
UTLMEMORY_TRACK_FREE();
m_nAllocationCount = numElements;
UTLMEMORY_TRACK_ALLOC();
MEM_ALLOC_CREDIT_CLASS();
m_pMemory = PvRealloc( m_pMemory, (size_t)m_nAllocationCount * m_unSizeOfElements );
}
else
{
m_nAllocationCount = numElements;
}
}
#ifdef DBGFLAG_VALIDATE
void CUtlMemoryBase::Validate( CValidator &validator, const char *pchName )
{
#ifdef _WIN32
validator.Push( typeid(*this).raw_name(), this, pchName );
#else
validator.Push( typeid(*this).name(), this, pchName );
#endif
if ( NULL != m_pMemory )
validator.ClaimMemory( m_pMemory );
validator.Pop();
}
#endif