csgo-2018-source/public/tier1/utlbufferstrider.h
2021-07-24 21:11:47 -07:00

246 lines
5.6 KiB
C++

//====== Copyright (c) Valve Corporation, All rights reserved. =======//
#ifndef TIER1_UTL_BUFFER_STRIDER_HDR
#define TIER1_UTL_BUFFER_STRIDER_HDR
#include "tier1/strtools.h"
//#include "tier0/memdbg_for_headers.h"
template< class T, class A >
class CUtlVector;
class CBufferStrider
{
public:
CBufferStrider( void *pBuffer );
template <typename T> T *Stride( int nCount = 1 );
template <typename T> T StrideUnaligned( );
template <typename T> void StrideUnaligned( T* pOut, int nCount = 1 );
char* StrideString( );
char* StrideString( const void *pEnd );
template <typename T> T Peek( ){ return *(T*)Get(); }
uint8 *Get(){ return m_pBuffer; }
void Set( void *p ){ m_pBuffer = ( uint8 *)p; }
void Align( uint nAlignment ){ m_pBuffer = ( uint8* )( ( uintp( m_pBuffer ) + nAlignment - 1 ) & ~uintp( nAlignment - 1 ) ); }
protected:
uint8 *m_pBuffer;
};
template <typename T>
inline T *CBufferStrider::Stride( int nCount )
{
uint nAlignMask = VALIGNOF( T ) - 1; NOTE_UNUSED( nAlignMask );
AssertDbg( !( uintp( m_pBuffer ) & nAlignMask ) );
T* p = ( T* ) m_pBuffer;
m_pBuffer += sizeof( T ) * nCount;
return p;
}
template <typename T>
inline T CBufferStrider::StrideUnaligned( )
{
T out;
memcpy( &out, m_pBuffer, sizeof( T ) );
m_pBuffer += sizeof( T );
return out;
}
template <typename T>
inline void CBufferStrider::StrideUnaligned( T* pOut, int nCount )
{
memcpy( pOut, m_pBuffer, sizeof( T ) * nCount );
m_pBuffer += sizeof( T ) * nCount;
}
inline char* CBufferStrider::StrideString( const void *pEnd )
{
uint8 *pNextItem = m_pBuffer;
do
{
if ( pNextItem >= ( uint8* ) pEnd )
{
return NULL; // we steppend past end of buffer
}
}
while ( *( pNextItem++ ) );
// found end of string
char *pString = ( char* ) m_pBuffer;
m_pBuffer = pNextItem;
return pString;
}
inline char* CBufferStrider::StrideString( )
{
uint8 *pNextItem = m_pBuffer;
while ( *( pNextItem++ ) ) // this will crash in case of malformed (no terminating NULL) buffer
{
continue;
}
// found end of string
char *pString = ( char* ) m_pBuffer;
m_pBuffer = pNextItem;
return pString;
}
inline
CBufferStrider::CBufferStrider( void *pBuffer )
: m_pBuffer( ( uint8* ) pBuffer )
{
}
#define MULTIBUFFER_ASSERTS
class CMultiBufferCounter
{
public:
CMultiBufferCounter( )
:m_nByteCount( 0 )
#ifdef MULTIBUFFER_ASSERTS
, m_nMaxAlignment( 0 )
, m_nRunAlignment( 0xFFFFFFFF )
#endif
{}
template <typename T>
T* operator()( T *& pDummy, uint nCount )
{
#ifdef MULTIBUFFER_ASSERTS
const uint nAlignMask = VALIGNOF( T ) - 1;
Assert( m_nRunAlignment >= nAlignMask );
m_nRunAlignment &= nAlignMask;
m_nMaxAlignment |= nAlignMask;
#endif
m_nByteCount += sizeof( T ) * nCount;
return NULL; // we didn't allocate anything yet!
}
template< typename T, typename A >
T* operator()( T*& pDummy, const CUtlVector< T, A > &arr )
{
( *this )( pDummy, arr.Count( ) );
return NULL; // we didn't allocate anything yet
}
char *String( const char *& pDummy, const char *pSourceString )
{
if ( pSourceString )
{
( *this )( pDummy, uint( V_strlen( pSourceString ) + 1 ) );
}
return NULL; // we didn't allocate anything yet
}
uint GetByteCount( )const { return m_nByteCount; }
protected:
uint m_nByteCount;
#ifdef MULTIBUFFER_ASSERTS
uint m_nMaxAlignment;
uint m_nRunAlignment;
#endif
};
class CMultiBufferStrider: public CBufferStrider
{
public:
CMultiBufferStrider( void *pBuffer ): CBufferStrider( pBuffer ){}
template <typename T>
T* operator() ( T*& refPtr, uint nCount )
{
refPtr = nCount ? Stride< T >( nCount ) : NULL;
return refPtr;
}
template < typename T, typename A >
T* operator()( T *&refPtr, const CUtlVector< T, A > &arr )
{
if ( arr.IsEmpty( ) )
{
refPtr = NULL;
}
else
{
refPtr = Stride< T >( arr.Count( ) );
V_memcpy( refPtr, arr.Base( ), sizeof( T ) * arr.Count( ) );
}
return refPtr;
}
char *String( const char *& refPtr, const char *pSourceString )
{
if ( pSourceString )
{
uint nBufLen = V_strlen( pSourceString ) + 1;
char *pOut = const_cast< char* >( ( *this )( refPtr, nBufLen ) );
V_memcpy( pOut, pSourceString, nBufLen );
AssertDbg( refPtr == pOut );
return pOut;
}
else
{
return NULL; // we didn't allocate anything
}
}
};
//////////////////////////////////////////////////////////////////////////
// Derive from this buffer and override function Enum( T& ) that should
// enumerate all the pointers and sizes of buffers to be allocated
//
template <typename Derived>
class CMultiBufferHelper
{
public:
CMultiBufferHelper( )
{
m_pMultiBuffer = NULL;
m_nMultiBufferSize = 0;
}
~CMultiBufferHelper( )
{
if ( m_pMultiBuffer )
{
MemAlloc_FreeAligned( m_pMultiBuffer );
m_pMultiBuffer = NULL;
m_nMultiBufferSize = 0;
}
}
uint8 *GetBuffer( ) { return m_pMultiBuffer; }
uint GetBufferSize( ) { return m_nMultiBufferSize; }
uint8 *TakeBuffer( )
{
// forget the buffer
uint8 *pBuffer = m_pMultiBuffer;
m_pMultiBuffer = NULL;
m_nMultiBufferSize = 0;
return pBuffer;
}
protected:
template <typename Ctx >
void ReallocateMultiBuffer( Ctx &context )
{
if ( m_pMultiBuffer )
{
MemAlloc_FreeAligned( m_pMultiBuffer );
}
CMultiBufferCounter byteCounter;
static_cast< Derived* >( this )->OnAllocateMultiBuffer( byteCounter, context );
m_nMultiBufferSize = byteCounter.GetByteCount( );
m_pMultiBuffer = ( uint8* )MemAlloc_AllocAligned( m_nMultiBufferSize, 16 );
CMultiBufferStrider bufferStrider( m_pMultiBuffer );
static_cast< Derived* >( this )->OnAllocateMultiBuffer( bufferStrider, context );
Assert( m_pMultiBuffer + m_nMultiBufferSize == bufferStrider.Get( ) );
}
protected:
uint8 *m_pMultiBuffer;
uint m_nMultiBufferSize;
};
#endif