You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
467 lines
13 KiB
467 lines
13 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//============================================================================= |
|
|
|
#ifndef GCRECORD_H |
|
#define GCRECORD_H |
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#include "schema.h" |
|
|
|
#include "tier0/memdbgon.h" |
|
namespace GCSDK |
|
{ |
|
#pragma pack( push, 1 ) |
|
|
|
class CRecordInfo; |
|
|
|
//----------------------------------------------------------------------------- |
|
// VarFieldBlockInfo_t |
|
// Tracks a block of memory used to hold all the variable-length |
|
// fields for a record. |
|
//----------------------------------------------------------------------------- |
|
struct VarFieldBlockInfo_t |
|
{ |
|
union |
|
{ |
|
// Take up 64-bits of space now even though |
|
// pointers are still 32 bits |
|
uint8* m_pubBlock; |
|
uint64 _unused; |
|
}; |
|
uint32 m_cubBlock; // how much is in this block? |
|
uint32 m_cubBlockFree; // how much in this block is free? |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// VarField_t |
|
// Data format for a variable field entry in a DS record |
|
// For leaf code, is hidden inside a CVarField or CVarCharField |
|
//----------------------------------------------------------------------------- |
|
struct VarField_t |
|
{ |
|
uint32 m_cubField; // Size of the field |
|
uint32 m_dubOffset; // Offset of the field within the block |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// CVarField |
|
// Defines a class to encompass a variable-length field - opaque |
|
//----------------------------------------------------------------------------- |
|
class CVarField : private VarField_t |
|
{ |
|
public: |
|
friend class CRecordVar; |
|
private: |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// CVarCharField |
|
// Defines a class to encompass a variable-length string field - opaque |
|
//----------------------------------------------------------------------------- |
|
class CVarCharField : public CVarField |
|
{ |
|
public: |
|
friend class CRecordVar; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// CVarCharField |
|
// Defines a class to encompass a variable-length string field - opaque |
|
//----------------------------------------------------------------------------- |
|
class CVarBinaryField : public CVarField |
|
{ |
|
public: |
|
friend class CRecordVar; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// CImageField |
|
// Defines a class to encompass a long variable-length binary field - opaque |
|
//----------------------------------------------------------------------------- |
|
class CImageField : public CVarField |
|
{ |
|
public: |
|
friend class CRecordVar; |
|
}; |
|
|
|
|
|
#pragma pack( pop ) |
|
|
|
// fix the size of this just to be safe |
|
#pragma pack( push, 4 ) |
|
|
|
class CSchema; |
|
|
|
//----------------------------------------------------------------------------- |
|
// CRecordBase |
|
// Defines a class which arbitrates access to a fixed-length record |
|
// |
|
// This is used as a base class for the CSchTable wrapper classes emitted |
|
// by the schema compiler when the involved table has no variable length data. |
|
//----------------------------------------------------------------------------- |
|
class CRecordBase |
|
{ |
|
public: |
|
// These both allocate new space and COPY the record data into it |
|
CRecordBase( const CRecordBase &that ); |
|
CRecordBase &operator=(const CRecordBase &that); |
|
|
|
// Init from general memory |
|
int InitFromBytes( uint8 *pubRecord ); |
|
|
|
virtual ~CRecordBase(); |
|
|
|
// Use these when sending records over the wire |
|
uint32 CubSerialized(); |
|
|
|
virtual uint8 *PubRecordFixed(); |
|
const uint8 *PubRecordFixed() const; |
|
uint32 CubRecordFixed() const; |
|
|
|
virtual uint8 *PubRecordVarBlock(); |
|
virtual const uint8 *PubRecordVarBlock() const; |
|
uint32 CubRecordVarBlock() const; |
|
bool BAssureRecordVarStorage( uint32 cVariableBytes ); |
|
|
|
// generic data accessors |
|
bool BGetField( int iField, uint8 **ppubData, uint32 *pcubField ) const; |
|
virtual bool BSetField( int iField, void * pvData, uint32 cubData ); |
|
virtual void WipeField( int iField ); |
|
|
|
// data accessors |
|
const char * GetStringField( int iField, uint32 *pcubField ); |
|
int GetInt( int iField ); |
|
uint16 GetUint16( int iField ); |
|
uint32 GetUint32( int iField ); |
|
uint64 GetUint64( int iField ); |
|
|
|
// variable length data accessors |
|
// (not implemented by this class) |
|
virtual const char *ReadVarCharField( const CVarCharField &field ) const; |
|
virtual const uint8 *ReadVarDataField( const CVarField &field, uint32 *pcubField ) const; |
|
virtual bool SetVarCharField( CVarCharField &field, const char *pchString, bool bTruncate, int32 iField ); |
|
virtual void SetVarDataField( CVarField &field, const void *pvData, uint32 cubData ); |
|
|
|
virtual const CSchema *GetPSchema() const |
|
{ |
|
return const_cast<CRecordBase*>(this)->GetPSchema(); |
|
} |
|
virtual CSchema *GetPSchema(); |
|
const CRecordInfo *GetPRecordInfo() const; |
|
|
|
// implemented by CSch-something derivatives |
|
virtual int GetITable() const = 0; |
|
|
|
void RenderField( uint32 unColumn, int cchBuffer, char *pchBuffer ) const; |
|
|
|
#ifdef DBGFLAG_VALIDATE |
|
void Validate( CValidator &validator, const char *pchName ); // Validate our internal structures |
|
static void ValidateStatics( CValidator &validator, const char *pchName ); |
|
#endif // DBGFLAG_VALIDATE |
|
|
|
protected: |
|
// copies the contents of the record. The assignement operator uses this internally |
|
virtual void Copy( const CRecordBase & that ); |
|
|
|
CSchema *GetPSchemaImpl(); |
|
void Cleanup(); |
|
bool BSetField( int iField, void *pvData, uint32 cubData, bool *pbRealloced ); |
|
|
|
|
|
// ctor for derived classes, CSch* |
|
CRecordBase( ) { } |
|
|
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// CRecordVar |
|
// Defines a class which arbitrates access to a variable-length record |
|
// |
|
// This is used as a base class for the CSchTable wrapper classes emitted |
|
// by the schema compiler when the involved table *does* have variable-length data |
|
//----------------------------------------------------------------------------- |
|
class CRecordVar : public CRecordBase |
|
{ |
|
public: |
|
CRecordVar( ) |
|
{ |
|
m_pSchema = NULL; |
|
m_nFlags = 0; |
|
} |
|
|
|
virtual ~CRecordVar() |
|
{ |
|
Cleanup(); |
|
} |
|
|
|
virtual uint8* PubRecordFixed(); |
|
const uint8 *PubRecordFixed() const; |
|
|
|
virtual CSchema *GetPSchema() |
|
{ |
|
return m_pSchema; |
|
} |
|
virtual const CSchema *GetPSchema() const |
|
{ |
|
return m_pSchema; |
|
} |
|
|
|
// Init from general memory |
|
int InitFromBytes( uint8 *pubRecord ); |
|
|
|
// generic data accessors |
|
virtual bool BSetField( int iField, void * pvData, uint32 cubData ); |
|
virtual void WipeField( int iField ); |
|
|
|
// variable-length data accessors |
|
virtual const char *ReadVarCharField( const CVarCharField &field ) const; |
|
virtual const uint8 *ReadVarDataField( const CVarField &field, uint32 *pcubField ) const; |
|
virtual bool SetVarCharField( CVarCharField &field, const char *pchString, bool bTruncate, int32 iField ); |
|
virtual void SetVarDataField( CVarField &field, const void *pvData, uint32 cubData ); |
|
|
|
// allocated fixed means we've got our own memory for the fixed record |
|
// allocated var block means we've allocated a block for the variable part of this record |
|
enum EFlags { k_EAllocatedFixed = 0x1, k_EAllocatedVarBlock = 0x2 }; |
|
bool BFlagSet( int eFlag ) const; |
|
|
|
#ifdef DBGFLAG_VALIDATE |
|
void Validate( CValidator &validator, const char *pchName ); // Validate our internal structures |
|
#endif // DBGFLAG_VALIDATE |
|
|
|
protected: |
|
// copies the contents of the record. The assignement operator uses this internally |
|
virtual void Copy( const CRecordBase & that ); |
|
|
|
// initialization helper |
|
void DoInit() |
|
{ |
|
m_pSchema = CRecordBase::GetPSchema(); |
|
} |
|
|
|
void SetFlag( int eFlag, bool bSet ); |
|
|
|
void Cleanup(); |
|
CSchema *m_pSchema; // Corresponding Schema |
|
int m_nFlags; // Flags about the record memory allocations / location |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// CRecordExternal |
|
// Defines a class which arbitrates access to a variable-length record |
|
// |
|
// This is used as an accessor for a polymorphic record. It can be used to |
|
// read CSchTable records when the type is unknown, manipulate stats records, |
|
// or touch data that isn't preallocated. Its use is relatively rare. |
|
//----------------------------------------------------------------------------- |
|
class CRecordExternal : public CRecordVar |
|
{ |
|
public: |
|
CRecordExternal() |
|
{ |
|
m_pubRecordFixedExternal = NULL; |
|
m_nFlags = 0; |
|
} |
|
|
|
virtual ~CRecordExternal() |
|
{ |
|
Cleanup(); |
|
} |
|
|
|
virtual uint8* PubRecordFixed(); |
|
const uint8 *PubRecordFixed() const; |
|
|
|
void DeSerialize( uint8 *pubData ); |
|
|
|
int GetITable() const |
|
{ |
|
return -1; |
|
} |
|
|
|
void Init( CSchema *pSchema ); |
|
int Init( CSchema *pSchema, uint8 *pubRecord, bool bTakeOwnership ); |
|
|
|
// test helpers |
|
void InitRecordRandom( uint32 unPrimaryIndex ); |
|
void SetFieldRandom( int iField ); |
|
|
|
#ifdef DBGFLAG_VALIDATE |
|
void Validate( CValidator &validator, const char *pchName ); // Validate our internal structures |
|
#endif // DBGFLAG_VALIDATE |
|
|
|
protected: |
|
// copies the contents of the record. The assignement operator uses this internally |
|
virtual void Copy( const CRecordBase & that ); |
|
|
|
void Cleanup(); |
|
|
|
void DoInit() |
|
{ |
|
m_pSchema = CRecordBase::GetPSchema(); |
|
} |
|
|
|
uint8 *m_pubRecordFixedExternal; // If the fixed record is not a part of this object, |
|
// this points to where it is |
|
|
|
CSchema *GetPSchemaImpl(); |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Accessors for variable length character data. |
|
// These goofy little macros implement some syntax sugar |
|
//----------------------------------------------------------------------------- |
|
|
|
#define READ_VAR_CHAR_FIELD( record, field )\ |
|
(record).ReadVarCharField( (record).field ) |
|
|
|
#define WRITE_VAR_CHAR_FIELD( record, field, text )\ |
|
(record).SetVarCharField( (record).m_##field, text, false, (record).k_iField_##field ) |
|
|
|
#define WRITE_VAR_CHAR_FIELD_TRUNC( record, field, text )\ |
|
(record).SetVarCharField( (record).m_##field, text, true, (record).k_iField_##field ) |
|
|
|
#pragma pack( pop ) |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Template classes that get a LessFunc that sorts CRecordBases by a field |
|
// within them |
|
//----------------------------------------------------------------------------- |
|
template <class T, int I, typename F> |
|
class CDefSchOps |
|
{ |
|
public: |
|
static bool LessFunc( const T &lhs, const T &rhs ) |
|
{ |
|
// Check that the field number is valid |
|
COMPILE_TIME_ASSERT( I >= 0 && I < T::k_iFieldMax ); |
|
|
|
// Check to make sure this is a fixed field |
|
const Field_t &fieldInfo = lhs.GetPSchema()->GetField( I ); |
|
Assert( !fieldInfo.BIsStringType() && !fieldInfo.BIsVariableLength() ); |
|
if ( fieldInfo.BIsStringType() || fieldInfo.BIsVariableLength() ) |
|
return false; |
|
|
|
// Read the data and make sure the sizes are correct for the field type we expect |
|
uint8 *pubLhs; |
|
uint8 *pubRhs; |
|
bool bRet; |
|
uint32 cubRead; |
|
|
|
bRet = lhs.BGetField( I, &pubLhs, &cubRead ); |
|
Assert( bRet && cubRead == sizeof( F ) ); |
|
if ( !bRet || cubRead != sizeof( F ) ) |
|
return false; |
|
|
|
bRet = rhs.BGetField( I, &pubRhs, &cubRead ); |
|
Assert( bRet && cubRead == sizeof( F ) ); |
|
if ( !bRet || cubRead != sizeof( F ) ) |
|
return false; |
|
|
|
// Finally do the comparison |
|
return ( *( (F *)pubLhs ) ) < ( *( (F *)pubRhs ) ); |
|
} |
|
|
|
static bool LessFuncCtx( const T &lhs, const T &rhs, void *pCtx ) |
|
{ |
|
return LessFunc( lhs, rhs ); |
|
} |
|
}; |
|
|
|
|
|
#define DefSchLessFunc( RecordType, FieldIndex, FieldType ) CDefSchOps<RecordType, FieldIndex, FieldType>::LessFunc |
|
#define DefSchLessFuncCtx( RecordType, FieldIndex, FieldType ) CDefSchOps<RecordType, FieldIndex, FieldType>::LessFuncCtx |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Specializations for string fields |
|
//----------------------------------------------------------------------------- |
|
template <class T, int I> |
|
class CDefSchOps<T, I, char *> |
|
{ |
|
public: |
|
static bool LessFunc( const T &lhs, const T &rhs ) |
|
{ |
|
// Check that the field number is valid |
|
COMPILE_TIME_ASSERT( I >= 0 && I < T::k_iFieldMax ); |
|
|
|
// Check to make sure this is indeed a string field |
|
Field_t &fieldInfo = lhs.GetPSchema()->GetField( I ); |
|
Assert( fieldInfo.BIsStringType() ); |
|
if ( !fieldInfo.BIsStringType() ) |
|
return false; |
|
|
|
// Read the data |
|
uint32 cubRead; |
|
const char *pchLhs = lhs.GetStringField( I, &cubRead ); |
|
const char *pchRhs = rhs.GetStringField( I, &cubRead ); |
|
|
|
// Finally do the comparison |
|
return CDefOps<const char *>::LessFunc( lhs, rhs ); |
|
} |
|
|
|
static bool LessFuncCtx( const T &lhs, const T &rhs, void *pCtx ) |
|
{ |
|
return LessFunc( lhs, rhs ); |
|
} |
|
}; |
|
|
|
|
|
template <class T, int I> |
|
class CDefSchOps<T, I, const char *> |
|
{ |
|
public: |
|
static bool LessFunc( const T &lhs, const T &rhs ) |
|
{ |
|
return CDefSchOps<T, I, char *>::LessFunc( lhs, rhs ); |
|
} |
|
|
|
static bool LessFuncCtx( const T &lhs, const T &rhs, void *pCtx ) |
|
{ |
|
return LessFunc( lhs, rhs ); |
|
} |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Provide a convenient object to pass around to represent a type |
|
// of record |
|
//----------------------------------------------------------------------------- |
|
class CRecordType |
|
{ |
|
public: |
|
virtual int GetITable() const = 0; |
|
virtual CRecordBase *Create() const = 0; |
|
|
|
CSchema *GetSchema() const; |
|
CRecordInfo *GetRecordInfo() const; |
|
protected: |
|
private: |
|
}; |
|
|
|
template <typename TRecord> |
|
class CRecordTypeConcrete: public CRecordType |
|
{ |
|
public: |
|
virtual int GetITable() const { return TRecord::k_iTable; } |
|
virtual CRecordBase *Create() const { return new TRecord(); } |
|
}; |
|
|
|
#define RTYPE( recordClass ) CRecordTypeConcrete<recordClass>() |
|
|
|
} // namespace GCSDK |
|
|
|
#include "tier0/memdbgoff.h" |
|
|
|
#endif // GCRECORD_H
|
|
|