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.
468 lines
13 KiB
468 lines
13 KiB
5 years ago
|
//========= 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
|