initial
This commit is contained in:
966
public/resourcefile/resourcestream.h
Normal file
966
public/resourcefile/resourcestream.h
Normal file
@@ -0,0 +1,966 @@
|
||||
//===== Copyright <20> Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: Resource Stream is conceptually memory file where you write the data
|
||||
// that you want to live both on disk and in memory. The constraint then is
|
||||
// that the data must be movable in memory, since you don't know in advance,
|
||||
// when you're creating the data, what will be its start address once it gets
|
||||
// loaded. To accomplish this, we use CResourcePointer and CResourceArray
|
||||
// in places of pointers and dynamic arrays. They store offsets rather than
|
||||
// absolute addresses of the referenced objects, thus they are moveable.
|
||||
// On Intel, the available addressing modes make the access to CResourcePointer
|
||||
// as fast as pointer dereferencing in most cases. On architectures with
|
||||
// rigid addressing, adding the base address is still virtually free.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "resourcefile/schema.h"
|
||||
|
||||
#ifndef RESOURCESTREAM_H
|
||||
#define RESOURCESTREAM_H
|
||||
|
||||
|
||||
#ifdef COMPILER_MSVC
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/platform.h"
|
||||
#include "tier0/basetypes.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
class CResourceStream;
|
||||
|
||||
|
||||
inline byte *ResolveOffset( const int32 *pOffset )
|
||||
{
|
||||
int offset = *pOffset;
|
||||
return offset ? ( ( byte* )pOffset ) + offset : NULL;
|
||||
}
|
||||
|
||||
inline byte *ResolveOffsetFast( const int32 *pOffset )
|
||||
{
|
||||
int offset = *pOffset;
|
||||
AssertDbg( offset != 0 );
|
||||
return ( ( byte* )pOffset ) + offset;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CLockedResource
|
||||
{
|
||||
private:
|
||||
T *m_pData; // data; may be const
|
||||
uint m_nCount; // number of allocated data elements
|
||||
//uint m_nStride; // normally sizeof(T), but may be not
|
||||
//uint m_nClassCRC;
|
||||
public:
|
||||
CLockedResource(): m_pData( NULL ), m_nCount( 0 ) {}
|
||||
CLockedResource( T *pData, uint nCount ): m_pData( pData ), m_nCount( nCount ) {}
|
||||
|
||||
// emulates pointer arithmetics
|
||||
CLockedResource<T> operator + ( int nOffset ) { Assert( m_nCount <= (uint)nOffset); return CLockedResource<T>( m_pData + nOffset, m_nCount - (uint)nOffset ); }
|
||||
|
||||
operator const T* ()const { return m_pData; }
|
||||
operator T* () { return m_pData; }
|
||||
|
||||
T* operator ->() { return m_pData; }
|
||||
const T* operator ->() const { return m_pData; }
|
||||
|
||||
uint Count()const {return m_nCount;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CUnlockedResource
|
||||
{
|
||||
private:
|
||||
CResourceStream *m_pStream; // data; may be const
|
||||
uint32 m_nOffset;
|
||||
uint32 m_nCount; // number of allocated data elements
|
||||
//uint m_nStride; // normally sizeof(T), but may be not
|
||||
//uint m_nClassCRC;
|
||||
public:
|
||||
CUnlockedResource( ): m_pStream( NULL ), m_nOffset( 0 ), m_nCount( 0 ) {}
|
||||
CUnlockedResource( CResourceStream *pStream, T *pData, uint nCount );
|
||||
bool IsValid( )const { return m_pStream != NULL; }
|
||||
void Reset( ) { m_pStream = NULL; }
|
||||
|
||||
// emulates pointer arithmetics
|
||||
CUnlockedResource<T> operator + ( int nOffset )
|
||||
{
|
||||
Assert( m_nCount <= ( uint ) nOffset );
|
||||
return CUnlockedResource<T>( m_pStream, GetPtr() + nOffset, m_nCount - ( uint ) nOffset );
|
||||
}
|
||||
|
||||
operator const T* ( )const { return GetPtr(); }
|
||||
operator T* ( ) { return GetPtr(); }
|
||||
|
||||
T* operator ->( ) { return GetPtr(); }
|
||||
const T* operator ->( ) const { return GetPtr(); }
|
||||
|
||||
uint Count( )const { return m_nCount; }
|
||||
T* GetPtr( );
|
||||
const T* GetPtr( )const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// AT RUN-TIME ONLY the offset converts automatically into pointers to the appropritate type
|
||||
// at tool-time, you should use LinkSource_t and LinkTarget_t
|
||||
class CResourcePointerBase
|
||||
{
|
||||
protected:
|
||||
int32 m_nOffset;
|
||||
public:
|
||||
CResourcePointerBase() : m_nOffset( 0 ) {}
|
||||
|
||||
bool operator == ( int zero )const
|
||||
{
|
||||
AssertDbg( zero == 0 );
|
||||
return m_nOffset == zero;
|
||||
}
|
||||
|
||||
bool IsNull()const
|
||||
{
|
||||
return m_nOffset == 0;
|
||||
}
|
||||
|
||||
int32 NotNull()const
|
||||
{
|
||||
return m_nOffset;
|
||||
}
|
||||
|
||||
int32 GetOffset() const
|
||||
{
|
||||
return m_nOffset;
|
||||
}
|
||||
|
||||
const byte* GetUncheckedRawPtr() const
|
||||
{
|
||||
// assumes non-null; returns garbage if this is a null pointer
|
||||
return ResolveOffsetFast( &m_nOffset );
|
||||
}
|
||||
|
||||
byte* GetUncheckedRawPtr()
|
||||
{
|
||||
// assumes non-null; returns garbage if this is a null pointer
|
||||
return ResolveOffsetFast( &m_nOffset );
|
||||
}
|
||||
|
||||
const byte* GetRawPtr() const
|
||||
{
|
||||
return ResolveOffset( &m_nOffset );
|
||||
}
|
||||
|
||||
byte* GetRawPtr()
|
||||
{
|
||||
return ResolveOffset( &m_nOffset );
|
||||
}
|
||||
|
||||
void SetRawPtr( const void* p )
|
||||
{
|
||||
if ( p == NULL )
|
||||
{
|
||||
m_nOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
intp nOffset = ( intp )p - ( intp )&m_nOffset;
|
||||
m_nOffset = ( int32 )nOffset;
|
||||
AssertDbg( m_nOffset == nOffset );
|
||||
}
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
{
|
||||
m_nOffset = 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class CResourcePointer: public CResourcePointerBase
|
||||
{
|
||||
public:
|
||||
FORCEINLINE const T* GetUncheckedPtr() const
|
||||
{
|
||||
// assumes non-null; returns garbage if this is a null pointer
|
||||
AssertDbg( m_nOffset != 0 );
|
||||
byte *ptr = ResolveOffsetFast( &m_nOffset );
|
||||
return ( const T* )ptr;
|
||||
}
|
||||
|
||||
FORCEINLINE const T* GetPtr() const
|
||||
{
|
||||
byte *ptr = ResolveOffset( &m_nOffset );
|
||||
return ( const T* )ptr;
|
||||
}
|
||||
|
||||
FORCEINLINE operator const T*() const
|
||||
{
|
||||
return GetPtr();
|
||||
}
|
||||
|
||||
FORCEINLINE const T* operator->() const
|
||||
{
|
||||
return GetPtr();
|
||||
}
|
||||
|
||||
void operator = ( const T* pT )
|
||||
{
|
||||
SetRawPtr( pT );
|
||||
}
|
||||
|
||||
void SetPtr( const T* pT )
|
||||
{
|
||||
SetRawPtr( pT );
|
||||
}
|
||||
|
||||
// FIXME: Should these be in a 'CResourceWritablePointer' subclass?
|
||||
// There are plenty of cases where we know that a CResourcePointer should be read-only
|
||||
|
||||
public:
|
||||
FORCEINLINE T* GetUncheckedPtr()
|
||||
{
|
||||
// assumes non-null; returns garbage if this is a null pointer
|
||||
Assert( m_nOffset != 0 );
|
||||
byte *ptr = ResolveOffsetFast( &m_nOffset );
|
||||
return ( T* )ptr;
|
||||
}
|
||||
|
||||
FORCEINLINE T* GetPtr()
|
||||
{
|
||||
byte *ptr = ResolveOffset( &m_nOffset );
|
||||
return ( T* )ptr;
|
||||
}
|
||||
|
||||
FORCEINLINE operator T*()
|
||||
{
|
||||
return GetPtr();
|
||||
}
|
||||
|
||||
FORCEINLINE T* operator->()
|
||||
{
|
||||
return GetPtr();
|
||||
}
|
||||
|
||||
public:
|
||||
void Unsafe_OutOfBoundsAllocate()
|
||||
{
|
||||
SetPtr( new T() );
|
||||
}
|
||||
|
||||
void Unsafe_OutOfBoundsFree()
|
||||
{
|
||||
delete GetPtr();
|
||||
}
|
||||
|
||||
void SwapBytes()
|
||||
{
|
||||
m_nOffset = DWordSwapC( m_nOffset );
|
||||
}
|
||||
};
|
||||
|
||||
// never construct this - only the Resource stream may construct or load data that contains ResourceArray or ResourcePointer; use LockedResource or naked pointer or CUtlBuffer or something like that instead
|
||||
|
||||
class CResourceArrayBase
|
||||
{
|
||||
public:
|
||||
CResourceArrayBase()
|
||||
{
|
||||
m_nOffset = 0;
|
||||
m_nCount = 0;
|
||||
}
|
||||
|
||||
bool operator == ( int zero )const
|
||||
{
|
||||
AssertDbg( zero == 0 );
|
||||
return m_nOffset == zero;
|
||||
}
|
||||
|
||||
bool IsNull()const
|
||||
{
|
||||
return m_nOffset == 0;
|
||||
}
|
||||
|
||||
int32 NotNull()const
|
||||
{
|
||||
return m_nOffset;
|
||||
}
|
||||
|
||||
const byte* GetRawPtr() const
|
||||
{
|
||||
// validate
|
||||
return ResolveOffset( &m_nOffset );
|
||||
}
|
||||
|
||||
byte* GetRawPtr()
|
||||
{
|
||||
// validate
|
||||
return ResolveOffset( &m_nOffset );
|
||||
}
|
||||
|
||||
int Count() const
|
||||
{
|
||||
return m_nCount;
|
||||
}
|
||||
|
||||
void WriteDirect( int nCount, void *pData )
|
||||
{
|
||||
if ( pData == NULL )
|
||||
{
|
||||
AssertDbg( nCount == 0 );
|
||||
m_nOffset = 0;
|
||||
m_nCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nOffset = ((intp)pData) - (intp)&m_nOffset;
|
||||
m_nCount = nCount;
|
||||
}
|
||||
}
|
||||
|
||||
void SwapMemberBytes()
|
||||
{
|
||||
m_nCount = DWordSwapC( m_nCount );
|
||||
m_nOffset = DWordSwapC( m_nOffset );
|
||||
}
|
||||
|
||||
private:
|
||||
CResourceArrayBase(const CResourceArrayBase&rThat ){} // private: we don't want to recompute offsets every time we copy a structure
|
||||
protected:
|
||||
int32 m_nOffset;
|
||||
uint32 m_nCount;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
class CResourceArray: public CResourceArrayBase
|
||||
{
|
||||
public:
|
||||
CResourceArray(): CResourceArrayBase() {}
|
||||
|
||||
private:
|
||||
CResourceArray( const CResourceArray<T>&rThat ){} // private: we don't want to recompute offsets every time we copy a structure
|
||||
public:
|
||||
const T& operator []( int nIndex ) const
|
||||
{
|
||||
AssertDbg( (uint)nIndex < m_nCount );
|
||||
return this->GetPtr()[nIndex];
|
||||
}
|
||||
|
||||
T& operator []( int nIndex )
|
||||
{
|
||||
AssertDbg( (uint)nIndex < m_nCount );
|
||||
return this->GetPtr()[nIndex];
|
||||
}
|
||||
|
||||
const T& Element( int nIndex ) const
|
||||
{
|
||||
AssertDbg( (uint)nIndex < m_nCount );
|
||||
return this->GetPtr()[nIndex];
|
||||
}
|
||||
|
||||
T& Element( int nIndex )
|
||||
{
|
||||
AssertDbg( (uint)nIndex < m_nCount );
|
||||
return this->GetPtr()[nIndex];
|
||||
}
|
||||
|
||||
CResourceArray<T>& operator = ( const CLockedResource<T> & lockedResource )
|
||||
{
|
||||
m_nOffset = ( lockedResource.Count() ) ? ( ((intp)(const T*)lockedResource) - (intp)&m_nOffset ) : 0;
|
||||
m_nCount = lockedResource.Count();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CResourceArray<T>& operator = ( const CResourceArray<T> & that )
|
||||
{
|
||||
m_nOffset = ( that.Count() ) ? ( ((intp)(const T*)that.GetPtr()) - (intp)&m_nOffset ) : 0;
|
||||
m_nCount = that.Count();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T* GetPtr() const
|
||||
{
|
||||
return ( const T* )GetRawPtr();
|
||||
}
|
||||
|
||||
T* GetPtr()
|
||||
{
|
||||
return ( T* )GetRawPtr();
|
||||
}
|
||||
|
||||
const T* Base() const
|
||||
{
|
||||
return ( const T* )GetRawPtr();
|
||||
}
|
||||
|
||||
T* Base()
|
||||
{
|
||||
return ( T* )GetRawPtr();
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return m_nCount == 0;
|
||||
}
|
||||
|
||||
operator CLockedResource<T> () {return CLockedResource<T>( GetPtr(), Count() ) ; }
|
||||
|
||||
// Temporary functions
|
||||
|
||||
void Unsafe_OutOfBoundsAllocate( int nCount )
|
||||
{
|
||||
const T* pAlloc = new T[nCount];
|
||||
m_nOffset = ((intp)(const T*)pAlloc) - (intp)&m_nOffset;
|
||||
m_nCount = nCount;
|
||||
}
|
||||
|
||||
void Unsafe_OutOfBoundsPurgeAndFreeRPs()
|
||||
{
|
||||
for ( uint32 i = 0; i < m_nCount; ++i )
|
||||
{
|
||||
Element(i).Unsafe_OutOfBoundsFree();
|
||||
}
|
||||
|
||||
delete[] GetPtr();
|
||||
}
|
||||
|
||||
// Remove all the NULL pointers from this resource array and shorten it (without changing any allocations)
|
||||
// (assumes that the elements of the array can be equality-tested with NULL)
|
||||
inline void CoalescePointerArrayInPlace()
|
||||
{
|
||||
int nValidElements = 0;
|
||||
int nArrayLen = Count();
|
||||
T* pBase = GetPtr();
|
||||
|
||||
for ( int i = 0; i < nArrayLen; ++i )
|
||||
{
|
||||
if ( pBase[i] == 0 )
|
||||
continue;
|
||||
|
||||
if ( nValidElements != i )
|
||||
{
|
||||
pBase[nValidElements].SetRawPtr( pBase[i].GetRawPtr() );
|
||||
}
|
||||
|
||||
nValidElements++;
|
||||
}
|
||||
|
||||
m_nCount = nValidElements;
|
||||
}
|
||||
|
||||
// Enable support for range-based loops in C++ 11
|
||||
inline T* begin()
|
||||
{
|
||||
return GetPtr();
|
||||
}
|
||||
|
||||
inline const T* begin() const
|
||||
{
|
||||
return GetPtr( );
|
||||
}
|
||||
|
||||
inline T* end()
|
||||
{
|
||||
return GetPtr() + m_nCount;
|
||||
}
|
||||
|
||||
inline const T* end() const
|
||||
{
|
||||
return GetPtr( ) + m_nCount;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// this class may be useful at runtime to use fast serialize interface (without data linking)
|
||||
//
|
||||
class CResourceStream
|
||||
{
|
||||
public:
|
||||
// Constructor, destructor
|
||||
CResourceStream( );
|
||||
virtual ~CResourceStream( ) {} // make sure to implement proper cleanup in derived classes
|
||||
|
||||
// Methods used to allocate space in the stream
|
||||
// just use Allocate<uint8>(100) to simply allocate 100 bytes of crap
|
||||
void *AllocateBytes( uint nCount );
|
||||
template <typename T> CLockedResource<T> Allocate( uint count = 1 );
|
||||
template <typename T> CUnlockedResource<T> AllocateUnaligned( uint count = 1 );
|
||||
|
||||
// Methods that write data into the stream
|
||||
template <typename T> CLockedResource<T> Write( const T &x );
|
||||
template <typename T> CUnlockedResource<T> WriteUnaligned( const T &x );
|
||||
CLockedResource<float> WriteFloat( float x );
|
||||
CLockedResource<uint64> WriteU64( uint64 x );
|
||||
CLockedResource<uint32> WriteU32( uint32 x );
|
||||
CLockedResource<uint16> WriteU16( uint16 x );
|
||||
CLockedResource<uint8> WriteByte( byte x );
|
||||
CLockedResource<char> WriteString( const char *pString );
|
||||
CLockedResource<char> WriteStringMaxLen( const char *pString, int nMaxLen ); // will never read beyond pString[nMaxLen-1] and will force-null-terminate if necessary
|
||||
|
||||
// Methods to force alignment of the next data written into the stream
|
||||
void Align( uint nAlignment, int nOffset = 0 );
|
||||
void AlignPointer();
|
||||
|
||||
// How much data have we written into the stream?
|
||||
uint32 Tell() const;
|
||||
uint32 Tell( const void * pPast )const;
|
||||
const void *TellPtr() const;
|
||||
void Rollback( uint32 nPreviousTell );
|
||||
void Rollback( const void *pPreviousTell );
|
||||
|
||||
void* Compile( );
|
||||
template <class Memory>
|
||||
void* CompileToMemory( Memory &memory );
|
||||
uint GetTotalSize() const;
|
||||
void Barrier() {} // no pointers crossing barriers allowed! all pointers are invalidated
|
||||
void PrintStats();
|
||||
void ClearStats();
|
||||
|
||||
// This is the max alignment ever used within the stream
|
||||
uint GetStreamAlignment() const;
|
||||
|
||||
void* GetDataPtr( uint Offset = 0 );
|
||||
template <typename T> T* GetDataPtrTypeAligned( uint Offset );
|
||||
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
void EnsureAvailable( uint nAddCapacity )
|
||||
{
|
||||
Assert( nAddCapacity < 0x40000000 ); // we don't support >1Gb of data yet
|
||||
uint nNewCommit = m_nUsed + nAddCapacity;
|
||||
if ( nNewCommit > m_nCommitted )
|
||||
{
|
||||
Commit( nNewCommit ); // Commit is only called when necessary, as it may be expensive
|
||||
}
|
||||
}
|
||||
// the only logic entry the derived class needs to reimplement, besides constructor+destructor pair.
|
||||
// depending on how expensive it is to call this function, it may commit (allocate) large chunks of extra memory, that's totally ok
|
||||
virtual void Commit( uint nNewCommit ) = 0;
|
||||
|
||||
template <typename T> friend class CUnlockedResource;
|
||||
|
||||
protected:
|
||||
uint8 *m_pData; // the reserved virtual address space address; or just the start of allocated block of memory if virtual memory is not being used
|
||||
|
||||
uint m_nCommitted; // how much memory was already committed (or allocated, in case no virtual memory is being used)
|
||||
uint m_nUsed; // this is the amount of currently used/allocated data, in bytes; may be unaligned
|
||||
|
||||
uint m_nAlignBits; // the ( max alignment - 1 ) of the current block of data
|
||||
uint m_nMaxAlignment;
|
||||
};
|
||||
|
||||
|
||||
class CResourceStreamVM: public CResourceStream
|
||||
{
|
||||
public:
|
||||
// Constructor, destructor
|
||||
CResourceStreamVM( uint nReserveSize = 16 * 1024 * 1024 );
|
||||
virtual ~CResourceStreamVM( ) OVERRIDE;
|
||||
void CloneStream( CResourceStreamVM& copyFromStream );
|
||||
protected:
|
||||
virtual void Commit( uint nNewCommit ) OVERRIDE;
|
||||
void ReserveVirtualMemory( uint nAddressSize );
|
||||
void ReleaseVirtualMemory( );
|
||||
enum
|
||||
{
|
||||
COMMIT_STEP = 64 * 1024
|
||||
};
|
||||
protected:
|
||||
uint m_nReserved; // the reserved virtual address space for the block of data
|
||||
};
|
||||
|
||||
|
||||
// use this class to create resources efficiently in runtime using your own allocator
|
||||
// supply a fixed buffer; it belongs to the caller
|
||||
class CResourceStreamFixed: public CResourceStream
|
||||
{
|
||||
private:
|
||||
bool m_bOwnMemory;
|
||||
public:
|
||||
CResourceStreamFixed( uint nPreallocateDataSize );// NOTE: the preallocated data is Zeroed in this constructor
|
||||
CResourceStreamFixed( void *pPreallocatedData, uint nPreallocatedDataSize ); // NOTE: the preallocated data is Zeroed in this constructor
|
||||
virtual ~CResourceStreamFixed() OVERRIDE;
|
||||
|
||||
int GetSlack(); // remaining bytes
|
||||
virtual void Commit( uint nNewCommit );
|
||||
};
|
||||
|
||||
class CResourceStreamGrowable: public CResourceStream
|
||||
{
|
||||
public:
|
||||
CResourceStreamGrowable( uint nReserveDataSize );
|
||||
~CResourceStreamGrowable( );
|
||||
|
||||
virtual void Commit( uint nNewCommit );
|
||||
uint8 *Detach( )
|
||||
{
|
||||
uint8 *pData = m_pData;
|
||||
m_pData = 0;
|
||||
m_nCommitted = 0;
|
||||
m_nUsed = 0;
|
||||
m_pData = NULL;
|
||||
return pData;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CLockedResourceAutoAggregator
|
||||
{
|
||||
protected:
|
||||
CResourceStreamVM *m_pStream;
|
||||
const void * m_pTellStart;
|
||||
uint m_nTellStart;
|
||||
public:
|
||||
CLockedResourceAutoAggregator( CResourceStreamVM *pStream, const void * pTellStart )
|
||||
{
|
||||
m_pStream = pStream;
|
||||
m_pTellStart = pTellStart;
|
||||
m_nTellStart = pStream->Tell( pTellStart );
|
||||
}
|
||||
|
||||
CLockedResource<uint8> GetAggregate()
|
||||
{
|
||||
return CLockedResource<uint8>( ( uint8* )m_pTellStart, m_pStream->Tell() - m_nTellStart );
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Specialization for strings
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CResourceString: public CResourcePointer<char>
|
||||
{
|
||||
public:
|
||||
CResourceString& operator = ( const CLockedResource<char> & lockedCharResource )
|
||||
{
|
||||
SetPtr( (const char*)lockedCharResource );
|
||||
return *this;
|
||||
}
|
||||
|
||||
CResourceString& operator = ( const CResourcePointerBase & lockedCharResource )
|
||||
{
|
||||
SetPtr( ( const char* )lockedCharResource.GetRawPtr() );
|
||||
return *this;
|
||||
}
|
||||
|
||||
// empty strings can be serialized as a null pointer (instead of a pointer to '\0')
|
||||
|
||||
const char* GetPtr() const
|
||||
{
|
||||
if ( GetRawPtr() == NULL )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( const char* )GetRawPtr();
|
||||
}
|
||||
}
|
||||
|
||||
char* GetPtr()
|
||||
{
|
||||
if ( GetRawPtr() == NULL )
|
||||
{
|
||||
return ( char* )"";
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( char* )GetRawPtr();
|
||||
}
|
||||
}
|
||||
|
||||
operator const char* ()const
|
||||
{
|
||||
if ( GetRawPtr() == NULL )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( char* )GetRawPtr();
|
||||
}
|
||||
}
|
||||
|
||||
void Unsafe_OutOfBoundsCopy( const char* pStr )
|
||||
{
|
||||
int nLen = V_strlen(pStr);
|
||||
char* pAlloc = new char[nLen+1];
|
||||
V_strcpy( pAlloc, pStr );
|
||||
SetPtr( pAlloc );
|
||||
}
|
||||
|
||||
bool IsEmpty() const
|
||||
{
|
||||
return IsNull() || !*GetUncheckedRawPtr();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// Disable comparison operators for ResourceStrings, otherwise they'll
|
||||
// be implicitly converted to char* (we don't want to actually implement
|
||||
// these because it's ambiguous whether it's case-sensitive or not.
|
||||
bool operator==( const CResourceString &rhs ) const;
|
||||
bool operator!=( const CResourceString &rhs ) const;
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Inline methods
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline CLockedResource<T> CResourceStream::Allocate( uint nCount )
|
||||
{
|
||||
// TODO: insert reflection code here
|
||||
uint nAlignment = VALIGNOF( T );
|
||||
Align( nAlignment );
|
||||
T *ptr = AllocateUnaligned< T >( nCount );
|
||||
// Construct
|
||||
for ( uint i = 0; i < nCount; i++ )
|
||||
{
|
||||
Construct< T >( &ptr[ i ] );
|
||||
}
|
||||
|
||||
return CLockedResource<T>( ptr, nCount );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline CUnlockedResource<T> CResourceStream::AllocateUnaligned( uint nCount )
|
||||
{
|
||||
// Allocate
|
||||
return CUnlockedResource< T >( this, ( T* )AllocateBytes( nCount * sizeof( T ) ), nCount );
|
||||
}
|
||||
|
||||
inline void CResourceStream::AlignPointer()
|
||||
{
|
||||
Align( sizeof( intp ) );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline CUnlockedResource<T> CResourceStream::WriteUnaligned( const T &x )
|
||||
{
|
||||
CUnlockedResource<T> pMemory = AllocateUnaligned<T>( );
|
||||
V_memcpy( pMemory, &x, sizeof( T ) );
|
||||
return pMemory;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline CLockedResource<T> CResourceStream::Write( const T &x )
|
||||
{
|
||||
CLockedResource<T> memory = Allocate<T>();
|
||||
*memory = x;
|
||||
return memory;
|
||||
}
|
||||
|
||||
inline CLockedResource<float> CResourceStream::WriteFloat( float x )
|
||||
{
|
||||
return Write( x );
|
||||
}
|
||||
|
||||
|
||||
inline CLockedResource<uint64> CResourceStream::WriteU64( uint64 x )
|
||||
{
|
||||
return Write( x );
|
||||
}
|
||||
|
||||
inline CLockedResource<uint32> CResourceStream::WriteU32( uint32 x )
|
||||
{
|
||||
return Write( x );
|
||||
}
|
||||
|
||||
inline CLockedResource<uint16> CResourceStream::WriteU16( uint16 x )
|
||||
{
|
||||
return Write( x );
|
||||
}
|
||||
|
||||
inline CLockedResource<uint8> CResourceStream::WriteByte( byte x )
|
||||
{
|
||||
return Write( x );
|
||||
}
|
||||
|
||||
inline CLockedResource<char> CResourceStream::WriteString( const char *pString )
|
||||
{
|
||||
int nLength = pString ? V_strlen( pString ) : 0;
|
||||
|
||||
if ( nLength == 0 )
|
||||
{
|
||||
return CLockedResource<char>( NULL, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
CLockedResource<char> memory = Allocate<char>(nLength+1);
|
||||
memcpy( (char*)memory, pString, nLength+1 );
|
||||
return memory;
|
||||
}
|
||||
}
|
||||
|
||||
inline CLockedResource<char> CResourceStream::WriteStringMaxLen( const char *pString, int nMaxLen )
|
||||
{
|
||||
int nStrLen = 0;
|
||||
while ( pString && nStrLen < nMaxLen && pString[nStrLen] != '\0' )
|
||||
{
|
||||
nStrLen++;
|
||||
}
|
||||
|
||||
if ( nStrLen == 0 )
|
||||
{
|
||||
return CLockedResource<char>( NULL, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
CLockedResource<char> memory = Allocate<char>( nStrLen + 1 ); // +1 for null term
|
||||
memcpy( (char*)memory, pString, nStrLen );
|
||||
((char*)memory)[nStrLen] = '\0';
|
||||
return memory;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32 CResourceStream::Tell() const
|
||||
{
|
||||
return m_nUsed;
|
||||
}
|
||||
|
||||
|
||||
inline void CResourceStream::Rollback( uint32 nPreviousTell )
|
||||
{
|
||||
Assert( nPreviousTell <= m_nUsed );
|
||||
m_nUsed = nPreviousTell;
|
||||
}
|
||||
|
||||
inline void CResourceStream::Rollback( const void *pPreviousTell )
|
||||
{
|
||||
Assert( pPreviousTell > m_pData && pPreviousTell <= m_pData + m_nUsed );
|
||||
m_nUsed = ( ( uint8* ) pPreviousTell ) - m_pData;
|
||||
}
|
||||
|
||||
|
||||
inline uint32 CResourceStream::Tell( const void * pPast )const
|
||||
{
|
||||
// we do not reallocate the reserved memory , so the pointers do not invalidate and m_pData stays the same, and all absolute addresses stay the same in memory
|
||||
uint nTell = uintp( pPast ) - uintp( m_pData );
|
||||
AssertDbg( nTell <= m_nUsed );
|
||||
return nTell;
|
||||
}
|
||||
|
||||
inline const void *CResourceStream::TellPtr() const
|
||||
{
|
||||
return m_pData + m_nUsed;
|
||||
}
|
||||
|
||||
inline void* CResourceStream::Compile( )
|
||||
{
|
||||
return m_pData;
|
||||
}
|
||||
|
||||
template< class Memory >
|
||||
inline void* CResourceStream::CompileToMemory( Memory &memory )
|
||||
{
|
||||
memory.Init( 0, GetTotalSize() );
|
||||
V_memcpy( memory.Base(), Compile(), GetTotalSize() );
|
||||
return memory.Base();
|
||||
}
|
||||
|
||||
inline uint CResourceStream::GetTotalSize() const
|
||||
{
|
||||
return m_nUsed;
|
||||
}
|
||||
|
||||
inline uint CResourceStream::GetStreamAlignment() const
|
||||
{
|
||||
return m_nMaxAlignment;
|
||||
}
|
||||
|
||||
inline void* CResourceStream::GetDataPtr( uint nOffset )
|
||||
{
|
||||
if ( nOffset > m_nUsed )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_pData + nOffset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void CResourceStream::Clear()
|
||||
{
|
||||
V_memset( m_pData, 0, m_nCommitted );
|
||||
m_nUsed = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T* CResourceStream::GetDataPtrTypeAligned( uint Offset )
|
||||
{
|
||||
uint nAlignment = VALIGNOF( T );
|
||||
Offset += ( ( 0 - Offset ) & ( nAlignment - 1 ) );
|
||||
return ( T* ) GetDataPtr( Offset );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline const T* OffsetPointer( const T *p, intp nOffsetBytes )
|
||||
{
|
||||
return p ? ( const T* )( intp( p ) + nOffsetBytes ) : NULL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T* ConstCastOffsetPointer( const T *p, intp nOffsetBytes )
|
||||
{
|
||||
return p ? ( T* ) ( intp( p ) + nOffsetBytes ) : NULL;
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
inline CLockedResource< T > CloneArray( CResourceStream *pStream, const T *pArray, uint nCount )
|
||||
{
|
||||
if ( nCount > 0 && pArray )
|
||||
{
|
||||
CLockedResource< T > pOut = pStream->Allocate< T >( nCount );
|
||||
V_memcpy( pOut, pArray, nCount * sizeof( T ) );
|
||||
return pOut;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CLockedResource< T >( );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline int CResourceStreamFixed::GetSlack( )
|
||||
{
|
||||
return m_nCommitted - m_nUsed;
|
||||
}
|
||||
|
||||
|
||||
template < typename T >
|
||||
CUnlockedResource< T >::CUnlockedResource( CResourceStream *pStream, T *pData, uint nCount ):
|
||||
m_pStream( pStream ),
|
||||
m_nOffset( ( ( uint8* ) pData ) - pStream->m_pData ),
|
||||
m_nCount( nCount )
|
||||
{
|
||||
AssertDbg( ( ( uint8* ) pData ) >= pStream->m_pData && ( ( uint8* ) ( pData + nCount ) <= pStream->m_pData + pStream->m_nUsed ) );
|
||||
AssertDbg( m_nOffset <= pStream->m_nUsed && m_nOffset + nCount * sizeof( T ) <= pStream->m_nUsed );
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
inline T* CUnlockedResource< T >::GetPtr( )
|
||||
{
|
||||
return ( T* )m_pStream->GetDataPtr( m_nOffset );
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
inline const T* CUnlockedResource< T >::GetPtr( )const
|
||||
{
|
||||
return ( const T * )m_pStream->GetDataPtr( m_nOffset );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // RESOURCESTREAM_H
|
||||
Reference in New Issue
Block a user