|
|
//========= 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
|