diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /external/vpc/public | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'external/vpc/public')
100 files changed, 46854 insertions, 0 deletions
diff --git a/external/vpc/public/appframework/iappsystem.h b/external/vpc/public/appframework/iappsystem.h new file mode 100644 index 0000000..5375fb0 --- /dev/null +++ b/external/vpc/public/appframework/iappsystem.h @@ -0,0 +1,121 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: An application framework +// +// $Revision: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef IAPPSYSTEM_H +#define IAPPSYSTEM_H + +#ifdef COMPILER_MSVC +#pragma once +#endif + +#include "tier1/interface.h" +#include "interfaces/interfaces.h" + + +//----------------------------------------------------------------------------- +// Specifies a module + interface name for initialization +//----------------------------------------------------------------------------- +struct AppSystemInfo_t +{ + const char *m_pModuleName; + const char *m_pInterfaceName; +}; + + +//----------------------------------------------------------------------------- +// Client systems are singleton objects in the client codebase responsible for +// various tasks +// The order in which the client systems appear in this list are the +// order in which they are initialized and updated. They are shut down in +// reverse order from which they are initialized. +//----------------------------------------------------------------------------- +enum InitReturnVal_t +{ + INIT_FAILED = 0, + INIT_OK, + + INIT_LAST_VAL, +}; + +enum AppSystemTier_t +{ + APP_SYSTEM_TIER0 = 0, + APP_SYSTEM_TIER1, + APP_SYSTEM_TIER2, + APP_SYSTEM_TIER3, + + APP_SYSTEM_TIER_OTHER, +}; + + +abstract_class IAppSystem +{ +public: + // Here's where the app systems get to learn about each other + virtual bool Connect( CreateInterfaceFn factory ) = 0; + virtual void Disconnect() = 0; + + // Here's where systems can access other interfaces implemented by this object + // Returns NULL if it doesn't implement the requested interface + virtual void *QueryInterface( const char *pInterfaceName ) = 0; + + // Init, shutdown + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; + + // Returns all dependent libraries + virtual const AppSystemInfo_t* GetDependencies() = 0; + + // Returns the tier + virtual AppSystemTier_t GetTier() = 0; + + // Reconnect to a particular interface + virtual void Reconnect( CreateInterfaceFn factory, const char *pInterfaceName ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Helper empty implementation of an IAppSystem +//----------------------------------------------------------------------------- +template< class IInterface > +class CBaseAppSystem : public IInterface +{ +public: + // Here's where the app systems get to learn about each other + virtual bool Connect( CreateInterfaceFn factory ) { return true; } + virtual void Disconnect() {} + + // Here's where systems can access other interfaces implemented by this object + // Returns NULL if it doesn't implement the requested interface + virtual void *QueryInterface( const char *pInterfaceName ) { return NULL; } + + // Init, shutdown + virtual InitReturnVal_t Init() { return INIT_OK; } + virtual void Shutdown() {} + + virtual const AppSystemInfo_t* GetDependencies() { return NULL; } + virtual AppSystemTier_t GetTier() { return APP_SYSTEM_TIER_OTHER; } + + virtual void Reconnect( CreateInterfaceFn factory, const char *pInterfaceName ) + { + ReconnectInterface( factory, pInterfaceName ); + } +}; + + +//----------------------------------------------------------------------------- +// Helper implementation of an IAppSystem for tier0 +//----------------------------------------------------------------------------- +template< class IInterface > +class CTier0AppSystem : public CBaseAppSystem< IInterface > +{ +}; + + +#endif // IAPPSYSTEM_H + diff --git a/external/vpc/public/color.h b/external/vpc/public/color.h new file mode 100644 index 0000000..d84cc11 --- /dev/null +++ b/external/vpc/public/color.h @@ -0,0 +1,124 @@ +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef COLOR_H +#define COLOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/basetypes.h" + +//----------------------------------------------------------------------------- +// Purpose: Basic handler for an rgb set of colors +// This class is fully inline +//----------------------------------------------------------------------------- +class Color +{ +public: + // constructors + Color() + { + *((int *)this) = 0; + } + Color(int _r,int _g,int _b) + { + SetColor(_r, _g, _b, 0); + } + Color(int _r,int _g,int _b,int _a) + { + SetColor(_r, _g, _b, _a); + } + + // set the color + // r - red component (0-255) + // g - green component (0-255) + // b - blue component (0-255) + // a - alpha component, controls transparency (0 - transparent, 255 - opaque); + void SetColor(int _r, int _g, int _b, int _a = 0) + { + _color[0] = (unsigned char)_r; + _color[1] = (unsigned char)_g; + _color[2] = (unsigned char)_b; + _color[3] = (unsigned char)_a; + } + + void GetColor(int &_r, int &_g, int &_b, int &_a) const + { + _r = _color[0]; + _g = _color[1]; + _b = _color[2]; + _a = _color[3]; + } + + void SetRawColor( int color32 ) + { + *((int *)this) = color32; + } + + int GetRawColor() const + { + return *((int *)this); + } + + inline int r() const { return _color[0]; } + inline int g() const { return _color[1]; } + inline int b() const { return _color[2]; } + inline int a() const { return _color[3]; } + + unsigned char &operator[](int index) + { + return _color[index]; + } + + const unsigned char &operator[](int index) const + { + return _color[index]; + } + + bool operator == (const Color &rhs) const + { + return ( *((int *)this) == *((int *)&rhs) ); + } + + bool operator != (const Color &rhs) const + { + return !(operator==(rhs)); + } + + Color &operator=( const Color &rhs ) + { + SetRawColor( rhs.GetRawColor() ); + return *this; + } + + Color &operator=( const color32 &rhs ) + { + _color[0] = rhs.r; + _color[1] = rhs.g; + _color[2] = rhs.b; + _color[3] = rhs.a; + return *this; + } + + color32 ToColor32() const + { + color32 newColor; + newColor.r = _color[0]; + newColor.g = _color[1]; + newColor.b = _color[2]; + newColor.a = _color[3]; + return newColor; + } + +private: + unsigned char _color[4]; +}; + + +#endif // COLOR_H diff --git a/external/vpc/public/datamap.h b/external/vpc/public/datamap.h new file mode 100644 index 0000000..941ba51 --- /dev/null +++ b/external/vpc/public/datamap.h @@ -0,0 +1,521 @@ +//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DATAMAP_H +#define DATAMAP_H +#ifdef _WIN32 +#pragma once +#endif + +#ifndef VECTOR_H +#include "mathlib/vector.h" +#endif + +#include "tier1/utlvector.h" + +#include "tier0/memdbgon.h" + +// SINGLE_INHERITANCE restricts the size of CBaseEntity pointers-to-member-functions to 4 bytes +class SINGLE_INHERITANCE CBaseEntity; +struct inputdata_t; + +#define INVALID_TIME (FLT_MAX * -1.0) // Special value not rebased on save/load + +typedef enum _fieldtypes +{ + FIELD_VOID = 0, // No type or value + FIELD_FLOAT, // Any floating point value + FIELD_STRING, // A string ID (return from ALLOC_STRING) + FIELD_VECTOR, // Any vector, QAngle, or AngularImpulse + FIELD_QUATERNION, // A quaternion + FIELD_INTEGER, // Any integer or enum + FIELD_BOOLEAN, // boolean, implemented as an int, I may use this as a hint for compression + FIELD_SHORT, // 2 byte integer + FIELD_CHARACTER, // a byte + FIELD_COLOR32, // 8-bit per channel r,g,b,a (32bit color) + FIELD_EMBEDDED, // an embedded object with a datadesc, recursively traverse and embedded class/structure based on an additional typedescription + FIELD_CUSTOM, // special type that contains function pointers to it's read/write/parse functions + + FIELD_CLASSPTR, // CBaseEntity * + FIELD_EHANDLE, // Entity handle + FIELD_EDICT, // edict_t * + + FIELD_POSITION_VECTOR, // A world coordinate (these are fixed up across level transitions automagically) + FIELD_TIME, // a floating point time (these are fixed up automatically too!) + FIELD_TICK, // an integer tick count( fixed up similarly to time) + FIELD_MODELNAME, // Engine string that is a model name (needs precache) + FIELD_SOUNDNAME, // Engine string that is a sound name (needs precache) + + FIELD_INPUT, // a list of inputed data fields (all derived from CMultiInputVar) + FIELD_FUNCTION, // A class function pointer (Think, Use, etc) + + FIELD_VMATRIX, // a vmatrix (output coords are NOT worldspace) + + // NOTE: Use float arrays for local transformations that don't need to be fixed up. + FIELD_VMATRIX_WORLDSPACE,// A VMatrix that maps some local space to world space (translation is fixed up on level transitions) + FIELD_MATRIX3X4_WORLDSPACE, // matrix3x4_t that maps some local space to world space (translation is fixed up on level transitions) + + FIELD_INTERVAL, // a start and range floating point interval ( e.g., 3.2->3.6 == 3.2 and 0.4 ) + FIELD_MODELINDEX, // a model index + FIELD_MATERIALINDEX, // a material index (using the material precache string table) + + FIELD_VECTOR2D, // 2 floats + FIELD_INTEGER64, // 64bit integer + + FIELD_VECTOR4D, // 4 floats + + FIELD_TYPECOUNT, // MUST BE LAST +} fieldtype_t; + + +//----------------------------------------------------------------------------- +// Field sizes... +//----------------------------------------------------------------------------- +template <int FIELD_TYPE> +class CDatamapFieldSizeDeducer +{ +public: + enum + { + SIZE = 0 + }; + + static int FieldSize( ) + { + return 0; + } +}; + +#define DECLARE_FIELD_SIZE( _fieldType, _fieldSize ) \ + template< > class CDatamapFieldSizeDeducer<_fieldType> { public: enum { SIZE = _fieldSize }; static int FieldSize() { return _fieldSize; } }; +#define FIELD_SIZE( _fieldType ) CDatamapFieldSizeDeducer<_fieldType>::SIZE +#define FIELD_BITS( _fieldType ) (FIELD_SIZE( _fieldType ) * 8) + +DECLARE_FIELD_SIZE( FIELD_FLOAT, sizeof(float) ) +DECLARE_FIELD_SIZE( FIELD_STRING, sizeof(int) ) +DECLARE_FIELD_SIZE( FIELD_VECTOR, 3 * sizeof(float) ) +DECLARE_FIELD_SIZE( FIELD_VECTOR2D, 2 * sizeof(float) ) +DECLARE_FIELD_SIZE( FIELD_VECTOR4D, 4 * sizeof( float ) ) +DECLARE_FIELD_SIZE( FIELD_QUATERNION, 4 * sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_INTEGER, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_INTEGER64, sizeof(int64)) +DECLARE_FIELD_SIZE( FIELD_BOOLEAN, sizeof(char)) +DECLARE_FIELD_SIZE( FIELD_SHORT, sizeof(short)) +DECLARE_FIELD_SIZE( FIELD_CHARACTER, sizeof(char)) +DECLARE_FIELD_SIZE( FIELD_COLOR32, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_CLASSPTR, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_EHANDLE, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_EDICT, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_POSITION_VECTOR, 3 * sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_TIME, sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_TICK, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_MODELNAME, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_SOUNDNAME, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_INPUT, sizeof(int)) +#if defined(_WIN32) +DECLARE_FIELD_SIZE( FIELD_FUNCTION, sizeof(void *)) +#elif defined(POSIX) +// pointer to members under gnuc are 8bytes if you have a virtual func +DECLARE_FIELD_SIZE( FIELD_FUNCTION, 2 * sizeof(void *)) +#else +#error +#endif +DECLARE_FIELD_SIZE( FIELD_VMATRIX, 16 * sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_VMATRIX_WORLDSPACE, 16 * sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_MATRIX3X4_WORLDSPACE, 12 * sizeof(float)) +DECLARE_FIELD_SIZE( FIELD_INTERVAL, 2 * sizeof( float) ) // NOTE: Must match interval.h definition +DECLARE_FIELD_SIZE( FIELD_MODELINDEX, sizeof(int) ) +DECLARE_FIELD_SIZE( FIELD_MATERIALINDEX, sizeof(int) ) + + +#define ARRAYSIZE2D(p) (sizeof(p)/sizeof(p[0][0])) +#define SIZE_OF_ARRAY(p) _ARRAYSIZE(p) + +#define _FIELD(name,fieldtype,count,flags,mapname,tolerance) { fieldtype, #name, offsetof(classNameTypedef, name), count, flags, mapname, NULL, NULL, NULL, sizeof( ((classNameTypedef *)0)->name ), NULL, 0, tolerance } +#define DEFINE_FIELD_NULL { FIELD_VOID,0,0,0,0,0,0,0,0} +#define DEFINE_FIELD(name,fieldtype) _FIELD(name, fieldtype, 1, FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_FIELD_NOT_SAVED(name,fieldtype) _FIELD(name, fieldtype, 1, 0, NULL, 0 ) + +#define DEFINE_KEYFIELD(name,fieldtype, mapname) _FIELD(name, fieldtype, 1, FTYPEDESC_KEY | FTYPEDESC_SAVE, mapname, 0 ) +#define DEFINE_KEYFIELD_NOT_SAVED(name,fieldtype, mapname)_FIELD(name, fieldtype, 1, FTYPEDESC_KEY, mapname, 0 ) +#define DEFINE_AUTO_ARRAY(name,fieldtype) _FIELD(name, fieldtype, SIZE_OF_ARRAY(((classNameTypedef *)0)->name), FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_AUTO_ARRAY_KEYFIELD(name,fieldtype,mapname) _FIELD(name, fieldtype, SIZE_OF_ARRAY(((classNameTypedef *)0)->name), FTYPEDESC_SAVE, mapname, 0 ) +#define DEFINE_ARRAY(name,fieldtype, count) _FIELD(name, fieldtype, count, FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_ARRAY_NOT_SAVED(name,fieldtype, count) _FIELD(name, fieldtype, count, 0, NULL, 0 ) +#define DEFINE_ENTITY_FIELD(name,fieldtype) _FIELD(edict_t, name, fieldtype, 1, FTYPEDESC_KEY | FTYPEDESC_SAVE, #name, 0 ) +#define DEFINE_ENTITY_GLOBAL_FIELD(name,fieldtype) _FIELD(edict_t, name, fieldtype, 1, FTYPEDESC_KEY | FTYPEDESC_SAVE | FTYPEDESC_GLOBAL, #name, 0 ) +#define DEFINE_GLOBAL_FIELD(name,fieldtype) _FIELD(name, fieldtype, 1, FTYPEDESC_GLOBAL | FTYPEDESC_SAVE, NULL, 0 ) +#define DEFINE_GLOBAL_KEYFIELD(name,fieldtype, mapname) _FIELD(name, fieldtype, 1, FTYPEDESC_GLOBAL | FTYPEDESC_KEY | FTYPEDESC_SAVE, mapname, 0 ) +#define DEFINE_CUSTOM_FIELD(name,datafuncs) { FIELD_CUSTOM, #name, offsetof(classNameTypedef, name), 1, FTYPEDESC_SAVE, NULL, datafuncs, NULL } +#define DEFINE_CUSTOM_KEYFIELD(name,datafuncs,mapname) { FIELD_CUSTOM, #name, offsetof(classNameTypedef, name), 1, FTYPEDESC_SAVE | FTYPEDESC_KEY, mapname, datafuncs, NULL } +#define DEFINE_AUTO_ARRAY2D(name,fieldtype) _FIELD(name, fieldtype, ARRAYSIZE2D(((classNameTypedef *)0)->name), FTYPEDESC_SAVE, NULL, 0 ) +// Used by byteswap datadescs +#define DEFINE_BITFIELD(name,fieldtype,bitcount) DEFINE_ARRAY(name,fieldtype,((bitcount+FIELD_BITS(fieldtype)-1)&~(FIELD_BITS(fieldtype)-1)) / FIELD_BITS(fieldtype) ) +#define DEFINE_INDEX(name,fieldtype) _FIELD(name, fieldtype, 1, FTYPEDESC_INDEX, NULL, 0 ) + +#define DEFINE_EMBEDDED( name ) \ + { FIELD_EMBEDDED, #name, offsetof(classNameTypedef, name), 1, FTYPEDESC_SAVE, NULL, NULL, NULL, &(((classNameTypedef *)0)->name.m_DataMap), sizeof( ((classNameTypedef *)0)->name ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDED_OVERRIDE( name, overridetype ) \ + { FIELD_EMBEDDED, #name, offsetof(classNameTypedef, name), 1, FTYPEDESC_SAVE, NULL, NULL, NULL, &((overridetype *)0)->m_DataMap, sizeof( ((classNameTypedef *)0)->name ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDEDBYREF( name ) \ + { FIELD_EMBEDDED, #name, offsetof(classNameTypedef, name), 1, FTYPEDESC_SAVE | FTYPEDESC_PTR, NULL, NULL, NULL, &(((classNameTypedef *)0)->name->m_DataMap), sizeof( *(((classNameTypedef *)0)->name) ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDED_ARRAY( name, count ) \ + { FIELD_EMBEDDED, #name, offsetof(classNameTypedef, name), count, FTYPEDESC_SAVE, NULL, NULL, NULL, &(((classNameTypedef *)0)->name->m_DataMap), sizeof( ((classNameTypedef *)0)->name[0] ), NULL, 0, 0.0f } + +#define DEFINE_EMBEDDED_AUTO_ARRAY( name ) \ + { FIELD_EMBEDDED, #name, offsetof(classNameTypedef, name), SIZE_OF_ARRAY( ((classNameTypedef *)0)->name ), FTYPEDESC_SAVE, NULL, NULL, NULL, &(((classNameTypedef *)0)->name->m_DataMap), sizeof( ((classNameTypedef *)0)->name[0] ), NULL, 0, 0.0f } + +#ifndef NO_ENTITY_PREDICTION + +// FTYPEDESC_KEY tells the prediction copy system to report the full nameof the field when reporting errors +#define DEFINE_PRED_TYPEDESCRIPTION( name, fieldtype ) \ + { FIELD_EMBEDDED, #name, offsetof(classNameTypedef, name), 1, FTYPEDESC_SAVE | FTYPEDESC_KEY, NULL, NULL, NULL, &fieldtype::m_PredMap } + +#define DEFINE_PRED_TYPEDESCRIPTION_PTR( name, fieldtype ) \ + { FIELD_EMBEDDED, #name, offsetof(classNameTypedef, name), 1, FTYPEDESC_SAVE | FTYPEDESC_PTR | FTYPEDESC_KEY, NULL, NULL, NULL, &fieldtype::m_PredMap } + +#else + +#define DEFINE_PRED_TYPEDESCRIPTION( name, fieldtype ) DEFINE_FIELD_NULL +#define DEFINE_PRED_TYPEDESCRIPTION_PTR( name, fieldtype ) DEFINE_FIELD_NULL + +#endif + +// Extensions to datamap.h macros for predicted entities only +#define DEFINE_PRED_FIELD(name,fieldtype, flags) _FIELD(name, fieldtype, 1, flags, NULL, 0.0f ) +#define DEFINE_PRED_ARRAY(name,fieldtype, count,flags) _FIELD(name, fieldtype, count, flags, NULL, 0.0f ) +#define DEFINE_FIELD_NAME(localname,netname,fieldtype) _FIELD(localname, fieldtype, 1, 0, #netname, 0.0f ) +// Predictable macros, which include a tolerance for floating point values... +#define DEFINE_PRED_FIELD_TOL(name,fieldtype, flags,tolerance) _FIELD(name, fieldtype, 1, flags, NULL, tolerance ) +#define DEFINE_PRED_ARRAY_TOL(name,fieldtype, count,flags,tolerance) _FIELD(name, fieldtype, count, flags, NULL, tolerance) +#define DEFINE_FIELD_NAME_TOL(localname,netname,fieldtolerance) _FIELD(localname, fieldtype, 1, 0, #netname, tolerance ) + +//#define DEFINE_DATA( name, fieldextname, flags ) _FIELD(name, fieldtype, 1, flags, extname ) + +// INPUTS +#define DEFINE_INPUT( name, fieldtype, inputname ) { fieldtype, #name, offsetof(classNameTypedef, name), 1, FTYPEDESC_INPUT | FTYPEDESC_SAVE | FTYPEDESC_KEY, inputname, NULL, NULL, NULL, sizeof( ((classNameTypedef *)0)->name ) } +#define DEFINE_INPUTFUNC( fieldtype, inputname, inputfunc ) { fieldtype, #inputfunc, NULL, 1, FTYPEDESC_INPUT, inputname, NULL, static_cast <inputfunc_t> (&classNameTypedef::inputfunc) } + +// OUTPUTS +// the variable 'name' MUST BE derived from CBaseOutput +// we know the output type from the variable itself, so it doesn't need to be specified here +class ISaveRestoreOps; +extern ISaveRestoreOps *eventFuncs; +#define DEFINE_OUTPUT( name, outputname ) { FIELD_CUSTOM, #name, offsetof(classNameTypedef, name), 1, FTYPEDESC_OUTPUT | FTYPEDESC_SAVE | FTYPEDESC_KEY, outputname, eventFuncs } + +// replaces EXPORT table for portability and non-DLL based systems (xbox) +#define DEFINE_FUNCTION_RAW( function, func_type ) { FIELD_VOID, nameHolder.GenerateName(#function), NULL, 1, FTYPEDESC_FUNCTIONTABLE, NULL, NULL, (inputfunc_t)((func_type)(&classNameTypedef::function)) } +#define DEFINE_FUNCTION( function ) DEFINE_FUNCTION_RAW( function, inputfunc_t ) + + +#define FTYPEDESC_GLOBAL 0x0001 // This field is masked for global entity save/restore +#define FTYPEDESC_SAVE 0x0002 // This field is saved to disk +#define FTYPEDESC_KEY 0x0004 // This field can be requested and written to by string name at load time +#define FTYPEDESC_INPUT 0x0008 // This field can be written to by string name at run time, and a function called +#define FTYPEDESC_OUTPUT 0x0010 // This field propagates its value to all targets whenever it changes +#define FTYPEDESC_FUNCTIONTABLE 0x0020 // This is a table entry for a member function pointer +#define FTYPEDESC_PTR 0x0040 // This field is a pointer, not an embedded object +#define FTYPEDESC_OVERRIDE 0x0080 // The field is an override for one in a base class (only used by prediction system for now) + +// Flags used by other systems (e.g., prediction system) +#define FTYPEDESC_INSENDTABLE 0x0100 // This field is present in a network SendTable +#define FTYPEDESC_PRIVATE 0x0200 // The field is local to the client or server only (not referenced by prediction code and not replicated by networking) +#define FTYPEDESC_NOERRORCHECK 0x0400 // The field is part of the prediction typedescription, but doesn't get compared when checking for errors + +#define FTYPEDESC_MODELINDEX 0x0800 // The field is a model index (used for debugging output) + +#define FTYPEDESC_INDEX 0x1000 // The field is an index into file data, used for byteswapping. + +// These flags apply to C_BasePlayer derived objects only +#define FTYPEDESC_VIEW_OTHER_PLAYER 0x2000 // By default you can only view fields on the local player (yourself), + // but if this is set, then we allow you to see fields on other players +#define FTYPEDESC_VIEW_OWN_TEAM 0x4000 // Only show this data if the player is on the same team as the local player +#define FTYPEDESC_VIEW_NEVER 0x8000 // Never show this field to anyone, even the local player (unusual) + +#define TD_MSECTOLERANCE 0.001f // This is a FIELD_FLOAT and should only be checked to be within 0.001 of the networked info + +struct typedescription_t; + + +class ISaveRestoreOps; + +// +// Function prototype for all input handlers. +// +typedef void (CBaseEntity::*inputfunc_t)(inputdata_t &data); + +struct datamap_t; +struct typedescription_t; + +enum +{ + PC_NON_NETWORKED_ONLY = 0, + PC_NETWORKED_ONLY, + + PC_COPYTYPE_COUNT, + PC_EVERYTHING = PC_COPYTYPE_COUNT, +}; + +enum +{ + TD_OFFSET_NORMAL = 0, + TD_OFFSET_PACKED = 1, + + // Must be last + TD_OFFSET_COUNT, +}; + +struct typedescription_t +{ + fieldtype_t fieldType; + const char *fieldName; + int fieldOffset; // Local offset value + unsigned short fieldSize; + short flags; + // the name of the variable in the map/fgd data, or the name of the action + const char *externalName; + // pointer to the function set for save/restoring of custom data types + ISaveRestoreOps *pSaveRestoreOps; + // for associating function with string names + inputfunc_t inputFunc; + // For embedding additional datatables inside this one + datamap_t *td; + + // Stores the actual member variable size in bytes + int fieldSizeInBytes; + + // FTYPEDESC_OVERRIDE point to first baseclass instance if chains_validated has occurred + struct typedescription_t *override_field; + + // Used to track exclusion of baseclass fields + int override_count; + + // Tolerance for field errors for float fields + float fieldTolerance; + + // For raw fields (including children of embedded stuff) this is the flattened offset + int flatOffset[ TD_OFFSET_COUNT ]; + unsigned short flatGroup; +}; + +// See predictioncopy.h for implementation and notes +struct optimized_datamap_t; + +//----------------------------------------------------------------------------- +// Purpose: stores the list of objects in the hierarchy +// used to iterate through an object's data descriptions +//----------------------------------------------------------------------------- +struct datamap_t +{ + typedescription_t *dataDesc; + int dataNumFields; + char const *dataClassName; + datamap_t *baseMap; + + int m_nPackedSize; + optimized_datamap_t *m_pOptimizedDataMap; + +#if defined( _DEBUG ) + bool bValidityChecked; +#endif // _DEBUG +}; + + +//----------------------------------------------------------------------------- +// +// Macros used to implement datadescs +// +#define DECLARE_FRIEND_DATADESC_ACCESS() \ + template <typename T> friend void DataMapAccess(T *, datamap_t **p); \ + template <typename T> friend datamap_t *DataMapInit(T *); + +#define DECLARE_SIMPLE_DATADESC() \ + static datamap_t m_DataMap; \ + static datamap_t *GetBaseMap(); \ + template <typename T> friend void DataMapAccess(T *, datamap_t **p); \ + template <typename T> friend datamap_t *DataMapInit(T *); + +#if defined(POSIX) && !defined(_PS3) + +#define DECLARE_SIMPLE_DATADESC_INSIDE_NAMESPACE() \ + static datamap_t m_DataMap; \ + static datamap_t *GetBaseMap(); \ + template <typename T> friend void ::DataMapAccess(T *, datamap_t **p); + +#else +#define DECLARE_SIMPLE_DATADESC_INSIDE_NAMESPACE() \ + static datamap_t m_DataMap; \ + static datamap_t *GetBaseMap(); \ + template <typename T> friend void ::DataMapAccess(T *, datamap_t **p); \ + template <typename T> friend datamap_t *::DataMapInit(T *); + +#endif + +#define DECLARE_DATADESC() \ + DECLARE_SIMPLE_DATADESC() \ + virtual datamap_t *GetDataDescMap( void ); + +#define BEGIN_DATADESC( className ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetDataDescMap( void ) { return &m_DataMap; } \ + datamap_t *className::GetBaseMap() { datamap_t *pResult; DataMapAccess((BaseClass *)NULL, &pResult); return pResult; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_DATADESC_NO_BASE( className ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetDataDescMap( void ) { return &m_DataMap; } \ + datamap_t *className::GetBaseMap() { return NULL; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_SIMPLE_DATADESC( className ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetBaseMap() { return NULL; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_SIMPLE_DATADESC_( className, BaseClass ) \ + datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \ + datamap_t *className::GetBaseMap() { datamap_t *pResult; DataMapAccess((BaseClass *)NULL, &pResult); return pResult; } \ + BEGIN_DATADESC_GUTS( className ) + +#define BEGIN_DATADESC_GUTS( className ) \ + template <typename T> datamap_t *DataMapInit(T *); \ + template <> datamap_t *DataMapInit<className>( className * ); \ + namespace className##_DataDescInit \ + { \ + datamap_t *g_DataMapHolder = DataMapInit<className>( (className *)NULL ); /* This can/will be used for some clean up duties later */ \ + } \ + \ + template <> datamap_t *DataMapInit<className>( className * ) \ + { \ + typedef className classNameTypedef; \ + static CDatadescGeneratedNameHolder nameHolder(#className); \ + className::m_DataMap.baseMap = className::GetBaseMap(); \ + static typedescription_t dataDesc[] = \ + { \ + { FIELD_VOID,0,0,0,0,0,0,0,0}, /* so you can define "empty" tables */ + + +#define BEGIN_DATADESC_GUTS_NAMESPACE( className, nameSpace ) \ + template <typename T> datamap_t *nameSpace::DataMapInit(T *); \ + template <> datamap_t *nameSpace::DataMapInit<className>( className * ); \ + namespace className##_DataDescInit \ + { \ + datamap_t *g_DataMapHolder = nameSpace::DataMapInit( (className *)NULL ); /* This can/will be used for some clean up duties later */ \ + } \ + \ + template <> datamap_t *nameSpace::DataMapInit<className>( className * ) \ + { \ + typedef className classNameTypedef; \ + static CDatadescGeneratedNameHolder nameHolder(#className); \ + className::m_DataMap.baseMap = className::GetBaseMap(); \ + static typedescription_t dataDesc[] = \ + { \ + { FIELD_VOID,0,0,0,0,0,0,0,0}, /* so you can define "empty" tables */ + +#define END_DATADESC() \ + }; \ + \ + if ( sizeof( dataDesc ) > sizeof( dataDesc[0] ) ) \ + { \ + classNameTypedef::m_DataMap.dataNumFields = SIZE_OF_ARRAY( dataDesc ) - 1; \ + classNameTypedef::m_DataMap.dataDesc = &dataDesc[1]; \ + } \ + else \ + { \ + classNameTypedef::m_DataMap.dataNumFields = 1; \ + classNameTypedef::m_DataMap.dataDesc = dataDesc; \ + } \ + return &classNameTypedef::m_DataMap; \ + } + +// used for when there is no data description +#define IMPLEMENT_NULL_SIMPLE_DATADESC( derivedClass ) \ + BEGIN_SIMPLE_DATADESC( derivedClass ) \ + END_DATADESC() + +#define IMPLEMENT_NULL_SIMPLE_DATADESC_( derivedClass, baseClass ) \ + BEGIN_SIMPLE_DATADESC_( derivedClass, baseClass ) \ + END_DATADESC() + +#define IMPLEMENT_NULL_DATADESC( derivedClass ) \ + BEGIN_DATADESC( derivedClass ) \ + END_DATADESC() + +// helps get the offset of a bitfield +#define BEGIN_BITFIELD( name ) \ + union \ + { \ + char name; \ + struct \ + { + +#define END_BITFIELD() \ + }; \ + }; + +//----------------------------------------------------------------------------- +// Forward compatability with potential seperate byteswap datadescs + +#define DECLARE_BYTESWAP_DATADESC() DECLARE_SIMPLE_DATADESC() +#define BEGIN_BYTESWAP_DATADESC(name) BEGIN_SIMPLE_DATADESC(name) +#define BEGIN_BYTESWAP_DATADESC_(name,base) BEGIN_SIMPLE_DATADESC_(name,base) +#define END_BYTESWAP_DATADESC() END_DATADESC() + +//----------------------------------------------------------------------------- + +template <typename T> +inline void DataMapAccess(T *ignored, datamap_t **p) +{ + *p = &T::m_DataMap; +} + +//----------------------------------------------------------------------------- + +class CDatadescGeneratedNameHolder +{ +public: + CDatadescGeneratedNameHolder( const char *pszBase ) + : m_pszBase(pszBase) + { + m_nLenBase = strlen( m_pszBase ); + } + + ~CDatadescGeneratedNameHolder() + { + for ( int i = 0; i < m_Names.Count(); i++ ) + { + delete m_Names[i]; + } + } + + const char *GenerateName( const char *pszIdentifier ) + { + char *pBuf = new char[m_nLenBase + strlen(pszIdentifier) + 1]; + strcpy( pBuf, m_pszBase ); + strcat( pBuf, pszIdentifier ); + m_Names.AddToTail( pBuf ); + return pBuf; + } + +private: + const char *m_pszBase; + size_t m_nLenBase; + CUtlVector<char *> m_Names; +}; + +//----------------------------------------------------------------------------- + +// Compiler can require the global-namespace template friend to be declared +// before DECLARE_SIMPLE_DATADESC_INSIDE_NAMESPACE() can be used +template <typename T> datamap_t *DataMapInit(T *); + +#include "tier0/memdbgoff.h" + +#endif // DATAMAP_H diff --git a/external/vpc/public/filesystem.h b/external/vpc/public/filesystem.h new file mode 100644 index 0000000..81d4d98 --- /dev/null +++ b/external/vpc/public/filesystem.h @@ -0,0 +1,958 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef FILESYSTEM_H +#define FILESYSTEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include <limits.h> + +#include "tier0/threadtools.h" +#include "tier0/memalloc.h" +#include "tier0/tslist.h" +#include "tier1/interface.h" +#include "tier1/utlsymbol.h" +#include "tier1/utlstring.h" +#include "tier1/functors.h" +#include "tier1/checksum_crc.h" +#include "tier1/utlqueue.h" +#include "appframework/iappsystem.h" +#include "tier2/tier2.h" +#ifdef _PS3 +#include <sysutil/sysutil_syscache.h> +#include <sysutil/sysutil_gamecontent.h> +struct HddCacheFileStatus; +extern char gSrcGameDataPath[]; +class CFileGroupSystem; +#endif + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + +class CUtlBuffer; +class KeyValues; +class IFileList; + +typedef void * FileHandle_t; +typedef int FileFindHandle_t; +typedef void (*FileSystemLoggingFunc_t)( const char *fileName, const char *accessType ); +typedef int WaitForResourcesHandle_t; + +#ifdef _X360 +typedef void* HANDLE; +#endif + +//----------------------------------------------------------------------------- +// Enums used by the interface +//----------------------------------------------------------------------------- + +#define FILESYSTEM_MAX_SEARCH_PATHS 128 + +enum FileSystemSeek_t +{ + FILESYSTEM_SEEK_HEAD = SEEK_SET, + FILESYSTEM_SEEK_CURRENT = SEEK_CUR, + FILESYSTEM_SEEK_TAIL = SEEK_END, +}; + +enum +{ + FILESYSTEM_INVALID_FIND_HANDLE = -1 +}; + +enum FileWarningLevel_t +{ + // A problem! + FILESYSTEM_WARNING = -1, + + // Don't print anything + FILESYSTEM_WARNING_QUIET = 0, + + // On shutdown, report names of files left unclosed + FILESYSTEM_WARNING_REPORTUNCLOSED, + + // Report number of times a file was opened, closed + FILESYSTEM_WARNING_REPORTUSAGE, + + // Report all open/close events to console ( !slow! ) + FILESYSTEM_WARNING_REPORTALLACCESSES, + + // Report all open/close/read events to the console ( !slower! ) + FILESYSTEM_WARNING_REPORTALLACCESSES_READ, + + // Report all open/close/read/write events to the console ( !slower! ) + FILESYSTEM_WARNING_REPORTALLACCESSES_READWRITE, + + // Report all open/close/read/write events and all async I/O file events to the console ( !slower(est)! ) + FILESYSTEM_WARNING_REPORTALLACCESSES_ASYNC, + +}; + +// search path filtering +enum PathTypeFilter_t +{ + FILTER_NONE = 0, // no filtering, all search path types match + FILTER_CULLPACK = 1, // pack based search paths are culled (maps and zips) + FILTER_CULLNONPACK = 2, // non-pack based search paths are culled + FILTER_CULLLOCALIZED = 3, // Ignore localized paths, assumes CULLNONPACK + FILTER_CULLLOCALIZED_ANY = 4, // Ignore any localized paths +}; + +// search path querying (bit flags) +enum +{ + PATH_IS_NORMAL = 0x00, // normal path, not pack based + PATH_IS_PACKFILE = 0x01, // path is a pack file + PATH_IS_MAPPACKFILE = 0x02, // path is a map pack file + PATH_IS_DVDDEV = 0x04, // path is the dvddev cache +}; +typedef uint32 PathTypeQuery_t; + +#define IS_PACKFILE( n ) ( n & ( PATH_IS_PACKFILE | PATH_IS_MAPPACKFILE ) ) +#define IS_DVDDEV( n ) ( n & PATH_IS_DVDDEV ) + +enum DVDMode_t +{ + DVDMODE_OFF = 0, // not using dvd + DVDMODE_STRICT = 1, // dvd device only + DVDMODE_DEV = 2, // dev mode, mutiple devices ok + DVDMODE_DEV_VISTA = 3, // dev mode from a vista host, mutiple devices ok +}; + +#ifdef _PS3 + +enum FsState_t +{ + FS_STATE_INIT = 0, + FS_STATE_LEVEL_LOAD = 1, + FS_STATE_LEVEL_RUN = 2, + FS_STATE_LEVEL_RESTORE = 3, + FS_STATE_LEVEL_LOAD_END = 4, + FS_STATE_EXITING = 5 +}; + +enum Ps3FileType_t +{ + PS3_FILETYPE_WAV, + PS3_FILETYPE_ANI, + PS3_FILETYPE_BSP, + PS3_FILETYPE_VMT, + PS3_FILETYPE_QPRE, + PS3_FILETYPE_OTHER, + PS3_FILETYPE_DIR, + PS3_FILETYPE_UNKNOWN +}; + + +#endif + +// In non-retail builds, enable the file blocking access tracking stuff... +#if defined( TRACK_BLOCKING_IO ) +enum FileBlockingWarning_t +{ + // Report how long synchronous i/o took to complete + FILESYSTEM_BLOCKING_SYNCHRONOUS = 0, + // Report how long async i/o took to complete if AsyncFileFinished caused it to load via "blocking" i/o + FILESYSTEM_BLOCKING_ASYNCHRONOUS_BLOCK, + // Report how long async i/o took to complete + FILESYSTEM_BLOCKING_ASYNCHRONOUS, + // Report how long the async "callback" took + FILESYSTEM_BLOCKING_CALLBACKTIMING, + + FILESYSTEM_BLOCKING_NUMBINS, +}; + +#pragma pack(1) +class FileBlockingItem +{ +public: + enum + { + FB_ACCESS_OPEN = 1, + FB_ACCESS_CLOSE = 2, + FB_ACCESS_READ = 3, + FB_ACCESS_WRITE = 4, + FB_ACCESS_APPEND = 5, + FB_ACCESS_SIZE = 6 + }; + + FileBlockingItem() : + m_ItemType( (FileBlockingWarning_t)0 ), + m_flElapsed( 0.0f ), + m_nAccessType( 0 ) + { + SetFileName( NULL ); + } + + FileBlockingItem( int type, char const *filename, float elapsed, int accessType ) : + m_ItemType( (FileBlockingWarning_t)type ), + m_flElapsed( elapsed ), + m_nAccessType( accessType ) + { + SetFileName( filename ); + } + + void SetFileName( char const *filename ) + { + if ( !filename ) + { + m_szFilename[ 0 ] = 0; + return; + } + + int len = V_strlen( filename ); + if ( len >= sizeof( m_szFilename ) ) + { + V_strncpy( m_szFilename, &filename[ len - sizeof( m_szFilename ) + 1 ], sizeof( m_szFilename ) ); + } + else + { + V_strncpy( m_szFilename, filename, sizeof( m_szFilename ) ); + } + } + + char const *GetFileName() const + { + return m_szFilename; + } + + FileBlockingWarning_t m_ItemType; + float m_flElapsed; + byte m_nAccessType; +private: + + char m_szFilename[ 32 ]; +}; +#pragma pack() + +class IBlockingFileItemList +{ +public: + + // You can't call any of the below calls without locking first + virtual void LockMutex() = 0; + virtual void UnlockMutex() = 0; + + virtual int First() const = 0; + virtual int Next( int i ) const = 0; + virtual int InvalidIndex() const = 0; + + virtual const FileBlockingItem& Get( int index ) const = 0; + + virtual void Reset() = 0; +}; + +#endif // TRACK_BLOCKING_IO + +enum FilesystemMountRetval_t +{ + FILESYSTEM_MOUNT_OK = 0, + FILESYSTEM_MOUNT_FAILED, +}; + +enum SearchPathAdd_t +{ + PATH_ADD_TO_HEAD, // First path searched + PATH_ADD_TO_TAIL, // Last path searched + PATH_ADD_TO_TAIL_ATINDEX, // First path searched +}; + +enum FilesystemOpenExFlags_t +{ + FSOPEN_UNBUFFERED = (1 << 0), + FSOPEN_FORCE_TRACK_CRC = (1 << 1), // This makes it calculate a CRC for the file (if the file came from disk) regardless + // of the IFileList passed to RegisterFileWhitelist. + FSOPEN_NEVERINPACK = (1 << 2), // 360 only, hint to FS that file is not allowed to be in pack file +}; + +#define FILESYSTEM_INVALID_HANDLE ( FileHandle_t )0 + +//----------------------------------------------------------------------------- +// Structures used by the interface +//----------------------------------------------------------------------------- + +struct FileSystemStatistics +{ + CInterlockedUInt nReads, + nWrites, + nBytesRead, + nBytesWritten, + nSeeks; +}; + +//----------------------------------------------------------------------------- +// File system allocation functions. Client must free on failure +//----------------------------------------------------------------------------- +typedef void *(*FSAllocFunc_t)( const char *pszFilename, unsigned nBytes ); + + +//----------------------------------------------------------------------------- +// Used to display dirty disk error functions +//----------------------------------------------------------------------------- +typedef void (*FSDirtyDiskReportFunc_t)(); + + +//----------------------------------------------------------------------------- +// Asynchronous support types +//----------------------------------------------------------------------------- +DECLARE_POINTER_HANDLE(FSAsyncControl_t); +DECLARE_POINTER_HANDLE(FSAsyncFile_t); +const FSAsyncFile_t FS_INVALID_ASYNC_FILE = (FSAsyncFile_t)(0x0000ffff); + + +//--------------------------------------------------------- +// Async file status +//--------------------------------------------------------- +enum FSAsyncStatus_t +{ + FSASYNC_ERR_ALIGNMENT = -6, // read parameters invalid for unbuffered IO + FSASYNC_ERR_FAILURE = -5, // hard subsystem failure + FSASYNC_ERR_READING = -4, // read error on file + FSASYNC_ERR_NOMEMORY = -3, // out of memory for file read + FSASYNC_ERR_UNKNOWNID = -2, // caller's provided id is not recognized + FSASYNC_ERR_FILEOPEN = -1, // filename could not be opened (bad path, not exist, etc) + FSASYNC_OK = 0, // operation is successful + FSASYNC_STATUS_PENDING, // file is properly queued, waiting for service + FSASYNC_STATUS_INPROGRESS, // file is being accessed + FSASYNC_STATUS_ABORTED, // file was aborted by caller + FSASYNC_STATUS_UNSERVICED, // file is not yet queued +}; + +//--------------------------------------------------------- +// Async request flags +//--------------------------------------------------------- +enum FSAsyncFlags_t +{ + FSASYNC_FLAGS_ALLOCNOFREE = ( 1 << 0 ), // do the allocation for dataPtr, but don't free + FSASYNC_FLAGS_FREEDATAPTR = ( 1 << 1 ), // free the memory for the dataPtr post callback + FSASYNC_FLAGS_SYNC = ( 1 << 2 ), // Actually perform the operation synchronously. Used to simplify client code paths + FSASYNC_FLAGS_NULLTERMINATE = ( 1 << 3 ), // allocate an extra byte and null terminate the buffer read in +}; + +//--------------------------------------------------------- +// Return value for CheckFileCRC. +//--------------------------------------------------------- +enum EFileCRCStatus +{ + k_eFileCRCStatus_CantOpenFile, // We don't have this file. + k_eFileCRCStatus_GotCRC +}; + +// Used in CacheFileCRCs. +enum ECacheCRCType +{ + k_eCacheCRCType_SingleFile, + k_eCacheCRCType_Directory, + k_eCacheCRCType_Directory_Recursive +}; + +//--------------------------------------------------------- +// Optional completion callback for each async file serviced (or failed) +// call is not reentrant, async i/o guaranteed suspended until return +// Note: If you change the signature of the callback, you will have to account for it in FileSystemV12 (toml [4/18/2005] ) +//--------------------------------------------------------- +struct FileAsyncRequest_t; +typedef void (*FSAsyncCallbackFunc_t)(const FileAsyncRequest_t &request, int nBytesRead, FSAsyncStatus_t err); + +//----------------------------------------------------------------------------- +// Used to add results from async directory scans +//----------------------------------------------------------------------------- +typedef void (*FSAsyncScanAddFunc_t)( void* pContext, char* pFoundPath, char* pFoundFile ); +typedef void (*FSAsyncScanCompleteFunc_t)( void* pContext, FSAsyncStatus_t err ); + +//--------------------------------------------------------- +// Description of an async request +//--------------------------------------------------------- +struct FileAsyncRequest_t +{ + FileAsyncRequest_t() { memset( this, 0, sizeof(*this) ); hSpecificAsyncFile = FS_INVALID_ASYNC_FILE; } + const char * pszFilename; // file system name + void * pData; // optional, system will alloc/free if NULL + int nOffset; // optional initial seek_set, 0=beginning + int nBytes; // optional read clamp, -1=exist test, 0=full read + FSAsyncCallbackFunc_t pfnCallback; // optional completion callback + void * pContext; // caller's unique file identifier + int priority; // inter list priority, 0=lowest + unsigned flags; // behavior modifier + const char * pszPathID; // path ID (NOTE: this field is here to remain binary compatible with release HL2 filesystem interface) + FSAsyncFile_t hSpecificAsyncFile; // Optional hint obtained using AsyncBeginRead() + FSAllocFunc_t pfnAlloc; // custom allocator. can be null. not compatible with FSASYNC_FLAGS_FREEDATAPTR +}; + + +class CUnverifiedCRCFile +{ +public: + char m_PathID[MAX_PATH]; + char m_Filename[MAX_PATH]; + CRC32_t m_CRC; +}; + + +// Spew flags for SetWhitelistSpewFlags (set with the fs_whitelist_spew_flags cvar). +// Update the comment for the fs_whitelist_spew_flags cvar if you change these. +#define WHITELIST_SPEW_WHILE_LOADING 0x0001 // list files as they are added to the CRC tracker +#define WHITELIST_SPEW_RELOAD_FILES 0x0002 // show files the filesystem is telling the engine to reload +#define WHITELIST_SPEW_DONT_RELOAD_FILES 0x0004 // show files the filesystem is NOT telling the engine to reload + + + +// DLC license mask flags is 32 publisher defined bits +// MSW 16 bits in 8.8: Type.SubVersion +// LSW 16 bits: Flags + +// return id component +#define DLC_LICENSE_ID( x ) ( ( ( (unsigned int)( x ) ) >> 24 ) & 0x000000FF ) +// returns minor version component (not generally used, i.e. we dont rev dlc's yet) +#define DLC_LICENSE_MINORVERSION( x ) ( ( ( (unsigned int)( x ) ) >> 16 ) & 0x000000FF ) +// returns license flags +#define DLC_LICENSE_FLAGS( x ) ( ( ( (unsigned int)( x ) ) & 0x0000FFFF ) ) + +#define DLCFLAGS_PRESENCE_ONLY 0x0001 // causes no search path loadout + + + +//----------------------------------------------------------------------------- +// Base file system interface +//----------------------------------------------------------------------------- + +// This is the minimal interface that can be implemented to provide access to +// a named set of files. +#define BASEFILESYSTEM_INTERFACE_VERSION "VBaseFileSystem011" + +abstract_class IBaseFileSystem +{ +public: + virtual int Read( void* pOutput, int size, FileHandle_t file ) = 0; + virtual int Write( void const* pInput, int size, FileHandle_t file ) = 0; + + // if pathID is NULL, all paths will be searched for the file + virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID = 0 ) = 0; + virtual void Close( FileHandle_t file ) = 0; + + + virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t seekType ) = 0; + virtual unsigned int Tell( FileHandle_t file ) = 0; + virtual unsigned int Size( FileHandle_t file ) = 0; + virtual unsigned int Size( const char *pFileName, const char *pPathID = 0 ) = 0; + + virtual void Flush( FileHandle_t file ) = 0; + virtual bool Precache( const char *pFileName, const char *pPathID = 0 ) = 0; + + virtual bool FileExists( const char *pFileName, const char *pPathID = 0 ) = 0; + virtual bool IsFileWritable( char const *pFileName, const char *pPathID = 0 ) = 0; + virtual bool SetFileWritable( char const *pFileName, bool writable, const char *pPathID = 0 ) = 0; + + virtual long GetFileTime( const char *pFileName, const char *pPathID = 0 ) = 0; + + //-------------------------------------------------------- + // Reads/writes files to utlbuffers. Use this for optimal read performance when doing open/read/close + //-------------------------------------------------------- + virtual bool ReadFile( const char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL ) = 0; + virtual bool WriteFile( const char *pFileName, const char *pPath, CUtlBuffer &buf ) = 0; + virtual bool UnzipFile( const char *pFileName, const char *pPath, const char *pDestination ) = 0; +}; + +abstract_class IIoStats +{ +public: + virtual void OnFileSeek( int nTimeInMs ) = 0; + virtual void OnFileRead( int nTimeInMs, int nBytesRead ) = 0; + virtual void OnFileOpen( const char * pFileName ) = 0; + + virtual int GetNumberOfFileSeeks() = 0; + virtual int GetTimeInFileSeek() = 0; + + virtual int GetNumberOfFileReads() = 0; + virtual int GetTimeInFileReads() = 0; + virtual int GetFileReadTotalSize() = 0; + + virtual int GetNumberOfFileOpens() = 0; + + virtual void Reset() = 0; + +protected: + virtual ~IIoStats() + { + // Do nothing... + } +}; + +//----------------------------------------------------------------------------- +// Main file system interface +//----------------------------------------------------------------------------- +abstract_class IFileSystem : public IAppSystem, public IBaseFileSystem +{ +public: + //-------------------------------------------------------- + // Steam operations + //-------------------------------------------------------- + + virtual bool IsSteam() const = 0; + + // Supplying an extra app id will mount this app in addition + // to the one specified in the environment variable "steamappid" + // + // If nExtraAppId is < -1, then it will mount that app ID only. + // (Was needed by the dedicated server b/c the "SteamAppId" env var only gets passed to steam.dll + // at load time, so the dedicated couldn't pass it in that way). + virtual FilesystemMountRetval_t MountSteamContent( int nExtraAppId = -1 ) = 0; + + //-------------------------------------------------------- + // Search path manipulation + //-------------------------------------------------------- + + // Add paths in priority order (mod dir, game dir, ....) + // If one or more .pak files are in the specified directory, then they are + // added after the file system path + // If the path is the relative path to a .bsp file, then any previous .bsp file + // override is cleared and the current .bsp is searched for an embedded PAK file + // and this file becomes the highest priority search path ( i.e., it's looked at first + // even before the mod's file system path ). + virtual void AddSearchPath( const char *pPath, const char *pathID, SearchPathAdd_t addType = PATH_ADD_TO_TAIL ) = 0; + virtual bool RemoveSearchPath( const char *pPath, const char *pathID = 0 ) = 0; + + // Remove all search paths (including write path?) + virtual void RemoveAllSearchPaths( void ) = 0; + + // Remove search paths associated with a given pathID + virtual void RemoveSearchPaths( const char *szPathID ) = 0; + + // This is for optimization. If you mark a path ID as "by request only", then files inside it + // will only be accessed if the path ID is specifically requested. Otherwise, it will be ignored. + // If there are currently no search paths with the specified path ID, then it will still + // remember it in case you add search paths with this path ID. + virtual void MarkPathIDByRequestOnly( const char *pPathID, bool bRequestOnly ) = 0; + + // converts a partial path into a full path + virtual const char *RelativePathToFullPath( const char *pFileName, const char *pPathID, char *pLocalPath, int localPathBufferSize, PathTypeFilter_t pathFilter = FILTER_NONE, PathTypeQuery_t *pPathType = NULL ) = 0; +#if IsGameConsole() + // Given a relative path, gets the PACK file that contained this file and its offset and size. Can be used to prefetch a file to a HDD for caching reason. + virtual bool GetPackFileInfoFromRelativePath( const char *pFileName, const char *pPathID, char *pPackPath, int nPackPathBufferSize, int64 &nPosition, int64 &nLength ) = 0; +#endif + // Returns the search path, each path is separated by ;s. Returns the length of the string returned + virtual int GetSearchPath( const char *pathID, bool bGetPackFiles, char *pPath, int nMaxLen ) = 0; + + // interface for custom pack files > 4Gb + virtual bool AddPackFile( const char *fullpath, const char *pathID ) = 0; + + //-------------------------------------------------------- + // File manipulation operations + //-------------------------------------------------------- + + // Deletes a file (on the WritePath) + virtual void RemoveFile( char const* pRelativePath, const char *pathID = 0 ) = 0; + + // Renames a file (on the WritePath) + virtual bool RenameFile( char const *pOldPath, char const *pNewPath, const char *pathID = 0 ) = 0; + + // create a local directory structure + virtual void CreateDirHierarchy( const char *path, const char *pathID = 0 ) = 0; + + // File I/O and info + virtual bool IsDirectory( const char *pFileName, const char *pathID = 0 ) = 0; + + virtual void FileTimeToString( char* pStrip, int maxCharsIncludingTerminator, long fileTime ) = 0; + + //-------------------------------------------------------- + // Open file operations + //-------------------------------------------------------- + + virtual void SetBufferSize( FileHandle_t file, unsigned nBytes ) = 0; + + virtual bool IsOk( FileHandle_t file ) = 0; + + virtual bool EndOfFile( FileHandle_t file ) = 0; + + virtual char *ReadLine( char *pOutput, int maxChars, FileHandle_t file ) = 0; + virtual int FPrintf( FileHandle_t file, const char *pFormat, ... ) FMTFUNCTION( 3, 4 ) = 0; + + //-------------------------------------------------------- + // Dynamic library operations + //-------------------------------------------------------- + + // load/unload modules + virtual CSysModule *LoadModule( const char *pFileName, const char *pPathID = 0, bool bValidatedDllOnly = true ) = 0; + virtual void UnloadModule( CSysModule *pModule ) = 0; + + //-------------------------------------------------------- + // File searching operations + //-------------------------------------------------------- + + // FindFirst/FindNext. Also see FindFirstEx. + virtual const char *FindFirst( const char *pWildCard, FileFindHandle_t *pHandle ) = 0; + virtual const char *FindNext( FileFindHandle_t handle ) = 0; + virtual bool FindIsDirectory( FileFindHandle_t handle ) = 0; + virtual void FindClose( FileFindHandle_t handle ) = 0; + + // Same as FindFirst, but you can filter by path ID, which can make it faster. + virtual const char *FindFirstEx( + const char *pWildCard, + const char *pPathID, + FileFindHandle_t *pHandle + ) = 0; + + // Searches for a file in all paths and results absolute path names for the file, works in pack files (zip and vpk) too + // Lets you search for something like sound/sound.cache and get a list of every sound cache + virtual void FindFileAbsoluteList( CUtlVector< CUtlString > &outAbsolutePathNames, const char *pWildCard, const char *pPathID ) = 0; + + //-------------------------------------------------------- + // File name and directory operations + //-------------------------------------------------------- + + // FIXME: This method is obsolete! Use RelativePathToFullPath instead! + // converts a partial path into a full path + virtual const char *GetLocalPath( const char *pFileName, char *pLocalPath, int localPathBufferSize ) = 0; + + // Returns true on success ( based on current list of search paths, otherwise false if + // it can't be resolved ) + virtual bool FullPathToRelativePath( const char *pFullpath, char *pRelative, int maxlen ) = 0; + + // Gets the current working directory + virtual bool GetCurrentDirectory( char* pDirectory, int maxlen ) = 0; + + //-------------------------------------------------------- + // Filename dictionary operations + //-------------------------------------------------------- + + virtual FileNameHandle_t FindOrAddFileName( char const *pFileName ) = 0; + virtual bool String( const FileNameHandle_t& handle, char *buf, int buflen ) = 0; + + //-------------------------------------------------------- + // Asynchronous file operations + //-------------------------------------------------------- + + //------------------------------------ + // Global operations + //------------------------------------ + FSAsyncStatus_t AsyncRead( const FileAsyncRequest_t &request, FSAsyncControl_t *phControl = NULL ) { return AsyncReadMultiple( &request, 1, phControl ); } + virtual FSAsyncStatus_t AsyncReadMultiple( const FileAsyncRequest_t *pRequests, int nRequests, FSAsyncControl_t *phControls = NULL ) = 0; + virtual FSAsyncStatus_t AsyncAppend(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, FSAsyncControl_t *pControl = NULL ) = 0; + virtual FSAsyncStatus_t AsyncAppendFile(const char *pAppendToFileName, const char *pAppendFromFileName, FSAsyncControl_t *pControl = NULL ) = 0; + virtual void AsyncFinishAll( int iToPriority = 0 ) = 0; + virtual void AsyncFinishAllWrites() = 0; + virtual FSAsyncStatus_t AsyncFlush() = 0; + virtual bool AsyncSuspend() = 0; + virtual bool AsyncResume() = 0; + + //------------------------------------ + // Functions to hold a file open if planning on doing mutiple reads. Use is optional, + // and is taken only as a hint + //------------------------------------ + virtual FSAsyncStatus_t AsyncBeginRead( const char *pszFile, FSAsyncFile_t *phFile ) = 0; + virtual FSAsyncStatus_t AsyncEndRead( FSAsyncFile_t hFile ) = 0; + + //------------------------------------ + // Request management + //------------------------------------ + virtual FSAsyncStatus_t AsyncFinish( FSAsyncControl_t hControl, bool wait = true ) = 0; + virtual FSAsyncStatus_t AsyncGetResult( FSAsyncControl_t hControl, void **ppData, int *pSize ) = 0; + virtual FSAsyncStatus_t AsyncAbort( FSAsyncControl_t hControl ) = 0; + virtual FSAsyncStatus_t AsyncStatus( FSAsyncControl_t hControl ) = 0; + // set a new priority for a file already in the queue + virtual FSAsyncStatus_t AsyncSetPriority(FSAsyncControl_t hControl, int newPriority) = 0; + virtual void AsyncAddRef( FSAsyncControl_t hControl ) = 0; + virtual void AsyncRelease( FSAsyncControl_t hControl ) = 0; + + //-------------------------------------------------------- + // Remote resource management + //-------------------------------------------------------- + + // starts waiting for resources to be available + // returns FILESYSTEM_INVALID_HANDLE if there is nothing to wait on + virtual WaitForResourcesHandle_t WaitForResources( const char *resourcelist ) = 0; + // get progress on waiting for resources; progress is a float [0, 1], complete is true on the waiting being done + // returns false if no progress is available + // any calls after complete is true or on an invalid handle will return false, 0.0f, true + virtual bool GetWaitForResourcesProgress( WaitForResourcesHandle_t handle, float *progress /* out */ , bool *complete /* out */ ) = 0; + // cancels a progress call + virtual void CancelWaitForResources( WaitForResourcesHandle_t handle ) = 0; + + // hints that a set of files will be loaded in near future + // HintResourceNeed() is not to be confused with resource precaching. + virtual int HintResourceNeed( const char *hintlist, int forgetEverything ) = 0; + // returns true if a file is on disk + virtual bool IsFileImmediatelyAvailable(const char *pFileName) = 0; + + // copies file out of pak/bsp/steam cache onto disk (to be accessible by third-party code) + virtual void GetLocalCopy( const char *pFileName ) = 0; + + //-------------------------------------------------------- + // Debugging operations + //-------------------------------------------------------- + + // Dump to printf/OutputDebugString the list of files that have not been closed + virtual void PrintOpenedFiles( void ) = 0; + virtual void PrintSearchPaths( void ) = 0; + + // output + virtual void SetWarningFunc( void (*pfnWarning)( const char *fmt, ... ) ) = 0; + virtual void SetWarningLevel( FileWarningLevel_t level ) = 0; + virtual void AddLoggingFunc( void (*pfnLogFunc)( const char *fileName, const char *accessType ) ) = 0; + virtual void RemoveLoggingFunc( FileSystemLoggingFunc_t logFunc ) = 0; + + // Returns the file system statistics retreived by the implementation. Returns NULL if not supported. + virtual const FileSystemStatistics *GetFilesystemStatistics() = 0; + +#if defined( _PS3 ) + // EA cruft not used: virtual Ps3FileType_t GetPs3FileType(const char* path) = 0; + virtual void LogFileAccess( const char *pFullFileName ) = 0; + + // Prefetches a full file in the HDD cache. + virtual bool PrefetchFile( const char *pFileName, int nPriority, bool bPersist ) = 0; + // Prefetches a file portion in the HDD cache. + virtual bool PrefetchFile( const char *pFileName, int nPriority, bool bPersist, int64 nOffset, int64 nSize ) = 0; + // Flushes the HDD cache. + virtual void FlushCache() = 0; + // Suspends all prefetches (like when the game is doing a file intensive operation not controlled by the HDD cache, like Bink movies). + virtual void SuspendPrefetches( const char *pWhy ) = 0; + // Resumes prefetches. This function has to to be called as many time as SuspendPrefetches() to effectively resumes prefetches. + virtual void ResumePrefetches( const char * pWhy ) = 0; + + // Gets called when we are starting / ending a save (it allows the file system to reduce its HDD usage and use BluRay instead). + virtual void OnSaveStateChanged( bool bSaving ) = 0; + + // Returns the prefetching state. If true, everything has been prefetched on the HDD. + virtual bool IsPrefetchingDone() = 0; + +#endif //_PS3 + //-------------------------------------------------------- + // Start of new functions after Lost Coast release (7/05) + //-------------------------------------------------------- + + virtual FileHandle_t OpenEx( const char *pFileName, const char *pOptions, unsigned flags = 0, const char *pathID = 0, char **ppszResolvedFilename = NULL ) = 0; + + // Extended version of read provides more context to allow for more optimal reading + virtual int ReadEx( void* pOutput, int sizeDest, int size, FileHandle_t file ) = 0; + virtual int ReadFileEx( const char *pFileName, const char *pPath, void **ppBuf, bool bNullTerminate = false, bool bOptimalAlloc = false, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL ) = 0; + + virtual FileNameHandle_t FindFileName( char const *pFileName ) = 0; + +#if defined( TRACK_BLOCKING_IO ) + virtual void EnableBlockingFileAccessTracking( bool state ) = 0; + virtual bool IsBlockingFileAccessEnabled() const = 0; + + virtual IBlockingFileItemList *RetrieveBlockingFileAccessInfo() = 0; +#endif + + virtual void SetupPreloadData() = 0; + virtual void DiscardPreloadData() = 0; + + // Fixme, we could do these via a string embedded into the compiled data, etc... + enum KeyValuesPreloadType_t + { + TYPE_VMT, + TYPE_SOUNDEMITTER, + TYPE_SOUNDSCAPE, + TYPE_SOUNDOPERATORS, + NUM_PRELOAD_TYPES + }; + + // If the "PreloadedData" hasn't been purged, then this'll try and instance the KeyValues using the fast path of compiled keyvalues loaded during startup. + // Otherwise, it'll just fall through to the regular KeyValues loading routines + virtual KeyValues *LoadKeyValues( KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 ) = 0; + virtual bool LoadKeyValues( KeyValues& head, KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 ) = 0; + + virtual FSAsyncStatus_t AsyncWrite(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend = false, FSAsyncControl_t *pControl = NULL ) = 0; + virtual FSAsyncStatus_t AsyncWriteFile(const char *pFileName, const CUtlBuffer *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend = false, FSAsyncControl_t *pControl = NULL ) = 0; + // Async read functions with memory blame + FSAsyncStatus_t AsyncReadCreditAlloc( const FileAsyncRequest_t &request, const char *pszFile, int line, FSAsyncControl_t *phControl = NULL ) { return AsyncReadMultipleCreditAlloc( &request, 1, pszFile, line, phControl ); } + virtual FSAsyncStatus_t AsyncReadMultipleCreditAlloc( const FileAsyncRequest_t *pRequests, int nRequests, const char *pszFile, int line, FSAsyncControl_t *phControls = NULL ) = 0; + + virtual FSAsyncStatus_t AsyncDirectoryScan( const char* pSearchSpec, bool recurseFolders, void* pContext, FSAsyncScanAddFunc_t pfnAdd, FSAsyncScanCompleteFunc_t pfnDone, FSAsyncControl_t *pControl = NULL ) = 0; + + virtual bool GetFileTypeForFullPath( char const *pFullPath, wchar_t *buf, size_t bufSizeInBytes ) = 0; + + //-------------------------------------------------------- + //-------------------------------------------------------- + virtual bool ReadToBuffer( FileHandle_t hFile, CUtlBuffer &buf, int nMaxBytes = 0, FSAllocFunc_t pfnAlloc = NULL ) = 0; + + //-------------------------------------------------------- + // Optimal IO operations + //-------------------------------------------------------- + virtual bool GetOptimalIOConstraints( FileHandle_t hFile, unsigned *pOffsetAlign, unsigned *pSizeAlign, unsigned *pBufferAlign ) = 0; + inline unsigned GetOptimalReadSize( FileHandle_t hFile, unsigned nLogicalSize ); + virtual void *AllocOptimalReadBuffer( FileHandle_t hFile, unsigned nSize = 0, unsigned nOffset = 0 ) = 0; + virtual void FreeOptimalReadBuffer( void * ) = 0; + + //-------------------------------------------------------- + // + //-------------------------------------------------------- + virtual void BeginMapAccess() = 0; + virtual void EndMapAccess() = 0; + + // Returns true on success, otherwise false if it can't be resolved + virtual bool FullPathToRelativePathEx( const char *pFullpath, const char *pPathId, char *pRelative, int maxlen ) = 0; + + virtual int GetPathIndex( const FileNameHandle_t &handle ) = 0; + virtual long GetPathTime( const char *pPath, const char *pPathID ) = 0; + + virtual DVDMode_t GetDVDMode() = 0; + + //-------------------------------------------------------- + // Whitelisting for pure servers. + //-------------------------------------------------------- + + // This should be called ONCE at startup. Multiplayer games (gameinfo.txt does not contain singleplayer_only) + // want to enable this so sv_pure works. + virtual void EnableWhitelistFileTracking( bool bEnable ) = 0; + + // This is called when the client connects to a server using a pure_server_whitelist.txt file. + // + // Files listed in pWantCRCList will have CRCs calculated for them IF they come off disk + // (and those CRCs will come out of GetUnverifiedCRCFiles). + // + // Files listed in pAllowFromDiskList will be allowed to load from disk. All other files will + // be forced to come from Steam. + // + // The filesystem hangs onto the whitelists you pass in here, and it will Release() them when it closes down + // or when you call this function again. + // + // NOTE: The whitelists you pass in here will be accessed from multiple threads, so make sure the + // IsFileInList function is thread safe. + // + // If pFilesToReload is non-null, the filesystem will hand back a list of files that should be reloaded because they + // are now "dirty". For example, if you were on a non-pure server and you loaded a certain model, and then you connected + // to a pure server that said that model had to come from Steam, then pFilesToReload would specify that model + // and the engine should reload it so it can come from Steam. + // + // Be sure to call Release() on pFilesToReload. + virtual void RegisterFileWhitelist( IFileList *pWantCRCList, IFileList *pAllowFromDiskList, IFileList **pFilesToReload ) = 0; + + // Called when the client logs onto a server. Any files that came off disk should be marked as + // unverified because this server may have a different set of files it wants to guarantee. + virtual void MarkAllCRCsUnverified() = 0; + + // As the server loads whitelists when it transitions maps, it calls this to calculate CRCs for any files marked + // with check_crc. Then it calls CheckCachedFileCRC later when it gets client requests to verify CRCs. + virtual void CacheFileCRCs( const char *pPathname, ECacheCRCType eType, IFileList *pFilter ) = 0; + virtual EFileCRCStatus CheckCachedFileCRC( const char *pPathID, const char *pRelativeFilename, CRC32_t *pCRC ) = 0; + + // Fills in the list of files that have been loaded off disk and have not been verified. + // Returns the number of files filled in (between 0 and nMaxFiles). + // + // This also removes any files it's returning from the unverified CRC list, so they won't be + // returned from here again. + // The client sends batches of these to the server to verify. + virtual int GetUnverifiedCRCFiles( CUnverifiedCRCFile *pFiles, int nMaxFiles ) = 0; + + // Control debug message output. + // Pass a combination of WHITELIST_SPEW_ flags. + virtual int GetWhitelistSpewFlags() = 0; + virtual void SetWhitelistSpewFlags( int flags ) = 0; + + // Installs a callback used to display a dirty disk dialog + virtual void InstallDirtyDiskReportFunc( FSDirtyDiskReportFunc_t func ) = 0; + + virtual bool IsLaunchedFromXboxHDD() = 0; + virtual bool IsInstalledToXboxHDDCache() = 0; + virtual bool IsDVDHosted() = 0; + virtual bool IsInstallAllowed() = 0; + + virtual int GetSearchPathID( char *pPath, int nMaxLen ) = 0; + virtual bool FixupSearchPathsAfterInstall() = 0; + + virtual FSDirtyDiskReportFunc_t GetDirtyDiskReportFunc() = 0; + + virtual void AddVPKFile( char const *pszName, SearchPathAdd_t addType = PATH_ADD_TO_TAIL ) = 0; + virtual void RemoveVPKFile( char const *pszName ) = 0; + virtual void GetVPKFileNames( CUtlVector<CUtlString> &destVector ) = 0; + virtual void RemoveAllMapSearchPaths() = 0; + virtual void SyncDvdDevCache() = 0; + + virtual bool GetStringFromKVPool( CRC32_t poolKey, unsigned int key, char *pOutBuff, int buflen ) = 0; + + virtual bool DiscoverDLC( int iController ) = 0; + virtual int IsAnyDLCPresent( bool *pbDLCSearchPathMounted = NULL ) = 0; + virtual bool GetAnyDLCInfo( int iDLC, unsigned int *pLicenseMask, wchar_t *pTitleBuff, int nOutTitleSize ) = 0; + virtual int IsAnyCorruptDLC() = 0; + virtual bool GetAnyCorruptDLCInfo( int iCorruptDLC, wchar_t *pTitleBuff, int nOutTitleSize ) = 0; + virtual bool AddDLCSearchPaths() = 0; + virtual bool IsSpecificDLCPresent( unsigned int nDLCPackage ) = 0; + + // call this to look for CPU-hogs during loading processes. When you set this, a breakpoint + // will be issued whenever the indicated # of seconds go by without an i/o request. Passing + // 0.0 will turn off the functionality. + virtual void SetIODelayAlarm( float flThreshhold ) = 0; + + virtual bool AddXLSPUpdateSearchPath( const void *pData, int nSize ) = 0; + + virtual IIoStats *GetIoStats() = 0; + +}; + +//----------------------------------------------------------------------------- + +#if defined( _X360 ) && !defined( _CERT ) +extern char g_szXboxProfileLastFileOpened[MAX_PATH]; +#define SetLastProfileFileRead( s ) V_strncpy( g_szXboxProfileLastFileOpened, sizeof( g_szXboxProfileLastFileOpened), pFileName ) +#define GetLastProfileFileRead() (&g_szXboxProfileLastFileOpened[0]) +#else +#define SetLastProfileFileRead( s ) ((void)0) +#define GetLastProfileFileRead() NULL +#endif + +#if defined( _X360 ) && defined( _BASETSD_H_ ) +class CXboxDiskCacheSetter +{ +public: + CXboxDiskCacheSetter( SIZE_T newSize ) + { + m_oldSize = XGetFileCacheSize(); + XSetFileCacheSize( newSize ); + } + + ~CXboxDiskCacheSetter() + { + XSetFileCacheSize( m_oldSize ); + } +private: + SIZE_T m_oldSize; +}; +#define DISK_INTENSIVE() CXboxDiskCacheSetter cacheSetter( 1024*1024 ) +#else +#define DISK_INTENSIVE() ((void)0) +#endif + +//----------------------------------------------------------------------------- + +inline unsigned IFileSystem::GetOptimalReadSize( FileHandle_t hFile, unsigned nLogicalSize ) +{ + unsigned align; + if ( GetOptimalIOConstraints( hFile, &align, NULL, NULL ) ) + return AlignValue( nLogicalSize, align ); + else + return nLogicalSize; +} + +//----------------------------------------------------------------------------- + +// We include this here so it'll catch compile errors in VMPI early. +#include "filesystem_passthru.h" + +//----------------------------------------------------------------------------- +// Async memory tracking +//----------------------------------------------------------------------------- + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +#define AsyncRead( a, b ) AsyncReadCreditAlloc( a, __FILE__, __LINE__, b ) +#define AsyncReadMutiple( a, b, c ) AsyncReadMultipleCreditAlloc( a, b, __FILE__, __LINE__, c ) +#endif + +//----------------------------------------------------------------------------- +// Globals Exposed +//----------------------------------------------------------------------------- +DECLARE_TIER2_INTERFACE( IFileSystem, g_pFullFileSystem ); + + + + +#endif // FILESYSTEM_H diff --git a/external/vpc/public/filesystem_passthru.h b/external/vpc/public/filesystem_passthru.h new file mode 100644 index 0000000..ed1372d --- /dev/null +++ b/external/vpc/public/filesystem_passthru.h @@ -0,0 +1,299 @@ +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FILESYSTEM_PASSTHRU_H +#define FILESYSTEM_PASSTHRU_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "filesystem.h" +#include <stdio.h> +#include <stdarg.h> + +#ifdef AsyncRead +#undef AsyncRead +#undef AsyncReadMutiple +#endif + +// +// These classes pass all filesystem interface calls through to another filesystem +// interface. They can be used anytime you want to override a couple things in +// a filesystem. VMPI uses this to override the base filesystem calls while +// allowing the rest of the filesystem functionality to work on the master. +// + +template<class Base> +class CInternalFileSystemPassThru : public Base +{ +public: + CInternalFileSystemPassThru() + { + m_pBaseFileSystemPassThru = NULL; + } + virtual void InitPassThru( IBaseFileSystem *pBaseFileSystemPassThru ) + { + m_pBaseFileSystemPassThru = pBaseFileSystemPassThru; + } + virtual int Read( void* pOutput, int size, FileHandle_t file ) { return m_pBaseFileSystemPassThru->Read( pOutput, size, file ); } + virtual int Write( void const* pInput, int size, FileHandle_t file ) { return m_pBaseFileSystemPassThru->Write( pInput, size, file ); } + virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID ) { return m_pBaseFileSystemPassThru->Open( pFileName, pOptions, pathID ); } + virtual void Close( FileHandle_t file ) { m_pBaseFileSystemPassThru->Close( file ); } + virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t seekType ) { m_pBaseFileSystemPassThru->Seek( file, pos, seekType ); } + virtual unsigned int Tell( FileHandle_t file ) { return m_pBaseFileSystemPassThru->Tell( file ); } + virtual unsigned int Size( FileHandle_t file ) { return m_pBaseFileSystemPassThru->Size( file ); } + virtual unsigned int Size( const char *pFileName, const char *pPathID ) { return m_pBaseFileSystemPassThru->Size( pFileName, pPathID ); } + virtual void Flush( FileHandle_t file ) { m_pBaseFileSystemPassThru->Flush( file ); } + virtual bool Precache( const char *pFileName, const char *pPathID ) { return m_pBaseFileSystemPassThru->Precache( pFileName, pPathID ); } + virtual bool FileExists( const char *pFileName, const char *pPathID ) { return m_pBaseFileSystemPassThru->FileExists( pFileName, pPathID ); } + virtual bool IsFileWritable( char const *pFileName, const char *pPathID ) { return m_pBaseFileSystemPassThru->IsFileWritable( pFileName, pPathID ); } + virtual bool SetFileWritable( char const *pFileName, bool writable, const char *pPathID ) { return m_pBaseFileSystemPassThru->SetFileWritable( pFileName, writable, pPathID ); } + virtual long GetFileTime( const char *pFileName, const char *pPathID ) { return m_pBaseFileSystemPassThru->GetFileTime( pFileName, pPathID ); } + virtual bool ReadFile( const char *pFileName, const char *pPath, CUtlBuffer &buf, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL ) { return m_pBaseFileSystemPassThru->ReadFile( pFileName, pPath, buf, nMaxBytes, nStartingByte, pfnAlloc ); } + virtual bool WriteFile( const char *pFileName, const char *pPath, CUtlBuffer &buf ) { return m_pBaseFileSystemPassThru->WriteFile( pFileName, pPath, buf ); } + virtual bool UnzipFile( const char *pFileName, const char *pPath, const char *pDestination ) { return m_pBaseFileSystemPassThru->UnzipFile( pFileName, pPath, pDestination ); } + +protected: + IBaseFileSystem *m_pBaseFileSystemPassThru; +}; + + +class CBaseFileSystemPassThru : public CInternalFileSystemPassThru<IBaseFileSystem> +{ +public: +}; + + +class CFileSystemPassThru : public CInternalFileSystemPassThru<IFileSystem> +{ +public: + typedef CInternalFileSystemPassThru<IFileSystem> BaseClass; + + CFileSystemPassThru() + { + m_pFileSystemPassThru = NULL; + } + virtual void InitPassThru( IFileSystem *pFileSystemPassThru, bool bBaseOnly ) + { + if ( !bBaseOnly ) + m_pFileSystemPassThru = pFileSystemPassThru; + + BaseClass::InitPassThru( pFileSystemPassThru ); + } + + // IAppSystem stuff. + // Here's where the app systems get to learn about each other + virtual bool Connect( CreateInterfaceFn factory ) { return m_pFileSystemPassThru->Connect( factory ); } + virtual void Disconnect() { m_pFileSystemPassThru->Disconnect(); } + virtual void *QueryInterface( const char *pInterfaceName ) { return m_pFileSystemPassThru->QueryInterface( pInterfaceName ); } + virtual InitReturnVal_t Init() { return m_pFileSystemPassThru->Init(); } + virtual void Shutdown() { m_pFileSystemPassThru->Shutdown(); } + virtual const AppSystemInfo_t* GetDependencies() { return m_pFileSystemPassThru->GetDependencies(); } + virtual AppSystemTier_t GetTier() { return m_pFileSystemPassThru->GetTier(); } + virtual void Reconnect( CreateInterfaceFn factory, const char *pInterfaceName ) { m_pFileSystemPassThru->Reconnect( factory, pInterfaceName ); } + + virtual void RemoveAllSearchPaths( void ) { m_pFileSystemPassThru->RemoveAllSearchPaths(); } + virtual void AddSearchPath( const char *pPath, const char *pathID, SearchPathAdd_t addType ) { m_pFileSystemPassThru->AddSearchPath( pPath, pathID, addType ); } + virtual bool RemoveSearchPath( const char *pPath, const char *pathID ) { return m_pFileSystemPassThru->RemoveSearchPath( pPath, pathID ); } + virtual void RemoveFile( char const* pRelativePath, const char *pathID ) { m_pFileSystemPassThru->RemoveFile( pRelativePath, pathID ); } + virtual bool RenameFile( char const *pOldPath, char const *pNewPath, const char *pathID ) { return m_pFileSystemPassThru->RenameFile( pOldPath, pNewPath, pathID ); } + virtual void CreateDirHierarchy( const char *path, const char *pathID ) { m_pFileSystemPassThru->CreateDirHierarchy( path, pathID ); } + virtual bool IsDirectory( const char *pFileName, const char *pathID ) { return m_pFileSystemPassThru->IsDirectory( pFileName, pathID ); } + virtual void FileTimeToString( char* pStrip, int maxCharsIncludingTerminator, long fileTime ) { m_pFileSystemPassThru->FileTimeToString( pStrip, maxCharsIncludingTerminator, fileTime ); } + virtual void SetBufferSize( FileHandle_t file, unsigned nBytes ) { m_pFileSystemPassThru->SetBufferSize( file, nBytes ); } + virtual bool IsOk( FileHandle_t file ) { return m_pFileSystemPassThru->IsOk( file ); } + virtual bool EndOfFile( FileHandle_t file ) { return m_pFileSystemPassThru->EndOfFile( file ); } + virtual char *ReadLine( char *pOutput, int maxChars, FileHandle_t file ) { return m_pFileSystemPassThru->ReadLine( pOutput, maxChars, file ); } + virtual int FPrintf( FileHandle_t file, const char *pFormat, ... ) + { + char str[8192]; + va_list marker; + va_start( marker, pFormat ); + _vsnprintf( str, sizeof( str ), pFormat, marker ); + va_end( marker ); + return m_pFileSystemPassThru->FPrintf( file, "%s", str ); + } + virtual CSysModule *LoadModule( const char *pFileName, const char *pPathID, bool bValidatedDllOnly ) { return m_pFileSystemPassThru->LoadModule( pFileName, pPathID, bValidatedDllOnly ); } + virtual void UnloadModule( CSysModule *pModule ) { m_pFileSystemPassThru->UnloadModule( pModule ); } + virtual const char *FindFirst( const char *pWildCard, FileFindHandle_t *pHandle ) { return m_pFileSystemPassThru->FindFirst( pWildCard, pHandle ); } + virtual const char *FindNext( FileFindHandle_t handle ) { return m_pFileSystemPassThru->FindNext( handle ); } + virtual bool FindIsDirectory( FileFindHandle_t handle ) { return m_pFileSystemPassThru->FindIsDirectory( handle ); } + virtual void FindClose( FileFindHandle_t handle ) { m_pFileSystemPassThru->FindClose( handle ); } + virtual void FindFileAbsoluteList( CUtlVector< CUtlString > &outAbsolutePathNames, const char *pWildCard, const char *pPathID ) { m_pFileSystemPassThru->FindFileAbsoluteList( outAbsolutePathNames, pWildCard, pPathID ); } + virtual const char *GetLocalPath( const char *pFileName, char *pLocalPath, int localPathBufferSize ) { return m_pFileSystemPassThru->GetLocalPath( pFileName, pLocalPath, localPathBufferSize ); } + virtual bool FullPathToRelativePath( const char *pFullpath, char *pRelative, int maxlen ) { return m_pFileSystemPassThru->FullPathToRelativePath( pFullpath, pRelative, maxlen ); } + virtual bool GetCurrentDirectory( char* pDirectory, int maxlen ) { return m_pFileSystemPassThru->GetCurrentDirectory( pDirectory, maxlen ); } + virtual void PrintOpenedFiles( void ) { m_pFileSystemPassThru->PrintOpenedFiles(); } + virtual void PrintSearchPaths( void ) { m_pFileSystemPassThru->PrintSearchPaths(); } + virtual void SetWarningFunc( void (*pfnWarning)( const char *fmt, ... ) ) { m_pFileSystemPassThru->SetWarningFunc( pfnWarning ); } + virtual void SetWarningLevel( FileWarningLevel_t level ) { m_pFileSystemPassThru->SetWarningLevel( level ); } + virtual void AddLoggingFunc( void (*pfnLogFunc)( const char *fileName, const char *accessType ) ){ m_pFileSystemPassThru->AddLoggingFunc( pfnLogFunc ); } + virtual void RemoveLoggingFunc( FileSystemLoggingFunc_t logFunc ) { m_pFileSystemPassThru->RemoveLoggingFunc( logFunc ); } + virtual FSAsyncStatus_t AsyncReadMultiple( const FileAsyncRequest_t *pRequests, int nRequests, FSAsyncControl_t *pControls ) { return m_pFileSystemPassThru->AsyncReadMultiple( pRequests, nRequests, pControls ); } + virtual FSAsyncStatus_t AsyncReadMultipleCreditAlloc( const FileAsyncRequest_t *pRequests, int nRequests, const char *pszFile, int line, FSAsyncControl_t *pControls ) { return m_pFileSystemPassThru->AsyncReadMultipleCreditAlloc( pRequests, nRequests, pszFile, line, pControls ); } + virtual FSAsyncStatus_t AsyncDirectoryScan( const char* pSearchSpec, bool recurseFolders, void* pContext, FSAsyncScanAddFunc_t pfnAdd, FSAsyncScanCompleteFunc_t pfnDone, FSAsyncControl_t *pControl = NULL ) { return m_pFileSystemPassThru->AsyncDirectoryScan( pSearchSpec, recurseFolders, pContext, pfnAdd, pfnDone, pControl ); } + virtual FSAsyncStatus_t AsyncFinish(FSAsyncControl_t hControl, bool wait) { return m_pFileSystemPassThru->AsyncFinish( hControl, wait ); } + virtual FSAsyncStatus_t AsyncGetResult( FSAsyncControl_t hControl, void **ppData, int *pSize ) { return m_pFileSystemPassThru->AsyncGetResult( hControl, ppData, pSize ); } + virtual FSAsyncStatus_t AsyncAbort(FSAsyncControl_t hControl) { return m_pFileSystemPassThru->AsyncAbort( hControl ); } + virtual FSAsyncStatus_t AsyncStatus(FSAsyncControl_t hControl) { return m_pFileSystemPassThru->AsyncStatus( hControl ); } + virtual FSAsyncStatus_t AsyncFlush() { return m_pFileSystemPassThru->AsyncFlush(); } + virtual void AsyncAddRef( FSAsyncControl_t hControl ) { m_pFileSystemPassThru->AsyncAddRef( hControl ); } + virtual void AsyncRelease( FSAsyncControl_t hControl ) { m_pFileSystemPassThru->AsyncRelease( hControl ); } + virtual FSAsyncStatus_t AsyncBeginRead( const char *pszFile, FSAsyncFile_t *phFile ) { return m_pFileSystemPassThru->AsyncBeginRead( pszFile, phFile ); } + virtual FSAsyncStatus_t AsyncEndRead( FSAsyncFile_t hFile ) { return m_pFileSystemPassThru->AsyncEndRead( hFile ); } + virtual const FileSystemStatistics *GetFilesystemStatistics() { return m_pFileSystemPassThru->GetFilesystemStatistics(); } + + +#if defined( _PS3 ) + // These should never be called on PS3! + virtual Ps3FileType_t GetPs3FileType(const char* path) { return PS3_FILETYPE_UNKNOWN; } + virtual void LogFileAccess( const char *pFullFileName ) { } + + virtual bool PrefetchFile( const char *pFileName, int nPriority, bool bPersist ) { return m_pFileSystemPassThru->PrefetchFile( pFileName, nPriority, bPersist ); } + virtual bool PrefetchFile( const char *pFileName, int nPriority, bool bPersist, int64 nOffset, int64 nSize ) { return m_pFileSystemPassThru->PrefetchFile( pFileName, nPriority, bPersist, nOffset, nSize ); } + virtual void FlushCache() { m_pFileSystemPassThru->FlushCache(); } + virtual void SuspendPrefetches( const char * pWhy ) { m_pFileSystemPassThru->SuspendPrefetches( pWhy ); } + virtual void ResumePrefetches( const char * pWhy ) { m_pFileSystemPassThru->ResumePrefetches( pWhy ); } + virtual void OnSaveStateChanged( bool bSaving ) { m_pFileSystemPassThru->OnSaveStateChanged( bSaving ); } + virtual bool IsPrefetchingDone( ) { return m_pFileSystemPassThru->IsPrefetchingDone(); } +#endif //_PS3 + + virtual WaitForResourcesHandle_t WaitForResources( const char *resourcelist ) { return m_pFileSystemPassThru->WaitForResources( resourcelist ); } + virtual bool GetWaitForResourcesProgress( WaitForResourcesHandle_t handle, + float *progress, bool *complete ) { return m_pFileSystemPassThru->GetWaitForResourcesProgress( handle, progress, complete ); } + virtual void CancelWaitForResources( WaitForResourcesHandle_t handle ) { m_pFileSystemPassThru->CancelWaitForResources( handle ); } + virtual int HintResourceNeed( const char *hintlist, int forgetEverything ) { return m_pFileSystemPassThru->HintResourceNeed( hintlist, forgetEverything ); } + virtual bool IsFileImmediatelyAvailable(const char *pFileName) { return m_pFileSystemPassThru->IsFileImmediatelyAvailable( pFileName ); } + virtual void GetLocalCopy( const char *pFileName ) { m_pFileSystemPassThru->GetLocalCopy( pFileName ); } + virtual FileNameHandle_t FindOrAddFileName( char const *pFileName ) { return m_pFileSystemPassThru->FindOrAddFileName( pFileName ); } + virtual FileNameHandle_t FindFileName( char const *pFileName ) { return m_pFileSystemPassThru->FindFileName( pFileName ); } + virtual bool String( const FileNameHandle_t& handle, char *buf, int buflen ) { return m_pFileSystemPassThru->String( handle, buf, buflen ); } + virtual bool IsOk2( FileHandle_t file ) { return IsOk(file); } + virtual void RemoveSearchPaths( const char *szPathID ) { m_pFileSystemPassThru->RemoveSearchPaths( szPathID ); } + virtual bool IsSteam() const { return m_pFileSystemPassThru->IsSteam(); } + virtual FilesystemMountRetval_t MountSteamContent( int nExtraAppId = -1 ) { return m_pFileSystemPassThru->MountSteamContent( nExtraAppId ); } + + virtual const char *FindFirstEx( + const char *pWildCard, + const char *pPathID, + FileFindHandle_t *pHandle + ) { return m_pFileSystemPassThru->FindFirstEx( pWildCard, pPathID, pHandle ); } + virtual void MarkPathIDByRequestOnly( const char *pPathID, bool bRequestOnly ) { m_pFileSystemPassThru->MarkPathIDByRequestOnly( pPathID, bRequestOnly ); } + virtual bool AddPackFile( const char *fullpath, const char *pathID ) { return m_pFileSystemPassThru->AddPackFile( fullpath, pathID ); } + virtual FSAsyncStatus_t AsyncAppend(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, FSAsyncControl_t *pControl ) { return m_pFileSystemPassThru->AsyncAppend( pFileName, pSrc, nSrcBytes, bFreeMemory, pControl); } + virtual FSAsyncStatus_t AsyncWrite(const char *pFileName, const void *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t *pControl ) { return m_pFileSystemPassThru->AsyncWrite( pFileName, pSrc, nSrcBytes, bFreeMemory, bAppend, pControl); } + virtual FSAsyncStatus_t AsyncWriteFile(const char *pFileName, const CUtlBuffer *pSrc, int nSrcBytes, bool bFreeMemory, bool bAppend, FSAsyncControl_t *pControl ) { return m_pFileSystemPassThru->AsyncWriteFile( pFileName, pSrc, nSrcBytes, bFreeMemory, bAppend, pControl); } + virtual FSAsyncStatus_t AsyncAppendFile(const char *pDestFileName, const char *pSrcFileName, FSAsyncControl_t *pControl ) { return m_pFileSystemPassThru->AsyncAppendFile(pDestFileName, pSrcFileName, pControl); } + virtual void AsyncFinishAll( int iToPriority ) { m_pFileSystemPassThru->AsyncFinishAll(iToPriority); } + virtual void AsyncFinishAllWrites() { m_pFileSystemPassThru->AsyncFinishAllWrites(); } + virtual FSAsyncStatus_t AsyncSetPriority(FSAsyncControl_t hControl, int newPriority) { return m_pFileSystemPassThru->AsyncSetPriority(hControl, newPriority); } + virtual bool AsyncSuspend() { return m_pFileSystemPassThru->AsyncSuspend(); } + virtual bool AsyncResume() { return m_pFileSystemPassThru->AsyncResume(); } + virtual const char *RelativePathToFullPath( const char *pFileName, const char *pPathID, char *pLocalPath, int localPathBufferSize, PathTypeFilter_t pathFilter = FILTER_NONE, PathTypeQuery_t *pPathType = NULL ) { return m_pFileSystemPassThru->RelativePathToFullPath( pFileName, pPathID, pLocalPath, localPathBufferSize, pathFilter, pPathType ); } +#if IsGameConsole() + // Given a relative path, gets the PACK file that contained this file and its offset and size. Can be used to prefetch a file to a HDD for caching reason. + virtual bool GetPackFileInfoFromRelativePath( const char *pFileName, const char * pPathID, char *pPackPath, int nPackPathBufferSize, int64 &nPosition, int64 &nLength ) { return m_pFileSystemPassThru->GetPackFileInfoFromRelativePath( pFileName, pPathID, pPackPath, nPackPathBufferSize, nPosition, nLength ); } +#endif + + virtual int GetSearchPath( const char *pathID, bool bGetPackFiles, char *pPath, int nMaxLen ) { return m_pFileSystemPassThru->GetSearchPath( pathID, bGetPackFiles, pPath, nMaxLen ); } + + virtual FileHandle_t OpenEx( const char *pFileName, const char *pOptions, unsigned flags = 0, const char *pathID = 0, char **ppszResolvedFilename = NULL ) { return m_pFileSystemPassThru->OpenEx( pFileName, pOptions, flags, pathID, ppszResolvedFilename );} + virtual int ReadEx( void* pOutput, int destSize, int size, FileHandle_t file ) { return m_pFileSystemPassThru->ReadEx( pOutput, destSize, size, file ); } + virtual int ReadFileEx( const char *pFileName, const char *pPath, void **ppBuf, bool bNullTerminate, bool bOptimalAlloc, int nMaxBytes = 0, int nStartingByte = 0, FSAllocFunc_t pfnAlloc = NULL ) { return m_pFileSystemPassThru->ReadFileEx( pFileName, pPath, ppBuf, bNullTerminate, bOptimalAlloc, nMaxBytes, nStartingByte, pfnAlloc ); } + +#if defined( TRACK_BLOCKING_IO ) + virtual void EnableBlockingFileAccessTracking( bool state ) { m_pFileSystemPassThru->EnableBlockingFileAccessTracking( state ); } + virtual bool IsBlockingFileAccessEnabled() const { return m_pFileSystemPassThru->IsBlockingFileAccessEnabled(); } + + virtual IBlockingFileItemList *RetrieveBlockingFileAccessInfo() { return m_pFileSystemPassThru->RetrieveBlockingFileAccessInfo(); } +#endif + virtual void SetupPreloadData() {} + virtual void DiscardPreloadData() {} + + // If the "PreloadedData" hasn't been purged, then this'll try and instance the KeyValues using the fast path of compiled keyvalues loaded during startup. + // Otherwise, it'll just fall through to the regular KeyValues loading routines + virtual KeyValues *LoadKeyValues( KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 ) { return m_pFileSystemPassThru->LoadKeyValues( type, filename, pPathID ); } + virtual bool LoadKeyValues( KeyValues& head, KeyValuesPreloadType_t type, char const *filename, char const *pPathID = 0 ) { return m_pFileSystemPassThru->LoadKeyValues( head, type, filename, pPathID ); } + + virtual bool GetFileTypeForFullPath( char const *pFullPath, wchar_t *buf, size_t bufSizeInBytes ) { return m_pFileSystemPassThru->GetFileTypeForFullPath( pFullPath, buf, bufSizeInBytes ); } + + virtual bool GetOptimalIOConstraints( FileHandle_t hFile, unsigned *pOffsetAlign, unsigned *pSizeAlign, unsigned *pBufferAlign ) { return m_pFileSystemPassThru->GetOptimalIOConstraints( hFile, pOffsetAlign, pSizeAlign, pBufferAlign ); } + virtual void *AllocOptimalReadBuffer( FileHandle_t hFile, unsigned nSize, unsigned nOffset ) { return m_pFileSystemPassThru->AllocOptimalReadBuffer( hFile, nOffset, nSize ); } + virtual void FreeOptimalReadBuffer( void *p ) { m_pFileSystemPassThru->FreeOptimalReadBuffer( p ); } + + virtual void BeginMapAccess() { m_pFileSystemPassThru->BeginMapAccess(); } + virtual void EndMapAccess() { m_pFileSystemPassThru->EndMapAccess(); } + + virtual bool ReadToBuffer( FileHandle_t hFile, CUtlBuffer &buf, int nMaxBytes = 0, FSAllocFunc_t pfnAlloc = NULL ) { return m_pFileSystemPassThru->ReadToBuffer( hFile, buf, nMaxBytes, pfnAlloc ); } + virtual bool FullPathToRelativePathEx( const char *pFullPath, const char *pPathId, char *pRelative, int nMaxLen ) { return m_pFileSystemPassThru->FullPathToRelativePathEx( pFullPath, pPathId, pRelative, nMaxLen ); } + virtual int GetPathIndex( const FileNameHandle_t &handle ) { return m_pFileSystemPassThru->GetPathIndex( handle ); } + virtual long GetPathTime( const char *pPath, const char *pPathID ) { return m_pFileSystemPassThru->GetPathTime( pPath, pPathID ); } + + virtual DVDMode_t GetDVDMode() { return m_pFileSystemPassThru->GetDVDMode(); } + + virtual void EnableWhitelistFileTracking( bool bEnable ) + { m_pFileSystemPassThru->EnableWhitelistFileTracking( bEnable ); } + virtual void RegisterFileWhitelist( IFileList *pForceMatchList, IFileList *pAllowFromDiskList, IFileList **pFilesToReload ) + { m_pFileSystemPassThru->RegisterFileWhitelist( pForceMatchList, pAllowFromDiskList, pFilesToReload ); } + virtual void MarkAllCRCsUnverified() + { m_pFileSystemPassThru->MarkAllCRCsUnverified(); } + virtual void CacheFileCRCs( const char *pPathname, ECacheCRCType eType, IFileList *pFilter ) + { return m_pFileSystemPassThru->CacheFileCRCs( pPathname, eType, pFilter ); } + virtual EFileCRCStatus CheckCachedFileCRC( const char *pPathID, const char *pRelativeFilename, CRC32_t *pCRC ) + { return m_pFileSystemPassThru->CheckCachedFileCRC( pPathID, pRelativeFilename, pCRC ); } + virtual int GetUnverifiedCRCFiles( CUnverifiedCRCFile *pFiles, int nMaxFiles ) + { return m_pFileSystemPassThru->GetUnverifiedCRCFiles( pFiles, nMaxFiles ); } + virtual int GetWhitelistSpewFlags() + { return m_pFileSystemPassThru->GetWhitelistSpewFlags(); } + virtual void SetWhitelistSpewFlags( int spewFlags ) + { m_pFileSystemPassThru->SetWhitelistSpewFlags( spewFlags ); } + virtual void InstallDirtyDiskReportFunc( FSDirtyDiskReportFunc_t func ) { m_pFileSystemPassThru->InstallDirtyDiskReportFunc( func ); } + + virtual bool IsLaunchedFromXboxHDD() { return m_pFileSystemPassThru->IsLaunchedFromXboxHDD(); } + virtual bool IsInstalledToXboxHDDCache() { return m_pFileSystemPassThru->IsInstalledToXboxHDDCache(); } + virtual bool IsDVDHosted() { return m_pFileSystemPassThru->IsDVDHosted(); } + virtual bool IsInstallAllowed() { return m_pFileSystemPassThru->IsInstallAllowed(); } + virtual int GetSearchPathID( char *pPath, int nMaxLen ) { return m_pFileSystemPassThru->GetSearchPathID( pPath, nMaxLen ); } + virtual bool FixupSearchPathsAfterInstall() { return m_pFileSystemPassThru->FixupSearchPathsAfterInstall(); } + + virtual FSDirtyDiskReportFunc_t GetDirtyDiskReportFunc() { return m_pFileSystemPassThru->GetDirtyDiskReportFunc(); } + + virtual void AddVPKFile( char const *pPkName, SearchPathAdd_t addType = PATH_ADD_TO_TAIL ) { m_pFileSystemPassThru->AddVPKFile( pPkName, addType ); } + virtual void RemoveVPKFile( char const *pPkName ) { m_pFileSystemPassThru->RemoveVPKFile( pPkName ); } + virtual void GetVPKFileNames( CUtlVector<CUtlString> &destVector ) { m_pFileSystemPassThru->GetVPKFileNames( destVector ); } + + virtual void RemoveAllMapSearchPaths( void ) { m_pFileSystemPassThru->RemoveAllMapSearchPaths(); } + + virtual void SyncDvdDevCache( void ) { m_pFileSystemPassThru->SyncDvdDevCache(); } + + virtual bool GetStringFromKVPool( CRC32_t poolKey, unsigned int key, char *pOutBuff, int buflen ) { return m_pFileSystemPassThru->GetStringFromKVPool( poolKey, key, pOutBuff, buflen ); } + + virtual bool DiscoverDLC( int iController ) { return m_pFileSystemPassThru->DiscoverDLC( iController ); } + virtual int IsAnyDLCPresent( bool *pbDLCSearchPathMounted = NULL ) { return m_pFileSystemPassThru->IsAnyDLCPresent( pbDLCSearchPathMounted ); } + virtual bool GetAnyDLCInfo( int iDLC, unsigned int *pLicenseMask, wchar_t *pTitleBuff, int nOutTitleSize ) { return m_pFileSystemPassThru->GetAnyDLCInfo( iDLC, pLicenseMask, pTitleBuff, nOutTitleSize ); } + virtual int IsAnyCorruptDLC() { return m_pFileSystemPassThru->IsAnyCorruptDLC(); } + virtual bool GetAnyCorruptDLCInfo( int iCorruptDLC, wchar_t *pTitleBuff, int nOutTitleSize ) { return m_pFileSystemPassThru->GetAnyCorruptDLCInfo( iCorruptDLC, pTitleBuff, nOutTitleSize ); } + virtual bool AddDLCSearchPaths() { return m_pFileSystemPassThru->AddDLCSearchPaths(); } + virtual bool IsSpecificDLCPresent( unsigned int nDLCPackage ) { return m_pFileSystemPassThru->IsSpecificDLCPresent( nDLCPackage ); } + virtual void SetIODelayAlarm( float flThreshhold ) { m_pFileSystemPassThru->SetIODelayAlarm( flThreshhold ); } + virtual bool AddXLSPUpdateSearchPath( const void *pData, int nSize ) { return m_pFileSystemPassThru->AddXLSPUpdateSearchPath( pData, nSize ); } + virtual IIoStats *GetIoStats() { return m_pFileSystemPassThru->GetIoStats(); } + +protected: + IFileSystem *m_pFileSystemPassThru; +}; + + +// This is so people who change the filesystem interface are forced to add the passthru wrapper into CFileSystemPassThru, +// so they don't break VMPI. +inline void GiveMeACompileError() +{ + CFileSystemPassThru asdf; +} + + +#endif // FILESYSTEM_PASSTHRU_H diff --git a/external/vpc/public/icvar.h b/external/vpc/public/icvar.h new file mode 100644 index 0000000..b471a3b --- /dev/null +++ b/external/vpc/public/icvar.h @@ -0,0 +1,211 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// + +#ifndef ICVAR_H +#define ICVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "appframework/iappsystem.h" +#include "tier1/iconvar.h" +#include "tier1/utlvector.h" + + +class ConCommandBase; +class ConCommand; +class ConVar; +class Color; + + +//----------------------------------------------------------------------------- +// ConVars/ComCommands are marked as having a particular DLL identifier +//----------------------------------------------------------------------------- +typedef int CVarDLLIdentifier_t; + + +//----------------------------------------------------------------------------- +// Used to display console messages +//----------------------------------------------------------------------------- +abstract_class IConsoleDisplayFunc +{ +public: + virtual void ColorPrint( const Color& clr, const char *pMessage ) = 0; + virtual void Print( const char *pMessage ) = 0; + virtual void DPrint( const char *pMessage ) = 0; + + virtual void GetConsoleText( char *pchText, size_t bufSize ) const = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Applications can implement this to modify behavior in ICvar +//----------------------------------------------------------------------------- +#define CVAR_QUERY_INTERFACE_VERSION "VCvarQuery001" +abstract_class ICvarQuery : public IAppSystem +{ +public: + // Can these two convars be aliased? + virtual bool AreConVarsLinkable( const ConVar *child, const ConVar *parent ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: DLL interface to ConVars/ConCommands +//----------------------------------------------------------------------------- +abstract_class ICvar : public IAppSystem +{ +public: + // Allocate a unique DLL identifier + virtual CVarDLLIdentifier_t AllocateDLLIdentifier() = 0; + + // Register, unregister commands + virtual void RegisterConCommand( ConCommandBase *pCommandBase ) = 0; + virtual void UnregisterConCommand( ConCommandBase *pCommandBase ) = 0; + virtual void UnregisterConCommands( CVarDLLIdentifier_t id ) = 0; + + // If there is a +<varname> <value> on the command line, this returns the value. + // Otherwise, it returns NULL. + virtual const char* GetCommandLineValue( const char *pVariableName ) = 0; + + // Try to find the cvar pointer by name + virtual ConCommandBase *FindCommandBase( const char *name ) = 0; + virtual const ConCommandBase *FindCommandBase( const char *name ) const = 0; + virtual ConVar *FindVar ( const char *var_name ) = 0; + virtual const ConVar *FindVar ( const char *var_name ) const = 0; + virtual ConCommand *FindCommand( const char *name ) = 0; + virtual const ConCommand *FindCommand( const char *name ) const = 0; + + + + // Install a global change callback (to be called when any convar changes) + virtual void InstallGlobalChangeCallback( FnChangeCallback_t callback ) = 0; + virtual void RemoveGlobalChangeCallback( FnChangeCallback_t callback ) = 0; + virtual void CallGlobalChangeCallbacks( ConVar *var, const char *pOldString, float flOldValue ) = 0; + + // Install a console printer + virtual void InstallConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc ) = 0; + virtual void RemoveConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc ) = 0; + virtual void ConsoleColorPrintf( const Color& clr, const char *pFormat, ... ) const = 0; + virtual void ConsolePrintf( const char *pFormat, ... ) const = 0; + virtual void ConsoleDPrintf( const char *pFormat, ... ) const = 0; + + // Reverts cvars which contain a specific flag + virtual void RevertFlaggedConVars( int nFlag ) = 0; + + // Method allowing the engine ICvarQuery interface to take over + // A little hacky, owing to the fact the engine is loaded + // well after ICVar, so we can't use the standard connect pattern + virtual void InstallCVarQuery( ICvarQuery *pQuery ) = 0; + +#if defined( USE_VXCONSOLE ) + virtual void PublishToVXConsole( ) = 0; +#endif + + virtual void SetMaxSplitScreenSlots( int nSlots ) = 0; + virtual int GetMaxSplitScreenSlots() const = 0; + + virtual void AddSplitScreenConVars() = 0; + virtual void RemoveSplitScreenConVars( CVarDLLIdentifier_t id ) = 0; + + virtual int GetConsoleDisplayFuncCount() const = 0; + virtual void GetConsoleText( int nDisplayFuncIndex, char *pchText, size_t bufSize ) const = 0; + + // Utilities for convars accessed by the material system thread + virtual bool IsMaterialThreadSetAllowed( ) const = 0; + virtual void QueueMaterialThreadSetValue( ConVar *pConVar, const char *pValue ) = 0; + virtual void QueueMaterialThreadSetValue( ConVar *pConVar, int nValue ) = 0; + virtual void QueueMaterialThreadSetValue( ConVar *pConVar, float flValue ) = 0; + virtual bool HasQueuedMaterialThreadConVarSets() const = 0; + virtual int ProcessQueuedMaterialThreadConVarSets() = 0; + +protected: class ICVarIteratorInternal; +public: + /// Iteration over all cvars. + /// (THIS IS A SLOW OPERATION AND YOU SHOULD AVOID IT.) + /// usage: + /// { ICVar::Iterator iter(g_pCVar); + /// for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() ) + /// { + /// ConCommandBase *cmd = iter.Get(); + /// } + /// } + /// The Iterator class actually wraps the internal factory methods + /// so you don't need to worry about new/delete -- scope takes care + // of it. + /// We need an iterator like this because we can't simply return a + /// pointer to the internal data type that contains the cvars -- + /// it's a custom, protected class with unusual semantics and is + /// prone to change. + class Iterator + { + public: + inline Iterator(ICvar *icvar); + inline ~Iterator(void); + inline void SetFirst( void ); + inline void Next( void ); + inline bool IsValid( void ); + inline ConCommandBase *Get( void ); + private: + ICVarIteratorInternal *m_pIter; + }; + +protected: + // internals for ICVarIterator + class ICVarIteratorInternal + { + public: + virtual void SetFirst( void ) = 0; + virtual void Next( void ) = 0; + virtual bool IsValid( void ) = 0; + virtual ConCommandBase *Get( void ) = 0; + }; + + virtual ICVarIteratorInternal *FactoryInternalIterator( void ) = 0; + friend class Iterator; +}; + +inline ICvar::Iterator::Iterator(ICvar *icvar) +{ + m_pIter = icvar->FactoryInternalIterator(); +} + +inline ICvar::Iterator::~Iterator( void ) +{ + delete m_pIter; +} + +inline void ICvar::Iterator::SetFirst( void ) +{ + m_pIter->SetFirst(); +} + +inline void ICvar::Iterator::Next( void ) +{ + m_pIter->Next(); +} + +inline bool ICvar::Iterator::IsValid( void ) +{ + return m_pIter->IsValid(); +} + +inline ConCommandBase * ICvar::Iterator::Get( void ) +{ + return m_pIter->Get(); +} + + +//----------------------------------------------------------------------------- +// These global names are defined by tier1.h, duplicated here so you +// don't have to include tier1.h +//----------------------------------------------------------------------------- + +// These are marked DLL_EXPORT for Linux. +DECLARE_TIER1_INTERFACE( ICvar, cvar ); +DECLARE_TIER1_INTERFACE( ICvar, g_pCVar ); + + +#endif // ICVAR_H diff --git a/external/vpc/public/ilaunchabledll.h b/external/vpc/public/ilaunchabledll.h new file mode 100644 index 0000000..4062588 --- /dev/null +++ b/external/vpc/public/ilaunchabledll.h @@ -0,0 +1,28 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef ILAUNCHABLEDLL_H +#define ILAUNCHABLEDLL_H +#ifdef _WIN32 +#pragma once +#endif + + +#define LAUNCHABLE_DLL_INTERFACE_VERSION "launchable_dll_1" + + +// vmpi_service can use this to debug worker apps in-process, +// and some of the launchers (like texturecompile) use this. +class ILaunchableDLL +{ +public: + // All vrad.exe does is load the VRAD DLL and run this. + virtual int main( int argc, char **argv ) = 0; +}; + + + +#endif // ILAUNCHABLEDLL_H diff --git a/external/vpc/public/interfaces/interfaces.h b/external/vpc/public/interfaces/interfaces.h new file mode 100644 index 0000000..6e3166f --- /dev/null +++ b/external/vpc/public/interfaces/interfaces.h @@ -0,0 +1,287 @@ +//===== Copyright � 2005-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + + +#ifndef INTERFACES_H +#define INTERFACES_H + +#if defined( COMPILER_MSVC ) +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// Interface creation function +//----------------------------------------------------------------------------- +typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); + + +//----------------------------------------------------------------------------- +// Macros to declare interfaces appropriate for various tiers +//----------------------------------------------------------------------------- +#if 1 || defined( TIER1_LIBRARY ) || defined( TIER2_LIBRARY ) || defined( TIER3_LIBRARY ) || defined( TIER4_LIBRARY ) || defined( APPLICATION ) +#define DECLARE_TIER1_INTERFACE( _Interface, _Global ) extern _Interface * _Global; +#else +#define DECLARE_TIER1_INTERFACE( _Interface, _Global ) +#endif + +#if 1 || defined( TIER2_LIBRARY ) || defined( TIER3_LIBRARY ) || defined( TIER4_LIBRARY ) || defined( APPLICATION ) +#define DECLARE_TIER2_INTERFACE( _Interface, _Global ) extern _Interface * _Global; +#else +#define DECLARE_TIER2_INTERFACE( _Interface, _Global ) +#endif + +#if 1 || defined( TIER3_LIBRARY ) || defined( TIER4_LIBRARY ) || defined( APPLICATION ) +#define DECLARE_TIER3_INTERFACE( _Interface, _Global ) extern _Interface * _Global; +#else +#define DECLARE_TIER3_INTERFACE( _Interface, _Global ) +#endif + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class ICvar; +class IProcessUtils; +class ILocalize; +class IPhysics2; +class IPhysics2ActorManager; +class IPhysics2ResourceManager; +class IEventSystem; + +class IAsyncFileSystem; +class IColorCorrectionSystem; +class IDebugTextureInfo; +class IFileSystem; +class IRenderHardwareConfig; +class IInputSystem; +class IInputStackSystem; +class IMaterialSystem; +class IMaterialSystem2; +class IMaterialSystemHardwareConfig; +class IMdlLib; +class INetworkSystem; +class IP4; +class IQueuedLoader; +class IResourceAccessControl; +class IPrecacheSystem; +class IRenderDevice; +class IRenderDeviceMgr; +class IResourceSystem; +class IVBAllocTracker; +class IXboxInstaller; +class IMatchFramework; +class ISoundSystem; +class IStudioRender; +class IMatSystemSurface; +class IGameUISystemMgr; +class IDataCache; +class IMDLCache; +class IAvi; +class IBik; +class IDmeMakefileUtils; +class IPhysicsCollision; +class ISoundEmitterSystemBase; +class IMeshSystem; +class IWorldRendererMgr; +class ISceneSystem; +class IVGuiRenderSurface; + +namespace vgui +{ + class ISurface; + class IVGui; + class IInput; + class IPanel; + class IVGUILocalize; + class ISchemeManager; + class ISystem; +} + + + +//----------------------------------------------------------------------------- +// Fills out global DLL exported interface pointers +//----------------------------------------------------------------------------- +#define CVAR_INTERFACE_VERSION "VEngineCvar007" +DECLARE_TIER1_INTERFACE( ICvar, cvar ); +DECLARE_TIER1_INTERFACE( ICvar, g_pCVar ) + +#define PROCESS_UTILS_INTERFACE_VERSION "VProcessUtils002" +DECLARE_TIER1_INTERFACE( IProcessUtils, g_pProcessUtils ); + +#define VPHYSICS2_INTERFACE_VERSION "Physics2 Interface v0.3" +DECLARE_TIER1_INTERFACE( IPhysics2, g_pPhysics2 ); + +#define VPHYSICS2_ACTOR_MGR_INTERFACE_VERSION "Physics2 Interface ActorMgr v0.1" +DECLARE_TIER1_INTERFACE( IPhysics2ActorManager, g_pPhysics2ActorManager ); + +#define VPHYSICS2_RESOURCE_MGR_INTERFACE_VERSION "Physics2 Interface ResourceMgr v0.1" +DECLARE_TIER1_INTERFACE( IPhysics2ResourceManager, g_pPhysics2ResourceManager ); + +#define EVENTSYSTEM_INTERFACE_VERSION "EventSystem001" +DECLARE_TIER1_INTERFACE( IEventSystem, g_pEventSystem ); + +#define LOCALIZE_INTERFACE_VERSION "Localize_001" +DECLARE_TIER2_INTERFACE( ILocalize, g_pLocalize ); +DECLARE_TIER3_INTERFACE( vgui::IVGUILocalize, g_pVGuiLocalize ); + +#define RENDER_DEVICE_MGR_INTERFACE_VERSION "RenderDeviceMgr001" +DECLARE_TIER2_INTERFACE( IRenderDeviceMgr, g_pRenderDeviceMgr ); + +#define FILESYSTEM_INTERFACE_VERSION "VFileSystem017" +DECLARE_TIER2_INTERFACE( IFileSystem, g_pFullFileSystem ); + +#define ASYNCFILESYSTEM_INTERFACE_VERSION "VNewAsyncFileSystem001" +DECLARE_TIER2_INTERFACE( IAsyncFileSystem, g_pAsyncFileSystem ); + +#define RESOURCESYSTEM_INTERFACE_VERSION "ResourceSystem004" +DECLARE_TIER2_INTERFACE( IResourceSystem, g_pResourceSystem ); + +#define MATERIAL_SYSTEM_INTERFACE_VERSION "VMaterialSystem080" +DECLARE_TIER2_INTERFACE( IMaterialSystem, materials ); +DECLARE_TIER2_INTERFACE( IMaterialSystem, g_pMaterialSystem ); + +#define MATERIAL_SYSTEM2_INTERFACE_VERSION "VMaterialSystem2_001" +DECLARE_TIER2_INTERFACE( IMaterialSystem2, g_pMaterialSystem2 ); + +#define INPUTSYSTEM_INTERFACE_VERSION "InputSystemVersion001" +DECLARE_TIER2_INTERFACE( IInputSystem, g_pInputSystem ); + +#define INPUTSTACKSYSTEM_INTERFACE_VERSION "InputStackSystemVersion001" +DECLARE_TIER2_INTERFACE( IInputStackSystem, g_pInputStackSystem ); + +#define NETWORKSYSTEM_INTERFACE_VERSION "NetworkSystemVersion001" +DECLARE_TIER2_INTERFACE( INetworkSystem, g_pNetworkSystem ); + +#define MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION "MaterialSystemHardwareConfig013" +DECLARE_TIER2_INTERFACE( IMaterialSystemHardwareConfig, g_pMaterialSystemHardwareConfig ); + +#define DEBUG_TEXTURE_INFO_VERSION "DebugTextureInfo001" +DECLARE_TIER2_INTERFACE( IDebugTextureInfo, g_pMaterialSystemDebugTextureInfo ); + +#define VB_ALLOC_TRACKER_INTERFACE_VERSION "VBAllocTracker001" +DECLARE_TIER2_INTERFACE( IVBAllocTracker, g_VBAllocTracker ); + +#define COLORCORRECTION_INTERFACE_VERSION "COLORCORRECTION_VERSION_1" +DECLARE_TIER2_INTERFACE( IColorCorrectionSystem, colorcorrection ); + +#define P4_INTERFACE_VERSION "VP4002" +DECLARE_TIER2_INTERFACE( IP4, p4 ); + +#define MDLLIB_INTERFACE_VERSION "VMDLLIB001" +DECLARE_TIER2_INTERFACE( IMdlLib, mdllib ); + +#define QUEUEDLOADER_INTERFACE_VERSION "QueuedLoaderVersion001" +DECLARE_TIER2_INTERFACE( IQueuedLoader, g_pQueuedLoader ); + +#define RESOURCE_ACCESS_CONTROL_INTERFACE_VERSION "VResourceAccessControl001" +DECLARE_TIER2_INTERFACE( IResourceAccessControl, g_pResourceAccessControl ); + +#define PRECACHE_SYSTEM_INTERFACE_VERSION "VPrecacheSystem001" +DECLARE_TIER2_INTERFACE( IPrecacheSystem, g_pPrecacheSystem ); + +#if defined( _X360 ) +#define XBOXINSTALLER_INTERFACE_VERSION "XboxInstallerVersion001" +DECLARE_TIER2_INTERFACE( IXboxInstaller, g_pXboxInstaller ); +#endif + +#define MATCHFRAMEWORK_INTERFACE_VERSION "MATCHFRAMEWORK_001" +DECLARE_TIER2_INTERFACE( IMatchFramework, g_pMatchFramework ); + +#define GAMEUISYSTEMMGR_INTERFACE_VERSION "GameUISystemMgr001" +DECLARE_TIER3_INTERFACE( IGameUISystemMgr, g_pGameUISystemMgr ); + + +//----------------------------------------------------------------------------- +// Not exactly a global, but we're going to keep track of these here anyways +// NOTE: Appframework deals with connecting these bad boys. See materialsystem2app.cpp +//----------------------------------------------------------------------------- +#define RENDER_DEVICE_INTERFACE_VERSION "RenderDevice001" +DECLARE_TIER2_INTERFACE( IRenderDevice, g_pRenderDevice ); + +#define RENDER_HARDWARECONFIG_INTERFACE_VERSION "RenderHardwareConfig001" +DECLARE_TIER2_INTERFACE( IRenderHardwareConfig, g_pRenderHardwareConfig ); + +#define SOUNDSYSTEM_INTERFACE_VERSION "SoundSystem001" +DECLARE_TIER2_INTERFACE( ISoundSystem, g_pSoundSystem ); + +#define MESHSYSTEM_INTERFACE_VERSION "MeshSystem001" +DECLARE_TIER3_INTERFACE( IMeshSystem, g_pMeshSystem ); + +#define STUDIO_RENDER_INTERFACE_VERSION "VStudioRender026" +DECLARE_TIER3_INTERFACE( IStudioRender, g_pStudioRender ); +DECLARE_TIER3_INTERFACE( IStudioRender, studiorender ); + +#define MAT_SYSTEM_SURFACE_INTERFACE_VERSION "MatSystemSurface006" +DECLARE_TIER3_INTERFACE( IMatSystemSurface, g_pMatSystemSurface ); + +#define RENDER_SYSTEM_SURFACE_INTERFACE_VERSION "RenderSystemSurface001" +DECLARE_TIER3_INTERFACE( IVGuiRenderSurface, g_pVGuiRenderSurface ); + +#define SCENESYSTEM_INTERFACE_VERSION "SceneSystem_001" +DECLARE_TIER3_INTERFACE( ISceneSystem, g_pSceneSystem ); + +#define VGUI_SURFACE_INTERFACE_VERSION "VGUI_Surface031" +DECLARE_TIER3_INTERFACE( vgui::ISurface, g_pVGuiSurface ); + +#define SCHEME_SURFACE_INTERFACE_VERSION "SchemeSurface001" + +#define VGUI_INPUT_INTERFACE_VERSION "VGUI_Input005" +DECLARE_TIER3_INTERFACE( vgui::IInput, g_pVGuiInput ); + +#define VGUI_IVGUI_INTERFACE_VERSION "VGUI_ivgui008" +DECLARE_TIER3_INTERFACE( vgui::IVGui, g_pVGui ); + +#define VGUI_PANEL_INTERFACE_VERSION "VGUI_Panel009" +DECLARE_TIER3_INTERFACE( vgui::IPanel, g_pVGuiPanel ); + +#define VGUI_SCHEME_INTERFACE_VERSION "VGUI_Scheme010" +DECLARE_TIER3_INTERFACE( vgui::ISchemeManager, g_pVGuiSchemeManager ); + +#define VGUI_SYSTEM_INTERFACE_VERSION "VGUI_System010" +DECLARE_TIER3_INTERFACE( vgui::ISystem, g_pVGuiSystem ); + +#define DATACACHE_INTERFACE_VERSION "VDataCache003" +DECLARE_TIER3_INTERFACE( IDataCache, g_pDataCache ); // FIXME: Should IDataCache be in tier2? + +#define MDLCACHE_INTERFACE_VERSION "MDLCache004" +DECLARE_TIER3_INTERFACE( IMDLCache, g_pMDLCache ); +DECLARE_TIER3_INTERFACE( IMDLCache, mdlcache ); + +#define AVI_INTERFACE_VERSION "VAvi001" +DECLARE_TIER3_INTERFACE( IAvi, g_pAVI ); + +#define BIK_INTERFACE_VERSION "VBik001" +DECLARE_TIER3_INTERFACE( IBik, g_pBIK ); + +#define DMEMAKEFILE_UTILS_INTERFACE_VERSION "VDmeMakeFileUtils001" +DECLARE_TIER3_INTERFACE( IDmeMakefileUtils, g_pDmeMakefileUtils ); + +#define VPHYSICS_COLLISION_INTERFACE_VERSION "VPhysicsCollision007" +DECLARE_TIER3_INTERFACE( IPhysicsCollision, g_pPhysicsCollision ); + +#define SOUNDEMITTERSYSTEM_INTERFACE_VERSION "VSoundEmitter003" +DECLARE_TIER3_INTERFACE( ISoundEmitterSystemBase, g_pSoundEmitterSystem ); + +#define WORLD_RENDERER_MGR_INTERFACE_VERSION "WorldRendererMgr001" +DECLARE_TIER3_INTERFACE( IWorldRendererMgr, g_pWorldRendererMgr ); + +//----------------------------------------------------------------------------- +// Fills out global DLL exported interface pointers +//----------------------------------------------------------------------------- +void ConnectInterfaces( CreateInterfaceFn *pFactoryList, int nFactoryCount ); +void DisconnectInterfaces(); + + +//----------------------------------------------------------------------------- +// Reconnects an interface +//----------------------------------------------------------------------------- +void ReconnectInterface( CreateInterfaceFn factory, const char *pInterfaceName ); + + +#endif // INTERFACES_H + diff --git a/external/vpc/public/mathlib/fltx4.h b/external/vpc/public/mathlib/fltx4.h new file mode 100644 index 0000000..a32877b --- /dev/null +++ b/external/vpc/public/mathlib/fltx4.h @@ -0,0 +1,97 @@ +//===== Copyright 1996-2010, Valve Corporation, All rights reserved. ======// +// +// Purpose: - defines the type fltx4 - Avoid cyclic includion. +// +//===========================================================================// + +#ifndef FLTX4_H +#define FLTX4_H + +#if defined(GNUC) +#define USE_STDC_FOR_SIMD 0 +#else +#define USE_STDC_FOR_SIMD 0 +#endif + +#if (!defined(PLATFORM_PPC) && (USE_STDC_FOR_SIMD == 0)) +#define _SSE1 1 +#endif + +// I thought about defining a class/union for the SIMD packed floats instead of using fltx4, +// but decided against it because (a) the nature of SIMD code which includes comparisons is to blur +// the relationship between packed floats and packed integer types and (b) not sure that the +// compiler would handle generating good code for the intrinsics. + +#if USE_STDC_FOR_SIMD + +#error "hello" +typedef union +{ + float m128_f32[4]; + uint32 m128_u32[4]; +} fltx4; + +typedef fltx4 i32x4; +typedef fltx4 u32x4; + +#ifdef _PS3 +typedef fltx4 u32x4; +typedef fltx4 i32x4; +#endif +typedef fltx4 bi32x4; + +#elif ( defined( _PS3 ) ) + +typedef union +{ + // This union allows float/int access (which generally shouldn't be done in inner loops) + + vec_float4 vmxf; + vec_int4 vmxi; + vec_uint4 vmxui; + __vector bool vmxbi; + + struct + { + float x; + float y; + float z; + float w; + }; + + float m128_f32[4]; + uint32 m128_u32[4]; + int32 m128_i32[4]; + +} fltx4_union; + +typedef vec_float4 fltx4; +typedef vec_uint4 u32x4; +typedef vec_int4 i32x4; +typedef __vector bool bi32x4; +#define DIFFERENT_NATIVE_VECTOR_TYPES // true if the compiler has different types for float4, uint4, int4, etc + +#elif ( defined( _X360 ) ) + +typedef union +{ + // This union allows float/int access (which generally shouldn't be done in inner loops) + __vector4 vmx; + float m128_f32[4]; + uint32 m128_u32[4]; +} fltx4_union; + +typedef __vector4 fltx4; +typedef __vector4 i32x4; // a VMX register; just a way of making it explicit that we're doing integer ops. +typedef __vector4 u32x4; // a VMX register; just a way of making it explicit that we're doing unsigned integer ops. +typedef fltx4 bi32x4; +#else + +typedef __m128 fltx4; +typedef __m128 i32x4; +typedef __m128 u32x4; +typedef fltx4 bi32x4; + +#endif + +#endif diff --git a/external/vpc/public/mathlib/math_pfns.h b/external/vpc/public/mathlib/math_pfns.h new file mode 100644 index 0000000..23a4f6b --- /dev/null +++ b/external/vpc/public/mathlib/math_pfns.h @@ -0,0 +1,283 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#ifndef _MATH_PFNS_H_ +#define _MATH_PFNS_H_ + +#include <limits> + +#if defined( _X360 ) +#include <xboxmath.h> +#elif defined(_PS3) + +#ifndef SPU +#include <ppu_asm_intrinsics.h> +#endif + +// Note that similar defines exist in ssemath.h +// Maybe we should consolidate in one place for all platforms. + +#define _VEC_0x7ff (vec_int4){0x7ff,0x7ff,0x7ff,0x7ff} +#define _VEC_0x3ff (vec_int4){0x3ff,0x3ff,0x3ff,0x3ff} +#define _VEC_22L (vector unsigned int){22,22,22,22} +#define _VEC_11L (vector unsigned int){11,11,11,11} +#define _VEC_0L (vector unsigned int){0,0,0,0} +#define _VEC_255F (vector float){255.0f,255.0f,255.0f,255.0f} +#define _VEC_NEGONEF (vector float){-1.0f,-1.0f,-1.0f,-1.0f} +#define _VEC_ONEF (vector float){1.0f,1.0f,1.0f,1.0f} +#define _VEC_ZEROF (vector float){0.0f,0.0f,0.0f,0.0f} +#define _VEC_ZEROxyzONEwF (vector float){0.0f,0.0f,0.0f,1.0f} +#define _VEC_HALFF (vector float){0.5f,0.5f,0.5f,0.5f} +#define _VEC_HALFxyzZEROwF (vector float){0.5f,0.5f,0.5f,0.0f} +#define _VEC_PERMUTE_XYZ0W1 (vector unsigned char){0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x1c,0x1d,0x1e,0x1f} + +#define _VEC_IEEEHACK (vector float){(float)(1 << 23),(float)(1 << 23),(float)(1 << 23),(float)(1 << 23)} +#define _VEC_PERMUTE_FASTFTOC (vector unsigned char){0,0,0,0,0,0,0,0,0,0,0,0,0x03,0x07,0x0b,0x0f} + +// AngleQuaternion +#define _VEC_PERMUTE_AQsxsxcxcx (vector unsigned char) {0x00,0x01,0x02,0x03,0x00,0x01,0x02,0x03,0x10,0x11,0x12,0x13,0x10,0x11,0x12,0x13} +#define _VEC_PERMUTE_AQczszszcz (vector unsigned char) {0x18,0x19,0x1a,0x1b,0x08,0x09,0x0a,0x0b,0x08,0x09,0x0a,0x0b,0x18,0x19,0x1a,0x1b} +#define _VEC_PERMUTE_AQcxcxsxsx (vector unsigned char) {0x10,0x11,0x12,0x13,0x10,0x11,0x12,0x13,0x00,0x01,0x02,0x03,0x00,0x01,0x02,0x03} +#define _VEC_PERMUTE_AQszczczsz (vector unsigned char) {0x08,0x09,0x0a,0x0b,0x18,0x19,0x1a,0x1b,0x18,0x19,0x1a,0x1b,0x08,0x09,0x0a,0x0b} +#define _VEC_PERMUTE_ANGLEQUAT (vector unsigned char) {0x10,0x11,0x12,0x13,0x04,0x05,0x06,0x07,0x18,0x19,0x1a,0x1b,0x0c,0x0d,0x0e,0x0f} + +#define _VEC_EPSILONF (__vector float) {FLT_EPSILON,FLT_EPSILON,FLT_EPSILON,FLT_EPSILON} + +#endif + +#if !(defined( PLATFORM_PPC ) || defined(SPU)) +// If we are not PPC based or SPU based, then assumes it is SSE2. We should make this code cleaner. + +#include <xmmintrin.h> + +// These globals are initialized by mathlib and redirected based on available fpu features + +// The following are not declared as macros because they are often used in limiting situations, +// and sometimes the compiler simply refuses to inline them for some reason +FORCEINLINE float FastSqrt( float x ) +{ + __m128 root = _mm_sqrt_ss( _mm_load_ss( &x ) ); + return *( reinterpret_cast<float *>( &root ) ); +} + +FORCEINLINE float FastRSqrtFast( float x ) +{ + // use intrinsics + __m128 rroot = _mm_rsqrt_ss( _mm_load_ss( &x ) ); + return *( reinterpret_cast<float *>( &rroot ) ); +} +// Single iteration NewtonRaphson reciprocal square root: +// 0.5 * rsqrtps * (3 - x * rsqrtps(x) * rsqrtps(x)) +// Very low error, and fine to use in place of 1.f / sqrtf(x). +FORCEINLINE float FastRSqrt( float x ) +{ + float rroot = FastRSqrtFast( x ); + return (0.5f * rroot) * (3.f - (x * rroot) * rroot); +} + +void FastSinCos( float x, float* s, float* c ); // any x +float FastCos( float x ); + + + +inline float FastRecip(float x) {return 1.0f / x;} +// Simple SSE rsqrt. Usually accurate to around 6 (relative) decimal places +// or so, so ok for closed transforms. (ie, computing lighting normals) +inline float FastSqrtEst(float x) { return FastRSqrtFast(x) * x; } + + +#else // !defined( PLATFORM_PPC ) && !defined(_SPU) + +#ifndef SPU +// We may not need this for SPU, so let's not bother for now + +FORCEINLINE float _VMX_Sqrt( float x ) +{ + return __fsqrts( x ); +} + +FORCEINLINE double _VMX_RSqrt( double x ) +{ + double rroot = __frsqrte( x ); + + // Single iteration NewtonRaphson on reciprocal square root estimate + return (0.5f * rroot) * (3.0f - (x * rroot) * rroot); +} + +FORCEINLINE double _VMX_RSqrtFast( double x ) +{ + return __frsqrte( x ); +} + +#ifdef _X360 +FORCEINLINE void _VMX_SinCos( float a, float *pS, float *pC ) +{ + XMScalarSinCos( pS, pC, a ); +} + +FORCEINLINE float _VMX_Cos( float a ) +{ + return XMScalarCos( a ); +} +#endif + +// the 360 has fixed hw and calls directly +#define FastSqrt(x) _VMX_Sqrt(x) +#define FastRSqrt(x) _VMX_RSqrt(x) +#define FastRSqrtFast(x) _VMX_RSqrtFast(x) +#define FastSinCos(x,s,c) _VMX_SinCos(x,s,c) +#define FastCos(x) _VMX_Cos(x) + +inline double FastRecip(double x) {return __fres(x);} +inline double FastSqrtEst(double x) { return __frsqrte(x) * x; } + +#endif // !defined( PLATFORM_PPC ) && !defined(_SPU) + +// if x is infinite, return FLT_MAX +inline float FastClampInfinity( float x ) +{ +#ifdef PLATFORM_PPC + return fsel( std::numeric_limits<float>::infinity() - x, x, FLT_MAX ); +#else + return ( x > FLT_MAX ? FLT_MAX : x ); +#endif +} + +#if defined (_PS3) && !defined(SPU) + +// extern float cosvf(float); /* single precision cosine */ +// extern float sinvf(float); /* single precision sine */ +// TODO: need a faster single precision equivalent +#define cosvf cosf +#define sinvf sinf + +inline int _rotl( int x, int c ) +{ + return __rlwimi(x,x,c,0,31); +} + +inline int64 _rotl64( int64 x, int c ) +{ + return __rldicl( x, c, 0 ); +} + +//----------------------------------------------------------------- +// Vector Unions +//----------------------------------------------------------------- + +//----------------------------------------------------------------- +// Floats +//----------------------------------------------------------------- +typedef union +{ + vector float vf; + float f[4]; +} vector_float_union; + +//----------------------------------------------------------------- +// Ints +//----------------------------------------------------------------- +typedef union +{ + vector int vi; + int i[4]; +} vector_int4_union; + +typedef union +{ + vector unsigned int vui; + unsigned int ui[4]; +} vector_uint4_union; + +//----------------------------------------------------------------- +// Shorts +//----------------------------------------------------------------- +typedef union +{ + vector signed short vs; + signed short s[8]; +} vector_short8_union; + +typedef union +{ + vector unsigned short vus; + unsigned short us[8]; +} vector_ushort8_union; + +//----------------------------------------------------------------- +// Chars +//----------------------------------------------------------------- +typedef union +{ + vector signed char vc; + signed char c[16]; +} vector_char16_union; + +typedef union +{ + vector unsigned char vuc; + unsigned char uc[16]; +} vector_uchar16_union; + +/* +FORCEINLINE float _VMX_Sqrt( float x ) +{ + vector_float_union vIn, vOut; + + vIn.f[0] = x; + + vOut.vf = sqrtf4(vIn.vf); + + return vOut.f[0]; +} + +FORCEINLINE float _VMX_RSqrt( float x ) +{ + vector_float_union vIn, vOut; + + vIn.f[0] = x; + + vOut.vf = rsqrtf4(vIn.vf); + + return vOut.f[0]; +} + +FORCEINLINE float _VMX_RSqrtFast( float x ) +{ + vector_float_union vIn, vOut; + + vIn.f[0] = x; + + vOut.vf = rsqrtf4fast(vIn.vf); + + return vOut.f[0]; +} +*/ + +FORCEINLINE void _VMX_SinCos( float a, float *pS, float *pC ) +{ + *pS=sinvf(a); + *pC=cosvf(a); +} + +FORCEINLINE float _VMX_Cos( float a ) +{ + return cosvf(a); +} + + +// the 360 has fixed hw and calls directly +/* +#define FastSqrt(x) _VMX_Sqrt(x) +#define FastRSqrt(x) _VMX_RSqrt(x) +#define FastRSqrtFast(x) _VMX_RSqrtFast(x) +#define FastSinCos(x,s,c) _VMX_SinCos(x,s,c) +#define FastCos(x) _VMX_Cos(x) +*/ +#endif // _PS3 +#endif // #ifndef SPU + +#endif // _MATH_PFNS_H_ diff --git a/external/vpc/public/mathlib/mathlib.h b/external/vpc/public/mathlib/mathlib.h new file mode 100644 index 0000000..db1848f --- /dev/null +++ b/external/vpc/public/mathlib/mathlib.h @@ -0,0 +1,2425 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// + +#ifndef MATH_LIB_H +#define MATH_LIB_H + +#include <math.h> +#include "tier0/basetypes.h" +#include "mathlib/vector.h" +#include "mathlib/vector2d.h" +#include "tier0/dbg.h" + +#include "mathlib/math_pfns.h" +#include "mathlib/fltx4.h" + +#ifndef ALIGN8_POST +#define ALIGN8_POST +#endif + +#if defined(_PS3) + +#include <ppu_intrinsics.h> +#include <altivec.h> +#include <vectormath/c/vectormath_soa.h> + +#endif + +// plane_t structure +// !!! if this is changed, it must be changed in asm code too !!! +// FIXME: does the asm code even exist anymore? +// FIXME: this should move to a different file +struct cplane_t +{ + Vector normal; + float dist; + byte type; // for fast side tests + byte signbits; // signx + (signy<<1) + (signz<<1) + byte pad[2]; + +#ifdef VECTOR_NO_SLOW_OPERATIONS + cplane_t() {} + +private: + // No copy constructors allowed if we're in optimal mode + cplane_t(const cplane_t& vOther); +#endif +}; + +// structure offset for asm code +#define CPLANE_NORMAL_X 0 +#define CPLANE_NORMAL_Y 4 +#define CPLANE_NORMAL_Z 8 +#define CPLANE_DIST 12 +#define CPLANE_TYPE 16 +#define CPLANE_SIGNBITS 17 +#define CPLANE_PAD0 18 +#define CPLANE_PAD1 19 + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + + +//----------------------------------------------------------------------------- +// Frustum plane indices. +// WARNING: there is code that depends on these values +//----------------------------------------------------------------------------- + +enum +{ + FRUSTUM_RIGHT = 0, + FRUSTUM_LEFT = 1, + FRUSTUM_TOP = 2, + FRUSTUM_BOTTOM = 3, + FRUSTUM_NEARZ = 4, + FRUSTUM_FARZ = 5, + FRUSTUM_NUMPLANES = 6 +}; + +extern int SignbitsForPlane( cplane_t *out ); +class Frustum_t; + +// Computes Y fov from an X fov and a screen aspect ratio + X from Y +float CalcFovY( float flFovX, float flScreenAspect ); +float CalcFovX( float flFovY, float flScreenAspect ); + +// Generate a frustum based on perspective view parameters +// NOTE: FOV is specified in degrees, as the *full* view angle (not half-angle) +class VPlane; +void GeneratePerspectiveFrustum( const Vector& origin, const QAngle &angles, float flZNear, float flZFar, float flFovX, float flAspectRatio, Frustum_t &frustum ); +void GeneratePerspectiveFrustum( const Vector& origin, const Vector &forward, const Vector &right, const Vector &up, float flZNear, float flZFar, float flFovX, float flFovY, VPlane *pPlanesOut ); +// Cull the world-space bounding box to the specified frustum. +// bool R_CullBox( const Vector& mins, const Vector& maxs, const Frustum_t &frustum ); +// bool R_CullBoxSkipNear( const Vector& mins, const Vector& maxs, const Frustum_t &frustum ); +void GenerateOrthoFrustum( const Vector &origin, const Vector &forward, const Vector &right, const Vector &up, float flLeft, float flRight, float flBottom, float flTop, float flZNear, float flZFar, VPlane *pPlanesOut ); + +class matrix3x4a_t; + +struct matrix3x4_t +{ + matrix3x4_t() {} + matrix3x4_t( + float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23 ) + { + m_flMatVal[0][0] = m00; m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02; m_flMatVal[0][3] = m03; + m_flMatVal[1][0] = m10; m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12; m_flMatVal[1][3] = m13; + m_flMatVal[2][0] = m20; m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22; m_flMatVal[2][3] = m23; + } + + //----------------------------------------------------------------------------- + // Creates a matrix where the X axis = forward + // the Y axis = left, and the Z axis = up + //----------------------------------------------------------------------------- + void Init( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin ) + { + m_flMatVal[0][0] = xAxis.x; m_flMatVal[0][1] = yAxis.x; m_flMatVal[0][2] = zAxis.x; m_flMatVal[0][3] = vecOrigin.x; + m_flMatVal[1][0] = xAxis.y; m_flMatVal[1][1] = yAxis.y; m_flMatVal[1][2] = zAxis.y; m_flMatVal[1][3] = vecOrigin.y; + m_flMatVal[2][0] = xAxis.z; m_flMatVal[2][1] = yAxis.z; m_flMatVal[2][2] = zAxis.z; m_flMatVal[2][3] = vecOrigin.z; + } + + //----------------------------------------------------------------------------- + // Creates a matrix where the X axis = forward + // the Y axis = left, and the Z axis = up + //----------------------------------------------------------------------------- + matrix3x4_t( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector &vecOrigin ) + { + Init( xAxis, yAxis, zAxis, vecOrigin ); + } + + inline void SetOrigin( Vector const & p ) + { + m_flMatVal[0][3] = p.x; + m_flMatVal[1][3] = p.y; + m_flMatVal[2][3] = p.z; + } + + inline void Invalidate( void ) + { + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 4; j++) + { + m_flMatVal[i][j] = VEC_T_NAN; + } + } + } + + float *operator[]( int i ) { Assert(( i >= 0 ) && ( i < 3 )); return m_flMatVal[i]; } + const float *operator[]( int i ) const { Assert(( i >= 0 ) && ( i < 3 )); return m_flMatVal[i]; } + float *Base() { return &m_flMatVal[0][0]; } + const float *Base() const { return &m_flMatVal[0][0]; } + + float m_flMatVal[3][4]; +}; + +class ALIGN16 matrix3x4a_t : public matrix3x4_t +{ +public: + /* + matrix3x4a_t() { if (((size_t)Base()) % 16 != 0) { Error( "matrix3x4a_t missaligned" ); } } + */ + matrix3x4a_t& operator=( const matrix3x4_t& src ) { memcpy( Base(), src.Base(), sizeof( float ) * 3 * 4 ); return *this; }; +} ALIGN16_POST; + +#ifndef M_PI + #define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +#define M_PI_F ((float)(M_PI)) // Shouldn't collide with anything. + +// NJS: Inlined to prevent floats from being autopromoted to doubles, as with the old system. +#ifndef RAD2DEG + #define RAD2DEG( x ) ( (float)(x) * (float)(180.f / M_PI_F) ) +#endif + +#ifndef DEG2RAD + #define DEG2RAD( x ) ( (float)(x) * (float)(M_PI_F / 180.f) ) +#endif + +// Used to represent sides of things like planes. +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 +#define SIDE_CROSS -2 // necessary for polylib.c + +// Use different side values (1, 2, 4) instead of (0, 1, 2) so we can '|' and '&' them, and quickly determine overall clipping +// without having to maintain counters and read / write memory. +enum Sides +{ + OR_SIDE_FRONT = 1, + OR_SIDE_BACK = 2, + OR_SIDE_ON = 4, +}; + +#define ON_VIS_EPSILON 0.01 // necessary for vvis (flow.c) -- again look into moving later! +#define EQUAL_EPSILON 0.001 // necessary for vbsp (faces.c) -- should look into moving it there? + +extern bool s_bMathlibInitialized; + +extern const Vector vec3_origin; +extern const QAngle vec3_angle; +extern const Quaternion quat_identity; +extern const Vector vec3_invalid; +extern const int nanmask; + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +FORCEINLINE vec_t DotProduct(const vec_t *v1, const vec_t *v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} +FORCEINLINE void VectorSubtract(const vec_t *a, const vec_t *b, vec_t *c) +{ + c[0]=a[0]-b[0]; + c[1]=a[1]-b[1]; + c[2]=a[2]-b[2]; +} +FORCEINLINE void VectorAdd(const vec_t *a, const vec_t *b, vec_t *c) +{ + c[0]=a[0]+b[0]; + c[1]=a[1]+b[1]; + c[2]=a[2]+b[2]; +} +FORCEINLINE void VectorCopy(const vec_t *a, vec_t *b) +{ + b[0]=a[0]; + b[1]=a[1]; + b[2]=a[2]; +} +FORCEINLINE void VectorClear(vec_t *a) +{ + a[0]=a[1]=a[2]=0; +} + +FORCEINLINE float VectorMaximum(const vec_t *v) +{ + return MAX( v[0], MAX( v[1], v[2] ) ); +} + +FORCEINLINE float VectorMaximum(const Vector& v) +{ + return MAX( v.x, MAX( v.y, v.z ) ); +} + +FORCEINLINE void VectorScale (const float* in, vec_t scale, float* out) +{ + out[0] = in[0]*scale; + out[1] = in[1]*scale; + out[2] = in[2]*scale; +} + + +// Cannot be forceinline as they have overloads: +inline void VectorFill(vec_t *a, float b) +{ + a[0]=a[1]=a[2]=b; +} + +inline void VectorNegate(vec_t *a) +{ + a[0]=-a[0]; + a[1]=-a[1]; + a[2]=-a[2]; +} + + +//#define VectorMaximum(a) ( max( (a)[0], max( (a)[1], (a)[2] ) ) ) +#define Vector2Clear(x) {(x)[0]=(x)[1]=0;} +#define Vector2Negate(x) {(x)[0]=-((x)[0]);(x)[1]=-((x)[1]);} +#define Vector2Copy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];} +#define Vector2Subtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];} +#define Vector2Add(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];} +#define Vector2Scale(a,b,c) {(c)[0]=(b)*(a)[0];(c)[1]=(b)*(a)[1];} + +// NJS: Some functions in VBSP still need to use these for dealing with mixing vec4's and shorts with vec_t's. +// remove when no longer needed. +#define VECTOR_COPY( A, B ) do { (B)[0] = (A)[0]; (B)[1] = (A)[1]; (B)[2]=(A)[2]; } while(0) +#define DOT_PRODUCT( A, B ) ( (A)[0]*(B)[0] + (A)[1]*(B)[1] + (A)[2]*(B)[2] ) + +FORCEINLINE void VectorMAInline( const float* start, float scale, const float* direction, float* dest ) +{ + dest[0]=start[0]+direction[0]*scale; + dest[1]=start[1]+direction[1]*scale; + dest[2]=start[2]+direction[2]*scale; +} + +FORCEINLINE void VectorMAInline( const Vector& start, float scale, const Vector& direction, Vector& dest ) +{ + dest.x=start.x+direction.x*scale; + dest.y=start.y+direction.y*scale; + dest.z=start.z+direction.z*scale; +} + +FORCEINLINE void VectorMA( const Vector& start, float scale, const Vector& direction, Vector& dest ) +{ + VectorMAInline(start, scale, direction, dest); +} + +FORCEINLINE void VectorMA( const float * start, float scale, const float *direction, float *dest ) +{ + VectorMAInline(start, scale, direction, dest); +} + + +int VectorCompare (const float *v1, const float *v2); + +inline float VectorLength(const float *v) +{ + return FastSqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + FLT_EPSILON ); +} + +void CrossProduct (const float *v1, const float *v2, float *cross); + +qboolean VectorsEqual( const float *v1, const float *v2 ); + +inline vec_t RoundInt (vec_t in) +{ + return floor(in + 0.5f); +} + +size_t Q_log2( unsigned int val ); + +// Math routines done in optimized assembly math package routines +void inline SinCos( float radians, float * RESTRICT sine, float * RESTRICT cosine ) +{ +#if defined( _X360 ) + XMScalarSinCos( sine, cosine, radians ); +#elif defined( _PS3 ) +#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 1 ) && ( __GNUC_PATCHLEVEL__ == 1 ) + vector_float_union s; + vector_float_union c; + + vec_float4 rad = vec_splats( radians ); + vec_float4 sin; + vec_float4 cos; + + sincosf4( rad, &sin, &cos ); + + vec_st( sin, 0, s.f ); + vec_st( cos, 0, c.f ); + + *sine = s.f[0]; + *cosine = c.f[0]; +#else //__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ == 1 + vector_float_union r; + vector_float_union s; + vector_float_union c; + + vec_float4 rad; + vec_float4 sin; + vec_float4 cos; + + r.f[0] = radians; + rad = vec_ld( 0, r.f ); + + sincosf4( rad, &sin, &cos ); + + vec_st( sin, 0, s.f ); + vec_st( cos, 0, c.f ); + + *sine = s.f[0]; + *cosine = c.f[0]; +#endif //__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ == 1 +#elif defined( COMPILER_MSVC32 ) + _asm + { + fld DWORD PTR [radians] + fsincos + + mov edx, DWORD PTR [cosine] + mov eax, DWORD PTR [sine] + + fstp DWORD PTR [edx] + fstp DWORD PTR [eax] + } +#elif defined( GNUC ) + register double __cosr, __sinr; + __asm __volatile__ ("fsincos" : "=t" (__cosr), "=u" (__sinr) : "0" (radians)); + + *sine = __sinr; + *cosine = __cosr; +#else + *sine = sinf(radians); + *cosine = cosf(radians); +#endif +} + +#define SIN_TABLE_SIZE 256 +#define FTOIBIAS 12582912.f +extern float SinCosTable[SIN_TABLE_SIZE]; + +inline float TableCos( float theta ) +{ + union + { + int i; + float f; + } ftmp; + + // ideally, the following should compile down to: theta * constant + constant, changing any of these constants from defines sometimes fubars this. + ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + ( FTOIBIAS + ( SIN_TABLE_SIZE / 4 ) ); + return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ]; +} + +inline float TableSin( float theta ) +{ + union + { + int i; + float f; + } ftmp; + + // ideally, the following should compile down to: theta * constant + constant + ftmp.f = theta * ( float )( SIN_TABLE_SIZE / ( 2.0f * M_PI ) ) + FTOIBIAS; + return SinCosTable[ ftmp.i & ( SIN_TABLE_SIZE - 1 ) ]; +} + +template<class T> +FORCEINLINE T Square( T const &a ) +{ + return a * a; +} + +FORCEINLINE bool IsPowerOfTwo( uint x ) +{ + return ( x & ( x - 1 ) ) == 0; +} + +// return the smallest power of two >= x. +// returns 0 if x == 0 or x > 0x80000000 (ie numbers that would be negative if x was signed) +// NOTE: the old code took an int, and if you pass in an int of 0x80000000 casted to a uint, +// you'll get 0x80000000, which is correct for uints, instead of 0, which was correct for ints +FORCEINLINE uint SmallestPowerOfTwoGreaterOrEqual( uint x ) +{ + x -= 1; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; +} + +// return the largest power of two <= x. Will return 0 if passed 0 +FORCEINLINE uint LargestPowerOfTwoLessThanOrEqual( uint x ) +{ + if ( x >= 0x80000000 ) + return 0x80000000; + + return SmallestPowerOfTwoGreaterOrEqual( x + 1 ) >> 1; +} + + +// Math routines for optimizing division +void FloorDivMod (double numer, double denom, int *quotient, int *rem); +int GreatestCommonDivisor (int i1, int i2); + +// Test for FPU denormal mode +bool IsDenormal( const float &val ); + +// MOVEMENT INFO +enum +{ + PITCH = 0, // up / down + YAW, // left / right + ROLL // fall over +}; + +void MatrixAngles( const matrix3x4_t & matrix, float *angles ); // !!!! +void MatrixVectors( const matrix3x4_t &matrix, Vector* pForward, Vector *pRight, Vector *pUp ); +void VectorTransform (const float *in1, const matrix3x4_t & in2, float *out); +void VectorITransform (const float *in1, const matrix3x4_t & in2, float *out); +void VectorRotate( const float *in1, const matrix3x4_t & in2, float *out); +void VectorRotate( const Vector &in1, const QAngle &in2, Vector &out ); +void VectorRotate( const Vector &in1, const Quaternion &in2, Vector &out ); +void VectorIRotate( const float *in1, const matrix3x4_t & in2, float *out); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +QAngle TransformAnglesToLocalSpace( const QAngle &angles, const matrix3x4_t &parentMatrix ); +QAngle TransformAnglesToWorldSpace( const QAngle &angles, const matrix3x4_t &parentMatrix ); + +#endif + +void MatrixInitialize( matrix3x4_t &mat, const Vector &vecOrigin, const Vector &vecXAxis, const Vector &vecYAxis, const Vector &vecZAxis ); +void MatrixCopy( const matrix3x4_t &in, matrix3x4_t &out ); +void MatrixInvert( const matrix3x4_t &in, matrix3x4_t &out ); + +// Matrix equality test +bool MatricesAreEqual( const matrix3x4_t &src1, const matrix3x4_t &src2, float flTolerance = 1e-5 ); + +void MatrixGetColumn( const matrix3x4_t &in, int column, Vector &out ); +void MatrixSetColumn( const Vector &in, int column, matrix3x4_t &out ); + +//void DecomposeRotation( const matrix3x4_t &mat, float *out ); +void ConcatRotations (const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out); +void ConcatTransforms (const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out); +// faster version assumes m0, m1, out are 16-byte aligned addresses +void ConcatTransforms_Aligned( const matrix3x4a_t &m0, const matrix3x4a_t &m1, matrix3x4a_t &out ); + +// For identical interface w/ VMatrix +inline void MatrixMultiply ( const matrix3x4_t &in1, const matrix3x4_t &in2, matrix3x4_t &out ) +{ + ConcatTransforms( in1, in2, out ); +} + +void QuaternionExp( const Quaternion &p, Quaternion &q ); +void QuaternionLn( const Quaternion &p, Quaternion &q ); +void QuaternionAverageExponential( Quaternion &q, int nCount, const Quaternion *pQuaternions, const float *pflWeights = NULL ); +void QuaternionLookAt( const Vector &vecForward, const Vector &referenceUp, Quaternion &q ); +void QuaternionSlerp( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ); +void QuaternionSlerpNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ); +void QuaternionBlend( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ); +void QuaternionBlendNoAlign( const Quaternion &p, const Quaternion &q, float t, Quaternion &qt ); +void QuaternionIdentityBlend( const Quaternion &p, float t, Quaternion &qt ); +float QuaternionAngleDiff( const Quaternion &p, const Quaternion &q ); +void QuaternionScale( const Quaternion &p, float t, Quaternion &q ); +void QuaternionAlign( const Quaternion &p, const Quaternion &q, Quaternion &qt ); +float QuaternionDotProduct( const Quaternion &p, const Quaternion &q ); +void QuaternionConjugate( const Quaternion &p, Quaternion &q ); +void QuaternionInvert( const Quaternion &p, Quaternion &q ); +float QuaternionNormalize( Quaternion &q ); +void QuaternionAdd( const Quaternion &p, const Quaternion &q, Quaternion &qt ); +void QuaternionMult( const Quaternion &p, const Quaternion &q, Quaternion &qt ); +void QuaternionMatrix( const Quaternion &q, matrix3x4_t &matrix ); +void QuaternionMatrix( const Quaternion &q, const Vector &pos, matrix3x4_t &matrix ); +void QuaternionAngles( const Quaternion &q, QAngle &angles ); +void AngleQuaternion( const QAngle& angles, Quaternion &qt ); +void QuaternionAngles( const Quaternion &q, RadianEuler &angles ); +void AngleQuaternion( RadianEuler const &angles, Quaternion &qt ); +void QuaternionAxisAngle( const Quaternion &q, Vector &axis, float &angle ); +void AxisAngleQuaternion( const Vector &axis, float angle, Quaternion &q ); +void BasisToQuaternion( const Vector &vecForward, const Vector &vecRight, const Vector &vecUp, Quaternion &q ); +void MatrixQuaternion( const matrix3x4_t &mat, Quaternion &q ); + +// A couple methods to find the dot product of a vector with a matrix row or column... +inline float MatrixRowDotProduct( const matrix3x4_t &in1, int row, const Vector& in2 ) +{ + Assert( (row >= 0) && (row < 3) ); + return DotProduct( in1[row], in2.Base() ); +} + +inline float MatrixColumnDotProduct( const matrix3x4_t &in1, int col, const Vector& in2 ) +{ + Assert( (col >= 0) && (col < 4) ); + return in1[0][col] * in2[0] + in1[1][col] * in2[1] + in1[2][col] * in2[2]; +} + +int __cdecl BoxOnPlaneSide (const float *emins, const float *emaxs, const cplane_t *plane); + +inline float anglemod(float a) +{ + a = (360.f/65536) * ((int)(a*(65536.f/360.0f)) & 65535); + return a; +} + +//// CLAMP +#if defined(__cplusplus) && defined(PLATFORM_PPC) + +#ifdef _X360 +#define __fsels __fsel +#endif + +template< > +inline double clamp( double const &val, double const &minVal, double const &maxVal ) +{ + float diffmin = val - minVal; + float diffmax = maxVal - val; + float r; + r = __fsel(diffmin, val, minVal); + r = __fsel(diffmax, r, maxVal); + return r; +} + +template< > +inline double clamp( double const &val, float const &minVal, float const &maxVal ) +{ + // these typecasts are actually free since all FPU regs are 64 bit on PPC anyway + return clamp ( val, (double) minVal, (double) maxVal ); +} +template< > +inline double clamp( double const &val, float const &minVal, double const &maxVal ) +{ + return clamp ( val, (double) minVal, (double) maxVal ); +} +template< > +inline double clamp( double const &val, double const &minVal, float const &maxVal ) +{ + return clamp ( val, (double) minVal, (double) maxVal ); +} + +template< > +inline float clamp( float const &val, float const &minVal, float const &maxVal ) +{ + float diffmin = val - minVal; + float diffmax = maxVal - val; + float r; + r = __fsels(diffmin, val, minVal); + r = __fsels(diffmax, r, maxVal); + return r; +} + +template< > +inline float clamp( float const &val, double const &minVal, double const &maxVal ) +{ + float diffmin = val - minVal; + float diffmax = maxVal - val; + float r; + r = __fsels(diffmin, val, minVal); + r = __fsels(diffmax, r, maxVal); + return r; +} +template< > +inline float clamp( float const &val, double const &minVal, float const &maxVal ) +{ + return clamp ( val, (float) minVal, maxVal ); +} +template< > +inline float clamp( float const &val, float const &minVal, double const &maxVal ) +{ + return clamp ( val, minVal, (float) maxVal ); +} + +#endif + +// Remap a value in the range [A,B] to [C,D]. +inline float RemapVal( float val, float A, float B, float C, float D) +{ + if ( A == B ) + return fsel( val - B , D , C ); + return C + (D - C) * (val - A) / (B - A); +} + +inline float RemapValClamped( float val, float A, float B, float C, float D) +{ + if ( A == B ) + return fsel( val - B , D , C ); + float cVal = (val - A) / (B - A); + cVal = clamp<float>( cVal, 0.0f, 1.0f ); + + return C + (D - C) * cVal; +} + +// Returns A + (B-A)*flPercent. +// float Lerp( float flPercent, float A, float B ); +template <class T> +FORCEINLINE T Lerp( float flPercent, T const &A, T const &B ) +{ + return A + (B - A) * flPercent; +} + +FORCEINLINE float Sqr( float f ) +{ + return f*f; +} + +// 5-argument floating point linear interpolation. +// FLerp(f1,f2,i1,i2,x)= +// f1 at x=i1 +// f2 at x=i2 +// smooth lerp between f1 and f2 at x>i1 and x<i2 +// extrapolation for x<i1 or x>i2 +// +// If you know a function f(x)'s value (f1) at position i1, and its value (f2) at position i2, +// the function can be linearly interpolated with FLerp(f1,f2,i1,i2,x) +// i2=i1 will cause a divide by zero. +static inline float FLerp(float f1, float f2, float i1, float i2, float x) +{ + return f1+(f2-f1)*(x-i1)/(i2-i1); +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +// YWB: Specialization for interpolating euler angles via quaternions... +template<> FORCEINLINE QAngle Lerp<QAngle>( float flPercent, const QAngle& q1, const QAngle& q2 ) +{ + // Avoid precision errors + if ( q1 == q2 ) + return q1; + + Quaternion src, dest; + + // Convert to quaternions + AngleQuaternion( q1, src ); + AngleQuaternion( q2, dest ); + + Quaternion result; + + // Slerp + QuaternionSlerp( src, dest, flPercent, result ); + + // Convert to euler + QAngle output; + QuaternionAngles( result, output ); + return output; +} + +#else + +#pragma error + +// NOTE NOTE: I haven't tested this!! It may not work! Check out interpolatedvar.cpp in the client dll to try it +template<> FORCEINLINE QAngleByValue Lerp<QAngleByValue>( float flPercent, const QAngleByValue& q1, const QAngleByValue& q2 ) +{ + // Avoid precision errors + if ( q1 == q2 ) + return q1; + + Quaternion src, dest; + + // Convert to quaternions + AngleQuaternion( q1, src ); + AngleQuaternion( q2, dest ); + + Quaternion result; + + // Slerp + QuaternionSlerp( src, dest, flPercent, result ); + + // Convert to euler + QAngleByValue output; + QuaternionAngles( result, output ); + return output; +} + +#endif // VECTOR_NO_SLOW_OPERATIONS + + +// Swap two of anything. +template <class T> +FORCEINLINE void V_swap( T& x, T& y ) +{ + T temp = x; + x = y; + y = temp; +} + +template <class T> FORCEINLINE T AVG(T a, T b) +{ + return (a+b)/2; +} + +// number of elements in an array of static size +#define NELEMS(x) ((sizeof(x))/sizeof(x[0])) + +// XYZ macro, for printf type functions - ex printf("%f %f %f",XYZ(myvector)); +#define XYZ(v) (v).x,(v).y,(v).z + + + + +inline float Sign( float x ) +{ + return fsel( x, 1.0f, -1.0f ); // x >= 0 ? 1.0f : -1.0f + //return (x <0.0f) ? -1.0f : 1.0f; +} + +// +// Clamps the input integer to the given array bounds. +// Equivalent to the following, but without using any branches: +// +// if( n < 0 ) return 0; +// else if ( n > maxindex ) return maxindex; +// else return n; +// +// This is not always a clear performance win, but when you have situations where a clamped +// value is thrashing against a boundary this is a big win. (ie, valid, invalid, valid, invalid, ...) +// +// Note: This code has been run against all possible integers. +// +inline int ClampArrayBounds( int n, unsigned maxindex ) +{ + // mask is 0 if less than 4096, 0xFFFFFFFF if greater than + unsigned int inrangemask = 0xFFFFFFFF + (((unsigned) n) > maxindex ); + unsigned int lessthan0mask = 0xFFFFFFFF + ( n >= 0 ); + + // If the result was valid, set the result, (otherwise sets zero) + int result = (inrangemask & n); + + // if the result was out of range or zero. + result |= ((~inrangemask) & (~lessthan0mask)) & maxindex; + + return result; +} + + + +// Turn a number "inside out". +// See Recording Animation in Binary Order for Progressive Temporal Refinement +// by Paul Heckbert from "Graphics Gems". +// +// If you want to iterate something from 0 to n, you can use this to iterate non-sequentially, in +// such a way that you will start with widely separated values and then refine the gaps between +// them, as you would for progressive refinement. This works with non-power of two ranges. +int InsideOut( int nTotal, int nCounter ); + +#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ + (((p)->type < 3)? \ + ( \ + ((p)->dist <= (emins)[(p)->type])? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type])?\ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSide( (emins), (emaxs), (p))) + +//----------------------------------------------------------------------------- +// FIXME: Vector versions.... the float versions will go away hopefully soon! +//----------------------------------------------------------------------------- + +void AngleVectors (const QAngle& angles, Vector *forward); +void AngleVectors (const QAngle& angles, Vector *forward, Vector *right, Vector *up); +void AngleVectorsTranspose (const QAngle& angles, Vector *forward, Vector *right, Vector *up); +void AngleMatrix (const QAngle &angles, matrix3x4_t &mat ); +void AngleMatrix( const QAngle &angles, const Vector &position, matrix3x4_t &mat ); +void AngleMatrix (const RadianEuler &angles, matrix3x4_t &mat ); +void AngleMatrix( RadianEuler const &angles, const Vector &position, matrix3x4_t &mat ); +void AngleIMatrix (const QAngle &angles, matrix3x4_t &mat ); +void AngleIMatrix (const QAngle &angles, const Vector &position, matrix3x4_t &mat ); +void AngleIMatrix (const RadianEuler &angles, matrix3x4_t &mat ); +void VectorAngles( const Vector &forward, QAngle &angles ); +void VectorAngles( const Vector &forward, const Vector &pseudoup, QAngle &angles ); +void VectorMatrix( const Vector &forward, matrix3x4_t &mat ); +void VectorVectors( const Vector &forward, Vector &right, Vector &up ); +void SetIdentityMatrix( matrix3x4_t &mat ); +void SetScaleMatrix( float x, float y, float z, matrix3x4_t &dst ); +void MatrixBuildRotationAboutAxis( const Vector &vAxisOfRot, float angleDegrees, matrix3x4_t &dst ); + +inline bool MatrixIsIdentity( const matrix3x4_t &m ) +{ + return + m.m_flMatVal[0][0] == 1.0f && m.m_flMatVal[0][1] == 0.0f && m.m_flMatVal[0][2] == 0.0f && m.m_flMatVal[0][3] == 0.0f && + m.m_flMatVal[1][0] == 0.0f && m.m_flMatVal[1][1] == 1.0f && m.m_flMatVal[1][2] == 0.0f && m.m_flMatVal[1][3] == 0.0f && + m.m_flMatVal[2][0] == 0.0f && m.m_flMatVal[2][1] == 0.0f && m.m_flMatVal[2][2] == 1.0f && m.m_flMatVal[2][3] == 0.0f; +} + + +inline void SetScaleMatrix( float flScale, matrix3x4_t &dst ) +{ + SetScaleMatrix( flScale, flScale, flScale, dst ); +} + +inline void SetScaleMatrix( const Vector& scale, matrix3x4_t &dst ) +{ + SetScaleMatrix( scale.x, scale.y, scale.z, dst ); +} + +// Computes the inverse transpose +void MatrixTranspose( matrix3x4_t& mat ); +void MatrixTranspose( const matrix3x4_t& src, matrix3x4_t& dst ); +void MatrixInverseTranspose( const matrix3x4_t& src, matrix3x4_t& dst ); + +inline void PositionMatrix( const Vector &position, matrix3x4_t &mat ) +{ + MatrixSetColumn( position, 3, mat ); +} + +inline void MatrixPosition( const matrix3x4_t &matrix, Vector &position ) +{ + position[0] = matrix[0][3]; + position[1] = matrix[1][3]; + position[2] = matrix[2][3]; +} + +inline void VectorRotate( const Vector& in1, const matrix3x4_t &in2, Vector &out) +{ + VectorRotate( &in1.x, in2, &out.x ); +} + +inline void VectorIRotate( const Vector& in1, const matrix3x4_t &in2, Vector &out) +{ + VectorIRotate( &in1.x, in2, &out.x ); +} + +inline void MatrixAngles( const matrix3x4_t &matrix, QAngle &angles ) +{ + MatrixAngles( matrix, &angles.x ); +} + +inline void MatrixAngles( const matrix3x4_t &matrix, QAngle &angles, Vector &position ) +{ + MatrixAngles( matrix, angles ); + MatrixPosition( matrix, position ); +} + +inline void MatrixAngles( const matrix3x4_t &matrix, RadianEuler &angles ) +{ + MatrixAngles( matrix, &angles.x ); + + angles.Init( DEG2RAD( angles.z ), DEG2RAD( angles.x ), DEG2RAD( angles.y ) ); +} + +void MatrixAngles( const matrix3x4_t &mat, RadianEuler &angles, Vector &position ); + +void MatrixAngles( const matrix3x4_t &mat, Quaternion &q, Vector &position ); + +inline int VectorCompare (const Vector& v1, const Vector& v2) +{ + return v1 == v2; +} + +inline void VectorTransform (const Vector& in1, const matrix3x4_t &in2, Vector &out) +{ + VectorTransform( &in1.x, in2, &out.x ); +} + +inline void VectorITransform (const Vector& in1, const matrix3x4_t &in2, Vector &out) +{ + VectorITransform( &in1.x, in2, &out.x ); +} + +/* +inline void DecomposeRotation( const matrix3x4_t &mat, Vector &out ) +{ + DecomposeRotation( mat, &out.x ); +} +*/ + +inline int BoxOnPlaneSide (const Vector& emins, const Vector& emaxs, const cplane_t *plane ) +{ + return BoxOnPlaneSide( &emins.x, &emaxs.x, plane ); +} + +inline void VectorFill(Vector& a, float b) +{ + a[0]=a[1]=a[2]=b; +} + +inline void VectorNegate(Vector& a) +{ + a[0] = -a[0]; + a[1] = -a[1]; + a[2] = -a[2]; +} + +inline vec_t VectorAvg(Vector& a) +{ + return ( a[0] + a[1] + a[2] ) / 3; +} + +//----------------------------------------------------------------------------- +// Box/plane test (slow version) +//----------------------------------------------------------------------------- +inline int FASTCALL BoxOnPlaneSide2 (const Vector& emins, const Vector& emaxs, const cplane_t *p, float tolerance = 0.f ) +{ + Vector corners[2]; + + if (p->normal[0] < 0) + { + corners[0][0] = emins[0]; + corners[1][0] = emaxs[0]; + } + else + { + corners[1][0] = emins[0]; + corners[0][0] = emaxs[0]; + } + + if (p->normal[1] < 0) + { + corners[0][1] = emins[1]; + corners[1][1] = emaxs[1]; + } + else + { + corners[1][1] = emins[1]; + corners[0][1] = emaxs[1]; + } + + if (p->normal[2] < 0) + { + corners[0][2] = emins[2]; + corners[1][2] = emaxs[2]; + } + else + { + corners[1][2] = emins[2]; + corners[0][2] = emaxs[2]; + } + + int sides = 0; + + float dist1 = DotProduct (p->normal, corners[0]) - p->dist; + if (dist1 >= tolerance) + sides = 1; + + float dist2 = DotProduct (p->normal, corners[1]) - p->dist; + if (dist2 < -tolerance) + sides |= 2; + + return sides; +} + +//----------------------------------------------------------------------------- +// Helpers for bounding box construction +//----------------------------------------------------------------------------- + +void ClearBounds (Vector& mins, Vector& maxs); +void AddPointToBounds (const Vector& v, Vector& mins, Vector& maxs); + +//----------------------------------------------------------------------------- +// Ensures that the min and max bounds values are valid. +// (ClearBounds() sets min > max, which is clearly invalid.) +//----------------------------------------------------------------------------- +bool AreBoundsValid( const Vector &vMin, const Vector &vMax ); + +//----------------------------------------------------------------------------- +// Returns true if the provided point is in the AABB defined by vMin +// at the lower corner and vMax at the upper corner. +//----------------------------------------------------------------------------- +bool IsPointInBounds( const Vector &vPoint, const Vector &vMin, const Vector &vMax ); + +// +// COLORSPACE/GAMMA CONVERSION STUFF +// +void BuildGammaTable( float gamma, float texGamma, float brightness, int overbright ); + +// convert texture to linear 0..1 value +inline float TexLightToLinear( int c, int exponent ) +{ + extern float power2_n[256]; + Assert( exponent >= -128 && exponent <= 127 ); + return ( float )c * power2_n[exponent+128]; +} + + +// convert texture to linear 0..1 value +int LinearToTexture( float f ); +// converts 0..1 linear value to screen gamma (0..255) +int LinearToScreenGamma( float f ); +float TextureToLinear( int c ); + +// compressed color format +struct ColorRGBExp32 +{ + byte r, g, b; + signed char exponent; +}; + +void ColorRGBExp32ToVector( const ColorRGBExp32& in, Vector& out ); +void VectorToColorRGBExp32( const Vector& v, ColorRGBExp32 &c ); + +// solve for "x" where "a x^2 + b x + c = 0", return true if solution exists +bool SolveQuadratic( float a, float b, float c, float &root1, float &root2 ); + +// solves for "a, b, c" where "a x^2 + b x + c = y", return true if solution exists +bool SolveInverseQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c ); + +// solves for a,b,c specified as above, except that it always creates a monotonically increasing or +// decreasing curve if the data is monotonically increasing or decreasing. In order to enforce the +// monoticity condition, it is possible that the resulting quadratic will only approximate the data +// instead of interpolating it. This code is not especially fast. +bool SolveInverseQuadraticMonotonic( float x1, float y1, float x2, float y2, + float x3, float y3, float &a, float &b, float &c ); + + + + +// solves for "a, b, c" where "1/(a x^2 + b x + c ) = y", return true if solution exists +bool SolveInverseReciprocalQuadratic( float x1, float y1, float x2, float y2, float x3, float y3, float &a, float &b, float &c ); + +// rotate a vector around the Z axis (YAW) +void VectorYawRotate( const Vector& in, float flYaw, Vector &out); + + +// Bias takes an X value between 0 and 1 and returns another value between 0 and 1 +// The curve is biased towards 0 or 1 based on biasAmt, which is between 0 and 1. +// Lower values of biasAmt bias the curve towards 0 and higher values bias it towards 1. +// +// For example, with biasAmt = 0.2, the curve looks like this: +// +// 1 +// | * +// | * +// | * +// | ** +// | ** +// | **** +// |********* +// |___________________ +// 0 1 +// +// +// With biasAmt = 0.8, the curve looks like this: +// +// 1 +// | ************** +// | ** +// | * +// | * +// |* +// |* +// |* +// |___________________ +// 0 1 +// +// With a biasAmt of 0.5, Bias returns X. +float Bias( float x, float biasAmt ); + + +// Gain is similar to Bias, but biasAmt biases towards or away from 0.5. +// Lower bias values bias towards 0.5 and higher bias values bias away from it. +// +// For example, with biasAmt = 0.2, the curve looks like this: +// +// 1 +// | * +// | * +// | ** +// | *************** +// | ** +// | * +// |* +// |___________________ +// 0 1 +// +// +// With biasAmt = 0.8, the curve looks like this: +// +// 1 +// | ***** +// | *** +// | * +// | * +// | * +// | *** +// |***** +// |___________________ +// 0 1 +float Gain( float x, float biasAmt ); + + +// SmoothCurve maps a 0-1 value into another 0-1 value based on a cosine wave +// where the derivatives of the function at 0 and 1 (and 0.5) are 0. This is useful for +// any fadein/fadeout effect where it should start and end smoothly. +// +// The curve looks like this: +// +// 1 +// | ** +// | * * +// | * * +// | * * +// | * * +// | ** ** +// |*** *** +// |___________________ +// 0 1 +// +float SmoothCurve( float x ); + + +// This works like SmoothCurve, with two changes: +// +// 1. Instead of the curve peaking at 0.5, it will peak at flPeakPos. +// (So if you specify flPeakPos=0.2, then the peak will slide to the left). +// +// 2. flPeakSharpness is a 0-1 value controlling the sharpness of the peak. +// Low values blunt the peak and high values sharpen the peak. +float SmoothCurve_Tweak( float x, float flPeakPos=0.5, float flPeakSharpness=0.5 ); + + +//float ExponentialDecay( float halflife, float dt ); +//float ExponentialDecay( float decayTo, float decayTime, float dt ); + +// halflife is time for value to reach 50% +inline float ExponentialDecay( float halflife, float dt ) +{ + // log(0.5) == -0.69314718055994530941723212145818 + return expf( -0.69314718f / halflife * dt); +} + +// decayTo is factor the value should decay to in decayTime +inline float ExponentialDecay( float decayTo, float decayTime, float dt ) +{ + return expf( logf( decayTo ) / decayTime * dt); +} + +// Get the integrated distanced traveled +// decayTo is factor the value should decay to in decayTime +// dt is the time relative to the last velocity update +inline float ExponentialDecayIntegral( float decayTo, float decayTime, float dt ) +{ + return (powf( decayTo, dt / decayTime) * decayTime - decayTime) / logf( decayTo ); +} + +// hermite basis function for smooth interpolation +// Similar to Gain() above, but very cheap to call +// value should be between 0 & 1 inclusive +inline float SimpleSpline( float value ) +{ + float valueSquared = value * value; + + // Nice little ease-in, ease-out spline-like curve + return (3 * valueSquared - 2 * valueSquared * value); +} + +// remaps a value in [startInterval, startInterval+rangeInterval] from linear to +// spline using SimpleSpline +inline float SimpleSplineRemapVal( float val, float A, float B, float C, float D) +{ + if ( A == B ) + return val >= B ? D : C; + float cVal = (val - A) / (B - A); + return C + (D - C) * SimpleSpline( cVal ); +} + +// remaps a value in [startInterval, startInterval+rangeInterval] from linear to +// spline using SimpleSpline +inline float SimpleSplineRemapValClamped( float val, float A, float B, float C, float D ) +{ + if ( A == B ) + return val >= B ? D : C; + float cVal = (val - A) / (B - A); + cVal = clamp( cVal, 0.0f, 1.0f ); + return C + (D - C) * SimpleSpline( cVal ); +} + +FORCEINLINE int RoundFloatToInt(float f) +{ +#if defined( _X360 ) +#ifdef Assert + Assert( IsFPUControlWordSet() ); +#endif + union + { + double flResult; + int pResult[2]; + }; + flResult = __fctiw( f ); + return pResult[1]; +#elif defined ( _PS3 ) + return __fctiw( f ); +#else // !X360 + int nResult; +#if defined( COMPILER_MSVC32 ) + __asm + { + fld f + fistp nResult + } +#elif GNUC + __asm __volatile__ ( + "fistpl %0;": "=m" (nResult): "t" (f) : "st" + ); +#else + nResult = static_cast<int>(f); +#endif + return nResult; +#endif +} + +FORCEINLINE unsigned char RoundFloatToByte(float f) +{ +#if defined( _X360 ) +#ifdef Assert + Assert( IsFPUControlWordSet() ); +#endif + union + { + double flResult; + int pIntResult[2]; + unsigned char pResult[8]; + }; + flResult = __fctiw( f ); +#ifdef Assert + Assert( pIntResult[1] >= 0 && pIntResult[1] <= 255 ); +#endif + return pResult[7]; + +#elif defined ( _PS3 ) + return __fctiw( f ); +#else // !X360 + + int nResult; + +#if defined( COMPILER_MSVC32 ) + __asm + { + fld f + fistp nResult + } +#elif GNUC + __asm __volatile__ ( + "fistpl %0;": "=m" (nResult): "t" (f) : "st" + ); +#else + nResult = static_cast<unsigned int> (f) & 0xff; +#endif + +#ifdef Assert + Assert( nResult >= 0 && nResult <= 255 ); +#endif + return nResult; + +#endif +} + +FORCEINLINE unsigned long RoundFloatToUnsignedLong(float f) +{ +#if defined( _X360 ) +#ifdef Assert + Assert( IsFPUControlWordSet() ); +#endif + union + { + double flResult; + int pIntResult[2]; + unsigned long pResult[2]; + }; + flResult = __fctiw( f ); + Assert( pIntResult[1] >= 0 ); + return pResult[1]; +#elif defined ( _PS3 ) + return __fctiw( f ); +#else // !X360 + +#if defined( COMPILER_MSVC32 ) + unsigned char nResult[8]; + __asm + { + fld f + fistp qword ptr nResult + } + return *((unsigned long*)nResult); +#elif defined( COMPILER_GCC ) + unsigned char nResult[8]; + __asm __volatile__ ( + "fistpl %0;": "=m" (nResult): "t" (f) : "st" + ); + return *((unsigned long*)nResult); +#else + return static_cast<unsigned long>(f); +#endif + +#endif +} + +FORCEINLINE bool IsIntegralValue( float flValue, float flTolerance = 0.001f ) +{ + return fabs( RoundFloatToInt( flValue ) - flValue ) < flTolerance; +} + +// Fast, accurate ftol: +FORCEINLINE int Float2Int( float a ) +{ +#if defined( _X360 ) + union + { + double flResult; + int pResult[2]; + }; + flResult = __fctiwz( a ); + return pResult[1]; +#elif defined ( _PS3 ) + return __fctiwz( a ); +#else // !X360 + + int RetVal; + +#if defined( COMPILER_MSVC32 ) + int CtrlwdHolder; + int CtrlwdSetter; + __asm + { + fld a // push 'a' onto the FP stack + fnstcw CtrlwdHolder // store FPU control word + movzx eax, CtrlwdHolder // move and zero extend word into eax + and eax, 0xFFFFF3FF // set all bits except rounding bits to 1 + or eax, 0x00000C00 // set rounding mode bits to round towards zero + mov CtrlwdSetter, eax // Prepare to set the rounding mode -- prepare to enter plaid! + fldcw CtrlwdSetter // Entering plaid! + fistp RetVal // Store and converted (to int) result + fldcw CtrlwdHolder // Restore control word + } +#else + RetVal = static_cast<int>( a ); +#endif + + return RetVal; +#endif +} + +// Over 15x faster than: (int)floor(value) +inline int Floor2Int( float a ) +{ + int RetVal; + +#if defined( PLATFORM_PPC ) + RetVal = (int)floor( a ); +#elif defined( COMPILER_MSVC32 ) + int CtrlwdHolder; + int CtrlwdSetter; + __asm + { + fld a // push 'a' onto the FP stack + fnstcw CtrlwdHolder // store FPU control word + movzx eax, CtrlwdHolder // move and zero extend word into eax + and eax, 0xFFFFF3FF // set all bits except rounding bits to 1 + or eax, 0x00000400 // set rounding mode bits to round down + mov CtrlwdSetter, eax // Prepare to set the rounding mode -- prepare to enter plaid! + fldcw CtrlwdSetter // Entering plaid! + fistp RetVal // Store floored and converted (to int) result + fldcw CtrlwdHolder // Restore control word + } +#else + RetVal = static_cast<int>( floor(a) ); +#endif + + return RetVal; +} + +//----------------------------------------------------------------------------- +// Fast color conversion from float to unsigned char +//----------------------------------------------------------------------------- +FORCEINLINE unsigned char FastFToC( float c ) +{ + volatile float dc; + + // ieee trick + dc = c * 255.0f + (float)(1 << 23); + + // return the lsb +#if defined( _X360 ) || defined( _PS3 ) + return ((unsigned char*)&dc)[3]; +#else + return *(unsigned char*)&dc; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Bound input float to .001 (millisecond) boundary +// Input : in - +// Output : inline float +//----------------------------------------------------------------------------- +inline float ClampToMsec( float in ) +{ + int msec = Floor2Int( in * 1000.0f + 0.5f ); + return msec / 1000.0f; +} + +// Over 15x faster than: (int)ceil(value) +inline int Ceil2Int( float a ) +{ + int RetVal; + +#if defined( PLATFORM_PPC ) + RetVal = (int)ceil( a ); +#elif defined( COMPILER_MSVC32 ) + int CtrlwdHolder; + int CtrlwdSetter; + __asm + { + fld a // push 'a' onto the FP stack + fnstcw CtrlwdHolder // store FPU control word + movzx eax, CtrlwdHolder // move and zero extend word into eax + and eax, 0xFFFFF3FF // set all bits except rounding bits to 1 + or eax, 0x00000800 // set rounding mode bits to round down + mov CtrlwdSetter, eax // Prepare to set the rounding mode -- prepare to enter plaid! + fldcw CtrlwdSetter // Entering plaid! + fistp RetVal // Store floored and converted (to int) result + fldcw CtrlwdHolder // Restore control word + } +#else + RetVal = static_cast<int>( ceil(a) ); +#endif + + return RetVal; +} + + +// Regular signed area of triangle +#define TriArea2D( A, B, C ) \ + ( 0.5f * ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) ) + +// This version doesn't premultiply by 0.5f, so it's the area of the rectangle instead +#define TriArea2DTimesTwo( A, B, C ) \ + ( ( ( B.x - A.x ) * ( C.y - A.y ) - ( B.y - A.y ) * ( C.x - A.x ) ) ) + + +// Get the barycentric coordinates of "pt" in triangle [A,B,C]. +inline void GetBarycentricCoords2D( + Vector2D const &A, + Vector2D const &B, + Vector2D const &C, + Vector2D const &pt, + float bcCoords[3] ) +{ + // Note, because to top and bottom are both x2, the issue washes out in the composite + float invTriArea = 1.0f / TriArea2DTimesTwo( A, B, C ); + + // NOTE: We assume here that the lightmap coordinate vertices go counterclockwise. + // If not, TriArea2D() is negated so this works out right. + bcCoords[0] = TriArea2DTimesTwo( B, C, pt ) * invTriArea; + bcCoords[1] = TriArea2DTimesTwo( C, A, pt ) * invTriArea; + bcCoords[2] = TriArea2DTimesTwo( A, B, pt ) * invTriArea; +} + + +// Return true of the sphere might touch the box (the sphere is actually treated +// like a box itself, so this may return true if the sphere's bounding box touches +// a corner of the box but the sphere itself doesn't). +inline bool QuickBoxSphereTest( + const Vector& vOrigin, + float flRadius, + const Vector& bbMin, + const Vector& bbMax ) +{ + return vOrigin.x - flRadius < bbMax.x && vOrigin.x + flRadius > bbMin.x && + vOrigin.y - flRadius < bbMax.y && vOrigin.y + flRadius > bbMin.y && + vOrigin.z - flRadius < bbMax.z && vOrigin.z + flRadius > bbMin.z; +} + + +// Return true of the boxes intersect (but not if they just touch). +inline bool QuickBoxIntersectTest( + const Vector& vBox1Min, + const Vector& vBox1Max, + const Vector& vBox2Min, + const Vector& vBox2Max ) +{ + return + vBox1Min.x < vBox2Max.x && vBox1Max.x > vBox2Min.x && + vBox1Min.y < vBox2Max.y && vBox1Max.y > vBox2Min.y && + vBox1Min.z < vBox2Max.z && vBox1Max.z > vBox2Min.z; +} + + +extern float GammaToLinearFullRange( float gamma ); +extern float LinearToGammaFullRange( float linear ); +extern float GammaToLinear( float gamma ); +extern float LinearToGamma( float linear ); + +extern float SrgbGammaToLinear( float flSrgbGammaValue ); +extern float SrgbLinearToGamma( float flLinearValue ); +extern float X360GammaToLinear( float fl360GammaValue ); +extern float X360LinearToGamma( float flLinearValue ); +extern float SrgbGammaTo360Gamma( float flSrgbGammaValue ); + +// linear (0..4) to screen corrected vertex space (0..1?) +FORCEINLINE float LinearToVertexLight( float f ) +{ + extern float lineartovertex[4096]; + + // Gotta clamp before the multiply; could overflow... + // assume 0..4 range + int i = RoundFloatToInt( f * 1024.f ); + + // Presumably the comman case will be not to clamp, so check that first: + if( (unsigned)i > 4095 ) + { + if ( i < 0 ) + i = 0; // Compare to zero instead of 4095 to save 4 bytes in the instruction stream + else + i = 4095; + } + + return lineartovertex[i]; +} + + +FORCEINLINE unsigned char LinearToLightmap( float f ) +{ + extern unsigned char lineartolightmap[4096]; + + // Gotta clamp before the multiply; could overflow... + int i = RoundFloatToInt( f * 1024.f ); // assume 0..4 range + + // Presumably the comman case will be not to clamp, so check that first: + if ( (unsigned)i > 4095 ) + { + if ( i < 0 ) + i = 0; // Compare to zero instead of 4095 to save 4 bytes in the instruction stream + else + i = 4095; + } + + return lineartolightmap[i]; +} + +FORCEINLINE void ColorClamp( Vector& color ) +{ + float maxc = MAX( color.x, MAX( color.y, color.z ) ); + if ( maxc > 1.0f ) + { + float ooMax = 1.0f / maxc; + color.x *= ooMax; + color.y *= ooMax; + color.z *= ooMax; + } + + if ( color[0] < 0.f ) color[0] = 0.f; + if ( color[1] < 0.f ) color[1] = 0.f; + if ( color[2] < 0.f ) color[2] = 0.f; +} + +inline void ColorClampTruncate( Vector& color ) +{ + if (color[0] > 1.0f) color[0] = 1.0f; else if (color[0] < 0.0f) color[0] = 0.0f; + if (color[1] > 1.0f) color[1] = 1.0f; else if (color[1] < 0.0f) color[1] = 0.0f; + if (color[2] > 1.0f) color[2] = 1.0f; else if (color[2] < 0.0f) color[2] = 0.0f; +} + +// Interpolate a Catmull-Rom spline. +// t is a [0,1] value and interpolates a curve between p2 and p3. +void Catmull_Rom_Spline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector &output ); + +// Interpolate a Catmull-Rom spline. +// Returns the tangent of the point at t of the spline +void Catmull_Rom_Spline_Tangent( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector &output ); + +// area under the curve [0..t] +void Catmull_Rom_Spline_Integral( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// area under the curve [0..1] +void Catmull_Rom_Spline_Integral( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + Vector& output ); + +// Interpolate a Catmull-Rom spline. +// Normalize p2->p1 and p3->p4 to be the same length as p2->p3 +void Catmull_Rom_Spline_Normalize( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector &output ); + +// area under the curve [0..t] +// Normalize p2->p1 and p3->p4 to be the same length as p2->p3 +void Catmull_Rom_Spline_Integral_Normalize( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// Interpolate a Catmull-Rom spline. +// Normalize p2.x->p1.x and p3.x->p4.x to be the same length as p2.x->p3.x +void Catmull_Rom_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector &output ); + +// area under the curve [0..t] +void Catmull_Rom_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// Interpolate a Hermite spline. +// t is a [0,1] value and interpolates a curve between p1 and p2 with the deltas d1 and d2. +void Hermite_Spline( + const Vector &p1, + const Vector &p2, + const Vector &d1, + const Vector &d2, + float t, + Vector& output ); + +float Hermite_Spline( + float p1, + float p2, + float d1, + float d2, + float t ); + +// t is a [0,1] value and interpolates a curve between p1 and p2 with the slopes p0->p1 and p1->p2 +void Hermite_Spline( + const Vector &p0, + const Vector &p1, + const Vector &p2, + float t, + Vector& output ); + +float Hermite_Spline( + float p0, + float p1, + float p2, + float t ); + + +void Hermite_SplineBasis( float t, float basis[] ); + +void Hermite_Spline( + const Quaternion &q0, + const Quaternion &q1, + const Quaternion &q2, + float t, + Quaternion &output ); + + +// See http://en.wikipedia.org/wiki/Kochanek-Bartels_curves +// +// Tension: -1 = Round -> 1 = Tight +// Bias: -1 = Pre-shoot (bias left) -> 1 = Post-shoot (bias right) +// Continuity: -1 = Box corners -> 1 = Inverted corners +// +// If T=B=C=0 it's the same matrix as Catmull-Rom. +// If T=1 & B=C=0 it's the same as Cubic. +// If T=B=0 & C=-1 it's just linear interpolation +// +// See http://news.povray.org/povray.binaries.tutorials/attachment/%[email protected]%3E/Splines.bas.txt +// for example code and descriptions of various spline types... +// +void Kochanek_Bartels_Spline( + float tension, + float bias, + float continuity, + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +void Kochanek_Bartels_Spline_NormalizeX( + float tension, + float bias, + float continuity, + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// See link at Kochanek_Bartels_Spline for info on the basis matrix used +void Cubic_Spline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +void Cubic_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// See link at Kochanek_Bartels_Spline for info on the basis matrix used +void BSpline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +void BSpline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// See link at Kochanek_Bartels_Spline for info on the basis matrix used +void Parabolic_Spline( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +void Parabolic_Spline_NormalizeX( + const Vector &p1, + const Vector &p2, + const Vector &p3, + const Vector &p4, + float t, + Vector& output ); + +// Evaluate the cubic Bernstein basis for the input parametric coordinate. +// Output is the coefficient for that basis polynomial. +float CubicBasis0( float t ); +float CubicBasis1( float t ); +float CubicBasis2( float t ); +float CubicBasis3( float t ); + +// quintic interpolating polynomial from Perlin. +// 0->0, 1->1, smooth-in between with smooth tangents +FORCEINLINE float QuinticInterpolatingPolynomial(float t) +{ + // 6t^5-15t^4+10t^3 + return t * t * t *( t * ( t* 6.0 - 15.0 ) + 10.0 ); +} + +// given a table of sorted tabulated positions, return the two indices and blendfactor to linear +// interpolate. Does a search. Can be used to find the blend value to interpolate between +// keyframes. +void GetInterpolationData( float const *pKnotPositions, + float const *pKnotValues, + int nNumValuesinList, + int nInterpolationRange, + float flPositionToInterpolateAt, + bool bWrap, + float *pValueA, + float *pValueB, + float *pInterpolationValue); +float RangeCompressor( float flValue, float flMin, float flMax, float flBase ); + +// Get the minimum distance from vOrigin to the bounding box defined by [mins,maxs] +// using voronoi regions. +// 0 is returned if the origin is inside the box. +float CalcSqrDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point ); +void CalcClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut ); +void CalcSqrDistAndClosestPointOnAABB( const Vector &mins, const Vector &maxs, const Vector &point, Vector &closestOut, float &distSqrOut ); + +inline float CalcDistanceToAABB( const Vector &mins, const Vector &maxs, const Vector &point ) +{ + float flDistSqr = CalcSqrDistanceToAABB( mins, maxs, point ); + return sqrt(flDistSqr); +} + +// Get the closest point from P to the (infinite) line through vLineA and vLineB and +// calculate the shortest distance from P to the line. +// If you pass in a value for t, it will tell you the t for (A + (B-A)t) to get the closest point. +// If the closest point lies on the segment between A and B, then 0 <= t <= 1. +void CalcClosestPointOnLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *t=0 ); +float CalcDistanceToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 ); +float CalcDistanceSqrToLine( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 ); + +// The same three functions as above, except now the line is closed between A and B. +void CalcClosestPointOnLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, Vector &vClosest, float *t=0 ); +float CalcDistanceToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 ); +float CalcDistanceSqrToLineSegment( const Vector &P, const Vector &vLineA, const Vector &vLineB, float *t=0 ); + +// A function to compute the closes line segment connnection two lines (or false if the lines are parallel, etc.) +bool CalcLineToLineIntersectionSegment( + const Vector& p1,const Vector& p2,const Vector& p3,const Vector& p4,Vector *s1,Vector *s2, + float *t1, float *t2 ); + +// The above functions in 2D +void CalcClosestPointOnLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, Vector2D &vClosest, float *t=0 ); +float CalcDistanceToLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 ); +float CalcDistanceSqrToLine2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 ); +void CalcClosestPointOnLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, Vector2D &vClosest, float *t=0 ); +float CalcDistanceToLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 ); +float CalcDistanceSqrToLineSegment2D( Vector2D const &P, Vector2D const &vLineA, Vector2D const &vLineB, float *t=0 ); + +// Init the mathlib +void MathLib_Init( float gamma = 2.2f, float texGamma = 2.2f, float brightness = 0.0f, int overbright = 2.0f, bool bAllow3DNow = true, bool bAllowSSE = true, bool bAllowSSE2 = true, bool bAllowMMX = true ); +bool MathLib_MMXEnabled( void ); +bool MathLib_SSEEnabled( void ); +bool MathLib_SSE2Enabled( void ); + +inline float Approach( float target, float value, float speed ); +float ApproachAngle( float target, float value, float speed ); +float AngleDiff( float destAngle, float srcAngle ); +float AngleDistance( float next, float cur ); +float AngleNormalize( float angle ); + +// ensure that 0 <= angle <= 360 +float AngleNormalizePositive( float angle ); + +bool AnglesAreEqual( float a, float b, float tolerance = 0.0f ); + + +void RotationDeltaAxisAngle( const QAngle &srcAngles, const QAngle &destAngles, Vector &deltaAxis, float &deltaAngle ); +void RotationDelta( const QAngle &srcAngles, const QAngle &destAngles, QAngle *out ); + +//----------------------------------------------------------------------------- +// Clips a line segment such that only the portion in the positive half-space +// of the plane remains. If the segment is entirely clipped, the vectors +// are set to vec3_invalid (all components are FLT_MAX). +// +// flBias is added to the dot product with the normal. A positive bias +// results in a more inclusive positive half-space, while a negative bias +// results in a more exclusive positive half-space. +//----------------------------------------------------------------------------- +void ClipLineSegmentToPlane( const Vector &vNormal, const Vector &vPlanePoint, Vector *p1, Vector *p2, float flBias = 0.0f ); + +void ComputeTrianglePlane( const Vector& v1, const Vector& v2, const Vector& v3, Vector& normal, float& intercept ); +int PolyFromPlane( Vector *pOutVerts, const Vector& normal, float dist, float fHalfScale = 9000.0f ); +void PolyFromPlane_SIMD( fltx4 *pOutVerts, const fltx4 & plane, float fHalfScale = 9000.0f ); +int ClipPolyToPlane( Vector *inVerts, int vertCount, Vector *outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon = 0.1f ); +int ClipPolyToPlane_SIMD( fltx4 *pInVerts, int vertCount, fltx4 *pOutVerts, const fltx4& plane, float fOnPlaneEpsilon = 0.1f ); +int ClipPolyToPlane_Precise( double *inVerts, int vertCount, double *outVerts, const double *normal, double dist, double fOnPlaneEpsilon = 0.1 ); +float TetrahedronVolume( const Vector &p0, const Vector &p1, const Vector &p2, const Vector &p3 ); +float TriangleArea( const Vector &p0, const Vector &p1, const Vector &p2 ); + +//----------------------------------------------------------------------------- +// Computes a reasonable tangent space for a triangle +//----------------------------------------------------------------------------- +void CalcTriangleTangentSpace( const Vector &p0, const Vector &p1, const Vector &p2, + const Vector2D &t0, const Vector2D &t1, const Vector2D& t2, + Vector &sVect, Vector &tVect ); + +//----------------------------------------------------------------------------- +// Transforms a AABB into another space; which will inherently grow the box. +//----------------------------------------------------------------------------- +void TransformAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ); + +//----------------------------------------------------------------------------- +// Uses the inverse transform of in1 +//----------------------------------------------------------------------------- +void ITransformAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ); + +//----------------------------------------------------------------------------- +// Rotates a AABB into another space; which will inherently grow the box. +// (same as TransformAABB, but doesn't take the translation into account) +//----------------------------------------------------------------------------- +void RotateAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ); + +//----------------------------------------------------------------------------- +// Uses the inverse transform of in1 +//----------------------------------------------------------------------------- +void IRotateAABB( const matrix3x4_t &in1, const Vector &vecMinsIn, const Vector &vecMaxsIn, Vector &vecMinsOut, Vector &vecMaxsOut ); + +//----------------------------------------------------------------------------- +// Transform a plane +//----------------------------------------------------------------------------- +inline void MatrixTransformPlane( const matrix3x4_t &src, const cplane_t &inPlane, cplane_t &outPlane ) +{ + // What we want to do is the following: + // 1) transform the normal into the new space. + // 2) Determine a point on the old plane given by plane dist * plane normal + // 3) Transform that point into the new space + // 4) Plane dist = DotProduct( new normal, new point ) + + // An optimized version, which works if the plane is orthogonal. + // 1) Transform the normal into the new space + // 2) Realize that transforming the old plane point into the new space + // is given by [ d * n'x + Tx, d * n'y + Ty, d * n'z + Tz ] + // where d = old plane dist, n' = transformed normal, Tn = translational component of transform + // 3) Compute the new plane dist using the dot product of the normal result of #2 + + // For a correct result, this should be an inverse-transpose matrix + // but that only matters if there are nonuniform scale or skew factors in this matrix. + VectorRotate( inPlane.normal, src, outPlane.normal ); + outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal ); + outPlane.dist += outPlane.normal.x * src[0][3] + outPlane.normal.y * src[1][3] + outPlane.normal.z * src[2][3]; +} + +inline void MatrixITransformPlane( const matrix3x4_t &src, const cplane_t &inPlane, cplane_t &outPlane ) +{ + // The trick here is that Tn = translational component of transform, + // but for an inverse transform, Tn = - R^-1 * T + Vector vecTranslation; + MatrixGetColumn( src, 3, vecTranslation ); + + Vector vecInvTranslation; + VectorIRotate( vecTranslation, src, vecInvTranslation ); + + VectorIRotate( inPlane.normal, src, outPlane.normal ); + outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal ); + outPlane.dist -= outPlane.normal.x * vecInvTranslation[0] + outPlane.normal.y * vecInvTranslation[1] + outPlane.normal.z * vecInvTranslation[2]; +} + +int CeilPow2( int in ); +int FloorPow2( int in ); + +FORCEINLINE float * UnpackNormal_HEND3N( const unsigned int *pPackedNormal, float *pNormal ) +{ + int temp[3]; + temp[0] = ((*pPackedNormal >> 0L) & 0x7ff); + if ( temp[0] & 0x400 ) + { + temp[0] = 2048 - temp[0]; + } + temp[1] = ((*pPackedNormal >> 11L) & 0x7ff); + if ( temp[1] & 0x400 ) + { + temp[1] = 2048 - temp[1]; + } + temp[2] = ((*pPackedNormal >> 22L) & 0x3ff); + if ( temp[2] & 0x200 ) + { + temp[2] = 1024 - temp[2]; + } + pNormal[0] = (float)temp[0] * 1.0f/1023.0f; + pNormal[1] = (float)temp[1] * 1.0f/1023.0f; + pNormal[2] = (float)temp[2] * 1.0f/511.0f; + return pNormal; +} + + +FORCEINLINE unsigned int * PackNormal_HEND3N( const float *pNormal, unsigned int *pPackedNormal ) +{ + int temp[3]; + + temp[0] = Float2Int( pNormal[0] * 1023.0f ); + temp[1] = Float2Int( pNormal[1] * 1023.0f ); + temp[2] = Float2Int( pNormal[2] * 511.0f ); + + // the normal is out of bounds, determine the source and fix + // clamping would be even more of a slowdown here + Assert( temp[0] >= -1023 && temp[0] <= 1023 ); + Assert( temp[1] >= -1023 && temp[1] <= 1023 ); + Assert( temp[2] >= -511 && temp[2] <= 511 ); + + *pPackedNormal = ( ( temp[2] & 0x3ff ) << 22L ) | + ( ( temp[1] & 0x7ff ) << 11L ) | + ( ( temp[0] & 0x7ff ) << 0L ); + return pPackedNormal; +} + + +FORCEINLINE unsigned int * PackNormal_HEND3N( float nx, float ny, float nz, unsigned int *pPackedNormal ) +{ + int temp[3]; + + temp[0] = Float2Int( nx * 1023.0f ); + temp[1] = Float2Int( ny * 1023.0f ); + temp[2] = Float2Int( nz * 511.0f ); + + // the normal is out of bounds, determine the source and fix + // clamping would be even more of a slowdown here + Assert( temp[0] >= -1023 && temp[0] <= 1023 ); + Assert( temp[1] >= -1023 && temp[1] <= 1023 ); + Assert( temp[2] >= -511 && temp[2] <= 511 ); + + *pPackedNormal = ( ( temp[2] & 0x3ff ) << 22L ) | + ( ( temp[1] & 0x7ff ) << 11L ) | + ( ( temp[0] & 0x7ff ) << 0L ); + return pPackedNormal; +} + + + +FORCEINLINE float * UnpackNormal_SHORT2( const unsigned int *pPackedNormal, float *pNormal, bool bIsTangent = FALSE ) +{ + // Unpacks from Jason's 2-short format (fills in a 4th binormal-sign (+1/-1) value, if this is a tangent vector) + + // FIXME: short math is slow on 360 - use ints here instead (bit-twiddle to deal w/ the sign bits) + short iX = (*pPackedNormal & 0x0000FFFF); + short iY = (*pPackedNormal & 0xFFFF0000) >> 16; + + float zSign = +1; + if ( iX < 0 ) + { + zSign = -1; + iX = -iX; + } + float tSign = +1; + if ( iY < 0 ) + { + tSign = -1; + iY = -iY; + } + + pNormal[0] = ( iX - 16384.0f ) / 16384.0f; + pNormal[1] = ( iY - 16384.0f ) / 16384.0f; + float mag = ( pNormal[0]*pNormal[0] + pNormal[1]*pNormal[1] ); + if ( mag > 1.0f ) + { + mag = 1.0f; + } + pNormal[2] = zSign*sqrtf( 1.0f - mag ); + if ( bIsTangent ) + { + pNormal[3] = tSign; + } + + return pNormal; +} + +FORCEINLINE unsigned int * PackNormal_SHORT2( float nx, float ny, float nz, unsigned int *pPackedNormal, float binormalSign = +1.0f ) +{ + // Pack a vector (ASSUMED TO BE NORMALIZED) into Jason's 4-byte (SHORT2) format. + // This simply reconstructs Z from X & Y. It uses the sign bits of the X & Y coords + // to reconstruct the sign of Z and, if this is a tangent vector, the sign of the + // binormal (this is needed because tangent/binormal vectors are supposed to follow + // UV gradients, but shaders reconstruct the binormal from the tangent and normal + // assuming that they form a right-handed basis). + + nx += 1; // [-1,+1] -> [0,2] + ny += 1; + nx *= 16384.0f; // [ 0, 2] -> [0,32768] + ny *= 16384.0f; + + // '0' and '32768' values are invalid encodings + nx = MAX( nx, 1.0f ); // Make sure there are no zero values + ny = MAX( ny, 1.0f ); + nx = MIN( nx, 32767.0f ); // Make sure there are no 32768 values + ny = MIN( ny, 32767.0f ); + + if ( nz < 0.0f ) + nx = -nx; // Set the sign bit for z + + ny *= binormalSign; // Set the sign bit for the binormal (use when encoding a tangent vector) + + // FIXME: short math is slow on 360 - use ints here instead (bit-twiddle to deal w/ the sign bits), also use Float2Int() + short sX = (short)nx; // signed short [1,32767] + short sY = (short)ny; + + *pPackedNormal = ( sX & 0x0000FFFF ) | ( sY << 16 ); // NOTE: The mask is necessary (if sX is negative and cast to an int...) + + return pPackedNormal; +} + +FORCEINLINE unsigned int * PackNormal_SHORT2( const float *pNormal, unsigned int *pPackedNormal, float binormalSign = +1.0f ) +{ + return PackNormal_SHORT2( pNormal[0], pNormal[1], pNormal[2], pPackedNormal, binormalSign ); +} + +// Unpacks a UBYTE4 normal (for a tangent, the result's fourth component receives the binormal 'sign') +FORCEINLINE float * UnpackNormal_UBYTE4( const unsigned int *pPackedNormal, float *pNormal, bool bIsTangent = FALSE ) +{ + unsigned char cX, cY; + if ( bIsTangent ) + { + cX = *pPackedNormal >> 16; // Unpack Z + cY = *pPackedNormal >> 24; // Unpack W + } + else + { + cX = *pPackedNormal >> 0; // Unpack X + cY = *pPackedNormal >> 8; // Unpack Y + } + + float x = cX - 128.0f; + float y = cY - 128.0f; + float z; + + float zSignBit = x < 0 ? 1.0f : 0.0f; // z and t negative bits (like slt asm instruction) + float tSignBit = y < 0 ? 1.0f : 0.0f; + float zSign = -( 2*zSignBit - 1 ); // z and t signs + float tSign = -( 2*tSignBit - 1 ); + + x = x*zSign - zSignBit; // 0..127 + y = y*tSign - tSignBit; + x = x - 64; // -64..63 + y = y - 64; + + float xSignBit = x < 0 ? 1.0f : 0.0f; // x and y negative bits (like slt asm instruction) + float ySignBit = y < 0 ? 1.0f : 0.0f; + float xSign = -( 2*xSignBit - 1 ); // x and y signs + float ySign = -( 2*ySignBit - 1 ); + + x = ( x*xSign - xSignBit ) / 63.0f; // 0..1 range + y = ( y*ySign - ySignBit ) / 63.0f; + z = 1.0f - x - y; + + float oolen = 1.0f / sqrt( x*x + y*y + z*z ); // Normalize and + x *= oolen * xSign; // Recover signs + y *= oolen * ySign; + z *= oolen * zSign; + + pNormal[0] = x; + pNormal[1] = y; + pNormal[2] = z; + if ( bIsTangent ) + { + pNormal[3] = tSign; + } + + return pNormal; +} + +////////////////////////////////////////////////////////////////////////////// +// See: http://www.oroboro.com/rafael/docserv.php/index/programming/article/unitv2 +// +// UBYTE4 encoding, using per-octant projection onto x+y+z=1 +// Assume input vector is already unit length +// +// binormalSign specifies 'sign' of binormal, stored in t sign bit of tangent +// (lets the shader know whether norm/tan/bin form a right-handed basis) +// +// bIsTangent is used to specify which WORD of the output to store the data +// The expected usage is to call once with the normal and once with +// the tangent and binormal sign flag, bitwise OR'ing the returned DWORDs +FORCEINLINE unsigned int * PackNormal_UBYTE4( float nx, float ny, float nz, unsigned int *pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f ) +{ + float xSign = nx < 0.0f ? -1.0f : 1.0f; // -1 or 1 sign + float ySign = ny < 0.0f ? -1.0f : 1.0f; + float zSign = nz < 0.0f ? -1.0f : 1.0f; + float tSign = binormalSign; + Assert( ( binormalSign == +1.0f ) || ( binormalSign == -1.0f ) ); + + float xSignBit = 0.5f*( 1 - xSign ); // [-1,+1] -> [1,0] + float ySignBit = 0.5f*( 1 - ySign ); // 1 is negative bit (like slt instruction) + float zSignBit = 0.5f*( 1 - zSign ); + float tSignBit = 0.5f*( 1 - binormalSign ); + + float absX = xSign*nx; // 0..1 range (abs) + float absY = ySign*ny; + float absZ = zSign*nz; + + float xbits = absX / ( absX + absY + absZ ); // Project onto x+y+z=1 plane + float ybits = absY / ( absX + absY + absZ ); + + xbits *= 63; // 0..63 + ybits *= 63; + + xbits = xbits * xSign - xSignBit; // -64..63 range + ybits = ybits * ySign - ySignBit; + xbits += 64.0f; // 0..127 range + ybits += 64.0f; + + xbits = xbits * zSign - zSignBit; // Negate based on z and t + ybits = ybits * tSign - tSignBit; // -128..127 range + + xbits += 128.0f; // 0..255 range + ybits += 128.0f; + + unsigned char cX = (unsigned char) xbits; + unsigned char cY = (unsigned char) ybits; + + if ( !bIsTangent ) + *pPackedNormal = (cX << 0) | (cY << 8); // xy for normal + else + *pPackedNormal = (cX << 16) | (cY << 24); // zw for tangent + + return pPackedNormal; +} + +FORCEINLINE unsigned int * PackNormal_UBYTE4( const float *pNormal, unsigned int *pPackedNormal, bool bIsTangent = false, float binormalSign = +1.0f ) +{ + return PackNormal_UBYTE4( pNormal[0], pNormal[1], pNormal[2], pPackedNormal, bIsTangent, binormalSign ); +} + +FORCEINLINE void RGB2YUV( int &nR, int &nG, int &nB, float &fY, float &fU, float &fV, bool bApplySaturationCurve ) +{ + // YUV conversion: + // |Y| | 0.299f 0.587f 0.114f | |R| + // |U| = | -0.14713f -0.28886f 0.436f | x |G| + // |V| | 0.615f -0.51499f -0.10001f | |B| + // + // The coefficients in the first row sum to one, whereas the 2nd and 3rd rows each sum to zero (UV (0,0) means greyscale). + // Ranges are Y [0,1], U [-0.436,+0.436] and V [-0.615,+0.615]. + // We scale and offset to [0,1] and allow the caller to round as they please. + + fY = ( 0.29900f*nR + 0.58700f*nG + 0.11400f*nB ) / 255; + fU = ( -0.14713f*nR + -0.28886f*nG + 0.43600f*nB )*( 0.5f / 0.436f ) / 255 + 0.5f; + fV = ( 0.61500f*nR + -0.51499f*nG + -0.10001f*nB )*( 0.5f / 0.615f ) / 255 + 0.5f; + + if ( bApplySaturationCurve ) + { + // Apply a curve to saturation, and snap-to-grey for low saturations + const float SNAP_TO_GREY = 0;//0.0125f; Disabled, saturation curve seems sufficient + float dX, dY, sat, scale; + dX = 2*( fU - 0.5f ); + dY = 2*( fV - 0.5f ); + sat = sqrtf( dX*dX + dY*dY ); + sat = clamp( ( sat*( 1 + SNAP_TO_GREY ) - SNAP_TO_GREY ), 0, 1 ); + scale = ( sat == 0 ) ? 0 : MIN( ( sqrtf( sat ) / sat ), 4.0f ); + fU = 0.5f + scale*( fU - 0.5f ); + fV = 0.5f + scale*( fV - 0.5f ); + } +} + +#ifdef _X360 +// Used for direct CPU access to VB data on 360 (used by shaderapi, studiorender and engine) +struct VBCPU_AccessInfo_t +{ + // Points to the GPU data pointer in the CVertexBuffer struct (VB data can be relocated during level transitions) + const byte **ppBaseAddress; + // pBaseAddress should be computed from ppBaseAddress immediately before use + const byte *pBaseAddress; + int nStride; + int nPositionOffset; + int nTexCoord0_Offset; + int nNormalOffset; + int nBoneIndexOffset; + int nBoneWeightOffset; + int nCompressionType; + // TODO: if needed, add colour and tangents +}; +#endif + +//----------------------------------------------------------------------------- +// Convert RGB to HSV +//----------------------------------------------------------------------------- +void RGBtoHSV( const Vector &rgb, Vector &hsv ); + + +//----------------------------------------------------------------------------- +// Convert HSV to RGB +//----------------------------------------------------------------------------- +void HSVtoRGB( const Vector &hsv, Vector &rgb ); + + +//----------------------------------------------------------------------------- +// Fast version of pow and log +//----------------------------------------------------------------------------- +#ifndef _PS3 // these actually aren't fast (or correct) on the PS3 +float FastLog2(float i); // log2( i ) +float FastPow2(float i); // 2^i +float FastPow(float a, float b); // a^b +float FastPow10( float i ); // 10^i +#else +inline float FastLog2(float i) {return logbf(i);} // log2( i ) +inline float FastPow2(float i) {return exp2f(i);} // 2^i +inline float FastPow(float a, float b) {return powf(a,b);} // a^b +#define LOGBASE2OF10 3.3219280948873623478703194294893901758648313930 +inline float FastPow10( float i ) { return exp2f( i * LOGBASE2OF10 ); } // 10^i, transform to base two, so log2(10^y) = y log2(10) . log2(10) = 3.3219280948873623478703194294893901758648313930 +#endif + +//----------------------------------------------------------------------------- +// For testing float equality +//----------------------------------------------------------------------------- + +inline bool CloseEnough( float a, float b, float epsilon = EQUAL_EPSILON ) +{ + return fabs( a - b ) <= epsilon; +} + +inline bool CloseEnough( const Vector &a, const Vector &b, float epsilon = EQUAL_EPSILON ) +{ + return fabs( a.x - b.x ) <= epsilon && + fabs( a.y - b.y ) <= epsilon && + fabs( a.z - b.z ) <= epsilon; +} + +// Fast compare +// maxUlps is the maximum error in terms of Units in the Last Place. This +// specifies how big an error we are willing to accept in terms of the value +// of the least significant digit of the floating point number�s +// representation. maxUlps can also be interpreted in terms of how many +// representable floats we are willing to accept between A and B. +// This function will allow maxUlps-1 floats between A and B. +bool AlmostEqual(float a, float b, int maxUlps = 10); + +inline bool AlmostEqual( const Vector &a, const Vector &b, int maxUlps = 10) +{ + return AlmostEqual( a.x, b.x, maxUlps ) && + AlmostEqual( a.y, b.y, maxUlps ) && + AlmostEqual( a.z, b.z, maxUlps ); +} + +inline float Approach( float target, float value, float speed ) +{ + float delta = target - value; + +#if defined(_X360) || defined( _PS3 ) // use conditional move for speed on 360 + + return fsel( delta-speed, // delta >= speed ? + value + speed, // if delta == speed, then value + speed == value + delta == target + fsel( (-speed) - delta, // delta <= -speed + value - speed, + target ) + ); // delta < speed && delta > -speed + +#else + + if ( delta > speed ) + value += speed; + else if ( delta < -speed ) + value -= speed; + else + value = target; + + return value; + +#endif +} + +// on PPC we can do this truncate without converting to int +#if defined(_X360) || defined(_PS3) +inline double TruncateFloatToIntAsFloat( double flVal ) +{ +#if defined(_X360) + double flIntFormat = __fctiwz( flVal ); + return __fcfid( flIntFormat ); +#elif defined(_PS3) + double flIntFormat = __builtin_fctiwz( flVal ); + return __builtin_fcfid( flIntFormat ); +#endif +} +#endif + +inline double SubtractIntegerPart( double flVal ) +{ +#if defined(_X360) || defined(_PS3) + return flVal - TruncateFloatToIntAsFloat(flVal); +#else + return flVal - int(flVal); +#endif +} +#endif // MATH_BASE_H + diff --git a/external/vpc/public/mathlib/vector.h b/external/vpc/public/mathlib/vector.h new file mode 100644 index 0000000..dac51a4 --- /dev/null +++ b/external/vpc/public/mathlib/vector.h @@ -0,0 +1,2633 @@ +//====== Copyright 1996-2005, Valve Corporation, All rights reserved. =======// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef VECTOR_H +#define VECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include <math.h> +#include <float.h> + +// For vec_t, put this somewhere else? +#include "tier0/basetypes.h" + +#if defined( _PS3 ) +//#include <ssemath.h> +#include <vectormath/c/vectormath_aos.h> +#include "platform.h" +#include "mathlib/math_pfns.h" +#endif + +#ifndef PLATFORM_PPC // we want our linux with xmm support +// For MMX intrinsics +#include <xmmintrin.h> +#endif + +#ifndef ALIGN16_POST +#define ALIGN16_POST +#endif + +#include "tier0/dbg.h" +#include "tier0/platform.h" +#include "tier0/threadtools.h" +#include "mathlib/vector2d.h" +#include "mathlib/math_pfns.h" +#include "tier0/memalloc.h" +#include "vstdlib/random.h" +// Uncomment this to add extra Asserts to check for NANs, uninitialized vecs, etc. +//#define VECTOR_PARANOIA 1 + +// Uncomment this to make sure we don't do anything slow with our vectors +//#define VECTOR_NO_SLOW_OPERATIONS 1 + + +// Used to make certain code easier to read. +#define X_INDEX 0 +#define Y_INDEX 1 +#define Z_INDEX 2 + + +#ifdef VECTOR_PARANOIA +#define CHECK_VALID( _v) Assert( (_v).IsValid() ) +#else +#ifdef GNUC +#define CHECK_VALID( _v) +#else +#define CHECK_VALID( _v) 0 +#endif +#endif + +#define VecToString(v) (static_cast<const char *>(CFmtStr("(%f, %f, %f)", (v).x, (v).y, (v).z))) // ** Note: this generates a temporary, don't hold reference! + +class VectorByValue; + +//========================================================= +// 3D Vector +//========================================================= +class Vector +{ +public: + // Members + vec_t x, y, z; + + // Construction/destruction: + Vector(void); + Vector(vec_t X, vec_t Y, vec_t Z); + + // Initialization + void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f); + // TODO (Ilya): Should there be an init that takes a single float for consistency? + + // Got any nasty NAN's? + bool IsValid() const; + void Invalidate(); + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + // Base address... + vec_t* Base(); + vec_t const* Base() const; + + // Cast to Vector2D... + Vector2D& AsVector2D(); + const Vector2D& AsVector2D() const; + + // Initialization methods + void Random( vec_t minVal, vec_t maxVal ); + inline void Zero(); ///< zero out a vector + + // equality + bool operator==(const Vector& v) const; + bool operator!=(const Vector& v) const; + + // arithmetic operations + FORCEINLINE Vector& operator+=(const Vector &v); + FORCEINLINE Vector& operator-=(const Vector &v); + FORCEINLINE Vector& operator*=(const Vector &v); + FORCEINLINE Vector& operator*=(float s); + FORCEINLINE Vector& operator/=(const Vector &v); + FORCEINLINE Vector& operator/=(float s); + FORCEINLINE Vector& operator+=(float fl) ; ///< broadcast add + FORCEINLINE Vector& operator-=(float fl) ; ///< broadcast sub + +// negate the vector components + void Negate(); + + // Get the vector's magnitude. + inline vec_t Length() const; + + // Get the vector's magnitude squared. + FORCEINLINE vec_t LengthSqr(void) const + { + CHECK_VALID(*this); + return (x*x + y*y + z*z); + } + + // Get one over the vector's length + // via fast hardware approximation + inline vec_t LengthRecipFast(void) const + { + return FastRSqrtFast( LengthSqr() ); + } + + // return true if this vector is (0,0,0) within tolerance + bool IsZero( float tolerance = 0.01f ) const + { + return (x > -tolerance && x < tolerance && + y > -tolerance && y < tolerance && + z > -tolerance && z < tolerance); + } + + + // return true if this vector is exactly (0,0,0) -- only fast if vector is coming from memory, not registers + inline bool IsZeroFast( ) const RESTRICT + { + COMPILE_TIME_ASSERT( sizeof(vec_t) == sizeof(int) ); + return ( *(const int *)(&x) == 0 && + *(const int *)(&y) == 0 && + *(const int *)(&z) == 0 ); + } + + vec_t NormalizeInPlace(); + Vector Normalized() const; + bool IsLengthGreaterThan( float val ) const; + bool IsLengthLessThan( float val ) const; + + // check if a vector is within the box defined by two other vectors + FORCEINLINE bool WithinAABox( Vector const &boxmin, Vector const &boxmax); + + // Get the distance from this vector to the other one. + vec_t DistTo(const Vector &vOther) const; + + // Get the distance from this vector to the other one squared. + // NJS: note, VC wasn't inlining it correctly in several deeply nested inlines due to being an 'out of line' inline. + // may be able to tidy this up after switching to VC7 + FORCEINLINE vec_t DistToSqr(const Vector &vOther) const + { + Vector delta; + + delta.x = x - vOther.x; + delta.y = y - vOther.y; + delta.z = z - vOther.z; + + return delta.LengthSqr(); + } + + // Copy + void CopyToArray(float* rgfl) const; + + // Multiply, add, and assign to this (ie: *this = a + b * scalar). This + // is about 12% faster than the actual vector equation (because it's done per-component + // rather than per-vector). + void MulAdd(const Vector& a, const Vector& b, float scalar); + + // Dot product. + vec_t Dot(const Vector& vOther) const; + + // assignment + Vector& operator=(const Vector &vOther); + + // returns 0, 1, 2 corresponding to the component with the largest absolute value + inline int LargestComponent() const; + + // 2d + vec_t Length2D(void) const; + vec_t Length2DSqr(void) const; + + /// get the component of this vector parallel to some other given vector + inline Vector ProjectOnto( const Vector& onto ); + + operator VectorByValue &() { return *((VectorByValue *)(this)); } + operator const VectorByValue &() const { return *((const VectorByValue *)(this)); } + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // copy constructors +// Vector(const Vector &vOther); + + // arithmetic operations + Vector operator-(void) const; + + Vector operator+(const Vector& v) const; + Vector operator-(const Vector& v) const; + Vector operator*(const Vector& v) const; + Vector operator/(const Vector& v) const; + Vector operator*(float fl) const; + Vector operator/(float fl) const; + + // Cross product between two vectors. + Vector Cross(const Vector &vOther) const; + + // Returns a vector with the min or max in X, Y, and Z. + Vector Min(const Vector &vOther) const; + Vector Max(const Vector &vOther) const; + +#else + +private: + // No copy constructors allowed if we're in optimal mode + Vector(const Vector& vOther); +#endif +}; + + + +#define USE_M64S defined( PLATFORM_WINDOWS_PC ) + + + +//========================================================= +// 4D Short Vector (aligned on 8-byte boundary) +//========================================================= +class ALIGN8 ShortVector +{ +public: + + short x, y, z, w; + + // Initialization + void Init(short ix = 0, short iy = 0, short iz = 0, short iw = 0 ); + + +#if USE_M64S + __m64 &AsM64() { return *(__m64*)&x; } + const __m64 &AsM64() const { return *(const __m64*)&x; } +#endif + + // Setter + void Set( const ShortVector& vOther ); + void Set( const short ix, const short iy, const short iz, const short iw ); + + // array access... + short operator[](int i) const; + short& operator[](int i); + + // Base address... + short* Base(); + short const* Base() const; + + // equality + bool operator==(const ShortVector& v) const; + bool operator!=(const ShortVector& v) const; + + // Arithmetic operations + FORCEINLINE ShortVector& operator+=(const ShortVector &v); + FORCEINLINE ShortVector& operator-=(const ShortVector &v); + FORCEINLINE ShortVector& operator*=(const ShortVector &v); + FORCEINLINE ShortVector& operator*=(float s); + FORCEINLINE ShortVector& operator/=(const ShortVector &v); + FORCEINLINE ShortVector& operator/=(float s); + FORCEINLINE ShortVector operator*(float fl) const; + +private: + + // No copy constructors allowed if we're in optimal mode +// ShortVector(ShortVector const& vOther); + + // No assignment operators either... +// ShortVector& operator=( ShortVector const& src ); + +} ALIGN8_POST; + + + + + + +//========================================================= +// 4D Integer Vector +//========================================================= +class IntVector4D +{ +public: + + int x, y, z, w; + + // Initialization + void Init(int ix = 0, int iy = 0, int iz = 0, int iw = 0 ); + +#if USE_M64S + __m64 &AsM64() { return *(__m64*)&x; } + const __m64 &AsM64() const { return *(const __m64*)&x; } +#endif + + // Setter + void Set( const IntVector4D& vOther ); + void Set( const int ix, const int iy, const int iz, const int iw ); + + // array access... + int operator[](int i) const; + int& operator[](int i); + + // Base address... + int* Base(); + int const* Base() const; + + // equality + bool operator==(const IntVector4D& v) const; + bool operator!=(const IntVector4D& v) const; + + // Arithmetic operations + FORCEINLINE IntVector4D& operator+=(const IntVector4D &v); + FORCEINLINE IntVector4D& operator-=(const IntVector4D &v); + FORCEINLINE IntVector4D& operator*=(const IntVector4D &v); + FORCEINLINE IntVector4D& operator*=(float s); + FORCEINLINE IntVector4D& operator/=(const IntVector4D &v); + FORCEINLINE IntVector4D& operator/=(float s); + FORCEINLINE IntVector4D operator*(float fl) const; + +private: + + // No copy constructors allowed if we're in optimal mode + // IntVector4D(IntVector4D const& vOther); + + // No assignment operators either... + // IntVector4D& operator=( IntVector4D const& src ); + +}; + + + +//----------------------------------------------------------------------------- +// Allows us to specifically pass the vector by value when we need to +//----------------------------------------------------------------------------- +class VectorByValue : public Vector +{ +public: + // Construction/destruction: + VectorByValue(void) : Vector() {} + VectorByValue(vec_t X, vec_t Y, vec_t Z) : Vector( X, Y, Z ) {} + VectorByValue(const VectorByValue& vOther) { *this = vOther; } +}; + + +//----------------------------------------------------------------------------- +// Utility to simplify table construction. No constructor means can use +// traditional C-style initialization +//----------------------------------------------------------------------------- +class TableVector +{ +public: + vec_t x, y, z; + + operator Vector &() { return *((Vector *)(this)); } + operator const Vector &() const { return *((const Vector *)(this)); } + + // array access... + inline vec_t& operator[](int i) + { + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; + } + + inline vec_t operator[](int i) const + { + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; + } +}; + + +//----------------------------------------------------------------------------- +// Here's where we add all those lovely SSE optimized routines +//----------------------------------------------------------------------------- + +class ALIGN16 VectorAligned : public Vector +{ +public: + inline VectorAligned(void) {}; + inline VectorAligned(vec_t X, vec_t Y, vec_t Z) + { + Init(X,Y,Z); + } + +#ifdef VECTOR_NO_SLOW_OPERATIONS + +private: + // No copy constructors allowed if we're in optimal mode + VectorAligned(const VectorAligned& vOther); + VectorAligned(const Vector &vOther); + +#else +public: + explicit VectorAligned(const Vector &vOther) + { + Init(vOther.x, vOther.y, vOther.z); + } + + VectorAligned& operator=(const Vector &vOther) + { + Init(vOther.x, vOther.y, vOther.z); + return *this; + } + + VectorAligned& operator=(const VectorAligned &vOther) + { + // we know we're aligned, so use simd + // we can't use the convenient abstract interface coz it gets declared later +#ifdef _X360 + XMStoreVector4A(Base(), XMLoadVector4A(vOther.Base())); +#elif _WIN32 + _mm_store_ps(Base(), _mm_load_ps( vOther.Base() )); +#else + Init(vOther.x, vOther.y, vOther.z); +#endif + return *this; + } + + +#endif + float w; // this space is used anyway + +#if !defined(NO_MALLOC_OVERRIDE) + void* operator new[] ( size_t nSize) + { + return MemAlloc_AllocAligned(nSize, 16); + } + + void* operator new[] ( size_t nSize, const char *pFileName, int nLine) + { + return MemAlloc_AllocAlignedFileLine(nSize, 16, pFileName, nLine); + } + + void* operator new[] ( size_t nSize, int /*nBlockUse*/, const char *pFileName, int nLine) + { + return MemAlloc_AllocAlignedFileLine(nSize, 16, pFileName, nLine); + } + + void operator delete[] ( void* p) + { + MemAlloc_FreeAligned(p); + } + + void operator delete[] ( void* p, const char *pFileName, int nLine) + { + MemAlloc_FreeAligned(p, pFileName, nLine); + } + + void operator delete[] ( void* p, int /*nBlockUse*/, const char *pFileName, int nLine) + { + MemAlloc_FreeAligned(p, pFileName, nLine); + } + + // please don't allocate a single quaternion... + void* operator new ( size_t nSize ) + { + return MemAlloc_AllocAligned(nSize, 16); + } + void* operator new ( size_t nSize, const char *pFileName, int nLine ) + { + return MemAlloc_AllocAlignedFileLine(nSize, 16, pFileName, nLine); + } + void* operator new ( size_t nSize, int /*nBlockUse*/, const char *pFileName, int nLine ) + { + return MemAlloc_AllocAlignedFileLine(nSize, 16, pFileName, nLine); + } + void operator delete ( void* p) + { + MemAlloc_FreeAligned(p); + } + + void operator delete ( void* p, const char *pFileName, int nLine) + { + MemAlloc_FreeAligned(p, pFileName, nLine); + } + + void operator delete ( void* p, int /*nBlockUse*/, const char *pFileName, int nLine) + { + MemAlloc_FreeAligned(p, pFileName, nLine); + } +#endif +} ALIGN16_POST; + +//----------------------------------------------------------------------------- +// Vector related operations +//----------------------------------------------------------------------------- + +// Vector clear +FORCEINLINE void VectorClear( Vector& a ); + +// Copy +FORCEINLINE void VectorCopy( const Vector& src, Vector& dst ); + +// Vector arithmetic +FORCEINLINE void VectorAdd( const Vector& a, const Vector& b, Vector& result ); +FORCEINLINE void VectorSubtract( const Vector& a, const Vector& b, Vector& result ); +FORCEINLINE void VectorMultiply( const Vector& a, vec_t b, Vector& result ); +FORCEINLINE void VectorMultiply( const Vector& a, const Vector& b, Vector& result ); +FORCEINLINE void VectorDivide( const Vector& a, vec_t b, Vector& result ); +FORCEINLINE void VectorDivide( const Vector& a, const Vector& b, Vector& result ); +inline void VectorScale ( const Vector& in, vec_t scale, Vector& result ); +void VectorMA( const Vector& start, float scale, const Vector& direction, Vector& dest ); + +// Vector equality with tolerance +bool VectorsAreEqual( const Vector& src1, const Vector& src2, float tolerance = 0.0f ); + +#define VectorExpand(v) (v).x, (v).y, (v).z + + +// Normalization +// FIXME: Can't use quite yet +//vec_t VectorNormalize( Vector& v ); + +// Length +inline vec_t VectorLength( const Vector& v ); + +// Dot Product +FORCEINLINE vec_t DotProduct(const Vector& a, const Vector& b); + +// Cross product +void CrossProduct(const Vector& a, const Vector& b, Vector& result ); + +// Store the min or max of each of x, y, and z into the result. +void VectorMin( const Vector &a, const Vector &b, Vector &result ); +void VectorMax( const Vector &a, const Vector &b, Vector &result ); + +// Linearly interpolate between two vectors +void VectorLerp(const Vector& src1, const Vector& src2, vec_t t, Vector& dest ); +Vector VectorLerp(const Vector& src1, const Vector& src2, vec_t t ); + +FORCEINLINE Vector ReplicateToVector( float x ) +{ + return Vector( x, x, x ); +} + +FORCEINLINE bool PointWithinViewAngle( Vector const &vecSrcPosition, + Vector const &vecTargetPosition, + Vector const &vecLookDirection, float flCosHalfFOV ) +{ + Vector vecDelta = vecTargetPosition - vecSrcPosition; + float cosDiff = DotProduct( vecLookDirection, vecDelta ); + + if ( flCosHalfFOV <= 0 ) // >180 + { + // signs are different, answer is implicit + if ( cosDiff > 0 ) + return true; + + // a/sqrt(b) > c == a^2 < b * c ^2 + // IFF left and right sides are <= 0 + float flLen2 = vecDelta.LengthSqr(); + return ( cosDiff * cosDiff <= flLen2 * flCosHalfFOV * flCosHalfFOV ); + } + else // flCosHalfFOV > 0 + { + // signs are different, answer is implicit + if ( cosDiff < 0 ) + return false; + + // a/sqrt(b) > c == a^2 > b * c ^2 + // IFF left and right sides are >= 0 + float flLen2 = vecDelta.LengthSqr(); + return ( cosDiff * cosDiff >= flLen2 * flCosHalfFOV * flCosHalfFOV ); + } +} + + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +// Cross product +Vector CrossProduct( const Vector& a, const Vector& b ); + +// Random vector creation +Vector RandomVector( vec_t minVal, vec_t maxVal ); + +#endif + +float RandomVectorInUnitSphere( Vector *pVector ); +float RandomVectorInUnitCircle( Vector2D *pVector ); + + +//----------------------------------------------------------------------------- +// +// Inlined Vector methods +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// constructors +//----------------------------------------------------------------------------- +inline Vector::Vector(void) +{ +#ifdef _DEBUG +#ifdef VECTOR_PARANOIA + // Initialize to NAN to catch errors + x = y = z = VEC_T_NAN; +#endif +#endif +} + +inline Vector::Vector(vec_t X, vec_t Y, vec_t Z) +{ + x = X; y = Y; z = Z; + CHECK_VALID(*this); +} + +//inline Vector::Vector(const float *pFloat) +//{ +// Assert( pFloat ); +// x = pFloat[0]; y = pFloat[1]; z = pFloat[2]; +// CHECK_VALID(*this); +//} + +#if 0 +//----------------------------------------------------------------------------- +// copy constructor +//----------------------------------------------------------------------------- + +inline Vector::Vector(const Vector &vOther) +{ + CHECK_VALID(vOther); + x = vOther.x; y = vOther.y; z = vOther.z; +} +#endif + +//----------------------------------------------------------------------------- +// initialization +//----------------------------------------------------------------------------- + +inline void Vector::Init( vec_t ix, vec_t iy, vec_t iz ) +{ + x = ix; y = iy; z = iz; + CHECK_VALID(*this); +} + +inline void Vector::Random( vec_t minVal, vec_t maxVal ) +{ + x = RandomFloat( minVal, maxVal ); + y = RandomFloat( minVal, maxVal ); + z = RandomFloat( minVal, maxVal ); + CHECK_VALID(*this); +} + +// This should really be a single opcode on the PowerPC (move r0 onto the vec reg) +inline void Vector::Zero() +{ + x = y = z = 0.0f; +} + +inline void VectorClear( Vector& a ) +{ + a.x = a.y = a.z = 0.0f; +} + +//----------------------------------------------------------------------------- +// assignment +//----------------------------------------------------------------------------- + +inline Vector& Vector::operator=(const Vector &vOther) +{ + CHECK_VALID(vOther); + x=vOther.x; y=vOther.y; z=vOther.z; + return *this; +} + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline vec_t& Vector::operator[](int i) +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + +inline vec_t Vector::operator[](int i) const +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- +inline vec_t* Vector::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* Vector::Base() const +{ + return (vec_t const*)this; +} + +//----------------------------------------------------------------------------- +// Cast to Vector2D... +//----------------------------------------------------------------------------- + +inline Vector2D& Vector::AsVector2D() +{ + return *(Vector2D*)this; +} + +inline const Vector2D& Vector::AsVector2D() const +{ + return *(const Vector2D*)this; +} + +//----------------------------------------------------------------------------- +// IsValid? +//----------------------------------------------------------------------------- + +inline bool Vector::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z); +} + +//----------------------------------------------------------------------------- +// Invalidate +//----------------------------------------------------------------------------- + +inline void Vector::Invalidate() +{ +//#ifdef _DEBUG +//#ifdef VECTOR_PARANOIA + x = y = z = VEC_T_NAN; +//#endif +//#endif +} + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- + +inline bool Vector::operator==( const Vector& src ) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x == x) && (src.y == y) && (src.z == z); +} + +inline bool Vector::operator!=( const Vector& src ) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x != x) || (src.y != y) || (src.z != z); +} + + +//----------------------------------------------------------------------------- +// Copy +//----------------------------------------------------------------------------- + +FORCEINLINE void VectorCopy( const Vector& src, Vector& dst ) +{ + CHECK_VALID(src); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +inline void Vector::CopyToArray(float* rgfl) const +{ + Assert( rgfl ); + CHECK_VALID(*this); + rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; +} + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- +// #pragma message("TODO: these should be SSE") + +inline void Vector::Negate() +{ + CHECK_VALID(*this); + x = -x; y = -y; z = -z; +} + +FORCEINLINE Vector& Vector::operator+=(const Vector& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x+=v.x; y+=v.y; z += v.z; + return *this; +} + +FORCEINLINE Vector& Vector::operator-=(const Vector& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x-=v.x; y-=v.y; z -= v.z; + return *this; +} + +FORCEINLINE Vector& Vector::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + CHECK_VALID(*this); + return *this; +} + +FORCEINLINE Vector& Vector::operator*=(const Vector& v) +{ + CHECK_VALID(v); + x *= v.x; + y *= v.y; + z *= v.z; + CHECK_VALID(*this); + return *this; +} + +// this ought to be an opcode. +FORCEINLINE Vector& Vector::operator+=(float fl) +{ + x += fl; + y += fl; + z += fl; + CHECK_VALID(*this); + return *this; +} + +FORCEINLINE Vector& Vector::operator-=(float fl) +{ + x -= fl; + y -= fl; + z -= fl; + CHECK_VALID(*this); + return *this; +} + + + +FORCEINLINE Vector& Vector::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + CHECK_VALID(*this); + return *this; +} + +FORCEINLINE Vector& Vector::operator/=(const Vector& v) +{ + CHECK_VALID(v); + Assert( v.x != 0.0f && v.y != 0.0f && v.z != 0.0f ); + x /= v.x; + y /= v.y; + z /= v.z; + CHECK_VALID(*this); + return *this; +} + + +// get the component of this vector parallel to some other given vector +inline Vector Vector::ProjectOnto( const Vector& onto ) +{ + return onto * ( this->Dot(onto) / ( onto.LengthSqr() ) ); +} + + +//----------------------------------------------------------------------------- +// +// Inlined Short Vector methods +// +//----------------------------------------------------------------------------- + + +inline void ShortVector::Init( short ix, short iy, short iz, short iw ) +{ + x = ix; y = iy; z = iz; w = iw; +} + +FORCEINLINE void ShortVector::Set( const ShortVector& vOther ) +{ + x = vOther.x; + y = vOther.y; + z = vOther.z; + w = vOther.w; +} + +FORCEINLINE void ShortVector::Set( const short ix, const short iy, const short iz, const short iw ) +{ + x = ix; + y = iy; + z = iz; + w = iw; +} + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline short ShortVector::operator[](int i) const +{ + Assert( (i >= 0) && (i < 4) ); + return ((short*)this)[i]; +} + +inline short& ShortVector::operator[](int i) +{ + Assert( (i >= 0) && (i < 4) ); + return ((short*)this)[i]; +} + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- +inline short* ShortVector::Base() +{ + return (short*)this; +} + +inline short const* ShortVector::Base() const +{ + return (short const*)this; +} + + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- + +inline bool ShortVector::operator==( const ShortVector& src ) const +{ + return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w); +} + +inline bool ShortVector::operator!=( const ShortVector& src ) const +{ + return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w); +} + + + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- + +FORCEINLINE ShortVector& ShortVector::operator+=(const ShortVector& v) +{ + x+=v.x; y+=v.y; z += v.z; w += v.w; + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator-=(const ShortVector& v) +{ + x-=v.x; y-=v.y; z -= v.z; w -= v.w; + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator*=(float fl) +{ + x = (short)(x * fl); + y = (short)(y * fl); + z = (short)(z * fl); + w = (short)(w * fl); + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator*=(const ShortVector& v) +{ + x = (short)(x * v.x); + y = (short)(y * v.y); + z = (short)(z * v.z); + w = (short)(w * v.w); + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x = (short)(x * oofl); + y = (short)(y * oofl); + z = (short)(z * oofl); + w = (short)(w * oofl); + return *this; +} + +FORCEINLINE ShortVector& ShortVector::operator/=(const ShortVector& v) +{ + Assert( v.x != 0 && v.y != 0 && v.z != 0 && v.w != 0 ); + x = (short)(x / v.x); + y = (short)(y / v.y); + z = (short)(z / v.z); + w = (short)(w / v.w); + return *this; +} + +FORCEINLINE void ShortVectorMultiply( const ShortVector& src, float fl, ShortVector& res ) +{ + Assert( IsFinite(fl) ); + res.x = (short)(src.x * fl); + res.y = (short)(src.y * fl); + res.z = (short)(src.z * fl); + res.w = (short)(src.w * fl); +} + +FORCEINLINE ShortVector ShortVector::operator*(float fl) const +{ + ShortVector res; + ShortVectorMultiply( *this, fl, res ); + return res; +} + + + + + + +//----------------------------------------------------------------------------- +// +// Inlined Integer Vector methods +// +//----------------------------------------------------------------------------- + + +inline void IntVector4D::Init( int ix, int iy, int iz, int iw ) +{ + x = ix; y = iy; z = iz; w = iw; +} + +FORCEINLINE void IntVector4D::Set( const IntVector4D& vOther ) +{ + x = vOther.x; + y = vOther.y; + z = vOther.z; + w = vOther.w; +} + +FORCEINLINE void IntVector4D::Set( const int ix, const int iy, const int iz, const int iw ) +{ + x = ix; + y = iy; + z = iz; + w = iw; +} + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline int IntVector4D::operator[](int i) const +{ + Assert( (i >= 0) && (i < 4) ); + return ((int*)this)[i]; +} + +inline int& IntVector4D::operator[](int i) +{ + Assert( (i >= 0) && (i < 4) ); + return ((int*)this)[i]; +} + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- +inline int* IntVector4D::Base() +{ + return (int*)this; +} + +inline int const* IntVector4D::Base() const +{ + return (int const*)this; +} + + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- + +inline bool IntVector4D::operator==( const IntVector4D& src ) const +{ + return (src.x == x) && (src.y == y) && (src.z == z) && (src.w == w); +} + +inline bool IntVector4D::operator!=( const IntVector4D& src ) const +{ + return (src.x != x) || (src.y != y) || (src.z != z) || (src.w != w); +} + + + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- + +FORCEINLINE IntVector4D& IntVector4D::operator+=(const IntVector4D& v) +{ + x+=v.x; y+=v.y; z += v.z; w += v.w; + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator-=(const IntVector4D& v) +{ + x-=v.x; y-=v.y; z -= v.z; w -= v.w; + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator*=(float fl) +{ + x = (int)(x * fl); + y = (int)(y * fl); + z = (int)(z * fl); + w = (int)(w * fl); + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator*=(const IntVector4D& v) +{ + x = (int)(x * v.x); + y = (int)(y * v.y); + z = (int)(z * v.z); + w = (int)(w * v.w); + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x = (int)(x * oofl); + y = (int)(y * oofl); + z = (int)(z * oofl); + w = (int)(w * oofl); + return *this; +} + +FORCEINLINE IntVector4D& IntVector4D::operator/=(const IntVector4D& v) +{ + Assert( v.x != 0 && v.y != 0 && v.z != 0 && v.w != 0 ); + x = (int)(x / v.x); + y = (int)(y / v.y); + z = (int)(z / v.z); + w = (int)(w / v.w); + return *this; +} + +FORCEINLINE void IntVector4DMultiply( const IntVector4D& src, float fl, IntVector4D& res ) +{ + Assert( IsFinite(fl) ); + res.x = (int)(src.x * fl); + res.y = (int)(src.y * fl); + res.z = (int)(src.z * fl); + res.w = (int)(src.w * fl); +} + +FORCEINLINE IntVector4D IntVector4D::operator*(float fl) const +{ + IntVector4D res; + IntVector4DMultiply( *this, fl, res ); + return res; +} + + + +// ======================= + + +FORCEINLINE void VectorAdd( const Vector& a, const Vector& b, Vector& c ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + c.x = a.x + b.x; + c.y = a.y + b.y; + c.z = a.z + b.z; +} + +FORCEINLINE void VectorSubtract( const Vector& a, const Vector& b, Vector& c ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + c.x = a.x - b.x; + c.y = a.y - b.y; + c.z = a.z - b.z; +} + +FORCEINLINE void VectorMultiply( const Vector& a, vec_t b, Vector& c ) +{ + CHECK_VALID(a); + Assert( IsFinite(b) ); + c.x = a.x * b; + c.y = a.y * b; + c.z = a.z * b; +} + +FORCEINLINE void VectorMultiply( const Vector& a, const Vector& b, Vector& c ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + c.x = a.x * b.x; + c.y = a.y * b.y; + c.z = a.z * b.z; +} + +// for backwards compatability +inline void VectorScale ( const Vector& in, vec_t scale, Vector& result ) +{ + VectorMultiply( in, scale, result ); +} + + +FORCEINLINE void VectorDivide( const Vector& a, vec_t b, Vector& c ) +{ + CHECK_VALID(a); + Assert( b != 0.0f ); + vec_t oob = 1.0f / b; + c.x = a.x * oob; + c.y = a.y * oob; + c.z = a.z * oob; +} + +FORCEINLINE void VectorDivide( const Vector& a, const Vector& b, Vector& c ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + Assert( (b.x != 0.0f) && (b.y != 0.0f) && (b.z != 0.0f) ); + c.x = a.x / b.x; + c.y = a.y / b.y; + c.z = a.z / b.z; +} + +// FIXME: Remove +// For backwards compatability +inline void Vector::MulAdd(const Vector& a, const Vector& b, float scalar) +{ + CHECK_VALID(a); + CHECK_VALID(b); + x = a.x + b.x * scalar; + y = a.y + b.y * scalar; + z = a.z + b.z * scalar; +} + +inline void VectorLerp(const Vector& src1, const Vector& src2, vec_t t, Vector& dest ) +{ + CHECK_VALID(src1); + CHECK_VALID(src2); + dest.x = src1.x + (src2.x - src1.x) * t; + dest.y = src1.y + (src2.y - src1.y) * t; + dest.z = src1.z + (src2.z - src1.z) * t; +} + +inline Vector VectorLerp(const Vector& src1, const Vector& src2, vec_t t ) +{ + Vector result; + VectorLerp( src1, src2, t, result ); + return result; +} + +//----------------------------------------------------------------------------- +// Temporary storage for vector results so const Vector& results can be returned +//----------------------------------------------------------------------------- +inline Vector &AllocTempVector() +{ + static Vector s_vecTemp[128]; + static CInterlockedInt s_nIndex; + + int nIndex; + for (;;) + { + int nOldIndex = s_nIndex; + nIndex = ( (nOldIndex + 0x10001) & 0x7F ); + + if ( s_nIndex.AssignIf( nOldIndex, nIndex ) ) + { + break; + } + ThreadPause(); + } + return s_vecTemp[nIndex & 0xffff]; +} + + + +//----------------------------------------------------------------------------- +// dot, cross +//----------------------------------------------------------------------------- +FORCEINLINE vec_t DotProduct(const Vector& a, const Vector& b) +{ + CHECK_VALID(a); + CHECK_VALID(b); + return( a.x*b.x + a.y*b.y + a.z*b.z ); +} + +// for backwards compatability +inline vec_t Vector::Dot( const Vector& vOther ) const +{ + CHECK_VALID(vOther); + return DotProduct( *this, vOther ); +} + +inline int Vector::LargestComponent() const +{ + float flAbsx = fabs(x); + float flAbsy = fabs(y); + float flAbsz = fabs(z); + if ( flAbsx > flAbsy ) + { + if ( flAbsx > flAbsz ) + return X_INDEX; + return Z_INDEX; + } + if ( flAbsy > flAbsz ) + return Y_INDEX; + return Z_INDEX; +} + +inline void CrossProduct(const Vector& a, const Vector& b, Vector& result ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + Assert( &a != &result ); + Assert( &b != &result ); + result.x = a.y*b.z - a.z*b.y; + result.y = a.z*b.x - a.x*b.z; + result.z = a.x*b.y - a.y*b.x; +} + +inline vec_t DotProductAbs( const Vector &v0, const Vector &v1 ) +{ + CHECK_VALID(v0); + CHECK_VALID(v1); + return FloatMakePositive(v0.x*v1.x) + FloatMakePositive(v0.y*v1.y) + FloatMakePositive(v0.z*v1.z); +} + +inline vec_t DotProductAbs( const Vector &v0, const float *v1 ) +{ + return FloatMakePositive(v0.x * v1[0]) + FloatMakePositive(v0.y * v1[1]) + FloatMakePositive(v0.z * v1[2]); +} + +//----------------------------------------------------------------------------- +// length +//----------------------------------------------------------------------------- + +inline vec_t VectorLength( const Vector& v ) +{ + CHECK_VALID(v); + return (vec_t)FastSqrt(v.x*v.x + v.y*v.y + v.z*v.z); +} + + +inline vec_t Vector::Length(void) const +{ + CHECK_VALID(*this); + return VectorLength( *this ); +} + + +//----------------------------------------------------------------------------- +// Normalization +//----------------------------------------------------------------------------- + +/* +// FIXME: Can't use until we're un-macroed in mathlib.h +inline vec_t VectorNormalize( Vector& v ) +{ + Assert( v.IsValid() ); + vec_t l = v.Length(); + if (l != 0.0f) + { + v /= l; + } + else + { + // FIXME: + // Just copying the existing implemenation; shouldn't res.z == 0? + v.x = v.y = 0.0f; v.z = 1.0f; + } + return l; +} +*/ + + +// check a point against a box +bool Vector::WithinAABox( Vector const &boxmin, Vector const &boxmax) +{ + return ( + ( x >= boxmin.x ) && ( x <= boxmax.x) && + ( y >= boxmin.y ) && ( y <= boxmax.y) && + ( z >= boxmin.z ) && ( z <= boxmax.z) + ); +} + +//----------------------------------------------------------------------------- +// Get the distance from this vector to the other one +//----------------------------------------------------------------------------- +inline vec_t Vector::DistTo(const Vector &vOther) const +{ + Vector delta; + VectorSubtract( *this, vOther, delta ); + return delta.Length(); +} + + +//----------------------------------------------------------------------------- +// Vector equality with tolerance +//----------------------------------------------------------------------------- +inline bool VectorsAreEqual( const Vector& src1, const Vector& src2, float tolerance ) +{ + if (FloatMakePositive(src1.x - src2.x) > tolerance) + return false; + if (FloatMakePositive(src1.y - src2.y) > tolerance) + return false; + return (FloatMakePositive(src1.z - src2.z) <= tolerance); +} + + +//----------------------------------------------------------------------------- +// Computes the closest point to vecTarget no farther than flMaxDist from vecStart +//----------------------------------------------------------------------------- +inline void ComputeClosestPoint( const Vector& vecStart, float flMaxDist, const Vector& vecTarget, Vector *pResult ) +{ + Vector vecDelta; + VectorSubtract( vecTarget, vecStart, vecDelta ); + float flDistSqr = vecDelta.LengthSqr(); + if ( flDistSqr <= flMaxDist * flMaxDist ) + { + *pResult = vecTarget; + } + else + { + vecDelta /= FastSqrt( flDistSqr ); + VectorMA( vecStart, flMaxDist, vecDelta, *pResult ); + } +} + + +//----------------------------------------------------------------------------- +// Takes the absolute value of a vector +//----------------------------------------------------------------------------- +inline void VectorAbs( const Vector& src, Vector& dst ) +{ + dst.x = FloatMakePositive(src.x); + dst.y = FloatMakePositive(src.y); + dst.z = FloatMakePositive(src.z); +} + + +//----------------------------------------------------------------------------- +// +// Slow methods +// +//----------------------------------------------------------------------------- + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +//----------------------------------------------------------------------------- +// Returns a vector with the min or max in X, Y, and Z. +//----------------------------------------------------------------------------- +inline Vector Vector::Min(const Vector &vOther) const +{ + return Vector(x < vOther.x ? x : vOther.x, + y < vOther.y ? y : vOther.y, + z < vOther.z ? z : vOther.z); +} + +inline Vector Vector::Max(const Vector &vOther) const +{ + return Vector(x > vOther.x ? x : vOther.x, + y > vOther.y ? y : vOther.y, + z > vOther.z ? z : vOther.z); +} + + +//----------------------------------------------------------------------------- +// arithmetic operations +//----------------------------------------------------------------------------- + +inline Vector Vector::operator-(void) const +{ + return Vector(-x,-y,-z); +} + +inline Vector Vector::operator+(const Vector& v) const +{ + Vector res; + VectorAdd( *this, v, res ); + return res; +} + +inline Vector Vector::operator-(const Vector& v) const +{ + Vector res; + VectorSubtract( *this, v, res ); + return res; +} + +inline Vector Vector::operator*(float fl) const +{ + Vector res; + VectorMultiply( *this, fl, res ); + return res; +} + +inline Vector Vector::operator*(const Vector& v) const +{ + Vector res; + VectorMultiply( *this, v, res ); + return res; +} + +inline Vector Vector::operator/(float fl) const +{ + Vector res; + VectorDivide( *this, fl, res ); + return res; +} + +inline Vector Vector::operator/(const Vector& v) const +{ + Vector res; + VectorDivide( *this, v, res ); + return res; +} + +inline Vector operator*(float fl, const Vector& v) +{ + return v * fl; +} + +//----------------------------------------------------------------------------- +// cross product +//----------------------------------------------------------------------------- + +inline Vector Vector::Cross(const Vector& vOther) const +{ + Vector res; + CrossProduct( *this, vOther, res ); + return res; +} + +//----------------------------------------------------------------------------- +// 2D +//----------------------------------------------------------------------------- + +inline vec_t Vector::Length2D(void) const +{ + return (vec_t)FastSqrt(x*x + y*y); +} + +inline vec_t Vector::Length2DSqr(void) const +{ + return (x*x + y*y); +} + +inline Vector CrossProduct(const Vector& a, const Vector& b) +{ + return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); +} + +inline void VectorMin( const Vector &a, const Vector &b, Vector &result ) +{ + result.x = fpmin(a.x, b.x); + result.y = fpmin(a.y, b.y); + result.z = fpmin(a.z, b.z); +} + +inline void VectorMax( const Vector &a, const Vector &b, Vector &result ) +{ + result.x = fpmax(a.x, b.x); + result.y = fpmax(a.y, b.y); + result.z = fpmax(a.z, b.z); +} + +// and when you want to return the vector rather than cause a LHS with it... +inline Vector VectorMin( const Vector &a, const Vector &b ) +{ + return Vector( fpmin(a.x, b.x), fpmin(a.y, b.y), fpmin(a.z, b.z) ); +} + +inline Vector VectorMax( const Vector &a, const Vector &b ) +{ + return Vector( fpmax(a.x, b.x), fpmax(a.y, b.y), fpmax(a.z, b.z) ); +} + +inline float ComputeVolume( const Vector &vecMins, const Vector &vecMaxs ) +{ + Vector vecDelta; + VectorSubtract( vecMaxs, vecMins, vecDelta ); + return DotProduct( vecDelta, vecDelta ); +} + +// Get a random vector. +inline Vector RandomVector( float minVal, float maxVal ) +{ + Vector random; + random.Random( minVal, maxVal ); + return random; +} + +#endif //slow + +//----------------------------------------------------------------------------- +// Helper debugging stuff.... +//----------------------------------------------------------------------------- + +inline bool operator==( float const* f, const Vector& v ) +{ + // AIIIEEEE!!!! + Assert(0); + return false; +} + +inline bool operator==( const Vector& v, float const* f ) +{ + // AIIIEEEE!!!! + Assert(0); + return false; +} + +inline bool operator!=( float const* f, const Vector& v ) +{ + // AIIIEEEE!!!! + Assert(0); + return false; +} + +inline bool operator!=( const Vector& v, float const* f ) +{ + // AIIIEEEE!!!! + Assert(0); + return false; +} + + +// return a vector perpendicular to another, with smooth variation. The difference between this and +// something like VectorVectors is that there are now discontinuities. _unlike_ VectorVectors, +// you won't get an "u +void VectorPerpendicularToVector( Vector const &in, Vector *pvecOut ); + +//----------------------------------------------------------------------------- +// AngularImpulse +//----------------------------------------------------------------------------- +// AngularImpulse are exponetial maps (an axis scaled by a "twist" angle in degrees) +typedef Vector AngularImpulse; + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline AngularImpulse RandomAngularImpulse( float minVal, float maxVal ) +{ + AngularImpulse angImp; + angImp.Random( minVal, maxVal ); + return angImp; +} + +#endif + + +//----------------------------------------------------------------------------- +// Quaternion +//----------------------------------------------------------------------------- + +class RadianEuler; + +class Quaternion // same data-layout as engine's vec4_t, +{ // which is a vec_t[4] +public: + inline Quaternion(void) { + + // Initialize to NAN to catch errors +#ifdef _DEBUG +#ifdef VECTOR_PARANOIA + x = y = z = w = VEC_T_NAN; +#endif +#endif + } + inline Quaternion(vec_t ix, vec_t iy, vec_t iz, vec_t iw) : x(ix), y(iy), z(iz), w(iw) { } + inline Quaternion(RadianEuler const &angle); // evil auto type promotion!!! + + inline void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f, vec_t iw=0.0f) { x = ix; y = iy; z = iz; w = iw; } + + bool IsValid() const; + void Invalidate(); + + bool operator==( const Quaternion &src ) const; + bool operator!=( const Quaternion &src ) const; + + inline Quaternion Conjugate() const { return Quaternion( -x, -y, -z, w ); } + + vec_t* Base() { return (vec_t*)this; } + const vec_t* Base() const { return (vec_t*)this; } + + // convenience for debugging + inline void Print() const; + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + vec_t x, y, z, w; +}; + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline vec_t& Quaternion::operator[](int i) +{ + Assert( (i >= 0) && (i < 4) ); + return ((vec_t*)this)[i]; +} + +inline vec_t Quaternion::operator[](int i) const +{ + Assert( (i >= 0) && (i < 4) ); + return ((vec_t*)this)[i]; +} + + +//----------------------------------------------------------------------------- +// Equality test +//----------------------------------------------------------------------------- +inline bool Quaternion::operator==( const Quaternion &src ) const +{ + return ( x == src.x ) && ( y == src.y ) && ( z == src.z ) && ( w == src.w ); +} + +inline bool Quaternion::operator!=( const Quaternion &src ) const +{ + return !operator==( src ); +} + + +//----------------------------------------------------------------------------- +// Debugging only +//----------------------------------------------------------------------------- +void Quaternion::Print() const +{ +#ifndef _CERT + Msg("q{ %.3fi + %.3fj + %.3fk + %.3f }", x, y, z, w ); +#endif +} + +//----------------------------------------------------------------------------- +// Quaternion equality with tolerance +//----------------------------------------------------------------------------- +inline bool QuaternionsAreEqual( const Quaternion& src1, const Quaternion& src2, float tolerance ) +{ + if (FloatMakePositive(src1.x - src2.x) > tolerance) + return false; + if (FloatMakePositive(src1.y - src2.y) > tolerance) + return false; + if (FloatMakePositive(src1.z - src2.z) > tolerance) + return false; + return (FloatMakePositive(src1.w - src2.w) <= tolerance); +} + + +//----------------------------------------------------------------------------- +// Here's where we add all those lovely SSE optimized routines +//----------------------------------------------------------------------------- +class ALIGN16 QuaternionAligned : public Quaternion +{ +public: + inline QuaternionAligned(void) {}; + inline QuaternionAligned(vec_t X, vec_t Y, vec_t Z, vec_t W) + { + Init(X,Y,Z,W); + } + + operator Quaternion * () { return this; } + operator const Quaternion * () { return this; } + +#ifdef VECTOR_NO_SLOW_OPERATIONS + +private: + // No copy constructors allowed if we're in optimal mode + QuaternionAligned(const QuaternionAligned& vOther); + QuaternionAligned(const Quaternion &vOther); + +#else +public: + explicit QuaternionAligned(const Quaternion &vOther) + { + Init(vOther.x, vOther.y, vOther.z, vOther.w); + } + + QuaternionAligned& operator=(const Quaternion &vOther) + { + Init(vOther.x, vOther.y, vOther.z, vOther.w); + return *this; + } + + QuaternionAligned& operator=(const QuaternionAligned &vOther) + { + // we know we're aligned, so use simd + // we can't use the convenient abstract interface coz it gets declared later +#ifdef _X360 + XMStoreVector4A(Base(), XMLoadVector4A(vOther.Base())); +#elif _WIN32 + _mm_store_ps(Base(), _mm_load_ps( vOther.Base() )); +#else + Init(vOther.x, vOther.y, vOther.z, vOther.w); +#endif + return *this; + } + +#endif + +#if !defined(NO_MALLOC_OVERRIDE) + void* operator new[] ( size_t nSize) + { + return MemAlloc_AllocAligned(nSize, 16); + } + + void* operator new[] ( size_t nSize, const char *pFileName, int nLine) + { + return MemAlloc_AllocAlignedFileLine(nSize, 16, pFileName, nLine); + } + + void* operator new[] ( size_t nSize, int /*nBlockUse*/, const char *pFileName, int nLine) + { + return MemAlloc_AllocAlignedFileLine(nSize, 16, pFileName, nLine); + } + + void operator delete[] ( void* p) + { + MemAlloc_FreeAligned(p); + } + + void operator delete[] ( void* p, const char *pFileName, int nLine) + { + MemAlloc_FreeAligned(p, pFileName, nLine); + } + + void operator delete[] ( void* p, int /*nBlockUse*/, const char *pFileName, int nLine) + { + MemAlloc_FreeAligned(p, pFileName, nLine); + } + + // please don't allocate a single quaternion... + void* operator new ( size_t nSize ) + { + return MemAlloc_AllocAligned(nSize, 16); + } + void* operator new ( size_t nSize, const char *pFileName, int nLine ) + { + return MemAlloc_AllocAlignedFileLine(nSize, 16, pFileName, nLine); + } + void* operator new ( size_t nSize, int /*nBlockUse*/, const char *pFileName, int nLine ) + { + return MemAlloc_AllocAlignedFileLine(nSize, 16, pFileName, nLine); + } + void operator delete ( void* p) + { + MemAlloc_FreeAligned(p); + } + + void operator delete ( void* p, const char *pFileName, int nLine) + { + MemAlloc_FreeAligned(p, pFileName, nLine); + } + + void operator delete ( void* p, int /*nBlockUse*/, const char *pFileName, int nLine) + { + MemAlloc_FreeAligned(p, pFileName, nLine); + } +#endif +} ALIGN16_POST; + +//----------------------------------------------------------------------------- +// Radian Euler angle aligned to axis (NOT ROLL/PITCH/YAW) +//----------------------------------------------------------------------------- +class QAngle; +class RadianEuler +{ +public: + inline RadianEuler(void) { } + inline RadianEuler(vec_t X, vec_t Y, vec_t Z) { x = X; y = Y; z = Z; } + inline RadianEuler(Quaternion const &q); // evil auto type promotion!!! + inline RadianEuler(QAngle const &angles); // evil auto type promotion!!! + + // Initialization + inline void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f) { x = ix; y = iy; z = iz; } + + // conversion to qangle + QAngle ToQAngle( void ) const; + bool IsValid() const; + void Invalidate(); + + inline vec_t *Base() { return &x; } + inline const vec_t *Base() const { return &x; } + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + vec_t x, y, z; +}; + + +extern void AngleQuaternion( RadianEuler const &angles, Quaternion &qt ); +extern void QuaternionAngles( Quaternion const &q, RadianEuler &angles ); +inline Quaternion::Quaternion(RadianEuler const &angle) +{ + AngleQuaternion( angle, *this ); +} + +inline bool Quaternion::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z) && IsFinite(w); +} + +inline void Quaternion::Invalidate() +{ +//#ifdef _DEBUG +//#ifdef VECTOR_PARANOIA + x = y = z = w = VEC_T_NAN; +//#endif +//#endif +} + +inline RadianEuler::RadianEuler(Quaternion const &q) +{ + QuaternionAngles( q, *this ); +} + +inline void VectorCopy( RadianEuler const& src, RadianEuler &dst ) +{ + CHECK_VALID(src); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + +inline void VectorScale( RadianEuler const& src, float b, RadianEuler &dst ) +{ + CHECK_VALID(src); + Assert( IsFinite(b) ); + dst.x = src.x * b; + dst.y = src.y * b; + dst.z = src.z * b; +} + +inline bool RadianEuler::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z); +} + +inline void RadianEuler::Invalidate() +{ +//#ifdef _DEBUG +//#ifdef VECTOR_PARANOIA + x = y = z = VEC_T_NAN; +//#endif +//#endif +} + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline vec_t& RadianEuler::operator[](int i) +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + +inline vec_t RadianEuler::operator[](int i) const +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + + +//----------------------------------------------------------------------------- +// Degree Euler QAngle pitch, yaw, roll +//----------------------------------------------------------------------------- +class QAngleByValue; + +class QAngle +{ +public: + // Members + vec_t x, y, z; + + // Construction/destruction + QAngle(void); + QAngle(vec_t X, vec_t Y, vec_t Z); +#ifndef _PS3 +// QAngle(RadianEuler const &angles); // evil auto type promotion!!! +#endif + + // Allow pass-by-value + operator QAngleByValue &() { return *((QAngleByValue *)(this)); } + operator const QAngleByValue &() const { return *((const QAngleByValue *)(this)); } + + // Initialization + void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f); + void Random( vec_t minVal, vec_t maxVal ); + + // Got any nasty NAN's? + bool IsValid() const; + void Invalidate(); + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + // Base address... + vec_t* Base(); + vec_t const* Base() const; + + // equality + bool operator==(const QAngle& v) const; + bool operator!=(const QAngle& v) const; + + // arithmetic operations + QAngle& operator+=(const QAngle &v); + QAngle& operator-=(const QAngle &v); + QAngle& operator*=(float s); + QAngle& operator/=(float s); + + // Get the vector's magnitude. + vec_t Length() const; + vec_t LengthSqr() const; + + // negate the QAngle components + //void Negate(); + + // No assignment operators either... + QAngle& operator=( const QAngle& src ); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // copy constructors + + // arithmetic operations + QAngle operator-(void) const; + + QAngle operator+(const QAngle& v) const; + QAngle operator-(const QAngle& v) const; + QAngle operator*(float fl) const; + QAngle operator/(float fl) const; +#else + +private: + // No copy constructors allowed if we're in optimal mode + QAngle(const QAngle& vOther); + +#endif +}; + +//----------------------------------------------------------------------------- +// Allows us to specifically pass the vector by value when we need to +//----------------------------------------------------------------------------- +class QAngleByValue : public QAngle +{ +public: + // Construction/destruction: + QAngleByValue(void) : QAngle() {} + QAngleByValue(vec_t X, vec_t Y, vec_t Z) : QAngle( X, Y, Z ) {} + QAngleByValue(const QAngleByValue& vOther) { *this = vOther; } +}; + + +inline void VectorAdd( const QAngle& a, const QAngle& b, QAngle& result ) +{ + CHECK_VALID(a); + CHECK_VALID(b); + result.x = a.x + b.x; + result.y = a.y + b.y; + result.z = a.z + b.z; +} + +inline void VectorMA( const QAngle &start, float scale, const QAngle &direction, QAngle &dest ) +{ + CHECK_VALID(start); + CHECK_VALID(direction); + dest.x = start.x + scale * direction.x; + dest.y = start.y + scale * direction.y; + dest.z = start.z + scale * direction.z; +} + + +//----------------------------------------------------------------------------- +// constructors +//----------------------------------------------------------------------------- +inline QAngle::QAngle(void) +{ +#ifdef _DEBUG +#ifdef VECTOR_PARANOIA + // Initialize to NAN to catch errors + x = y = z = VEC_T_NAN; +#endif +#endif +} + +inline QAngle::QAngle(vec_t X, vec_t Y, vec_t Z) +{ + x = X; y = Y; z = Z; + CHECK_VALID(*this); +} + + +//----------------------------------------------------------------------------- +// initialization +//----------------------------------------------------------------------------- +inline void QAngle::Init( vec_t ix, vec_t iy, vec_t iz ) +{ + x = ix; y = iy; z = iz; + CHECK_VALID(*this); +} + +inline void QAngle::Random( vec_t minVal, vec_t maxVal ) +{ + x = RandomFloat( minVal, maxVal ); + y = RandomFloat( minVal, maxVal ); + z = RandomFloat( minVal, maxVal ); + CHECK_VALID(*this); +} + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline QAngle RandomAngle( float minVal, float maxVal ) +{ + Vector random; + random.Random( minVal, maxVal ); + QAngle ret( random.x, random.y, random.z ); + return ret; +} + +#endif + +inline RadianEuler::RadianEuler(QAngle const &angles) +{ + Init( + angles.z * 3.14159265358979323846f / 180.f, + angles.x * 3.14159265358979323846f / 180.f, + angles.y * 3.14159265358979323846f / 180.f ); +} + + + + +inline QAngle RadianEuler::ToQAngle( void) const +{ + return QAngle( + y * 180.f / 3.14159265358979323846f, + z * 180.f / 3.14159265358979323846f, + x * 180.f / 3.14159265358979323846f ); +} + +//----------------------------------------------------------------------------- +// assignment +//----------------------------------------------------------------------------- +inline QAngle& QAngle::operator=(const QAngle &vOther) +{ + CHECK_VALID(vOther); + x=vOther.x; y=vOther.y; z=vOther.z; + return *this; +} + + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- +inline vec_t& QAngle::operator[](int i) +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + +inline vec_t QAngle::operator[](int i) const +{ + Assert( (i >= 0) && (i < 3) ); + return ((vec_t*)this)[i]; +} + + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- +inline vec_t* QAngle::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* QAngle::Base() const +{ + return (vec_t const*)this; +} + + +//----------------------------------------------------------------------------- +// IsValid? +//----------------------------------------------------------------------------- +inline bool QAngle::IsValid() const +{ + return IsFinite(x) && IsFinite(y) && IsFinite(z); +} + +//----------------------------------------------------------------------------- +// Invalidate +//----------------------------------------------------------------------------- + +inline void QAngle::Invalidate() +{ +//#ifdef _DEBUG +//#ifdef VECTOR_PARANOIA + x = y = z = VEC_T_NAN; +//#endif +//#endif +} + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- +inline bool QAngle::operator==( const QAngle& src ) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x == x) && (src.y == y) && (src.z == z); +} + +inline bool QAngle::operator!=( const QAngle& src ) const +{ + CHECK_VALID(src); + CHECK_VALID(*this); + return (src.x != x) || (src.y != y) || (src.z != z); +} + + +//----------------------------------------------------------------------------- +// Copy +//----------------------------------------------------------------------------- +inline void VectorCopy( const QAngle& src, QAngle& dst ) +{ + CHECK_VALID(src); + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; +} + + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- +inline QAngle& QAngle::operator+=(const QAngle& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x+=v.x; y+=v.y; z += v.z; + return *this; +} + +inline QAngle& QAngle::operator-=(const QAngle& v) +{ + CHECK_VALID(*this); + CHECK_VALID(v); + x-=v.x; y-=v.y; z -= v.z; + return *this; +} + +inline QAngle& QAngle::operator*=(float fl) +{ + x *= fl; + y *= fl; + z *= fl; + CHECK_VALID(*this); + return *this; +} + +inline QAngle& QAngle::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + z *= oofl; + CHECK_VALID(*this); + return *this; +} + + +//----------------------------------------------------------------------------- +// length +//----------------------------------------------------------------------------- +inline vec_t QAngle::Length( ) const +{ + CHECK_VALID(*this); + return (vec_t)FastSqrt( LengthSqr( ) ); +} + + +inline vec_t QAngle::LengthSqr( ) const +{ + CHECK_VALID(*this); + return x * x + y * y + z * z; +} + + +//----------------------------------------------------------------------------- +// Vector equality with tolerance +//----------------------------------------------------------------------------- +inline bool QAnglesAreEqual( const QAngle& src1, const QAngle& src2, float tolerance = 0.0f ) +{ + if (FloatMakePositive(src1.x - src2.x) > tolerance) + return false; + if (FloatMakePositive(src1.y - src2.y) > tolerance) + return false; + return (FloatMakePositive(src1.z - src2.z) <= tolerance); +} + + +//----------------------------------------------------------------------------- +// arithmetic operations (SLOW!!) +//----------------------------------------------------------------------------- +#ifndef VECTOR_NO_SLOW_OPERATIONS + +inline QAngle QAngle::operator-(void) const +{ + QAngle ret(-x,-y,-z); + return ret; +} + +inline QAngle QAngle::operator+(const QAngle& v) const +{ + QAngle res; + res.x = x + v.x; + res.y = y + v.y; + res.z = z + v.z; + return res; +} + +inline QAngle QAngle::operator-(const QAngle& v) const +{ + QAngle res; + res.x = x - v.x; + res.y = y - v.y; + res.z = z - v.z; + return res; +} + +inline QAngle QAngle::operator*(float fl) const +{ + QAngle res; + res.x = x * fl; + res.y = y * fl; + res.z = z * fl; + return res; +} + +inline QAngle QAngle::operator/(float fl) const +{ + QAngle res; + res.x = x / fl; + res.y = y / fl; + res.z = z / fl; + return res; +} + +inline QAngle operator*(float fl, const QAngle& v) +{ + QAngle ret( v * fl ); + return ret; +} + +#endif // VECTOR_NO_SLOW_OPERATIONS + + +//----------------------------------------------------------------------------- +// NOTE: These are not completely correct. The representations are not equivalent +// unless the QAngle represents a rotational impulse along a coordinate axis (x,y,z) +inline void QAngleToAngularImpulse( const QAngle &angles, AngularImpulse &impulse ) +{ + impulse.x = angles.z; + impulse.y = angles.x; + impulse.z = angles.y; +} + +inline void AngularImpulseToQAngle( const AngularImpulse &impulse, QAngle &angles ) +{ + angles.x = impulse.y; + angles.y = impulse.z; + angles.z = impulse.x; +} + +#if !defined( _X360 ) && !defined( _PS3 ) + +FORCEINLINE vec_t InvRSquared( const float* v ) +{ + return 1.0 / MAX( 1.0, v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ); +} + +FORCEINLINE vec_t InvRSquared( const Vector &v ) +{ + return InvRSquared( v.Base() ); +} + +#else + +// call directly +FORCEINLINE float _VMX_InvRSquared( const Vector &v ) +{ +#if !defined (_PS3) + XMVECTOR xmV = XMVector3ReciprocalLength( XMLoadVector3( v.Base() ) ); + xmV = XMVector3Dot( xmV, xmV ); + return xmV.x; +#else //!_PS3 + vector_float_union vRet; + vec_float4 v0, v1, vIn, vOut; + vector unsigned char permMask; + v0 = vec_ld( 0, v.Base() ); + permMask = vec_lvsl( 0, v.Base() ); + v1 = vec_ld( 11, v.Base() ); + vIn = vec_perm(v0, v1, permMask); + vOut = vec_madd( vIn, vIn, _VEC_ZEROF ); + vec_float4 vTmp = vec_sld( vIn, vIn, 4 ); + vec_float4 vTmp2 = vec_sld( vIn, vIn, 8 ); + vOut = vec_madd( vTmp, vTmp, vOut ); + vOut = vec_madd( vTmp2, vTmp2, vOut ); + vOut = vec_re( vec_add(vOut, _VEC_EPSILONF) ); + vec_st(vOut,0,&vRet.vf); + float ret = vRet.f[0]; + return ret; +#endif //!_PS3 +} + +#define InvRSquared(x) _VMX_InvRSquared(x) + +#endif // _X360 + +#if !defined( _X360 ) && !defined( _PS3 ) + +// FIXME: Change this back to a #define once we get rid of the vec_t version +float VectorNormalize( Vector& v ); + +// FIXME: Obsolete version of VectorNormalize, once we remove all the friggin float*s +FORCEINLINE float VectorNormalize( float * v ) +{ + return VectorNormalize(*(reinterpret_cast<Vector *>(v))); +} + +#else +#if !defined( _PS3 ) +// modified version of Microsoft's XMVector3Length +// microsoft's version will return INF for very small vectors +// e.g. Vector vTest(7.98555446e-20,-6.85012984e-21,0); VectorNormalize( vTest ); +// so we clamp to epsilon instead of checking for zero +XMFINLINE XMVECTOR XMVector3Length_Fixed +( + FXMVECTOR V + ) +{ + // Returns a QNaN on infinite vectors. + static CONST XMVECTOR g_fl4SmallVectorEpsilon = {1e-24f,1e-24f,1e-24f,1e-24f}; + + XMVECTOR D; + XMVECTOR Rsq; + XMVECTOR Rcp; + XMVECTOR Zero; + XMVECTOR RT; + XMVECTOR Result; + XMVECTOR Length; + XMVECTOR H; + + H = __vspltisw(1); + D = __vmsum3fp(V, V); + H = __vcfsx(H, 1); + Rsq = __vrsqrtefp(D); + RT = __vmulfp(D, H); + Rcp = __vmulfp(Rsq, Rsq); + H = __vnmsubfp(RT, Rcp, H); + Rsq = __vmaddfp(Rsq, H, Rsq); + Zero = __vspltisw(0); + Result = __vcmpgefp( g_fl4SmallVectorEpsilon, D ); + Length = __vmulfp(D, Rsq); + Result = __vsel(Length, Zero, Result); + + return Result; +} +#endif + +// call directly +FORCEINLINE float _VMX_VectorNormalize( Vector &vec ) +{ +#if !defined _PS3 + float mag = XMVector3Length_Fixed( XMLoadVector3( vec.Base() ) ).x; + float den = 1.f / (mag + FLT_EPSILON ); + vec.x *= den; + vec.y *= den; + vec.z *= den; + return mag; +#else // !_PS3 + vec_float4 vIn; + vec_float4 v0, v1; + vector unsigned char permMask; + v0 = vec_ld( 0, vec.Base() ); + permMask = vec_lvsl( 0, vec.Base() ); + v1 = vec_ld( 11, vec.Base() ); + vIn = vec_perm(v0, v1, permMask); + float mag = vmathV3Length((VmathVector3 *)&vIn); + float den = 1.f / (mag + FLT_EPSILON ); + vec.x *= den; + vec.y *= den; + vec.z *= den; + return mag; +#endif // !_PS3 +} +// FIXME: Change this back to a #define once we get rid of the vec_t version +FORCEINLINE float VectorNormalize( Vector& v ) +{ + return _VMX_VectorNormalize( v ); +} +// FIXME: Obsolete version of VectorNormalize, once we remove all the friggin float*s +FORCEINLINE float VectorNormalize( float *pV ) +{ + return _VMX_VectorNormalize(*(reinterpret_cast<Vector*>(pV))); +} + +#endif // _X360 + +#if !defined( _X360 ) && !defined( _PS3 ) +FORCEINLINE void VectorNormalizeFast (Vector& vec) +{ + float ool = FastRSqrt( FLT_EPSILON + vec.x * vec.x + vec.y * vec.y + vec.z * vec.z ); + + vec.x *= ool; + vec.y *= ool; + vec.z *= ool; +} +#else + +// call directly +FORCEINLINE void VectorNormalizeFast( Vector &vec ) +{ +#if !defined (_PS3) + XMVECTOR xmV = XMVector3LengthEst( XMLoadVector3( vec.Base() ) ); + float den = 1.f / (xmV.x + FLT_EPSILON); + vec.x *= den; + vec.y *= den; + vec.z *= den; +#else // !_PS3 + vector_float_union vVec; + + vec_float4 vIn, vOut, vOOLen, vDot; + + // load + vec_float4 v0, v1; + vector unsigned char permMask; + v0 = vec_ld( 0, vec.Base() ); + permMask = vec_lvsl( 0, vec.Base() ); + v1 = vec_ld( 11, vec.Base() ); + vIn = vec_perm(v0, v1, permMask); + + // vec.vec + vOut = vec_madd( vIn, vIn, _VEC_ZEROF ); + vec_float4 vTmp = vec_sld( vIn, vIn, 4 ); + vec_float4 vTmp2 = vec_sld( vIn, vIn, 8 ); + vOut = vec_madd( vTmp, vTmp, vOut ); + vOut = vec_madd( vTmp2, vTmp2, vOut ); + + // splat dot to all + vDot = vec_splat( vOut, 0 ); + + vOOLen = vec_rsqrte( vec_add( vDot, _VEC_EPSILONF ) ); + + // vec * 1.0/sqrt(vec.vec) + vOut = vec_madd( vIn, vOOLen, _VEC_ZEROF ); + + // store + vec_st(vOut,0,&vVec.vf); + + // store vec + vec.x = vVec.f[0]; + vec.y = vVec.f[1]; + vec.z = vVec.f[2]; + +#endif // !_PS3 +} + +#endif // _X360 + +inline vec_t Vector::NormalizeInPlace() +{ + return VectorNormalize( *this ); +} + +inline Vector Vector::Normalized() const +{ + Vector norm = *this; + VectorNormalize( norm ); + return norm; +} + +inline bool Vector::IsLengthGreaterThan( float val ) const +{ + return LengthSqr() > val*val; +} + +inline bool Vector::IsLengthLessThan( float val ) const +{ + return LengthSqr() < val*val; +} + +#endif + diff --git a/external/vpc/public/mathlib/vector2d.h b/external/vpc/public/mathlib/vector2d.h new file mode 100644 index 0000000..30fcc86 --- /dev/null +++ b/external/vpc/public/mathlib/vector2d.h @@ -0,0 +1,670 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef VECTOR2D_H +#define VECTOR2D_H + +#ifdef _WIN32 +#pragma once +#endif + +#include <math.h> +#include <float.h> + +// For vec_t, put this somewhere else? +#include "tier0/basetypes.h" + +// For RandomFloat() +#include "vstdlib/random.h" + +#include "tier0/dbg.h" +#include "mathlib/math_pfns.h" + +//========================================================= +// 2D Vector2D +//========================================================= + +class Vector2D +{ +public: + // Members + vec_t x, y; + + // Construction/destruction + Vector2D(void); + Vector2D(vec_t X, vec_t Y); + Vector2D(const float *pFloat); + + // Initialization + void Init(vec_t ix=0.0f, vec_t iy=0.0f); + + // Got any nasty NAN's? + bool IsValid() const; + + // array access... + vec_t operator[](int i) const; + vec_t& operator[](int i); + + // Base address... + vec_t* Base(); + vec_t const* Base() const; + + // Initialization methods + void Random( float minVal, float maxVal ); + + // equality + bool operator==(const Vector2D& v) const; + bool operator!=(const Vector2D& v) const; + + // arithmetic operations + Vector2D& operator+=(const Vector2D &v); + Vector2D& operator-=(const Vector2D &v); + Vector2D& operator*=(const Vector2D &v); + Vector2D& operator*=(float s); + Vector2D& operator/=(const Vector2D &v); + Vector2D& operator/=(float s); + + // negate the Vector2D components + void Negate(); + + // Get the Vector2D's magnitude. + vec_t Length() const; + + // Get the Vector2D's magnitude squared. + vec_t LengthSqr(void) const; + + // return true if this vector is (0,0) within tolerance + bool IsZero( float tolerance = 0.01f ) const + { + return (x > -tolerance && x < tolerance && + y > -tolerance && y < tolerance); + } + + // Normalize in place and return the old length. + vec_t NormalizeInPlace(); + + // Compare length. + bool IsLengthGreaterThan( float val ) const; + bool IsLengthLessThan( float val ) const; + + // Get the distance from this Vector2D to the other one. + vec_t DistTo(const Vector2D &vOther) const; + + // Get the distance from this Vector2D to the other one squared. + vec_t DistToSqr(const Vector2D &vOther) const; + + // Copy + void CopyToArray(float* rgfl) const; + + // Multiply, add, and assign to this (ie: *this = a + b * scalar). This + // is about 12% faster than the actual Vector2D equation (because it's done per-component + // rather than per-Vector2D). + void MulAdd(const Vector2D& a, const Vector2D& b, float scalar); + + // Dot product. + vec_t Dot(const Vector2D& vOther) const; + + // assignment + Vector2D& operator=(const Vector2D &vOther); + +#ifndef VECTOR_NO_SLOW_OPERATIONS + // copy constructors + Vector2D(const Vector2D &vOther); + + // arithmetic operations + Vector2D operator-(void) const; + + Vector2D operator+(const Vector2D& v) const; + Vector2D operator-(const Vector2D& v) const; + Vector2D operator*(const Vector2D& v) const; + Vector2D operator/(const Vector2D& v) const; + Vector2D operator*(float fl) const; + Vector2D operator/(float fl) const; + + // Cross product between two vectors. + Vector2D Cross(const Vector2D &vOther) const; + + // Returns a Vector2D with the min or max in X, Y, and Z. + Vector2D Min(const Vector2D &vOther) const; + Vector2D Max(const Vector2D &vOther) const; + +#else + +private: + // No copy constructors allowed if we're in optimal mode + Vector2D(const Vector2D& vOther); +#endif +}; + +//----------------------------------------------------------------------------- + +const Vector2D vec2_origin(0,0); +const Vector2D vec2_invalid( FLT_MAX, FLT_MAX ); + +//----------------------------------------------------------------------------- +// Vector2D related operations +//----------------------------------------------------------------------------- + +// Vector2D clear +void Vector2DClear( Vector2D& a ); + +// Copy +void Vector2DCopy( const Vector2D& src, Vector2D& dst ); + +// Vector2D arithmetic +void Vector2DAdd( const Vector2D& a, const Vector2D& b, Vector2D& result ); +void Vector2DSubtract( const Vector2D& a, const Vector2D& b, Vector2D& result ); +void Vector2DMultiply( const Vector2D& a, vec_t b, Vector2D& result ); +void Vector2DMultiply( const Vector2D& a, const Vector2D& b, Vector2D& result ); +void Vector2DDivide( const Vector2D& a, vec_t b, Vector2D& result ); +void Vector2DDivide( const Vector2D& a, const Vector2D& b, Vector2D& result ); +void Vector2DMA( const Vector2D& start, float s, const Vector2D& dir, Vector2D& result ); + +// Store the min or max of each of x, y, and z into the result. +void Vector2DMin( const Vector2D &a, const Vector2D &b, Vector2D &result ); +void Vector2DMax( const Vector2D &a, const Vector2D &b, Vector2D &result ); + +#define Vector2DExpand( v ) (v).x, (v).y + +// Normalization +vec_t Vector2DNormalize( Vector2D& v ); + +// Length +vec_t Vector2DLength( const Vector2D& v ); + +// Dot Product +vec_t DotProduct2D(const Vector2D& a, const Vector2D& b); + +// Linearly interpolate between two vectors +void Vector2DLerp(const Vector2D& src1, const Vector2D& src2, vec_t t, Vector2D& dest ); + + +//----------------------------------------------------------------------------- +// +// Inlined Vector2D methods +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// constructors +//----------------------------------------------------------------------------- + +inline Vector2D::Vector2D(void) +{ +#ifdef _DEBUG + // Initialize to NAN to catch errors + x = y = VEC_T_NAN; +#endif +} + +inline Vector2D::Vector2D(vec_t X, vec_t Y) +{ + x = X; y = Y; + Assert( IsValid() ); +} + +inline Vector2D::Vector2D(const float *pFloat) +{ + Assert( pFloat ); + x = pFloat[0]; y = pFloat[1]; + Assert( IsValid() ); +} + + +//----------------------------------------------------------------------------- +// copy constructor +//----------------------------------------------------------------------------- + +inline Vector2D::Vector2D(const Vector2D &vOther) +{ + Assert( vOther.IsValid() ); + x = vOther.x; y = vOther.y; +} + +//----------------------------------------------------------------------------- +// initialization +//----------------------------------------------------------------------------- + +inline void Vector2D::Init( vec_t ix, vec_t iy ) +{ + x = ix; y = iy; + Assert( IsValid() ); +} + +inline void Vector2D::Random( float minVal, float maxVal ) +{ + x = RandomFloat( minVal , maxVal ); + y = RandomFloat( minVal , maxVal ); +} + +inline void Vector2DClear( Vector2D& a ) +{ + a.x = a.y = 0.0f; +} + +//----------------------------------------------------------------------------- +// assignment +//----------------------------------------------------------------------------- + +inline Vector2D& Vector2D::operator=(const Vector2D &vOther) +{ + Assert( vOther.IsValid() ); + x=vOther.x; y=vOther.y; + return *this; +} + +//----------------------------------------------------------------------------- +// Array access +//----------------------------------------------------------------------------- + +inline vec_t& Vector2D::operator[](int i) +{ + Assert( (i >= 0) && (i < 2) ); + return ((vec_t*)this)[i]; +} + +inline vec_t Vector2D::operator[](int i) const +{ + Assert( (i >= 0) && (i < 2) ); + return ((vec_t*)this)[i]; +} + +//----------------------------------------------------------------------------- +// Base address... +//----------------------------------------------------------------------------- + +inline vec_t* Vector2D::Base() +{ + return (vec_t*)this; +} + +inline vec_t const* Vector2D::Base() const +{ + return (vec_t const*)this; +} + +//----------------------------------------------------------------------------- +// IsValid? +//----------------------------------------------------------------------------- + +inline bool Vector2D::IsValid() const +{ + return IsFinite(x) && IsFinite(y); +} + +//----------------------------------------------------------------------------- +// comparison +//----------------------------------------------------------------------------- + +inline bool Vector2D::operator==( const Vector2D& src ) const +{ + Assert( src.IsValid() && IsValid() ); + return (src.x == x) && (src.y == y); +} + +inline bool Vector2D::operator!=( const Vector2D& src ) const +{ + Assert( src.IsValid() && IsValid() ); + return (src.x != x) || (src.y != y); +} + + +//----------------------------------------------------------------------------- +// Copy +//----------------------------------------------------------------------------- + +inline void Vector2DCopy( const Vector2D& src, Vector2D& dst ) +{ + Assert( src.IsValid() ); + dst.x = src.x; + dst.y = src.y; +} + +inline void Vector2D::CopyToArray(float* rgfl) const +{ + Assert( IsValid() ); + Assert( rgfl ); + rgfl[0] = x; rgfl[1] = y; +} + +//----------------------------------------------------------------------------- +// standard math operations +//----------------------------------------------------------------------------- + +inline void Vector2D::Negate() +{ + Assert( IsValid() ); + x = -x; y = -y; +} + +inline Vector2D& Vector2D::operator+=(const Vector2D& v) +{ + Assert( IsValid() && v.IsValid() ); + x+=v.x; y+=v.y; + return *this; +} + +inline Vector2D& Vector2D::operator-=(const Vector2D& v) +{ + Assert( IsValid() && v.IsValid() ); + x-=v.x; y-=v.y; + return *this; +} + +inline Vector2D& Vector2D::operator*=(float fl) +{ + x *= fl; + y *= fl; + Assert( IsValid() ); + return *this; +} + +inline Vector2D& Vector2D::operator*=(const Vector2D& v) +{ + x *= v.x; + y *= v.y; + Assert( IsValid() ); + return *this; +} + +inline Vector2D& Vector2D::operator/=(float fl) +{ + Assert( fl != 0.0f ); + float oofl = 1.0f / fl; + x *= oofl; + y *= oofl; + Assert( IsValid() ); + return *this; +} + +inline Vector2D& Vector2D::operator/=(const Vector2D& v) +{ + Assert( v.x != 0.0f && v.y != 0.0f ); + x /= v.x; + y /= v.y; + Assert( IsValid() ); + return *this; +} + +inline void Vector2DAdd( const Vector2D& a, const Vector2D& b, Vector2D& c ) +{ + Assert( a.IsValid() && b.IsValid() ); + c.x = a.x + b.x; + c.y = a.y + b.y; +} + +inline void Vector2DSubtract( const Vector2D& a, const Vector2D& b, Vector2D& c ) +{ + Assert( a.IsValid() && b.IsValid() ); + c.x = a.x - b.x; + c.y = a.y - b.y; +} + +inline void Vector2DMultiply( const Vector2D& a, vec_t b, Vector2D& c ) +{ + Assert( a.IsValid() && IsFinite(b) ); + c.x = a.x * b; + c.y = a.y * b; +} + +inline void Vector2DMultiply( const Vector2D& a, const Vector2D& b, Vector2D& c ) +{ + Assert( a.IsValid() && b.IsValid() ); + c.x = a.x * b.x; + c.y = a.y * b.y; +} + + +inline void Vector2DDivide( const Vector2D& a, vec_t b, Vector2D& c ) +{ + Assert( a.IsValid() ); + Assert( b != 0.0f ); + vec_t oob = 1.0f / b; + c.x = a.x * oob; + c.y = a.y * oob; +} + +inline void Vector2DDivide( const Vector2D& a, const Vector2D& b, Vector2D& c ) +{ + Assert( a.IsValid() ); + Assert( (b.x != 0.0f) && (b.y != 0.0f) ); + c.x = a.x / b.x; + c.y = a.y / b.y; +} + +inline void Vector2DMA( const Vector2D& start, float s, const Vector2D& dir, Vector2D& result ) +{ + Assert( start.IsValid() && IsFinite(s) && dir.IsValid() ); + result.x = start.x + s*dir.x; + result.y = start.y + s*dir.y; +} + +// FIXME: Remove +// For backwards compatability +inline void Vector2D::MulAdd(const Vector2D& a, const Vector2D& b, float scalar) +{ + x = a.x + b.x * scalar; + y = a.y + b.y * scalar; +} + +inline void Vector2DLerp(const Vector2D& src1, const Vector2D& src2, vec_t t, Vector2D& dest ) +{ + dest[0] = src1[0] + (src2[0] - src1[0]) * t; + dest[1] = src1[1] + (src2[1] - src1[1]) * t; +} + +//----------------------------------------------------------------------------- +// dot, cross +//----------------------------------------------------------------------------- +inline vec_t DotProduct2D(const Vector2D& a, const Vector2D& b) +{ + Assert( a.IsValid() && b.IsValid() ); + return( a.x*b.x + a.y*b.y ); +} + +// for backwards compatability +inline vec_t Vector2D::Dot( const Vector2D& vOther ) const +{ + return DotProduct2D( *this, vOther ); +} + + +//----------------------------------------------------------------------------- +// length +//----------------------------------------------------------------------------- +inline vec_t Vector2DLength( const Vector2D& v ) +{ + Assert( v.IsValid() ); + return (vec_t)FastSqrt(v.x*v.x + v.y*v.y); +} + +inline vec_t Vector2D::LengthSqr(void) const +{ + Assert( IsValid() ); + return (x*x + y*y); +} + +inline vec_t Vector2D::NormalizeInPlace() +{ + return Vector2DNormalize( *this ); +} + +inline bool Vector2D::IsLengthGreaterThan( float val ) const +{ + return LengthSqr() > val*val; +} + +inline bool Vector2D::IsLengthLessThan( float val ) const +{ + return LengthSqr() < val*val; +} + +inline vec_t Vector2D::Length(void) const +{ + return Vector2DLength( *this ); +} + + +inline void Vector2DMin( const Vector2D &a, const Vector2D &b, Vector2D &result ) +{ + result.x = (a.x < b.x) ? a.x : b.x; + result.y = (a.y < b.y) ? a.y : b.y; +} + + +inline void Vector2DMax( const Vector2D &a, const Vector2D &b, Vector2D &result ) +{ + result.x = (a.x > b.x) ? a.x : b.x; + result.y = (a.y > b.y) ? a.y : b.y; +} + + +//----------------------------------------------------------------------------- +// Normalization +//----------------------------------------------------------------------------- +inline vec_t Vector2DNormalize( Vector2D& v ) +{ + Assert( v.IsValid() ); + vec_t l = v.Length(); + if (l != 0.0f) + { + v /= l; + } + else + { + v.x = v.y = 0.0f; + } + return l; +} + + +//----------------------------------------------------------------------------- +// Get the distance from this Vector2D to the other one +//----------------------------------------------------------------------------- +inline vec_t Vector2D::DistTo(const Vector2D &vOther) const +{ + Vector2D delta; + Vector2DSubtract( *this, vOther, delta ); + return delta.Length(); +} + +inline vec_t Vector2D::DistToSqr(const Vector2D &vOther) const +{ + Vector2D delta; + Vector2DSubtract( *this, vOther, delta ); + return delta.LengthSqr(); +} + + +//----------------------------------------------------------------------------- +// Computes the closest point to vecTarget no farther than flMaxDist from vecStart +//----------------------------------------------------------------------------- +inline void ComputeClosestPoint2D( const Vector2D& vecStart, float flMaxDist, const Vector2D& vecTarget, Vector2D *pResult ) +{ + Vector2D vecDelta; + Vector2DSubtract( vecTarget, vecStart, vecDelta ); + float flDistSqr = vecDelta.LengthSqr(); + if ( flDistSqr <= flMaxDist * flMaxDist ) + { + *pResult = vecTarget; + } + else + { + vecDelta /= FastSqrt( flDistSqr ); + Vector2DMA( vecStart, flMaxDist, vecDelta, *pResult ); + } +} + + + +//----------------------------------------------------------------------------- +// +// Slow methods +// +//----------------------------------------------------------------------------- + +#ifndef VECTOR_NO_SLOW_OPERATIONS + +//----------------------------------------------------------------------------- +// Returns a Vector2D with the min or max in X, Y, and Z. +//----------------------------------------------------------------------------- + +inline Vector2D Vector2D::Min(const Vector2D &vOther) const +{ + return Vector2D(x < vOther.x ? x : vOther.x, + y < vOther.y ? y : vOther.y); +} + +inline Vector2D Vector2D::Max(const Vector2D &vOther) const +{ + return Vector2D(x > vOther.x ? x : vOther.x, + y > vOther.y ? y : vOther.y); +} + + +//----------------------------------------------------------------------------- +// arithmetic operations +//----------------------------------------------------------------------------- + +inline Vector2D Vector2D::operator-(void) const +{ + return Vector2D(-x,-y); +} + +inline Vector2D Vector2D::operator+(const Vector2D& v) const +{ + Vector2D res; + Vector2DAdd( *this, v, res ); + return res; +} + +inline Vector2D Vector2D::operator-(const Vector2D& v) const +{ + Vector2D res; + Vector2DSubtract( *this, v, res ); + return res; +} + +inline Vector2D Vector2D::operator*(float fl) const +{ + Vector2D res; + Vector2DMultiply( *this, fl, res ); + return res; +} + +inline Vector2D Vector2D::operator*(const Vector2D& v) const +{ + Vector2D res; + Vector2DMultiply( *this, v, res ); + return res; +} + +inline Vector2D Vector2D::operator/(float fl) const +{ + Vector2D res; + Vector2DDivide( *this, fl, res ); + return res; +} + +inline Vector2D Vector2D::operator/(const Vector2D& v) const +{ + Vector2D res; + Vector2DDivide( *this, v, res ); + return res; +} + +inline Vector2D operator*(float fl, const Vector2D& v) +{ + return v * fl; +} + +#endif //slow + +#endif // VECTOR2D_H + diff --git a/external/vpc/public/p4lib/ip4.h b/external/vpc/public/p4lib/ip4.h new file mode 100644 index 0000000..651d613 --- /dev/null +++ b/external/vpc/public/p4lib/ip4.h @@ -0,0 +1,191 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef IP4_H +#define IP4_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlsymbol.h" +#include "tier1/utlvector.h" +#include "tier1/utlstring.h" +#include "appframework/iappsystem.h" + + +//----------------------------------------------------------------------------- +// Current perforce file state +//----------------------------------------------------------------------------- +enum P4FileState_t +{ + P4FILE_UNOPENED = 0, + P4FILE_OPENED_FOR_ADD, + P4FILE_OPENED_FOR_EDIT, + P4FILE_OPENED_FOR_DELETE, + P4FILE_OPENED_FOR_INTEGRATE, +}; + + +//----------------------------------------------------------------------------- +// Purpose: definition of a file +//----------------------------------------------------------------------------- +struct P4File_t +{ + CUtlSymbol m_sName; // file name + CUtlSymbol m_sPath; // residing folder + CUtlSymbol m_sDepotFile; // the name in the depot + CUtlSymbol m_sClientFile; // the name on the client in Perforce syntax + CUtlSymbol m_sLocalFile; // the name on the client in local syntax + int m_iHeadRevision; // head revision number + int m_iHaveRevision; // the revision the clientspec has synced locally + bool m_bOpenedByOther; // opened by another user + bool m_bDir; // directory + bool m_bDeleted; // deleted + P4FileState_t m_eOpenState; // current change state + int m_iChangelist; // changelist current opened in +}; + + +//----------------------------------------------------------------------------- +// Purpose: a single revision of a file +//----------------------------------------------------------------------------- +struct P4Revision_t +{ + int m_iChange; // changelist number + int m_nYear, m_nMonth, m_nDay; + int m_nHour, m_nMinute, m_nSecond; + + CUtlSymbol m_sUser; // submitting user + CUtlSymbol m_sClient; // submitting client + CUtlString m_Description; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a single clientspec +//----------------------------------------------------------------------------- +struct P4Client_t +{ + CUtlSymbol m_sName; + CUtlSymbol m_sUser; + CUtlSymbol m_sHost; // machine name this client is on + CUtlSymbol m_sLocalRoot; // local path +}; + + +//----------------------------------------------------------------------------- +// Purpose: Interface to accessing P4 commands +//----------------------------------------------------------------------------- +#define P4_MAX_INPUT_BUFFER_SIZE 16384 // descriptions should be limited to this size! + +abstract_class IP4 : public IAppSystem +{ +public: + // name of the current clientspec + virtual P4Client_t &GetActiveClient() = 0; + + // changes the current client + virtual void SetActiveClient(const char *clientname) = 0; + + // Refreshes the current client from p4 settings + virtual void RefreshActiveClient() = 0; + + // translate filespecs into the desired syntax + virtual void GetDepotFilePath(char *depotFilePath, const char *filespec, int size) = 0; + virtual void GetClientFilePath(char *clientFilePath, const char *filespec, int size) = 0; + virtual void GetLocalFilePath(char *localFilePath, const char *filespec, int size) = 0; + + // retreives the list of files in a path + virtual CUtlVector<P4File_t> &GetFileList( const char *path ) = 0; + + // returns the list of files opened for edit/integrate/delete + virtual void GetOpenedFileList( CUtlVector<P4File_t> &fileList, bool bDefaultChangeOnly ) = 0; + virtual void GetOpenedFileList( const char *pRootDirectory, CUtlVector<P4File_t> &fileList ) = 0; + virtual void GetOpenedFileListInPath( const char *pPathID, CUtlVector<P4File_t> &fileList ) = 0; + + // retrieves revision history for a file or directory + virtual CUtlVector<P4Revision_t> &GetRevisionList( const char *path, bool bIsDir ) = 0; + + // returns a list of clientspecs + virtual CUtlVector<P4Client_t> &GetClientList() = 0; + + // changes the clientspec to remove the specified path (cloaking) + virtual void RemovePathFromActiveClientspec( const char *path ) = 0; + + // file manipulation + virtual bool OpenFileForAdd( const char *pFullPath ) = 0; + virtual bool OpenFileForEdit( const char *pFullPath ) = 0; + virtual bool OpenFileForDelete( const char *pFullPath ) = 0; + virtual bool SyncFile( const char *pFullPath, int nRevision = -1 ) = 0; // default revision is to sync to the head revision + + // submit/revert + virtual bool SubmitFile( const char *pFullPath, const char *pDescription ) = 0; + virtual bool RevertFile( const char *pFullPath ) = 0; + + // file checkin/checkout for multiple files + virtual bool OpenFilesForAdd( int nCount, const char **ppFullPathList ) = 0; + virtual bool OpenFilesForEdit( int nCount, const char **ppFullPathList ) = 0; + virtual bool OpenFilesForDelete( int nCount, const char **ppFullPathList ) = 0; + + // submit/revert for multiple files + virtual bool SubmitFiles( int nCount, const char **ppFullPathList, const char *pDescription ) = 0; + virtual bool RevertFiles( int nCount, const char **ppFullPathList ) = 0; + + // Is this file in perforce? + virtual bool IsFileInPerforce( const char *pFullPath ) = 0; + + // Get the perforce file state + virtual P4FileState_t GetFileState( const char *pFullPath ) = 0; + + // depot root + virtual const char *GetDepotRoot() = 0; + virtual int GetDepotRootLength() = 0; + + // local root + virtual const char *GetLocalRoot() = 0; + virtual int GetLocalRootLength() = 0; + + // Gets a string for a symbol + virtual const char *String( CUtlSymbol s ) const = 0; + + // Returns which clientspec a file lies under. This will + // search for p4config files in root directories of the file + // It returns false if it didn't find a p4config file. + virtual bool GetClientSpecForFile( const char *pFullPath, char *pClientSpec, int nMaxLen ) = 0; + virtual bool GetClientSpecForDirectory( const char *pFullPathDir, char *pClientSpec, int nMaxLen ) = 0; + + // Returns which clientspec a filesystem path ID lies under. This will + // search for p4config files in all root directories of the all paths in + // the search path. NOTE: All directories in a path need to use the same clientspec + // or this function will return false. + // It returns false if it didn't find a p4config file. + virtual bool GetClientSpecForPath( const char *pPathId, char *pClientSpec, int nMaxLen ) = 0; + + // Opens a file in p4 win + virtual void OpenFileInP4Win( const char *pFullPath ) = 0; + + // have we connected? if not, nothing works + virtual bool IsConnectedToServer( bool bRetry = true ) = 0; + + // Returns file information for a single file + virtual bool GetFileInfo( const char *pFullPath, P4File_t *pFileInfo ) = 0; + + // retrieves the list of files in a path, using a known client spec + virtual CUtlVector<P4File_t> &GetFileListUsingClientSpec( const char *pPath, const char *pClientSpec ) = 0; + + // retrieves the last error from the last op (which is likely to span multiple lines) + // this is only valid after OpenFile[s]For{Add,Edit,Delete} or {Submit,Revert}File[s] + virtual const char *GetLastError() = 0; + + // sets the name of the changelist to open files under, NULL for "Default" changelist + virtual void SetOpenFileChangeList( const char *pChangeListName ) = 0; + + virtual void GetFileListInChangelist( unsigned int changeListNumber, CUtlVector<P4File_t> &fileList ) = 0; +}; + +DECLARE_TIER2_INTERFACE( IP4, p4 ); + +#endif // IP4_H diff --git a/external/vpc/public/tier0/annotations.h b/external/vpc/public/tier0/annotations.h new file mode 100644 index 0000000..d10e530 --- /dev/null +++ b/external/vpc/public/tier0/annotations.h @@ -0,0 +1,116 @@ +#ifndef ANALYSIS_ANNOTATIONS_H +#define ANALYSIS_ANNOTATIONS_H + +#if _MSC_VER >= 1600 // VS 2010 and above. +//----------------------------------------------------------------------------- +// Upgrading important helpful warnings to errors +//----------------------------------------------------------------------------- +#pragma warning(error : 4789 ) // warning C4789: destination of memory copy is too small + +// Suppress some code analysis warnings +#ifdef _PREFAST_ +// Include the annotation header file. +#include <sal.h> + +// /Analyze warnings can only be suppressed when using a compiler that supports them, which VS 2010 +// Professional does not. + +// We don't care about these warnings because they are bugs that can only occur during resource +// exhaustion or other unexpected API failure, which we are nowhere near being able to handle. +#pragma warning(disable : 6308) // warning C6308: 'realloc' might return null pointer: assigning null pointer to 's_ppTestCases', which is passed as an argument to 'realloc', will cause the original memory block to be leaked +#pragma warning(disable : 6255) // warning C6255: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead +#pragma warning(disable : 6387) // warning C6387: 'argument 1' might be '0': this does not adhere to the specification for the function 'GetProcAddress' +#pragma warning(disable : 6309) // warning C6309: Argument '1' is null: this does not adhere to function specification of 'GetProcAddress' +#pragma warning(disable : 6011) // warning C6011: Dereferencing NULL pointer 'm_ppTestCases' +#pragma warning(disable : 6211) // warning C6211: Leaking memory 'newKeyValue' due to an exception. Consider using a local catch block to clean up memory +#pragma warning(disable : 6031) // warning C6031: Return value ignored: '_getcwd' + +// These warnings are because /analyze doesn't like our use of constants, especially things like IsPC() +#pragma warning(disable : 6326) // warning C6326: Potential comparison of a constant with another constant +#pragma warning(disable : 6239) // warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator? +#pragma warning(disable : 6285) // warning C6285: (<non-zero constant> || <non-zero constant>) is always a non-zero constant. Did you intend to use the bitwise-and operator? +#pragma warning(disable : 6237) // warning C6237: (<zero> && <expression>) is always zero. <expression> is never evaluated and might have side effects +#pragma warning(disable : 6235) // warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant +#pragma warning(disable : 6240) // warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator? + +// These warnings aren't really important: +#pragma warning(disable : 6323) // warning C6323: Use of arithmetic operator on Boolean type(s) + +// Miscellaneous other /analyze warnings. We should consider fixing these at some point. +//#pragma warning(disable : 6204) // warning C6204: Possible buffer overrun in call to 'memcpy': use of unchecked parameter 'src' +//#pragma warning(disable : 6262) // warning C6262: Function uses '16464' bytes of stack: exceeds /analyze:stacksize'16384'. Consider moving some data to heap +// This is a serious warning. Don't suppress it. +//#pragma warning(disable : 6263) // warning C6263: Using _alloca in a loop: this can quickly overflow stack +// 6328 is also used for passing __int64 to printf when int is expected so we can't suppress it. +//#pragma warning(disable : 6328) // warning C6328: 'char' passed as parameter '1' when 'unsigned char' is required in call to 'V_isdigit' +// /analyze doesn't like GCOMPILER_ASSERT's implementation of compile-time asserts +#pragma warning(disable : 6326) // warning C6326: Potential comparison of a constant with another constant +#pragma warning(disable : 6335) // warning C6335: Leaking process information handle 'pi.hThread' +#pragma warning(disable : 6320) // warning C6320: Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER. This might mask exceptions that were not intended to be handled +#pragma warning(disable : 6250) // warning C6250: Calling 'VirtualFree' without the MEM_RELEASE flag might free memory but not address descriptors (VADs). This causes address space leaks +#pragma warning(disable : 6384) // ientity2_class_h_schema_gen.cpp(76): warning C6384: Dividing sizeof a pointer by another value + +// For temporarily suppressing warnings -- the warnings are suppressed for the next source line. +#define ANALYZE_SUPPRESS(wnum) __pragma(warning(suppress: wnum)) +#define ANALYZE_SUPPRESS2(wnum1, wnum2) __pragma(warning(supress: wnum1 wnum2)) +#define ANALYZE_SUPPRESS3(wnum1, wnum2, wnum3) __pragma(warning(suppress: wnum1 wnum2 wnum3)) +#define ANALYZE_SUPPRESS4(wnum1, wnum2, wnum3, wnum4) __pragma(warning(suppress: wnum1 wnum2 wnum3 wnum4)) + +// Tag all printf style format strings with this +#define PRINTF_FORMAT_STRING _Printf_format_string_ +#define SCANF_FORMAT_STRING _Scanf_format_string_impl_ +// Various macros for specifying the capacity of the buffer pointed +// to by a function parameter. Variations include in/out/inout, +// CAP (elements) versus BYTECAP (bytes), and null termination or +// not (_Z). +#define IN_Z _In_z_ +#define IN_CAP(x) _In_count_(x) +#define IN_BYTECAP(x) _In_bytecount_(x) +#define OUT_Z_CAP(x) _Out_z_cap_(x) +#define OUT_CAP(x) _Out_cap_(x) +#define OUT_BYTECAP(x) _Out_bytecap_(x) +#define OUT_Z_BYTECAP(x) _Out_z_bytecap_(x) +#define INOUT_BYTECAP(x) _Inout_bytecap_(x) +#define INOUT_Z_CAP(x) _Inout_z_cap_(x) +#define INOUT_Z_BYTECAP(x) _Inout_z_bytecap_(x) +// These macros are use for annotating array reference parameters, typically used in functions +// such as V_strcpy_safe. Because they are array references the capacity is already known. +#if _MSC_VER >= 1700 +#define IN_Z_ARRAY _Pre_z_ +#define OUT_Z_ARRAY _Post_z_ +#define INOUT_Z_ARRAY _Prepost_z_ +#else +#define IN_Z_ARRAY _Deref_pre_z_ +#define OUT_Z_ARRAY _Deref_post_z_ +#define INOUT_Z_ARRAY _Deref_prepost_z_ +#endif // _MSC_VER >= 1700 +// Use the macros above to annotate string functions that fill buffers as shown here, +// in order to give VS's /analyze more opportunities to find bugs. +// void V_wcsncpy( OUT_Z_BYTECAP(maxLenInBytes) wchar_t *pDest, wchar_t const *pSrc, int maxLenInBytes ); +// int V_snwprintf( OUT_Z_CAP(maxLenInCharacters) wchar_t *pDest, int maxLenInCharacters, PRINTF_FORMAT_STRING const wchar_t *pFormat, ... ); + +#endif // _PREFAST_ +#endif // _MSC_VER >= 1600 // VS 2010 and above. + +#ifndef ANALYZE_SUPPRESS +#define ANALYZE_SUPPRESS(wnum) +#define ANALYZE_SUPPRESS2(wnum1, wnum2) +#define ANALYZE_SUPPRESS3(wnum1, wnum2, wnum3) +#define ANALYZE_SUPPRESS4(wnum1, wnum2, wnum3, wnum4) +#define PRINTF_FORMAT_STRING +#define SCANF_FORMAT_STRING +#define IN_Z +#define IN_CAP(x) +#define IN_BYTECAP(x) +#define OUT_Z_CAP(x) +#define OUT_CAP(x) +#define OUT_BYTECAP(x) +#define OUT_Z_BYTECAP(x) +#define INOUT_BYTECAP(x) +#define INOUT_Z_CAP(x) +#define INOUT_Z_BYTECAP(x) +#define OUT_Z_ARRAY +#define INOUT_Z_ARRAY +#endif + +#endif // ANALYSIS_ANNOTATIONS_H diff --git a/external/vpc/public/tier0/basetypes.h b/external/vpc/public/tier0/basetypes.h new file mode 100644 index 0000000..caa297e --- /dev/null +++ b/external/vpc/public/tier0/basetypes.h @@ -0,0 +1,650 @@ +//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef BASETYPES_H +#define BASETYPES_H + +#ifdef COMPILER_MSVC +#pragma once +#endif + +// This is a trick to get the DLL extension off the -D option on the command line. +#define DLLExtTokenPaste(x) #x +#define DLLExtTokenPaste2(x) DLLExtTokenPaste(x) +#define DLL_EXT_STRING DLLExtTokenPaste2( _DLL_EXT ) + +////////////////////////////////////////////////////////////////////////// + +#ifndef schema +#define schema namespace ValveSchemaMarker {} +#endif + +#ifdef COMPILING_SCHEMA +#define UNSCHEMATIZED_METHOD( x ) +#else +#define UNSCHEMATIZED_METHOD( x ) x +#endif + +////////////////////////////////////////////////////////////////////////// + +#include "tier0/platform.h" +#include "commonmacros.h" +#include "wchartypes.h" +#ifdef _PS3 +#include <float.h> +#elif defined( PLATFORM_POSIX ) +#include <math.h> +#endif + +#include "tier0/valve_off.h" + +// There's a different version of this file in the xbox codeline +// so the PC version built in the xbox branch includes things like +// tickrate changes. +#include "xbox_codeline_defines.h" + +#if defined(_PS3) +#include <ppu_intrinsics.h> +#include <sys/fs.h> +#define PATH_MAX CELL_FS_MAX_FS_PATH_LENGTH +#define _MAX_PATH PATH_MAX +#endif +// stdio.h +#ifndef NULL +#define NULL 0 +#endif + +#ifdef PLATFORM_POSIX +#include <stdint.h> + +template<class T> +T abs( const T &a ) +{ + if ( a < 0 ) + return -a; + else + return a; +} +#endif + +#define ExecuteNTimes( nTimes, x ) \ + { \ + static int __executeCount=0;\ + if ( __executeCount < nTimes )\ + { \ + ++__executeCount; \ + x; \ + } \ + } + + +#define ExecuteOnce( x ) ExecuteNTimes( 1, x ) + + + +// Pad a number so it lies on an N byte boundary. +// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4 +#define PAD_NUMBER(number, boundary) \ + ( ((number) + ((boundary)-1)) / (boundary) ) * (boundary) + +// In case this ever changes +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +// #define COMPILETIME_MAX and COMPILETIME_MIN for max/min in constant expressions +#define COMPILETIME_MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#define COMPILETIME_MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#ifndef MIN +#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#endif + +#ifndef MAX +#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) +#endif + + + + +#ifdef __cplusplus + +template< class T, class Y, class X > +inline T clamp( T const &val, Y const &minVal, X const &maxVal ) +{ + if( val < minVal ) + return minVal; + else if( val > maxVal ) + return maxVal; + else + return val; +} + +#else + +#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val))) + +#endif + +#ifndef FALSE +#define FALSE 0 +#define TRUE (!FALSE) +#endif + +//----------------------------------------------------------------------------- +// fsel +//----------------------------------------------------------------------------- +#if !defined(_PS3) && !defined(_X360) + +#define fsel(c,x,y) ( (c) >= 0 ? (x) : (y) ) + +// integer conditional move +// if a >= 0, return x, else y +#define isel(a,x,y) ( ((a) >= 0) ? (x) : (y) ) + +// if x = y, return a, else b +#define ieqsel(x,y,a,b) (( (x) == (y) ) ? (a) : (b)) + +// if the nth bit of a is set (counting with 0 = LSB), +// return x, else y +// this is fast if nbit is a compile-time immediate +#define ibitsel(a, nbit, x, y) ( ( ((a) & (1 << (nbit))) != 0 ) ? (x) : (y) ) + + +FORCEINLINE double fpmin( double a, double b ) +{ + return a > b ? b : a; +} + +FORCEINLINE double fpmax( double a, double b ) +{ + return a >= b ? a : b; +} + +// clamp x to lie inside [a,b]. Assumes b>a +FORCEINLINE float fclamp( float x, float a, float b ) +{ + return fpmin( fpmax( x, a ), b ); +} +// clamp x to lie inside [a,b]. Assumes b>a +FORCEINLINE double fclamp( double x, double a, double b ) +{ + return fpmin( fpmax( x, a ), b ); +} + +// At some point, we will need a unified API. +#define imin( x, y ) ( (x) < (y) ? (x) : (y) ) +#define imax( x, y ) ( (x) > (y) ? (x) : (y) ) +#define iclamp clamp + +#else + +// __fsel(double fComparand, double fValGE, double fLT) == fComparand >= 0 ? fValGE : fLT +// this is much faster than if ( aFloat > 0 ) { x = .. } +// the XDK defines two intrinsics, one for floats and one for doubles -- it's the same +// opcode, but the __fself version tells the compiler not to do a wasteful unnecessary +// rounding op after each sel. +// #define fsel __fsel +#ifdef _X360 +FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) { return __fsel( fComparand, fValGE, fLT ); } +FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) { return __fself( fComparand, fValGE, fLT ); } +#else +FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) { return __fsel( fComparand, fValGE, fLT ); } +FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) { return __fsels( fComparand, fValGE, fLT ); } +#endif + +#if !defined(_X360) +FORCEINLINE float fpmin( float a, float b ) +{ + return fsel( a-b, b,a); +} +FORCEINLINE double fpmin( double a, double b ) +{ + return fsel( a-b, b,a); +} + +FORCEINLINE float fpmax( float a, float b ) +{ + return fsel( a-b, a,b); +} +FORCEINLINE double fpmax( double a, double b ) +{ + return fsel( a-b, a,b); +} + +// any mixed calls should promote to double +FORCEINLINE double fpmax(float a, double b) +{ + return fpmax( (double) a, b ); +} +// any mixed calls should promote to double +FORCEINLINE double fpmax(double a, float b) +{ + return fpmax( (double) a, (double) b ); +} +#endif + +// clamp x to lie inside [a,b]. Assumes b>a +FORCEINLINE float fclamp( float x, float a, float b ) +{ + return fpmin( fpmax( x, a ), b ); +} +// clamp x to lie inside [a,b]. Assumes b>a +FORCEINLINE double fclamp( double x, double a, double b ) +{ + return fpmin( fpmax( x, a ), b ); +} + +// if a >= 0, return x, else y +FORCEINLINE int isel( int a, int x, int y ) +{ + int mask = a >> 31; // arithmetic shift right, splat out the sign bit + return x + ((y - x) & mask); +}; + +// if a >= 0, return x, else y +FORCEINLINE unsigned isel( int a, unsigned x, unsigned y ) +{ + int mask = a >> 31; // arithmetic shift right, splat out the sign bit + return x + ((y - x) & mask); +}; + +// ( x == y ) ? a : b +FORCEINLINE unsigned ieqsel( unsigned x, unsigned y, unsigned a, unsigned b ) +{ + unsigned mask = (x == y) ? 0 : -1; + return a + ((b - a) & mask); +}; + +// ( x == y ) ? a : b +FORCEINLINE int ieqsel( int x, int y, int a, int b ) +{ + int mask = (x == y) ? 0 : -1; + return a + ((b - a) & mask); +}; + +FORCEINLINE int imin( int x, int y ) +{ + int nMaxSign = x - y; // Positive if x greater than y + int nMaxMask = nMaxSign >> 31; // 0 if x greater than y, 0xffffffff if x smaller than y + int nMaxSaturated = y + ( nMaxSign & nMaxMask ); + return nMaxSaturated; +} + +FORCEINLINE int imax( int x, int y ) +{ + int nMinSign = y - x; // Positive if x smaller than y + int nMinMask = nMinSign >> 31; // 0 if x smaller than y, 0xffffffff if x greater than y + int nMinSaturated = y - ( nMinSign & nMinMask); + return nMinSaturated; +} + +FORCEINLINE int iclamp( int x, int min, int max ) +{ + int nResult = imin( x, max ); + return imax( nResult, min ); +} + +// if the nth bit of a is set (counting with 0 = LSB), +// return x, else y +// this is fast if nbit is a compile-time immediate +#define ibitsel(a, nbit, x, y) ( (x) + (((y) - (x)) & (((a) & (1 << (nbit))) ? 0 : -1)) ) + +#endif + +#if CROSS_PLATFORM_VERSION < 1 + +#ifndef DONT_DEFINE_BOOL // Needed for Cocoa stuff to compile. +typedef int BOOL; +#endif + +typedef int qboolean; +//typedef uint32 ULONG; +typedef uint8 BYTE; +typedef uint8 byte; +typedef uint16 word; +#endif + +#if defined( _WIN32 ) || defined( _PS3 ) +typedef wchar_t ucs2; // under windows & PS3 wchar_t is ucs2 +#else +typedef unsigned short ucs2; +#endif + +enum ThreeState_t +{ + TRS_FALSE, + TRS_TRUE, + TRS_NONE, +}; + +typedef float vec_t; +#ifdef _WIN32 +typedef __int32 vec_t_as_gpr; // a general purpose register type equal in size to a vec_t (in case we have to avoid the fpu for some reason) +#endif + + +template <typename T> +inline T AlignValue( T val, uintp alignment ) +{ + return (T)( ( (uintp)val + alignment - 1 ) & ~( alignment - 1 ) ); +} + + +// FIXME: this should move +#ifndef __cplusplus +#define true TRUE +#define false FALSE +#endif + +//----------------------------------------------------------------------------- +// look for NANs, infinities, and underflows. +// This assumes the ANSI/IEEE 754-1985 standard +//----------------------------------------------------------------------------- + +#ifdef __cplusplus + +inline uint32 FloatBits( const vec_t &f ) +{ + union Convertor_t + { + vec_t f; + uint32 ul; + }tmp; + + switch( false ) { case false: ; case (sizeof( tmp ) == 4 && sizeof( tmp.f ) == 4 && sizeof( tmp.ul ) == 4):; }; + tmp.f = f; + return tmp.ul; +} + +inline vec_t BitsToFloat( uint32 i ) +{ + union Convertor_t + { + vec_t f; + uint32 ul; + }tmp; + switch( false ) { case false: ; case (sizeof( tmp ) == 4 && sizeof( tmp.f ) == 4 && sizeof( tmp.ul ) == 4 ):; }; + tmp.ul = i; + return tmp.f; +} + +inline bool IsFinite( const vec_t &f ) +{ +#ifdef _GAMECONSOLE + return f == f && fabs(f) <= FLT_MAX; +#else + return ((FloatBits(f) & 0x7F800000) != 0x7F800000); +#endif +} + +#if defined( WIN32 ) + +//#include <math.h> +// Just use prototype from math.h +#ifdef __cplusplus +extern "C" +{ +#endif + double __cdecl fabs(double); + //_CRT_JIT_INTRINSIC _CRTIMP float __cdecl fabsf( __in float _X); + float __cdecl fabsf( _In_ float ); +#ifdef __cplusplus +} +#endif + +// In win32 try to use the intrinsic fabs so the optimizer can do it's thing inline in the code +#pragma intrinsic( fabs ) +// Also, alias float make positive to use fabs, too +// NOTE: Is there a perf issue with double<->float conversion? +inline float FloatMakePositive( vec_t f ) +{ + return fabsf( f ); +} +#else +inline float FloatMakePositive( vec_t f ) +{ + return fabsf(f); // was since 2002: BitsToFloat( FloatBits(f) & 0x7FFFFFFF ); fixed in 2010 +} +#endif + +inline float FloatNegate( vec_t f ) +{ + return -f; //BitsToFloat( FloatBits(f) ^ 0x80000000 ); +} + + +#define FLOAT32_NAN_BITS (uint32)0x7FC00000 // not a number! +#define FLOAT32_NAN BitsToFloat( FLOAT32_NAN_BITS ) + +#define VEC_T_NAN FLOAT32_NAN + +#endif + +inline float FloatMakeNegative( vec_t f ) +{ + return -fabsf( f );// was since 2002: BitsToFloat( FloatBits(f) | 0x80000000 ); fixed in 2010 +} + + +// FIXME: why are these here? Hardly anyone actually needs them. +struct color24 +{ + byte r, g, b; +}; + +typedef struct color32_s +{ + bool operator!=( const struct color32_s &other ) const; + byte r, g, b, a; + + // assign and copy by using the whole register rather + // than byte-by-byte copy. (No, the compiler is not + // smart enough to do this for you. /FAcs if you + // don't believe me.) + inline unsigned *asInt(void) { return reinterpret_cast<unsigned*>(this); } + inline const unsigned *asInt(void) const { return reinterpret_cast<const unsigned*>(this); } + // This thing is in a union elsewhere, and union members can't have assignment + // operators, so you have to explicitly assign using this, or be slow. SUCK. + inline void Copy(const color32_s &rhs) + { + *asInt() = *rhs.asInt(); + } + +} color32; + +inline bool color32::operator!=( const color32 &other ) const +{ + return r != other.r || g != other.g || b != other.b || a != other.a; +} + +struct colorVec +{ + unsigned r, g, b, a; +}; + + +#ifndef NOTE_UNUSED +#define NOTE_UNUSED(arg) ((void)arg) // for pesky compiler / lint warnings +#endif +#ifdef __cplusplus + +struct vrect_t +{ + int x,y,width,height; + vrect_t *pnext; +}; + +#endif + + +//----------------------------------------------------------------------------- +// MaterialRect_t struct - used for DrawDebugText +//----------------------------------------------------------------------------- +struct Rect_t +{ + int x, y; + int width, height; +}; + +struct Rect3D_t +{ + int x, y, z; + int width, height, depth; + + FORCEINLINE Rect3D_t( int nX, int nY, int nZ, int nWidth, int nHeight, int nDepth ) + { + x = nX; + y = nY; + z = nZ; + width = nWidth; + height = nHeight; + depth = nDepth; + } + + FORCEINLINE Rect3D_t( void ) + { + } + +}; + + + +//----------------------------------------------------------------------------- +// Interval, used by soundemittersystem + the game +//----------------------------------------------------------------------------- +struct interval_t +{ + float start; + float range; +}; + + +//----------------------------------------------------------------------------- +// Declares a type-safe handle type; you can't assign one handle to the next +//----------------------------------------------------------------------------- + +// 32-bit pointer handles. + +// Typesafe 8-bit and 16-bit handles. +template< class HandleType > +class CBaseIntHandle +{ +public: + + inline bool operator==( const CBaseIntHandle &other ) { return m_Handle == other.m_Handle; } + inline bool operator!=( const CBaseIntHandle &other ) { return m_Handle != other.m_Handle; } + + // Only the code that doles out these handles should use these functions. + // Everyone else should treat them as a transparent type. + inline HandleType GetHandleValue() { return m_Handle; } + inline void SetHandleValue( HandleType val ) { m_Handle = val; } + + typedef HandleType HANDLE_TYPE; + +protected: + + HandleType m_Handle; +}; + +template< class DummyType > +class CIntHandle16 : public CBaseIntHandle< unsigned short > +{ +public: + inline CIntHandle16() {} + + static inline CIntHandle16<DummyType> MakeHandle( HANDLE_TYPE val ) + { + return CIntHandle16<DummyType>( val ); + } + +protected: + inline CIntHandle16( HANDLE_TYPE val ) + { + m_Handle = val; + } +}; + + +template< class DummyType > +class CIntHandle32 : public CBaseIntHandle< uint32 > +{ +public: + inline CIntHandle32() {} + + static inline CIntHandle32<DummyType> MakeHandle( HANDLE_TYPE val ) + { + return CIntHandle32<DummyType>( val ); + } + +protected: + inline CIntHandle32( HANDLE_TYPE val ) + { + m_Handle = val; + } +}; + + +// NOTE: This macro is the same as windows uses; so don't change the guts of it +#define DECLARE_HANDLE_16BIT(name) typedef CIntHandle16< struct name##__handle * > name; +#define DECLARE_HANDLE_32BIT(name) typedef CIntHandle32< struct name##__handle * > name; + +#define DECLARE_POINTER_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name +#define FORWARD_DECLARE_HANDLE(name) typedef struct name##__ *name + +#define DECLARE_DERIVED_POINTER_HANDLE( _name, _basehandle ) struct _name##__ : public _basehandle##__ {}; typedef struct _name##__ *_name +#define DECLARE_ALIASED_POINTER_HANDLE( _name, _alias ) typedef struct _alias##__ *name + +// @TODO: Find a better home for this +#if !defined(_STATIC_LINKED) && !defined(PUBLISH_DLL_SUBSYSTEM) +// for platforms built with dynamic linking, the dll interface does not need spoofing +#define PUBLISH_DLL_SUBSYSTEM() +#endif + +#define UID_PREFIX generated_id_ +#define UID_CAT1(a,c) a ## c +#define UID_CAT2(a,c) UID_CAT1(a,c) +#define EXPAND_CONCAT(a,c) UID_CAT1(a,c) +#ifdef _MSC_VER +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__COUNTER__) +#else +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__LINE__) +#endif + +#define _MKSTRING(arg) #arg +#define MKSTRING(arg) _MKSTRING(arg) + + +// this allows enumerations to be used as flags, and still remain type-safe! +#define DEFINE_ENUM_BITWISE_OPERATORS( Type ) \ + inline Type operator| ( Type a, Type b ) { return Type( int( a ) | int( b ) ); } \ + inline Type operator& ( Type a, Type b ) { return Type( int( a ) & int( b ) ); } \ + inline Type operator^ ( Type a, Type b ) { return Type( int( a ) ^ int( b ) ); } \ + inline Type operator<< ( Type a, int b ) { return Type( int( a ) << b ); } \ + inline Type operator>> ( Type a, int b ) { return Type( int( a ) >> b ); } \ + inline Type &operator|= ( Type &a, Type b ) { return a = a | b; } \ + inline Type &operator&= ( Type &a, Type b ) { return a = a & b; } \ + inline Type &operator^= ( Type &a, Type b ) { return a = a ^ b; } \ + inline Type &operator<<=( Type &a, int b ) { return a = a << b; } \ + inline Type &operator>>=( Type &a, int b ) { return a = a >> b; } \ + inline Type operator~( Type a ) { return Type( ~int( a ) ); } + +// defines increment/decrement operators for enums for easy iteration +#define DEFINE_ENUM_INCREMENT_OPERATORS( Type ) \ + inline Type &operator++( Type &a ) { return a = Type( int( a ) + 1 ); } \ + inline Type &operator--( Type &a ) { return a = Type( int( a ) - 1 ); } \ + inline Type operator++( Type &a, int ) { Type t = a; ++a; return t; } \ + inline Type operator--( Type &a, int ) { Type t = a; --a; return t; } + +// Max 2 player splitscreen in portal (don't merge this back), saves a bunch of memory [8/31/2010 tom] +#define MAX_SPLITSCREEN_CLIENT_BITS 1 +// this should == MAX_JOYSTICKS in InputEnums.h +#define MAX_SPLITSCREEN_CLIENTS ( 1 << MAX_SPLITSCREEN_CLIENT_BITS ) // 2 + +#include "tier0/valve_on.h" + +#endif // BASETYPES_H diff --git a/external/vpc/public/tier0/commonmacros.h b/external/vpc/public/tier0/commonmacros.h new file mode 100644 index 0000000..1c12442 --- /dev/null +++ b/external/vpc/public/tier0/commonmacros.h @@ -0,0 +1,149 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef COMMONMACROS_H +#define COMMONMACROS_H + +#ifdef _WIN32 +#pragma once +#endif + +// ------------------------------------------------------- +// +// commonmacros.h +// +// This should contain ONLY general purpose macros that are +// appropriate for use in engine/launcher/all tools +// +// ------------------------------------------------------- + +// Makes a 4-byte "packed ID" int out of 4 characters +#define MAKEID(d,c,b,a) ( ((int)(a) << 24) | ((int)(b) << 16) | ((int)(c) << 8) | ((int)(d)) ) + +// Compares a string with a 4-byte packed ID constant +#define STRING_MATCHES_ID( p, id ) ( (*((int *)(p)) == (id) ) ? true : false ) +#define ID_TO_STRING( id, p ) ( (p)[3] = (((id)>>24) & 0xFF), (p)[2] = (((id)>>16) & 0xFF), (p)[1] = (((id)>>8) & 0xFF), (p)[0] = (((id)>>0) & 0xFF) ) + +#define V_ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +#define SETBITS(iBitVector, bits) ((iBitVector) |= (bits)) +#define CLEARBITS(iBitVector, bits) ((iBitVector) &= ~(bits)) +#define FBitSet(iBitVector, bits) ((iBitVector) & (bits)) + +inline bool IsPowerOfTwo( int value ) +{ + return (value & ( value - 1 )) == 0; +} + +#ifndef REFERENCE +#define REFERENCE(arg) ((void)arg) +#endif + +#define CONST_INTEGER_AS_STRING(x) #x //Wraps the integer in quotes, allowing us to form constant strings with it +#define __HACK_LINE_AS_STRING__(x) CONST_INTEGER_AS_STRING(x) //__LINE__ can only be converted to an actual number by going through this, otherwise the output is literally "__LINE__" +#define __LINE__AS_STRING __HACK_LINE_AS_STRING__(__LINE__) //Gives you the line number in constant string form + +// Using ARRAYSIZE implementation from winnt.h: +#ifdef ARRAYSIZE +#undef ARRAYSIZE +#endif + +// Return the number of elements in a statically sized array. +// DWORD Buffer[100]; +// RTL_NUMBER_OF(Buffer) == 100 +// This is also popularly known as: NUMBER_OF, ARRSIZE, _countof, NELEM, etc. +// +#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) + +#if defined(__cplusplus) && \ + !defined(MIDL_PASS) && \ + !defined(RC_INVOKED) && \ + !defined(_PREFAST_) && \ + (_MSC_FULL_VER >= 13009466) && \ + !defined(SORTPP_PASS) + +// From crtdefs.h +#if !defined(UNALIGNED) +#if defined(_M_IA64) || defined(_M_AMD64) +#define UNALIGNED __unaligned +#else +#define UNALIGNED +#endif +#endif + +// RtlpNumberOf is a function that takes a reference to an array of N Ts. +// +// typedef T array_of_T[N]; +// typedef array_of_T &reference_to_array_of_T; +// +// RtlpNumberOf returns a pointer to an array of N chars. +// We could return a reference instead of a pointer but older compilers do not accept that. +// +// typedef char array_of_char[N]; +// typedef array_of_char *pointer_to_array_of_char; +// +// sizeof(array_of_char) == N +// sizeof(*pointer_to_array_of_char) == N +// +// pointer_to_array_of_char RtlpNumberOf(reference_to_array_of_T); +// +// We never even call RtlpNumberOf, we just take the size of dereferencing its return type. +// We do not even implement RtlpNumberOf, we just decare it. +// +// Attempts to pass pointers instead of arrays to this macro result in compile time errors. +// That is the point. +extern "C++" // templates cannot be declared to have 'C' linkage +template <typename T, size_t N> +char (*RtlpNumberOf( UNALIGNED T (&)[N] ))[N]; + +#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A))) + +// This does not work with: +// +// void Foo() +// { +// struct { int x; } y[2]; +// RTL_NUMBER_OF_V2(y); // illegal use of anonymous local type in template instantiation +// } +// +// You must instead do: +// +// struct Foo1 { int x; }; +// +// void Foo() +// { +// Foo1 y[2]; +// RTL_NUMBER_OF_V2(y); // ok +// } +// +// OR +// +// void Foo() +// { +// struct { int x; } y[2]; +// RTL_NUMBER_OF_V1(y); // ok +// } +// +// OR +// +// void Foo() +// { +// struct { int x; } y[2]; +// _ARRAYSIZE(y); // ok +// } + +#else +#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A) +#endif + +// ARRAYSIZE is more readable version of RTL_NUMBER_OF_V2 +// _ARRAYSIZE is a version useful for anonymous types +#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A) +#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) + +#endif // COMMONMACROS_H + diff --git a/external/vpc/public/tier0/dbg.h b/external/vpc/public/tier0/dbg.h new file mode 100644 index 0000000..2e54a47 --- /dev/null +++ b/external/vpc/public/tier0/dbg.h @@ -0,0 +1,716 @@ +//===== Copyright (c) Valve Corporation, All rights reserved. ========// +// +// Purpose: +// +// $NoKeywords: $ +// +//====================================================================// +#ifndef DBG_H +#define DBG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier0/basetypes.h" +#include "dbgflag.h" +#include "logging.h" +#include <math.h> +#include <stdio.h> +#include <stdarg.h> + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- + +class Color; + + +//----------------------------------------------------------------------------- +// Usage model for the Dbg library +// +// 1. Assertions. +// +// Assertions are used to detect and warn about invalid states +// +// To use an assertion, use +// +// Assert( (f == 5) ); +// AssertMsg( (f == 5), ("F needs to be %d here!\n", 5) ); +// AssertFunc( (f == 5), BadFunc() ); +// AssertEquals( f, 5 ); +// AssertFloatEquals( f, 5.0f, 1e-3 ); +// +// The first will simply report that an assertion failed on a particular +// code file and line. The second version will display a print-f formatted message +// along with the file and line, the third will display a generic message and +// will also cause the function BadFunc to be executed, and the last two +// will report an error if f is not equal to 5 (the last one asserts within +// a particular tolerance). +// +// 2. Code activation +// +// To cause code to be run only in debug builds, use DBG_CODE: +// An example is below. +// +// DBG_CODE( +// { +// int x = 5; +// ++x; +// } +// ); +// +// Code can be activated based on the dynamic spew groups also. Use +// +// DBG_DCODE( "group", level, +// { int x = 5; ++x; } +// ); +// +// 3. Breaking into the debugger. +// +// To cause an unconditional break into the debugger in debug builds only, use DBG_BREAK +// +// DBG_BREAK(); +// +// You can force a break in any build (release or debug) using +// +// DebuggerBreak(); +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE void _ExitOnFatalAssert( const tchar* pFile, int line ); + +#if defined( DBGFLAG_STRINGS_STRIP ) +#define DbgFlagMacro_ExitOnFatalAssert( pFile, line ) _ExitOnFatalAssert( "", 0 ) +#else +#define DbgFlagMacro_ExitOnFatalAssert( pFile, line ) _ExitOnFatalAssert( pFile, line ) +#endif + +PLATFORM_INTERFACE bool ShouldUseNewAssertDialog(); + +PLATFORM_INTERFACE bool SetupWin32ConsoleIO(); + +// Returns true if they want to break in the debugger. +PLATFORM_INTERFACE bool DoNewAssertDialog( const tchar *pFile, int line, const tchar *pExpression ); + +#if defined( DBGFLAG_STRINGS_STRIP ) +#define DbgFlagMacro_DoNewAssertDialog( pFile, line, pExpression ) DoNewAssertDialog( "", 0, "" ) +#else +#define DbgFlagMacro_DoNewAssertDialog( pFile, line, pExpression ) DoNewAssertDialog( pFile, line, pExpression ) +#endif + +/* Used to define macros, never use these directly. */ + +#ifdef _PREFAST_ + // When doing /analyze builds define the assert macros to be __analysis_assume. This tells + // the compiler to assume that the condition is true, which helps to suppress many + // warnings. This define is done in debug and release builds, but debug builds should be + // preferred for static analysis because some asserts are compiled out in release. + // The unfortunate !! is necessary because otherwise /analyze is incapable of evaluating + // all of the logical expressions that the regular compiler can handle. + #define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) __analysis_assume( !!(_exp) ) + #define _AssertMsgOnce( _exp, _msg, _bFatal ) __analysis_assume( !!(_exp) ) + // Force asserts on for /analyze so that we get a __analysis_assume of all of the constraints. + #define DBGFLAG_ASSERT + #define DBGFLAG_ASSERTFATAL +#else + #define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) \ + do { \ + if (!(_exp)) \ + { \ + LoggingResponse_t ret = Log_Assert( "%s (%d) : %s\n", __TFILE__, __LINE__, _msg ); \ + _executeExp; \ + if ( ret == LR_DEBUGGER ) \ + { \ + if ( !ShouldUseNewAssertDialog() || DbgFlagMacro_DoNewAssertDialog( __TFILE__, __LINE__, _msg ) ) \ + DebuggerBreak(); \ + if ( _bFatal ) \ + DbgFlagMacro_ExitOnFatalAssert( __TFILE__, __LINE__ ); \ + } \ + } \ + } while (0) + + #define _AssertMsgOnce( _exp, _msg, _bFatal ) \ + do { \ + static bool fAsserted; \ + if (!fAsserted ) \ + { \ + _AssertMsg( _exp, _msg, (fAsserted = true), _bFatal ); \ + } \ + } while (0) +#endif + +/* Spew macros... */ + +// AssertFatal macros +// AssertFatal is used to detect an unrecoverable error condition. +// If enabled, it may display an assert dialog (if DBGFLAG_ASSERTDLG is turned on or running under the debugger), +// and always terminates the application + +#ifdef DBGFLAG_ASSERTFATAL + +#define AssertFatal( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), true ) +#define AssertFatalOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), true ) +#define AssertFatalMsg( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), true ) +#define AssertFatalMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, true ) +#define AssertFatalFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: " _T(#_exp), _f, true ) +#define AssertFatalEquals( _exp, _expectedValue ) AssertFatalMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) ) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) AssertFatalMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) ) +#define VerifyFatal( _exp ) AssertFatal( _exp ) +#define VerifyEqualsFatal( _exp, _expectedValue ) AssertFatalEquals( _exp, _expectedValue ) + +#define AssertFatalMsg1( _exp, _msg, a1 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1 ))) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2 ))) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3 ))) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4 ))) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5 ))) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ))) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ))) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7 ))) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8 ))) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ))) + +#else // DBGFLAG_ASSERTFATAL + +#define AssertFatal( _exp ) ((void)0) +#define AssertFatalOnce( _exp ) ((void)0) +#define AssertFatalMsg( _exp, _msg ) ((void)0) +#define AssertFatalMsgOnce( _exp, _msg ) ((void)0) +#define AssertFatalFunc( _exp, _f ) ((void)0) +#define AssertFatalEquals( _exp, _expectedValue ) ((void)0) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define VerifyFatal( _exp ) (_exp) +#define VerifyEqualsFatal( _exp, _expectedValue ) (_exp) + +#define AssertFatalMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif // DBGFLAG_ASSERTFATAL + +// lightweight assert macros: in theory, can be run in release without slowing it down +#if defined(_CERT) || defined(_RETAIL) +#define AssertAligned(PTR) +#else +# if defined( _X360 ) +# define AssertAligned(PTR) __twnei( intp(PTR) & 0xF, 0 ) // trap if not equal to immediate value; unsigned comparison +# elif defined( DBGFLAG_ASSERT ) +# define AssertAligned( adr ) Assert( ( ( ( intp ) ( adr ) ) & 0xf ) == 0 ) +# else +# define AssertAligned(PTR) +# endif +#endif + +// Assert macros +// Assert is used to detect an important but survivable error. +// It's only turned on when DBGFLAG_ASSERT is true. + +#ifdef DBGFLAG_ASSERT + +#define Assert( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) +#define AssertMsg_( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), false ) +#define AssertOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), false ) +#define AssertMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, false ) +#define AssertFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), _f, false ) +#define AssertEquals( _exp, _expectedValue ) AssertMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) ) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) AssertMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) ) +#define Verify( _exp ) Assert( _exp ) +#define VerifyEquals( _exp, _expectedValue ) AssertEquals( _exp, _expectedValue ) + +#define AssertMsg( _exp, _msg ) AssertMsg_( _exp, _T( _msg ) ) +#define AssertMsg1( _exp, _msg, a1 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1 )) ) +#define AssertMsg2( _exp, _msg, a1, a2 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2 )) ) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3 )) ) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4 )) ) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5 )) ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6 )) ) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7 )) ) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7, a8 )) ) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7, a8, a9 )) ) + +#else // DBGFLAG_ASSERT + +#define Assert( _exp ) ((void)0) +#define AssertOnce( _exp ) ((void)0) +#define AssertMsg( _exp, _msg ) ((void)0) +#define AssertMsgOnce( _exp, _msg ) ((void)0) +#define AssertFunc( _exp, _f ) ((void)0) +#define AssertEquals( _exp, _expectedValue ) ((void)0) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define Verify( _exp ) (_exp) +#define VerifyEquals( _exp, _expectedValue ) (_exp) + +#define AssertMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif // DBGFLAG_ASSERT + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + +#define FILE_LINE_FUNCTION_STRING __FILE__ "(" STRINGIFY(__LINE__) "):" __FUNCTION__ ":" +#define FILE_LINE_STRING __FILE__ "(" STRINGIFY(__LINE__) "):" +#define FUNCTION_LINE_STRING __FUNCTION__ "(" STRINGIFY(__LINE__) "): " + + +////////////////////////////////////////////////////////////////////////// +// Legacy Logging System +////////////////////////////////////////////////////////////////////////// + +// Channels which map the legacy logging system to the new system. + +// Channel for all default Msg/Warning/Error commands. +DECLARE_LOGGING_CHANNEL( LOG_GENERAL ); +// Channel for all asserts. +DECLARE_LOGGING_CHANNEL( LOG_ASSERT ); +// Channel for all ConMsg and ConColorMsg commands. +DECLARE_LOGGING_CHANNEL( LOG_CONSOLE ); +// Channel for all DevMsg and DevWarning commands with level < 2. +DECLARE_LOGGING_CHANNEL( LOG_DEVELOPER ); +// Channel for ConDMsg commands. +DECLARE_LOGGING_CHANNEL( LOG_DEVELOPER_CONSOLE ); +// Channel for all DevMsg and DevWarning commands with level >= 2. +DECLARE_LOGGING_CHANNEL( LOG_DEVELOPER_VERBOSE ); + +// Legacy logging functions + +PLATFORM_INTERFACE void Error( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_INTERFACE void Error_SpewCallStack( int iMaxCallStackLength, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +#if defined( DBGFLAG_STRINGS_STRIP ) && !defined( TIER0_DLL_EXPORT ) + +#define Msg( ... ) ((void)0) +#define Warning( ... ) ((void)0) +#define Warning_SpewCallStack( ... ) ((void)0) +#define DevMsg( ... ) ((void)0) +#define DevWarning( ... ) ((void)0) +#define ConColorMsg( ... ) ((void)0) +#define ConMsg( ... ) ((void)0) +#define ConDMsg( ... ) ((void)0) +#define COM_TimestampedLog( ... ) ((void)0) + +#else // #if defined( DBGFLAG_STRINGS_STRIP ) && !defined( TIER0_DLL_EXPORT ) + +PLATFORM_INTERFACE void Msg( const tchar* pMsg, ... ); +PLATFORM_INTERFACE void Warning( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_INTERFACE void Warning_SpewCallStack( int iMaxCallStackLength, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +#ifdef _PS3 + +PLATFORM_OVERLOAD void DevMsg( int level, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_OVERLOAD void DevWarning( int level, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +PLATFORM_INTERFACE void DevMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_INTERFACE void DevWarning( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); + +PLATFORM_INTERFACE void ConColorMsg( const Color& clr, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_INTERFACE void ConMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); + +#else // !_PS3 + +PLATFORM_INTERFACE void DevMsg( int level, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_INTERFACE void DevWarning( int level, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +PLATFORM_OVERLOAD void DevMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_OVERLOAD void DevWarning( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); + +PLATFORM_OVERLOAD void ConColorMsg( const Color& clr, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_OVERLOAD void ConMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); + +#endif // _PS3 + +PLATFORM_INTERFACE void ConDMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); + +PLATFORM_INTERFACE void COM_TimestampedLog( char const *fmt, ... ) FMTFUNCTION( 1, 2 ); + +#endif // #if defined( DBGFLAG_STRINGS_STRIP ) && !defined( TIER0_DLL_EXPORT ) + +// You can use this macro like a runtime assert macro. +// If the condition fails, then Error is called with the message. This macro is called +// like AssertMsg, where msg must be enclosed in parenthesis: +// +// ErrorIfNot( bCondition, ("a b c %d %d %d", 1, 2, 3) ); +#define ErrorIfNot( condition, msg ) \ + if ( (condition) ) \ + ; \ + else \ + { \ + Error msg; \ + } + +#ifdef _DEBUG +#define DebugMsg(...) DevMsg(__VA_ARGS__) +#else +#define DebugMsg(...) +#endif + +// @TODO: these callstack spew functions are currently disabled in the new logging system. Need to add support for these if desired. +PLATFORM_INTERFACE void _Warning_AlwaysSpewCallStack_Enable( bool bEnable ); +PLATFORM_INTERFACE void _Warning_AlwaysSpewCallStack_Length( int iMaxCallStackLength ); + +PLATFORM_INTERFACE void _Error_AlwaysSpewCallStack_Enable( bool bEnable ); +PLATFORM_INTERFACE void _Error_AlwaysSpewCallStack_Length( int iMaxCallStackLength ); + + +/* Code macros, debugger interface */ + +#ifdef _DEBUG + +#define DBG_CODE( _code ) if (0) ; else { _code } +#define DBG_CODE_NOSCOPE( _code ) _code +#define DBG_DCODE( _g, _l, _code ) if (IsSpewActive( _g, _l )) { _code } else {} +#define DBG_BREAK() DebuggerBreak() /* defined in platform.h */ + +#else /* not _DEBUG */ + +#define DBG_CODE( _code ) ((void)0) +#define DBG_CODE_NOSCOPE( _code ) +#define DBG_DCODE( _g, _l, _code ) ((void)0) +#define DBG_BREAK() ((void)0) + +#endif /* _DEBUG */ + +//----------------------------------------------------------------------------- +// Macro to assist in asserting constant invariants during compilation + +#ifdef _DEBUG +#define COMPILE_TIME_ASSERT( pred ) switch(0){case 0:case pred:;} +#define ASSERT_INVARIANT( pred ) static void UNIQUE_ID() { COMPILE_TIME_ASSERT( pred ) } +#else +#define COMPILE_TIME_ASSERT( pred ) +#define ASSERT_INVARIANT( pred ) +#endif + +#ifdef _DEBUG +template<typename DEST_POINTER_TYPE, typename SOURCE_POINTER_TYPE> +inline DEST_POINTER_TYPE assert_cast(SOURCE_POINTER_TYPE* pSource) +{ + Assert( static_cast<DEST_POINTER_TYPE>(pSource) == dynamic_cast<DEST_POINTER_TYPE>(pSource) ); + return static_cast<DEST_POINTER_TYPE>(pSource); +} +#else +#define assert_cast static_cast +#endif + +//----------------------------------------------------------------------------- +// Templates to assist in validating pointers: + +// Have to use these stubs so we don't have to include windows.h here. +PLATFORM_INTERFACE void _AssertValidReadPtr( void* ptr, int count = 1 ); +PLATFORM_INTERFACE void _AssertValidWritePtr( void* ptr, int count = 1 ); +PLATFORM_INTERFACE void _AssertValidReadWritePtr( void* ptr, int count = 1 ); +PLATFORM_INTERFACE void _AssertValidStringPtr( const tchar* ptr, int maxchar ); + +#ifdef DBGFLAG_ASSERT +inline void AssertValidStringPtr( const tchar* ptr, int maxchar = 0xFFFFFF ) { _AssertValidStringPtr( ptr, maxchar ); } +template<class T> inline void AssertValidReadPtr( T* ptr, int count = 1 ) { _AssertValidReadPtr( (void*)ptr, count ); } +template<class T> inline void AssertValidWritePtr( T* ptr, int count = 1 ) { _AssertValidWritePtr( (void*)ptr, count ); } +template<class T> inline void AssertValidReadWritePtr( T* ptr, int count = 1 ) { _AssertValidReadWritePtr( (void*)ptr, count ); } +#define AssertValidThis() AssertValidReadWritePtr(this,sizeof(*this)) + +#else + +inline void AssertValidStringPtr( const tchar* ptr, int maxchar = 0xFFFFFF ) { } +template<class T> inline void AssertValidReadPtr( T* ptr, int count = 1 ) { } +template<class T> inline void AssertValidWritePtr( T* ptr, int count = 1 ) { } +template<class T> inline void AssertValidReadWritePtr( T* ptr, int count = 1 ) { } +#define AssertValidThis() +#endif + +//----------------------------------------------------------------------------- +// Macro to protect functions that are not reentrant + +#ifdef _DEBUG +class CReentryGuard +{ +public: + CReentryGuard(int *pSemaphore) + : m_pSemaphore(pSemaphore) + { + ++(*m_pSemaphore); + } + + ~CReentryGuard() + { + --(*m_pSemaphore); + } + +private: + int *m_pSemaphore; +}; + +#define ASSERT_NO_REENTRY() \ + static int fSemaphore##__LINE__; \ + Assert( !fSemaphore##__LINE__ ); \ + CReentryGuard ReentryGuard##__LINE__( &fSemaphore##__LINE__ ) +#else +#define ASSERT_NO_REENTRY() +#endif + +// Tier0 uses these for string functions since this abstraction is normally done in tier1. +#ifdef POSIX + #define Tier0Internal_sntprintf snprintf + #define Tier0Internal_vsntprintf vsnprintf + #define Tier0Internal_vsnprintf vsnprintf +#else + #define Tier0Internal_sntprintf _sntprintf + #define Tier0Internal_vsntprintf _vsntprintf + #define Tier0Internal_vsnprintf _vsnprintf +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Inline string formatter +// + +#include "tier0/valve_off.h" +class CDbgFmtMsg +{ +public: + CDbgFmtMsg(const tchar *pszFormat, ...) + { + va_list arg_ptr; + + va_start(arg_ptr, pszFormat); + Tier0Internal_vsntprintf(m_szBuf, sizeof(m_szBuf)-1, pszFormat, arg_ptr); + va_end(arg_ptr); + + m_szBuf[sizeof(m_szBuf)-1] = 0; + } + + operator const tchar *() const + { + return m_szBuf; + } + +private: + tchar m_szBuf[256]; +}; +#include "tier0/valve_on.h" + +//----------------------------------------------------------------------------- +// +// Purpose: Embed debug info in each file. +// +#if defined( _WIN32 ) && !defined( _X360 ) + + #ifdef _DEBUG + #pragma comment(compiler) + #endif + +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Wrap around a variable to create a simple place to put a breakpoint +// + +#ifdef _DEBUG + +template< class Type > +class CDataWatcher +{ +public: + const Type& operator=( const Type &val ) + { + return Set( val ); + } + + const Type& operator=( const CDataWatcher<Type> &val ) + { + return Set( val.m_Value ); + } + + const Type& Set( const Type &val ) + { + // Put your breakpoint here + m_Value = val; + return m_Value; + } + + Type& GetForModify() + { + return m_Value; + } + + const Type& operator+=( const Type &val ) + { + return Set( m_Value + val ); + } + + const Type& operator-=( const Type &val ) + { + return Set( m_Value - val ); + } + + const Type& operator/=( const Type &val ) + { + return Set( m_Value / val ); + } + + const Type& operator*=( const Type &val ) + { + return Set( m_Value * val ); + } + + const Type& operator^=( const Type &val ) + { + return Set( m_Value ^ val ); + } + + const Type& operator|=( const Type &val ) + { + return Set( m_Value | val ); + } + + const Type& operator++() + { + return (*this += 1); + } + + Type operator--() + { + return (*this -= 1); + } + + Type operator++( int ) // postfix version.. + { + Type val = m_Value; + (*this += 1); + return val; + } + + Type operator--( int ) // postfix version.. + { + Type val = m_Value; + (*this -= 1); + return val; + } + + // For some reason the compiler only generates type conversion warnings for this operator when used like + // CNetworkVarBase<unsigned tchar> = 0x1 + // (it warns about converting from an int to an unsigned char). + template< class C > + const Type& operator&=( C val ) + { + return Set( m_Value & val ); + } + + operator const Type&() const + { + return m_Value; + } + + const Type& Get() const + { + return m_Value; + } + + const Type* operator->() const + { + return &m_Value; + } + + Type m_Value; + +}; + +#else + +template< class Type > +class CDataWatcher +{ +private: + CDataWatcher(); // refuse to compile in non-debug builds +}; + +#endif + +// Code for programmatically setting/unsetting hardware breakpoints (there's probably a 360 and +#ifdef IS_WINDOWS_PC + +typedef void * HardwareBreakpointHandle_t; + +enum EHardwareBreakpointType +{ + BREAKPOINT_EXECUTE = 0, + BREAKPOINT_WRITE, + BREAKPOINT_READWRITE, +}; + +enum EHardwareBreakpointSize +{ + BREAKPOINT_SIZE_1 = 1, + BREAKPOINT_SIZE_2 = 2, + BREAKPOINT_SIZE_4 = 4, + BREAKPOINT_SIZE_8 = 8, +}; + +PLATFORM_INTERFACE HardwareBreakpointHandle_t SetHardwareBreakpoint( EHardwareBreakpointType eType, EHardwareBreakpointSize eSize, const void *pvLocation ); +PLATFORM_INTERFACE bool ClearHardwareBreakpoint( HardwareBreakpointHandle_t handle ); + +class CHardwareBreakPointScopeGuard +{ +public: + CHardwareBreakPointScopeGuard( const void *pvLocation, size_t nLocationSize, EHardwareBreakpointType eType = BREAKPOINT_WRITE ) + { + EHardwareBreakpointSize eSize = BREAKPOINT_SIZE_4; + switch ( nLocationSize ) + { + case 1: + eSize = BREAKPOINT_SIZE_1; + break; + case 2: + eSize = BREAKPOINT_SIZE_2; + break; + case 4: + eSize = BREAKPOINT_SIZE_4; + break; + case 8: + eSize = BREAKPOINT_SIZE_8; + break; + default: + Warning( _T( "SetHardwareBreakpoint can only work with 1, 2, 4 or 8 byte data fields." ) ); + break; + } + + m_hBreakPoint = SetHardwareBreakpoint( eType, eSize, pvLocation ); + m_bActive = m_hBreakPoint != (HardwareBreakpointHandle_t)0; + } + + ~CHardwareBreakPointScopeGuard() + { + Release(); + } + + void Release() + { + if ( !m_bActive ) + return; + ClearHardwareBreakpoint( m_hBreakPoint ); + } + +private: + bool m_bActive; + HardwareBreakpointHandle_t m_hBreakPoint; +}; + +#endif // IS_WINDOWS_PC +//----------------------------------------------------------------------------- + +#endif /* DBG_H */ diff --git a/external/vpc/public/tier0/dbgflag.h b/external/vpc/public/tier0/dbgflag.h new file mode 100644 index 0000000..deee3e5 --- /dev/null +++ b/external/vpc/public/tier0/dbgflag.h @@ -0,0 +1,68 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This file sets all of our debugging flags. It should be +// called before all other header files. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef DBGFLAG_H +#define DBGFLAG_H +#ifdef _WIN32 +#pragma once +#endif + + +// Here are all the flags we support: +// DBGFLAG_MEMORY: Enables our memory debugging system, which overrides malloc & free +// DBGFLAG_MEMORY_NEWDEL: Enables new / delete tracking for memory debug system. Requires DBGFLAG_MEMORY to be enabled. +// DBGFLAG_VALIDATE: Enables our recursive validation system for checking integrity and memory leaks +// DBGFLAG_ASSERT: Turns Assert on or off (when off, it isn't compiled at all) +// DBGFLAG_ASSERTFATAL: Turns AssertFatal on or off (when off, it isn't compiled at all) +// DBGFLAG_ASSERTDLG: Turns assert dialogs on or off and debug breaks on or off when not under the debugger. +// (Dialogs will always be on when process is being debugged.) +// DBGFLAG_STRINGS: Turns on hardcore string validation (slow but safe) + +#undef DBGFLAG_MEMORY +#undef DBGFLAG_MEMORY_NEWDEL +#undef DBGFLAG_VALIDATE +#undef DBGFLAG_ASSERT +#undef DBGFLAG_ASSERTFATAL +#undef DBGFLAG_ASSERTDLG +#undef DBGFLAG_STRINGS + +//----------------------------------------------------------------------------- +// Default flags for debug builds +//----------------------------------------------------------------------------- +#if defined( _DEBUG ) && !defined( PS3MEMOVERRIDEWRAP ) + +#define DBGFLAG_MEMORY +#ifdef _SERVER // only enable new & delete tracking for server; on client it conflicts with CRT mem leak tracking +#define DBGFLAG_MEMORY_NEWDEL +#endif +#ifdef STEAM +#define DBGFLAG_VALIDATE +#endif +#define DBGFLAG_ASSERT +#define DBGFLAG_ASSERTFATAL +#define DBGFLAG_ASSERTDLG +#define DBGFLAG_STRINGS + + +//----------------------------------------------------------------------------- +// Default flags for release builds +//----------------------------------------------------------------------------- +#else // _DEBUG +#ifdef STEAM +#define DBGFLAG_ASSERT +#endif +#define DBGFLAG_ASSERTFATAL // note: fatal asserts are enabled in release builds +#define DBGFLAG_ASSERTDLG + +#endif // _DEBUG + +#if defined( _CERT ) +#define DBGFLAG_STRINGS_STRIP +#endif + +#endif // DBGFLAG_H diff --git a/external/vpc/public/tier0/etwprof.h b/external/vpc/public/tier0/etwprof.h new file mode 100644 index 0000000..ba9f8f5 --- /dev/null +++ b/external/vpc/public/tier0/etwprof.h @@ -0,0 +1,155 @@ +//============ Copyright (c) Valve Corporation, All rights reserved. ============ +// +// ETW (Event Tracing for Windows) profiling helpers. +// This allows easy insertion of Generic Event markers into ETW/xperf tracing +// which then aids in analyzing the traces and finding performance problems. +// The usage patterns are to use ETWBegin and ETWEnd (typically through the +// convenience class CETWScope) to bracket time-consuming operations. In addition +// ETWFrameMark marks the beginning of each frame, and ETWMark can be used to +// mark other notable events. More event types and providers can be added as needed. +// When recording xperf profiles add Valve-Main+Valve-FrameRate to the list of +// user-mode providers and be sure to register the providers with this sequence +// of commands: +// xcopy /y game\bin\tier0.dll %temp% +// wevtutil um src\tier0\ValveETWProvider.man +// wevtutil im src\tier0\ValveETWProvider.man +// +//=============================================================================== + +#ifndef ETWPROF_H +#define ETWPROF_H +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +#include "tier0/platform.h" + +#ifdef IS_WINDOWS_PC +// ETW support should be compiled in for all Windows PC platforms. It isn't +// supported on Windows XP but that is determined at run-time. +#if !defined(STANDALONE_VPC) +#define ETW_MARKS_ENABLED +#endif +#endif + +#ifdef ETW_MARKS_ENABLED + +// Insert a single event to mark a point in an ETW trace. The return value is a 64-bit +// time stamp. +PLATFORM_INTERFACE int64 ETWMark( const char *pMessage ); +// Optionally do full printf formatting of the mark string. This will be more expensive, +// but only when tracing is enabled. +PLATFORM_INTERFACE int64 ETWMarkPrintf( PRINTF_FORMAT_STRING const char *pMessage, ... ) FMTFUNCTION( 1, 2 ); +// Optionally specify one to four floats. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +PLATFORM_INTERFACE void ETWMark1F( const char *pMessage, float data1 ); +PLATFORM_INTERFACE void ETWMark2F( const char *pMessage, float data1, float data2 ); +PLATFORM_INTERFACE void ETWMark3F( const char *pMessage, float data1, float data2, float data3 ); +PLATFORM_INTERFACE void ETWMark4F( const char *pMessage, float data1, float data2, float data3, float data4 ); +// Optionally specify one to four ints. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +PLATFORM_INTERFACE void ETWMark1I( const char *pMessage, int data1 ); +PLATFORM_INTERFACE void ETWMark2I( const char *pMessage, int data1, int data2 ); +PLATFORM_INTERFACE void ETWMark3I( const char *pMessage, int data1, int data2, int data3 ); +PLATFORM_INTERFACE void ETWMark4I( const char *pMessage, int data1, int data2, int data3, int data4 ); +// Optionally specify one to two strings. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +PLATFORM_INTERFACE void ETWMark1S( const char *pMessage, const char* data1 ); +PLATFORM_INTERFACE void ETWMark2S( const char *pMessage, const char* data1, const char* data2 ); + +// Insert a begin event to mark the start of some work. The return value is a 64-bit +// time stamp which should be passed to the corresponding ETWEnd function. +PLATFORM_INTERFACE int64 ETWBegin( const char *pMessage ); + +// Insert a paired end event to mark the end of some work. +PLATFORM_INTERFACE int64 ETWEnd( const char *pMessage, int64 nStartTime ); + +// Mark the start of the next render frame. bIsServerProcess must be passed +// in consistently for a particular process. +PLATFORM_INTERFACE void ETWRenderFrameMark( bool bIsServerProcess ); +// Mark the start of the next simulation frame. bIsServerProcess must be passed +// in consistently for a particular process. +PLATFORM_INTERFACE void ETWSimFrameMark( bool bIsServerProcess ); +// Return the frame number recorded in the ETW trace -- useful for synchronization +// other profile information to the ETW trace. +PLATFORM_INTERFACE int ETWGetRenderFrameNumber(); + +PLATFORM_INTERFACE void ETWMouseDown( int nWhichButton, int nX, int nY ); +PLATFORM_INTERFACE void ETWMouseUp( int nWhichButton, int nX, int nY ); +PLATFORM_INTERFACE void ETWKeyDown( int nScanCode, int nVirtualCode, const char *pChar ); + +PLATFORM_INTERFACE void ETWSendPacket( const char *pTo, int nWireSize, int nOutSequenceNR, int nOutSequenceNrAck ); +PLATFORM_INTERFACE void ETWThrottled(); +PLATFORM_INTERFACE void ETWReadPacket( const char *pFrom, int nWireSize, int nInSequenceNR, int nOutSequenceNRAck ); + +// This class calls the ETW Begin and End functions in order to insert a +// pair of events to bracket some work. +class CETWScope +{ +public: + CETWScope( const char *pMessage ) + : m_pMessage( pMessage ) + { + m_nStartTime = ETWBegin( pMessage ); + } + ~CETWScope() + { + ETWEnd( m_pMessage, m_nStartTime ); + } +private: + // Private and unimplemented to disable copying. + CETWScope( const CETWScope& rhs ); + CETWScope& operator=( const CETWScope& rhs ); + + const char* m_pMessage; + int64 m_nStartTime; +}; + +#else + +inline int64 ETWMark( const char* ) { return 0; } +inline int64 ETWMarkPrintf( const char *, ... ) { return 0; } +inline void ETWMark1F( const char *, float ) { } +inline void ETWMark2F( const char *, float , float ) { } +inline void ETWMark3F( const char *, float , float , float ) { } +inline void ETWMark4F( const char *, float , float , float , float ) { } +inline void ETWMark1I( const char *, int ) { } +inline void ETWMark2I( const char *, int , int ) { } +inline void ETWMark3I( const char *, int , int , int ) { } +inline void ETWMark4I( const char *, int , int , int , int ) { } +// Optionally specify one to two strings. They will show up in separate columns in +// summary tables to allow sorting and easier transfer to spreadsheets. +inline void ETWMark1S( const char *, const char* ) { } +inline void ETWMark2S( const char *, const char* , const char* ) { } + +inline int64 ETWBegin( const char* ) { return 0; } +inline int64 ETWEnd( const char*, int64 ) { return 0; } +inline void ETWRenderFrameMark( bool ) {} +inline void ETWSimFrameMark( bool ) {} +inline int ETWGetRenderFrameNumber() { return 0; } + +inline void ETWMouseDown( int nWhichButton, int nX, int nY ) {} +inline void ETWMouseUp( int nWhichButton, int nX, int nY ) {} +inline void ETWKeyDown( int nScanCode, int nVirtualCode, const char *pChar ) {} + +inline void ETWSendPacket( const char *pTo, int nWireSize, int nOutSequenceNR, int nOutSequenceNrAck ) {} +inline void ETWThrottled() {} +inline void ETWReadPacket( const char *pFrom, int nWireSize, int nInSequenceNR, int nOutSequenceNRAck ) {} + +// This class calls the ETW Begin and End functions in order to insert a +// pair of events to bracket some work. +class CETWScope +{ +public: + CETWScope( const char* ) + { + } +private: + // Private and unimplemented to disable copying. + CETWScope( const CETWScope& rhs ); + CETWScope& operator=( const CETWScope& rhs ); +}; + +#endif + +#endif // ETWPROF_H diff --git a/external/vpc/public/tier0/eventmasks.h b/external/vpc/public/tier0/eventmasks.h new file mode 100644 index 0000000..4774809 --- /dev/null +++ b/external/vpc/public/tier0/eventmasks.h @@ -0,0 +1,480 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#pragma once + +typedef union EVENT_MASK(TC_deliver_mode) +{ + struct + { + uint16 DD:1; // both logical processors in deliver mode }, + uint16 DB:1; // logical processor 0 in deliver mode, 1 in build mode }, + uint16 DI:1; // logical processor 0 in deliver mode, 1 is inactive }, + uint16 BD:1; // logical processor 0 in build mode, 1 in deliver mode }, + uint16 BB:1; // both logical processors in build mode }, + uint16 BI:1; // logical processor 0 in build mode, 1 is inactive }, + uint16 ID:1; // logical processor 0 is inactive, 1 in deliver mode }, + uint16 IB:1; // logical processor 0 is inactive, 1 in build mode } + }; + uint16 flat; +} EVENT_MASK(TC_deliver_mode); + +typedef union EVENT_MASK(BPU_fetch_request) +{ + + struct + { + uint16 TCMISS:1; // Trace cache lookup miss }, + }; + uint16 flat; +} EVENT_MASK(BPU_fetch_request); + + +typedef union EVENT_MASK(ITLB_reference) +{ + struct + { + uint16 HIT : 1; //ITLB hit }, + uint16 MISS : 1;//ITLB miss }, + uint16 HIT_UC :1; // Uncacheable ITLB hit } + }; + uint16 flat; +} EVENT_MASK(ITLB_reference); + +typedef union EVENT_MASK(memory_cancel) +{ + struct + { + uint16 dummy : 2; + + uint16 ST_RB_FULL:1; //Replayed because no store request buffer is available }, + uint16 _64K_CONF:1; //Conflicts due to 64K aliasing } + }; + uint16 flat; +}EVENT_MASK(memory_cancel); + +typedef union EVENT_MASK(memory_complete) +{ + struct + { + uint16 LSC:1; // Load split completed, excluding UC/WC loads }, + uint16 SSC:1; //Any split stores completed } } + }; + uint16 flat; +} EVENT_MASK(memory_complete); + +typedef union EVENT_MASK(load_port_replay) +{ + struct + { + uint16 dummy:1; + uint16 SPLIT_LD:1; //Split load } } + }; + uint16 flat; +} EVENT_MASK(load_port_replay); + +typedef union EVENT_MASK(store_port_replay) +{ + struct + { + uint16 dummy0:1; + uint16 SPLIT_ST:1; //Split store } } + + }; + uint16 flat; +} EVENT_MASK(store_port_replay); + +typedef union EVENT_MASK(MOB_load_replay) +{ + struct + { + uint16 dummy0:1; + + uint16 NO_STA:1; //Replayed because of unknown store address }, + + uint16 dummy2:1; + + uint16 NO_STD:1; //Replayed because of unknown store data }, + uint16 PARTIAL_DATA:1; //Replayed because of partially overlapped data access between the load and store operations }, + uint16 UNALGN_ADDR:1; //Replayed because the lower 4 bits of the linear address do not match between the load and store operations } } + }; + uint16 flat; +}EVENT_MASK(MOB_load_replay); + +typedef union EVENT_MASK(page_walk_type) +{ + struct + { + uint16 DTMISS:1; // Page walk for a data TLB miss }, + uint16 ITMISS:1; // Page walk for an instruction TLB miss } } + }; + uint16 flat; +}EVENT_MASK(page_walk_type); + + +typedef union EVENT_MASK(BSQ_cache_reference) +{ + struct + { + uint16 RD_2ndL_HITS:1; // Read 2nd level cache hit Shared }, + uint16 RD_2ndL_HITE:1; // Read 2nd level cache hit Exclusive }, + uint16 RD_2ndL_HITM:1; // Read 2nd level cache hit Modified }, + uint16 RD_3rdL_HITS:1; // Read 3rd level cache hit Shared }, + uint16 RD_3rdL_HITE:1; // Read 3rd level cache hit Exclusive }, + uint16 RD_3rdL_HITM:1; // Read 3rd level cache hit Modified }, + uint16 dummy6:1; + uint16 dummy7:1; + uint16 RD_2ndL_MISS:1; // Read 2nd level cache miss }, + uint16 RD_3rdL_MISS:1; // Read 3rd level cache miss }, + uint16 WR_2ndL_MISS:1; // Writeback lookup from DAC misses the 2nd level cache } } + }; + uint16 flat; +} EVENT_MASK(BSQ_cache_reference) ; + +typedef union EVENT_MASK(IOQ) +{ + struct + { + uint16 bit0:1; // bus request type (use 00001 for invalid or default) + uint16 bit1:1; // + uint16 bit2:1; // + uint16 bit3:1; // + uint16 bit4:1; // + uint16 ALL_READ:1; // Count read entries }, + uint16 ALL_WRITE:1; // Count write entries }, + uint16 MEM_UC:1; // Count UC memory access entries }, + uint16 MEM_WC:1; // Count WC memory access entries }, + uint16 MEM_WT:1; // Count WT memory access entries }, + uint16 MEM_WP:1; // Count WP memory access entries }, + uint16 MEM_WB:1; // Count WB memory access entries }, + uint16 dummy12:1; + + uint16 OWN:1; // Count own store requests }, + uint16 OTHER:1; // Count other and DMA store requests }, + uint16 PREFETCH:1; // Include HW and SW prefetch requests } } + }; + uint16 flat; +} EVENT_MASK(IOQ) ; + +typedef union EVENT_MASK(FSB_data_activity) +{ + struct + { + /* DRDY_OWN is mutually exclusive with DRDY_OTHER */ + /* DBSY_OWN is mutually exclusive with DBSY_OTHER */ + uint16 DRDY_DRV:1; // Count when this processor drives data onto the bus }, + uint16 DRDY_OWN:1; // Count when this processor reads data from the bus }, + uint16 DRDY_OTHER:1; // Count when data is on the bus but not being sampled by the processor }, + uint16 DBSY_DRV:1; // Count when this processor reserves the bus for driving data }, + uint16 DBSY_OWN:1; // Count when this processor reserves the bus for sampling data }, + uint16 DBSY_OTHER:1; // Count when the bus is reserved for driving data this processor will not sample } } + }; + uint16 flat; +}EVENT_MASK(FSB_data_activity); + +typedef union EVENT_MASK(BSQ) +{ + struct + { + uint16 REQ_TYPE0:1; // Request type encoding bit 0 }, + uint16 REQ_TYPE1:1; // Request type encoding bit 1 }, + uint16 REQ_LEN0:1; // Request length encoding bit 0 }, + uint16 REQ_LEN1:1; // Request length encoding bit 1 }, + uint16 dummy4: 1; + uint16 REQ_IO_TYPE:1; // Request type is input or output }, + uint16 REQ_LOCK_TYPE:1; // Request type is bus lock }, + uint16 REQ_CACHE_TYPE:1; // Request type is cacheable }, + uint16 REQ_SPLIT_TYPE:1; // Request type is a bus 8-byte chunk split across 8-byte boundary }, + uint16 REQ_DEM_TYPE:1; // Request type is a demand (1) or prefetch (0) }, + uint16 REQ_ORD_TYPE:1; // Request is an ordered type }, + uint16 MEM_TYPE0:1; // Memory type encoding bit 0 }, + uint16 MEM_TYPE1:1; // Memory type encoding bit 1 }, + uint16 MEM_TYPE2:1; // Memory type encoding bit 2 } } + }; + uint16 flat; +} EVENT_MASK(BSQ); + +typedef union EVENT_MASK(firm_uop) +{ + struct + { + uint16 dummy15 : 15; + uint16 ALL:1; // count all uops of this type } } + }; + uint16 flat; +} EVENT_MASK(firm_uop); + + + +typedef union EVENT_MASK(TC_misc) +{ + struct + { + uint16 dymmy4 : 4; + uint16 FLUSH:1; // Number of flushes } } + }; + uint16 flat; +} EVENT_MASK(TC_misc); + +typedef union EVENT_MASK(global_power_events) +{ + struct + { + uint16 Running:1; // The processor is active } } + }; + uint16 flat; +} EVENT_MASK(global_power_events); + +typedef union EVENT_MASK(tc_ms_xfer) +{ + struct + { + uint16 CISC:1; // A TC to MS transfer ocurred } } + }; + uint16 flat; +}EVENT_MASK(tc_ms_xfer); + + + +typedef union EVENT_MASK(uop_queue_writes) +{ + struct + { + uint16 FROM_TC_BUILD:1; // uops written from TC build mode + uint16 FROM_TC_DELIVER:1; // uops written from TC deliver mode + uint16 FROM_ROM:1; // uops written from microcode ROM } } + }; + uint16 flat; +} EVENT_MASK(uop_queue_writes); + +typedef union EVENT_MASK(branch_type) +{ + struct + { + uint16 dummy : 1; + uint16 CONDITIONAL:1; // Conditional jumps + uint16 CALL:1; // Direct or indirect call + uint16 RETURN:1; // Return branches + uint16 INDIRECT:1; // Returns, indirect calls, or indirect jumps + }; + uint16 flat; +} EVENT_MASK(branch_type); + + + +typedef union EVENT_MASK(resource_stall) +{ + struct + { + uint16 dummy1 : 5; + uint16 SBFULL:1; // A Stall due to lack of store buffers } } + }; + uint16 flat; +} EVENT_MASK(resource_stall); + + + + +typedef union EVENT_MASK(WC_Buffer) +{ + struct + { + uint16 WCB_EVICTS : 1; // all causes }, + uint16 WCB_FULL_EVICT : 1; // no WC buffer is available }, + /* XXX: 245472-011 no longer lists bit 2, but that looks like + a table formatting error. Keeping it for now. */ + uint16 WCB_HITM_EVICT : 1; // store encountered a Hit Modified condition } } + }; + uint16 flat; +} EVENT_MASK(WC_Buffer); + + +typedef union EVENT_MASK(b2b_cycles) +{ + struct + { + uint16 dummy0 : 1; + uint16 bit1 : 1; // + uint16 bit2 : 1; // + uint16 bit3 : 1; // + uint16 bit4 : 1; // + uint16 bit5 : 1; // + uint16 bit6 : 1; // + + }; + uint16 flat; +} EVENT_MASK(b2b_cycles); + +typedef union EVENT_MASK(bnr) +{ + struct + { + uint16 bit0:1; // + uint16 bit1:1; // + uint16 bit2:1; // + }; + uint16 flat; +} EVENT_MASK(bnr); + + +typedef union EVENT_MASK(snoop) +{ + struct + { + uint16 dummy0 : 1; + uint16 dummy1 : 1; + + uint16 bit2:1; // + uint16 dummy3:1; // + uint16 dummy4:1; // + uint16 dummy5:1; // + uint16 bit6:1; // + uint16 bit7:1; // + }; + uint16 flat; +} EVENT_MASK(snoop); + + +typedef union EVENT_MASK(response) +{ + struct + { + uint16 dummy0:1; // + uint16 bit1:1; // + uint16 bit2:1; // + uint16 dummy3:1; // + uint16 dummy4:1; // + uint16 dummy5:1; // + uint16 dummy6:1; // + uint16 dummy7:1; // + uint16 bit8:1; // + uint16 bit9:1; // + }; + uint16 flat; +} EVENT_MASK(response); + + +typedef union EVENT_MASK(nbogus_bogus) +{ + struct + { + uint16 NBOGUS:1; // The marked uops are not bogus + uint16 BOGUS:1; // The marked uops are bogus + }; + uint16 flat; +} EVENT_MASK(nbogus_bogus); + + +typedef union EVENT_MASK(execution_event) +{ + struct + { + uint16 NBOGUS0:1; // non-bogus uops with tag bit 0 set }, + uint16 NBOGUS1:1; // non-bogus uops with tag bit 1 set }, + uint16 NBOGUS2:1; // non-bogus uops with tag bit 2 set }, + uint16 NBOGUS3:1; // non-bogus uops with tag bit 3 set }, + uint16 BOGUS0:1; // bogus uops with tag bit 0 set }, + uint16 BOGUS1:1; // bogus uops with tag bit 1 set }, + uint16 BOGUS2:1; // bogus uops with tag bit 2 set }, + uint16 BOGUS3:1; // bogus uops with tag bit 3 set } } + }; + uint16 flat; +}EVENT_MASK(execution_event); + +typedef union EVENT_MASK(instr_retired) +{ + struct + { + uint16 NBOGUSNTAG:1; // Non-bogus instructions that are not tagged }, + uint16 NBOGUSTAG:1; // Non-bogus instructions that are tagged }, + uint16 BOGUSNTAG:1; // Bogus instructions that are not tagged }, + uint16 BOGUSTAG:1; // Bogus instructions that are tagged } } + }; + uint16 flat; +} EVENT_MASK(instr_retired); + + +typedef union EVENT_MASK(uop_type) +{ + struct + { + uint16 dummy0 : 1; + uint16 TAGLOADS:1; // The uop is a load operation }, + uint16 TAGSTORES:1; // The uop is a store operation } } + }; + uint16 flat; +} EVENT_MASK(uop_type); + +typedef union EVENT_MASK(branch_retired) +{ + struct + { + uint16 MMNP:1; // Branch Not-taken Predicted + uint16 MMNM:1; // Branch Not-taken Mispredicted + uint16 MMTP:1; // Branch Taken Predicted + uint16 MMTM:1; // Branch Taken Mispredicted + }; + uint16 flat; +} EVENT_MASK(branch_retired); + +typedef union EVENT_MASK(mispred_branch_retired) +{ + struct + { + uint16 NBOGUS:1; // The retired branch is not bogus } } + }; + uint16 flat; +} EVENT_MASK(mispred_branch_retired); + + +typedef union EVENT_MASK(x87_assist) +{ + struct + { + uint16 FPSU:1; // FP stack underflow }, + uint16 FPSO:1; // FP stack overflow }, + uint16 POAO:1; // x87 output overflow }, + uint16 POAU:1; // x87 output underflow }, + uint16 PREA:1; // x87 input assist } } + }; + uint16 flat; +}EVENT_MASK(x87_assist); + +typedef union EVENT_MASK(machine_clear) +{ + struct + { + uint16 CLEAR:1; // Count a portion of the cycles when the machine is cleared }, + uint16 dummy1: 1; + uint16 MOCLEAR:1; // Count clears due to memory ordering issues }, + uint16 dummy3: 1; + uint16 dummy4: 1; + uint16 dummy5: 1; + + uint16 SMCLEAR:1;// Count clears due to self-modifying code issues } } + }; + uint16 flat; +} EVENT_MASK(machine_clear); + + +typedef union EVENT_MASK(x87_SIMD_moves_uop) +{ + struct + { + uint16 dummy3:3; + uint16 ALLP0:1; // Count all x87/SIMD store/move uops }, + uint16 ALLP2:1; // count all x87/SIMD load uops } } + }; + uint16 flat; +} EVENT_MASK(x87_SIMD_moves_uop); + + + + + + + diff --git a/external/vpc/public/tier0/eventmodes.h b/external/vpc/public/tier0/eventmodes.h new file mode 100644 index 0000000..05e5b21 --- /dev/null +++ b/external/vpc/public/tier0/eventmodes.h @@ -0,0 +1,1787 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef EVENTMODES_H +#define EVENTMODES_H + + +#pragma once + +/* + + + + Event Modes to choose from: + + P4Event_TC_deliver_mode + + P4Event_BPU_fetch_request + + P4Event_ITLB_reference + + P4Event_memory_cancel + + P4Event_memory_complete + + P4Event_load_port_replay + + P4Event_store_port_replay + + P4Event_MOB_load_replay + + P4Event_page_walk_type + + P4Event_BSQ_cache_reference + + P4Event_IOQ_allocation + + P4Event_IOQ_active_entries + + P4Event_FSB_data_activity + + P4Event_BSQ_allocation + + P4Event_BSQ_active_entries + + P4Event_SSE_input_assist + + P4Event_packed_SP_uop + + P4Event_packed_DP_uop + + P4Event_scalar_SP_uop + + P4Event_scalar_DP_uop + + P4Event_64bit_MMX_uop + + P4Event_128bit_MMX_uop + + P4Event_x87_FP_uop + + P4Event_x87_SIMD_moves_uop + + P4Event_TC_misc + + P4Event_global_power_events + + P4Event_tc_ms_xfer + + P4Event_uop_queue_writes + + P4Event_retired_mispred_branch_type + + P4Event_retired_branch_type + + P4Event_resource_stall + + P4Event_WC_Buffer + + P4Event_b2b_cycles + + P4Event_bnr + + P4Event_snoop + + P4Event_response + + P4Event_front_end_event + + P4Event_execution_event + + P4Event_replay_event + + P4Event_instr_retired + + P4Event_uops_retired + + P4Event_uop_type + + P4Event_branch_retired + + P4Event_mispred_branch_retired + + P4Event_x87_assist + + P4Event_machine_clear + + +*/ + + + +class P4P4Event_TC_deliver_mode: public P4BaseEvent +{ +public: + EVENT_MASK(TC_deliver_mode) * eventMask; + + P4P4Event_TC_deliver_mode() + { + eventMask = (EVENT_MASK(TC_deliver_mode) *)&m_eventMask; + + escr.ESCREventSelect = 0x01; + cccr.CCCRSelect = 0x01; + //// eventType = EVENT_TYPE(TC_deliver_mode); + description = _T("TC_deliver_mode"); + UseCounter4(); + } + + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; + +class P4P4Event_BPU_fetch_request: public P4BaseEvent + +{ +public: + EVENT_MASK(BPU_fetch_request)* eventMask; + + P4P4Event_BPU_fetch_request() + { + eventMask = (EVENT_MASK(BPU_fetch_request) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x00; + // eventType = EVENT_TYPE(BPU_fetch_request); + description=_T("BPU_fetch_request"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } + +}; +class P4P4Event_ITLB_reference: public P4BaseEvent + +{ +public: + EVENT_MASK(ITLB_reference) * eventMask; + + P4P4Event_ITLB_reference() + { + eventMask = (EVENT_MASK(ITLB_reference) *)&m_eventMask; + + escr.ESCREventSelect= 0x18; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(ITLB_reference); + description=_T("ITLB_reference"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_memory_cancel: public P4BaseEvent + +{ +public: + EVENT_MASK(memory_cancel) * eventMask; + + P4Event_memory_cancel() + { + eventMask = (EVENT_MASK(memory_cancel) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(memory_cancel); + description=_T("memory_cancel"); + UseCounter8(); + } + + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_memory_complete: public P4BaseEvent + +{ +public: + EVENT_MASK(memory_complete) * eventMask; + + P4Event_memory_complete() + { + eventMask = (EVENT_MASK(memory_complete) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(memory_complete); + description=_T("memory_complete"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_load_port_replay: public P4BaseEvent + +{ +public: + EVENT_MASK(load_port_replay) * eventMask; + + P4Event_load_port_replay() + { + eventMask = (EVENT_MASK(load_port_replay) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(load_port_replay); + description=_T("load_port_replay"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_store_port_replay: public P4BaseEvent + +{ +public: + EVENT_MASK(store_port_replay) * eventMask; + + P4Event_store_port_replay() + { + eventMask = (EVENT_MASK(store_port_replay) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(store_port_replay); + description=_T("store_port_replay"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_MOB_load_replay: public P4BaseEvent + +{ +public: + EVENT_MASK(MOB_load_replay) * eventMask; + + P4Event_MOB_load_replay() + { + eventMask = (EVENT_MASK(MOB_load_replay) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(MOB_load_replay); + description=_T("MOB_load_replay"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_page_walk_type: public P4BaseEvent + +{ +public: + EVENT_MASK(page_walk_type) * eventMask; + + P4Event_page_walk_type() + { + eventMask = (EVENT_MASK(page_walk_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x01; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(page_walk_type); + description=_T("page_walk_type"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_BSQ_cache_reference: public P4BaseEvent + +{ +public: + EVENT_MASK(BSQ_cache_reference) * eventMask; + + P4Event_BSQ_cache_reference() + { + eventMask = (EVENT_MASK(BSQ_cache_reference) *)&m_eventMask; + + escr.ESCREventSelect= 0x0C; + cccr.CCCRSelect= 0x07; + // eventType=EVENT_TYPE(BSQ_cache_reference); + description=_T("BSQ_cache_reference"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_IOQ_allocation: public P4BaseEvent + +{ +public: + EVENT_MASK(IOQ) * eventMask; + + P4Event_IOQ_allocation() + { + eventMask = (EVENT_MASK(IOQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(IOQ); + description=_T("IOQ_allocation"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_IOQ_active_entries: public P4BaseEvent + +{ +public: + EVENT_MASK(IOQ) * eventMask; + + P4Event_IOQ_active_entries() + { + eventMask = (EVENT_MASK(IOQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x1A; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(IOQ); + description=_T("IOQ_active_entries"); + UseCounter2(); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_FSB_data_activity: public P4BaseEvent + +{ +public: + EVENT_MASK(FSB_data_activity) * eventMask; + + P4Event_FSB_data_activity() + { + eventMask = (EVENT_MASK(FSB_data_activity) *)&m_eventMask; + + escr.ESCREventSelect= 0x17; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(FSB_data_activity); + description=_T("FSB_data_activity"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_BSQ_allocation: public P4BaseEvent + +{ +public: + EVENT_MASK(BSQ) * eventMask; + + P4Event_BSQ_allocation() + { + eventMask = (EVENT_MASK(BSQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x07; + // eventType=EVENT_TYPE(BSQ); + description=_T("BSQ_allocation"); + UseCounter0(); + } + + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + + } +}; +class P4Event_BSQ_active_entries: public P4BaseEvent + +{ +public: + EVENT_MASK(BSQ) * eventMask; + + P4Event_BSQ_active_entries() + { + eventMask = (EVENT_MASK(BSQ) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x07; + // eventType=EVENT_TYPE(BSQ); + description=_T("bsq_active_entries"); + UseCounter2(); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_SSE_input_assist: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_SSE_input_assist() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x34; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("SSE_input_assist"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_packed_SP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_packed_SP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("packed_SP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_packed_DP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_packed_DP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x0C; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("packed_DP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_scalar_SP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_scalar_SP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x0A; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("scalar_SP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_scalar_DP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_scalar_DP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x0E; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("scalar_DP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_64bit_MMX_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_64bit_MMX_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("64bit_MMX_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_128bit_MMX_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_128bit_MMX_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x1A; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("128bit_MMX_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_x87_FP_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(firm_uop) * eventMask; + + P4Event_x87_FP_uop() + { + eventMask = (EVENT_MASK(firm_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(firm_uop); + description=_T("x87_FP_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_x87_SIMD_moves_uop: public P4BaseEvent + +{ +public: + EVENT_MASK(x87_SIMD_moves_uop) * eventMask; + + P4Event_x87_SIMD_moves_uop() + { + eventMask = (EVENT_MASK(x87_SIMD_moves_uop) *)&m_eventMask; + + escr.ESCREventSelect= 0x2E; + cccr.CCCRSelect= 0; + // eventType=EVENT_TYPE(x87_SIMD_moves_uop); + description=_T("x87_SIMD_moves_uop"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_TC_misc: public P4BaseEvent + +{ +public: + EVENT_MASK(TC_misc) * eventMask; + + P4Event_TC_misc() + { + eventMask = (EVENT_MASK(TC_misc) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x01; + // eventType=EVENT_TYPE(TC_misc); + description=_T("TC_misc"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_global_power_events: public P4BaseEvent + +{ +public: + EVENT_MASK(global_power_events) * eventMask; + + P4Event_global_power_events() + { + eventMask = (EVENT_MASK(global_power_events) *)&m_eventMask; + + escr.ESCREventSelect= 0x13; + cccr.CCCRSelect= 0x06; + // eventType=EVENT_TYPE(global_power_events); + description=_T("global_power_events"); + UseCounter0(); + } + + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_tc_ms_xfer: public P4BaseEvent + +{ +public: + EVENT_MASK(tc_ms_xfer) * eventMask; + + P4Event_tc_ms_xfer() + { + eventMask = (EVENT_MASK(tc_ms_xfer) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x00; + // eventType=EVENT_TYPE(tc_ms_xfer); + description=_T("tc_ms_xfer"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_uop_queue_writes: public P4BaseEvent + +{ +public: + EVENT_MASK(uop_queue_writes) * eventMask; + + P4Event_uop_queue_writes() + { + eventMask = (EVENT_MASK(uop_queue_writes) *)&m_eventMask; + + escr.ESCREventSelect= 0x09; + cccr.CCCRSelect= 0x00; + // eventType=EVENT_TYPE(uop_queue_writes); + description=_T("uop_queue_writes"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_retired_mispred_branch_type: public P4BaseEvent + +{ +public: + EVENT_MASK(branch_type) * eventMask; + + P4Event_retired_mispred_branch_type() + { + eventMask = (EVENT_MASK(branch_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(branch_type); + description=_T("retired_mispred_branch_type"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_retired_branch_type: public P4BaseEvent + +{ +public: + EVENT_MASK(branch_type) * eventMask; + + P4Event_retired_branch_type() + { + eventMask = (EVENT_MASK(branch_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(branch_type); + description=_T("retired_branch_type"); + UseCounter4(); + } + + void UseCounter4() + { + SetCounter(4);; + } + void UseCounter5() + { + SetCounter(5); + } + void UseCounter6() + { + SetCounter(6); + } + void UseCounter7() + { + SetCounter(7); + } +}; +class P4Event_resource_stall: public P4BaseEvent + +{ +public: + EVENT_MASK(resource_stall) * eventMask; + + P4Event_resource_stall() + { + eventMask = (EVENT_MASK(resource_stall) *)&m_eventMask; + + escr.ESCREventSelect= 0x01; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(resource_stall); + description=_T("resource_stall"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } + +}; +class P4Event_WC_Buffer: public P4BaseEvent + +{ +public: + EVENT_MASK(WC_Buffer) * eventMask; + + P4Event_WC_Buffer() + { + eventMask = (EVENT_MASK(WC_Buffer) *)&m_eventMask; + + escr.ESCREventSelect= 0x05; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(WC_Buffer); + description=_T("WC_Buffer"); + UseCounter8(); + } + void UseCounter8() + { + SetCounter(8); + } + void UseCounter9() + { + SetCounter(9); + } + void UseCounter10() + { + SetCounter(10); + } + void UseCounter11() + { + SetCounter(11); + } + +}; +class P4Event_b2b_cycles: public P4BaseEvent + +{ +public: + EVENT_MASK(b2b_cycles) * eventMask; + + P4Event_b2b_cycles() + { + eventMask = (EVENT_MASK(b2b_cycles) *)&m_eventMask; + + escr.ESCREventSelect= 0x16; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(b2b_cycles); + description=_T("b2b_cycles"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_bnr: public P4BaseEvent + +{ +public: + EVENT_MASK(bnr) * eventMask; + + P4Event_bnr() + { + eventMask = (EVENT_MASK(bnr) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(bnr); + description=_T("bnr"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_snoop: public P4BaseEvent + +{ +public: + EVENT_MASK(snoop) * eventMask; + + P4Event_snoop() + { + eventMask = (EVENT_MASK(snoop) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(snoop); + description=_T("snoop"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_response: public P4BaseEvent + +{ +public: + EVENT_MASK(response) * eventMask; + + P4Event_response() + { + eventMask = (EVENT_MASK(response) *)&m_eventMask; + + escr.ESCREventSelect= 0x04; + cccr.CCCRSelect= 0x03; + // eventType=EVENT_TYPE(response); + description=_T("response"); + UseCounter0(); + } + void UseCounter0() + { + SetCounter(0); + } + void UseCounter1() + { + SetCounter(1); + } + void UseCounter2() + { + SetCounter(2); + } + void UseCounter3() + { + SetCounter(3); + } +}; +class P4Event_front_end_event: public P4BaseEvent + +{ +public: + EVENT_MASK(nbogus_bogus) * eventMask; + + P4Event_front_end_event() + { + eventMask = (EVENT_MASK(nbogus_bogus) *)&m_eventMask; + + escr.ESCREventSelect= 0x08; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(nbogus_bogus); + description=_T("front_end_event"); + UseCounter12(); + } + + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_execution_event: public P4BaseEvent + +{ +public: + EVENT_MASK(execution_event) * eventMask; + + P4Event_execution_event() + { + eventMask = (EVENT_MASK(execution_event) *)&m_eventMask; + + escr.ESCREventSelect= 0x0C; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(execution_event); + description=_T("execution_event"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_replay_event: public P4BaseEvent + +{ +public: + EVENT_MASK(nbogus_bogus) * eventMask; + + P4Event_replay_event() + { + eventMask = (EVENT_MASK(nbogus_bogus) *)&m_eventMask; + + escr.ESCREventSelect= 0x09; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(nbogus_bogus); + description=_T("replay_event"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_instr_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(instr_retired) * eventMask; + + P4Event_instr_retired() + { + eventMask = (EVENT_MASK(instr_retired) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(instr_retired); + description=_T("instr_retired"); + UseCounter12(); + } + + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_uops_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(nbogus_bogus) * eventMask; + + P4Event_uops_retired() + { + eventMask = (EVENT_MASK(nbogus_bogus) *)&m_eventMask; + + escr.ESCREventSelect= 0x01; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(nbogus_bogus); + description=_T("uops_retired"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_uop_type: public P4BaseEvent + +{ +public: + EVENT_MASK(uop_type) * eventMask; + + P4Event_uop_type() + { + eventMask = (EVENT_MASK(uop_type) *)&m_eventMask; + + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x02; + // eventType=EVENT_TYPE(uop_type); + description=_T("uop_type"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_branch_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(branch_retired) * eventMask; + + P4Event_branch_retired() + { + eventMask = (EVENT_MASK(branch_retired) *)&m_eventMask; + + escr.ESCREventSelect= 0x06; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(branch_retired); + description=_T("branch_retired"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_mispred_branch_retired: public P4BaseEvent + +{ +public: + EVENT_MASK(mispred_branch_retired) * eventMask; + + P4Event_mispred_branch_retired() + { + eventMask = (EVENT_MASK(mispred_branch_retired) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x04; + // eventType=EVENT_TYPE(mispred_branch_retired); + description=_T("mispred_branch_retired"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_x87_assist: public P4BaseEvent + +{ +public: + EVENT_MASK(x87_assist) * eventMask; + + P4Event_x87_assist() + { + eventMask = (EVENT_MASK(x87_assist) *)&m_eventMask; + + escr.ESCREventSelect= 0x03; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(x87_assist); + description=_T("x87_assist"); + UseCounter12(); + } + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } +}; +class P4Event_machine_clear: public P4BaseEvent + +{ +public: + EVENT_MASK(machine_clear) * eventMask; + + P4Event_machine_clear() + { + eventMask = (EVENT_MASK(machine_clear) *)&m_eventMask; + escr.ESCREventSelect= 0x02; + cccr.CCCRSelect= 0x05; + // eventType=EVENT_TYPE(machine_clear); + description=_T("machine_clear"); + UseCounter12(); + } + + + + void UseCounter12() + { + SetCounter(12); + } + void UseCounter13() + { + SetCounter(13); + + } + + void UseCounter14() + { + SetCounter(14); + } + void UseCounter15() + { + SetCounter(15); + + } + + void UseCounter16() + { + SetCounter(16); + } + void UseCounter17() + { + SetCounter(17); + + } + +}; + +#endif // EVENTMODES_H diff --git a/external/vpc/public/tier0/fasttimer.h b/external/vpc/public/tier0/fasttimer.h new file mode 100644 index 0000000..a820a60 --- /dev/null +++ b/external/vpc/public/tier0/fasttimer.h @@ -0,0 +1,625 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef FASTTIMER_H +#define FASTTIMER_H +#ifdef _WIN32 +#pragma once +#endif + +#include <assert.h> +#include "tier0/platform.h" +#ifdef _PS3 +#include "sys/sys_time.h" +#else +inline uint64 sys_time_get_timebase_frequency() +{ + DebuggerBreak(); // Error("sys_time_get_timebase_frequency called on non-PS3 platform."); + return 1; // this function should never ever be called. +} +#endif + +PLATFORM_INTERFACE uint64 g_ClockSpeed; +PLATFORM_INTERFACE unsigned long g_dwClockSpeed; + +PLATFORM_INTERFACE double g_ClockSpeedMicrosecondsMultiplier; +PLATFORM_INTERFACE double g_ClockSpeedMillisecondsMultiplier; +PLATFORM_INTERFACE double g_ClockSpeedSecondsMultiplier; + +#ifdef COMPILER_MSVC64 +extern "C" +{ + unsigned __int64 __rdtsc(); +} + +#pragma intrinsic(__rdtsc) +#endif + +class CCycleCount +{ + friend class CFastTimer; + +public: + CCycleCount(); + CCycleCount( uint64 cycles ); + + void Sample(); // Sample the clock. This takes about 34 clocks to execute (or 26,000 calls per millisecond on a P900). + + void Init(); // Set to zero. + void Init( float initTimeMsec ); + void Init( double initTimeMsec ) { Init( (float)initTimeMsec ); } + void Init( uint64 cycles ); + bool IsLessThan( CCycleCount const &other ) const; // Compare two counts. + + // Convert to other time representations. These functions are slow, so it's preferable to call them + // during display rather than inside a timing block. + unsigned long GetCycles() const; + uint64 GetLongCycles() const; + + unsigned long GetMicroseconds() const; + uint64 GetUlMicroseconds() const; + double GetMicrosecondsF() const; + void SetMicroseconds( unsigned long nMicroseconds ); + + unsigned long GetMilliseconds() const; + double GetMillisecondsF() const; + + double GetSeconds() const; + + CCycleCount& operator+=( CCycleCount const &other ); + + // dest = rSrc1 + rSrc2 + static void Add( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ); // Add two samples together. + + // dest = rSrc1 - rSrc2 + static void Sub( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ); // Add two samples together. + + static uint64 GetTimestamp(); + + uint64 m_Int64; +}; + +class CClockSpeedInit +{ +public: + CClockSpeedInit() + { + Init(); + } + + static void Init() + { + const CPUInformation& pi = GetCPUInformation(); + + if ( IsX360() ) + { + // cycle counter runs as doc'd at 1/64 Xbox 3.2GHz clock speed, thus 50 Mhz + g_ClockSpeed = pi.m_Speed / 64L; + } + else if ( IsPS3() ) + { + g_ClockSpeed = sys_time_get_timebase_frequency(); // CPU clock rate is totally unrelated to time base register frequency on PS3 + } + else + { + g_ClockSpeed = pi.m_Speed; + } + g_dwClockSpeed = (unsigned long)g_ClockSpeed; + + g_ClockSpeedMicrosecondsMultiplier = 1000000.0 / (double)g_ClockSpeed; + g_ClockSpeedMillisecondsMultiplier = 1000.0 / (double)g_ClockSpeed; + g_ClockSpeedSecondsMultiplier = 1.0f / (double)g_ClockSpeed; + } +}; + +class CFastTimer +{ +public: + // These functions are fast to call and should be called from your sampling code. + void Start(); + void End(); + + const CCycleCount & GetDuration() const; // Get the elapsed time between Start and End calls. + CCycleCount GetDurationInProgress() const; // Call without ending. Not that cheap. + + // Return number of cycles per second on this processor. + static inline unsigned long GetClockSpeed(); + +private: + CCycleCount m_Duration; +#ifdef DEBUG_FASTTIMER + bool m_bRunning; // Are we currently running? +#endif +}; + + +// This is a helper class that times whatever block of code it's in +class CTimeScope +{ +public: + CTimeScope( CFastTimer *pTimer ); + ~CTimeScope(); + +private: + CFastTimer *m_pTimer; +}; + +inline CTimeScope::CTimeScope( CFastTimer *pTotal ) +{ + m_pTimer = pTotal; + m_pTimer->Start(); +} + +inline CTimeScope::~CTimeScope() +{ + m_pTimer->End(); +} + +// This is a helper class that times whatever block of code it's in and +// adds the total (int microseconds) to a global counter. +class CTimeAdder +{ +public: + CTimeAdder( CCycleCount *pTotal ); + ~CTimeAdder(); + + void End(); + +private: + CCycleCount *m_pTotal; + CFastTimer m_Timer; +}; + +inline CTimeAdder::CTimeAdder( CCycleCount *pTotal ) +{ + m_pTotal = pTotal; + m_Timer.Start(); +} + +inline CTimeAdder::~CTimeAdder() +{ + End(); +} + +inline void CTimeAdder::End() +{ + if( m_pTotal ) + { + m_Timer.End(); + *m_pTotal += m_Timer.GetDuration(); + m_pTotal = 0; + } +} + + + +// -------------------------------------------------------------------------- // +// Simple tool to support timing a block of code, and reporting the results on +// program exit or at each iteration +// +// Macros used because dbg.h uses this header, thus Msg() is unavailable +// -------------------------------------------------------------------------- // + +#define PROFILE_SCOPE(name) \ + class C##name##ACC : public CAverageCycleCounter \ + { \ + public: \ + ~C##name##ACC() \ + { \ + Msg("%-48s: %6.3f avg (%8.1f total, %7.3f peak, %5d iters)\n", \ + #name, \ + GetAverageMilliseconds(), \ + GetTotalMilliseconds(), \ + GetPeakMilliseconds(), \ + GetIters() ); \ + } \ + }; \ + static C##name##ACC name##_ACC; \ + CAverageTimeMarker name##_ATM( &name##_ACC ) + +#define TIME_SCOPE(name) \ + class CTimeScopeMsg_##name \ + { \ + public: \ + CTimeScopeMsg_##name() { m_Timer.Start(); } \ + ~CTimeScopeMsg_##name() \ + { \ + m_Timer.End(); \ + Msg( #name "time: %.4fms\n", m_Timer.GetDuration().GetMillisecondsF() ); \ + } \ + private: \ + CFastTimer m_Timer; \ + } name##_TSM; + + +// -------------------------------------------------------------------------- // + +class CAverageCycleCounter +{ +public: + CAverageCycleCounter(); + + void Init(); + void MarkIter( const CCycleCount &duration ); + + unsigned GetIters() const; + + double GetAverageMilliseconds() const; + double GetTotalMilliseconds() const; + double GetPeakMilliseconds() const; + +private: + unsigned m_nIters; + CCycleCount m_Total; + CCycleCount m_Peak; + bool m_fReport; + const tchar *m_pszName; +}; + +// -------------------------------------------------------------------------- // + +class CAverageTimeMarker +{ +public: + CAverageTimeMarker( CAverageCycleCounter *pCounter ); + ~CAverageTimeMarker(); + +private: + CAverageCycleCounter *m_pCounter; + CFastTimer m_Timer; +}; + + +// -------------------------------------------------------------------------- // +// CCycleCount inlines. +// -------------------------------------------------------------------------- // + +inline CCycleCount::CCycleCount() +{ + Init( (uint64)0 ); +} + +inline CCycleCount::CCycleCount( uint64 cycles ) +{ + Init( cycles ); +} + +inline void CCycleCount::Init() +{ + Init( (uint64)0 ); +} + +inline void CCycleCount::Init( float initTimeMsec ) +{ + if ( g_ClockSpeedMillisecondsMultiplier > 0 ) + Init( (uint64)(initTimeMsec / g_ClockSpeedMillisecondsMultiplier) ); + else + Init( (uint64)0 ); +} + +inline void CCycleCount::Init( uint64 cycles ) +{ + m_Int64 = cycles; +} + +#if !COMPILER_GCC +#pragma warning(push) +#pragma warning(disable : 4189) // warning C4189: local variable is initialized but not referenced +#endif + +inline void CCycleCount::Sample() +{ +#ifdef COMPILER_MSVC64 + unsigned __int64* pSample = (unsigned __int64*)&m_Int64; + *pSample = __rdtsc(); + // Msg( "Sample = %I64x", pSample ); +#elif defined( _X360 ) + // only need lower 32 bits, avoids doc'd read bug and 32 bit rollover is in 85 seconds + m_Int64 = (uint64)__mftb32(); + // scale back up, needs to be viewed as 1 cycle/clock +#elif defined( _PS3 ) + // only need lower 32 bits, avoids doc'd read bug and 32 bit rollover is in 85 seconds + m_Int64 = (uint64)__mftb(); + // scale back up, needs to be viewed as 1 cycle/clock +#elif defined( __GNUC__ ) + union + { + unsigned long* pSample; + uint64 * pInt64; + } tmp; + tmp.pInt64 = &m_Int64; + __asm__ __volatile__ ( + "rdtsc\n\t" + "movl %%eax, (%0)\n\t" + "movl %%edx, 4(%0)\n\t" + : /* no output regs */ + : "D" (tmp.pSample) + : "%eax", "%edx" ); +#elif defined( _WIN32 ) + unsigned long* pSample = (unsigned long *)&m_Int64; + __asm + { + // force the cpu to synchronize the instruction queue + // NJS: CPUID can really impact performance in tight loops. + //cpuid + //cpuid + //cpuid + mov ecx, pSample + rdtsc + mov [ecx], eax + mov [ecx+4], edx + } +#elif defined( POSIX ) + unsigned long* pSample = (unsigned long *)&m_Int64; + __asm__ __volatile__ ( + "rdtsc\n\t" + "movl %%eax, (%0)\n\t" + "movl %%edx, 4(%0)\n\t" + : /* no output regs */ + : "D" (pSample) + : "%eax", "%edx" ); +#endif +} + +#if !COMPILER_GCC +#pragma warning(pop) +#endif + +inline CCycleCount& CCycleCount::operator+=( CCycleCount const &other ) +{ + m_Int64 += other.m_Int64; + return *this; +} + + +inline void CCycleCount::Add( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ) +{ + dest.m_Int64 = rSrc1.m_Int64 + rSrc2.m_Int64; +} + +inline void CCycleCount::Sub( CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest ) +{ + dest.m_Int64 = rSrc1.m_Int64 - rSrc2.m_Int64; +} + +inline uint64 CCycleCount::GetTimestamp() +{ + CCycleCount c; + c.Sample(); + return c.GetLongCycles(); +} + +inline bool CCycleCount::IsLessThan(CCycleCount const &other) const +{ + return m_Int64 < other.m_Int64; +} + + +inline unsigned long CCycleCount::GetCycles() const +{ + return (unsigned long)m_Int64; +} + +inline uint64 CCycleCount::GetLongCycles() const +{ + return m_Int64; +} + +inline unsigned long CCycleCount::GetMicroseconds() const +{ + return (unsigned long)((m_Int64 * 1000000) / g_ClockSpeed); +} + +inline uint64 CCycleCount::GetUlMicroseconds() const +{ + return ((m_Int64 * 1000000) / g_ClockSpeed); +} + + +inline double CCycleCount::GetMicrosecondsF() const +{ + return (double)( m_Int64 * g_ClockSpeedMicrosecondsMultiplier ); +} + + +inline void CCycleCount::SetMicroseconds( unsigned long nMicroseconds ) +{ + m_Int64 = ((uint64)nMicroseconds * g_ClockSpeed) / 1000000; +} + + +inline unsigned long CCycleCount::GetMilliseconds() const +{ + return (unsigned long)((m_Int64 * 1000) / g_ClockSpeed); +} + + +inline double CCycleCount::GetMillisecondsF() const +{ + return (double)( m_Int64 * g_ClockSpeedMillisecondsMultiplier ); +} + + +inline double CCycleCount::GetSeconds() const +{ + return (double)( m_Int64 * g_ClockSpeedSecondsMultiplier ); +} + + +// -------------------------------------------------------------------------- // +// CFastTimer inlines. +// -------------------------------------------------------------------------- // +inline void CFastTimer::Start() +{ + m_Duration.Sample(); +#ifdef DEBUG_FASTTIMER + m_bRunning = true; +#endif +} + + +inline void CFastTimer::End() +{ + CCycleCount cnt; + cnt.Sample(); + if ( IsX360() ) + { + // have to handle rollover, hires timer is only accurate to 32 bits + // more than one overflow should not have occurred, otherwise caller should use a slower timer + if ( (uint64)cnt.m_Int64 <= (uint64)m_Duration.m_Int64 ) + { + // rollover occurred + cnt.m_Int64 += 0x100000000LL; + } + } + + m_Duration.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64; + +#ifdef DEBUG_FASTTIMER + m_bRunning = false; +#endif +} + +inline CCycleCount CFastTimer::GetDurationInProgress() const +{ + CCycleCount cnt; + cnt.Sample(); + if ( IsX360() ) + { + // have to handle rollover, hires timer is only accurate to 32 bits + // more than one overflow should not have occurred, otherwise caller should use a slower timer + if ( (uint64)cnt.m_Int64 <= (uint64)m_Duration.m_Int64 ) + { + // rollover occurred + cnt.m_Int64 += 0x100000000LL; + } + } + + CCycleCount result; + result.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64; + + return result; +} + + +inline unsigned long CFastTimer::GetClockSpeed() +{ + return g_dwClockSpeed; +} + + +inline CCycleCount const& CFastTimer::GetDuration() const +{ +#ifdef DEBUG_FASTTIMER + assert( !m_bRunning ); +#endif + return m_Duration; +} + + +// -------------------------------------------------------------------------- // +// CAverageCycleCounter inlines + +inline CAverageCycleCounter::CAverageCycleCounter() + : m_nIters( 0 ) +{ +} + +inline void CAverageCycleCounter::Init() +{ + m_Total.Init(); + m_Peak.Init(); + m_nIters = 0; +} + +inline void CAverageCycleCounter::MarkIter( const CCycleCount &duration ) +{ + ++m_nIters; + m_Total += duration; + if ( m_Peak.IsLessThan( duration ) ) + m_Peak = duration; +} + +inline unsigned CAverageCycleCounter::GetIters() const +{ + return m_nIters; +} + +inline double CAverageCycleCounter::GetAverageMilliseconds() const +{ + if ( m_nIters ) + return (m_Total.GetMillisecondsF() / (double)m_nIters); + else + return 0; +} + +inline double CAverageCycleCounter::GetTotalMilliseconds() const +{ + return m_Total.GetMillisecondsF(); +} + +inline double CAverageCycleCounter::GetPeakMilliseconds() const +{ + return m_Peak.GetMillisecondsF(); +} + +// -------------------------------------------------------------------------- // + +inline CAverageTimeMarker::CAverageTimeMarker( CAverageCycleCounter *pCounter ) +{ + m_pCounter = pCounter; + m_Timer.Start(); +} + +inline CAverageTimeMarker::~CAverageTimeMarker() +{ + m_Timer.End(); + m_pCounter->MarkIter( m_Timer.GetDuration() ); +} + + +// CLimitTimer +// Use this to time whether a desired interval of time has passed. It's extremely fast +// to check while running. +class CLimitTimer +{ +public: + void SetLimit( uint64 m_cMicroSecDuration ); + bool BLimitReached( void ); + +private: + uint64 m_lCycleLimit; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Initializes the limit timer with a period of time to measure. +// Input : cMicroSecDuration - How long a time period to measure +//----------------------------------------------------------------------------- +inline void CLimitTimer::SetLimit( uint64 m_cMicroSecDuration ) +{ + uint64 dlCycles = ( ( uint64 ) m_cMicroSecDuration * ( uint64 ) g_dwClockSpeed ) / ( uint64 ) 1000000L; + CCycleCount cycleCount; + cycleCount.Sample( ); + m_lCycleLimit = cycleCount.GetLongCycles( ) + dlCycles; +} + + +//----------------------------------------------------------------------------- +// Purpose: Determines whether our specified time period has passed +// Output: true if at least the specified time period has passed +//----------------------------------------------------------------------------- +inline bool CLimitTimer::BLimitReached( ) +{ + CCycleCount cycleCount; + cycleCount.Sample( ); + return ( cycleCount.GetLongCycles( ) >= m_lCycleLimit ); +} + + + +#endif // FASTTIMER_H diff --git a/external/vpc/public/tier0/ia32detect.h b/external/vpc/public/tier0/ia32detect.h new file mode 100644 index 0000000..e4a63a7 --- /dev/null +++ b/external/vpc/public/tier0/ia32detect.h @@ -0,0 +1,383 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#ifndef IA32DETECT_H +#define IA32DETECT_H + +#ifdef COMPILER_MSVC64 +extern "C" void __cpuid(int* CPUInfo, int InfoType); +#pragma intrinsic (__cpuid) +#endif +/* + This section from http://iss.cs.cornell.edu/ia32.htm + + + */ +typedef unsigned bit; + +enum CPUVendor +{ + INTEL, + AMD, + UNKNOWN_VENDOR +}; +class ia32detect +{ +public: + + enum type_t + { + type_OEM, + type_OverDrive, + type_Dual, + type_reserved + }; + + enum brand_t + { + brand_na, + brand_Celeron, + brand_PentiumIII, + brand_PentiumIIIXeon, + brand_reserved1, + brand_reserved2, + brand_PentiumIIIMobile, + brand_reserved3, + brand_Pentium4, + brand_invalid + }; + +# pragma pack(push, 1) + + struct version_t + { + bit Stepping : 4; + bit Model : 4; + bit Family : 4; + bit Type : 2; + bit Reserved1 : 2; + bit XModel : 4; + bit XFamily : 8; + bit Reserved2 : 4; + }; + + struct misc_t + { + byte Brand; + byte CLFLUSH; + byte Reserved; + byte APICId; + }; + + struct feature_t + { + bit FPU : 1; // Floating Point Unit On-Chip + bit VME : 1; // Virtual 8086 Mode Enhancements + bit DE : 1; // Debugging Extensions + bit PSE : 1; // Page Size Extensions + bit TSC : 1; // Time Stamp Counter + bit MSR : 1; // Model Specific Registers + bit PAE : 1; // Physical Address Extension + bit MCE : 1; // Machine Check Exception + bit CX8 : 1; // CMPXCHG8 Instruction + bit APIC : 1; // APIC On-Chip + bit Reserved1 : 1; + bit SEP : 1; // SYSENTER and SYSEXIT instructions + bit MTRR : 1; // Memory Type Range Registers + bit PGE : 1; // PTE Global Bit + bit MCA : 1; // Machine Check Architecture + bit CMOV : 1; // Conditional Move Instructions + bit PAT : 1; // Page Attribute Table + bit PSE36 : 1; // 32-bit Page Size Extension + bit PSN : 1; // Processor Serial Number + bit CLFSH : 1; // CLFLUSH Instruction + bit Reserved2 : 1; + bit DS : 1; // Debug Store + bit ACPI : 1; // Thermal Monitor and Software Controlled Clock Facilities + bit MMX : 1; // Intel MMX Technology + bit FXSR : 1; // FXSAVE and FXRSTOR Instructions + bit SSE : 1; // Intel SSE Technology + bit SSE2 : 1; // Intel SSE2 Technology + bit SS : 1; // Self Snoop + bit HTT : 1; // Hyper Threading + bit TM : 1; // Thermal Monitor + bit Reserved3 : 1; + bit PBE : 1; // Pending Brk. EN. + }; + +# pragma pack(pop) + + tstring vendor_name; + CPUVendor vendor; + tstring brand; + version_t version; + misc_t misc; + feature_t feature; + byte *cache; + + ia32detect () + { + + cache = 0; + uint32 m = init0(); + + uint32 *d = new uint32[m * 4]; + + for (uint32 i = 1; i <= m; i++) + { + +#ifdef COMPILER_MSVC64 + __cpuid((int *) (d + (i-1) * 4), i); + +#else + uint32 *t = d + (i - 1) * 4; + __asm + { + mov eax, i; + mov esi, t; + + cpuid; + + mov dword ptr [esi + 0x0], eax; + mov dword ptr [esi + 0x4], ebx; + mov dword ptr [esi + 0x8], ecx; + mov dword ptr [esi + 0xC], edx; + } +#endif + } + + if (m >= 1) + init1(d); + + if (m >= 2) + init2(d[4] & 0xFF); + + delete [] d; + + init0x80000000(); + + + //----------------------------------------------------------------------- + // Get the vendor of the processor + //----------------------------------------------------------------------- + if (_tcscmp(vendor_name.c_str(), _T("GenuineIntel")) == 0) + { + vendor = INTEL; + + } + else if (_tcscmp(vendor_name.c_str(), _T("AuthenticAMD")) == 0) + { + vendor = AMD; + + } + else + { + vendor = UNKNOWN_VENDOR; + } + } + + const tstring version_text () const + { + tchar b[128]; + + _stprintf(b, _T("%d.%d.%d %s XVersion(%d.%d)"), + version.Family, version.Model, version.Stepping, type_text(), version.XFamily, version.XModel); + + return tstring(b); + } + +protected: + + const tchar * type_text () const + { + static const tchar *text[] = + { + _T("Intel OEM Processor"), + _T("Intel OverDrive(R) Processor"), + _T("Intel Dual Processor"), + _T("reserved") + }; + + return text[version.Type]; + } + + const tstring brand_text () const + { + static const tchar *text[] = + { + _T("n/a"), + _T("Celeron"), + _T("Pentium III"), + _T("Pentium III Xeon"), + _T("reserved (4)"), + _T("reserved (5)"), + _T("Pentium III Mobile"), + _T("reserved (7)"), + _T("Pentium 4") + }; + + if (misc.Brand < brand_invalid) + return tstring(text[misc.Brand]); + else + { + tchar b[32]; + + _stprintf(b, _T("Brand %d (Update)"), misc.Brand); + + return tstring(b); + } + } + +private: + + uint32 init0 () + { + uint32 m; + +#ifdef COMPILER_MSVC64 + int data[4]; + tchar * s1; + + s1 = (tchar *) &data[1]; + s1[12] = '\0'; + __cpuid(data, 0); + m = data[0]; + vendor_name = s1; +#else + tchar s1[13]; + + s1[12] = '\0'; + __asm + { + xor eax, eax; + cpuid; + mov m, eax; + mov dword ptr s1 + 0, ebx; + mov dword ptr s1 + 4, edx; + mov dword ptr s1 + 8, ecx; + } + vendor_name = s1; +#endif + return m; + } + + void init1 (uint32 *d) + { + version = *(version_t *)&d[0]; + misc = *(misc_t *)&d[1]; + feature = *(feature_t *)&d[3]; + } + + void process2 (uint32 d, bool c[]) + { + if ((d & 0x80000000) == 0) + for (int i = 0; i < 32; i += 8) + c[(d >> i) & 0xFF] = true; + } + + void init2 (byte count) + { + uint32 d[4]; + bool c[256]; + + for (int ci1 = 0; ci1 < 256; ci1++) + c[ci1] = false; + + for (int i = 0; i < count; i++) + { +#ifdef COMPILER_MSVC64 + __cpuid((int *) d, 2); +#else + __asm + { + mov eax, 2; + lea esi, d; + cpuid; + mov [esi + 0x0], eax; + mov [esi + 0x4], ebx; + mov [esi + 0x8], ecx; + mov [esi + 0xC], edx; + } +#endif + + if (i == 0) + d[0] &= 0xFFFFFF00; + + process2(d[0], c); + process2(d[1], c); + process2(d[2], c); + process2(d[3], c); + } + + int m = 0; + + for (int ci2 = 0; ci2 < 256; ci2++) + if (c[ci2]) + m++; + + cache = new byte[m]; + + m = 0; + + for (int ci3 = 1; ci3 < 256; ci3++) + if (c[ci3]) + cache[m++] = ci3; + + cache[m] = 0; + } + + void init0x80000000 () + { + uint32 m; + +#ifdef COMPILER_MSVC64 + int data[4]; + __cpuid(data, 0x80000000); + m = data[0]; +#else + __asm + { + mov eax, 0x80000000; + cpuid; + mov m, eax + } +#endif + + if ((m & 0x80000000) != 0) + { + uint32 *d = new uint32[(m - 0x80000000) * 4]; + + for (uint32 i = 0x80000001; i <= m; i++) + { + uint32 *t = d + (i - 0x80000001) * 4; + +#ifdef COMPILER_MSVC64 + __cpuid((int *) (d + (i - 0x80000001) * 4), i); +#else + __asm + { + mov eax, i; + mov esi, t; + cpuid; + mov dword ptr [esi + 0x0], eax; + mov dword ptr [esi + 0x4], ebx; + mov dword ptr [esi + 0x8], ecx; + mov dword ptr [esi + 0xC], edx; + } +#endif + } + + if (m >= 0x80000002) + brand = (tchar *)(d + 4); + + // note the assignment to brand above does a copy, we need to delete + delete[] d; + } + } +}; + +#endif // IA32DETECT_H diff --git a/external/vpc/public/tier0/icommandline.h b/external/vpc/public/tier0/icommandline.h new file mode 100644 index 0000000..d56d5a3 --- /dev/null +++ b/external/vpc/public/tier0/icommandline.h @@ -0,0 +1,65 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// + +#ifndef TIER0_ICOMMANDLINE_H +#define TIER0_ICOMMANDLINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + + +//----------------------------------------------------------------------------- +// Purpose: Interface to engine command line +//----------------------------------------------------------------------------- +abstract_class ICommandLine +{ +public: + virtual void CreateCmdLine( const char *commandline ) = 0; + virtual void CreateCmdLine( int argc, char **argv ) = 0; + virtual const char *GetCmdLine( void ) const = 0; + + // Check whether a particular parameter exists + virtual const char *CheckParm( const char *psz, const char **ppszValue = 0 ) const = 0; + virtual void RemoveParm( const char *parm ) = 0; + virtual void AppendParm( const char *pszParm, const char *pszValues ) = 0; + + // Returns the argument after the one specified, or the default if not found + virtual const char *ParmValue( const char *psz, const char *pDefaultVal = 0 ) const = 0; + virtual int ParmValue( const char *psz, int nDefaultVal ) const = 0; + virtual float ParmValue( const char *psz, float flDefaultVal ) const = 0; + + // Gets at particular parameters + virtual int ParmCount() const = 0; + virtual int FindParm( const char *psz ) const = 0; // Returns 0 if not found. + virtual const char* GetParm( int nIndex ) const = 0; + + // copies the string passwed + virtual void SetParm( int nIndex, char const *pNewParm ) =0; +}; + +//----------------------------------------------------------------------------- +// Gets a singleton to the commandline interface +// NOTE: The #define trickery here is necessary for backwards compat: +// this interface used to lie in the vstdlib library. +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE ICommandLine *CommandLine(); + + +//----------------------------------------------------------------------------- +// Process related functions +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE const tchar *Plat_GetCommandLine(); +#ifndef _WIN32 +// helper function for OS's that don't have a ::GetCommandLine() call +PLATFORM_INTERFACE void Plat_SetCommandLine( const char *cmdLine ); +#endif +PLATFORM_INTERFACE const char *Plat_GetCommandLineA(); + + +#endif // TIER0_ICOMMANDLINE_H + diff --git a/external/vpc/public/tier0/ioctlcodes.h b/external/vpc/public/tier0/ioctlcodes.h new file mode 100644 index 0000000..7fc8efb --- /dev/null +++ b/external/vpc/public/tier0/ioctlcodes.h @@ -0,0 +1,29 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef IOCTLCODES_H +#define IOCTLCODES_H +#pragma once + +// Define the IOCTL codes we will use. The IOCTL code contains a command +// identifier, plus other information about the device, the type of access +// with which the file must have been opened, and the type of buffering. + +// Device type -- in the "User Defined" range." +#define DEVICE_FILE_TYPE 40000 + + +// The IOCTL function codes from 0x800 to 0xFFF are for customer use. + +#define IOCTL_WRITE_MSR \ + CTL_CODE( DEVICE_FILE_TYPE, 0x900, METHOD_BUFFERED, FILE_READ_ACCESS ) + +#define IOCTL_READ_MSR \ + CTL_CODE( DEVICE_FILE_TYPE, 0x901, METHOD_BUFFERED, FILE_READ_ACCESS ) + + +#endif IOCTLCODES_H diff --git a/external/vpc/public/tier0/k8performancecounters.h b/external/vpc/public/tier0/k8performancecounters.h new file mode 100644 index 0000000..d405a8d --- /dev/null +++ b/external/vpc/public/tier0/k8performancecounters.h @@ -0,0 +1,2040 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#ifndef K8PERFORMANCECOUNTERS_H +#define K8PERFORMANCECOUNTERS_H + +/* + * AMD K8 events. + * + */ + +#ifdef COMPILER_MSVC64 +extern "C" +{ + unsigned __int64 __readpmc(unsigned long); +} + +#pragma intrinsic(__readpmc) +#endif + + +typedef union EVENT_MASK(NULL_MASK) +{ + // no tests defined + uint16 flat; +} EVENT_MASK(NULL_MASK); + + +#define MSR_K8_EVNTSEL0 0xC0010000 /* .. 0xC0010003 */ +#define MSR_K8_PERFCTR0 0xC0010004 /* .. 0xC0010007 */ + +# pragma pack(push, 1) + + + +// access to these bits is through the methods +typedef union PerfEvtSel +{ + struct + { + uint64 EventMask : 8; + + uint64 UnitMask : 8; + uint64 USR : 1; + uint64 OS : 1; + uint64 Edge : 1; + uint64 PC : 1; + uint64 INTAPIC : 1; + uint64 Reserved21 : 1; + uint64 Enable : 1; + uint64 Complement : 1; // aka INV + uint64 Threshold : 8; // aka CounterMask + uint64 Reserver32 : 32; + }; + uint64 flat; + +} PerfEvtSel; + + +enum UnitEncode +{ + FP, + LS, + DC, + BU, + IC, + UE_Unknown, + FR, + NB +}; + +# pragma pack(pop) + +// Turn off the no return value warning in ReadCounter. +#pragma warning( disable : 4035 ) +#define k8NUM_COUNTERS 4 +class k8BaseEvent +{ +public: + + PME * pme; + + PerfEvtSel eventSelect[k8NUM_COUNTERS]; + + unsigned short m_eventMask; + int event_id; + tchar * name; + tchar revRequired; + int eventSelectNum; + UnitEncode unitEncode; + + + void SetCounter(int n) + { + if (n < 0) + n = 0; + else if (n > 3) + n = 3; + eventSelectNum = n; + + } + k8BaseEvent() + { + pme = PME::Instance(); + + for(int i = 0; i< k8NUM_COUNTERS; i++) + { + eventSelect[i].flat = 0; + + } + eventSelectNum = 0; + + m_eventMask = 0; + event_id = 0; + name = 0; + revRequired = 'A'; + + + } + + void SetCaptureMode(PrivilegeCapture priv) + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + StopCounter(); + + switch (priv) + { + case OS_Only: + select.USR = 0; + select.OS = 1; + break; + + case USR_Only: + select.USR = 1; + select.OS = 0; + break; + + case OS_and_USR: + select.USR = 1; + select.OS = 1; + break; + } + + + select.UnitMask = m_eventMask; + select.EventMask = event_id; + + + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + pme->WriteMSR(selectPort, select.flat); + } + + + void SetFiltering(CompareState compareEnable, + CompareMethod compareMethod, + uint8 threshold, + EdgeState edgeEnable) + { + + PerfEvtSel & select = eventSelect[eventSelectNum]; + + StopCounter(); + + if (compareEnable == CompareDisable) + select.Threshold = 0; + else + select.Threshold = threshold; + + select.Complement = compareMethod; + + select.Edge = edgeEnable; + + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + pme->WriteMSR(selectPort, select.flat); + + + } + + + void StartCounter() + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + + select.Enable = 1; + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + + pme->WriteMSR(selectPort, select.flat); + + } + void StopCounter() + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + select.Enable = 0; + int selectPort = MSR_K8_EVNTSEL0 + eventSelectNum; + + pme->WriteMSR(selectPort, select.flat); + } + + + + void ClearCounter() + { + PerfEvtSel & select = eventSelect[eventSelectNum]; + + int counterPort = MSR_K8_PERFCTR0 + eventSelectNum; + + pme->WriteMSR(counterPort, 0ui64 ); // clear + } + + void WriteCounter(int64 value) + { + + PerfEvtSel & select = eventSelect[eventSelectNum]; + + int counterPort = MSR_K8_PERFCTR0 + eventSelectNum; + pme->WriteMSR(counterPort, value); // clear + } + + int64 ReadCounter() + { + +#if PME_DEBUG + PerfEvtSel & select = eventSelect[eventSelectNum]; + + if (select.USR == 0 && select.OS == 0) + return -1; // no area to collect, use SetCaptureMode + + if (select.EventMask == 0) + return -2; // no event mask set + + if (eventSelectNum < 0 || eventSelectNum > 3) + return -3; // counter not legal + + // check revision + +#endif + + // ReadMSR should work here too, but RDPMC should be faster + //ReadMSR(counterPort, int64); + + // we need to copy this into a temp for some reason +#ifdef COMPILER_MSVC64 + return __readpmc((unsigned long) eventSelectNum); +#else + int temp = eventSelectNum; + _asm + { + mov ecx, temp + RDPMC + } +#endif + + } + + +}; +#pragma warning( default : 4035 ) + + + + +typedef union EVENT_MASK(k8_dispatched_fpu_ops) +{ + // event 0 + struct + { + uint16 AddPipeOps:1; // Add pipe ops excluding junk ops" }, + uint16 MulPipeOps:1; // Multiply pipe ops excluding junk ops" },, + uint16 StoreOps:1; // Store pipe ops excluding junk ops" }, + uint16 AndPipeOpsJunk:1; // Add pipe junk ops" },, + uint16 MulPipeOpsJunk:1; // Multiply pipe junk ops" }, + uint16 StoreOpsJunk:1; // Store pipe junk ops" } } + }; + uint16 flat; +} EVENT_MASK(k8_dispatched_fpu_ops); + +class k8Event_DISPATCHED_FPU_OPS : public k8BaseEvent +{ +public: + + k8Event_DISPATCHED_FPU_OPS() + { + eventMask = (EVENT_MASK(k8_dispatched_fpu_ops) *)&m_eventMask; + + event_id = 0x00; + unitEncode = FP; + name = _T("Dispatched FPU ops"); + revRequired = 'B'; + } + EVENT_MASK(k8_dispatched_fpu_ops) * eventMask; + +}; + +////////////////////////////////////////////////////////// + + + +class k8Event_NO_FPU_OPS : public k8BaseEvent +{ +public: + + k8Event_NO_FPU_OPS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x01; + unitEncode = FP; + + name = _T("Cycles with no FPU ops retired"); + revRequired = 'B'; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + +////////////////////////////////////////////////////////// + +class k8Event_FAST_FPU_OPS : public k8BaseEvent +{ +public: + + k8Event_FAST_FPU_OPS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x02; + unitEncode = FP; + + name = _T("Dispatched FPU ops that use the fast flag interface"); + revRequired = 'B'; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +////////////////////////////////////////////////////////// + + +typedef union EVENT_MASK(k8_segment_register_load) +{ + + struct + { + uint16 ES:1; + uint16 CS:1; + uint16 SS:1; + uint16 DS:1; + uint16 FS:1; + uint16 GS:1; + uint16 HS:1; + }; + uint16 flat; +} EVENT_MASK(k8_segment_register_load); + + +class k8Event_SEG_REG_LOAD : public k8BaseEvent +{ +public: + + k8Event_SEG_REG_LOAD() + { + eventMask = (EVENT_MASK(k8_segment_register_load) *)&m_eventMask; + name = _T("Segment register load"); + event_id = 0x20; + unitEncode = LS; + + } + EVENT_MASK(k8_segment_register_load) * eventMask; + +}; + + +class k8Event_SELF_MODIFY_RESYNC : public k8BaseEvent +{ +public: + + k8Event_SELF_MODIFY_RESYNC() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural resync caused by self modifying code"); + event_id = 0x21; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; +class k8Event_LS_RESYNC_BY_SNOOP : public k8BaseEvent +{ +public: + + k8Event_LS_RESYNC_BY_SNOOP() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x22; + unitEncode = LS; + + name = _T("Microarchitectural resync caused by snoop"); + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; +class k8Event_LS_BUFFER_FULL : public k8BaseEvent +{ +public: + + k8Event_LS_BUFFER_FULL() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("LS Buffer 2 Full"); + event_id = 0x23; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +typedef union EVENT_MASK(k8_locked_op) +{ + + + struct + { + uint16 NumLockInstr : 1; //Number of lock instructions executed + uint16 NumCyclesInRequestGrant : 1; //Number of cycles spent in the lock request/grant stage + + uint16 NumCyclesForLock:1; + /*Number of cycles a lock takes to complete once it is + non-speculative and is the oldest load/store operation + (non-speculative cycles in Ls2 entry 0)*/ + + + }; + uint16 flat; + + +} EVENT_MASK(k8_locked_op); + + + +class k8Event_LOCKED_OP : public k8BaseEvent +{ +public: + + EVENT_MASK(k8_locked_op) * eventMask; + + k8Event_LOCKED_OP() + { + eventMask = (EVENT_MASK(k8_locked_op) *)&m_eventMask; + name = _T("Locked operation"); + event_id = 0x24; + unitEncode = LS; + + revRequired = 'C'; + } + + +}; + +class k8Event_OP_LATE_CANCEL : public k8BaseEvent +{ +public: + + k8Event_OP_LATE_CANCEL() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural late cancel of an operation"); + event_id = 0x25; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("OP_LATE_CANCEL"); + + +}; +class k8Event_CFLUSH_RETIRED : public k8BaseEvent +{ +public: + + k8Event_CFLUSH_RETIRED() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired CFLUSH instructions"); + event_id = 0x26; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("CFLUSH_RETIRED"); + + +}; +class k8Event_CPUID_RETIRED : public k8BaseEvent +{ +public: + + k8Event_CPUID_RETIRED() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired CPUID instructions"); + event_id = 0x27; + unitEncode = LS; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("CPUID_RETIRED"); + + +}; + +typedef union EVENT_MASK( k8_cache) +{ + + struct + { + uint16 Invalid:1; + uint16 Exclusive:1; + uint16 Shared:1; + uint16 Owner:1; + uint16 Modified:1; + }; + uint16 flat; + +}EVENT_MASK( k8_cache); + /* 0x40-0x47: from K7 official event set */ + + +class k8Event_DATA_CACHE_ACCESSES : public k8BaseEvent +{ + k8Event_DATA_CACHE_ACCESSES() + { + + event_id = 0x40; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //_T("DATA_CACHE_ACCESSES"), + name = _T("Data cache accesses"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + +class k8Event_DATA_CACHE_MISSES : public k8BaseEvent +{ + k8Event_DATA_CACHE_MISSES() + { + + event_id = 0x41; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //_T("DATA_CACHE_MISSES"), + name = _T("Data cache misses"); + } + EVENT_MASK(NULL_MASK) * eventMask; +}; + +class k8Event_DATA_CACHE_REFILLS_FROM_L2 : public k8BaseEvent +{ + k8Event_DATA_CACHE_REFILLS_FROM_L2() + { + + event_id = 0x42; + unitEncode = DC; + + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + + + name = _T("Data cache refills from L2"); + } + EVENT_MASK(k8_cache) * eventMask; + +}; + +class k8Event_DATA_CACHE_REFILLS_FROM_SYSTEM : public k8BaseEvent +{ + k8Event_DATA_CACHE_REFILLS_FROM_SYSTEM() + { + + event_id = 0x43; + unitEncode = DC; + + + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + + //UM(k7_um_moesi), + //_T("DATA_CACHE_REFILLS_FROM_SYSTEM"), + name = _T("Data cache refills from system"); + } + EVENT_MASK(k8_cache) * eventMask; + +}; + +class k8Event_DATA_CACHE_WRITEBACKS : public k8BaseEvent +{ + k8Event_DATA_CACHE_WRITEBACKS() + { + + event_id = 0x44; + unitEncode = DC; + + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + + //UM(k7_um_moesi), + //_T("DATA_CACHE_WRITEBACKS"), + name = _T("Data cache writebacks"); + } + EVENT_MASK(k8_cache) * eventMask; + + +}; + +class k8Event_L1_DTLB_MISSES_AND_L2_DTLB_HITS : public k8BaseEvent +{ + k8Event_L1_DTLB_MISSES_AND_L2_DTLB_HITS() + { + + event_id = 0x45; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + name = _T("L1 DTLB misses and L2 DTLB hits"); + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; + +class k8Event_L1_AND_L2_DTLB_MISSES : public k8BaseEvent +{ + k8Event_L1_AND_L2_DTLB_MISSES() + { + + event_id = 0x46; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + name = _T("L1 and L2 DTLB misses") ; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + +class k8Event_MISALIGNED_DATA_REFERENCES : public k8BaseEvent +{ + k8Event_MISALIGNED_DATA_REFERENCES() + { + + event_id = 0x47; + unitEncode = DC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //NULL, _T("MISALIGNED_DATA_REFERENCES"), + name = _T("Misaligned data references"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + + +class k8Event_ACCESS_CANCEL_LATE : public k8BaseEvent +{ +public: + + k8Event_ACCESS_CANCEL_LATE() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural late cancel of an access"); + event_id = 0x48; + unitEncode = DC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("ACCESS_CANCEL_LATE"); + + +}; +class k8Event_ACCESS_CANCEL_EARLY : public k8BaseEvent +{ +public: + + k8Event_ACCESS_CANCEL_EARLY() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Microarchitectural early cancel of an access"); + event_id = 0x49; + unitEncode = DC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("ACCESS_CANCEL_EARLY"); + + +}; +typedef union EVENT_MASK( k8_ecc) +{ + struct + { + uint16 ScrubberError : 1; // Scrubber error" }, + uint16 PiggybackScrubberErrors : 1; // Piggyback scrubber errors" } } + }; + uint16 flat; + +}EVENT_MASK( k8_ecc); + + +class k8Event_ECC_BIT_ERR : public k8BaseEvent +{ +public: + + k8Event_ECC_BIT_ERR() + { + eventMask = (EVENT_MASK(k8_ecc) *)&m_eventMask; + name = _T("One bit ECC error recorded found by scrubber"); + event_id = 0x4A; + unitEncode = DC; + + } + EVENT_MASK(k8_ecc) * eventMask; + // name = _T("ECC_BIT_ERR"); + + +}; + +// 4B +typedef union EVENT_MASK( k8_distpatch_prefetch_instructions) +{ + struct + { + uint16 Load : 1; + uint16 Store : 1; + uint16 NTA : 1; + }; + uint16 flat; + + +}EVENT_MASK( k8_distpatch_prefetch_instructions); + +class k8Event_DISPATCHED_PRE_INSTRS : public k8BaseEvent +{ +public: + + k8Event_DISPATCHED_PRE_INSTRS() + { + eventMask = (EVENT_MASK(k8_distpatch_prefetch_instructions) *)&m_eventMask; + name = _T("Dispatched prefetch instructions"); + event_id = 0x4B; + unitEncode = DC; + + } + EVENT_MASK(k8_distpatch_prefetch_instructions) * eventMask; + // name = _T("DISPATCHED_PRE_INSTRS"); + + /* 0x4C: added in Revision C */ + +}; + + + +typedef union EVENT_MASK( k8_lock_accesses) +{ + struct + { + uint16 DcacheAccesses:1; // Number of dcache accesses by lock instructions" }, + uint16 DcacheMisses:1; // Number of dcache misses by lock instructions" } } + }; + uint16 flat; + +}EVENT_MASK( k8_lock_accesses); + + + +class k8Event_LOCK_ACCESSES : public k8BaseEvent +{ +public: + + k8Event_LOCK_ACCESSES() + { + eventMask = (EVENT_MASK(k8_lock_accesses) *)&m_eventMask; + name = _T("DCACHE accesses by locks") ; + event_id = 0x4C; + unitEncode = DC; + + revRequired = 'C'; + } + EVENT_MASK(k8_lock_accesses) * eventMask; + + +}; + + +class k8Event_CYCLES_PROCESSOR_IS_RUNNING : public k8BaseEvent +{ +public: + + k8Event_CYCLES_PROCESSOR_IS_RUNNING() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Cycles processor is running (not in HLT or STPCLK)"); + event_id = 0x76; + unitEncode = BU; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("CYCLES_PROCESSOR_IS_RUNNING"); /* undocumented *; + + +}; + + +typedef union EVENT_MASK( k8_internal_L2_request) +{ + struct + { + uint16 ICFill:1; // IC fill" }, + uint16 DCFill:1; // DC fill" }, + uint16 TLBReload:1; // TLB reload" }, + uint16 TagSnoopRequest:1; // Tag snoop request" }, + uint16 CancelledRequest:1; // Cancelled request" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_internal_L2_request); + +class k8Event_BU_INT_L2_REQ : public k8BaseEvent +{ +public: + + k8Event_BU_INT_L2_REQ() + { + eventMask = (EVENT_MASK(k8_internal_L2_request) *)&m_eventMask; + name = _T("Internal L2 request"); + unitEncode = BU; + event_id = 0x7D; + } + + EVENT_MASK(k8_internal_L2_request) * eventMask; +} ; + + // name = _T("BU_INT_L2_REQ"); + + + +// 7E +typedef union EVENT_MASK( k8_fill_request_missed_L2) +{ + + struct + { + uint16 ICFill:1; // IC fill" }, + uint16 DCFill:1; // DC fill" }, + uint16 TLBReload:1; // TLB reload" }, + }; + uint16 flat; + +} EVENT_MASK( k8_fill_request_missed_L2); + + +class k8Event_BU_FILL_REQ : public k8BaseEvent +{ +public: + + k8Event_BU_FILL_REQ() + { + eventMask = (EVENT_MASK(k8_fill_request_missed_L2) *)&m_eventMask; + name = _T("Fill request that missed in L2"); + event_id = 0x7E; + unitEncode = BU; + + } + EVENT_MASK(k8_fill_request_missed_L2) * eventMask; + // name = _T("BU_FILL_REQ"); + + + +}; + + + + +// 7F +typedef union EVENT_MASK( k8_fill_into_L2) +{ + + struct + { + uint16 DirtyL2Victim:1; // Dirty L2 victim + uint16 VictimFromL2:1; // Victim from L2 + }; + uint16 flat; + +}EVENT_MASK( k8_fill_into_L2); + +class k8Event_BU_FILL_L2 : public k8BaseEvent +{ +public: + + k8Event_BU_FILL_L2() + { + eventMask = (EVENT_MASK(k8_fill_into_L2) *)&m_eventMask; + name = _T("Fill into L2"); + event_id = 0x7F; + unitEncode = BU; + + } + EVENT_MASK(k8_fill_into_L2) * eventMask; + // name = _T("BU_FILL_L2"); + + +}; + +class k8Event_INSTRUCTION_CACHE_FETCHES : public k8BaseEvent +{ +public: + k8Event_INSTRUCTION_CACHE_FETCHES() + { + event_id = 0x80; + unitEncode = IC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + name = _T("Instruction cache fetches"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +class k8Event_INSTRUCTION_CACHE_MISSES : public k8BaseEvent +{ +public: + k8Event_INSTRUCTION_CACHE_MISSES() + { + event_id = 0x81; + unitEncode = IC; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //0xF, NULL, _T("INSTRUCTION_CACHE_MISSES"), + name = _T("Instruction cache misses"); + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +class k8Event_IC_REFILL_FROM_L2 : public k8BaseEvent +{ +public: + + k8Event_IC_REFILL_FROM_L2() + { + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + name = _T("Refill from L2"); + event_id = 0x82; + unitEncode = IC; + + } + EVENT_MASK(k8_cache) * eventMask; + // name = _T("IC_REFILL_FROM_L2"); + + + +}; +class k8Event_IC_REFILL_FROM_SYS : public k8BaseEvent +{ +public: + + k8Event_IC_REFILL_FROM_SYS() + { + eventMask = (EVENT_MASK(k8_cache) *)&m_eventMask; + name = _T("Refill from system"); + event_id = 0x83; + unitEncode = IC; + + } + EVENT_MASK(k8_cache) * eventMask; + // name = _T("IC_REFILL_FROM_SYS"); + + + +}; +class k8Event_L1_ITLB_MISSES_AND_L2_ITLB_HITS : public k8BaseEvent +{ +public: + k8Event_L1_ITLB_MISSES_AND_L2_ITLB_HITS() + { + + event_id = 0x84; + unitEncode = IC; + + name = _T("L1 ITLB misses (and L2 ITLB hits)"); + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + + } + EVENT_MASK(NULL_MASK) * eventMask; + + +}; + +class k8Event_L1_AND_L2_ITLB_MISSES : public k8BaseEvent +{ +public: + k8Event_L1_AND_L2_ITLB_MISSES() + { + event_id = 0x85; + unitEncode = IC; + + name = _T("(L1 and) L2 ITLB misses"); + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + + + +class k8Event_IC_RESYNC_BY_SNOOP : public k8BaseEvent +{ +public: + + k8Event_IC_RESYNC_BY_SNOOP() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + event_id = 0x86; + unitEncode = IC; + + name = _T("Microarchitectural resync caused by snoop"); + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_RESYNC_BY_SNOOP"); + /* similar to 0x22; but IC unit instead of LS unit */ + + + +}; +class k8Event_IC_FETCH_STALL : public k8BaseEvent +{ +public: + + k8Event_IC_FETCH_STALL() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Instruction fetch stall"); + event_id = 0x87; + unitEncode = IC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_FETCH_STALL"); + + + +}; +class k8Event_IC_STACK_HIT : public k8BaseEvent +{ +public: + + k8Event_IC_STACK_HIT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Return stack hit"); + event_id = 0x88; + unitEncode = IC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_STACK_HIT"); + + + +}; +class k8Event_IC_STACK_OVERFLOW : public k8BaseEvent +{ +public: + + k8Event_IC_STACK_OVERFLOW() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Return stack overflow"); + event_id = 0x89; + unitEncode = IC; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("IC_STACK_OVERFLOW"); + + + + +}; + + /* 0xC0-0xC7: from K7 official event set */ +class k8Event_RETIRED_INSTRUCTIONS : public k8BaseEvent +{ +public: + k8Event_RETIRED_INSTRUCTIONS() + { + event_id = 0xC0; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + //0xF, NULL, _T("RETIRED_INSTRUCTIONS"), + name = _T("Retired instructions (includes exceptions, interrupts, resyncs)"); + } + EVENT_MASK(NULL_MASK) * eventMask; +}; + +class k8Event_RETIRED_OPS : public k8BaseEvent +{ +public: + k8Event_RETIRED_OPS() + { + event_id = 0xC1; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_OPS"), + name = _T("Retired Ops") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_BRANCHES : public k8BaseEvent +{ +public: + k8Event_RETIRED_BRANCHES() + { + event_id = 0xC2; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_BRANCHES"), + name = _T("Retired branches (conditional, unconditional, exceptions, interrupts)") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_BRANCHES_MISPREDICTED : public k8BaseEvent +{ +public: + k8Event_RETIRED_BRANCHES_MISPREDICTED() + { + event_id = 0xC3; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_BRANCHES_MISPREDICTED"), + name = _T("Retired branches mispredicted") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_TAKEN_BRANCHES : public k8BaseEvent +{ +public: + k8Event_RETIRED_TAKEN_BRANCHES() + { + event_id = 0xC4; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_TAKEN_BRANCHES"), + name = _T("Retired taken branches") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_TAKEN_BRANCHES_MISPREDICTED : public k8BaseEvent +{ +public: + k8Event_RETIRED_TAKEN_BRANCHES_MISPREDICTED() + { + event_id = 0xC5; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_TAKEN_BRANCHES_MISPREDICTED"), + name = _T("Retired taken branches mispredicted") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_FAR_CONTROL_TRANSFERS : public k8BaseEvent +{ +public: + k8Event_RETIRED_FAR_CONTROL_TRANSFERS() + { + event_id = 0xC6; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_FAR_CONTROL_TRANSFERS"), + name = _T("Retired far control transfers") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; +class k8Event_RETIRED_RESYNC_BRANCHES : public k8BaseEvent +{ +public: + k8Event_RETIRED_RESYNC_BRANCHES() + { + event_id = 0xC7; + unitEncode = FR; + + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + //0xF, NULL, _T("RETIRED_RESYNC_BRANCHES"), + name = _T("Retired resync branches (only non-control transfer branches counted)") ; + } + EVENT_MASK(NULL_MASK) * eventMask; +}; + +class k8Event_RETIRED_NEAR_RETURNS : public k8BaseEvent +{ +public: + + k8Event_RETIRED_NEAR_RETURNS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired near returns"); + event_id = 0xC8; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + + + +}; +class k8Event_RETIRED_RETURNS_MISPREDICT : public k8BaseEvent +{ +public: + + k8Event_RETIRED_RETURNS_MISPREDICT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired near returns mispredicted"); + event_id = 0xC9; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("RETIRED_RETURNS_MISPREDICT"); + + +}; +class k8Event_RETIRED_BRANCH_MISCOMPARE : public k8BaseEvent +{ +public: + + k8Event_RETIRED_BRANCH_MISCOMPARE() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Retired taken branches mispredicted due to address miscompare"); + event_id = 0xCA; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("RETIRED_BRANCH_MISCOMPARE"); + + +}; + + + /* Revision B and later */ + +typedef union EVENT_MASK( k8_retired_fpu_instr) +{ + struct + { + uint16 DirtyL2Victim:1; // x87 instructions + uint16 CombinedMMX_3DNow:1; // Combined MMX & 3DNow! instructions" }, + uint16 CombinedPackedSSE_SSE2:1; // Combined packed SSE and SSE2 instructions" }, + uint16 CombinedScalarSSE_SSE2:1; // Combined scalar SSE and SSE2 instructions" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_retired_fpu_instr); + + +class k8Event_RETIRED_FPU_INSTRS : public k8BaseEvent +{ +public: + + k8Event_RETIRED_FPU_INSTRS() + { + eventMask = (EVENT_MASK(k8_retired_fpu_instr) *)&m_eventMask; + event_id = 0xCB; + unitEncode = FR; + + name = _T("Retired FPU instructions"); + revRequired = 'B'; + } + EVENT_MASK(k8_retired_fpu_instr) * eventMask; + /* Revision B and later */ + + + +}; + +// CC +typedef union EVENT_MASK( k8_retired_fastpath_double_op_instr ) +{ + + struct + { + uint16 LowOpPosition0:1; // With low op in position 0" }, + uint16 LowOpPosition1:1; // With low op in position 1" }, + uint16 LowOpPosition2:1; // With low op in position 2" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_retired_fastpath_double_op_instr); + +class k8Event_RETIRED_FASTPATH_INSTRS : public k8BaseEvent +{ +public: + + k8Event_RETIRED_FASTPATH_INSTRS() + { + eventMask = (EVENT_MASK(k8_retired_fastpath_double_op_instr) *)&m_eventMask; + event_id = 0xCC; + unitEncode = FR; + + name = _T("Retired fastpath double op instructions"); + revRequired = 'B'; + + } + EVENT_MASK(k8_retired_fastpath_double_op_instr) * eventMask; + + +}; + +class k8Event_INTERRUPTS_MASKED_CYCLES : public k8BaseEvent +{ +public: + k8Event_INTERRUPTS_MASKED_CYCLES() + { + event_id = 0xCD; + unitEncode = FR; + + //0xF, NULL, _T("INTERRUPTS_MASKED_CYCLES"), + name = _T("Interrupts masked cycles (IF=0)") ; + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; +class k8Event_INTERRUPTS_MASKED_WHILE_PENDING_CYCLES : public k8BaseEvent +{ +public: + k8Event_INTERRUPTS_MASKED_WHILE_PENDING_CYCLES() + { + event_id = 0xCE; + unitEncode = FR; + + //0xF, NULL, _T("INTERRUPTS_MASKED_WHILE_PENDING_CYCLES"), + name = _T("Interrupts masked while pending cycles (INTR while IF=0)") ; + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; +class k8Event_NUMBER_OF_TAKEN_HARDWARE_INTERRUPTS : public k8BaseEvent +{ +public: + k8Event_NUMBER_OF_TAKEN_HARDWARE_INTERRUPTS() + { + event_id = 0xCF; + unitEncode = FR; + + //0xF, NULL, _T("NUMBER_OF_TAKEN_HARDWARE_INTERRUPTS"), + name = _T("Number of taken hardware interrupts") ; + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + } + EVENT_MASK(NULL_MASK) * eventMask; + +}; + + +class k8Event_DECODER_EMPTY : public k8BaseEvent +{ +public: + + k8Event_DECODER_EMPTY() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Nothing to dispatch (decoder empty)"); + event_id = 0xD0; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DECODER_EMPTY"); + + +}; +class k8Event_DISPATCH_STALLS : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALLS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stalls (events 0xD2-0xDA combined)"); + event_id = 0xD1; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALLS"); + + + +}; +class k8Event_DISPATCH_STALL_FROM_BRANCH_ABORT : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_FROM_BRANCH_ABORT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall from branch abort to retire"); + event_id = 0xD2; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_FROM_BRANCH_ABORT"); + + + +}; +class k8Event_DISPATCH_STALL_SERIALIZATION : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_SERIALIZATION() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall for serialization"); + event_id = 0xD3; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_SERIALIZATION"); + + +}; +class k8Event_DISPATCH_STALL_SEG_LOAD : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_SEG_LOAD() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall for segment load"); + event_id = 0xD4; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_SEG_LOAD"); + + + +}; +class k8Event_DISPATCH_STALL_REORDER_BUFFER : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_REORDER_BUFFER() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when reorder buffer is full"); + event_id = 0xD5; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_REORDER_BUFFER"); + + +}; +class k8Event_DISPATCH_STALL_RESERVE_STATIONS : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_RESERVE_STATIONS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when reservation stations are full"); + event_id = 0xD6; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_RESERVE_STATIONS"); + + +}; +class k8Event_DISPATCH_STALL_FPU : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_FPU() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when FPU is full"); + event_id = 0xD7; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_FPU"); + + +}; +class k8Event_DISPATCH_STALL_LS : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_LS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when LS is full"); + event_id = 0xD8; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_LS"); + + +}; +class k8Event_DISPATCH_STALL_QUIET_WAIT : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_QUIET_WAIT() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when waiting for all to be quiet"); + event_id = 0xD9; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_QUIET_WAIT"); + + + +}; +class k8Event_DISPATCH_STALL_PENDING : public k8BaseEvent +{ +public: + + k8Event_DISPATCH_STALL_PENDING() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Dispatch stall when far control transfer or resync branch is pending"); + event_id = 0xDA; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DISPATCH_STALL_PENDING"); + + + +}; + + +typedef union EVENT_MASK( k8_fpu_exceptions) +{ + + + + struct + { + uint16 x87ReclassMicrofaults:1; // x87 reclass microfaults" }, + uint16 SSERetypeMicrofaults:1; // SSE retype microfaults" }, + uint16 SSEReclassMicrofaults:1; // SSE reclass microfaults" }, + uint16 SSE_x87Microtraps:1; // SSE and x87 microtraps" } } + }; + uint16 flat; + + + +}EVENT_MASK( k8_fpu_exceptions); + +class k8Event_FPU_EXCEPTIONS : public k8BaseEvent +{ +public: + + k8Event_FPU_EXCEPTIONS() + { + eventMask = (EVENT_MASK(k8_fpu_exceptions) *)&m_eventMask; + event_id = 0xDB; + unitEncode = FR; + + name = _T("FPU exceptions"); + revRequired = 'B'; + + } + EVENT_MASK(k8_fpu_exceptions) * eventMask; + // name = _T("FPU_EXCEPTIONS"); + /* Revision B and later */ + + + +}; +class k8Event_DR0_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR0_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR0"); + event_id = 0xDC; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR0_BREAKPOINTS"); + + + +}; +class k8Event_DR1_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR1_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR1"); + event_id = 0xDD; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR1_BREAKPOINTS"); + + + +}; +class k8Event_DR2_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR2_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR2"); + event_id = 0xDE; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR2_BREAKPOINTS"); + + +}; +class k8Event_DR3_BREAKPOINTS : public k8BaseEvent +{ +public: + + k8Event_DR3_BREAKPOINTS() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Number of breakpoints for DR3"); + event_id = 0xDF; + unitEncode = FR; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DR3_BREAKPOINTS"); + + +}; + + + +// E0 +typedef union EVENT_MASK( k8_page_access_event) +{ + struct + { + uint16 PageHit:1; // Page hit" }, + uint16 PageMiss:1; // Page miss" }, + uint16 PageConflict:1; // Page conflict" } } + }; + uint16 flat; + +}EVENT_MASK( k8_page_access_event); + +class k8Event_MEM_PAGE_ACCESS : public k8BaseEvent +{ +public: + + k8Event_MEM_PAGE_ACCESS() + { + eventMask = (EVENT_MASK(k8_page_access_event) *)&m_eventMask; + name = _T("Memory controller page access"); + event_id = 0xE0; + unitEncode = NB; + + } + EVENT_MASK(k8_page_access_event) * eventMask; + // name = _T("MEM_PAGE_ACCESS"); + + +}; +class k8Event_MEM_PAGE_TBL_OVERFLOW : public k8BaseEvent +{ +public: + + k8Event_MEM_PAGE_TBL_OVERFLOW() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Memory controller page table overflow"); + event_id = 0xE1; + unitEncode = NB; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("MEM_PAGE_TBL_OVERFLOW"); + + +}; +class k8Event_DRAM_SLOTS_MISSED : public k8BaseEvent +{ +public: + + k8Event_DRAM_SLOTS_MISSED() + { + eventMask = (EVENT_MASK(NULL_MASK) *)&m_eventMask; + name = _T("Memory controller DRAM command slots missed (in MemClks)"); + event_id = 0xE2; + unitEncode = NB; + + } + EVENT_MASK(NULL_MASK) * eventMask; + // name = _T("DRAM_SLOTS_MISSED"); + + +}; + + +// e3 +typedef union EVENT_MASK( k8_turnaround) +{ + + struct + { + uint16 DIMMTurnaround:1; //DIMM turnaround" }, + uint16 ReadToWriteTurnaround:1; //Read to write turnaround" }, + uint16 WriteToReadTurnaround:1; //Write to read turnaround" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_turnaround); + +class k8Event_MEM_TURNAROUND : public k8BaseEvent +{ +public: + + k8Event_MEM_TURNAROUND() + { + eventMask = (EVENT_MASK(k8_turnaround) *)&m_eventMask; + name = _T("Memory controller turnaround"); + event_id = 0xE3; + unitEncode = NB; + + } + EVENT_MASK(k8_turnaround) * eventMask; + // name = _T("MEM_TURNAROUND"); + + +}; + + + + +// E4 +typedef union EVENT_MASK( k8_bypass_counter_saturation) +{ + struct + { + uint16 MEM_HighPriorityBypass:1; // Memory controller high priority bypass" }, + uint16 MEM_LowPriorityBypass:1; // Memory controller low priority bypass" }, + uint16 DRAM_InterfaceBypass:1; // DRAM controller interface bypass" }, + uint16 DRAM_QueueBypass:1; // DRAM controller queue bypass" } } + }; + uint16 flat; + +}EVENT_MASK( k8_bypass_counter_saturation); + +class k8Event_MEM_BYPASS_SAT : public k8BaseEvent +{ +public: + + k8Event_MEM_BYPASS_SAT() + { + eventMask = (EVENT_MASK(k8_bypass_counter_saturation) *)&m_eventMask; + name = _T("Memory controller bypass counter saturation"); + event_id = 0xE4; + unitEncode = NB; + + } + EVENT_MASK(k8_bypass_counter_saturation) * eventMask; + // name = _T("MEM_BYPASS_SAT"); + + +}; + + + +//EB +typedef union EVENT_MASK( k8_sized_commands) +{ + + struct + { + uint16 NonPostWrSzByte:1; // NonPostWrSzByte" }, + uint16 NonPostWrSzDword:1; // NonPostWrSzDword" }, + uint16 PostWrSzByte:1; // PostWrSzByte" }, + uint16 PostWrSzDword:1; // PostWrSzDword" }, + uint16 RdSzByte:1; // RdSzByte" }, + uint16 RdSzDword:1; // RdSzDword" }, + uint16 RdModWr:1; // RdModWr" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_sized_commands); + + +class k8Event_SIZED_COMMANDS : public k8BaseEvent +{ +public: + + k8Event_SIZED_COMMANDS() + { + eventMask = (EVENT_MASK(k8_sized_commands) *)&m_eventMask; + name = _T("Sized commands"); + event_id = 0xEB; + unitEncode = NB; + + } + EVENT_MASK(k8_sized_commands) * eventMask; + // name = _T("SIZED_COMMANDS"); + + +}; + +typedef union EVENT_MASK( k8_probe_result) +{ + struct + { + uint16 ProbeMiss:1; // Probe miss" }, + uint16 ProbeHit:1; // Probe hit" }, + uint16 ProbeHitDirtyWithoutMemoryCancel:1; // Probe hit dirty without memory cancel" }, + uint16 ProbeHitDirtyWithMemoryCancel:1; // Probe hit dirty with memory cancel" } } + uint16 UpstreamDisplayRefreshReads:1; // Rev D and later + uint16 UpstreamNonDisplayRefreshReads:1; // Rev D and later + uint16 UpstreamWrites:1; // Rev D and later + }; + uint16 flat; + + +}EVENT_MASK( k8_probe_result); + + +class k8Event_PROBE_RESULT : public k8BaseEvent +{ +public: + + k8Event_PROBE_RESULT() + { + eventMask = (EVENT_MASK(k8_probe_result) *)&m_eventMask; + name = _T("Probe result"); + event_id = 0xEC; + unitEncode = NB; + + } + EVENT_MASK(k8_probe_result) * eventMask; + // name = _T("PROBE_RESULT"); + + +}; + +typedef union EVENT_MASK( k8_ht) +{ + + struct + { + uint16 CommandSent:1; //Command sent" }, + uint16 DataSent:1; //Data sent" }, + uint16 BufferReleaseSent:1; //Buffer release sent" + uint16 NopSent:1; //Nop sent" } } + }; + uint16 flat; + + +}EVENT_MASK( k8_ht); + + +class k8Event_HYPERTRANSPORT_BUS0_WIDTH : public k8BaseEvent +{ +public: + + k8Event_HYPERTRANSPORT_BUS0_WIDTH() + { + eventMask = (EVENT_MASK(k8_ht) *)&m_eventMask; + name = _T("Hypertransport (tm) bus 0 bandwidth"); + event_id = 0xF6; + unitEncode = NB; + + } + EVENT_MASK(k8_ht) * eventMask; + // name = _T("HYPERTRANSPORT_BUS0_WIDTH"); + + +}; +class k8Event_HYPERTRANSPORT_BUS1_WIDTH : public k8BaseEvent +{ +public: + + k8Event_HYPERTRANSPORT_BUS1_WIDTH() + { + eventMask = (EVENT_MASK(k8_ht) *)&m_eventMask; + name = _T("Hypertransport (tm) bus 1 bandwidth"); + event_id = 0xF7; + unitEncode = NB; + + } + EVENT_MASK(k8_ht) * eventMask; + // name = _T("HYPERTRANSPORT_BUS1_WIDTH"); + + +}; +class k8Event_HYPERTRANSPORT_BUS2_WIDTH : public k8BaseEvent +{ +public: + + k8Event_HYPERTRANSPORT_BUS2_WIDTH() + { + eventMask = (EVENT_MASK(k8_ht) *)&m_eventMask; + name = _T("Hypertransport (tm) bus 2 bandwidth"); + event_id = 0xF8; + unitEncode = NB; + + } + EVENT_MASK(k8_ht) * eventMask; + // name = _T("HYPERTRANSPORT_BUS2_WIDTH"); + +}; + +// +//typedef union EVENT_MASK( perfctr_event_set k8_common_event_set) +//{ +// +// .cpu_type = PERFCTR_X86_AMD_K8, +// .event_prefix = _T("K8_"), +// .include = &k7_official_event_set, +// .nevents = ARRAY_SIZE(k8_common_events), +// .events = k8_common_events, +//}EVENT_MASK( perfctr_event_set k8_common_event_set); +// +//typedef union EVENT_MASK( perfctr_event k8_events[]) +//{ +// +// { 0x24, 0xF, UM(NULL), _T("LOCKED_OP"), /* unit mask changed in Rev. C */ +// _T("Locked operation") }, +//}EVENT_MASK( perfctr_event k8_events[]); + + + + +//const struct perfctr_event_set perfctr_k8_event_set) +//{ +// +// .cpu_type = PERFCTR_X86_AMD_K8, +// .event_prefix = _T("K8_"), +// .include = &k8_common_event_set, +// .nevents = ARRAY_SIZE(k8_events), +// .events = k8_events, +//}; +// +/* + * K8 Revision C. Starts at CPUID 0xF58 for Opteron/Athlon64FX and + * CPUID 0xF48 for Athlon64. (CPUID 0xF51 is Opteron Revision B3.) + */ + + + + + + + + +// +//typedef union EVENT_MASK( k8_lock_accesses) +//{ +// struct +// { +// uint16 DcacheAccesses:1; // Number of dcache accesses by lock instructions" }, +// uint16 DcacheMisses:1; // Number of dcache misses by lock instructions" } } +// }; +// uint16 flat; +// +//}EVENT_MASK( k8_lock_accesses); +// + +#endif // K8PERFORMANCECOUNTERS_H diff --git a/external/vpc/public/tier0/l2cache.h b/external/vpc/public/tier0/l2cache.h new file mode 100644 index 0000000..db54695 --- /dev/null +++ b/external/vpc/public/tier0/l2cache.h @@ -0,0 +1,47 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#ifndef CL2CACHE_H +#define CL2CACHE_H +#ifdef _WIN32 +#pragma once +#endif + +class P4Event_BSQ_cache_reference; + +class CL2Cache +{ +public: + + CL2Cache(); + ~CL2Cache(); + + void Start( void ); + void End( void ); + + //------------------------------------------------------------------------- + // GetL2CacheMisses + //------------------------------------------------------------------------- + int GetL2CacheMisses( void ) + { + return m_iL2CacheMissCount; + } + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +private: + + int m_nID; + + P4Event_BSQ_cache_reference *m_pL2CacheEvent; + int64 m_i64Start; + int64 m_i64End; + int m_iL2CacheMissCount; +}; + +#endif // CL2CACHE_H + diff --git a/external/vpc/public/tier0/logging.h b/external/vpc/public/tier0/logging.h new file mode 100644 index 0000000..42b10c4 --- /dev/null +++ b/external/vpc/public/tier0/logging.h @@ -0,0 +1,767 @@ +//============ Copyright (c) Valve Corporation, All rights reserved. ============ +// +// Logging system declarations. +// +// The logging system is a channel-based output mechanism which allows +// subsystems to route their text/diagnostic output to various listeners +// +//=============================================================================== + +#ifndef LOGGING_H +#define LOGGING_H + +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +#include "color.h" +#include "icommandline.h" +#include <stdio.h> + +// For XBX_** functions +#if defined( _X360 ) +#include "xbox/xbox_console.h" +#endif + +// Used by CColorizedLoggingListener +#if defined( _WIN32 ) || (defined(POSIX) && !defined(_GAMECONSOLE)) +#include "tier0/win32consoleio.h" +#endif + +/* + ---- Logging System ---- + + The logging system is a channel-based mechanism for all code (engine, + mod, tool) across all platforms to output information, warnings, + errors, etc. + + This system supersedes the existing Msg(), Warning(), Error(), DevMsg(), ConMsg() etc. functions. + There are channels defined in the new system through which all old messages are routed; + see LOG_GENERAL, LOG_CONSOLE, LOG_DEVELOPER, etc. + + To use the system, simply call one of the predefined macros: + + Log_Msg( ChannelID, [Color], Message, ... ) + Log_Warning( ChannelID, [Color], Message, ... ) + Log_Error( ChannelID, [Color], Message, ... ) + + A ChannelID is typically created by defining a logging channel with the + log channel macros: + + DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_ChannelName, "ChannelName", [Flags], [MinimumSeverity], [Color] ); + + or + + BEGIN_DEFINE_LOGGING_CHANNEL( LOG_ChannelName, "ChannelName", [Flags], [MinimumSeverity], [Color] ); + ADD_LOGGING_CHANNEL_TAG( "Tag1" ); + ADD_LOGGING_CHANNEL_TAG( "Tag2" ); + END_DEFINE_LOGGING_CHANNEL(); + + These macros create a global channel ID variable with the name specified + by the first parameter (in this example, LOG_ChannelName). This channel ID + can be used by various LoggingSystem_** functions to manipulate the channel settings. + + The optional [Flags] parameter is an OR'd together set of LoggingChannelFlags_t + values (default: 0). + + The optional [MinimumSeverity] parameter is the lowest threshold + above which messages will be processed (inclusive). The default is LS_MESSAGE, + which results in all messages, warnings, and errors being logged. + Variadic parameters to the Log_** functions will be ignored if a channel + is not enabled for a given severity (for performance reasons). + + Logging channels can have their minimum severity modified by name, ID, or tag. + + Logging channels are not hierarchical since there are situations in which + a channel needs to belong to multiple hierarchies. Use tags to create + categories or shallow hierarchies. + + @TODO (Feature wishlist): + 1) Callstack logging support + 2) Registering dynamic channels and unregistering channels at runtime + 3) Sentient robot to clean up the thousands of places using the old/legacy logging system. +*/ + +////////////////////////////////////////////////////////////////////////// +// Constants, Types, Forward Declares +////////////////////////////////////////////////////////////////////////// + +class CLoggingSystem; +class CThreadFastMutex; + +//----------------------------------------------------------------------------- +// Maximum length of a sprintf'ed logging message. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_MESSAGE_LENGTH = 2048; + +//----------------------------------------------------------------------------- +// Maximum length of a channel or tag name. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_IDENTIFIER_LENGTH = 32; + +//----------------------------------------------------------------------------- +// Maximum number of logging channels. Increase if needed. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_CHANNEL_COUNT = 256; + +//----------------------------------------------------------------------------- +// Maximum number of logging tags across all channels. Increase if needed. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_TAG_COUNT = 1024; + +//----------------------------------------------------------------------------- +// Maximum number of characters across all logging tags. Increase if needed. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_TAG_CHARACTER_COUNT = 8192; + +//----------------------------------------------------------------------------- +// Maximum number of concurrent logging listeners in a given logging state. +//----------------------------------------------------------------------------- +const int MAX_LOGGING_LISTENER_COUNT = 16; + +//----------------------------------------------------------------------------- +// An invalid color set on a channel to imply that it should use +// a device-dependent default color where applicable. +//----------------------------------------------------------------------------- +const Color UNSPECIFIED_LOGGING_COLOR( 0, 0, 0, 0 ); + +//----------------------------------------------------------------------------- +// An ID returned by the logging system to refer to a logging channel. +//----------------------------------------------------------------------------- +typedef int LoggingChannelID_t; + +//----------------------------------------------------------------------------- +// A sentinel value indicating an invalid logging channel ID. +//----------------------------------------------------------------------------- +const LoggingChannelID_t INVALID_LOGGING_CHANNEL_ID = -1; + +//----------------------------------------------------------------------------- +// The severity of a logging operation. +//----------------------------------------------------------------------------- +enum LoggingSeverity_t +{ + //----------------------------------------------------------------------------- + // An informative logging message. + //----------------------------------------------------------------------------- + LS_MESSAGE = 0, + + //----------------------------------------------------------------------------- + // A warning, typically non-fatal + //----------------------------------------------------------------------------- + LS_WARNING = 1, + + //----------------------------------------------------------------------------- + // A message caused by an Assert**() operation. + //----------------------------------------------------------------------------- + LS_ASSERT = 2, + + //----------------------------------------------------------------------------- + // An error, typically fatal/unrecoverable. + //----------------------------------------------------------------------------- + LS_ERROR = 3, + + //----------------------------------------------------------------------------- + // A placeholder level, higher than any legal value. + // Not a real severity value! + //----------------------------------------------------------------------------- + LS_HIGHEST_SEVERITY = 4, +}; + +//----------------------------------------------------------------------------- +// Action which should be taken by logging system as a result of +// a given logged message. +// +// The logging system invokes ILoggingResponsePolicy::OnLog() on +// the specified policy object, which returns a LoggingResponse_t. +//----------------------------------------------------------------------------- +enum LoggingResponse_t +{ + LR_CONTINUE, + LR_DEBUGGER, + LR_ABORT, +}; + +//----------------------------------------------------------------------------- +// Logging channel behavior flags, set on channel creation. +//----------------------------------------------------------------------------- +enum LoggingChannelFlags_t +{ + //----------------------------------------------------------------------------- + // Indicates that the spew is only relevant to interactive consoles. + //----------------------------------------------------------------------------- + LCF_CONSOLE_ONLY = 0x00000001, + + //----------------------------------------------------------------------------- + // Indicates that spew should not be echoed to any output devices. + // A suitable logging listener must be registered which respects this flag + // (e.g. a file logger). + //----------------------------------------------------------------------------- + LCF_DO_NOT_ECHO = 0x00000002, +}; + +//----------------------------------------------------------------------------- +// A callback function used to register tags on a logging channel +// during initialization. +//----------------------------------------------------------------------------- +typedef void ( *RegisterTagsFunc )(); + +//----------------------------------------------------------------------------- +// A context structure passed to logging listeners and response policy classes. +//----------------------------------------------------------------------------- +struct LoggingContext_t +{ + // ID of the channel being logged to. + LoggingChannelID_t m_ChannelID; + // Flags associated with the channel. + LoggingChannelFlags_t m_Flags; + // Severity of the logging event. + LoggingSeverity_t m_Severity; + // Color of logging message if one was specified to Log_****() macro. + // If not specified, falls back to channel color. + // If channel color is not specified, this value is UNSPECIFIED_LOGGING_COLOR + // and indicates that a suitable default should be chosen. + Color m_Color; +}; + +//----------------------------------------------------------------------------- +// Interface for classes to handle logging output. +// +// The Log() function of this class is called synchronously and serially +// by the logging system on all registered instances of ILoggingListener +// in the current "logging state". +// +// Derived classes may do whatever they want with the message (write to disk, +// write to console, send over the network, drop on the floor, etc.). +// +// In general, derived classes should do one, simple thing with the output +// to allow callers to register multiple, orthogonal logging listener classes. +//----------------------------------------------------------------------------- +class ILoggingListener +{ +public: + virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) = 0; +}; + +//----------------------------------------------------------------------------- +// Interface for policy classes which determine how to behave when a +// message is logged. +// +// Can return: +// LR_CONTINUE (continue execution) +// LR_DEBUGGER (break into debugger if one is present, otherwise continue) +// LR_ABORT (terminate process immediately with a failure code of 1) +//----------------------------------------------------------------------------- +class ILoggingResponsePolicy +{ +public: + virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext ) = 0; +}; + +////////////////////////////////////////////////////////////////////////// +// Common Logging Listeners & Logging Response Policies +////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// A basic logging listener which prints to stdout and the debug channel. +//----------------------------------------------------------------------------- +class CSimpleLoggingListener : public ILoggingListener +{ +public: + CSimpleLoggingListener( bool bQuietPrintf = false, bool bQuietDebugger = false ) : + m_bQuietPrintf( bQuietPrintf ), + m_bQuietDebugger( bQuietDebugger ) + { + } + + virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) + { +#ifdef _X360 + if ( !m_bQuietDebugger && XBX_IsConsoleConnected() ) + { + // send to console + XBX_DebugString( XMAKECOLOR( 0,0,0 ), pMessage ); + } + else +#endif + { +#if !defined( _CERT ) && !defined( DBGFLAG_STRINGS_STRIP ) + if ( !m_bQuietPrintf ) + { + _tprintf( _T("%s"), pMessage ); + } +#endif + +#ifdef _WIN32 + if ( !m_bQuietDebugger && Plat_IsInDebugSession() ) + { + Plat_DebugString( pMessage ); + } +#endif + } + } + + // If set to true, does not print anything to stdout. + bool m_bQuietPrintf; + // If set to true, does not print anything to debugger. + bool m_bQuietDebugger; +}; + +//----------------------------------------------------------------------------- +// A basic logging listener for GUI applications +//----------------------------------------------------------------------------- +class CSimpleWindowsLoggingListener : public ILoggingListener +{ +public: + virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) + { + if ( Plat_IsInDebugSession() ) + { + Plat_DebugString( pMessage ); + } + if ( pContext->m_Severity == LS_ERROR ) + { + if ( Plat_IsInDebugSession() ) + DebuggerBreak(); + + Plat_MessageBox( "Error", pMessage ); + } + } +}; + + +//----------------------------------------------------------------------------- +// ** NOTE FOR INTEGRATION ** +// This was copied over from source 2 rather than integrated because +// source 2 has more significantly refactored tier0 logging. +// +// A logging listener with Win32 console API color support which which prints +// to stdout and the debug channel. +//----------------------------------------------------------------------------- +#if !defined(_GAMECONSOLE) +class CColorizedLoggingListener : public CSimpleLoggingListener +{ +public: + CColorizedLoggingListener( bool bQuietPrintf = false, bool bQuietDebugger = false ) : CSimpleLoggingListener( bQuietPrintf, bQuietDebugger ) + { + InitWin32ConsoleColorContext( &m_ColorContext ); + } + + virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) + { + if ( !m_bQuietPrintf ) + { + int nPrevColor = -1; + + if ( pContext->m_Color != UNSPECIFIED_LOGGING_COLOR ) + { + nPrevColor = SetWin32ConsoleColor( &m_ColorContext, + pContext->m_Color.r(), pContext->m_Color.g(), pContext->m_Color.b(), + MAX( MAX( pContext->m_Color.r(), pContext->m_Color.g() ), pContext->m_Color.b() ) > 128 ); + } + + _tprintf( _T("%s"), pMessage ); + + if ( nPrevColor >= 0 ) + { + RestoreWin32ConsoleColor( &m_ColorContext, nPrevColor ); + } + } + +#ifdef _WIN32 + if ( !m_bQuietDebugger && Plat_IsInDebugSession() ) + { + Plat_DebugString( pMessage ); + } +#endif + } + + Win32ConsoleColorContext_t m_ColorContext; +}; +#endif // !_GAMECONSOLE + + +//----------------------------------------------------------------------------- +// Default logging response policy used when one is not specified. +//----------------------------------------------------------------------------- +class CDefaultLoggingResponsePolicy : public ILoggingResponsePolicy +{ +public: + virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext ) + { + if ( pContext->m_Severity == LS_ASSERT && !CommandLine()->FindParm( "-noassert" ) ) + { + return LR_DEBUGGER; + } + else if ( pContext->m_Severity == LS_ERROR ) + { + return LR_ABORT; + } + else + { + return LR_CONTINUE; + } + } +}; + +//----------------------------------------------------------------------------- +// A logging response policy which never terminates the process, even on error. +//----------------------------------------------------------------------------- +class CNonFatalLoggingResponsePolicy : public ILoggingResponsePolicy +{ +public: + virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext ) + { + if ( ( pContext->m_Severity == LS_ASSERT && !CommandLine()->FindParm( "-noassert" ) ) || pContext->m_Severity == LS_ERROR ) + { + return LR_DEBUGGER; + } + else + { + return LR_CONTINUE; + } + } +}; + +////////////////////////////////////////////////////////////////////////// +// Central Logging System +////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +// The central logging system. +// +// Multiple instances can exist, though all exported tier0 functionality +// specifically works with a single global instance +// (via GetGlobalLoggingSystem()). +//----------------------------------------------------------------------------- +class CLoggingSystem +{ +public: + struct LoggingChannel_t; + + CLoggingSystem(); + ~CLoggingSystem(); + + //----------------------------------------------------------------------------- + // Register a logging channel with the logging system. + // The same channel can be registered multiple times, but the parameters + // in each call to RegisterLoggingChannel must either match across all calls + // or be set to defaults on any given call + // + // This function is not thread-safe and should generally only be called + // by a single thread. Using the logging channel definition macros ensures + // that this is called on the static initialization thread. + //----------------------------------------------------------------------------- + LoggingChannelID_t RegisterLoggingChannel( const char *pChannelName, RegisterTagsFunc registerTagsFunc, int flags = 0, LoggingSeverity_t minimumSeverity = LS_MESSAGE, Color spewColor = UNSPECIFIED_LOGGING_COLOR ); + + //----------------------------------------------------------------------------- + // Gets a channel ID from a string name. + // Performs a simple linear search; cache the value whenever possible + // or re-register the logging channel to get a global ID. + //----------------------------------------------------------------------------- + LoggingChannelID_t FindChannel( const char *pChannelName ) const; + + int GetChannelCount() const { return m_nChannelCount; } + + //----------------------------------------------------------------------------- + // Gets a pointer to the logging channel description. + //----------------------------------------------------------------------------- + LoggingChannel_t *GetChannel( LoggingChannelID_t channelID ); + const LoggingChannel_t *GetChannel( LoggingChannelID_t channelID ) const; + + //----------------------------------------------------------------------------- + // Returns true if the given channel has the specified tag. + //----------------------------------------------------------------------------- + bool HasTag( LoggingChannelID_t channelID, const char *pTag ) const { return GetChannel( channelID )->HasTag( pTag ); } + + //----------------------------------------------------------------------------- + // Returns true if the given channel has been initialized. + // The main purpose is catching m_nChannelCount being zero because no channels have been registered. + //----------------------------------------------------------------------------- + bool IsValidChannelID( LoggingChannelID_t channelID ) const { return ( channelID >= 0 ) && ( channelID < m_nChannelCount ); } + + //----------------------------------------------------------------------------- + // Returns true if the given channel will spew at the given severity level. + //----------------------------------------------------------------------------- + bool IsChannelEnabled( LoggingChannelID_t channelID, LoggingSeverity_t severity ) const { return IsValidChannelID( channelID ) && GetChannel( channelID )->IsEnabled( severity ); } + + //----------------------------------------------------------------------------- + // Functions to set the spew level of a channel either directly by ID or + // string name, or for all channels with a given tag. + // + // These functions are not technically thread-safe but calling them across + // multiple threads should cause no significant problems + // (the underlying data types being changed are 32-bit/atomic). + //----------------------------------------------------------------------------- + void SetChannelSpewLevel( LoggingChannelID_t channelID, LoggingSeverity_t minimumSeverity ); + void SetChannelSpewLevelByName( const char *pName, LoggingSeverity_t minimumSeverity ); + void SetChannelSpewLevelByTag( const char *pTag, LoggingSeverity_t minimumSeverity ); + + //----------------------------------------------------------------------------- + // Gets or sets the color of a logging channel. + // (The functions are not thread-safe, but the consequences are not + // significant.) + //----------------------------------------------------------------------------- + Color GetChannelColor( LoggingChannelID_t channelID ) const { return GetChannel( channelID )->m_SpewColor; } + void SetChannelColor( LoggingChannelID_t channelID, Color color ) { GetChannel( channelID )->m_SpewColor = color; } + + //----------------------------------------------------------------------------- + // Gets or sets the flags on a logging channel. + // (The functions are not thread-safe, but the consequences are not + // significant.) + //----------------------------------------------------------------------------- + LoggingChannelFlags_t GetChannelFlags( LoggingChannelID_t channelID ) const { return GetChannel( channelID )->m_Flags; } + void SetChannelFlags( LoggingChannelID_t channelID, LoggingChannelFlags_t flags ) { GetChannel( channelID )->m_Flags = flags; } + + //----------------------------------------------------------------------------- + // Adds a string tag to a channel. + // This is not thread-safe and should only be called by a RegisterTagsFunc + // callback passed in to RegisterLoggingChannel (via the + // channel definition macros). + //----------------------------------------------------------------------------- + void AddTagToCurrentChannel( const char *pTagName ); + + //----------------------------------------------------------------------------- + // Functions to save/restore the current logging state. + // Set bThreadLocal to true on a matching Push/Pop call if the intent + // is to override the logging listeners on the current thread only. + // + // Pushing the current logging state onto the state stack results + // in the current state being cleared by default (no listeners, default logging response policy). + // Set bClearState to false to copy the existing listener pointers to the new state. + // + // These functions which mutate logging state ARE thread-safe and are + // guarded by m_StateMutex. + //----------------------------------------------------------------------------- + void PushLoggingState( bool bThreadLocal = false, bool bClearState = true ); + void PopLoggingState( bool bThreadLocal = false ); + + //----------------------------------------------------------------------------- + // Registers a logging listener (a class which handles logged messages). + //----------------------------------------------------------------------------- + void RegisterLoggingListener( ILoggingListener *pListener ); + + //----------------------------------------------------------------------------- + // Removes a logging listener from the registered list + //----------------------------------------------------------------------------- + void UnregisterLoggingListener( ILoggingListener *pListener ); + + //----------------------------------------------------------------------------- + // Returns whether the specified logging listener is registered. + //----------------------------------------------------------------------------- + bool IsListenerRegistered( ILoggingListener *pListener ); + + //----------------------------------------------------------------------------- + // Clears out all of the current logging state (removes all listeners, + // sets the response policy to the default). + //----------------------------------------------------------------------------- + void ResetCurrentLoggingState(); + + //----------------------------------------------------------------------------- + // Sets a policy class to decide what should happen when messages of a + // particular severity are logged + // (e.g. exit on error, break into debugger). + // If pLoggingResponse is NULL, uses the default response policy class. + //----------------------------------------------------------------------------- + void SetLoggingResponsePolicy( ILoggingResponsePolicy *pLoggingResponse ); + + //----------------------------------------------------------------------------- + // Logs a message to the specified channel using a given severity and + // spew color. Passing in UNSPECIFIED_LOGGING_COLOR for 'color' allows + // the logging listeners to provide a default. + // NOTE: test 'IsChannelEnabled(channelID,severity)' before calling this! + //----------------------------------------------------------------------------- + LoggingResponse_t LogDirect( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color color, const tchar *pMessage ); + + // Internal data to represent a logging tag + struct LoggingTag_t + { + const char *m_pTagName; + LoggingTag_t *m_pNextTag; + }; + + // Internal data to represent a logging channel. + struct LoggingChannel_t + { + bool HasTag( const char *pTag ) const + { + LoggingTag_t *pCurrentTag = m_pFirstTag; + while( pCurrentTag != NULL ) + { + if ( stricmp( pCurrentTag->m_pTagName, pTag ) == 0 ) + { + return true; + } + pCurrentTag = pCurrentTag->m_pNextTag; + } + return false; + } + bool IsEnabled( LoggingSeverity_t severity ) const { return severity >= m_MinimumSeverity; } + void SetSpewLevel( LoggingSeverity_t severity ) { m_MinimumSeverity = severity; } + + LoggingChannelID_t m_ID; + LoggingChannelFlags_t m_Flags; // an OR'd combination of LoggingChannelFlags_t + LoggingSeverity_t m_MinimumSeverity; // The minimum severity level required to activate this channel. + Color m_SpewColor; + char m_Name[MAX_LOGGING_IDENTIFIER_LENGTH]; + LoggingTag_t *m_pFirstTag; + }; + +private: + // Represents the current state of the logger (registered listeners, response policy class, etc.) and can + // vary from thread-to-thread. It can also be pushed/popped to save/restore listener/response state. + struct LoggingState_t + { + // Index of the previous entry on the listener set stack. + int m_nPreviousStackEntry; + + // Number of active listeners in this set. Cannot exceed MAX_LOGGING_LISTENER_COUNT. + // If set to -1, implies that this state structure is not in use. + int m_nListenerCount; + // Array of registered logging listener objects. + ILoggingListener *m_RegisteredListeners[MAX_LOGGING_LISTENER_COUNT]; + + // Specific policy class to determine behavior of logging system under specific message types. + ILoggingResponsePolicy *m_pLoggingResponse; + }; + + // These state functions to assume the caller has already grabbed the mutex. + LoggingState_t *GetCurrentState(); + const LoggingState_t *GetCurrentState() const; + + int FindUnusedStateIndex(); + LoggingTag_t *AllocTag( const char *pTagName ); + + int m_nChannelCount; + LoggingChannel_t m_RegisteredChannels[MAX_LOGGING_CHANNEL_COUNT]; + + int m_nChannelTagCount; + LoggingTag_t m_ChannelTags[MAX_LOGGING_TAG_COUNT]; + + // Index to first free character in name pool. + int m_nTagNamePoolIndex; + // Pool of character data used for tag names. + char m_TagNamePool[MAX_LOGGING_TAG_CHARACTER_COUNT]; + + // Protects all data in this class except the registered channels + // (which are supposed to be registered using the macros at static/global init time). + // It is assumed that this mutex is reentrant safe on all platforms. + CThreadFastMutex *m_pStateMutex; + + // The index of the current "global" state of the logging system. By default, all threads use this state + // for logging unless a given thread has pushed the logging state with bThreadLocal == true. + // If a thread-local state has been pushed, g_nThreadLocalStateIndex (a global thread-local integer) will be non-zero. + // By default, g_nThreadLocalStateIndex is 0 for all threads. + int m_nGlobalStateIndex; + + // A pool of logging states used to store a stack (potentially per-thread). + static const int MAX_LOGGING_STATE_COUNT = 16; + LoggingState_t m_LoggingStates[MAX_LOGGING_STATE_COUNT]; + + // Default policy class which determines behavior. + CDefaultLoggingResponsePolicy m_DefaultLoggingResponse; + + // Default spew function. + CSimpleLoggingListener m_DefaultLoggingListener; + +}; + +////////////////////////////////////////////////////////////////////////// +// Logging Macros +////////////////////////////////////////////////////////////////////////// + +// This macro will resolve to the most appropriate overload of LoggingSystem_Log() depending on the number of parameters passed in. +#ifdef DBGFLAG_STRINGS_STRIP +#define InternalMsg( Channel, Severity, /* [Color], Message, */ ... ) do { if ( Severity == LS_ERROR && LoggingSystem_IsChannelEnabled( Channel, Severity ) ) LoggingSystem_Log( Channel, Severity, /* [Color], Message, */ ##__VA_ARGS__ ); } while( 0 ) +#else +#define InternalMsg( Channel, Severity, /* [Color], Message, */ ... ) do { if ( LoggingSystem_IsChannelEnabled( Channel, Severity ) ) LoggingSystem_Log( Channel, Severity, /* [Color], Message, */ ##__VA_ARGS__ ); } while( 0 ) +#endif + +//----------------------------------------------------------------------------- +// New macros, use these! +// +// The macros take an optional Color parameter followed by the message +// and the message formatting. +// We rely on the variadic macro (__VA_ARGS__) operator to paste in the +// extra parameters and resolve to the appropriate overload. +//----------------------------------------------------------------------------- +#define Log_Msg( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_MESSAGE, /* [Color], Message, */ ##__VA_ARGS__ ) +#define Log_Warning( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_WARNING, /* [Color], Message, */ ##__VA_ARGS__ ) +#define Log_Error( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_ERROR, /* [Color], Message, */ ##__VA_ARGS__ ) +#ifdef DBGFLAG_STRINGS_STRIP +#define Log_Assert( ... ) LR_CONTINUE +#else +#define Log_Assert( Message, ... ) LoggingSystem_LogAssert( Message, ##__VA_ARGS__ ) +#endif + + +#define DECLARE_LOGGING_CHANNEL( Channel ) extern LoggingChannelID_t Channel + +#define DEFINE_LOGGING_CHANNEL_NO_TAGS( Channel, ChannelName, /* [Flags], [Severity], [Color] */ ... ) \ + LoggingChannelID_t Channel = LoggingSystem_RegisterLoggingChannel( ChannelName, NULL, ##__VA_ARGS__ ) + +#define BEGIN_DEFINE_LOGGING_CHANNEL( Channel, ChannelName, /* [Flags], [Severity], [Color] */ ... ) \ + static void Register_##Channel##_Tags(); \ + LoggingChannelID_t Channel = LoggingSystem_RegisterLoggingChannel( ChannelName, Register_##Channel##_Tags, ##__VA_ARGS__ ); \ + void Register_##Channel##_Tags() \ + { + +#define ADD_LOGGING_CHANNEL_TAG( Tag ) LoggingSystem_AddTagToCurrentChannel( Tag ) + +#define END_DEFINE_LOGGING_CHANNEL() \ + } + +////////////////////////////////////////////////////////////////////////// +// DLL Exports +////////////////////////////////////////////////////////////////////////// + +// For documentation on these functions, please look at the corresponding function +// in CLoggingSystem (unless otherwise specified). +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_RegisterLoggingChannel( const char *pName, RegisterTagsFunc registerTagsFunc, int flags = 0, LoggingSeverity_t severity = LS_MESSAGE, Color color = UNSPECIFIED_LOGGING_COLOR ); + +PLATFORM_INTERFACE void LoggingSystem_RegisterLoggingListener( ILoggingListener *pListener ); +PLATFORM_INTERFACE void LoggingSystem_UnregisterLoggingListener( ILoggingListener *pListener ); +PLATFORM_INTERFACE void LoggingSystem_ResetCurrentLoggingState(); +PLATFORM_INTERFACE void LoggingSystem_SetLoggingResponsePolicy( ILoggingResponsePolicy *pResponsePolicy ); +// NOTE: PushLoggingState() saves the current logging state on a stack and results in a new clear state +// (no listeners, default logging response policy). +PLATFORM_INTERFACE void LoggingSystem_PushLoggingState( bool bThreadLocal = false, bool bClearState = true ); +PLATFORM_INTERFACE void LoggingSystem_PopLoggingState( bool bThreadLocal = false ); + +PLATFORM_INTERFACE void LoggingSystem_AddTagToCurrentChannel( const char *pTagName ); + +// Returns INVALID_LOGGING_CHANNEL_ID if not found +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_FindChannel( const char *pChannelName ); +PLATFORM_INTERFACE int LoggingSystem_GetChannelCount(); +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_GetFirstChannelID(); +// Returns INVALID_LOGGING_CHANNEL_ID when there are no channels remaining. +PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_GetNextChannelID( LoggingChannelID_t channelID ); +PLATFORM_INTERFACE const CLoggingSystem::LoggingChannel_t *LoggingSystem_GetChannel( LoggingChannelID_t channelID ); + +PLATFORM_INTERFACE bool LoggingSystem_HasTag( LoggingChannelID_t channelID, const char *pTag ); + +PLATFORM_INTERFACE bool LoggingSystem_IsChannelEnabled( LoggingChannelID_t channelID, LoggingSeverity_t severity ); +PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevel( LoggingChannelID_t channelID, LoggingSeverity_t minimumSeverity ); +PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevelByName( const char *pName, LoggingSeverity_t minimumSeverity ); +PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevelByTag( const char *pTag, LoggingSeverity_t minimumSeverity ); + +// Color is represented as an int32 due to C-linkage restrictions +PLATFORM_INTERFACE int32 LoggingSystem_GetChannelColor( LoggingChannelID_t channelID ); +PLATFORM_INTERFACE void LoggingSystem_SetChannelColor( LoggingChannelID_t channelID, int color ); + +PLATFORM_INTERFACE LoggingChannelFlags_t LoggingSystem_GetChannelFlags( LoggingChannelID_t channelID ); +PLATFORM_INTERFACE void LoggingSystem_SetChannelFlags( LoggingChannelID_t channelID, LoggingChannelFlags_t flags ); + +//----------------------------------------------------------------------------- +// Logs a variable-argument to a given channel with the specified severity. +// NOTE: if adding overloads to this function, remember that the Log_*** +// macros simply pass their variadic parameters through to LoggingSystem_Log(). +// Therefore, you need to ensure that the parameters are in the same general +// order and that there are no ambiguities with the overload. +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_Log( LoggingChannelID_t channelID, LoggingSeverity_t severity, const char *pMessageFormat, ... ) FMTFUNCTION( 3, 4 ); +PLATFORM_OVERLOAD LoggingResponse_t LoggingSystem_Log( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, const char *pMessageFormat, ... ) FMTFUNCTION( 4, 5 ); + +PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_LogDirect( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, const char *pMessage ); +PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_LogAssert( const char *pMessageFormat, ... ) FMTFUNCTION( 1, 2 ); + +#endif // LOGGING_H
\ No newline at end of file diff --git a/external/vpc/public/tier0/mem.h b/external/vpc/public/tier0/mem.h new file mode 100644 index 0000000..ffb590b --- /dev/null +++ b/external/vpc/public/tier0/mem.h @@ -0,0 +1,50 @@ +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Memory allocation! +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_MEM_H +#define TIER0_MEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include <stddef.h> + + +#include "tier0/platform.h" + +#if !defined(STATIC_TIER0) && !defined(_STATIC_LINKED) + +#ifdef TIER0_DLL_EXPORT +# define MEM_INTERFACE DLL_EXPORT +#else +# define MEM_INTERFACE DLL_IMPORT +#endif + +#else // BUILD_AS_DLL + +#define MEM_INTERFACE extern + +#endif // BUILD_AS_DLL + + + +//----------------------------------------------------------------------------- +// DLL-exported methods for particular kinds of memory +//----------------------------------------------------------------------------- +MEM_INTERFACE void *MemAllocScratch( int nMemSize ); +MEM_INTERFACE void MemFreeScratch(); + +#if defined( POSIX ) +MEM_INTERFACE void ZeroMemory( void *mem, size_t length ); +#endif + +//Only works with USE_MEM_DEBUG and memory allocation call stack tracking enabled. +MEM_INTERFACE int GetAllocationCallStack( void *mem, void **pCallStackOut, int iMaxEntriesOut ); + + +#endif /* TIER0_MEM_H */ diff --git a/external/vpc/public/tier0/memalloc.h b/external/vpc/public/tier0/memalloc.h new file mode 100644 index 0000000..4254e74 --- /dev/null +++ b/external/vpc/public/tier0/memalloc.h @@ -0,0 +1,701 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This header should never be used directly from leaf code!!! +// Instead, just add the file memoverride.cpp into your project and all this +// will automagically be used +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_MEMALLOC_H +#define TIER0_MEMALLOC_H + +#ifdef _WIN32 +#pragma once +#endif + +// These memory debugging switches aren't relevant under Linux builds since memoverride.cpp +// isn't built into Linux projects +#ifndef LINUX +// Define this in release to get memory tracking even in release builds +//#define USE_MEM_DEBUG 1 + +// Define this in release to get light memory debugging +//#define USE_LIGHT_MEM_DEBUG + +// Define this to require -uselmd to turn light memory debugging on +//#define LIGHT_MEM_DEBUG_REQUIRES_CMD_LINE_SWITCH +#endif + +#if defined( _MEMTEST ) +#if defined( _WIN32 ) || defined( _PS3 ) +#define USE_MEM_DEBUG 1 +#endif +#endif + + +#if defined( _PS3 ) +// Define STEAM_SHARES_GAME_ALLOCATOR to make Steam use the game's tier0 memory allocator. +// This adds some memory to the game's Small Block Heap and Medium Block Heap, to compensate. +// This configuration was disabled for Portal 2, as we could not sufficiently test it before ship. +//#define STEAM_SHARES_GAME_ALLOCATOR +#endif + +#if defined( STEAM_SHARES_GAME_ALLOCATOR ) +#define MBYTES_STEAM_SBH_USAGE 2 +#define MBYTES_STEAM_MBH_USAGE 4 +#else // STEAM_SHARES_GAME_ALLOCATOR +#define MBYTES_STEAM_SBH_USAGE 0 +#define MBYTES_STEAM_MBH_USAGE 0 +#endif // STEAM_SHARES_GAME_ALLOCATOR + +// Undefine this if using a compiler lacking threadsafe RTTI (like vc6) +#define MEM_DEBUG_CLASSNAME 1 + +#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) + +#include <stddef.h> +#ifdef LINUX +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + +#ifdef _PS3 +#define MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS 1 +#endif + +#include "tier0/mem.h" + +struct _CrtMemState; + +#define MEMALLOC_VERSION 1 + +typedef size_t (*MemAllocFailHandler_t)( size_t ); + +struct GenericMemoryStat_t +{ + const char *name; + int value; +}; + + +// Virtual memory interface +#include "tier0/memvirt.h" + + +//----------------------------------------------------------------------------- +// NOTE! This should never be called directly from leaf code +// Just use new,delete,malloc,free etc. They will call into this eventually +//----------------------------------------------------------------------------- +abstract_class IMemAlloc +{ +public: + // Release versions + virtual void *Alloc( size_t nSize ) = 0; +public: + virtual void *Realloc( void *pMem, size_t nSize ) = 0; + + virtual void Free( void *pMem ) = 0; + virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize ) = 0; + + // Debug versions + virtual void *Alloc( size_t nSize, const char *pFileName, int nLine ) = 0; +public: + virtual void *Realloc( void *pMem, size_t nSize, const char *pFileName, int nLine ) = 0; + virtual void Free( void *pMem, const char *pFileName, int nLine ) = 0; + virtual void *Expand_NoLongerSupported( void *pMem, size_t nSize, const char *pFileName, int nLine ) = 0; + +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + virtual void *AllocAlign( size_t nSize, size_t align ) = 0; + virtual void *AllocAlign( size_t nSize, size_t align, const char *pFileName, int nLine ) = 0; + virtual void *ReallocAlign( void *pMem, size_t nSize, size_t align ) = 0; +#endif + + inline void *IndirectAlloc( size_t nSize ) { return Alloc( nSize ); } + inline void *IndirectAlloc( size_t nSize, const char *pFileName, int nLine ) { return Alloc( nSize, pFileName, nLine ); } + + // Returns the size of a particular allocation (NOTE: may be larger than the size requested!) + virtual size_t GetSize( void *pMem ) = 0; + + // Force file + line information for an allocation + virtual void PushAllocDbgInfo( const char *pFileName, int nLine ) = 0; + virtual void PopAllocDbgInfo() = 0; + + // FIXME: Remove when we have our own allocator + // these methods of the Crt debug code is used in our codebase currently + virtual int32 CrtSetBreakAlloc( int32 lNewBreakAlloc ) = 0; + virtual int CrtSetReportMode( int nReportType, int nReportMode ) = 0; + virtual int CrtIsValidHeapPointer( const void *pMem ) = 0; + virtual int CrtIsValidPointer( const void *pMem, unsigned int size, int access ) = 0; + virtual int CrtCheckMemory( void ) = 0; + virtual int CrtSetDbgFlag( int nNewFlag ) = 0; + virtual void CrtMemCheckpoint( _CrtMemState *pState ) = 0; + + // FIXME: Make a better stats interface + virtual void DumpStats() = 0; + virtual void DumpStatsFileBase( char const *pchFileBase ) = 0; + virtual size_t ComputeMemoryUsedBy( char const *pchSubStr ) = 0; + + // FIXME: Remove when we have our own allocator + virtual void* CrtSetReportFile( int nRptType, void* hFile ) = 0; + virtual void* CrtSetReportHook( void* pfnNewHook ) = 0; + virtual int CrtDbgReport( int nRptType, const char * szFile, + int nLine, const char * szModule, const char * pMsg ) = 0; + + virtual int heapchk() = 0; + + virtual bool IsDebugHeap() = 0; + + virtual void GetActualDbgInfo( const char *&pFileName, int &nLine ) = 0; + virtual void RegisterAllocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) = 0; + virtual void RegisterDeallocation( const char *pFileName, int nLine, size_t nLogicalSize, size_t nActualSize, unsigned nTime ) = 0; + + virtual int GetVersion() = 0; + + virtual void CompactHeap() = 0; + + // Function called when malloc fails or memory limits hit to attempt to free up memory (can come in any thread) + virtual MemAllocFailHandler_t SetAllocFailHandler( MemAllocFailHandler_t pfnMemAllocFailHandler ) = 0; + + virtual void DumpBlockStats( void * ) = 0; + + virtual void SetStatsExtraInfo( const char *pMapName, const char *pComment ) = 0; + + // Returns 0 if no failure, otherwise the size_t of the last requested chunk + virtual size_t MemoryAllocFailed() = 0; + + virtual void CompactIncremental() = 0; + + virtual void OutOfMemory( size_t nBytesAttempted = 0 ) = 0; + + // Region-based allocations + virtual void *RegionAlloc( int region, size_t nSize ) = 0; + virtual void *RegionAlloc( int region, size_t nSize, const char *pFileName, int nLine ) = 0; + + // Replacement for ::GlobalMemoryStatus which accounts for unused memory in our system + virtual void GlobalMemoryStatus( size_t *pUsedMemory, size_t *pFreeMemory ) = 0; + + // Obtain virtual memory manager interface + virtual IVirtualMemorySection * AllocateVirtualMemorySection( size_t numMaxBytes ) = 0; + + // Request 'generic' memory stats (returns a list of N named values; caller should assume this list will change over time) + virtual int GetGenericMemoryStats( GenericMemoryStat_t **ppMemoryStats ) = 0; + + virtual ~IMemAlloc() { }; + + // handles storing allocation info for coroutines + virtual uint32 GetDebugInfoSize() = 0; + virtual void SaveDebugInfo( void *pvDebugInfo ) = 0; + virtual void RestoreDebugInfo( const void *pvDebugInfo ) = 0; + virtual void InitDebugInfo( void *pvDebugInfo, const char *pchRootFileName, int nLine ) = 0; +}; + +//----------------------------------------------------------------------------- +// Singleton interface +//----------------------------------------------------------------------------- +#ifdef _PS3 + +PLATFORM_INTERFACE IMemAlloc * g_pMemAllocInternalPS3; +#ifndef PLATFORM_INTERFACE_MEM_ALLOC_INTERNAL_PS3_OVERRIDE +#define g_pMemAlloc g_pMemAllocInternalPS3 +#else +#define g_pMemAlloc PLATFORM_INTERFACE_MEM_ALLOC_INTERNAL_PS3_OVERRIDE +#endif + +#else // !_PS3 + +MEM_INTERFACE IMemAlloc *g_pMemAlloc; + +#endif + +//----------------------------------------------------------------------------- + +#ifdef MEMALLOC_REGIONS +#ifndef MEMALLOC_REGION +#define MEMALLOC_REGION 0 +#endif +inline void *MemAlloc_Alloc( size_t nSize ) +{ + return g_pMemAlloc->RegionAlloc( MEMALLOC_REGION, nSize ); +} + +inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName, int nLine ) +{ + return g_pMemAlloc->RegionAlloc( MEMALLOC_REGION, nSize, pFileName, nLine ); +} +#else +#undef MEMALLOC_REGION +inline void *MemAlloc_Alloc( size_t nSize ) +{ + return g_pMemAlloc->IndirectAlloc( nSize ); +} + +inline void *MemAlloc_Alloc( size_t nSize, const char *pFileName, int nLine ) +{ + return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine ); +} +#endif + +//----------------------------------------------------------------------------- + +#ifdef MEMALLOC_REGIONS +#else +#endif + + +inline bool ValueIsPowerOfTwo( size_t value ) // don't clash with mathlib definition +{ + return (value & ( value - 1 )) == 0; +} + + +inline void *MemAlloc_AllocAlignedUnattributed( size_t size, size_t align ) +{ +#ifndef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + unsigned char *pAlloc, *pResult; + +#endif + + if (!ValueIsPowerOfTwo(align)) + return NULL; + +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + return g_pMemAlloc->AllocAlign( size, align ); + +#else + + align = (align > sizeof(void *) ? align : sizeof(void *)) - 1; + + if ( (pAlloc = (unsigned char*)MemAlloc_Alloc( sizeof(void *) + align + size ) ) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align ); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void *)pResult; + +#endif +} + +inline void *MemAlloc_AllocAlignedFileLine( size_t size, size_t align, const char *pszFile, int nLine ) +{ +#ifndef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + unsigned char *pAlloc, *pResult; + +#endif + + if (!ValueIsPowerOfTwo(align)) + return NULL; + +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + return g_pMemAlloc->AllocAlign( size, align, pszFile, nLine ); + +#else + + align = (align > sizeof(void *) ? align : sizeof(void *)) - 1; + + if ( (pAlloc = (unsigned char*)MemAlloc_Alloc( sizeof(void *) + align + size, pszFile, nLine ) ) == (unsigned char*)NULL) + return NULL; + + pResult = (unsigned char*)( (size_t)(pAlloc + sizeof(void *) + align ) & ~align ); + ((unsigned char**)(pResult))[-1] = pAlloc; + + return (void *)pResult; + +#endif +} + +#ifdef USE_MEM_DEBUG +#define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedFileLine( s, a, __FILE__, __LINE__ ) +#elif defined(USE_LIGHT_MEM_DEBUG) +extern const char *g_pszModule; +#define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedFileLine( s, a, g_pszModule, 0 ) +#else +#define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedUnattributed( s, a ) +#endif + + +inline void *MemAlloc_ReallocAligned( void *ptr, size_t size, size_t align ) +{ + if ( !ValueIsPowerOfTwo( align ) ) + return NULL; + + // Don't change alignment between allocation + reallocation. + if ( ( (size_t)ptr & ( align - 1 ) ) != 0 ) + return NULL; + +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + return g_pMemAlloc->ReallocAlign( ptr, size, align ); + +#else + + if ( !ptr ) + return MemAlloc_AllocAligned( size, align ); + + void *pAlloc, *pResult; + + // Figure out the actual allocation point + pAlloc = ptr; + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + pAlloc = *( (void **)pAlloc ); + + // See if we have enough space + size_t nOffset = (size_t)ptr - (size_t)pAlloc; + size_t nOldSize = g_pMemAlloc->GetSize( pAlloc ); + if ( nOldSize >= size + nOffset ) + return ptr; + + pResult = MemAlloc_AllocAligned( size, align ); + memcpy( pResult, ptr, nOldSize - nOffset ); + g_pMemAlloc->Free( pAlloc ); + return pResult; + +#endif +} + +inline void MemAlloc_FreeAligned( void *pMemBlock ) +{ +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + g_pMemAlloc->Free( pMemBlock ); + +#else + + void *pAlloc; + + if ( pMemBlock == NULL ) + return; + + pAlloc = pMemBlock; + + // pAlloc points to the pointer to starting of the memory block + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + + // pAlloc is the pointer to the start of memory block + pAlloc = *( (void **)pAlloc ); + + g_pMemAlloc->Free( pAlloc ); + +#endif +} + +inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pszFile, int nLine ) +{ +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + g_pMemAlloc->Free( pMemBlock, pszFile, nLine ); + +#else + + void *pAlloc; + + if ( pMemBlock == NULL ) + return; + + pAlloc = pMemBlock; + + // pAlloc points to the pointer to starting of the memory block + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + + // pAlloc is the pointer to the start of memory block + pAlloc = *( (void **)pAlloc ); + g_pMemAlloc->Free( pAlloc, pszFile, nLine ); + +#endif +} + +inline size_t MemAlloc_GetSizeAligned( void *pMemBlock ) +{ +#ifdef MEMALLOC_SUPPORTS_ALIGNED_ALLOCATIONS + + return g_pMemAlloc->GetSize( pMemBlock ); + +#else + + void *pAlloc; + + if ( pMemBlock == NULL ) + return 0; + + pAlloc = pMemBlock; + + // pAlloc points to the pointer to starting of the memory block + pAlloc = (void *)(((size_t)pAlloc & ~( sizeof(void *) - 1 ) ) - sizeof(void *)); + + // pAlloc is the pointer to the start of memory block + pAlloc = *((void **)pAlloc ); + return g_pMemAlloc->GetSize( pAlloc ) - ( (byte *)pMemBlock - (byte *)pAlloc ); + +#endif +} + + +struct aligned_tmp_t +{ + // empty base class +}; + +// template here to allow adding alignment at levels of hierarchy that aren't the base +template< int bytesAlignment = 16, class T = aligned_tmp_t > +class CAlignedNewDelete : public T +{ +public: + void *operator new( size_t nSize ) + { + return MemAlloc_AllocAligned( nSize, bytesAlignment ); + } + + void* operator new( size_t nSize, int nBlockUse, const char *pFileName, int nLine ) + { + return MemAlloc_AllocAlignedFileLine( nSize, bytesAlignment, pFileName, nLine ); + } + + void operator delete(void *pData) + { + if ( pData ) + { + MemAlloc_FreeAligned( pData ); + } + } + + void operator delete( void* pData, int nBlockUse, const char *pFileName, int nLine ) + { + if ( pData ) + { + MemAlloc_FreeAligned( pData, pFileName, nLine ); + } + } +}; + +//----------------------------------------------------------------------------- + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +#define MEM_ALLOC_CREDIT_(tag) CMemAllocAttributeAlloction memAllocAttributeAlloction( tag, __LINE__ ) +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) g_pMemAlloc->PushAllocDbgInfo( pszFile, line ) +#define MemAlloc_PopAllocDbgInfo() g_pMemAlloc->PopAllocDbgInfo() +#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) +#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) +#else +#define MEM_ALLOC_CREDIT_(tag) ((void)0) +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) ((void)0) +#define MemAlloc_PopAllocDbgInfo() ((void)0) +#define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) +#define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0) +#endif + +//----------------------------------------------------------------------------- + +class CMemAllocAttributeAlloction +{ +public: + CMemAllocAttributeAlloction( const char *pszFile, int line ) + { + MemAlloc_PushAllocDbgInfo( pszFile, line ); + } + + ~CMemAllocAttributeAlloction() + { + MemAlloc_PopAllocDbgInfo(); + } +}; + +#define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__) + +//----------------------------------------------------------------------------- + +#if defined(MSVC) && ( defined(_DEBUG) || defined(USE_MEM_DEBUG) ) + + #pragma warning(disable:4290) + #pragma warning(push) + #include <typeinfo.h> + + // MEM_DEBUG_CLASSNAME is opt-in. + // Note: typeid().name() is not threadsafe, so if the project needs to access it in multiple threads + // simultaneously, it'll need a mutex. + #if defined(_CPPRTTI) && defined(MEM_DEBUG_CLASSNAME) + + template <typename T> const char *MemAllocClassName( T *p ) + { + static const char *pszName = typeid(*p).name(); // @TODO: support having debug heap ignore certain allocations, and ignore memory allocated here [5/7/2009 tom] + return pszName; + } + + #define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( MemAllocClassName( this ) ) + #define MEM_ALLOC_CLASSNAME(type) (typeid((type*)(0)).name()) + #else + #define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( __FILE__ ) + #define MEM_ALLOC_CLASSNAME(type) (__FILE__) + #endif + + // MEM_ALLOC_CREDIT_FUNCTION is used when no this pointer is available ( inside 'new' overloads, for example ) + #ifdef _MSC_VER + #define MEM_ALLOC_CREDIT_FUNCTION() MEM_ALLOC_CREDIT_( __FUNCTION__ ) + #else + #define MEM_ALLOC_CREDIT_FUNCTION() (__FILE__) + #endif + + #pragma warning(pop) +#else + #define MEM_ALLOC_CREDIT_CLASS() + #define MEM_ALLOC_CLASSNAME(type) NULL + #define MEM_ALLOC_CREDIT_FUNCTION() +#endif + +//----------------------------------------------------------------------------- + +#if (defined(_DEBUG) || defined(USE_MEM_DEBUG)) +struct MemAllocFileLine_t +{ + const char *pszFile; + int line; +}; + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) \ + static CUtlMap<void *, MemAllocFileLine_t, int> s_##tag##Allocs( DefLessFunc( void *) ); \ + CUtlMap<void *, MemAllocFileLine_t, int> * g_p##tag##Allocs = &s_##tag##Allocs; \ + static CThreadFastMutex s_##tag##AllocsMutex; \ + CThreadFastMutex * g_p##tag##AllocsMutex = &s_##tag##AllocsMutex; \ + const char * g_psz##tag##Alloc = strcpy( (char *)MemAlloc_Alloc( strlen( #tag "Alloc" ) + 1, "intentional leak", 0 ), #tag "Alloc" ); + +#define MEMALLOC_DECLARE_EXTERNAL_TRACKING( tag ) \ + extern CUtlMap<void *, MemAllocFileLine_t, int> * g_p##tag##Allocs; \ + extern CThreadFastMutex *g_p##tag##AllocsMutex; \ + extern const char * g_psz##tag##Alloc; + +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) \ + if ( !p ) \ + ; \ + else \ + { \ + AUTO_LOCK_FM( *g_p##tag##AllocsMutex ); \ + MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \ + g_pMemAlloc->GetActualDbgInfo( fileLine.pszFile, fileLine.line ); \ + if ( fileLine.pszFile != g_psz##tag##Alloc ) \ + { \ + g_p##tag##Allocs->Insert( p, fileLine ); \ + } \ + \ + MemAlloc_RegisterAllocation( fileLine.pszFile, fileLine.line, size, size, 0); \ + } + +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) \ + if ( !p ) \ + ; \ + else \ + { \ + AUTO_LOCK_FM( *g_p##tag##AllocsMutex ); \ + MemAllocFileLine_t fileLine = { g_psz##tag##Alloc, 0 }; \ + CUtlMap<void *, MemAllocFileLine_t, int>::IndexType_t iRecordedFileLine = g_p##tag##Allocs->Find( p ); \ + if ( iRecordedFileLine != g_p##tag##Allocs->InvalidIndex() ) \ + { \ + fileLine = (*g_p##tag##Allocs)[iRecordedFileLine]; \ + g_p##tag##Allocs->RemoveAt( iRecordedFileLine ); \ + } \ + \ + MemAlloc_RegisterDeallocation( fileLine.pszFile, fileLine.line, size, size, 0); \ + } + +#else + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) +#define MEMALLOC_DECLARE_EXTERNAL_TRACKING( tag ) +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0) +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0) + +#endif + +//----------------------------------------------------------------------------- + +#endif // !STEAM && !NO_MALLOC_OVERRIDE + +//----------------------------------------------------------------------------- + +#if !defined(STEAM) && defined(NO_MALLOC_OVERRIDE) +#include <malloc.h> + +#define MEM_ALLOC_CREDIT_(tag) ((void)0) +#define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__) +#define MEM_ALLOC_CREDIT_CLASS() +#define MEM_ALLOC_CLASSNAME(type) NULL + +#define MemAlloc_PushAllocDbgInfo( pszFile, line ) +#define MemAlloc_PopAllocDbgInfo() + +#define MemAlloc_RegisterAllocation( a,b,c,d,e ) ((void)0) +#define MemAlloc_RegisterDeallocation( a,b,c,d,e ) ((void)0) + +#define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) +#define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0) +#define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0) + +inline void *MemAlloc_AllocAligned( size_t size, size_t align ) +{ + return (void *)_aligned_malloc( size, align ); +} +inline void *MemAlloc_AllocAligned( size_t size, size_t align, const char *pszFile, int nLine ) +{ + pszFile = pszFile; + nLine = nLine; + return (void *)_aligned_malloc( size, align ); +} + +inline void MemAlloc_FreeAligned( void *pMemBlock ) +{ + _aligned_free( pMemBlock ); +} +inline void MemAlloc_FreeAligned( void *pMemBlock, const char *pszFile, int nLine ) +{ + pszFile = pszFile; + nLine = nLine; + _aligned_free( pMemBlock ); +} + +#endif // !STEAM && NO_MALLOC_OVERRIDE + +//----------------------------------------------------------------------------- + + + +// linux memory tracking via hooks. +#if defined( POSIX ) && !defined( _PS3 ) +PLATFORM_INTERFACE void MemoryLogMessage( char const *s ); // throw a message into the memory log +PLATFORM_INTERFACE void EnableMemoryLogging( bool bOnOff ); +PLATFORM_INTERFACE void DumpMemoryLog( int nThresh ); +PLATFORM_INTERFACE void DumpMemorySummary( void ); +PLATFORM_INTERFACE void SetMemoryMark( void ); +PLATFORM_INTERFACE void DumpChangedMemory( int nThresh ); + +// ApproximateProcessMemoryUsage returns the approximate memory footprint of this process. +PLATFORM_INTERFACE size_t ApproximateProcessMemoryUsage( void ); +#else +inline void MemoryLogMessage( char const * ) +{ +} +inline void EnableMemoryLogging( bool ) +{ +} +inline void DumpMemoryLog( int ) +{ +} +inline void DumpMemorySummary( void ) +{ +} +inline void SetMemoryMark( void ) +{ +} +inline void DumpChangedMemory( int ) +{ +} +inline size_t ApproximateProcessMemoryUsage( void ) +{ + return 0; +} +#endif + + +#endif /* TIER0_MEMALLOC_H */ diff --git a/external/vpc/public/tier0/memdbgoff.h b/external/vpc/public/tier0/memdbgoff.h new file mode 100644 index 0000000..4d2c021 --- /dev/null +++ b/external/vpc/public/tier0/memdbgoff.h @@ -0,0 +1,25 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This header, which must be the final line of a .h file, +// causes all crt methods to stop using debugging versions of the memory allocators. +// NOTE: Use memdbgon.h to re-enable memory debugging. +// +// $NoKeywords: $ +//=============================================================================// + +#ifdef MEM_OVERRIDE_ON + +#undef malloc +#undef realloc +#undef calloc +#undef free +#undef _expand +#undef _msize +#undef new +#undef _aligned_malloc +#undef _aligned_free +#undef _malloc_dbg + +#undef MEM_OVERRIDE_ON + +#endif diff --git a/external/vpc/public/tier0/memdbgon.h b/external/vpc/public/tier0/memdbgon.h new file mode 100644 index 0000000..e66664d --- /dev/null +++ b/external/vpc/public/tier0/memdbgon.h @@ -0,0 +1,281 @@ +//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This header, which must be the final include in a .cpp (or .h) file, +// causes all crt methods to use debugging versions of the memory allocators. +// NOTE: Use memdbgoff.h to disable memory debugging. +// +// $NoKeywords: $ +//=============================================================================// + +// SPECIAL NOTE! This file must *not* use include guards; we need to be able +// to include this potentially multiple times (since we can deactivate debugging +// by including memdbgoff.h) + +#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE) + +// SPECIAL NOTE #2: This must be the final include in a .cpp or .h file!!! + +#if defined(_DEBUG) && !defined(USE_MEM_DEBUG) && !defined( _PS3 ) +#define USE_MEM_DEBUG 1 +#endif + +// If debug build or ndebug and not already included MS custom alloc files, or already included this file +#if (defined(_DEBUG) || !defined(_INC_CRTDBG)) || defined(MEMDBGON_H) + +#include "tier0/basetypes.h" + +#include "tier0/valve_off.h" + #ifdef COMPILER_MSVC + #include <tchar.h> + #else + #include <wchar.h> + #endif + #include <string.h> + #ifndef _PS3 + #include <malloc.h> + #endif +#include "tier0/valve_on.h" + +#include "commonmacros.h" +#include "memalloc.h" + +#ifdef _WIN32 +#ifndef MEMALLOC_REGION +#define MEMALLOC_REGION 0 +#endif +#else +#undef MEMALLOC_REGION +#endif + +#if defined(USE_MEM_DEBUG) + #if defined( POSIX ) || defined( _PS3 ) + #define _NORMAL_BLOCK 1 + + #include "tier0/valve_off.h" + #include <cstddef> + #include <new> + #include <sys/types.h> + #if !defined( DID_THE_OPERATOR_NEW ) + #define DID_THE_OPERATOR_NEW + // posix doesn't have a new of this form, so we impl our own + void* operator new( size_t nSize, int blah, const char *pFileName, int nLine ); + void* operator new[]( size_t nSize, int blah, const char *pFileName, int nLine ); + #endif + + #else // defined(POSIX) + + // Include crtdbg.h and make sure _DEBUG is set to 1. + #if !defined(_DEBUG) + #define _DEBUG 1 + #include <crtdbg.h> + #undef _DEBUG + #else + #include <crtdbg.h> + #endif // !defined(_DEBUG) + + #endif // defined(POSIX) +#endif + +#include "tier0/memdbgoff.h" + +// -------------------------------------------------------- +// Debug/non-debug agnostic elements + +#define MEM_OVERRIDE_ON 1 + +#undef malloc +#undef realloc +#undef calloc +#undef _expand +#undef free +#undef _msize +#undef _aligned_malloc +#undef _aligned_free + +#ifndef MEMDBGON_H +inline void *MemAlloc_InlineCallocMemset( void *pMem, size_t nCount, size_t nElementSize) +{ + memset(pMem, 0, nElementSize * nCount); + return pMem; +} +#endif + +#define calloc(c, s) MemAlloc_InlineCallocMemset(malloc(c*s), c, s) +#ifndef USE_LIGHT_MEM_DEBUG +#define free(p) g_pMemAlloc->Free( p ) +#define _aligned_free( p ) MemAlloc_FreeAligned( p ) +#else +extern const char *g_pszModule; +#define free(p) g_pMemAlloc->Free( p, g_pszModule, 0 ) +#define _aligned_free( p ) MemAlloc_FreeAligned( p, g_pszModule, 0 ) +#endif +#define _msize(p) g_pMemAlloc->GetSize( p ) +#define _expand(p, s) _expand_NoLongerSupported(p, s) + +// -------------------------------------------------------- +// Debug path +#if defined(USE_MEM_DEBUG) + +#define malloc(s) MemAlloc_Alloc( s, __FILE__, __LINE__) +#define realloc(p, s) g_pMemAlloc->Realloc( p, s, __FILE__, __LINE__ ) +#define _aligned_malloc( s, a ) MemAlloc_AllocAlignedFileLine( s, a, __FILE__, __LINE__ ) + +#define _malloc_dbg(s, t, f, l) WHYCALLINGTHISDIRECTLY(s) + +#undef new + +#if defined( _PS3 ) + #ifndef PS3_OPERATOR_NEW_WRAPPER_DEFINED + #define PS3_OPERATOR_NEW_WRAPPER_DEFINED + inline void* operator new( size_t nSize, int blah, const char *pFileName, int nLine ) { return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine ); } + inline void* operator new[]( size_t nSize, int blah, const char *pFileName, int nLine ) { return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine ); } + #endif + #define new new( 1, __FILE__, __LINE__ ) +#elif !defined( GNUC ) + #if defined(__AFX_H__) && defined(DEBUG_NEW) + #define new DEBUG_NEW + #else + #define MEMALL_DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) + #define new MEMALL_DEBUG_NEW + #endif +#endif + +#undef _strdup +#undef strdup +#undef _wcsdup +#undef wcsdup + +#define _strdup(s) MemAlloc_StrDup(s, __FILE__, __LINE__) +#define strdup(s) MemAlloc_StrDup(s, __FILE__, __LINE__) +#define _wcsdup(s) MemAlloc_WcStrDup(s, __FILE__, __LINE__) +#define wcsdup(s) MemAlloc_WcStrDup(s, __FILE__, __LINE__) + +// Make sure we don't define strdup twice +#if !defined(MEMDBGON_H) + +inline char *MemAlloc_StrDup(const char *pString, const char *pFileName, unsigned nLine) +{ + char *pMemory; + + if (!pString) + return NULL; + + size_t len = strlen(pString) + 1; + if ((pMemory = (char *)MemAlloc_Alloc(len, pFileName, nLine)) != NULL) + { + return strcpy( pMemory, pString ); + } + + return NULL; +} + +inline wchar_t *MemAlloc_WcStrDup(const wchar_t *pString, const char *pFileName, unsigned nLine) +{ + wchar_t *pMemory; + + if (!pString) + return NULL; + + size_t len = (wcslen(pString) + 1); + if ((pMemory = (wchar_t *)MemAlloc_Alloc(len * sizeof(wchar_t), pFileName, nLine)) != NULL) + { + return wcscpy( pMemory, pString ); + } + + return NULL; +} + +#endif // DBMEM_DEFINED_STRDUP + +#else +// -------------------------------------------------------- +// Release path + +#ifndef USE_LIGHT_MEM_DEBUG +#define malloc(s) MemAlloc_Alloc( s ) +#define realloc(p, s) g_pMemAlloc->Realloc( p, s ) +#define _aligned_malloc( s, a ) MemAlloc_AllocAligned( s, a ) +#else +#define malloc(s) MemAlloc_Alloc( s, g_pszModule, 0 ) +#define realloc(p, s) g_pMemAlloc->Realloc( p, s, g_pszModule, 0 ) +#define _aligned_malloc( s, a ) MemAlloc_AllocAlignedFileLine( s, a, g_pszModule, 0 ) +#endif + +#ifndef _malloc_dbg +#define _malloc_dbg(s, t, f, l) WHYCALLINGTHISDIRECTLY(s) +#endif + +#undef new + +#if defined( _PS3 ) && !defined( _CERT ) + #ifndef PS3_OPERATOR_NEW_WRAPPER_DEFINED + #define PS3_OPERATOR_NEW_WRAPPER_DEFINED + inline void* operator new( size_t nSize, int blah, const char *pFileName, int nLine ) { return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine ); } + inline void* operator new[]( size_t nSize, int blah, const char *pFileName, int nLine ) { return g_pMemAlloc->IndirectAlloc( nSize, pFileName, nLine ); } + #endif + #define new new( 1, __FILE__, __LINE__ ) +#endif + +#undef _strdup +#undef strdup +#undef _wcsdup +#undef wcsdup + +#define _strdup(s) MemAlloc_StrDup(s) +#define strdup(s) MemAlloc_StrDup(s) +#define _wcsdup(s) MemAlloc_WcStrDup(s) +#define wcsdup(s) MemAlloc_WcStrDup(s) + +// Make sure we don't define strdup twice +#if !defined(MEMDBGON_H) + +inline char *MemAlloc_StrDup(const char *pString) +{ + char *pMemory; + + if (!pString) + return NULL; + + size_t len = strlen(pString) + 1; + if ((pMemory = (char *)malloc(len)) != NULL) + { + return strcpy( pMemory, pString ); + } + + return NULL; +} + +inline wchar_t *MemAlloc_WcStrDup(const wchar_t *pString) +{ + wchar_t *pMemory; + + if (!pString) + return NULL; + + size_t len = (wcslen(pString) + 1); + if ((pMemory = (wchar_t *)malloc(len * sizeof(wchar_t))) != NULL) + { + return wcscpy( pMemory, pString ); + } + + return NULL; +} + +#endif // DBMEM_DEFINED_STRDUP + +#endif // USE_MEM_DEBUG + +#define MEMDBGON_H // Defined here so can be used above + +#else + +#if defined(USE_MEM_DEBUG) +#ifndef _STATIC_LINKED +#pragma message ("Note: file includes crtdbg.h directly, therefore will cannot use memdbgon.h in non-debug build") +#else +#error "Error: file includes crtdbg.h directly, therefore will cannot use memdbgon.h in non-debug build. Not recoverable in static build" +#endif +#endif +#endif // _INC_CRTDBG + +#endif // !STEAM && !NO_MALLOC_OVERRIDE diff --git a/external/vpc/public/tier0/memvirt.h b/external/vpc/public/tier0/memvirt.h new file mode 100644 index 0000000..eeb0996 --- /dev/null +++ b/external/vpc/public/tier0/memvirt.h @@ -0,0 +1,46 @@ +//========== Copyright (C) Valve Corporation, All rights reserved. ==========// +// +// Purpose: CVirtualMemoryManager interface +// +//===========================================================================// + +#ifndef MEM_VIRT_H +#define MEM_VIRT_H +#ifdef _WIN32 +#pragma once +#endif + + +#define VMM_KB ( 1024 ) +#define VMM_MB ( 1024 * VMM_KB ) + +#ifdef _PS3 +// Total virtual address space reserved by CVirtualMemoryManager on startup: +#define VMM_VIRTUAL_SIZE ( 512 * VMM_MB ) +#define VMM_PAGE_SIZE ( 64 * VMM_KB ) +#endif + + + +// Allocate virtual sections via IMemAlloc::AllocateVirtualMemorySection +abstract_class IVirtualMemorySection +{ +public: + // Information about memory section + virtual void * GetBaseAddress() = 0; + virtual size_t GetPageSize() = 0; + virtual size_t GetTotalSize() = 0; + + // Functions to manage physical memory mapped to virtual memory + virtual bool CommitPages( void *pvBase, size_t numBytes ) = 0; + virtual void DecommitPages( void *pvBase, size_t numBytes ) = 0; + + // Release the physical memory and associated virtual address space + virtual void Release() = 0; +}; + +// Get the IVirtualMemorySection associated with a given memory address (if any): +extern IVirtualMemorySection *GetMemorySectionForAddress( void *pAddress ); + + +#endif // MEM_VIRT_H diff --git a/external/vpc/public/tier0/minidump.h b/external/vpc/public/tier0/minidump.h new file mode 100644 index 0000000..8f4b7b0 --- /dev/null +++ b/external/vpc/public/tier0/minidump.h @@ -0,0 +1,82 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef MINIDUMP_H +#define MINIDUMP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +// writes out a minidump of the current stack trace with a unique filename +PLATFORM_INTERFACE void WriteMiniDump(); + +typedef void (*FnWMain)( int , tchar *[] ); + +#ifdef IS_WINDOWS_PC + +// calls the passed in function pointer and catches any exceptions/crashes thrown by it, and writes a minidump +// use from wmain() to protect the whole program + +PLATFORM_INTERFACE void CatchAndWriteMiniDump( FnWMain pfn, int argc, tchar *argv[] ); + +// The ExceptionInfo_t struct is a typeless data struct +// which is OS-dependent and should never be used by external code. +// Just pass it back into MinidumpSetUnhandledExceptionFunction +struct ExceptionInfo_t; + + +// Replaces the current function pointer with the one passed in. +// Returns the previously-set function. +// The function is called internally by WriteMiniDump() and CatchAndWriteMiniDump() +// The default is the built-in function that uses DbgHlp.dll's MiniDumpWriteDump function +typedef void (*FnMiniDump)( unsigned int uStructuredExceptionCode, ExceptionInfo_t * pExceptionInfo ); +PLATFORM_INTERFACE FnMiniDump SetMiniDumpFunction( FnMiniDump pfn ); + +// Use this to write a minidump explicitly. +// Some of the tools choose to catch the minidump themselves instead of using CatchAndWriteMinidump +// so they can show their own dialog. +// +// ptchMinidumpFileNameBuffer if not-NULL should be a writable tchar buffer of length at +// least _MAX_PATH and on return will contain the name of the minidump file written. +// If ptchMinidumpFileNameBuffer is NULL the name of the minidump file written will not +// be available after the function returns. +// + + +// NOTE: Matches windows.h +enum MinidumpType_t +{ + MINIDUMP_Normal = 0x00000000, + MINIDUMP_WithDataSegs = 0x00000001, + MINIDUMP_WithFullMemory = 0x00000002, + MINIDUMP_WithHandleData = 0x00000004, + MINIDUMP_FilterMemory = 0x00000008, + MINIDUMP_ScanMemory = 0x00000010, + MINIDUMP_WithUnloadedModules = 0x00000020, + MINIDUMP_WithIndirectlyReferencedMemory = 0x00000040, + MINIDUMP_FilterModulePaths = 0x00000080, + MINIDUMP_WithProcessThreadData = 0x00000100, + MINIDUMP_WithPrivateReadWriteMemory = 0x00000200, + MINIDUMP_WithoutOptionalData = 0x00000400, + MINIDUMP_WithFullMemoryInfo = 0x00000800, + MINIDUMP_WithThreadInfo = 0x00001000, + MINIDUMP_WithCodeSegs = 0x00002000 +}; + +PLATFORM_INTERFACE bool WriteMiniDumpUsingExceptionInfo( + unsigned int uStructuredExceptionCode, + ExceptionInfo_t *pExceptionInfo, + uint32 nMinidumpTypeFlags, // OR-ed together MinidumpType_t flags + tchar *ptchMinidumpFileNameBuffer = NULL + ); + +PLATFORM_INTERFACE void MinidumpSetUnhandledExceptionFunction( FnMiniDump pfn ); + +#endif + +#endif // MINIDUMP_H diff --git a/external/vpc/public/tier0/p4performancecounters.h b/external/vpc/public/tier0/p4performancecounters.h new file mode 100644 index 0000000..d0882b9 --- /dev/null +++ b/external/vpc/public/tier0/p4performancecounters.h @@ -0,0 +1,322 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef P4PERFORMANCECOUNTERS_H +#define P4PERFORMANCECOUNTERS_H + +#pragma once +// Pentium 4 support + +/* + http://developer.intel.com/design/Pentium4/documentation.htm + + IA-32 Intel Architecture Software Developer's Manual Volume 1: Basic Architecture + + IA-32 Intel Architecture Software Developer's Manual Volume 2A: Instruction Set Reference, A-M + + IA-32 Intel Architecture Software Developer's Manual Volume 2B: Instruction Set Reference, N-Z + + IA-32 Intel Architecture Software Developer's Manual Volume 3: System Programming Guide + + + From Mikael Pettersson's perfctr: + + http://user.it.uu.se/~mikpe/linux/perfctr/ + + * Known quirks: + - OVF_PMI+FORCE_OVF counters must have an ireset value of -1. + This allows the regular overflow check to also handle FORCE_OVF + counters. Not having this restriction would lead to MAJOR + complications in the driver's "detect overflow counters" code. + There is no loss of functionality since the ireset value doesn't + affect the counter's PMI rate for FORCE_OVF counters. + + - In experiments with FORCE_OVF counters, and regular OVF_PMI + counters with small ireset values between -8 and -1, it appears + that the faulting instruction is subjected to a new PMI before + it can complete, ad infinitum. This occurs even though the driver + clears the CCCR (and in testing also the ESCR) and invokes a + user-space signal handler before restoring the CCCR and resuming + the instruction. +*/ + +#define NCOUNTERS 18 + +// The 18 counters +enum Counters +{ + MSR_BPU_COUNTER0, + MSR_BPU_COUNTER1, + MSR_BPU_COUNTER2, + MSR_BPU_COUNTER3, + MSR_MS_COUNTER0, + MSR_MS_COUNTER1, + MSR_MS_COUNTER2, + MSR_MS_COUNTER3, + MSR_FLAME_COUNTER0, + MSR_FLAME_COUNTER1, + MSR_FLAME_COUNTER2, + MSR_FLAME_COUNTER3, + MSR_IQ_COUNTER0, + MSR_IQ_COUNTER1, + MSR_IQ_COUNTER2, + MSR_IQ_COUNTER3, + MSR_IQ_COUNTER4, + MSR_IQ_COUNTER5 +}; + +// register base for counters +#define MSR_COUNTER_BASE 0x300 + +// register base for CCCR register +#define MSR_CCCR_BASE 0x360 + +#pragma pack(push, 1) +// access to these bits is through the methods +typedef union ESCR +{ + struct + { + uint64 Reserved0_1 : 2; // + uint64 USR : 1; // + uint64 OS : 1; // + uint64 TagEnable : 1; // + uint64 TagValue : 4; // + uint64 EventMask : 16; // from event select + uint64 ESCREventSelect : 6; // 31:25 class of event + uint64 Reserved31 : 1; // + + uint64 Reserved32_63 : 32; // + }; + uint64 flat; + +} ESCR; + +typedef union CCCR +{ + struct + { + uint64 Reserved0_11 : 12;// 0 -11 + uint64 Enable : 1; // 12 + uint64 CCCRSelect : 3; // 13-15 + uint64 Reserved16_17 : 2; // 16 17 + + uint64 Compare : 1; // 18 + uint64 Complement : 1; // 19 + uint64 Threshold : 4; // 20-23 + uint64 Edge : 1; // 24 + uint64 FORCE_OVF : 1; // 25 + uint64 OVF_PMI : 1; // 26 + uint64 Reserved27_29 : 3; // 27-29 + uint64 Cascade : 1; // 30 + uint64 OVF : 1; // 31 + + uint64 Reserved32_63 : 32; // + }; + uint64 flat; + +} CCCR; + +#pragma pack(pop) + +extern const unsigned short cccr_escr_map[NCOUNTERS][8]; + +enum P4TagState +{ + TagDisable, // + TagEnable, // +}; + +enum P4ForceOverflow +{ + ForceOverflowDisable, + ForceOverflowEnable, +}; + +enum P4OverflowInterrupt +{ + OverflowInterruptDisable, + OverflowInterruptEnable, +}; + +// Turn off the no return value warning in ReadCounter. +#pragma warning( disable : 4035 ) +class P4BaseEvent +{ + int m_counter; + +protected: + + void SetCounter(int counter) + { + m_counter = counter; + cccrPort = MSR_CCCR_BASE + m_counter; + counterPort = MSR_COUNTER_BASE + m_counter; + escrPort = cccr_escr_map[m_counter][cccr.CCCRSelect]; + } + +public: + + unsigned short m_eventMask; + const tchar *description; + PME *pme; + ESCR escr; + CCCR cccr; + int counterPort; + int cccrPort; + int escrPort; + + P4BaseEvent() + { + pme = PME::Instance(); + m_eventMask = 0; + description = _T(""); + escr.flat = 0; + cccr.flat = 0; + cccr.Reserved16_17 = 3; // must be set + escrPort = 0; + m_counter = -1; + } + + void StartCounter() + { + cccr.Enable = 1; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void StopCounter() + { + cccr.Enable = 0; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void ClearCounter() + { + pme->WriteMSR( counterPort, 0ui64 ); // clear + } + + void WriteCounter( int64 value ) + { + pme->WriteMSR( counterPort, value ); // clear + } + + int64 ReadCounter() + { +#if PME_DEBUG + if ( escr.USR == 0 && escr.OS == 0 ) + return -1; // no area to collect, use SetCaptureMode + + if ( escr.EventMask == 0 ) + return -2; // no event mask set + + if ( m_counter == -1 ) + return -3; // counter not legal +#endif + + // ReadMSR should work here too, but RDPMC should be faster + int64 value = 0; + pme->ReadMSR( counterPort, &value ); + return value; +#if 0 + // we need to copy this into a temp for some reason + int temp = m_counter; + _asm + { + mov ecx, temp + RDPMC + } +#endif + } + + void SetCaptureMode( PrivilegeCapture priv ) + { + switch ( priv ) + { + case OS_Only: + { + escr.USR = 0; + escr.OS = 1; + break; + } + case USR_Only: + { + escr.USR = 1; + escr.OS = 0; + break; + } + case OS_and_USR: + { + escr.USR = 1; + escr.OS = 1; + break; + } + } + + escr.EventMask = m_eventMask; + pme->WriteMSR( escrPort, escr.flat ); + } + + void SetTagging( P4TagState tagEnable, uint8 tagValue ) + { + escr.TagEnable = tagEnable; + escr.TagValue = tagValue; + pme->WriteMSR( escrPort, escr.flat ); + } + + void SetFiltering( CompareState compareEnable, CompareMethod compareMethod, uint8 threshold, EdgeState edgeEnable ) + { + cccr.Compare = compareEnable; + cccr.Complement = compareMethod; + cccr.Threshold = threshold; + cccr.Edge = edgeEnable; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void SetOverflowEnables( P4ForceOverflow overflowEnable, P4OverflowInterrupt overflowInterruptEnable ) + { + cccr.FORCE_OVF = overflowEnable; + cccr.OVF_PMI = overflowInterruptEnable; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void SetOverflow() + { + cccr.OVF = 1; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void ClearOverflow() + { + cccr.OVF = 0; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + bool isOverflow() + { + CCCR cccr_temp; + pme->ReadMSR( cccrPort, &cccr_temp.flat ); + return cccr_temp.OVF; + } + + void SetCascade() + { + cccr.Cascade = 1; + pme->WriteMSR( cccrPort, cccr.flat ); + } + + void ClearCascade() + { + cccr.Cascade = 0; + pme->WriteMSR( cccrPort, cccr.flat ); + } +}; +#pragma warning( default : 4035 ) + +#include "eventmasks.h" +#include "eventmodes.h" + +#endif // P4PERFORMANCECOUNTERS_H diff --git a/external/vpc/public/tier0/p5p6performancecounters.h b/external/vpc/public/tier0/p5p6performancecounters.h new file mode 100644 index 0000000..6e2d8b1 --- /dev/null +++ b/external/vpc/public/tier0/p5p6performancecounters.h @@ -0,0 +1,225 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#ifndef P5P6PERFORMANCECOUNTERS_H +#define P5P6PERFORMANCECOUNTERS_H + +// defined for < Pentium 4 + +//--------------------------------------------------------------------------- +// Format of the performance event IDs within this header file in case you +// wish to add any additional events that may not be present here. +// +// BITS 0-8 Unit Mask, Unsed on P5 processors +// BIT 9 Set if event can be set on counter 0 +// BIT 10 Set if event can be set on counter 1 +// BITS 11-15 Unused Set to zero +// BITS 16-23 Event Select ID, Only bits 16-21 used on P5 Family +// BITS 24-27 Unused set to zero +// BITS 28-32 Process family that the event belong to, as returned by +// the CPUID instruction. +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// PENTIUM PERFORMANCE COUNTERS. +//--------------------------------------------------------------------------- +#define P5_DTCRD 0x50000300 //Data Cache Reads +#define P5_DWRIT 0x50010300 //Data Cache Writes +#define P5_DTTLB 0x50020300 //Data TLB Miss +#define P5_DTRMS 0x50030300 //Data Read Misses +#define P5_DWRMS 0x50040300 //Data Write Miss +#define P5_WHLCL 0x50050300 //Write (Hit) to M- or E-state line +#define P5_DCLWB 0x50060300 //Data Cache Lines Written Back +#define P5_DCSNP 0x50070300 //External Snoops +#define P5_DCSHT 0x50080300 //Data Cache Snoop Hits +#define P5_MAIBP 0x50090300 //Memory Access in Both Pipes +#define P5_BANKS 0x500A0300 //Bank Conflicts +#define P5_MISAL 0x500B0300 //Misaligned Data Memory Reference +#define P5_COCRD 0x500C0300 //Code Cache Reads +#define P5_COTLB 0x500D0300 //Code TLB Misses +#define P5_COCMS 0x500E0300 //Code Cache Misses +#define P5_ANYSG 0x500F0300 //Any Segment Register Loaded +#define P5_BRANC 0x50120300 //Branches +#define P5_BTBHT 0x50130300 //BTB Hits +#define P5_TBRAN 0x50140300 //Taken Branch or BTB hit +#define P5_PFLSH 0x50150300 //Pipeline flushes +#define P5_INSTR 0x50160300 //Instructions Executed +#define P5_INSTV 0x50170300 //Instructions Executed in the V-Pipe (Pairing) +#define P5_CLOCL 0x50180300 //Bus active +#define P5_PSDWR 0x50190300 //Full write buffers +#define P5_PSWDR 0x501A0300 //Waiting for Data Memory Read +#define P5_NCLSW 0x501B0300 //Clocks stalled writing an E or M state line +#define P5_IORWC 0x501D0300 //I/O Read or Write Cycle +#define P5_NOCMR 0x501E0300 //Non-Cacheable Memory Reads +#define P5_PSLDA 0x501F0300 //Clocks stalled due to AGI +#define P5_FLOPS 0x50220300 //Floating Point Operations +#define P5_DBGR0 0x50230300 //Breakpoint match on DR0 +#define P5_DBGR1 0x50240300 //Breakpoint match on DR1 +#define P5_DBGR2 0x50250300 //Breakpoint match on DR2 +#define P5_DBGR3 0x50260300 //Breakpoint match on DR3 +#define P5_HWINT 0x50270300 //Hardware interrupts +#define P5_DTRWR 0x50280300 //Data reads or writes +#define P5_DTRWM 0x50290300 //Data read or write miss +#define P5_BOLAT 0x502A0100 //Bus ownership latency +#define P5_BOTFR 0x502A0200 //Bus ownership transfer +#define P5_MMXA1 0x502B0100 //MMX Instruction Executed in U-pipe +#define P5_MMXA2 0x502B0200 //MMX Instruction Executed in V-pipe +#define P5_MMXMS 0x502C0100 //Cache M state line sharing +#define P5_MMSLS 0x502C0200 //Cache line sharing +#define P5_MMXB1 0x502D0100 //EMMS Instructions Executed +#define P5_MMXB2 0x502D0200 //Transition from MMX to FP instructions +#define P5_NOCMW 0x502E0200 //Non-Cacheable Memory Writes +#define P5_MMXC1 0x502F0100 //Saturated MMX Instructions Executed +#define P5_MMXC2 0x502F0200 //Saturations Performed +#define P5_MMXHS 0x50300100 //Cycles Not in HALT State +#define P5_MMXD2 0x50310100 //MMX Data Read +#define P5_MMXFP 0x50320100 //Floating Point Stalls +#define P5_MMXTB 0x50320200 //Taken Branches +#define P5_MMXD0 0x50330100 //D1 Starvation and FIFO Empty +#define P5_MMXD1 0x50330200 //D1 Starvation and one instruction in FIFO +#define P5_MMXE1 0x50340100 //MMX Data Writes +#define P5_MMXE2 0x50340200 //MMX Data Write Misses +#define P5_MMXWB 0x50350100 //Pipeline flushes, wrong branch prediction +#define P5_MMXWJ 0x50350200 //Pipeline flushes, branch prediction WB-stage +#define P5_MMXF1 0x50360100 //Misaligned MMX Data Memory Reference +#define P5_MMXF2 0x50360200 //Pipeline Stalled Waiting for MMX data read +#define P5_MMXRI 0x50370100 //Returns Predicted Incorrectly +#define P5_MMXRP 0x50370200 //Returns Predicted +#define P5_MMXG1 0x50380100 //MMX Multiply Unit Interlock +#define P5_MMXG2 0x50380200 //MOVD/MOVQ store stall, previous operation +#define P5_MMXRT 0x50390100 //Returns +#define P5_MMXRO 0x50390200 //RSB Overflows +#define P5_MMXBF 0x503A0100 //BTB False entries +#define P5_MMXBM 0x503A0200 //BTB misprediction on a Not-Taken Branch +#define P5_PXDWR 0x503B0100 //stalled due MMX Full write buffers +#define P5_PXZWR 0x503B0200 //stalled on MMX write to E or M state line + +#define P5_CLOCK 0x503F0300 //Special value to count clocks on P5 + + +//--------------------------------------------------------------------------- +// PENTIUM PRO / PENTIUM II PERFORMANCE COUNTERS. +//--------------------------------------------------------------------------- +#define P6_STRBB 0x60030300 //Store Buffer Block +#define P6_STBDC 0x60040300 //Store Buffer Drain Cycles +#define P6_MISMM 0x60050300 //Misaligned Data Memory Reference +#define P6_SEGLD 0x60060300 //Segment register loads +#define P6_FPOPE 0x60100100 //FP Computational Op. (COUNTER 0 ONLY) +#define P6_FPEOA 0x60110200 //FP Microcode Exceptions (COUNTER 1 ONLY) +#define P6_FMULT 0x60120200 //Multiplies (COUNTER 1 ONLY) +#define P6_FPDIV 0x60130200 //Divides (COUNTER 1 ONLY) +#define P6_DBUSY 0x60140200 //Cycles Divider Busy (COUNTER 1 ONLY) +#define P6_L2STR 0x60210300 //L2 address strobes => address bus utilization +#define P6_L2BBS 0x60220300 //Cycles L2 Bus Busy +#define P6_L2BBT 0x60230300 //Cycles L2 Bus Busy transferring data to CPU +#define P6_L2ALO 0x60240300 //L2 Lines Allocated +#define P6_L2MAL 0x60250300 //L2 M-state Lines Allocated +#define P6_L2CEV 0x60260300 //L2 Lines Evicted +#define P6_L2MEV 0x60270300 //L2 M-state Lines Evicted +#define P6_L2MCF 0x60280301 //L2 Cache Instruction Fetch Misses +#define P6_L2FET 0x6028030F //L2 Cache Instruction Fetches +#define P6_L2DRM 0x60290301 //L2 Cache Read Misses +#define P6_L2DMR 0x6029030F //L2 Cache Reads +#define P6_L2DWM 0x602A0301 //L2 Cache Write Misses +#define P6_L2DMW 0x602A030F //L2 Cache Writes +#define P6_L2CMS 0x602E0301 //L2 Cache Request Misses +#define P6_L2DCR 0x602E030F //L2 Cache Requests +#define P6_DMREF 0x60430300 //Data Memory References +#define P6_DCALO 0x6045030F //L1 Lines Allocated +#define P6_DCMAL 0x60460300 //L1 M-state Data Cache Lines Allocated +#define P6_DCMEV 0x60470300 //L1 M-state Data Cache Lines Evicted +#define P6_DCOUT 0x60480300 //L1 Misses outstanding +#define P6_TSMCD 0x60520300 //Time Self-Modifiying Code Detected +#define P6_BRWRA 0x60600300 //External Bus Cycles While Receive Active +#define P6_BRDCD 0x60600300 //External Bus Request Outstanding +#define P6_BRBNR 0x60610300 //External Bus Cycles While BNR Asserted +#define P6_BUSBS 0x60620300 //External Bus Cycles-DRDY Asserted (busy) +#define P6_BLOCK 0x60630300 //External Bus Cycles-LOCK signal asserted +#define P6_BBRCV 0x60640300 //External Bus Cycles-Processor receiving data +#define P6_BURST 0x60650300 //External Bus Burst Read Operations +#define P6_BRINV 0x60660300 //External Bus Read for Ownership Transaction +#define P6_BMLEV 0x60670300 //External Bus Writeback M-state Evicted +#define P6_BBIFT 0x60680300 //External Bus Burst Instruction Fetches +#define P6_BINVL 0x60690300 //External Bus Invalidate Transactions +#define P6_BPRBT 0x606A0300 //External Bus Partial Read Transactions +#define P6_BPTMO 0x606B0300 //External Bus Partial Memory Transactions +#define P6_BUSIO 0x606C0300 //External Bus I/O Bus Transactions +#define P6_BUSDF 0x606D0300 //External Bus Deferred Transactions +#define P6_BUSTB 0x606E0300 //External Bus Burst Transactions +#define P6_BMALL 0x606F0300 //External Bus Memory Transactions +#define P6_BSALL 0x60700300 //External Bus Transactions +#define P6_CLOCK 0x60790300 //Clockticks +#define P6_BRHIT 0x607A0300 //External Bus Cycles While HIT Asserted +#define P6_BRHTM 0x607B0300 //External Bus Cycles While HITM Asserted +#define P6_BRSST 0x607E0300 //External Bus Cycles While Snoop Stalled +#define P6_CMREF 0x60800300 //Total Instruction Fetches +#define P6_TOIFM 0x60810300 //Total Instruction Fetch Misses +#define P6_INTLB 0x60850300 //Instructions TLB Misses +#define P6_CSFET 0x60860300 //Cycles Instruction Fetch Stalled +#define P6_FTSTL 0x60870300 //Cycles Instruction Fetch stalled +#define P6_RSTAL 0x60A20300 //Resource Related Stalls +#define P6_MMXIE 0x60B00300 //MMX Instructions Executed +#define P6_SAISE 0x60B10300 //Saturated Arithmetic Instructions Executed +#define P6_PORT0 0x60B20301 //MMX micro-ops executed on Port 0 +#define P6_PORT1 0x60B20302 //MMX micro-ops executed on Port 1 +#define P6_PORT2 0x60B20304 //MMX micro-ops executed on Port 2 +#define P6_PORT3 0x60B20308 //MMX micro-ops executed on Port 3 +#define P6_MMXPA 0x60B30300 //MMX Packed Arithmetic +#define P6_MMXPM 0x60B30301 //MMX Packed Multiply +#define P6_MMXPS 0x60B30302 //MMX Packed Shift +#define P6_MMXPO 0x60B30304 //MMX Packed Operations +#define P6_MMXUO 0x60B30308 //MMX Unpacked Operations +#define P6_MMXPL 0x60B30310 //MMX Packed Logical +#define P6_INSTR 0x60C00300 //Instructions Retired +#define P6_FPOPS 0x60C10100 //FP operations retired (COUNTER 0 ONLY) +#define P6_UOPSR 0x60C20300 //Micro-Ops Retired +#define P6_BRRET 0x60C40300 //Branch Instructions Retired +#define P6_BRMSR 0x60C50300 //Branch Mispredictions Retired +#define P6_MASKD 0x60C60300 //Clocks while interrupts masked +#define P6_MSKPN 0x60C70300 //Clocks while interrupt is pending +#define P6_HWINT 0x60C80300 //Hardware Interrupts Received +#define P6_BTAKR 0x60C90300 //Taken Branch Retired +#define P6_BTAKM 0x60CA0300 //Taken Branch Mispredictions +#define P6_FPMMX 0x60CC0301 //Transitions from Floating Point to MMX +#define P6_MMXFP 0x60CC0300 //Transitions from MMX to Floating Point +#define P6_SIMDA 0x60CD0300 //SIMD Assists (EMMS Instructions Executed) +#define P6_MMXIR 0x60CE0300 //MMX Instructions Retired +#define P6_SAISR 0x60CF0300 //Saturated Arithmetic Instructions Retired +#define P6_INSTD 0x60D00300 //Instructions Decoded +#define P6_NPRTL 0x60D20300 //Renaming Stalls +#define P6_SRSES 0x60D40301 //Segment Rename Stalls - ES +#define P6_SRSDS 0x60D40302 //Segment Rename Stalls - DS +#define P6_SRSFS 0x60D40304 //Segment Rename Stalls - FS +#define P6_SRSGS 0x60D40308 //Segment Rename Stalls - GS +#define P6_SRSXS 0x60D4030F //Segment Rename Stalls - ES DS FS GS +#define P6_SRNES 0x60D50301 //Segment Renames - ES +#define P6_SRNDS 0x60D50302 //Segment Renames - DS +#define P6_SRNFS 0x60D50304 //Segment Renames - FS +#define P6_SRNGS 0x60D50308 //Segment Renames - GS +#define P6_SRNXS 0x60D5030F //Segment Renames - ES DS FS GS +#define P6_BRDEC 0x60E00300 //Branch Instructions Decoded +#define P6_BTBMS 0x60E20301 //BTB Misses +#define P6_RETDC 0x60E40300 //Bogus Branches +#define P6_BACLR 0x60E60300 //BACLEARS Asserted (Testing) + + + + + + +// INTEL +#define PENTIUM_FAMILY 5 // define for pentium +#define PENTIUMPRO_FAMILY 6 // define for pentium pro +#define PENTIUM4_FAMILY 15 // define for pentium 4 + + +// AMD +#define K6_FAMILY 5 +#define K8_FAMILY 6 +#define EXTENDED_FAMILY 15 // AMD 64 and AMD Opteron + +#endif // P5P6PERFORMANCECOUNTERS_H diff --git a/external/vpc/public/tier0/platform.h b/external/vpc/public/tier0/platform.h new file mode 100644 index 0000000..4dad5df --- /dev/null +++ b/external/vpc/public/tier0/platform.h @@ -0,0 +1,2032 @@ +//===== Copyright 1997-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef PLATFORM_H +#define PLATFORM_H + + +#ifdef SN_TARGET_PS3 + +#define _PS3 1 +#define COMPILER_PS3 1 +#define PLATFORM_PS3 1 + +// There are 2 compilers for the PS3: GCC and the SN Systems compiler. +// They are mostly similar, but in a few places we need to distinguish between the two. +#if defined( __SNC__ ) +#define COMPILER_SNC 1 +#elif defined( __GCC__ ) +#define COMPILER_GCC 1 +#else +#error "Unrecognized PS3 compiler; either __SNC__ or __GCC__ must be defined" +#endif + +#endif // SN_TARGET_PS3 + +#ifdef __GCC__ +#define COMPILER_GCC 1 +#endif + +#if defined( _X360 ) || defined( _PS3 ) +#define PLATFORM_PPC 1 +#endif + + +#ifdef COMPILER_MSVC +#pragma once +#endif + +#if defined (_PS3) + #include <ppu_intrinsics.h> + + // We want to force the assert to be redefined, because the STD assert might have been + // included and redefined. ps3_assert.h will do a check for assert being redefined. + // #include "ps3/ps3_assert.h" + #ifndef COMPILER_PS3 + #error "for PS3, VPC must define COMPILER_PS3 macro just like it does for COMPILER_MSVCX360 macro" + #endif + #if !defined( COMPILER_SNC ) && !defined( COMPILER_GCC ) + #error "for PS3, VPC must define COMPILER_SNC or COMPILER_GCC macro, depending on the target compiler, just like it does for COMPILER_MSVCX360 macro" + #endif + +#elif defined( _X360 ) + #define NO_STEAM + #define NO_VOICE + // for the 360, the ppc platform and the rtos are tightly coupled + // setup the 360 environment here !once! for much less leaf module include wackiness + // these are critical order and purposely appear *before* anything else + #define _XBOX + #include <xaudio2.h> + #include <xbdm.h> + #include <xgraphics.h> + #include <xui.h> + #include <pmcpbsetup.h> + #include <xmahardwareabstraction.h> + #undef _XBOX + +#endif + +#include "wchartypes.h" +#include "tier0/valve_off.h" + +#ifdef _PS3 + + #include "ps3/ps3_platform.h" + + #define NO_STEAM_GAMECOORDINATOR + +#else + + #include <malloc.h> + #include <memory.h> + #include <limits.h> + #include <float.h> + #include <stdlib.h> + #include <string.h> +#ifdef OSX + #include <signal.h> +#endif + +#endif + +// This macro +#if defined( _PS3 ) && defined ( COMPILER_SNC ) + +// There are known bugs in the PS3 optimizer. The following macros allow us to lower optimization for a subset of a file +// If you run into build problems with optimization on, try turning off optimization for the selected file. If that +// fixes the problem, use process of elimination and the below macros to find the bare minimum that needs to be +// unoptimized and report the compiler issue to Sony as well. +// +// The correlation between optimization levels and numbers passed to the _Pragma xopt and postopt calls is as follows: +// See: Control-group reference tables / -Xshow +// .... xopt +// -O1 0 +// -O2 5 +// -O3 5 +// +// These macros MUST be used in pairs - Otherwise, the compiler will barf 'At end of source: error 67: expected a "}"' + +// xopt disables some of the miscellaneous optimizations +#if __option(xopt) +#define SN_OPT_DISABLE extern "C++" { _Pragma("control %push xopt=0") +#define SN_OPT_ENABLE _Pragma("control %pop xopt") } +#else // !__option(xopt) +#define SN_OPT_DISABLE +#define SN_OPT_ENABLE +#endif // !__option(xopt) + +// postopt disables the main optimizer +#if __option(postopt) > 0 +#define SN_MAIN_OPT_DISABLE extern "C++" { _Pragma("control %push postopt=0") +#define SN_MAIN_OPT_ENABLE _Pragma("control %pop postopt") } +#else // !__option(postopt) > 0 +#define SN_MAIN_OPT_DISABLE +#define SN_MAIN_OPT_ENABLE +#endif // !__option(postopt) > 0 + +#else // ! ( _PS3 && COMPILER_SNC ) +#define SN_OPT_DISABLE +#define SN_OPT_ENABLE +#define SN_MAIN_OPT_DISABLE +#define SN_MAIN_OPT_ENABLE +#endif // ! ( _PS3 && COMPILER_SNC ) + +#ifdef __cplusplus +#if defined( COMPILER_GCC ) || defined( COMPILER_PS3 ) + #include <new> +#else + #include <new.h> +#endif +#endif + +//----------------------------------------------------------------------------- +// Old-school defines we don't want to use moving forward +//----------------------------------------------------------------------------- +#if CROSS_PLATFORM_VERSION < 1 + +// feature enables +#define NEW_SOFTWARE_LIGHTING +#if !defined( _X360 ) +#define SUPPORT_PACKED_STORE +#endif + +#if defined( BINK_VIDEO ) && ( defined( _X360 ) || defined( _PS3 ) ) +#define BINK_ENABLED_FOR_CONSOLE +#endif + +#if !defined( PORTAL2 ) +//#define PORTAL2 +#endif + +// C functions for external declarations that call the appropriate C++ methods +#ifndef EXPORT + #ifdef _WIN32 + #define EXPORT _declspec( dllexport ) + #else + #define EXPORT /* */ + #endif +#endif + +#endif // CROSS_PLATFORM_VERSION < 1 + +#if defined(_STATIC_LINKED) +#include "staticlink/system.h" +#endif + +//----------------------------------------------------------------------------- +// NOTE: All compiler defines are set up in the base VPC scripts +// COMPILER_MSVC, COMPILER_MSVC32, COMPILER_MSVC64, COMPILER_MSVCX360 +// COMPILER_GCC +// The rationale for this is that we need COMPILER_MSVC for the pragma blocks +// #pragma once that occur at the top of all header files, therefore we can't +// place the defines for these in here. +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Set up platform defines. +//----------------------------------------------------------------------------- +#ifdef _WIN32 + #define IsPlatformLinux() 0 + #define IsPlatformPosix() 0 + #define IsPlatformOSX() 0 + #define IsOSXOpenGL() 0 + #define IsPlatformPS3() 0 + #define IsPlatformPS3_PPU() 0 + #define IsPlatformPS3_SPU() 0 + #define PLATFORM_WINDOWS 1 + #define PLATFORM_OPENGL 0 + + #ifndef _X360 + #define IsPlatformX360() 0 + #define IsPlatformWindowsPC() 1 + #define PLATFORM_WINDOWS_PC 1 + + #ifdef _WIN64 + #define IsPlatformWindowsPC64() 1 + #define IsPlatformWindowsPC32() 0 + #define PLATFORM_WINDOWS_PC64 1 + #else + #define IsPlatformWindowsPC64() 0 + #define IsPlatformWindowsPC32() 1 + #define PLATFORM_WINDOWS_PC32 1 + #endif + + #else // _X360 + + #define IsPlatformWindowsPC() 0 + #define IsPlatformWindowsPC64() 0 + #define IsPlatformWindowsPC32() 0 + #define IsPlatformX360() 1 + #define PLATFORM_X360 1 + + #endif // _X360 +#elif defined(_PS3) + + +#define IsPlatformX360() 0 +#define IsPlatformPS3() 1 +#ifdef SPU +#define IsPlatformPS3_PPU() 0 +#define IsPlatformPS3_SPU() 1 +#else +#define IsPlatformPS3_PPU() 1 +#define IsPlatformPS3_SPU() 0 +#endif +#define IsPlatformWindowsPC() 0 +#define IsPlatformWindowsPC64() 0 +#define IsPlatformWindowsPC32() 0 +#define IsPlatformPosix() 1 +#define PLATFORM_POSIX 1 +#define PLATFORM_OPENGL 0 + +#define IsPlatformLinux() 0 +#define IsPlatformOSX() 0 +#define IsOSXOpenGL() 0 + + +#elif defined(POSIX) + #define IsPlatformX360() 0 + #define IsPlatformPS3() 0 + #define IsPlatformPS3_PPU() 0 + #define IsPlatformPS3_SPU() 0 + #define IsPlatformWindowsPC() 0 + #define IsPlatformWindowsPC64() 0 + #define IsPlatformWindowsPC32() 0 + #define IsPlatformPosix() 1 + #define PLATFORM_POSIX 1 + + #if defined( LINUX ) && !defined( OSX ) // for havok we define both symbols, so don't let the osx build wander down here + #define IsPlatformLinux() 1 + #define IsPlatformOSX() 0 + #define IsOSXOpenGL() 0 + #define PLATFORM_OPENGL 0 + #define PLATFORM_LINUX 1 + #elif defined ( OSX ) + #define IsPlatformLinux() 0 + #define IsPlatformOSX() 1 + #define IsOSXOpenGL() 1 + #define PLATFORM_OSX 1 + #define PLATFORM_OPENGL 1 + #else + #define IsPlatformLinux() 0 + #define IsPlatformOSX() 0 + #define IsOSXOpenGL() 0 + #define PLATFORM_OPENGL 0 + #endif + +#else + #error +#endif + +// IsXXXX platform pseudo-functions +#if ( defined( PLATFORM_WINDOWS ) && ( PLATFORM_WINDOWS ) ) +#define IsPlatformWindows() 1 +#else +#define IsPlatformWindows() 0 +#endif + +#if ( defined( PLATFORM_OPENGL ) && PLATFORM_OPENGL ) +#define IsOpenGL() 1 +#else +#define IsOpenGL() 0 +#endif + + + +#ifndef _PS3 +//#include <malloc.h> +//#include <new.h> +#else +#include <stdlib.h> // For malloc() +#include <alloca.h> // for alloca() +#define _alloca alloca + #ifdef __cplusplus + #include <new> + #endif +#endif + + +//----------------------------------------------------------------------------- +// Old-school defines we're going to support since much code uses them +//----------------------------------------------------------------------------- +#if CROSS_PLATFORM_VERSION < 2 + +#define IsLinux() IsPlatformLinux() +#define IsOSX() IsPlatformOSX() +#define IsPosix() IsPlatformPosix() +#define IsX360() IsPlatformX360() +#define IsPS3() IsPlatformPS3() + +// Setup platform defines. +#ifdef COMPILER_MSVC +#define MSVC 1 +#endif + +#ifdef COMPILER_GCC +#define GNUC 1 +#endif + +#if defined( _WIN32 ) +#define _WINDOWS 1 +#endif + +#ifdef PLATFORM_WINDOWS_PC +#define IS_WINDOWS_PC 1 +#endif + +#endif // CROSS_PLATFORM_VERSION < 2 + +// VXConsole is enabled for... +#if defined(_X360) || defined(_PS3) +#define USE_VXCONSOLE 1 +#define HasVxConsole() 1 +#else +#define HasVxConsole() 0 +#endif + +//----------------------------------------------------------------------------- +// Set up platform type defines. +//----------------------------------------------------------------------------- +#if defined( PLATFORM_X360 ) || defined( _PS3 ) + #ifndef _GAMECONSOLE + #define _GAMECONSOLE + #endif + #define IsPC() 0 + #define IsGameConsole() 1 +#else + #define IsPC() 1 + #define IsGameConsole() 0 +#endif + + + +//----------------------------------------------------------------------------- +// Set up build configuration defines. +//----------------------------------------------------------------------------- +#ifdef _CERT +#define IsCert() 1 +#else +#define IsCert() 0 +#endif + +#ifdef _DEBUG +#define IsRelease() 0 +#define IsDebug() 1 +#else +#define IsRelease() 1 +#define IsDebug() 0 +#endif + +#ifdef _RETAIL +#define IsRetail() 1 +#else +#define IsRetail() 0 +#endif + + +//----------------------------------------------------------------------------- +// Portable data types +//----------------------------------------------------------------------------- +typedef unsigned char uint8; +typedef signed char int8; + +#if defined( COMPILER_MSVC ) + + typedef __int16 int16; + typedef unsigned __int16 uint16; + typedef __int32 int32; + typedef unsigned __int32 uint32; + typedef __int64 int64; + typedef unsigned __int64 uint64; + + // intp is an integer that can accomodate a pointer + // (ie, sizeof(intp) >= sizeof(int) && sizeof(intp) >= sizeof(void *) + typedef intptr_t intp; + typedef uintptr_t uintp; + + #if defined( COMPILER_MSVCX360 ) + #ifdef __m128 + #undef __m128 + #endif + #define __m128 __vector4 + #endif + +#else // !COMPILER_MSVC + + typedef short int16; + typedef unsigned short uint16; + typedef int int32; + typedef unsigned int uint32; + typedef long long int64; + typedef unsigned long long uint64; + #ifdef PLATFORM_64BITS + typedef long long intp; + typedef unsigned long long uintp; + #else + typedef int intp; + typedef unsigned int uintp; + #endif + typedef void *HWND; +#endif // else COMPILER_MSVC + +#if defined(_PS3) && !defined(NO_SIMD) +typedef union __attribute__ ((aligned (16))) +{ + float m128_f32[4]; +} l_m128; + +typedef __vector float __vector4; +typedef __vector4 __m128; + +const __m128 VMX_ZERO=(vector float)(0.0f); +const __m128 VMX_ONE_HALF=(vector float)(0.5f); +const __m128 VMX_ONE=(vector float)(1.0f); + +// Syntaxic sugar for multiply +inline __attribute__ ((always_inline)) __m128 __vec_mul(const __m128 a, const __m128 b) +{ + return vec_madd(a,b,VMX_ZERO); +} + +// Refined reciprocal function +inline __attribute__ ((always_inline)) __m128 __vec_rec(const __m128 a) +{ + //Get the reciprocal estimate + vector float estimate = vec_re( a ); + + //One round of Newton-Raphson refinement + return vec_madd( vec_nmsub( estimate, a, VMX_ONE ), estimate, estimate ); +} + +// refined reciprocal square root +inline __attribute__ ((always_inline)) __m128 __vec_rsqrt(const __m128 a) +{ + //Get the square root reciprocal estimate + __m128 estimate = vec_rsqrte( a ); + + //One round of Newton-Raphson refinement + __m128 estimateSquared = __vec_mul( estimate, estimate); + __m128 halfEstimate = __vec_mul( estimate, VMX_ONE_HALF); + return vec_madd( vec_nmsub( a, estimateSquared, VMX_ONE ), halfEstimate, estimate ); +} + +// refined square root +inline __attribute__ ((always_inline)) __m128 __vec_sqrt(const __m128 a) +{ + return __vec_mul( a, __vec_rsqrt( a )); +} + +// estimate square root +inline __attribute__ ((always_inline)) __m128 __vec_sqrtest(const __m128 a) +{ + return __vec_mul( a, vec_rsqrte( a )); +} + +// Syntaxic sugar for multiply +inline __attribute__ ((always_inline)) __m128 __vec_div(const __m128 a, const __m128 b) +{ + return __vec_mul( a, __vec_rec( b )); +} + +// load an unaligned array of float in a vector of floats +inline __attribute__ ((always_inline)) __m128 __vec_ld_unaligned(const float* in) +{ + return vec_perm(vec_ld(0,in), + vec_ld(sizeof(__m128),in), + vec_lvsl( 0, in )); +} + +// load an unaligned array of 3 floats in a vector of floats, last member being 0. +inline __attribute__ ((always_inline)) __m128 __vec_ld_unaligned3(const float* in) +{ + return vec_and(__vec_ld_unaligned(in),(__m128)(vector unsigned int)(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF ,0)); +} + +// stores a vector of floats in an unaligned array of float +inline __attribute__ ((always_inline)) void __vec_st_unaligned(__m128 in, float* out) +{ + __m128 temp0 = vec_ld(0,out); + __m128 temp1 = vec_ld(16,out); + vector unsigned char align = vec_lvsr(0,out); + vector unsigned char mask = vec_perm ((vector unsigned char)(0), (vector unsigned char)(0xFF), align); + + in = vec_perm ( in, in, align); + temp0 = vec_sel ( temp0, in, (vector bool)mask); + temp1 = vec_sel ( in, temp1, (vector bool)mask); + vec_st ( temp0, 0, out); + vec_st ( temp1, 16, out); +} + +// stores x,y,z from a vector of floats in an unaligned array of 3 floats +inline __attribute__ ((always_inline)) void __vec_st_unaligned3(__m128 in, float* out) +{ + __m128 temp0 = vec_ld(0,out); + __m128 temp1 = vec_ld(16,out); + vector unsigned char align = vec_lvsr(0,out); + vector unsigned char mask = vec_perm ((vector unsigned char)(0), + (vector unsigned char)(0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0,0,0), + align); + + in = vec_perm ( in, in, align); + temp0 = vec_sel ( temp0, in, (vector bool)mask); + temp1 = vec_sel ( in, temp1, (vector bool)mask); + vec_st ( temp0, 0, out); + vec_st ( temp1, 16, out); +} + +#endif // defined(NO_SIMD) + + +typedef float float32; +typedef double float64; + +// for when we don't care about how many bits we use +typedef unsigned int uint; + +#ifdef PLATFORM_POSIX +#ifndef _PS3 +typedef unsigned int DWORD; +typedef unsigned int *LPDWORD; +#endif +typedef unsigned short WORD; +typedef void * HINSTANCE; +#define _MAX_PATH PATH_MAX +#endif + +// MSVC CRT uses 0x7fff while gcc uses MAX_INT, leading to mismatches between platforms +// As a result, we pick the least common denominator here. This should be used anywhere +// you might typically want to use RAND_MAX +#define VALVE_RAND_MAX 0x7fff +// Maximum and minimum representable values +#ifndef PLATFORM_OSX + +#define INT8_MAX SCHAR_MAX +#define INT16_MAX SHRT_MAX +#define INT32_MAX LONG_MAX +#define INT64_MAX (((int64)~0) >> 1) + +#define INT8_MIN SCHAR_MIN +#define INT16_MIN SHRT_MIN +#define INT32_MIN LONG_MIN +#define INT64_MIN (((int64)1) << 63) + +#define UINT8_MAX ((uint8)~0) +#define UINT16_MAX ((uint16)~0) +#define UINT32_MAX ((uint32)~0) +#define UINT64_MAX ((uint64)~0) + +#define UINT8_MIN 0 +#define UINT16_MIN 0 +#define UINT32_MIN 0 +#define UINT64_MIN 0 + +#endif // PLATFORM_OSX + +#ifndef UINT_MIN +#define UINT_MIN UINT32_MIN +#endif + +#define FLOAT32_MAX FLT_MAX +#define FLOAT64_MAX DBL_MAX + +#ifdef GNUC +#undef offsetof +// Note: can't use builtin offsetof because many use cases (esp. in templates) wouldn't compile due to restrictions on the builtin offsetof +//#define offsetof( type, var ) __builtin_offsetof( type, var ) +#define offsetof(s,m) ( (size_t)&(((s *)0x1000000)->m) - 0x1000000u ) +#else +#include <stddef.h> +#undef offsetof +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + + +#define FLOAT32_MIN FLT_MIN +#define FLOAT64_MIN DBL_MIN + +//----------------------------------------------------------------------------- +// Long is evil because it's treated differently by different compilers +// Preventing its use is nasty however. This #define, which should be +// turned on in individual VPC files, causes you to include tier0/valve_off.h +// before standard C + windows headers, and include tier0/valve_on.h after +// standard C + windows headers. So, there's some painful overhead to disabling long +//----------------------------------------------------------------------------- +#ifdef DISALLOW_USE_OF_LONG + #define long long_is_the_devil_stop_using_it_use_int32_or_int64 +#endif + + +//----------------------------------------------------------------------------- +// Various compiler-specific keywords +//----------------------------------------------------------------------------- +#ifdef COMPILER_MSVC + + #ifdef FORCEINLINE + #undef FORCEINLINE + #endif + #define STDCALL __stdcall + #ifndef FASTCALL + #define FASTCALL __fastcall + #endif + #define FORCEINLINE __forceinline + #define FORCEINLINE_TEMPLATE __forceinline + #define NULLTERMINATED __nullterminated + + // This can be used to ensure the size of pointers to members when declaring + // a pointer type for a class that has only been forward declared + #define SINGLE_INHERITANCE __single_inheritance + #define MULTIPLE_INHERITANCE __multiple_inheritance + #define EXPLICIT explicit + #define NO_VTABLE __declspec( novtable ) + + // gcc doesn't allow storage specifiers on explicit template instatiation, but visual studio needs them to avoid link errors. + #define TEMPLATE_STATIC static + + // Used for dll exporting and importing + #define DLL_EXPORT extern "C" __declspec( dllexport ) + #define DLL_IMPORT extern "C" __declspec( dllimport ) + + // Can't use extern "C" when DLL exporting a class + #define DLL_CLASS_EXPORT __declspec( dllexport ) + #define DLL_CLASS_IMPORT __declspec( dllimport ) + + // Can't use extern "C" when DLL exporting a global + #define DLL_GLOBAL_EXPORT extern __declspec( dllexport ) + #define DLL_GLOBAL_IMPORT extern __declspec( dllimport ) + + // Pass hints to the compiler to prevent it from generating unnessecary / stupid code + // in certain situations. Several compilers other than MSVC also have an equivilent + // construct. + // + // Essentially the 'Hint' is that the condition specified is assumed to be true at + // that point in the compilation. If '0' is passed, then the compiler assumes that + // any subsequent code in the same 'basic block' is unreachable, and thus usually + // removed. + #define HINT(THE_HINT) __assume((THE_HINT)) + + // decls for aligning data + #define DECL_ALIGN(x) __declspec( align( x ) ) + + // GCC had a few areas where it didn't construct objects in the same order + // that Windows does. So when CVProfile::CVProfile() would access g_pMemAlloc, + // it would crash because the allocator wasn't initalized yet. + #define CONSTRUCT_EARLY + + #define SELECTANY __declspec(selectany) + + #define RESTRICT __restrict + #define RESTRICT_FUNC __declspec(restrict) + #define FMTFUNCTION( a, b ) + #define NOINLINE + +#if !defined( NO_THREAD_LOCAL ) + #define DECL_THREAD_LOCAL __declspec(thread) +#endif + + #define DISABLE_VC_WARNING( x ) __pragma(warning(disable:4310) ) + #define DEFAULT_VC_WARNING( x ) __pragma(warning(default:4310) ) + + +#elif defined ( COMPILER_GCC ) || defined( COMPILER_SNC ) + + #if defined( COMPILER_SNC ) + #define STDCALL + #define __stdcall + #elif (CROSS_PLATFORM_VERSION >= 1) && !defined( PLATFORM_64BITS ) && !defined( COMPILER_PS3 ) + #define STDCALL __attribute__ ((__stdcall__)) + #else + #define STDCALL + #define __stdcall __attribute__ ((__stdcall__)) + #endif + + #define FASTCALL + #ifdef _LINUX_DEBUGGABLE + #define FORCEINLINE + #else + #ifdef _PS3 + // [IESTYN 7/29/2010] As of SDK 3.4.0, this causes bad code generation in NET_Tick::ReadFromBuffer in netmessages.cpp, + // which caused (seeming) random network packet corruption. It probably causes other bugs too. + #define FORCEINLINE inline /* __attribute__ ((always_inline)) */ + #else + #define FORCEINLINE inline __attribute__ ((always_inline)) + #endif + #endif + + // GCC 3.4.1 has a bug in supporting forced inline of templated functions + // this macro lets us not force inlining in that case + #define FORCEINLINE_TEMPLATE inline + #define SINGLE_INHERITANCE + #define MULTIPLE_INHERITANCE + #define EXPLICIT + #define NO_VTABLE + + #define NULLTERMINATED + +#if defined( COMPILER_SNC ) + #define TEMPLATE_STATIC static +#else + #define TEMPLATE_STATIC +#endif + + // Used for dll exporting and importing + #ifdef COMPILER_SNC + #define DLL_DECLARATION_DEFAULT_VISIBILITY + #else + #define DLL_DECLARATION_DEFAULT_VISIBILITY __attribute__ ((visibility("default"))) + #endif + #define DLL_EXPORT extern "C" DLL_DECLARATION_DEFAULT_VISIBILITY + #define DLL_IMPORT extern "C" + + // Can't use extern "C" when DLL exporting a class +#ifndef _PS3 + #define __stdcall __attribute__ ((__stdcall__)) +#endif + #define DLL_CLASS_EXPORT DLL_DECLARATION_DEFAULT_VISIBILITY + #define DLL_CLASS_IMPORT + + // Can't use extern "C" when DLL exporting a global + #define DLL_GLOBAL_EXPORT DLL_DECLARATION_DEFAULT_VISIBILITY + #define DLL_GLOBAL_IMPORT extern + + #define HINT(THE_HINT) __builtin_expect( THE_HINT, 1 ) + #define DECL_ALIGN(x) __attribute__( ( aligned( x ) ) ) + #define CONSTRUCT_EARLY __attribute__((init_priority(101))) + #define SELECTANY __attribute__((weak)) + #define RESTRICT __restrict__ + #define RESTRICT_FUNC RESTRICT_FUNC_NOT_YET_DEFINED_FOR_THIS_COMPILER + #define FMTFUNCTION( fmtargnumber, firstvarargnumber ) __attribute__ (( format( printf, fmtargnumber, firstvarargnumber ))) + #define NOINLINE __attribute__ ((noinline)) + +#if !defined( NO_THREAD_LOCAL ) + #define DECL_THREAD_LOCAL __thread +#endif + + #define DISABLE_VC_WARNING( x ) + #define DEFAULT_VC_WARNING( x ) + +#else + + #define DECL_ALIGN(x) /* */ + #define SELECTANY static + +#endif + +#if defined( GNUC ) && !defined( COMPILER_PS3 ) // use pre-align on PS3 +// gnuc has the align decoration at the end +#define ALIGN4 +#define ALIGN8 +#define ALIGN16 +#define ALIGN32 +#define ALIGN128 + +#undef ALIGN16_POST +#define ALIGN4_POST DECL_ALIGN(4) +#define ALIGN8_POST DECL_ALIGN(8) +#define ALIGN16_POST DECL_ALIGN(16) +#define ALIGN32_POST DECL_ALIGN(32) +#define ALIGN128_POST DECL_ALIGN(128) +#else +// MSVC has the align at the start of the struct +// PS3 SNC supports both +#define ALIGN4 DECL_ALIGN(4) +#define ALIGN8 DECL_ALIGN(8) +#define ALIGN16 DECL_ALIGN(16) +#define ALIGN32 DECL_ALIGN(32) +#define ALIGN128 DECL_ALIGN(128) + +#define ALIGN4_POST +#define ALIGN8_POST +#define ALIGN16_POST +#define ALIGN32_POST +#define ALIGN128_POST +#endif + +// This can be used to declare an abstract (interface only) class. +// Classes marked abstract should not be instantiated. If they are, and access violation will occur. +// +// Example of use: +// +// abstract_class CFoo +// { +// ... +// } +// +// MSDN __declspec(novtable) documentation: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/_langref_novtable.asp +// +// Note: NJS: This is not enabled for regular PC, due to not knowing the implications of exporting a class with no no vtable. +// It's probable that this shouldn't be an issue, but an experiment should be done to verify this. +// +#ifndef COMPILER_MSVCX360 + #define abstract_class class +#else + #define abstract_class class NO_VTABLE +#endif + + +//----------------------------------------------------------------------------- +// Why do we need this? It would be nice to make it die die die +//----------------------------------------------------------------------------- +// Alloca defined for this platform +#if defined( COMPILER_MSVC ) && !defined( WINDED ) + #if defined(_M_IX86) + #define __i386__ 1 + #endif +#endif + +#if defined __i386__ && !defined __linux__ + #define id386 1 +#else + #define id386 0 +#endif // __i386__ + + +//----------------------------------------------------------------------------- +// Disable annoying unhelpful warnings +//----------------------------------------------------------------------------- +#ifdef COMPILER_MSVC +// Remove warnings from warning level 4. +#pragma warning(disable : 4514) // warning C4514: 'acosl' : unreferenced inline function has been removed +#pragma warning(disable : 4100) // warning C4100: 'hwnd' : unreferenced formal parameter +#pragma warning(disable : 4127) // warning C4127: conditional expression is constant +#pragma warning(disable : 4512) // warning C4512: 'InFileRIFF' : assignment operator could not be generated +#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable +#pragma warning(disable : 4710) // warning C4710: function 'x' not inlined +#pragma warning(disable : 4702) // warning C4702: unreachable code +#pragma warning(disable : 4505) // unreferenced local function has been removed +#pragma warning(disable : 4239) // nonstandard extension used : 'argument' ( conversion from class Vector to class Vector& ) +#pragma warning(disable : 4097) // typedef-name 'BaseClass' used as synonym for class-name 'CFlexCycler::CBaseFlex' +#pragma warning(disable : 4324) // Padding was added at the end of a structure +#pragma warning(disable : 4244) // type conversion warning. +#pragma warning(disable : 4305) // truncation from 'const double ' to 'float ' +#pragma warning(disable : 4786) // Disable warnings about long symbol names +#pragma warning(disable : 4250) // 'X' : inherits 'Y::Z' via dominance +#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union + +#if _MSC_VER >= 1300 +#pragma warning(disable : 4511) // Disable warnings about private copy constructors +#pragma warning(disable : 4121) // warning C4121: 'symbol' : alignment of a member was sensitive to packing +#pragma warning(disable : 4530) // warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc (disabled due to std headers having exception syntax) +#endif + +#if _MSC_VER >= 1400 +#pragma warning(disable : 4996) // functions declared deprecated +#endif + +// When we port to 64 bit, we'll have to resolve the int, ptr vs size_t 32/64 bit problems... +#if !defined( COMPILER_MSVC64 ) +#if ( CROSS_PLATFORM_VERSION < 1 ) +#pragma warning( disable : 4267 ) // conversion from 'size_t' to 'int', possible loss of data +#pragma warning( disable : 4311 ) // pointer truncation from 'char *' to 'int' +#pragma warning( disable : 4312 ) // conversion from 'unsigned int' to 'memhandle_t' of greater size +#endif +#endif + +#elif defined( COMPILER_SNC ) +#pragma diag_suppress=1700 // warning 1700: class "%s" has virtual functions but non-virtual destructor +// Uncomment the following line if you want to investigate a specific compiler remark without all the noise: +// #pragma diag_suppress=1700, 83, 162, 182, 192, 194, 229, 238, 262, 341, 382, 401, 402, 403, 481, 817, 828, 833, 1363, 1771, 1774, 1779, 1780, 1783, 1785, 1786, 1788 +#endif + +// Pull in the /analyze code annotations. +#include "annotations.h" + +//----------------------------------------------------------------------------- +// Convert int<-->pointer, avoiding 32/64-bit compiler warnings: +//----------------------------------------------------------------------------- +#define INT_TO_POINTER( i ) (void *)( ( i ) + (char *)NULL ) +#define POINTER_TO_INT( p ) ( (int)(uint64)( p ) ) + + +//----------------------------------------------------------------------------- +// Stack-based allocation related helpers +//----------------------------------------------------------------------------- +#if defined( COMPILER_GCC ) || defined( COMPILER_SNC ) + + #define stackalloc( _size ) alloca( ALIGN_VALUE( _size, 16 ) ) + + #ifdef PLATFORM_OSX + #define mallocsize( _p ) ( malloc_size( _p ) ) + #else + #define mallocsize( _p ) ( malloc_usable_size( _p ) ) + #endif + +#elif defined ( COMPILER_MSVC ) + + #define stackalloc( _size ) _alloca( ALIGN_VALUE( _size, 16 ) ) + #define mallocsize( _p ) ( _msize( _p ) ) + +#endif + +#define stackfree( _p ) 0 + +//----------------------------------------------------------------------------- +// Used to break into the debugger +//----------------------------------------------------------------------------- +#ifdef COMPILER_MSVC64 + #define DebuggerBreak() __debugbreak() +#elif COMPILER_MSVC32 + #define DebuggerBreak() __asm { int 3 } +#elif COMPILER_MSVCX360 + #define DebuggerBreak() DebugBreak() +#elif COMPILER_GCC + #if defined( _PS3 ) + #define DebuggerBreak() { __asm volatile ("tw 31,1,1"); } + #elif defined( OSX ) + #define DebuggerBreak() if ( Plat_IsInDebugSession() ) { __asm__ __volatile__ ( "int $3" ); } else { raise(SIGTRAP); } + #elif defined( PLATFORM_CYGWIN ) || defined( PLATFORM_POSIX ) + #define DebuggerBreak() __asm__( "int $0x3;") + #else + #define DebuggerBreak() asm( "int3" ) + #endif +#elif defined( COMPILER_SNC ) && defined( COMPILER_PS3 ) +static bool sPS3_SuppressAssertsInThisFile = false; // you can throw this in the debugger to temporarily disable asserts inside any particular .cpp module. + #define DebuggerBreak() if (!sPS3_SuppressAssertsInThisFile) __builtin_snpause(); // <sergiy> from SNC Migration Guide, tw 31,1,1 +#else +#error DebuggerBreak() is not defined for this platform! +#endif + +#if defined( _X360 ) || defined( _PS3 ) + #if defined( fsel ) + #error + #endif +#else + +FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) +{ + return fComparand >= 0 ? fValGE : fLT; +} +FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) +{ + return fComparand >= 0 ? fValGE : fLT; +} + +#endif + +//----------------------------------------------------------------------------- +// DLL export for platform utilities +//----------------------------------------------------------------------------- +#ifndef STATIC_TIER0 + +#ifdef TIER0_DLL_EXPORT +#define PLATFORM_INTERFACE DLL_EXPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_EXPORT +#define PLATFORM_CLASS DLL_CLASS_EXPORT +#else +#define PLATFORM_INTERFACE DLL_IMPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_IMPORT +#define PLATFORM_CLASS DLL_CLASS_IMPORT +#endif + +#else // BUILD_AS_DLL + +#define PLATFORM_INTERFACE extern +#define PLATFORM_OVERLOAD +#define PLATFORM_CLASS + +#endif // BUILD_AS_DLL + + +//----------------------------------------------------------------------------- +// Returns true if debugger attached, false otherwise +//----------------------------------------------------------------------------- +#if defined( PLATFORM_WINDOWS ) || defined( _PS3 ) +PLATFORM_INTERFACE void Plat_DebugString( const tchar * ); +#else +#define Plat_DebugString(s) ((void)0) +#endif + +PLATFORM_INTERFACE bool Plat_IsInDebugSession(); + +#define DebuggerBreakIfDebugging() if ( !Plat_IsInDebugSession() ) ; else DebuggerBreak() + + +//----------------------------------------------------------------------------- +// Message Box +//----------------------------------------------------------------------------- +#if defined( PLATFORM_WINDOWS_PC ) +PLATFORM_INTERFACE void Plat_MessageBox( const char *pTitle, const tchar *pMessage ); +#else +#define Plat_MessageBox( t, m ) ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// Posix platform helpers +//----------------------------------------------------------------------------- +#ifdef PLATFORM_POSIX + +// Visual Studio likes to put an underscore in front of anything that looks like a portable function. +#define _strupr strupr +#define _getcwd getcwd +#define _open open +#define _lseek lseek +#define _read read +#define _close close +#define _vsnprintf vsnprintf +#define _stat stat +#define _O_RDONLY O_RDONLY +#define _stricmp strcasecmp +#define _finite finite +#define _unlink unlink +#define _putenv putenv +#define _chdir chdir +#define _access access + +#define strcmpi stricmp +#define stricmp strcasecmp +#define _alloca alloca +#define GetProcAddress dlsym +#define _chdir chdir +#ifndef _PS3 +#define _strnicmp strnicmp +#endif +#define strnicmp strncasecmp +#define _snwprintf swprintf +#define swprintf_s swprintf +#define wcsicmp _wcsicmp +#define _wcsicmp wcscmp +#define _tempnam tempnam +#define strtok_s strtok_r +#define _mkdir(dir) mkdir( dir, S_IRWXU | S_IRWXG | S_IRWXO ) +#define _wtoi(arg) wcstol(arg, NULL, 10) +#define _wtoi64(arg) wcstoll(arg, NULL, 10) + +#ifndef _PS3 +typedef uint32 HMODULE; +#endif +typedef void *HANDLE; +#define __cdecl + +#if !defined( _snprintf ) // some vpc's define this on the command line +#define _snprintf snprintf +#endif + +#include <alloca.h> +#include <unistd.h> // get unlink +#include <errno.h> + +#endif // PLATFORM_POSIX + +#ifdef PLATFORM_WINDOWS +#ifndef SOCKLEN_T +#define SOCKLEN_T +typedef int socklen_t; +#endif +#endif + +//----------------------------------------------------------------------------- +// Generally useful platform-independent macros (move to another file?) +//----------------------------------------------------------------------------- + +// need macro for constant expression +#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) ) + +// Force a function call site -not- to inlined. (useful for profiling) +#define DONT_INLINE(a) (((int)(a)+1)?(a):(a)) + +// Marks the codepath from here until the next branch entry point as unreachable, +// and asserts if any attempt is made to execute it. +#define UNREACHABLE() { Assert(0); HINT(0); } + +// In cases where no default is present or appropriate, this causes MSVC to generate +// as little code as possible, and throw an assertion in debug. +#define NO_DEFAULT default: UNREACHABLE(); + +// Defines MAX_PATH +#ifndef MAX_PATH + #define MAX_PATH 260 +#endif + + +//----------------------------------------------------------------------------- +// FP exception handling +//----------------------------------------------------------------------------- +//#define CHECK_FLOAT_EXCEPTIONS 1 +//#define CHECK_FPU_CONTROL_WORD_SET 1 // x360 only + +#if defined( COMPILER_MSVC64 ) + + inline void SetupFPUControlWord() + { + } + +#elif defined ( COMPILER_MSVC32 ) + + inline void SetupFPUControlWordForceExceptions() + { + // use local to get and store control word + uint16 tmpCtrlW; + __asm + { + fnclex /* clear all current exceptions */ + fnstcw word ptr [tmpCtrlW] /* get current control word */ + and [tmpCtrlW], 0FCC0h /* Keep infinity control + rounding control */ + or [tmpCtrlW], 0230h /* set to 53-bit, mask only inexact, underflow */ + fldcw word ptr [tmpCtrlW] /* put new control word in FPU */ + } + } + + #ifdef CHECK_FLOAT_EXCEPTIONS + + inline void SetupFPUControlWord() + { + SetupFPUControlWordForceExceptions(); + } + + #else + + inline void SetupFPUControlWord() + { + // use local to get and store control word + uint16 tmpCtrlW; + __asm + { + fnstcw word ptr [tmpCtrlW] /* get current control word */ + and [tmpCtrlW], 0FCC0h /* Keep infinity control + rounding control */ + or [tmpCtrlW], 023Fh /* set to 53-bit, mask only inexact, underflow */ + fldcw word ptr [tmpCtrlW] /* put new control word in FPU */ + } + } + + #endif + +#elif defined ( COMPILER_GCC ) + +// Works for PS3 + inline void SetupFPUControlWord() + { +#ifdef _PS3 +// TODO: PS3 compiler spits out the following errors: +// C:/tmp/ccIN0aaa.s: Assembler messages: +// C:/tmp/ccIN0aaa.s(80): Error: Unrecognized opcode: `fnstcw' +// C:/tmp/ccIN0aaa.s(93): Error: Unrecognized opcode: `fldcw' +#else + __volatile unsigned short int __cw; + __asm __volatile ("fnstcw %0" : "=m" (__cw)); + __cw = __cw & 0x0FCC0; // keep infinity control, keep rounding mode + __cw = __cw | 0x023F; // set 53-bit, no exceptions + __asm __volatile ("fldcw %0" : : "m" (__cw)); +#endif + } + +#elif defined ( COMPILER_SNC ) + +// Works for PS3 + inline void SetupFPUControlWord() + { +#ifdef _PS3 +// TODO: PS3 compiler spits out the following errors: +// C:/tmp/ccIN0aaa.s: Assembler messages: +// C:/tmp/ccIN0aaa.s(80): Error: Unrecognized opcode: `fnstcw' +// C:/tmp/ccIN0aaa.s(93): Error: Unrecognized opcode: `fldcw' +#else + __volatile unsigned short int __cw; + __asm __volatile ("fnstcw %0" : "=m" (__cw)); + __cw = __cw & 0x0FCC0; // keep infinity control, keep rounding mode + __cw = __cw | 0x023F; // set 53-bit, no exceptions + __asm __volatile ("fldcw %0" : : "m" (__cw)); +#endif + } + +#elif defined( COMPILER_MSVCX360 ) + + #ifdef CHECK_FPU_CONTROL_WORD_SET + FORCEINLINE bool IsFPUControlWordSet() + { + float f = 0.996f; + union + { + double flResult; + int pResult[2]; + }; + flResult = __fctiw( f ); + return ( pResult[1] == 1 ); + } + #else + #define IsFPUControlWordSet() 1 + #endif + + inline void SetupFPUControlWord() + { + // Set round-to-nearest in FPSCR + // (cannot assemble, must use op-code form) + __emit( 0xFF80010C ); // mtfsfi 7,0 + + // Favour compatibility over speed (make sure the VPU set to Java-compliant mode) + // NOTE: the VPU *always* uses round-to-nearest + __vector4 a = { 0.0f, 0.0f, 0.0f, 0.0f }; + a; // Avoid compiler warning + __asm + { + mtvscr a; // Clear the Vector Status & Control Register to zero + } + } + +#endif // COMPILER_MSVCX360 + + + + +//----------------------------------------------------------------------------- +// Purpose: Standard functions for handling endian-ness +//----------------------------------------------------------------------------- + +//------------------------------------- +// Basic swaps +//------------------------------------- + +template <typename T> +inline T WordSwapC( T w ) +{ + uint16 temp; + + temp = ((*((uint16 *)&w) & 0xff00) >> 8); + temp |= ((*((uint16 *)&w) & 0x00ff) << 8); + + return *((T*)&temp); +} + +template <typename T> +inline T DWordSwapC( T dw ) +{ + uint32 temp; + + temp = *((uint32 *)&dw) >> 24; + temp |= ((*((uint32 *)&dw) & 0x00FF0000) >> 8); + temp |= ((*((uint32 *)&dw) & 0x0000FF00) << 8); + temp |= ((*((uint32 *)&dw) & 0x000000FF) << 24); + + return *((T*)&temp); +} + +//------------------------------------- +// Fast swaps +//------------------------------------- + +#if defined( COMPILER_MSVCX360 ) + + #define WordSwap WordSwap360Intr + #define DWordSwap DWordSwap360Intr + + template <typename T> + inline T WordSwap360Intr( T w ) + { + T output; + __storeshortbytereverse( w, 0, &output ); + return output; + } + + template <typename T> + inline T DWordSwap360Intr( T dw ) + { + T output; + __storewordbytereverse( dw, 0, &output ); + return output; + } + +#elif defined( COMPILER_MSVC32 ) + + #define WordSwap WordSwapAsm + #define DWordSwap DWordSwapAsm + + #pragma warning(push) + #pragma warning (disable:4035) // no return value + + template <typename T> + inline T WordSwapAsm( T w ) + { + __asm + { + mov ax, w + xchg al, ah + } + } + + template <typename T> + inline T DWordSwapAsm( T dw ) + { + __asm + { + mov eax, dw + bswap eax + } + } + + #pragma warning(pop) + +#else + + #define WordSwap WordSwapC + #define DWordSwap DWordSwapC + +#endif + +//------------------------------------- +// The typically used methods. +//------------------------------------- + +#if defined( _SGI_SOURCE ) || defined( PLATFORM_X360 ) || defined( _PS3 ) +#define PLAT_BIG_ENDIAN 1 +#else +#define PLAT_LITTLE_ENDIAN 1 +#endif + + +// If a swapped float passes through the fpu, the bytes may get changed. +// Prevent this by swapping floats as DWORDs. +#define SafeSwapFloat( pOut, pIn ) (*((uint*)pOut) = DWordSwap( *((uint*)pIn) )) + +#if defined(PLAT_LITTLE_ENDIAN) +#define BigShort( val ) WordSwap( val ) +#define BigWord( val ) WordSwap( val ) +#define BigLong( val ) DWordSwap( val ) +#define BigDWord( val ) DWordSwap( val ) +#define LittleShort( val ) ( val ) +#define LittleWord( val ) ( val ) +#define LittleLong( val ) ( val ) +#define LittleDWord( val ) ( val ) +#define SwapShort( val ) BigShort( val ) +#define SwapWord( val ) BigWord( val ) +#define SwapLong( val ) BigLong( val ) +#define SwapDWord( val ) BigDWord( val ) + +// Pass floats by pointer for swapping to avoid truncation in the fpu +#define BigFloat( pOut, pIn ) SafeSwapFloat( pOut, pIn ) +#define LittleFloat( pOut, pIn ) ( *pOut = *pIn ) +#define SwapFloat( pOut, pIn ) BigFloat( pOut, pIn ) + +#elif defined(PLAT_BIG_ENDIAN) + +#define BigShort( val ) ( val ) +#define BigWord( val ) ( val ) +#define BigLong( val ) ( val ) +#define BigDWord( val ) ( val ) +#define LittleShort( val ) WordSwap( val ) +#define LittleWord( val ) WordSwap( val ) +#define LittleLong( val ) DWordSwap( val ) +#define LittleDWord( val ) DWordSwap( val ) +#define SwapShort( val ) LittleShort( val ) +#define SwapWord( val ) LittleWord( val ) +#define SwapLong( val ) LittleLong( val ) +#define SwapDWord( val ) LittleDWord( val ) + +// Pass floats by pointer for swapping to avoid truncation in the fpu +#define BigFloat( pOut, pIn ) ( *pOut = *pIn ) +#define LittleFloat( pOut, pIn ) SafeSwapFloat( pOut, pIn ) +#define SwapFloat( pOut, pIn ) LittleFloat( pOut, pIn ) + +#else + +// @Note (toml 05-02-02): this technique expects the compiler to +// optimize the expression and eliminate the other path. On any new +// platform/compiler this should be tested. +inline short BigShort( short val ) { int test = 1; return ( *(char *)&test == 1 ) ? WordSwap( val ) : val; } +inline uint16 BigWord( uint16 val ) { int test = 1; return ( *(char *)&test == 1 ) ? WordSwap( val ) : val; } +inline long BigLong( long val ) { int test = 1; return ( *(char *)&test == 1 ) ? DWordSwap( val ) : val; } +inline uint32 BigDWord( uint32 val ) { int test = 1; return ( *(char *)&test == 1 ) ? DWordSwap( val ) : val; } +inline short LittleShort( short val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : WordSwap( val ); } +inline uint16 LittleWord( uint16 val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : WordSwap( val ); } +inline long LittleLong( long val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : DWordSwap( val ); } +inline uint32 LittleDWord( uint32 val ) { int test = 1; return ( *(char *)&test == 1 ) ? val : DWordSwap( val ); } +inline short SwapShort( short val ) { return WordSwap( val ); } +inline uint16 SwapWord( uint16 val ) { return WordSwap( val ); } +inline long SwapLong( long val ) { return DWordSwap( val ); } +inline uint32 SwapDWord( uint32 val ) { return DWordSwap( val ); } + +// Pass floats by pointer for swapping to avoid truncation in the fpu +inline void BigFloat( float *pOut, const float *pIn ) { int test = 1; ( *(char *)&test == 1 ) ? SafeSwapFloat( pOut, pIn ) : ( *pOut = *pIn ); } +inline void LittleFloat( float *pOut, const float *pIn ) { int test = 1; ( *(char *)&test == 1 ) ? ( *pOut = *pIn ) : SafeSwapFloat( pOut, pIn ); } +inline void SwapFloat( float *pOut, const float *pIn ) { SafeSwapFloat( pOut, pIn ); } + +#endif + +#if PLAT_BIG_ENDIAN + #if defined( _PS3 ) + inline uint32 LoadLittleDWord( uint32 *base, unsigned int dwordIndex ) + { + return __lwbrx( base + dwordIndex ); + } + + inline void StoreLittleDWord( uint32 *base, unsigned int dwordIndex, uint32 dword ) + { + __stwbrx( base + dwordIndex, dword ); + } + inline uint64 LoadLittleInt64( uint64 *base, unsigned int nWordIndex ) + { + return __ldbrx( base + nWordIndex ); + } + + inline void StoreLittleInt64( uint64 *base, unsigned int nWordIndex, uint64 nWord ) + { + __stdbrx( base + nWordIndex, nWord ); + } + #else + inline uint32 LoadLittleDWord( uint32 *base, unsigned int dwordIndex ) + { + return __loadwordbytereverse( dwordIndex<<2, base ); + } + + inline void StoreLittleDWord( uint32 *base, unsigned int dwordIndex, uint32 dword ) + { + __storewordbytereverse( dword, dwordIndex<<2, base ); + } + inline uint64 LoadLittleInt64( uint64 *base, unsigned int nWordIndex ) + { + return __loaddoublewordbytereverse( nWordIndex<<2, base ); + } + + inline void StoreLittleInt64( uint64 *base, unsigned int nWordIndex, uint64 nWord ) + { + __storedoublewordbytereverse( nWord, nWordIndex<<2, base ); + } + #endif +#else + inline uint32 LoadLittleDWord( uint32 *base, unsigned int dwordIndex ) + { + return LittleDWord( base[dwordIndex] ); + } + + inline void StoreLittleDWord( uint32 *base, unsigned int dwordIndex, uint32 dword ) + { + base[dwordIndex] = LittleDWord(dword); + } +#endif + + +// When in benchmark mode, the timer returns a simple incremented value each time you call it. +// +// It should not be changed after startup unless you really know what you're doing. The only place +// that should do this is the benchmark code itself so it can output a legit duration. +PLATFORM_INTERFACE void Plat_SetBenchmarkMode( bool bBenchmarkMode ); +PLATFORM_INTERFACE bool Plat_IsInBenchmarkMode(); + + +PLATFORM_INTERFACE double Plat_FloatTime(); // Returns time in seconds since the module was loaded. +PLATFORM_INTERFACE uint32 Plat_MSTime(); // Time in milliseconds. +PLATFORM_INTERFACE uint64 Plat_GetClockStart(); // Snapshot of the clock when app started. +PLATFORM_INTERFACE uint64 Timer_GetTimeUS(); + +// Get the local calendar time. +// Same as time() followed by localtime(), but non-crash-prone and threadsafe. +PLATFORM_INTERFACE void Plat_GetLocalTime( struct tm *pNow ); + +// Convert a time_t (specified in nTime - seconds since Jan 1, 1970 UTC) to a local calendar time in a threadsafe and non-crash-prone way. +PLATFORM_INTERFACE void Plat_ConvertToLocalTime( uint64 nTime, struct tm *pNow ); + +// Get a time string (same as ascstring, but threadsafe). +PLATFORM_INTERFACE void Plat_GetTimeString( struct tm *pTime, char *pOut, int nMaxBytes ); + +// converts a time_t to a struct tm without the local time conversion of ConvertToLocalTime +PLATFORM_INTERFACE void Plat_gmtime( uint64 nTime, struct tm *pTime ); +PLATFORM_INTERFACE time_t Plat_timegm( struct tm *timeptr ); + +// Get the process' executable filename. +PLATFORM_INTERFACE void Plat_GetModuleFilename( char *pOut, int nMaxBytes ); + +PLATFORM_INTERFACE void Plat_ExitProcess( int nCode ); + +// b/w compatibility +#define Sys_FloatTime Plat_FloatTime + +// Protect against bad auto operator= +#define DISALLOW_OPERATOR_EQUAL( _classname ) \ + private: \ + _classname &operator=( const _classname & ); \ + public: + +// Define a reasonable operator= +#define IMPLEMENT_OPERATOR_EQUAL( _classname ) \ + public: \ + _classname &operator=( const _classname &src ) \ + { \ + memcpy( this, &src, sizeof(_classname) ); \ + return *this; \ + } + +// Processor Information: +struct CPUInformation +{ + int m_Size; // Size of this structure, for forward compatability. + + bool m_bRDTSC : 1, // Is RDTSC supported? + m_bCMOV : 1, // Is CMOV supported? + m_bFCMOV : 1, // Is FCMOV supported? + m_bSSE : 1, // Is SSE supported? + m_bSSE2 : 1, // Is SSE2 Supported? + m_b3DNow : 1, // Is 3DNow! Supported? + m_bMMX : 1, // Is MMX supported? + m_bHT : 1; // Is HyperThreading supported? + + uint8 m_nLogicalProcessors; // Number op logical processors. + uint8 m_nPhysicalProcessors; // Number of physical processors + + bool m_bSSE3 : 1, + m_bSSSE3 : 1, + m_bSSE4a : 1, + m_bSSE41 : 1, + m_bSSE42 : 1; + + int64 m_Speed; // In cycles per second. + + tchar* m_szProcessorID; // Processor vendor Identification. + + CPUInformation(): m_Size(0){} +}; + +PLATFORM_INTERFACE const CPUInformation& GetCPUInformation(); + +PLATFORM_INTERFACE void GetCurrentDate( int *pDay, int *pMonth, int *pYear ); +PLATFORM_INTERFACE void GetCurrentDayOfTheWeek( int *pDay ); // 0 = Sunday +PLATFORM_INTERFACE void GetCurrentDayOfTheYear( int *pDay ); // 0 = Jan 1 + +// ---------------------------------------------------------------------------------- // +// Performance Monitoring Events - L2 stats etc... +// ---------------------------------------------------------------------------------- // +PLATFORM_INTERFACE void InitPME(); +PLATFORM_INTERFACE void ShutdownPME(); + + +//----------------------------------------------------------------------------- +// Security related functions +//----------------------------------------------------------------------------- +// Ensure that the hardware key's drivers have been installed. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyDriver(); + +// Ok, so this isn't a very secure way to verify the hardware key for now. It +// is primarially depending on the fact that all the binaries have been wrapped +// with the secure wrapper provided by the hardware keys vendor. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKey(); + +// The same as above, but notifies user with a message box when the key isn't in +// and gives him an opportunity to correct the situation. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyPrompt(); + +// Can be called in real time, doesn't perform the verify every frame. Mainly just +// here to allow the game to drop out quickly when the key is removed, rather than +// allowing the wrapper to pop up it's own blocking dialog, which the engine doesn't +// like much. +PLATFORM_INTERFACE bool Plat_FastVerifyHardwareKey(); + +//----------------------------------------------------------------------------- +// Just logs file and line to simple.log +//----------------------------------------------------------------------------- +PLATFORM_INTERFACE void* Plat_SimpleLog( const tchar* file, int line ); + + +#if defined( _X360 ) +#define Plat_FastMemset XMemSet +#define Plat_FastMemcpy XMemCpy +#else +#define Plat_FastMemset memset +#define Plat_FastMemcpy memcpy +#endif + +//----------------------------------------------------------------------------- +// XBOX Components valid in PC compilation space +//----------------------------------------------------------------------------- + +#define XBOX_DVD_SECTORSIZE 2048 +#define XBOX_DVD_ECC_SIZE 32768 // driver reads in quantum ECC blocks +#define XBOX_HDD_SECTORSIZE 512 + +// Custom windows messages for Xbox input +#define WM_XREMOTECOMMAND (WM_USER + 100) +#define WM_XCONTROLLER_KEY (WM_USER + 101) +#define WM_SYS_UI (WM_USER + 102) +#define WM_SYS_SIGNINCHANGED (WM_USER + 103) +#define WM_SYS_STORAGEDEVICESCHANGED (WM_USER + 104) +#define WM_SYS_PROFILESETTINGCHANGED (WM_USER + 105) +#define WM_SYS_MUTELISTCHANGED (WM_USER + 106) +#define WM_SYS_INPUTDEVICESCHANGED (WM_USER + 107) +#define WM_SYS_INPUTDEVICECONFIGCHANGED (WM_USER + 108) +#define WM_LIVE_CONNECTIONCHANGED (WM_USER + 109) +#define WM_LIVE_INVITE_ACCEPTED (WM_USER + 110) +#define WM_LIVE_LINK_STATE_CHANGED (WM_USER + 111) +#define WM_LIVE_CONTENT_INSTALLED (WM_USER + 112) +#define WM_LIVE_MEMBERSHIP_PURCHASED (WM_USER + 113) +#define WM_LIVE_VOICECHAT_AWAY (WM_USER + 114) +#define WM_LIVE_PRESENCE_CHANGED (WM_USER + 115) +#define WM_FRIENDS_PRESENCE_CHANGED (WM_USER + 116) +#define WM_FRIENDS_FRIEND_ADDED (WM_USER + 117) +#define WM_FRIENDS_FRIEND_REMOVED (WM_USER + 118) +#define WM_CUSTOM_GAMEBANNERPRESSED (WM_USER + 119) +#define WM_CUSTOM_ACTIONPRESSED (WM_USER + 120) +#define WM_XMP_STATECHANGED (WM_USER + 121) +#define WM_XMP_PLAYBACKBEHAVIORCHANGED (WM_USER + 122) +#define WM_XMP_PLAYBACKCONTROLLERCHANGED (WM_USER + 123) +#define WM_SYS_SHUTDOWNREQUEST (WM_USER + 124) + +#if defined( _PS3 ) +#define PLATFORM_EXT ".ps3" +#elif defined( PLATFORM_X360 ) +#define PLATFORM_EXT ".360" +#else +#define PLATFORM_EXT "" +#endif + +inline const char *GetPlatformExt( void ) +{ + return PLATFORM_EXT; +} + +// flat view, 6 hw threads +#define XBOX_PROCESSOR_0 ( 1<<0 ) +#define XBOX_PROCESSOR_1 ( 1<<1 ) +#define XBOX_PROCESSOR_2 ( 1<<2 ) +#define XBOX_PROCESSOR_3 ( 1<<3 ) +#define XBOX_PROCESSOR_4 ( 1<<4 ) +#define XBOX_PROCESSOR_5 ( 1<<5 ) + +// core view, 3 cores with 2 hw threads each +#define XBOX_CORE_0_HWTHREAD_0 XBOX_PROCESSOR_0 +#define XBOX_CORE_0_HWTHREAD_1 XBOX_PROCESSOR_1 +#define XBOX_CORE_1_HWTHREAD_0 XBOX_PROCESSOR_2 +#define XBOX_CORE_1_HWTHREAD_1 XBOX_PROCESSOR_3 +#define XBOX_CORE_2_HWTHREAD_0 XBOX_PROCESSOR_4 +#define XBOX_CORE_2_HWTHREAD_1 XBOX_PROCESSOR_5 + +//----------------------------------------------------------------------------- +// Include additional dependant header components. +//----------------------------------------------------------------------------- +#if defined( PLATFORM_X360 ) +#include "xbox/xbox_core.h" +#elif defined( PLATFORM_PS3 ) +#include "ps3/ps3_core.h" +#endif + +//----------------------------------------------------------------------------- +// Methods to invoke the constructor, copy constructor, and destructor +//----------------------------------------------------------------------------- + +template <class T> +inline T* Construct( T* pMemory ) +{ + return ::new( pMemory ) T; +} + +template <class T, typename ARG1> +inline T* Construct( T* pMemory, ARG1 a1 ) +{ + return ::new( pMemory ) T( a1 ); +} + +template <class T, typename ARG1, typename ARG2> +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2 ) +{ + return ::new( pMemory ) T( a1, a2 ); +} + +template <class T, typename ARG1, typename ARG2, typename ARG3> +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3 ) +{ + return ::new( pMemory ) T( a1, a2, a3 ); +} + +template <class T, typename ARG1, typename ARG2, typename ARG3, typename ARG4> +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4 ) +{ + return ::new( pMemory ) T( a1, a2, a3, a4 ); +} + +template <class T, typename ARG1, typename ARG2, typename ARG3, typename ARG4, typename ARG5> +inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4, ARG5 a5 ) +{ + return ::new( pMemory ) T( a1, a2, a3, a4, a5 ); +} + +template <class T> +inline T* CopyConstruct( T* pMemory, T const& src ) +{ + return ::new( pMemory ) T(src); +} + +template <class T> +inline void Destruct( T* pMemory ) +{ + pMemory->~T(); + +#ifdef _DEBUG + memset( pMemory, 0xDD, sizeof(T) ); +#endif +} + + +// +// GET_OUTER() +// +// A platform-independent way for a contained class to get a pointer to its +// owner. If you know a class is exclusively used in the context of some +// "outer" class, this is a much more space efficient way to get at the outer +// class than having the inner class store a pointer to it. +// +// class COuter +// { +// class CInner // Note: this does not need to be a nested class to work +// { +// void PrintAddressOfOuter() +// { +// printf( "Outer is at 0x%x\n", GET_OUTER( COuter, m_Inner ) ); +// } +// }; +// +// CInner m_Inner; +// friend class CInner; +// }; + +#define GET_OUTER( OuterType, OuterMember ) \ + ( ( OuterType * ) ( (uint8 *)this - offsetof( OuterType, OuterMember ) ) ) + + +/* TEMPLATE_FUNCTION_TABLE() + + (Note added to platform.h so platforms that correctly support templated + functions can handle portions as templated functions rather than wrapped + functions) + + Helps automate the process of creating an array of function + templates that are all specialized by a single integer. + This sort of thing is often useful in optimization work. + + For example, using TEMPLATE_FUNCTION_TABLE, this: + + TEMPLATE_FUNCTION_TABLE(int, Function, ( int blah, int blah ), 10) + { + return argument * argument; + } + + is equivilent to the following: + + (NOTE: the function has to be wrapped in a class due to code + generation bugs involved with directly specializing a function + based on a constant.) + + template<int argument> + class FunctionWrapper + { + public: + int Function( int blah, int blah ) + { + return argument*argument; + } + } + + typedef int (*FunctionType)( int blah, int blah ); + + class FunctionName + { + public: + enum { count = 10 }; + FunctionType functions[10]; + }; + + FunctionType FunctionName::functions[] = + { + FunctionWrapper<0>::Function, + FunctionWrapper<1>::Function, + FunctionWrapper<2>::Function, + FunctionWrapper<3>::Function, + FunctionWrapper<4>::Function, + FunctionWrapper<5>::Function, + FunctionWrapper<6>::Function, + FunctionWrapper<7>::Function, + FunctionWrapper<8>::Function, + FunctionWrapper<9>::Function + }; +*/ + +PLATFORM_INTERFACE bool vtune( bool resume ); + + +#define TEMPLATE_FUNCTION_TABLE(RETURN_TYPE, NAME, ARGS, COUNT) \ + \ +typedef RETURN_TYPE (FASTCALL *__Type_##NAME) ARGS; \ + \ +template<const int nArgument> \ +struct __Function_##NAME \ +{ \ + static RETURN_TYPE FASTCALL Run ARGS; \ +}; \ + \ +template <const int i> \ +struct __MetaLooper_##NAME : __MetaLooper_##NAME<i-1> \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME<i>::Run; } \ +}; \ + \ +template<> \ +struct __MetaLooper_##NAME<0> \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME<0>::Run; } \ +}; \ + \ +class NAME \ +{ \ +private: \ + static const __MetaLooper_##NAME<COUNT> m; \ +public: \ + enum { count = COUNT }; \ + static const __Type_##NAME* functions; \ +}; \ +const __MetaLooper_##NAME<COUNT> NAME::m; \ +const __Type_##NAME* NAME::functions = (__Type_##NAME*)&m; \ +template<const int nArgument> \ +RETURN_TYPE FASTCALL __Function_##NAME<nArgument>::Run ARGS + + +#define LOOP_INTERCHANGE(BOOLEAN, CODE)\ + if( (BOOLEAN) )\ + {\ + CODE;\ + } else\ + {\ + CODE;\ + } + + +//----------------------------------------------------------------------------- +// Dynamic libs support +//----------------------------------------------------------------------------- +#if defined( PLATFORM_WINDOWS ) + +PLATFORM_INTERFACE void *Plat_GetProcAddress( const char *pszModule, const char *pszName ); + +template <typename FUNCPTR_TYPE> +class CDynamicFunction +{ +public: + CDynamicFunction( const char *pszModule, const char *pszName, FUNCPTR_TYPE pfnFallback = NULL ) + { + m_pfn = pfnFallback; + void *pAddr = Plat_GetProcAddress( pszModule, pszName ); + if ( pAddr ) + { + m_pfn = (FUNCPTR_TYPE)pAddr; + } + } + + operator bool() { return m_pfn != NULL; } + bool operator !() { return !m_pfn; } + operator FUNCPTR_TYPE() { return m_pfn; } + +private: + FUNCPTR_TYPE m_pfn; +}; +#endif + + +//----------------------------------------------------------------------------- +// What OS version are we? +//----------------------------------------------------------------------------- +enum PlatOSVersion_t +{ + PLAT_OS_VERSION_UNKNOWN = -1, + + // X360-specific versions + PLAT_OS_VERSION_XBOX360 = 0, + + // PC-specific OS versions + PLAT_OS_VERSION_XP = 5, + PLAT_OS_VERSION_VISTA = 6, +}; + +PLATFORM_INTERFACE PlatOSVersion_t Plat_GetOSVersion(); + + +// Watchdog timer support. Call BeginWatchdogTimer( nn ) to kick the timer off. if you don't call +// EndWatchdogTimer within nn seconds, the program will kick off an exception. This is for making +// sure that hung dedicated servers abort (and restart) instead of staying hung. Calling +// EndWatchdogTimer more than once or when there is no active watchdog is fine. Only does anything +// under linux right now. It should be possible to implement this functionality in windows via a +// thread, if desired. + +#if defined( POSIX ) && !defined( _PS3 ) + +PLATFORM_INTERFACE void BeginWatchdogTimer( int nSecs ); +PLATFORM_INTERFACE void EndWatchdogTimer( void ); +PLATFORM_INTERFACE void ResetBaseTime( void ); // reset plat_floattime to 0 for a subprocess +#else +FORCEINLINE void BeginWatchdogTimer( int nSecs ) +{ +} + +FORCEINLINE void EndWatchdogTimer( void ) +{ +} +FORCEINLINE void ResetBaseTime( void ) // reset plat_floattime to 0 for a subprocess +{ +} + +#endif + + +#ifdef COMPILER_MSVC +/* +FORCEINLINE uint8 RotateBitsLeft8( uint8 nValue, int nRotateBits ) +{ + return _rotl8( nValue, nRotateBits ); +} +FORCEINLINE uint16 RotateBitsLeft16( uint16 nValue, int nRotateBits ) +{ + return _rotl( nValue, nRotateBits ); +} +FORCEINLINE uint8 RotateBitsRight8( uint8 nValue, int nRotateBits ) +{ +return _rotr8( nValue, nRotateBits ); +} +FORCEINLINE uint16 RotateBitsRight16( uint16 nValue, int nRotateBits ) +{ +return _rotr16( nValue, nRotateBits ); +} +*/ +FORCEINLINE uint32 RotateBitsLeft32( uint32 nValue, int nRotateBits ) +{ + return _rotl( nValue, nRotateBits ); +} +FORCEINLINE uint64 RotateBitsLeft64( uint64 nValue, int nRotateBits ) +{ + return _rotl64( nValue, nRotateBits ); +} +FORCEINLINE uint32 RotateBitsRight32( uint32 nValue, int nRotateBits ) +{ + return _rotr( nValue, nRotateBits ); +} +FORCEINLINE uint64 RotateBitsRight64( uint64 nValue, int nRotateBits ) +{ + return _rotr64( nValue, nRotateBits ); +} +#else +// GCC should compile this all into single instruction +/* +FORCEINLINE uint8 RotateBitsLeft8( uint8 nValue, int nRotateBits ) +{ + return ( nValue << nRotateBits ) | ( nValue >> ( ( -nRotateBits ) & 7 ) ); +} +FORCEINLINE uint16 RotateBitsLeft16( uint16 nValue, int nRotateBits ) +{ + return ( nValue << nRotateBits ) | ( nValue >> ( ( -nRotateBits ) & 15 ) ); +} +FORCEINLINE uint8 RotateBitsRight8( uint8 nValue, int nRotateBits ) +{ + return ( nValue >> nRotateBits ) | ( nValue << ( ( -nRotateBits ) & 7 ) ); +} +FORCEINLINE uint16 RotateBitsRight16( uint16 nValue, int nRotateBits ) +{ + return ( nValue >> nRotateBits ) | ( nValue << ( ( -nRotateBits ) & 15 ) ); +} +*/ +FORCEINLINE uint32 RotateBitsLeft32( uint32 nValue, int nRotateBits ) +{ + return ( nValue << nRotateBits ) | ( nValue >> ( ( -nRotateBits ) & 31 ) ); +} +FORCEINLINE uint64 RotateBitsLeft64( uint64 nValue, int nRotateBits ) +{ + return ( nValue << nRotateBits ) | ( nValue >> ( ( - nRotateBits ) & 63 ) ); +} +FORCEINLINE uint32 RotateBitsRight32( uint32 nValue, int nRotateBits ) +{ + return ( nValue >> nRotateBits ) | ( nValue << ( ( -nRotateBits ) & 31 ) ); +} +FORCEINLINE uint64 RotateBitsRight64( uint64 nValue, int nRotateBits ) +{ + return ( nValue >> nRotateBits ) | ( nValue << ( ( - nRotateBits ) & 63 ) ); +} +#endif +PLATFORM_INTERFACE const char * GetPlatformSpecificFileName(const char * FileName); + +#include "tier0/valve_on.h" + +#if defined(TIER0_DLL_EXPORT) +extern "C" int V_tier0_stricmp(const char *s1, const char *s2 ); +#undef stricmp +#undef strcmpi +#define stricmp(s1,s2) V_tier0_stricmp( s1, s2 ) +#define strcmpi(s1,s2) V_tier0_stricmp( s1, s2 ) +#else +int _V_stricmp (const char *s1, const char *s2 ); +int V_strncasecmp (const char *s1, const char *s2, int n); + +// A special high-performance case-insensitive compare function that in +// a single call distinguishes between exactly matching strings, +// strings equal in case-insensitive way, and not equal strings: +// returns 0 if strings match exactly +// returns >0 if strings match in a case-insensitive way, but do not match exactly +// returns <0 if strings do not match even in a case-insensitive way +int _V_stricmp_NegativeForUnequal ( const char *s1, const char *s2 ); + +#undef stricmp +#undef strcmpi +#define stricmp(s1,s2) _V_stricmp(s1, s2) +#define strcmpi(s1,s2) _V_stricmp(s1, s2) +#undef strnicmp +#define strnicmp V_strncasecmp +#endif + +#endif /* PLATFORM_H */ diff --git a/external/vpc/public/tier0/pmelib.h b/external/vpc/public/tier0/pmelib.h new file mode 100644 index 0000000..dcdec5f --- /dev/null +++ b/external/vpc/public/tier0/pmelib.h @@ -0,0 +1,212 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#ifndef PMELIB_H +#define PMELIB_H + +//#include "windows.h" + +#include "tier0/platform.h" + +// Get rid of a bunch of STL warnings! +#pragma warning( push, 3 ) +#pragma warning( disable : 4018 ) + +#define VERSION "1.0.2" + +// uncomment this list to add some runtime checks +//#define PME_DEBUG + +#include "tier0/valve_off.h" +#include <string> +#include "tier0/valve_on.h" + +using namespace std; + +// RDTSC Instruction macro +#ifdef COMPILER_MSVC64 +#define RDTSC(var) (var = __rdtsc()) +#else +#define RDTSC(var) \ +_asm RDTSC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx +#endif + +// RDPMC Instruction macro +#ifdef COMPILER_MSVC64 +#define RDPMC(counter, var) (var = __readpmc(counter)) +#else +#define RDPMC(counter, var) \ +_asm mov ecx, counter \ +_asm RDPMC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx +#endif + +// RDPMC Instruction macro, for performance counter 1 (ecx = 1) +#ifdef COMPILER_MSVC64 +#define RDPMC0(var) (var = __readpmc(0)) +#else +#define RDPMC0(var) \ +_asm mov ecx, 0 \ +_asm RDPMC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx +#endif + +#ifdef COMPILER_MSVC64 +#define RDPMC1(var) (var = __readpmc(1)) +#else +#define RDPMC1(var) \ +_asm mov ecx, 1 \ +_asm RDPMC \ +_asm mov DWORD PTR var,eax \ +_asm mov DWORD PTR var+4,edx +#endif + +#define EVENT_TYPE(mode) EventType##mode +#define EVENT_MASK(mode) EventMask##mode + +#include "ia32detect.h" + +enum ProcessPriority +{ + ProcessPriorityNormal, + ProcessPriorityHigh, +}; + +enum PrivilegeCapture +{ + OS_Only, // ring 0, kernel level + USR_Only, // app level + OS_and_USR, // all levels +}; + +enum CompareMethod +{ + CompareGreater, // + CompareLessEqual, // +}; + +enum EdgeState +{ + RisingEdgeDisabled, // + RisingEdgeEnabled, // +}; + +enum CompareState +{ + CompareDisable, // + CompareEnable, // +}; + +// Singletion Class +class PME : public ia32detect +{ +public: +//private: + + static PME* _singleton; + + HANDLE hFile; + bool bDriverOpen; + double m_CPUClockSpeed; + + //ia32detect detect; + HRESULT Init(); + HRESULT Close(); + +protected: + + PME() + { + hFile = NULL; + bDriverOpen = FALSE; + m_CPUClockSpeed = 0; + Init(); + } + +public: + + static PME* Instance(); // gives back a real object + + ~PME() + { + Close(); + } + + double GetCPUClockSpeedSlow( void ); + double GetCPUClockSpeedFast( void ); + + HRESULT SelectP5P6PerformanceEvent( uint32 dw_event, uint32 dw_counter, bool b_user, bool b_kernel ); + + HRESULT ReadMSR( uint32 dw_reg, int64 * pi64_value ); + HRESULT ReadMSR( uint32 dw_reg, uint64 * pi64_value ); + + HRESULT WriteMSR( uint32 dw_reg, const int64 & i64_value ); + HRESULT WriteMSR( uint32 dw_reg, const uint64 & i64_value ); + + void SetProcessPriority( ProcessPriority priority ) + { + switch( priority ) + { + case ProcessPriorityNormal: + { + SetPriorityClass (GetCurrentProcess(),NORMAL_PRIORITY_CLASS); + SetThreadPriority (GetCurrentThread(),THREAD_PRIORITY_NORMAL); + break; + } + case ProcessPriorityHigh: + { + SetPriorityClass (GetCurrentProcess(),REALTIME_PRIORITY_CLASS); + SetThreadPriority (GetCurrentThread(),THREAD_PRIORITY_HIGHEST); + break; + } + } + } + + //--------------------------------------------------------------------------- + // Return the family of the processor + //--------------------------------------------------------------------------- + CPUVendor GetVendor(void) + { + return vendor; + } + + int GetProcessorFamily(void) + { + return version.Family; + } + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +}; + +#include "p5p6performancecounters.h" +#include "p4performancecounters.h" +#include "k8performancecounters.h" + +enum PerfErrors +{ + E_UNKNOWN_CPU_VENDOR = -1, + E_BAD_COUNTER = -2, + E_UNKNOWN_CPU = -3, + E_CANT_OPEN_DRIVER = -4, + E_DRIVER_ALREADY_OPEN = -5, + E_DRIVER_NOT_OPEN = -6, + E_DISABLED = -7, + E_BAD_DATA = -8, + E_CANT_CLOSE = -9, + E_ILLEGAL_OPERATION = -10, +}; + +#pragma warning( pop ) + +#endif // PMELIB_H
\ No newline at end of file diff --git a/external/vpc/public/tier0/stackstats.h b/external/vpc/public/tier0/stackstats.h new file mode 100644 index 0000000..a14d64b --- /dev/null +++ b/external/vpc/public/tier0/stackstats.h @@ -0,0 +1,966 @@ +//========= Copyright � 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Tools for grabbing/dumping the stack at runtime +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_STACKSTATS_H +#define TIER0_STACKSTATS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/stacktools.h" +#include "tier0/threadtools.h" + +#if defined ENABLE_RUNTIME_STACK_TRANSLATION +#define ENABLE_STACK_STATS_GATHERING //uncomment to enable the gathering class +#endif + +#if defined ENABLE_STACK_STATS_GATHERING +#include "tier0/valve_off.h" +# include <map> //needed for CCallStackStatsGatherer +# include <vector> +#include "tier0/valve_on.h" +#define CDefaultStatsGathererAllocator std::allocator +#else +template<class _Ty> class CNullStatsGathererAllocator { CNullStatsGathererAllocator( void ) { } }; +#define CDefaultStatsGathererAllocator CNullStatsGathererAllocator +#endif + + +typedef size_t (*FN_DescribeStruct)( uint8 *, size_t ); + +class CCallStackStatsGatherer_Standardized_t; +struct CCallStackStatsGatherer_FunctionTable_t +{ + void (*pfn_GetDumpInfo)( void *, const char *&, size_t &, size_t &, void *&, size_t &, CCallStackStatsGatherer_Standardized_t *&, size_t & ); + void (*pfn_PushSubTree)( void *, const CCallStackStatsGatherer_Standardized_t &, const CCallStackStorage & ); + void (*pfn_PopSubTree)( void * ); + size_t (*pfn_DescribeCallStackStatStruct)( uint8 *, size_t ); + void (*pfn_SyncMutexes)( void *, bool ); + void *(*pfn_GetEntry)( void *, uint32 ); + void (*pfn_ApplyTreeAccessLock)( void *, bool ); + void (*pfn_LockEntry)( void *, uint32, bool ); +}; + +//templatized classes are fun, can't really use a base pointer effectively, so we'll have a translator struct and store pointers to instances of the translator function +class CCallStackStatsGatherer_Standardized_t +{ +public: + CCallStackStatsGatherer_Standardized_t( void ) {}; + CCallStackStatsGatherer_Standardized_t( void *pThis, const CCallStackStatsGatherer_FunctionTable_t &FnTable ) : pGatherer( pThis ), pFunctionTable( &FnTable ) {}; + + //go ahead and create some helper functions that are likely to be used by helper code + void PushSubTree( const CCallStackStatsGatherer_Standardized_t &SubTree, const CCallStackStorage &PushStack = CCallStackStorage() ) const + { + pFunctionTable->pfn_PushSubTree( pGatherer, SubTree, PushStack ); + } + + inline void PopSubTree( void ) const + { + pFunctionTable->pfn_PopSubTree( pGatherer ); + } + + void *pGatherer; + const CCallStackStatsGatherer_FunctionTable_t *pFunctionTable; +}; + +//Designed to be called by an instance of CCallStackStatsGatherer to dump it's data +PLATFORM_INTERFACE bool _CCallStackStatsGatherer_Internal_DumpStatsToFile( const char *szFileName, const CCallStackStatsGatherer_Standardized_t &StatsGatherer, bool bAllowMemoryAllocations ); + + + + + + +template <class STATSTRUCT> +class CCallStackStatsGatherer_StructAccessor_Base +{ +public: + CCallStackStatsGatherer_StructAccessor_Base( const CCallStackStatsGatherer_Standardized_t &Gatherer, int iEntryIndex ) : m_Gatherer( Gatherer ), m_iEntryIndex( iEntryIndex ) {}; +protected: + uint32 m_iEntryIndex; //index of the stat entry we want in the vector. Stored as index as the vector base address can change. + CCallStackStatsGatherer_Standardized_t m_Gatherer; //so we can lock the vector memory in place while manipulating the values +}; + + +class CCallStackStatsGatherer_StatMutexBase +{ +public: + void LockEntry( uint32 iEntryIndex, bool bLock ) {} //true to increase lock refcount, false to decrease +}; + +template <uint32 SHAREDENTRYMUTEXES> //must be a power of 2 +class CCallStackStatsGatherer_StatMutexPool +{ +public: + void LockEntry( uint32 iEntryIndex, bool bLock ) + { +#if defined( ENABLE_STACK_STATS_GATHERING ) + COMPILE_TIME_ASSERT( (SHAREDENTRYMUTEXES & (SHAREDENTRYMUTEXES - 1)) == 0 ); //must be a power of 2 + + if( bLock ) + { + m_IndividualEntryMutexes[iEntryIndex & (SHAREDENTRYMUTEXES - 1)].Lock(); + } + else + { + m_IndividualEntryMutexes[iEntryIndex & (SHAREDENTRYMUTEXES - 1)].Unlock(); + } +#endif + } +protected: + CThreadFastMutex m_IndividualEntryMutexes[SHAREDENTRYMUTEXES]; +}; + + + + +//STATSTRUCT - The structure you'll use to track whatever it is you're tracking. +//CAPTUREDCALLSTACKLENGTH - The maximum length of your stack trace that we'll use to distinguish entries +//STACKACQUISITIONFUNCTION - The function to use to gather the current call stack. GetCallStack() is safe, GetCallStack_Fast() is faster, but has special requirements +//STATMUTEXHANDLER - If you want automatic mutex management for your individual entries, supply a handler here. +// You'll need to not only call GetEntry(), but lock/unlock the entry while accessing it. +//TEMPLATIZEDMEMORYALLOCATOR - We'll need to allocate memory, supply an allocator if you want to manage that +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION = GetCallStack, typename STATMUTEXHANDLER = CCallStackStatsGatherer_StatMutexPool<4>, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR = CDefaultStatsGathererAllocator> +class CCallStackStatsGatherer : public STATMUTEXHANDLER +{ +public: +#if !defined( ENABLE_STACK_STATS_GATHERING ) + CCallStackStatsGatherer( void ) + { + for( size_t i = 0; i != CAPTUREDCALLSTACKLENGTH; ++i ) + m_SingleCallStack[i] = NULL; + } +#endif + + CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH] ); //get the entry using some callstack grabbed a while ago. Assumes ALL invalid entries have been nullified + CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ); //same as above, but does the work of nullifying invalid entries + CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( const CCallStackStorage &PushStack = CCallStackStorage( STACKACQUISITIONFUNCTION ) ); + CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> GetEntry( uint32 iEntryIndex ); + + //get the entry index for the caller's current call stack. Pre-nullified entries count as valid entries (and save re-nullification work) + uint32 GetEntryIndex( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ); //index is unchanging, safe to keep and use later (designed for exactly that purpose) + uint32 GetEntryIndex( const CCallStackStorage &PushStack = CCallStackStorage( STACKACQUISITIONFUNCTION ) ); + + + + typedef void *(&StackReference)[CAPTUREDCALLSTACKLENGTH]; + StackReference GetCallStackForIndex( uint32 iEntryIndex ) + { +#if defined( ENABLE_STACK_STATS_GATHERING ) + return m_StatEntries[iEntryIndex].m_CallStack; +#else + return m_SingleCallStack; +#endif + } + + void GetCallStackForIndex( uint32 iEntryIndex, void *CallStackOut[CAPTUREDCALLSTACKLENGTH] ); + + size_t NumEntries( void ) const; + + bool DumpToFile( const char *szFileName, bool bAllowMemoryAllocations = true ); + + static const CCallStackStatsGatherer_FunctionTable_t &GetFunctionTable( void ); + + static void GetDumpInfo( void *pThis, const char *&szStructName, size_t &iCapturedStackLength, size_t &iEntrySizeWithStack, void *&pEntries, size_t &iEntryCount, CCallStackStatsGatherer_Standardized_t *&pSubTrees, size_t &iSubTreeCount ); + static void PushSubTree( void *pParent, const CCallStackStatsGatherer_Standardized_t &SubTree, const CCallStackStorage &PushStack ); + + void PushSubTree( CCallStackStatsGatherer_Standardized_t &Parent, const CCallStackStorage &PushStack = CCallStackStorage( STACKACQUISITIONFUNCTION ) ); + + static void PopSubTree( void *pParent ); + static void SyncMutexes( void *pParent, bool bLock ); //true for lock, false for unlock + static void *GetEntry( void *pParent, uint32 iEntryIndex ); + static void ApplyTreeAccessLock( void *pParent, bool bLock ); + static void LockEntry( void *pParent, uint32 iEntryIndex, bool bLock ); + + void Reset( void ); + + + CCallStackStatsGatherer_Standardized_t Standardized( void ); + operator CCallStackStatsGatherer_Standardized_t( void ); + + const static FN_GetCallStack StackFunction; //publish the requested acquisition function so you can easily key all your stack gathering to the class instance + const static size_t CapturedCallStackLength; +private: + +#pragma pack(push) +#pragma pack(1) + struct StackAndStats_t + { + void *m_CallStack[CAPTUREDCALLSTACKLENGTH]; + STATSTRUCT m_Stats; + }; +#pragma pack(pop) + + typedef CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR> ThisCast; + + +#if defined( ENABLE_STACK_STATS_GATHERING ) + + struct IndexMapKey_t + { + IndexMapKey_t( void * const CallStack[CAPTUREDCALLSTACKLENGTH] ) + { + m_Hash = 0; + for( int i = 0; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + m_CallStack[i] = CallStack[i]; + m_Hash += (uintp)CallStack[i]; + } + } + bool operator<( const IndexMapKey_t &key ) const + { + if( m_Hash != key.m_Hash ) + return m_Hash < key.m_Hash; + + //only here if there's a hash match. Do a full check. Extremely likely to be the exact same call stack. But not 100% guaranteed. + for( int i = 0; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + if( m_CallStack[i] == key.m_CallStack[i] ) + { + continue; + } + + return m_CallStack[i] < key.m_CallStack[i]; + } + + return false; //exact same call stack + } + + uintp m_Hash; + void *m_CallStack[CAPTUREDCALLSTACKLENGTH]; + }; + + void KeepSubTree( CCallStackStatsGatherer_Standardized_t &SubTree ) + { + AUTO_LOCK_FM( m_SubTreeMutex ); + for( StoredSubTreeVector_t::iterator treeIter = m_StoredSubTrees.begin(); treeIter != m_StoredSubTrees.end(); ++treeIter ) + { + if( SubTree.pGatherer == treeIter->pGatherer ) + return; + } + + //Warning( "Storing subtree\n" ); + + m_StoredSubTrees.push_back( SubTree ); + } + + uint32 PatchInSubTrees( void * const CallStackIn[CAPTUREDCALLSTACKLENGTH], void *CallStackOut[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ) + { + if( iValidEntries > CAPTUREDCALLSTACKLENGTH ) + { + iValidEntries = CAPTUREDCALLSTACKLENGTH; + } + + AUTO_LOCK_FM( m_SubTreeMutex ); + if( m_PushedSubTrees.size() == 0 ) + { + memcpy( CallStackOut, CallStackIn, sizeof( void * ) * iValidEntries ); + return iValidEntries; + } + + unsigned long iThreadID = ThreadGetCurrentId(); + PushedSubTreeVector_t::reverse_iterator treeIter; + for( treeIter = m_PushedSubTrees.rbegin(); treeIter != m_PushedSubTrees.rend(); ++treeIter ) + { + if( treeIter->iThreadID == iThreadID ) + { + break; + } + } + + if( treeIter == m_PushedSubTrees.rend() ) + { + memcpy( CallStackOut, CallStackIn, sizeof( void * ) * iValidEntries ); + return iValidEntries; + } + + //char szTemp[4096]; + //TranslateStackInfo( CallStackIn, CAPTUREDCALLSTACKLENGTH, szTemp, sizeof( szTemp ), "\n\t" ); + + //Warning( "Attempting to link trees:\n=======================ONE=======================\n\t%s\n", szTemp ); + //TranslateStackInfo( treeIter->Stack, CAPTUREDCALLSTACKLENGTH, szTemp, sizeof( szTemp ), "\n\t" ); + //Warning( "=======================TWO=======================\n\t%s\n", szTemp ); + + void *pMatchAddress = treeIter->Stack[1]; //while the first entry is where the actual push was made. The second entry is the first that is matchable in most cases + + uint32 i; + for( i = 0; i < iValidEntries; ++i ) + { + if( CallStackIn[i] == pMatchAddress ) + { + //TranslateStackInfo( CallStackIn, i, szTemp, sizeof( szTemp ), "\n\t" ); + //Warning( "======================MATCH======================\n\t%s\n", szTemp ); + + CallStackOut[i] = treeIter->tree.pGatherer; //tag this entry as leading into the sub-tree + KeepSubTree( treeIter->tree ); //store the sub-tree forever + return i + 1; + } + CallStackOut[i] = CallStackIn[i]; + } + + return iValidEntries; + + //Warning( "=======================END=======================\n" ); + } + + struct StatIndex_t + { + StatIndex_t( void ) : m_Index((unsigned int)-1) {}; + unsigned int m_Index; + }; + + typedef std::vector<StackAndStats_t, TEMPLATIZEDMEMORYALLOCATOR<StackAndStats_t> > StatVector_t; + typedef std::map< IndexMapKey_t, StatIndex_t, std::less<IndexMapKey_t>, TEMPLATIZEDMEMORYALLOCATOR<std::pair<const IndexMapKey_t, StatIndex_t> > > IndexMap_t; + typedef typename IndexMap_t::iterator IndexMapIter_t; + typedef typename IndexMap_t::value_type IndexMapEntry_t; + + StatVector_t m_StatEntries; + IndexMap_t m_IndexMap; + + struct PushedSubTree_t + { + unsigned long iThreadID; + CCallStackStatsGatherer_Standardized_t tree; + void *Stack[CAPTUREDCALLSTACKLENGTH]; + }; + + typedef std::vector<PushedSubTree_t, TEMPLATIZEDMEMORYALLOCATOR<PushedSubTree_t> > PushedSubTreeVector_t; + PushedSubTreeVector_t m_PushedSubTrees; + + typedef std::vector<CCallStackStatsGatherer_Standardized_t, TEMPLATIZEDMEMORYALLOCATOR<CCallStackStatsGatherer_Standardized_t> > StoredSubTreeVector_t; + StoredSubTreeVector_t m_StoredSubTrees; + + CThreadFastMutex m_IndexMapMutex; + CThreadFastMutex m_SubTreeMutex; + + //only for locking the memory in place, locked for write when the entry addresses might change. + //Locked for read when you've claimed you're manipulating a value. + //You're on your own for making sure two threads don't access the same index simultaneously + CThreadRWLock m_StatEntryLock; + +#else //#if defined( ENABLE_STACK_STATS_GATHERING ) + + STATSTRUCT m_SingleEntry; //the class is disabled, we'll always return this same struct + void *m_SingleCallStack[CAPTUREDCALLSTACKLENGTH]; + + static size_t NULL_DescribeCallStackStatStruct( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) { return 0; } + +#endif //#if defined( ENABLE_STACK_STATS_GATHERING ) +}; + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +const FN_GetCallStack CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::StackFunction = STACKACQUISITIONFUNCTION; + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +const size_t CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::CapturedCallStackLength = CAPTUREDCALLSTACKLENGTH; + +#if defined( ENABLE_STACK_STATS_GATHERING ) + +class CallStackStatStructDescFuncs; +PLATFORM_INTERFACE size_t _CCallStackStatsGatherer_Write_FieldDescriptions( CallStackStatStructDescFuncs *pFieldDescriptions, uint8 *pWriteBuffer, size_t iWriteBufferSize ); +//PLATFORM_INTERFACE size_t _CCallStackStatsGatherer_Write_FieldMergeScript( CallStackStatStructDescFuncs *pFieldDescriptions, CallStackStatStructDescFuncs::MergeScript_Language scriptMergeLanguage, uint8 *pWriteBuffer, size_t iWriteBufferSize ); + +#define DECLARE_CALLSTACKSTATSTRUCT() static const char *STATSTRUCTSTRINGNAME;\ + static size_t DescribeCallStackStatStruct( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ); + +#define BEGIN_STATSTRUCTDESCRIPTION( className ) const char *className::STATSTRUCTSTRINGNAME = #className;\ + size_t className::DescribeCallStackStatStruct( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) {\ + size_t iWroteBytes = 0; +#define END_STATSTRUCTDESCRIPTION() return iWroteBytes; } + + +#define DECLARE_CALLSTACKSTATSTRUCT_FIELDDESCRIPTION() static CallStackStatStructDescFuncs *GetStatStructFieldDescriptions( void ); + +#define BEGIN_STATSTRUCTFIELDDESCRIPTION( className ) CallStackStatStructDescFuncs * className::GetStatStructFieldDescriptions( void ) {\ + typedef className ThisStruct;\ + CallStackStatStructDescFuncs *_pHeadLinkage = NULL;\ + CallStackStatStructDescFuncs **_pLinkageHelperVar = &_pHeadLinkage; + +#define _DEFINE_STATSTRUCTFIELD_VARNAME( varName, fieldName, fieldStruct, fieldParmsInParentheses ) static fieldStruct varName##_desc##fieldParmsInParentheses;\ + varName##_desc.m_szFieldName = #fieldName;\ + varName##_desc.m_iFieldOffset = (size_t)(&((ThisStruct *)NULL)->fieldName);\ + varName##_desc.m_pNext = NULL;\ + *_pLinkageHelperVar = &varName##_desc;\ + _pLinkageHelperVar = &varName##_desc.m_pNext; + +#define DEFINE_STATSTRUCTFIELD( fieldName, fieldStruct, fieldParmsInParentheses ) _DEFINE_STATSTRUCTFIELD_VARNAME( fieldName, fieldName, fieldStruct, fieldParmsInParentheses ) +#define DEFINE_STATSTRUCTFIELD_ARRAYENTRY( arrayName, arrayIndex, fieldStruct, fieldParmsInParentheses ) _DEFINE_STATSTRUCTFIELD_VARNAME( arrayName##_##arrayIndex, arrayName##[##arrayIndex##], fieldStruct, fieldParmsInParentheses ) + +#define END_STATSTRUCTFIELDDESCRIPTION() static CallStackStatStructDescFuncs *s_pHeadStruct = _pHeadLinkage;\ + return s_pHeadStruct; } + +#define WRITE_STATSTRUCT_FIELDDESCRIPTION() iWroteBytes += _CCallStackStatsGatherer_Write_FieldDescriptions( GetStatStructFieldDescriptions(), pDescribeWriteBuffer + iWroteBytes, iDescribeMaxLength - iWroteBytes ); +//#define WRITE_STATSTRUCT_FIELDMERGESCRIPT( scriptMergeLanguage ) iWroteBytes += _CCallStackStatsGatherer_Write_FieldMergeScript( GetStatStructFieldDescriptions(), CallStackStatStructDescFuncs::scriptMergeLanguage, pDescribeWriteBuffer + iWroteBytes, iDescribeMaxLength - iWroteBytes ); + + +#else //#if defined( ENABLE_STACK_STATS_GATHERING ) + +#define DECLARE_CALLSTACKSTATSTRUCT() +#define BEGIN_STATSTRUCTDESCRIPTION( className ) +#define END_STATSTRUCTDESCRIPTION() + +#define DECLARE_CALLSTACKSTATSTRUCT_FIELDDESCRIPTION() +#define BEGIN_STATSTRUCTFIELDDESCRIPTION( className ) +#define DEFINE_STATSTRUCTFIELD( fieldName, fieldStruct, fieldParmsInParentheses ) +#define END_STATSTRUCTFIELDDESCRIPTION() + +#define WRITE_STATSTRUCT_FIELDDESCRIPTION() +//#define WRITE_STATSTRUCT_FIELDMERGESCRIPT( scriptMergeLanguage ) + +#endif //#if defined( ENABLE_STACK_STATS_GATHERING ) + + + + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH] ) //get the entry using some callstack grabbed a while ago. Assumes ALL invalid entries have been nullified +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + return GetEntry( GetEntryIndex( CallStack ) ); +#else + return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 ); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ) //same as above, but does the work of nullifying invalid entries +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + void *CleanedCallStack[CAPTUREDCALLSTACKLENGTH]; + size_t i; + for( i = 0; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + CleanedCallStack[i] = CallStack[i]; + } + + for( ; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + CleanedCallStack[i] = NULL; + } + return GetEntry( GetEntryIndex( CleanedCallStack ) ); +#else + return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 ); +#endif +} + + + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( const CCallStackStorage &PushStack ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + COMPILE_TIME_ASSERT( CAPTUREDCALLSTACKLENGTH <= ARRAYSIZE( PushStack.pStack ) ); + return GetEntry( GetEntryIndex( PushStack.pStack, PushStack.iValidEntries ) ); +#else + return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 ); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +uint32 CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntryIndex( const CCallStackStorage &PushStack ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + COMPILE_TIME_ASSERT( CAPTUREDCALLSTACKLENGTH <= ARRAYSIZE( PushStack.pStack ) ); + return GetEntryIndex( PushStack.pStack, PushStack.iValidEntries ); +#else + return 0; +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( uint32 iEntryIndex ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), iEntryIndex ); +#else + return CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( Standardized(), 0 ); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +uint32 CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntryIndex( void * const CallStack[CAPTUREDCALLSTACKLENGTH], uint32 iValidEntries ) //index is unchanging, safe to keep and use later (designed for exactly that purpose) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + AUTO_LOCK_FM( m_IndexMapMutex ); + std::pair<IndexMapIter_t, bool> indexMapIter; + void *PatchedStack[CAPTUREDCALLSTACKLENGTH]; + + //if we have a sub-tree. We'll be splicing it into the original call stack as if it were a return address. Then patching that when we interpret the results later + //A stack with a sub-tree along the line is treated as distinctly different than one without a sub-tree + iValidEntries = PatchInSubTrees( CallStack, PatchedStack, iValidEntries ); + + Assert( iValidEntries <= CAPTUREDCALLSTACKLENGTH ); + + for( int i = iValidEntries; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + PatchedStack[i] = NULL; + } + + indexMapIter = m_IndexMap.insert( IndexMapEntry_t( IndexMapKey_t( PatchedStack ), StatIndex_t() ) ); + + if( indexMapIter.first->second.m_Index == -1 ) + { + m_StatEntryLock.LockForWrite(); + indexMapIter.first->second.m_Index = (unsigned int)m_StatEntries.size(); + + m_StatEntries.push_back( StackAndStats_t() ); + memcpy( m_StatEntries[indexMapIter.first->second.m_Index].m_CallStack, PatchedStack, sizeof( void * ) * CAPTUREDCALLSTACKLENGTH ); + m_StatEntryLock.UnlockWrite(); + } + + return indexMapIter.first->second.m_Index; +#else + return 0; +#endif +} + + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetCallStackForIndex( uint32 iEntryIndex, void *CallStackOut[CAPTUREDCALLSTACKLENGTH] ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + m_StatEntryLock.LockForRead(); + for( size_t i = 0; i != CAPTUREDCALLSTACKLENGTH; ++i ) + { + CallStackOut[i] = m_StatEntries[iEntryIndex].m_CallStack[i]; + } + m_StatEntryLock.UnlockRead(); +#else + for( size_t i = 0; i != CAPTUREDCALLSTACKLENGTH; ++i ) + CallStackOut[i] = NULL; +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +size_t CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::NumEntries( void ) const +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + return m_StatEntries.size(); +#else + return 0; +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +bool CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::DumpToFile( const char *szFileName, bool bAllowMemoryAllocations ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + CCallStackStatsGatherer_Standardized_t StandardThis = Standardized(); + SyncMutexes( this, true ); + bool bRetVal = _CCallStackStatsGatherer_Internal_DumpStatsToFile( szFileName, StandardThis, bAllowMemoryAllocations ); + SyncMutexes( this, false ); + return bRetVal; +#else + return false; +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +const CCallStackStatsGatherer_FunctionTable_t &CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetFunctionTable( void ) +{ + static CCallStackStatsGatherer_FunctionTable_t retVal = + { GetDumpInfo, + PushSubTree, + PopSubTree, +#if defined( ENABLE_STACK_STATS_GATHERING ) + STATSTRUCT::DescribeCallStackStatStruct, +#else + NULL_DescribeCallStackStatStruct, +#endif + SyncMutexes, + GetEntry, + ApplyTreeAccessLock, + LockEntry }; + + return retVal; +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetDumpInfo( void *pThis, const char *&szStructName, size_t &iCapturedStackLength, size_t &iEntrySizeWithStack, void *&pEntries, size_t &iEntryCount, CCallStackStatsGatherer_Standardized_t *&pSubTrees, size_t &iSubTreeCount ) +{ + ThisCast *pThisCast = (ThisCast *)pThis; + iCapturedStackLength = CAPTUREDCALLSTACKLENGTH; + iEntrySizeWithStack = sizeof( CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::StackAndStats_t ); + +#if defined( ENABLE_STACK_STATS_GATHERING ) + szStructName = STATSTRUCT::STATSTRUCTSTRINGNAME; + iEntryCount = pThisCast->m_StatEntries.size(); + pEntries = iEntryCount > 0 ? &pThisCast->m_StatEntries[0] : NULL; + iSubTreeCount = pThisCast->m_StoredSubTrees.size(); + pSubTrees = iSubTreeCount > 0 ? &pThisCast->m_StoredSubTrees[0] : NULL; +#else + szStructName = ""; + iEntryCount = 0; + pEntries = NULL; + iSubTreeCount = 0; + pSubTrees = NULL; +#endif +} + + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::PushSubTree( void *pParent, const CCallStackStatsGatherer_Standardized_t &SubTree, const CCallStackStorage &PushStack ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + ThisCast *pParentCast = (ThisCast *)pParent; + PushedSubTree_t pushVal; + pushVal.iThreadID = ThreadGetCurrentId(); + pushVal.tree = SubTree; + + memcpy( pushVal.Stack, PushStack.pStack, MIN( CAPTUREDCALLSTACKLENGTH, PushStack.iValidEntries ) * sizeof( void * ) ); + + for( int i = PushStack.iValidEntries; i < CAPTUREDCALLSTACKLENGTH; ++i ) + { + pushVal.Stack[i] = NULL; + } + + pParentCast->m_SubTreeMutex.Lock(); + pParentCast->m_PushedSubTrees.push_back( pushVal ); + pParentCast->m_SubTreeMutex.Unlock(); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::PushSubTree( CCallStackStatsGatherer_Standardized_t &Parent, const CCallStackStorage &PushStack ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + CCallStackStatsGatherer_Standardized_t StandardThis = Standardized(); + Parent.PushSubTree( StandardThis, PushStack ); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::PopSubTree( void *pParent ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + ThisCast *pParentCast = (ThisCast *)pParent; + pParentCast->m_SubTreeMutex.Lock(); + unsigned long iThreadID = ThreadGetCurrentId(); + + for( PushedSubTreeVector_t::reverse_iterator treeIter = pParentCast->m_PushedSubTrees.rbegin(); treeIter != pParentCast->m_PushedSubTrees.rend(); ++treeIter ) + { + if( treeIter->iThreadID == iThreadID ) + { + ++treeIter; //[24.4.1/1] &*(reverse_iterator(i)) == &*(i - 1) + PushedSubTreeVector_t::iterator eraseIter = treeIter.base(); + pParentCast->m_PushedSubTrees.erase(eraseIter); + break; + } + } + + pParentCast->m_SubTreeMutex.Unlock(); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::SyncMutexes( void *pParent, bool bLock ) //true for lock, false for unlock +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + ThisCast *pParentCast = (ThisCast *)pParent; + if( bLock ) + { + pParentCast->m_IndexMapMutex.Lock(); + pParentCast->m_SubTreeMutex.Lock(); + + for( StoredSubTreeVector_t::iterator treeIter = pParentCast->m_StoredSubTrees.begin(); treeIter != pParentCast->m_StoredSubTrees.end(); ++treeIter ) + { + treeIter->pFunctionTable->pfn_SyncMutexes( treeIter->pGatherer, true ); + } + } + else + { + for( StoredSubTreeVector_t::iterator treeIter = pParentCast->m_StoredSubTrees.begin(); treeIter != pParentCast->m_StoredSubTrees.end(); ++treeIter ) + { + treeIter->pFunctionTable->pfn_SyncMutexes( treeIter->pGatherer, false ); + } + + pParentCast->m_IndexMapMutex.Unlock(); + pParentCast->m_SubTreeMutex.Unlock(); + } +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void *CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::GetEntry( void *pParent, uint32 iEntryIndex ) +{ + ThisCast *pParentCast = (ThisCast *)pParent; +#if defined( ENABLE_STACK_STATS_GATHERING ) + return &pParentCast->m_StatEntries[iEntryIndex].m_Stats; +#else + return &pParentCast->m_SingleEntry; +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::ApplyTreeAccessLock( void *pParent, bool bLock ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + ThisCast *pParentCast = (ThisCast *)pParent; + if( bLock ) + { + pParentCast->m_StatEntryLock.LockForRead(); + } + else + { + pParentCast->m_StatEntryLock.UnlockRead(); + } +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::LockEntry( void *pParent, uint32 iEntryIndex, bool bLock ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + ThisCast *pParentCast = (ThisCast *)pParent; + pParentCast->STATMUTEXHANDLER::LockEntry( iEntryIndex, bLock ); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +void CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::Reset( void ) +{ +#if defined( ENABLE_STACK_STATS_GATHERING ) + m_StatEntryLock.LockForWrite(); + m_IndexMapMutex.Lock(); + m_SubTreeMutex.Lock(); + + m_StatEntries.clear(); + m_IndexMap.clear(); + m_StoredSubTrees.clear(); + + m_SubTreeMutex.Unlock(); + m_IndexMapMutex.Unlock(); + m_StatEntryLock.UnlockWrite(); +#endif +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::operator CCallStackStatsGatherer_Standardized_t( void ) +{ + return CCallStackStatsGatherer_Standardized_t( this, GetFunctionTable() ); +} + +template <class STATSTRUCT, size_t CAPTUREDCALLSTACKLENGTH, FN_GetCallStack STACKACQUISITIONFUNCTION, typename STATMUTEXHANDLER, template <typename T> class TEMPLATIZEDMEMORYALLOCATOR> +CCallStackStatsGatherer_Standardized_t CCallStackStatsGatherer<STATSTRUCT, CAPTUREDCALLSTACKLENGTH, STACKACQUISITIONFUNCTION, STATMUTEXHANDLER, TEMPLATIZEDMEMORYALLOCATOR>::Standardized( void ) +{ + return CCallStackStatsGatherer_Standardized_t( this, GetFunctionTable() ); +} + + + + + + + + + + + + + + + + + + +class PLATFORM_CLASS CallStackStatStructDescFuncs +{ +public: + //description file format + //1 byte version per entry. Assuming that the field will get more descriptive over time, reserving this now. + virtual size_t DescribeField( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) = 0; + + enum MergeScript_Language + { + SSMSL_Squirrel, //Only support squirrel for now, theoretically expandable to any vscript supported language + }; + +#if 0 //embedded script handling not ready yet + //this is expected to write a piece of script code into the body of a function that will merge two values of this type + //The function will have two parameters, "mergeTo", and "mergeFrom". Both are tables with your field defined by name + //So, an example to merge an integer count defined as "foo" in the stack struct would look like this "mergeTo.foo += mergeFrom.foo\n" + virtual size_t DescribeMergeOperation( MergeScript_Language scriptLanguage, uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ) = 0; +#endif + + //reserve your description field versions here to avoid stomping others + enum DescribeFieldVersions_t + { + DFV_BasicStatStructFieldTypes_t, //Format: 1 byte BasicStatStructFieldTypes_t type, 4 byte field offset, null terminated string field name + }; + + const char *m_szFieldName; + size_t m_iFieldOffset; + CallStackStatStructDescFuncs *m_pNext; //needed for how the description macros are laid out. Couldn't figure out a way to store the static struct instances as a static array +}; + +enum StatStructDescription_LumpID +{ + SSDLID_UNKNOWN, + SSDLID_STATICINTERPRETER, + SSDLID_FIELDDESC, + SSDLID_EMBEDDEDSCRIPT, + + + SSDLID_COUNT, + SSDLID_FORCE_UINT32 = 0xFFFFFFFF, +}; + +enum BasicStatStructFieldTypes_t +{ + BSSFT_UNKNOWN, + BSSFT_BOOL, + BSSFT_INT8, + BSSFT_UINT8, + BSSFT_INT16, + BSSFT_UINT16, + BSSFT_INT32, + BSSFT_UINT32, + BSSFT_INT64, + BSSFT_UINT64, + BSSFT_FLOAT, + BSSFT_DOUBLE, + BSSFT_VECTOR2D, + BSSFT_VECTOR3D, + BSSFT_VECTOR4D, + + BSSFT_COUNT, +}; + +#define BSSFT_INT (sizeof( int ) == sizeof( int32 ) ? BSSFT_INT32 : BSSFT_INT64) +#define BSSFT_UINT (sizeof( unsigned int ) == sizeof( uint32 ) ? BSSFT_UINT32 : BSSFT_UINT64) +#define BSSFT_SIZE_T (sizeof( size_t ) == sizeof( uint32 ) ? BSSFT_UINT32 : BSSFT_UINT64) + +enum BasicStatStructFieldCombineMethods_t +{ + BSSFCM_UNKNOWN, + BSSFCM_CUSTOM, //rely on some outside handler + BSSFCM_ADD, //add the values + //BSSFCM_SUBTRACT, //what would subtract even mean? which one from which? + BSSFCM_MAX, //keep max value + BSSFCM_MIN, //keep min value + BSSFCM_AND, // &= , Non-integer behavior undefined + BSSFCM_OR, // |= , Non-integer behavior undefined + BSSFCM_XOR, // ^= , Non-integer behavior undefined + /*BSSFCM_LIST, //keep a list of each value (probably complicated)*/ + + BSSFCM_COUNT, +}; + +class PLATFORM_CLASS BasicStatStructFieldDesc : public CallStackStatStructDescFuncs +{ +public: + BasicStatStructFieldDesc( BasicStatStructFieldTypes_t type, BasicStatStructFieldCombineMethods_t combineMethod ) : m_Type(type), m_Combine(combineMethod) {}; + size_t DescribeField( uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ); +#if 0 //embedded script handling not ready yet + size_t DescribeMergeOperation( MergeScript_Language scriptLanguage, uint8 *pDescribeWriteBuffer, size_t iDescribeMaxLength ); +#endif + + BasicStatStructFieldTypes_t m_Type; + BasicStatStructFieldCombineMethods_t m_Combine; +}; + + + + + + + +//struct is locked in place while you're holding onto one of these. Get a base, then create one of these from it +template <class STATSTRUCT> +class CCallStackStatsGatherer_StructAccessor_AutoLock : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> +{ +public: + CCallStackStatsGatherer_StructAccessor_AutoLock( CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> ©From ) + : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( copyFrom ) + { + this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, true ); + this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, true ); + this->m_pStruct = (STATSTRUCT *)this->m_Gatherer.pFunctionTable->pfn_GetEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex ); + } + + ~CCallStackStatsGatherer_StructAccessor_AutoLock( void ) + { + this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, false ); + this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, false ); + } + + STATSTRUCT *operator->() + { + return this->m_pStruct; + } + + STATSTRUCT *GetStruct( void ) //do not hold this pointer outside the lock period + { + return this->m_pStruct; + } + +protected: + STATSTRUCT *m_pStruct; +}; + + +//struct is locked in place only between Lock() and paired Unlock() calls. Get a base, then create one of these from it. +//It's safe to hold onto this for an extended period of time. The entry index is unchanging in the gatherer tree. +template <class STATSTRUCT> +class CCallStackStatsGatherer_StructAccessor_Manual : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> +{ +public: + CCallStackStatsGatherer_StructAccessor_Manual( CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT> ©From ) + : CCallStackStatsGatherer_StructAccessor_Base<STATSTRUCT>( copyFrom ), m_pStruct( NULL ) + { } + + STATSTRUCT *operator->() + { + return this->m_pStruct; //NULL while entry is not locked. + } + + STATSTRUCT *GetStruct( void ) //do not hold this pointer outside the lock period + { + return this->m_pStruct; //NULL while entry is not locked. + } + + void Lock( void ) + { + this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, true ); + this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, true ); + this->m_pStruct = (STATSTRUCT *)this->m_Gatherer.pFunctionTable->pfn_GetEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex ); + } + + void Unlock( void ) + { + this->m_pStruct = NULL; + this->m_Gatherer.pFunctionTable->pfn_LockEntry( this->m_Gatherer.pGatherer, this->m_iEntryIndex, false ); + this->m_Gatherer.pFunctionTable->pfn_ApplyTreeAccessLock( this->m_Gatherer.pGatherer, false ); + } + +protected: + STATSTRUCT *m_pStruct; +}; + + + + + +class CCallStackStats_PushSubTree_AutoPop +{ +public: + CCallStackStats_PushSubTree_AutoPop( const CCallStackStatsGatherer_Standardized_t &Parent, const CCallStackStatsGatherer_Standardized_t &Child, const CCallStackStorage &PushStack = CCallStackStorage() ) + : m_PopFrom( Parent ) + { + Parent.pFunctionTable->pfn_PushSubTree( Parent.pGatherer, Child, PushStack ); + } + ~CCallStackStats_PushSubTree_AutoPop( void ) + { + m_PopFrom.PopSubTree(); + } + + CCallStackStatsGatherer_Standardized_t m_PopFrom; +}; + + +#endif //#ifndef TIER0_STACKTOOLS_H diff --git a/external/vpc/public/tier0/stacktools.h b/external/vpc/public/tier0/stacktools.h new file mode 100644 index 0000000..c356b8c --- /dev/null +++ b/external/vpc/public/tier0/stacktools.h @@ -0,0 +1,153 @@ +//========= Copyright � 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Purpose: Tools for grabbing/dumping the stack at runtime +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef TIER0_STACKTOOLS_H +#define TIER0_STACKTOOLS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +#if (defined( PLATFORM_WINDOWS ) || defined( PLATFORM_X360 )) && !defined( STEAM ) && !defined( _CERT ) && defined( TCHAR_IS_CHAR ) //designed for windows/x360, not built/tested with wide characters, not intended for release builds (but probably wouldn't damage anything) +# define ENABLE_RUNTIME_STACK_TRANSLATION //uncomment to enable runtime stack translation tools. All of which use on-demand loading of necessary dll's and pdb's +#endif + +#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) +//#define ENABLE_THREAD_PARENT_STACK_TRACING 1 //uncomment to actually enable tracking stack traces from threads and jobs to their parent thread. Must also define THREAD_PARENT_STACK_TRACE_SUPPORTED in threadtools.h +# if defined( ENABLE_THREAD_PARENT_STACK_TRACING ) +# define THREAD_PARENT_STACK_TRACE_LENGTH 32 +# endif +#endif + + + + +PLATFORM_INTERFACE int GetCallStack( void **pReturnAddressesOut, int iArrayCount, int iSkipCount ); + +//ONLY WORKS IF THE CRAWLED PORTION OF THE STACK DISABLES FRAME POINTER OMISSION (/Oy-) "vpc /nofpo" +PLATFORM_INTERFACE int GetCallStack_Fast( void **pReturnAddressesOut, int iArrayCount, int iSkipCount ); + +typedef int (*FN_GetCallStack)( void **pReturnAddressesOut, int iArrayCount, int iSkipCount ); + +//where we'll find our PDB's for win32. +PLATFORM_INTERFACE void SetStackTranslationSymbolSearchPath( const char *szSemicolonSeparatedList = NULL ); +PLATFORM_INTERFACE void StackToolsNotify_LoadedLibrary( const char *szLibName ); + +//maximum output sample "tier0.dll!TranslateStackInfo - u:\Dev\L4D\src\tier0\stacktools.cpp(162) + 4 bytes" +enum TranslateStackInfo_StyleFlags_t +{ + TSISTYLEFLAG_NONE = 0, + TSISTYLEFLAG_MODULENAME = (1<<0), //start with module Sample: "tier0.dll!" + TSISTYLEFLAG_SYMBOLNAME = (1<<1), //include the symbol name Sample: "TranslateStackInfo" + TSISTYLEFLAG_FULLPATH = (1<<2), //include full path Sample: "u:\Dev\L4D\src\tier0\stacktools.cpp" + TSISTYLEFLAG_SHORTPATH = (1<<3), //only include 2 directories Sample: "\src\tier0\stacktools.cpp" + TSISTYLEFLAG_LINE = (1<<4), //file line number Sample: "(162)" + TSISTYLEFLAG_LINEANDOFFSET = (1<<5), //file line + offset Sample: "(162) + 4 bytes" + TSISTYLEFLAG_LAST = TSISTYLEFLAG_LINEANDOFFSET, + TSISTYLEFLAG_DEFAULT = (TSISTYLEFLAG_MODULENAME | TSISTYLEFLAG_SYMBOLNAME | TSISTYLEFLAG_FULLPATH | TSISTYLEFLAG_LINEANDOFFSET), //produces sample above +}; + +//Generates a formatted list of function information, returns number of translated entries +//On 360 this generates a string that can be decoded by VXConsole in print functions. Optimal path for translation because it's one way. Other paths require multiple transactions. +PLATFORM_INTERFACE int TranslateStackInfo( const void * const *pCallStack, int iCallStackCount, tchar *szOutput, int iOutBufferSize, const tchar *szEntrySeparator, TranslateStackInfo_StyleFlags_t style = TSISTYLEFLAG_DEFAULT ); + +PLATFORM_INTERFACE void PreloadStackInformation( void * const *pAddresses, int iAddressCount ); //caches data and reduces communication with VXConsole to speed up 360 decoding when using any of the Get***FromAddress() functions. Nop on PC. +PLATFORM_INTERFACE bool GetFileAndLineFromAddress( const void *pAddress, tchar *pFileNameOut, int iMaxFileNameLength, uint32 &iLineNumberOut, uint32 *pDisplacementOut = NULL ); +PLATFORM_INTERFACE bool GetSymbolNameFromAddress( const void *pAddress, tchar *pSymbolNameOut, int iMaxSymbolNameLength, uint64 *pDisplacementOut = NULL ); +PLATFORM_INTERFACE bool GetModuleNameFromAddress( const void *pAddress, tchar *pModuleNameOut, int iMaxModuleNameLength ); + + + +class PLATFORM_CLASS CCallStackStorage //a helper class to grab a stack trace as close to the leaf code surface as possible, then pass it on to deeper functions intact with less unpredictable inlining pollution +{ +public: + CCallStackStorage( FN_GetCallStack GetStackFunction = GetCallStack, uint32 iSkipCalls = 0 ); + CCallStackStorage( const CCallStackStorage ©From ) + { + iValidEntries = copyFrom.iValidEntries; + memcpy( pStack, copyFrom.pStack, sizeof( void * ) * copyFrom.iValidEntries ); + } + + void *pStack[128]; //probably too big, possibly too small for some applications. Don't want to spend the time figuring out how to generalize this without templatizing pollution or mallocs + uint32 iValidEntries; +}; + + +//Hold onto one of these to denote the top of a functional stack trace. Also allows us to string together threads to their parents +class PLATFORM_CLASS CStackTop_Base +{ +protected: +#if defined( ENABLE_RUNTIME_STACK_TRANSLATION ) + CStackTop_Base *m_pPrevTop; + void *m_pStackBase; + void *m_pReplaceAddress; + + void * const *m_pParentStackTrace; + int m_iParentStackTraceLength; +#endif +}; + +//makes a copy of the parent stack +class PLATFORM_CLASS CStackTop_CopyParentStack : public CStackTop_Base +{ +public: + CStackTop_CopyParentStack( void * const * pParentStackTrace, int iParentStackTraceLength ); + ~CStackTop_CopyParentStack( void ); +}; + +//just references the parent stack. Assuming that you'll keep that memory around as long as you're keeping this Stack Top marker. +class PLATFORM_CLASS CStackTop_ReferenceParentStack : public CStackTop_Base +{ +public: + CStackTop_ReferenceParentStack( void * const * pParentStackTrace = NULL, int iParentStackTraceLength = 0 ); + ~CStackTop_ReferenceParentStack( void ); + void ReleaseParentStackReferences( void ); //in case you need to delete the parent stack trace before this class goes out of scope +}; + + +//Encodes data so that every byte's most significant bit is a 1. Ensuring no null terminators. +//This puts the encoded data in the 128-255 value range. Leaving all standard ascii characters for control. +//Returns string length (not including the written null terminator as is standard). +//Or if the buffer is too small. Returns negative of necessary buffer size (including room needed for null terminator) +PLATFORM_INTERFACE int EncodeBinaryToString( const void *pToEncode, int iDataLength, char *pEncodeOut, int iEncodeBufferSize ); + +//Decodes a string produced by EncodeBinaryToString(). Safe to decode in place if you don't mind trashing your string, binary byte count always less than string byte count. +//Returns: +// >= 0 is the decoded data size +// INT_MIN (most negative value possible) indicates an improperly formatted string (not our data) +// all other negative values are the negative of how much dest buffer size is necessary. +PLATFORM_INTERFACE int DecodeBinaryFromString( const char *pString, void *pDestBuffer, int iDestBufferSize, char **ppParseFinishOut = NULL ); + + + + +// 360<->VXConsole specific communication definitions +#define XBX_CALLSTACKDECODEPREFIX ":CSDECODE[" + +enum StackTranslation_BinaryHandler_Command_t +{ + ST_BHC_LOADEDLIBARY, + ST_BHC_GETTRANSLATIONINFO, +}; + +#pragma pack(push) +#pragma pack(1) +struct FullStackInfo_t +{ + const void *pAddress; + char szModuleName[24]; + char szFileName[MAX_PATH/2]; + char szSymbol[64]; + uint32 iLine; + uint32 iSymbolOffset; + +}; +#pragma pack(pop) + +#endif //#ifndef TIER0_STACKTOOLS_H diff --git a/external/vpc/public/tier0/threadtools.h b/external/vpc/public/tier0/threadtools.h new file mode 100644 index 0000000..458675a --- /dev/null +++ b/external/vpc/public/tier0/threadtools.h @@ -0,0 +1,2402 @@ +//========== Copyright 2005, Valve Corporation, All rights reserved. ======== +// +// Purpose: A collection of utility classes to simplify thread handling, and +// as much as possible contain portability problems. Here avoiding +// including windows.h. +// +//============================================================================= + +#ifndef THREADTOOLS_H +#define THREADTOOLS_H + +#include <limits.h> + +#include "tier0/platform.h" +#include "tier0/dbg.h" + +#if defined( POSIX ) && !defined( _PS3 ) && !defined( _X360 ) +#include <pthread.h> +#include <errno.h> +#define WAIT_OBJECT_0 0 +#define WAIT_TIMEOUT 0x00000102 +#define WAIT_FAILED -1 +#define THREAD_PRIORITY_HIGHEST 2 +#endif + +#if defined( _PS3 ) +#include <sys/ppu_thread.h> +#include <sys/synchronization.h> +#include <cell/atomic.h> +#include <sys/timer.h> +#endif + +#ifdef OSX +// Add some missing defines +#define PTHREAD_MUTEX_TIMED_NP PTHREAD_MUTEX_NORMAL +#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE +#define PTHREAD_MUTEX_ERRORCHECK_NP PTHREAD_MUTEX_ERRORCHECK +#define PTHREAD_MUTEX_ADAPTIVE_NP 3 +#endif + +#ifdef _PS3 +#define PS3_SYS_PPU_THREAD_COMMON_STACK_SIZE ( 256 * 1024 ) +#endif + + +#if defined( _WIN32 ) +#pragma once +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +#ifdef COMPILER_MSVC64 +#include <intrin.h> +#endif + +// #define THREAD_PROFILER 1 + +#define THREAD_MUTEX_TRACING_SUPPORTED +#if defined(_WIN32) && defined(_DEBUG) +#define THREAD_MUTEX_TRACING_ENABLED +#endif + +#ifdef _WIN32 +typedef void *HANDLE; +#endif + +// maximum number of threads that can wait on one object +#define CTHREADEVENT_MAX_WAITING_THREADS 4 + +#if (defined( PLATFORM_WINDOWS_PC ) || defined( PLATFORM_X360 )) && !defined( STEAM ) && !defined( _CERT ) +//Thread parent stack trace linkage requires ALL executing binaries to disable frame pointer omission to operate speedily/successfully. (/Oy-) "vpc /nofpo" +#define THREAD_PARENT_STACK_TRACE_SUPPORTED 1 //uncomment to support joining the root of a thread's stack trace to its parent's at time of invocation. Must also set ENABLE_THREAD_PARENT_STACK_TRACING in stacktools.h +#endif + +#if defined( THREAD_PARENT_STACK_TRACE_SUPPORTED ) +#include "tier0/stacktools.h" +# if defined( ENABLE_THREAD_PARENT_STACK_TRACING ) //stacktools.h opted in +# define THREAD_PARENT_STACK_TRACE_ENABLED 1 //both threadtools.h and stacktools.h have opted into the feature, enable it +# endif +#endif + +extern bool gbCheckNotMultithreaded; + +#ifdef _PS3 + +#define USE_INTRINSIC_INTERLOCKED + +#define CHECK_NOT_MULTITHREADED() \ +{ \ + static int init = 0; \ + static sys_ppu_thread_t threadIDPrev; \ + \ + if (!init) \ + { \ + sys_ppu_thread_get_id(&threadIDPrev); \ + init = 1; \ + } \ + else if (gbCheckNotMultithreaded) \ + { \ + sys_ppu_thread_t threadID; \ + sys_ppu_thread_get_id(&threadID); \ + if (threadID != threadIDPrev) \ + { \ + printf("CHECK_NOT_MULTITHREADED: prev thread = %x, cur thread = %x\n", \ + (uint)threadIDPrev, (uint)threadID); \ + *(int*)0 = 0; \ + } \ + } \ +} + +#else + #define CHECK_NOT_MULTITHREADED() +#endif + +#if defined( _X360 ) || defined( _PS3 ) +#define MAX_THREADS_SUPPORTED 16 +#else +#define MAX_THREADS_SUPPORTED 32 +#endif + + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +const unsigned TT_INFINITE = 0xffffffff; + +#ifdef PLATFORM_64BITS +typedef uint64 ThreadId_t; +#else +typedef uint32 ThreadId_t; +#endif + +//----------------------------------------------------------------------------- +// +// Simple thread creation. Differs from VCR mode/CreateThread/_beginthreadex +// in that it accepts a standard C function rather than compiler specific one. +// +//----------------------------------------------------------------------------- +#ifdef COMPILER_SNC +typedef uint64 ThreadHandle_t; +#else // COMPILER_SNC +FORWARD_DECLARE_HANDLE( ThreadHandle_t ); +#endif // !COMPILER_SNC +typedef uintp (*ThreadFunc_t)( void *pParam ); + +#if defined( _PS3 ) +PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0x10000 /*64*/ ); +PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0x10000 /*64*/ ); +#else //_PS3 +PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0 ); +PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0 ); +#endif //_PS3 +PLATFORM_INTERFACE bool ReleaseThreadHandle( ThreadHandle_t ); + + +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0); +PLATFORM_INTERFACE ThreadId_t ThreadGetCurrentId(); +PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle(); +PLATFORM_INTERFACE int ThreadGetPriority( ThreadHandle_t hThread = NULL ); +PLATFORM_INTERFACE bool ThreadSetPriority( ThreadHandle_t hThread, int priority ); +inline bool ThreadSetPriority( int priority ) { return ThreadSetPriority( NULL, priority ); } +#ifndef _X360 +PLATFORM_INTERFACE bool ThreadInMainThread(); +PLATFORM_INTERFACE void DeclareCurrentThreadIsMainThread(); +#else +PLATFORM_INTERFACE byte *g_pBaseMainStack; +PLATFORM_INTERFACE byte *g_pLimitMainStack; +inline bool ThreadInMainThread() +{ + byte b; + byte *p = &b; + return ( p < g_pBaseMainStack && p >= g_pLimitMainStack ); +} +#endif + +// NOTE: ThreadedLoadLibraryFunc_t needs to return the sleep time in milliseconds or TT_INFINITE +typedef int (*ThreadedLoadLibraryFunc_t)(); +PLATFORM_INTERFACE void SetThreadedLoadLibraryFunc( ThreadedLoadLibraryFunc_t func ); +PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc(); + +#if defined( PLATFORM_WINDOWS_PC32 ) +DLL_IMPORT unsigned long STDCALL GetCurrentThreadId(); +#define ThreadGetCurrentId GetCurrentThreadId +#endif + +inline void ThreadPause() +{ +#if defined( COMPILER_PS3 ) + __db16cyc(); +#elif defined( COMPILER_GCC ) + __asm __volatile( "pause" ); +#elif defined ( COMPILER_MSVC64 ) + _mm_pause(); +#elif defined( COMPILER_MSVC32 ) + __asm pause; +#elif defined( COMPILER_MSVCX360 ) + YieldProcessor(); + __asm { or r0,r0,r0 } + YieldProcessor(); + __asm { or r1,r1,r1 } +#else +#error "implement me" +#endif +} + +PLATFORM_INTERFACE bool ThreadJoin( ThreadHandle_t, unsigned timeout = TT_INFINITE ); + +PLATFORM_INTERFACE void ThreadSetDebugName( ThreadHandle_t hThread, const char *pszName ); +inline void ThreadSetDebugName( const char *pszName ) { ThreadSetDebugName( NULL, pszName ); } + +PLATFORM_INTERFACE void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinityMask ); + + +//----------------------------------------------------------------------------- +// +// Interlock methods. These perform very fast atomic thread +// safe operations. These are especially relevant in a multi-core setting. +// +//----------------------------------------------------------------------------- + +#ifdef _WIN32 +#define NOINLINE +#elif defined( _PS3 ) +#define NOINLINE __attribute__ ((noinline)) +#elif defined(POSIX) +#define NOINLINE __attribute__ ((noinline)) +#endif + +#if defined( _X360 ) || defined( _PS3 ) +#define ThreadMemoryBarrier() __lwsync() +#else +#define ThreadMemoryBarrier() ((void)0) +#endif + +#if defined( _LINUX ) || defined( _OSX ) +#define USE_INTRINSIC_INTERLOCKED +// linux implementation +inline int32 ThreadInterlockedIncrement( int32 volatile *p ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_fetch_and_add( p, 1 ) + 1; +} + +inline int32 ThreadInterlockedDecrement( int32 volatile *p ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_fetch_and_add( p, -1 ) - 1; +} + +inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) +{ + Assert( (size_t)p % 4 == 0 ); + int32 nRet; + + // Note: The LOCK instruction prefix is assumed on the XCHG instruction and GCC gets very confused on the Mac when we use it. + __asm __volatile( + "xchgl %2,(%1)" + : "=r" (nRet) + : "r" (p), "0" (value) + : "memory"); + return nRet; +} + +inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_fetch_and_add( p, value ); +} +inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_val_compare_and_swap( p, comperand, value ); +} + + +inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) +{ + Assert( (size_t)p % 4 == 0 ); + return __sync_bool_compare_and_swap( p, comperand, value ); +} + +#elif ( defined( COMPILER_MSVC32 ) && ( _MSC_VER >= 1310 ) ) +// windows 32 implemnetation using compiler intrinsics +#define USE_INTRINSIC_INTERLOCKED + +extern "C" +{ + long __cdecl _InterlockedIncrement(volatile long*); + long __cdecl _InterlockedDecrement(volatile long*); + long __cdecl _InterlockedExchange(volatile long*, long); + long __cdecl _InterlockedExchangeAdd(volatile long*, long); + long __cdecl _InterlockedCompareExchange(volatile long*, long, long); +} + +#pragma intrinsic( _InterlockedCompareExchange ) +#pragma intrinsic( _InterlockedDecrement ) +#pragma intrinsic( _InterlockedExchange ) +#pragma intrinsic( _InterlockedExchangeAdd ) +#pragma intrinsic( _InterlockedIncrement ) + +inline int32 ThreadInterlockedIncrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedIncrement( (volatile long*)p ); } +inline int32 ThreadInterlockedDecrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedDecrement( (volatile long*)p ); } +inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchange( (volatile long*)p, value ); } +inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchangeAdd( (volatile long*)p, value ); } +inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedCompareExchange( (volatile long*)p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return ( _InterlockedCompareExchange( (volatile long*)p, value, comperand ) == comperand ); } +#elif defined( _PS3 ) +PLATFORM_INTERFACE inline int32 ThreadInterlockedIncrement( int32 volatile * ea ) { return cellAtomicIncr32( (uint32_t*)ea ) + 1; } +PLATFORM_INTERFACE inline int32 ThreadInterlockedDecrement( int32 volatile * ea ) { return cellAtomicDecr32( (uint32_t*)ea ) - 1; } +PLATFORM_INTERFACE inline int32 ThreadInterlockedExchange( int32 volatile * ea, int32 value ) { return cellAtomicStore32( ( uint32_t* )ea, value); } +PLATFORM_INTERFACE inline int32 ThreadInterlockedExchangeAdd( int32 volatile * ea, int32 value ) { return cellAtomicAdd32( ( uint32_t* )ea, value ); } +PLATFORM_INTERFACE inline int32 ThreadInterlockedCompareExchange( int32 volatile * ea, int32 value, int32 comperand ) { return cellAtomicCompareAndSwap32( (uint32_t*)ea, comperand, value ) ; } +PLATFORM_INTERFACE inline bool ThreadInterlockedAssignIf( int32 volatile * ea, int32 value, int32 comperand ) { return ( cellAtomicCompareAndSwap32( (uint32_t*)ea, comperand, value ) == ( uint32_t ) comperand ); } + +PLATFORM_INTERFACE inline int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, int64 comperand ) { return cellAtomicCompareAndSwap64( ( uint64_t* ) pDest, comperand, value ); } +PLATFORM_INTERFACE inline bool ThreadInterlockedAssignIf64( volatile int64 *pDest, int64 value, int64 comperand ) { return ( cellAtomicCompareAndSwap64( ( uint64_t* ) pDest, comperand, value ) == ( uint64_t ) comperand ); } + +#elif defined( _X360 ) +#define TO_INTERLOCK_PARAM(p) ((volatile long *)p) +#define TO_INTERLOCK_PTR_PARAM(p) ((void **)p) +FORCEINLINE int32 ThreadInterlockedIncrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedIncrement( TO_INTERLOCK_PARAM(pDest) ); } +FORCEINLINE int32 ThreadInterlockedDecrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedDecrement( TO_INTERLOCK_PARAM(pDest) ); } +FORCEINLINE int32 ThreadInterlockedExchange( int32 volatile *pDest, int32 value ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedExchange( TO_INTERLOCK_PARAM(pDest), value ); } +FORCEINLINE int32 ThreadInterlockedExchangeAdd( int32 volatile *pDest, int32 value ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedExchangeAdd( TO_INTERLOCK_PARAM(pDest), value ); } +FORCEINLINE int32 ThreadInterlockedCompareExchange( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand ); } +FORCEINLINE bool ThreadInterlockedAssignIf( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); return ( InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand ) == comperand ); } +#else +// non 32-bit windows and 360 implementation +PLATFORM_INTERFACE int32 ThreadInterlockedIncrement( int32 volatile * ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedDecrement( int32 volatile * ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedExchange( int32 volatile *, int32 value ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedExchangeAdd( int32 volatile *, int32 value ) NOINLINE; +PLATFORM_INTERFACE int32 ThreadInterlockedCompareExchange( int32 volatile *, int32 value, int32 comperand ) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( int32 volatile *, int32 value, int32 comperand ) NOINLINE; +#endif + + +#if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( PLATFORM_64BITS ) +#define TIPTR() +inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)( ( intp )ThreadInterlockedExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value) ) ); } +inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)( ( intp )ThreadInterlockedCompareExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value), reinterpret_cast<intp>(comperand) ) ); } +inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( ThreadInterlockedCompareExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value), reinterpret_cast<intp>(comperand) ) == reinterpret_cast<intp>(comperand) ); } +#else +PLATFORM_INTERFACE void *ThreadInterlockedExchangePointer( void * volatile *, void *value ) NOINLINE; +PLATFORM_INTERFACE void *ThreadInterlockedCompareExchangePointer( void * volatile *, void *value, void *comperand ) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf( void * volatile *, void *value, void *comperand ) NOINLINE; +#endif + + +inline unsigned ThreadInterlockedExchangeSubtract( int32 volatile *p, int32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, -value ); } + +inline void const *ThreadInterlockedExchangePointerToConst( void const * volatile *p, void const *value ) { return ThreadInterlockedExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ) ); } +inline void const *ThreadInterlockedCompareExchangePointerToConst( void const * volatile *p, void const *value, void const *comperand ) { return ThreadInterlockedCompareExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ), const_cast < void * > ( comperand ) ); } +inline bool ThreadInterlockedAssignPointerToConstIf( void const * volatile *p, void const *value, void const *comperand ) { return ThreadInterlockedAssignPointerIf( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ), const_cast < void * > ( comperand ) ); } + + +#ifndef _PS3 +PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE; +PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64( volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE; +#endif + +PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile * ) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile * ) NOINLINE; +PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE; + +inline unsigned ThreadInterlockedExchangeSubtract( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } + +inline unsigned ThreadInterlockedIncrement( uint32 volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); } +inline unsigned ThreadInterlockedDecrement( uint32 volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); } +inline unsigned ThreadInterlockedExchange( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchange( (int32 volatile *)p, value ); } +inline unsigned ThreadInterlockedExchangeAdd( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +inline unsigned ThreadInterlockedCompareExchange( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); } +inline bool ThreadInterlockedAssignIf( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); } + +//inline int ThreadInterlockedExchangeSubtract( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +//inline int ThreadInterlockedIncrement( int volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); } +//inline int ThreadInterlockedDecrement( int volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); } +//inline int ThreadInterlockedExchange( int volatile *p, int value ) { return ThreadInterlockedExchange( (int32 volatile *)p, value ); } +//inline int ThreadInterlockedExchangeAdd( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); } +//inline int ThreadInterlockedCompareExchange( int volatile *p, int value, int comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); } +//inline bool ThreadInterlockedAssignIf( int volatile *p, int value, int comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); } + + +//----------------------------------------------------------------------------- +// Access to VTune thread profiling +//----------------------------------------------------------------------------- +#if defined(_WIN32) && defined(THREAD_PROFILER) +PLATFORM_INTERFACE void ThreadNotifySyncPrepare(void *p); +PLATFORM_INTERFACE void ThreadNotifySyncCancel(void *p); +PLATFORM_INTERFACE void ThreadNotifySyncAcquired(void *p); +PLATFORM_INTERFACE void ThreadNotifySyncReleasing(void *p); +#else +#define ThreadNotifySyncPrepare(p) ((void)0) +#define ThreadNotifySyncCancel(p) ((void)0) +#define ThreadNotifySyncAcquired(p) ((void)0) +#define ThreadNotifySyncReleasing(p) ((void)0) +#endif + +//----------------------------------------------------------------------------- +// Encapsulation of a thread local datum (needed because THREAD_LOCAL doesn't +// work in a DLL loaded with LoadLibrary() +//----------------------------------------------------------------------------- + +#ifndef NO_THREAD_LOCAL + +#if defined( _PS3 ) +// linux totally supports compiler thread locals, even across dll's. +#define PLAT_COMPILER_SUPPORTED_THREADLOCALS 1 +#define CTHREADLOCALUSEERROR PS3_ELF_EXPORTED_THREADLOCAL PS3_ELF_EXPORTED_THREADLOCAL PS3_ELF_EXPORTED_THREADLOCAL +#define CTHREADLOCALINTEGER( typ ) CTHREADLOCALUSEERROR int +#define CTHREADLOCALINT CTHREADLOCALUSEERROR int +#define CTHREADLOCALPTR( typ ) CTHREADLOCALUSEERROR typ * +#define CTHREADLOCAL( typ ) CTHREADLOCALUSEERROR typ +#define GETLOCAL( x ) ( x ) +#endif + + +#if defined(_LINUX) && !defined(OSX) +// linux totally supports compiler thread locals, even across dll's. +#define PLAT_COMPILER_SUPPORTED_THREADLOCALS 1 +#define CTHREADLOCALINTEGER( typ ) __thread int +#define CTHREADLOCALINT __thread int +#define CTHREADLOCALPTR( typ ) __thread typ * +#define CTHREADLOCAL( typ ) __thread typ +#define GETLOCAL( x ) ( x ) +#ifndef TIER0_DLL_EXPORT +DLL_IMPORT __thread int g_nThreadID; +#endif +#endif + +#if defined(WIN32) || defined(OSX) +#ifndef __AFXTLS_H__ // not compatible with some Windows headers + +#define CTHREADLOCALINT GenericThreadLocals::CThreadLocalInt<int> +#define CTHREADLOCALINTEGER( typ ) GenericThreadLocals::CThreadLocalInt<typ> +#define CTHREADLOCALPTR( typ ) GenericThreadLocals::CThreadLocalPtr<typ> +#define CTHREADLOCAL( typ ) GenericThreadLocals::CThreadLocal<typ> +#define GETLOCAL( x ) ( x.Get() ) + + +namespace GenericThreadLocals +{ + // a (not so efficient) implementation of thread locals for compilers without full support (i.e. visual c). + // don't use this explicity - instead, use the CTHREADxxx macros above. + + class PLATFORM_CLASS CThreadLocalBase + { +public: + CThreadLocalBase(); + ~CThreadLocalBase(); + + void * Get() const; + void Set(void *); + +private: +#if defined(POSIX) && !defined( _GAMECONSOLE ) + pthread_key_t m_index; +#else + uint32 m_index; +#endif + }; + + //--------------------------------------------------------- + + template <class T> + class CThreadLocal : public CThreadLocalBase + { + public: + CThreadLocal() + { +#ifdef PLATFORM_64BITS + COMPILE_TIME_ASSERT( sizeof(T) <= sizeof(void *) ); +#else + COMPILE_TIME_ASSERT( sizeof(T) == sizeof(void *) ); +#endif + } + + void operator=( T i ) { Set( i ); } + + T Get() const + { +#ifdef PLATFORM_64BITS + void *pData = CThreadLocalBase::Get(); + return *reinterpret_cast<T*>( &pData ); +#else + #ifdef COMPILER_MSVC + #pragma warning ( disable : 4311 ) + #endif + return reinterpret_cast<T>( CThreadLocalBase::Get() ); + #ifdef COMPILER_MSVC + #pragma warning ( default : 4311 ) + #endif +#endif + } + + void Set(T val) + { +#ifdef PLATFORM_64BITS + void* pData = 0; + *reinterpret_cast<T*>( &pData ) = val; + CThreadLocalBase::Set( pData ); +#else + #ifdef COMPILER_MSVC + #pragma warning ( disable : 4312 ) + #endif + CThreadLocalBase::Set( reinterpret_cast<void *>(val) ); + #ifdef COMPILER_MSVC + #pragma warning ( default : 4312 ) + #endif +#endif + } + }; + + + //--------------------------------------------------------- + + template <class T = int32> + class CThreadLocalInt : public CThreadLocal<T> + { + public: + operator const T() const { return this->Get(); } + int operator=( T i ) { this->Set( i ); return i; } + + T operator++() { T i = this->Get(); this->Set( ++i ); return i; } + T operator++(int) { T i = this->Get(); this->Set( i + 1 ); return i; } + + T operator--() { T i = this->Get(); this->Set( --i ); return i; } + T operator--(int) { T i = this->Get(); this->Set( i - 1 ); return i; } + + inline CThreadLocalInt( ) { } + inline CThreadLocalInt( const T &initialvalue ) + { + this->Set( initialvalue ); + } + }; + + + //--------------------------------------------------------- + + template <class T> + class CThreadLocalPtr : private CThreadLocalBase + { + public: + CThreadLocalPtr() {} + + operator const void *() const { return (const T *)Get(); } + operator void *() { return (T *)Get(); } + + operator const T *() const { return (const T *)Get(); } + operator const T *() { return (const T *)Get(); } + operator T *() { return (T *)Get(); } + + T * operator=( T *p ) { Set( p ); return p; } + + bool operator !() const { return (!Get()); } + bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() != NULL); } + bool operator==( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() == NULL); } + bool operator==( const void *p ) const { return (Get() == p); } + bool operator!=( const void *p ) const { return (Get() != p); } + bool operator==( const T *p ) const { return operator==((const void*)p); } + bool operator!=( const T *p ) const { return operator!=((const void*)p); } + + T * operator->() { return (T *)Get(); } + T & operator *() { return *((T *)Get()); } + + const T * operator->() const { return (const T *)Get(); } + const T & operator *() const { return *((const T *)Get()); } + + const T & operator[]( int i ) const { return *((const T *)Get() + i); } + T & operator[]( int i ) { return *((T *)Get() + i); } + + private: + // Disallowed operations + CThreadLocalPtr( T *pFrom ); + CThreadLocalPtr( const CThreadLocalPtr<T> &from ); + T **operator &(); + T * const *operator &() const; + void operator=( const CThreadLocalPtr<T> &from ); + bool operator==( const CThreadLocalPtr<T> &p ) const; + bool operator!=( const CThreadLocalPtr<T> &p ) const; + }; +} + +#ifdef _OSX +PLATFORM_INTERFACE GenericThreadLocals::CThreadLocalInt<int> g_nThreadID; +#else // _OSX +#ifndef TIER0_DLL_EXPORT + +#ifndef _PS3 +extern GenericThreadLocals::CThreadLocalInt<int> g_nThreadID; +#endif // !_PS3 + +#endif // TIER0_DLL_EXPORT +#endif // _OSX + +#endif /// afx32 +#endif //__win32 + +#endif // NO_THREAD_LOCAL + +//----------------------------------------------------------------------------- +// +// A super-fast thread-safe integer A simple class encapsulating the notion of an +// atomic integer used across threads that uses the built in and faster +// "interlocked" functionality rather than a full-blown mutex. Useful for simple +// things like reference counts, etc. +// +//----------------------------------------------------------------------------- + +template <typename T> +class CInterlockedIntT +{ +public: + CInterlockedIntT() : m_value( 0 ) { COMPILE_TIME_ASSERT( sizeof(T) == sizeof(int32) ); } + CInterlockedIntT( T value ) : m_value( value ) {} + + T operator()( void ) const { return m_value; } + operator T() const { return m_value; } + + bool operator!() const { return ( m_value == 0 ); } + bool operator==( T rhs ) const { return ( m_value == rhs ); } + bool operator!=( T rhs ) const { return ( m_value != rhs ); } + + T operator++() { return (T)ThreadInterlockedIncrement( (int32 *)&m_value ); } + T operator++(int) { return operator++() - 1; } + + T operator--() { return (T)ThreadInterlockedDecrement( (int32 *)&m_value ); } + T operator--(int) { return operator--() + 1; } + + bool AssignIf( T conditionValue, T newValue ) { return ThreadInterlockedAssignIf( (int32 *)&m_value, (int32)newValue, (int32)conditionValue ); } + + T operator=( T newValue ) { ThreadInterlockedExchange((int32 *)&m_value, newValue); return m_value; } + + // Atomic add is like += except it returns the previous value as its return value + T AtomicAdd( T add ) { return (T)ThreadInterlockedExchangeAdd( (int32 *)&m_value, (int32)add ); } + + void operator+=( T add ) { ThreadInterlockedExchangeAdd( (int32 *)&m_value, (int32)add ); } + void operator-=( T subtract ) { operator+=( -subtract ); } + void operator*=( T multiplier ) { + T original, result; + do + { + original = m_value; + result = original * multiplier; + } while ( !AssignIf( original, result ) ); + } + void operator/=( T divisor ) { + T original, result; + do + { + original = m_value; + result = original / divisor; + } while ( !AssignIf( original, result ) ); + } + + T operator+( T rhs ) const { return m_value + rhs; } + T operator-( T rhs ) const { return m_value - rhs; } + +private: + volatile T m_value; +}; + +typedef CInterlockedIntT<int> CInterlockedInt; +typedef CInterlockedIntT<unsigned> CInterlockedUInt; + +//----------------------------------------------------------------------------- + +template <typename T> +class CInterlockedPtr +{ +public: + CInterlockedPtr() : m_value( 0 ) { COMPILE_TIME_ASSERT( sizeof(T *) == sizeof(int32) ); /* Will need to rework operator+= for 64 bit */ } + CInterlockedPtr( T *value ) : m_value( value ) {} + + operator T *() const { return m_value; } + + bool operator!() const { return ( m_value == 0 ); } + bool operator==( T *rhs ) const { return ( m_value == rhs ); } + bool operator!=( T *rhs ) const { return ( m_value != rhs ); } + + T *operator++() { return ((T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, sizeof(T) )) + 1; } + T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, sizeof(T) ); } + + T *operator--() { return ((T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, -sizeof(T) )) - 1; } + T *operator--(int) { return (T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, -sizeof(T) ); } + + bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); } + + T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; } + + void operator+=( int add ) { ThreadInterlockedExchangeAdd( (int32 *)&m_value, add * sizeof(T) ); } + void operator-=( int subtract ) { operator+=( -subtract ); } + + // Atomic add is like += except it returns the previous value as its return value + T *AtomicAdd( int add ) { return ( T * ) ThreadInterlockedExchangeAdd( (int32 *)&m_value, add * sizeof(T) ); } + + T *operator+( int rhs ) const { return m_value + rhs; } + T *operator-( int rhs ) const { return m_value - rhs; } + T *operator+( unsigned rhs ) const { return m_value + rhs; } + T *operator-( unsigned rhs ) const { return m_value - rhs; } + size_t operator-( T *p ) const { return m_value - p; } + size_t operator-( const CInterlockedPtr<T> &p ) const { return m_value - p.m_value; } + +private: + T * volatile m_value; +}; + + + +//----------------------------------------------------------------------------- +// +// Platform independent for critical sections management +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadMutex +{ +public: + CThreadMutex(); + ~CThreadMutex(); + + //------------------------------------------------------ + // Mutex acquisition/release. Const intentionally defeated. + //------------------------------------------------------ + void Lock(); + void Lock() const { (const_cast<CThreadMutex *>(this))->Lock(); } + void Unlock(); + void Unlock() const { (const_cast<CThreadMutex *>(this))->Unlock(); } + + bool TryLock(); + bool TryLock() const { return (const_cast<CThreadMutex *>(this))->TryLock(); } + + void LockSilent(); // A Lock() operation which never spews. Required by the logging system to prevent badness. + void UnlockSilent(); // An Unlock() operation which never spews. Required by the logging system to prevent badness. + + //------------------------------------------------------ + // Use this to make deadlocks easier to track by asserting + // when it is expected that the current thread owns the mutex + //------------------------------------------------------ + bool AssertOwnedByCurrentThread(); + + //------------------------------------------------------ + // Enable tracing to track deadlock problems + //------------------------------------------------------ + void SetTrace( bool ); + +private: + // Disallow copying + CThreadMutex( const CThreadMutex & ); + CThreadMutex &operator=( const CThreadMutex & ); + +#if defined( _WIN32 ) + // Efficient solution to breaking the windows.h dependency, invariant is tested. +#ifdef _WIN64 + #define TT_SIZEOF_CRITICALSECTION 40 +#else +#ifndef _X360 + #define TT_SIZEOF_CRITICALSECTION 24 +#else + #define TT_SIZEOF_CRITICALSECTION 28 +#endif // !_X360 +#endif // _WIN64 + byte m_CriticalSection[TT_SIZEOF_CRITICALSECTION]; +#elif defined( _PS3 ) + sys_mutex_t m_Mutex; +#elif defined(POSIX) + pthread_mutex_t m_Mutex; + pthread_mutexattr_t m_Attr; +#else +#error +#endif + +#ifdef THREAD_MUTEX_TRACING_SUPPORTED + // Debugging (always herge to allow mixed debug/release builds w/o changing size) + uint m_currentOwnerID; + uint16 m_lockCount; + bool m_bTrace; +#endif +}; + +//----------------------------------------------------------------------------- +// +// An alternative mutex that is useful for cases when thread contention is +// rare, but a mutex is required. Instances should be declared volatile. +// Sleep of 0 may not be sufficient to keep high priority threads from starving +// lesser threads. This class is not a suitable replacement for a critical +// section if the resource contention is high. +// +//----------------------------------------------------------------------------- + +#if !defined(THREAD_PROFILER) + +class CThreadFastMutex +{ +public: + CThreadFastMutex() + : m_ownerID( 0 ), + m_depth( 0 ) + { + } + +private: + FORCEINLINE bool TryLockInline( const uint32 threadId ) volatile + { + if ( threadId != m_ownerID && !ThreadInterlockedAssignIf( (volatile int32 *)&m_ownerID, (int32)threadId, 0 ) ) + return false; + + ThreadMemoryBarrier(); + ++m_depth; + return true; + } + + bool TryLock( const uint32 threadId ) volatile + { + return TryLockInline( threadId ); + } + + PLATFORM_CLASS void Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile; + +public: + bool TryLock() volatile + { +#ifdef _DEBUG + if ( m_depth == INT_MAX ) + DebuggerBreak(); + + if ( m_depth < 0 ) + DebuggerBreak(); +#endif + return TryLockInline( ThreadGetCurrentId() ); + } + +#ifndef _DEBUG + FORCEINLINE +#endif + void Lock( unsigned int nSpinSleepTime = 0 ) volatile + { + const uint32 threadId = ThreadGetCurrentId(); + + if ( !TryLockInline( threadId ) ) + { + ThreadPause(); + Lock( threadId, nSpinSleepTime ); + } +#ifdef _DEBUG + if ( m_ownerID != ThreadGetCurrentId() ) + DebuggerBreak(); + + if ( m_depth == INT_MAX ) + DebuggerBreak(); + + if ( m_depth < 0 ) + DebuggerBreak(); +#endif + } + +#ifndef _DEBUG + FORCEINLINE +#endif + void Unlock() volatile + { +#ifdef _DEBUG + if ( m_ownerID != ThreadGetCurrentId() ) + DebuggerBreak(); + + if ( m_depth <= 0 ) + DebuggerBreak(); +#endif + + --m_depth; + if ( !m_depth ) + { + ThreadMemoryBarrier(); + ThreadInterlockedExchange( &m_ownerID, 0 ); + } + } + + bool TryLock() const volatile { return (const_cast<CThreadFastMutex *>(this))->TryLock(); } + void Lock(unsigned nSpinSleepTime = 0 ) const volatile { (const_cast<CThreadFastMutex *>(this))->Lock( nSpinSleepTime ); } + void Unlock() const volatile { (const_cast<CThreadFastMutex *>(this))->Unlock(); } + + // To match regular CThreadMutex: + bool AssertOwnedByCurrentThread() { return true; } + void SetTrace( bool ) {} + + uint32 GetOwnerId() const { return m_ownerID; } + int GetDepth() const { return m_depth; } +private: + volatile uint32 m_ownerID; + int m_depth; +}; + +class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex +{ +public: + CAlignedThreadFastMutex() + { + Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 ); + } + +private: + uint8 pad[128-sizeof(CThreadFastMutex)]; +}; + +#else +#ifdef _PS3 + +class CThreadFastMutex +{ +public: + CThreadFastMutex(); + ~CThreadFastMutex(); + + //------------------------------------------------------ + // Mutex acquisition/release. Const intentionally defeated. + //------------------------------------------------------ + void Lock(); + void Lock() const { (const_cast<CThreadFastMutex *>(this))->Lock(); } + void Unlock(); + void Unlock() const { (const_cast<CThreadFastMutex *>(this))->Unlock(); } + + bool TryLock(); + bool TryLock() const { return (const_cast<CThreadFastMutex *>(this))->TryLock(); } + + //------------------------------------------------------ + // Use this to make deadlocks easier to track by asserting + // when it is expected that the current thread owns the mutex + //------------------------------------------------------ + bool AssertOwnedByCurrentThread(); + + //------------------------------------------------------ + // Enable tracing to track deadlock problems + //------------------------------------------------------ + void SetTrace( bool ); + +private: + // Disallow copying + CThreadFastMutex( const CThreadFastMutex & ); + //CThreadFastMutex &operator=( const CThreadFastMutex & ); + sys_lwmutex_t m_Mutex; + sys_mutex_t m_SlowMutex; +}; + +#else + +typedef CThreadMutex CThreadFastMutex; + +#endif + +class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex +{ +public: + CAlignedThreadFastMutex() + { + Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 ); + } + +private: + uint8 pad[128-sizeof(CThreadFastMutex)]; +}; + +#endif + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +class CThreadNullMutex +{ +public: + static void Lock() {} + static void Unlock() {} + + static bool TryLock() { return true; } + static bool AssertOwnedByCurrentThread() { return true; } + static void SetTrace( bool b ) {} + + static uint32 GetOwnerId() { return 0; } + static int GetDepth() { return 0; } +}; + +//----------------------------------------------------------------------------- +// +// A mutex decorator class used to control the use of a mutex, to make it +// less expensive when not multithreading +// +//----------------------------------------------------------------------------- + +template <class BaseClass, bool *pCondition> +class CThreadConditionalMutex : public BaseClass +{ +public: + void Lock() { if ( *pCondition ) BaseClass::Lock(); } + void Lock() const { if ( *pCondition ) BaseClass::Lock(); } + void Unlock() { if ( *pCondition ) BaseClass::Unlock(); } + void Unlock() const { if ( *pCondition ) BaseClass::Unlock(); } + + bool TryLock() { if ( *pCondition ) return BaseClass::TryLock(); else return true; } + bool TryLock() const { if ( *pCondition ) return BaseClass::TryLock(); else return true; } + bool AssertOwnedByCurrentThread() { if ( *pCondition ) return BaseClass::AssertOwnedByCurrentThread(); else return true; } + void SetTrace( bool b ) { if ( *pCondition ) BaseClass::SetTrace( b ); } +}; + +//----------------------------------------------------------------------------- +// Mutex decorator that blows up if another thread enters +//----------------------------------------------------------------------------- + +template <class BaseClass> +class CThreadTerminalMutex : public BaseClass +{ +public: + bool TryLock() { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; } + bool TryLock() const { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; } + void Lock() { if ( !TryLock() ) BaseClass::Lock(); } + void Lock() const { if ( !TryLock() ) BaseClass::Lock(); } + +}; + +//----------------------------------------------------------------------------- +// +// Class to Lock a critical section, and unlock it automatically +// when the lock goes out of scope +// +//----------------------------------------------------------------------------- + +template <class MUTEX_TYPE = CThreadMutex> +class CAutoLockT +{ +public: + FORCEINLINE CAutoLockT( MUTEX_TYPE &lock) + : m_lock(lock) + { + m_lock.Lock(); + } + + FORCEINLINE CAutoLockT(const MUTEX_TYPE &lock) + : m_lock(const_cast<MUTEX_TYPE &>(lock)) + { + m_lock.Lock(); + } + + FORCEINLINE ~CAutoLockT() + { + m_lock.Unlock(); + } + + +private: + MUTEX_TYPE &m_lock; + + // Disallow copying + CAutoLockT<MUTEX_TYPE>( const CAutoLockT<MUTEX_TYPE> & ); + CAutoLockT<MUTEX_TYPE> &operator=( const CAutoLockT<MUTEX_TYPE> & ); +}; + +typedef CAutoLockT<CThreadMutex> CAutoLock; + +//--------------------------------------------------------- + +template <int size> struct CAutoLockTypeDeducer {}; +template <> struct CAutoLockTypeDeducer<sizeof(CThreadMutex)> { typedef CThreadMutex Type_t; }; +template <> struct CAutoLockTypeDeducer<sizeof(CThreadNullMutex)> { typedef CThreadNullMutex Type_t; }; +#if !defined(THREAD_PROFILER) +template <> struct CAutoLockTypeDeducer<sizeof(CThreadFastMutex)> { typedef CThreadFastMutex Type_t; }; +template <> struct CAutoLockTypeDeducer<sizeof(CAlignedThreadFastMutex)> { typedef CAlignedThreadFastMutex Type_t; }; +#else +template <> struct CAutoLockTypeDeducer<sizeof(CAlignedThreadFastMutex)> { typedef CAlignedThreadFastMutex Type_t; }; +#endif + + +#ifdef MSVC +#define AUTO_LOCK_( type, mutex ) \ + CAutoLockT< typename type > UNIQUE_ID( static_cast<const type &>( mutex ) ) +#else +// clang requires +#define AUTO_LOCK_( type, mutex ) \ + CAutoLockT< typename type > UNIQUE_ID( static_cast<const typename type &>( mutex ) ) +#endif + +#define AUTO_LOCK( mutex ) \ + AUTO_LOCK_( CAutoLockTypeDeducer<sizeof(mutex)>::Type_t, mutex ) + + +#define AUTO_LOCK_FM( mutex ) \ + AUTO_LOCK_( CAutoLockTypeDeducer<sizeof(CThreadFastMutex)>::Type_t, mutex ) + +#define LOCAL_THREAD_LOCK_( tag ) \ + ; \ + static CThreadFastMutex autoMutex_##tag; \ + AUTO_LOCK( autoMutex_##tag ) + +#define LOCAL_THREAD_LOCK() \ + LOCAL_THREAD_LOCK_(_) + +//----------------------------------------------------------------------------- +// +// Base class for event, semaphore and mutex objects. +// +//----------------------------------------------------------------------------- + +// TW_TIMEOUT must match WAIT_TIMEOUT definition +#define TW_TIMEOUT 0x00000102 +// TW_FAILED must match WAIT_FAILED definition +#define TW_FAILED 0xFFFFFFFF + +class PLATFORM_CLASS CThreadSyncObject +{ +public: + ~CThreadSyncObject(); + + //----------------------------------------------------- + // Query if object is useful + //----------------------------------------------------- + bool operator!() const; + + //----------------------------------------------------- + // Access handle + //----------------------------------------------------- +#ifdef _WIN32 + operator HANDLE() { return GetHandle(); } + const HANDLE GetHandle() const { return m_hSyncObject; } +#endif + //----------------------------------------------------- + // Wait for a signal from the object + //----------------------------------------------------- + bool Wait( uint32 dwTimeout = TT_INFINITE ); + + //----------------------------------------------------- + // Wait for a signal from any of the specified objects. + // + // Returns the index of the object that signaled the event + // or THREADSYNC_TIMEOUT if the timeout was hit before the wait condition was met. + // + // Returns TW_FAILED if an incoming object is invalid. + // + // If bWaitAll=true, then it'll return 0 if all the objects were set. + //----------------------------------------------------- + static uint32 WaitForMultiple( int nObjects, CThreadSyncObject **ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + + // This builds a list of pointers and calls straight through to the other WaitForMultiple. + static uint32 WaitForMultiple( int nObjects, CThreadSyncObject *ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + +protected: + CThreadSyncObject(); + void AssertUseable(); + +#ifdef _WIN32 + HANDLE m_hSyncObject; + bool m_bCreatedHandle; +#elif defined( _PS3 ) + static sys_lwmutex_t m_staticMutex; + static uint32_t m_bstaticMutexInitialized; + static uint32_t m_bstaticMutexInitializing; +#elif defined(POSIX) + pthread_mutex_t m_Mutex; + pthread_cond_t m_Condition; + bool m_bInitalized; + int m_cSet; + bool m_bManualReset; + bool m_bWakeForEvent; +#else +#error "Implement me" +#endif + +private: + CThreadSyncObject( const CThreadSyncObject & ); + CThreadSyncObject &operator=( const CThreadSyncObject & ); +}; + + +//----------------------------------------------------------------------------- +// +// Wrapper for unnamed event objects +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// +// CThreadSemaphore +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadSemaphore : public CThreadSyncObject +{ +public: + CThreadSemaphore(int32 initialValue, int32 maxValue); + + //----------------------------------------------------- + // Increases the count of the semaphore object by a specified + // amount. Wait() decreases the count by one on return. + //----------------------------------------------------- + bool Release(int32 releaseCount = 1, int32 * pPreviousCount = NULL ); + bool Wait( uint32 dwTimeout = TT_INFINITE ); + +private: + CThreadSemaphore(const CThreadSemaphore &); + CThreadSemaphore &operator=(const CThreadSemaphore &); +#ifdef _PS3 + bool AddWaitingThread(); + void RemoveWaitingThread(); + sys_semaphore_t m_Semaphore; + sys_semaphore_value_t m_sema_max_val; + uint32_t m_numWaitingThread; + uint32_t m_bInitalized; + uint32_t m_semaCount; +#endif +}; + +#if defined( _WIN32 ) + +//----------------------------------------------------------------------------- +// +// A mutex suitable for out-of-process, multi-processor usage +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadFullMutex : public CThreadSyncObject +{ +public: + CThreadFullMutex( bool bEstablishInitialOwnership = false, const char * pszName = NULL ); + + //----------------------------------------------------- + // Release ownership of the mutex + //----------------------------------------------------- + bool Release(); + + // To match regular CThreadMutex: + void Lock() { Wait(); } + void Lock( unsigned timeout ) { Wait( timeout ); } + void Unlock() { Release(); } + bool AssertOwnedByCurrentThread() { return true; } + void SetTrace( bool ) {} + +private: + CThreadFullMutex( const CThreadFullMutex & ); + CThreadFullMutex &operator=( const CThreadFullMutex & ); +}; +#endif + +enum NamedEventResult_t +{ + TT_EventDoesntExist = 0, + TT_EventNotSignaled, + TT_EventSignaled +}; +#if defined( _PS3 ) +//--------------------------------------------------------------------------- +// CThreadEventWaitObject - the purpose of this class is to help implement +// WaitForMultipleObejcts on PS3. +// +// Each event maintains a linked list of CThreadEventWaitObjects. When a +// thread wants to wait on an event it passes the event a semaphore that +// ptr to see the index of the event that triggered it +// +// The thread-specific mutex is to ensure that setting the index and setting the +// semaphore are atomic +//--------------------------------------------------------------------------- + +class CThreadEventWaitObject +{ +public: + CThreadEventWaitObject *m_pPrev, *m_pNext; + sys_semaphore_t *m_pSemaphore; + int m_index; + int *m_pFlag; + + CThreadEventWaitObject() {} + + void Init(sys_semaphore_t *pSem, int index, int *pFlag) + { + m_pSemaphore = pSem; + m_index = index; + m_pFlag = pFlag; + } + + void Set(); +}; +#endif //_PS3 + +class PLATFORM_CLASS CThreadEvent : public CThreadSyncObject +{ +public: + CThreadEvent( bool fManualReset = false ); +#ifdef PLATFORM_WINDOWS + CThreadEvent( const char *name, bool initialState = false, bool bManualReset = false ); + static NamedEventResult_t CheckNamedEvent( const char *name, uint32 dwTimeout = 0 ); + + CThreadEvent( HANDLE hHandle ); +#endif + //----------------------------------------------------- + // Set the state to signaled + //----------------------------------------------------- + bool Set(); + + //----------------------------------------------------- + // Set the state to nonsignaled + //----------------------------------------------------- + bool Reset(); + + //----------------------------------------------------- + // Check if the event is signaled + //----------------------------------------------------- + bool Check(); // Please, use for debugging only! + + bool Wait( uint32 dwTimeout = TT_INFINITE ); + + // See CThreadSyncObject for definitions of these functions. + static uint32 WaitForMultiple( int nObjects, CThreadEvent **ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + // To implement these, I need to check that casts are safe + static uint32 WaitForMultiple( int nObjects, CThreadEvent *ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE ); + +#ifdef _PS3 + void RegisterWaitingThread(sys_semaphore_t *pSemaphore, int index, int *flag); + void UnregisterWaitingThread(sys_semaphore_t *pSemaphore); +#endif + +protected: +#ifdef _PS3 + // These virtual functions need to be inline in order for the class to be exported from tier0.prx + virtual bool AddWaitingThread() + { + //This checks if the event is already signaled and if not creates a semaphore which will be signaled + //when the event is finally signaled. + bool result; + + sys_lwmutex_lock(&m_staticMutex, 0); + + if (m_bSet) + result=false; + else + { + result=true; + + m_numWaitingThread++; + + if ( m_numWaitingThread == 1 ) + { + sys_semaphore_attribute_t semAttr; + sys_semaphore_attribute_initialize( semAttr ); + int err = sys_semaphore_create( &m_Semaphore, &semAttr, 0, 256 ); + Assert( err == CELL_OK ); + m_bInitalized = true; + } + } + + sys_lwmutex_unlock(&m_staticMutex); + return result; + } + + virtual void RemoveWaitingThread() + { + sys_lwmutex_lock(&m_staticMutex, 0); + + m_numWaitingThread--; + + if ( m_numWaitingThread == 0) + { + int err = sys_semaphore_destroy( m_Semaphore ); + Assert( err == CELL_OK ); + m_bInitalized = false; + } + + sys_lwmutex_unlock(&m_staticMutex); + } +#endif +private: + CThreadEvent( const CThreadEvent & ); + CThreadEvent &operator=( const CThreadEvent & ); +#if defined( _PS3 ) + uint32_t m_bSet; + bool m_bManualReset; + + sys_semaphore_t m_Semaphore; + uint32_t m_numWaitingThread; + uint32_t m_bInitalized; + + CThreadEventWaitObject m_waitObjects[CTHREADEVENT_MAX_WAITING_THREADS+2]; + CThreadEventWaitObject *m_pWaitObjectsPool; + CThreadEventWaitObject *m_pWaitObjectsList; + + CThreadEventWaitObject* LLUnlinkNode(CThreadEventWaitObject *node); + CThreadEventWaitObject* LLLinkNode(CThreadEventWaitObject* list, CThreadEventWaitObject *node); + +#endif +}; + +// Hard-wired manual event for use in array declarations +class CThreadManualEvent : public CThreadEvent +{ +public: + CThreadManualEvent() + : CThreadEvent( true ) + { + } +}; + +PLATFORM_INTERFACE int ThreadWaitForObjects( int nEvents, const HANDLE *pHandles, bool bWaitAll = true, unsigned timeout = TT_INFINITE ); +inline int ThreadWaitForEvents( int nEvents, const CThreadEvent *pEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) { return ThreadWaitForObjects( nEvents, (const HANDLE *)pEvents, bWaitAll, timeout ); } + +//----------------------------------------------------------------------------- +// +// CThreadRWLock +// +//----------------------------------------------------------------------------- + +class PLATFORM_CLASS CThreadRWLock +{ +public: + CThreadRWLock(); + + void LockForRead(); + void UnlockRead(); + void LockForWrite(); + void UnlockWrite(); + + void LockForRead() const { const_cast<CThreadRWLock *>(this)->LockForRead(); } + void UnlockRead() const { const_cast<CThreadRWLock *>(this)->UnlockRead(); } + void LockForWrite() const { const_cast<CThreadRWLock *>(this)->LockForWrite(); } + void UnlockWrite() const { const_cast<CThreadRWLock *>(this)->UnlockWrite(); } + +private: + void WaitForRead(); + +#ifdef WIN32 + CThreadFastMutex m_mutex; +#else + CThreadMutex m_mutex; +#endif + CThreadEvent m_CanWrite; + CThreadEvent m_CanRead; + + int m_nWriters; + int m_nActiveReaders; + int m_nPendingReaders; +}; + +//----------------------------------------------------------------------------- +// +// CThreadSpinRWLock +// +//----------------------------------------------------------------------------- + +#ifndef OLD_SPINRWLOCK +class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock +{ +public: + CThreadSpinRWLock() + { + m_lockInfo.m_i32 = 0; + m_writerId = 0; +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + m_iWriteDepth = 0; +#endif + } + + bool IsLockedForWrite(); + bool IsLockedForRead(); + + FORCEINLINE bool TryLockForWrite(); + bool TryLockForWrite_UnforcedInline(); + + void LockForWrite(); + void SpinLockForWrite(); + + FORCEINLINE bool TryLockForRead(); + bool TryLockForRead_UnforcedInline(); + + void LockForRead(); + void SpinLockForRead(); + + void UnlockWrite(); + void UnlockRead(); + + bool TryLockForWrite() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite(); } + bool TryLockForRead() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead(); } + void LockForRead() const { const_cast<CThreadSpinRWLock *>(this)->LockForRead(); } + void UnlockRead() const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead(); } + void LockForWrite() const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite(); } + void UnlockWrite() const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite(); } + +private: + enum + { + THREAD_SPIN = (8*1024) + }; + + union LockInfo_t + { + struct + { +#if PLAT_LITTLE_ENDIAN + uint16 m_nReaders; + uint16 m_fWriting; +#else + uint16 m_fWriting; + uint16 m_nReaders; +#endif + }; + uint32 m_i32; + }; + + LockInfo_t m_lockInfo; + uint32 m_writerId; +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + int m_iWriteDepth; + uint32 pad; +#endif +} ALIGN8_POST; + +#else + +/* (commented out to reduce distraction in colorized editor, remove entirely when new implementation settles) +class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock +{ +public: + CThreadSpinRWLock() { COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); Assert( (intp)this % 8 == 0 ); memset( this, 0, sizeof( *this ) ); } + + bool TryLockForWrite(); + bool TryLockForRead(); + + void LockForRead(); + void UnlockRead(); + void LockForWrite(); + void UnlockWrite(); + + bool TryLockForWrite() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite(); } + bool TryLockForRead() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead(); } + void LockForRead() const { const_cast<CThreadSpinRWLock *>(this)->LockForRead(); } + void UnlockRead() const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead(); } + void LockForWrite() const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite(); } + void UnlockWrite() const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite(); } + +private: + // This structure is used as an atomic & exchangeable 64-bit value. It would probably be better to just have one 64-bit value + // and accessor functions that make/break it, but at this late stage of development, I'm just wrapping it into union + // Beware of endianness: on Xbox/PowerPC m_writerId is high-word of m_i64; on PC, it's low-dword of m_i64 + union LockInfo_t + { + struct + { + uint32 m_writerId; + int m_nReaders; + }; + int64 m_i64; + }; + + bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ); + bool TryLockForWrite( const uint32 threadId ); + void SpinLockForWrite( const uint32 threadId ); + + volatile LockInfo_t m_lockInfo; + CInterlockedInt m_nWriters; +} ALIGN8_POST; +*/ +#endif + +//----------------------------------------------------------------------------- +// +// A thread wrapper similar to a Java thread. +// +//----------------------------------------------------------------------------- +#ifdef _PS3 +// Everything must be inline for this to work across PRX boundaries + +class CThread; +PLATFORM_INTERFACE CThread *GetCurThreadPS3(); +PLATFORM_INTERFACE void SetCurThreadPS3( CThread * ); +PLATFORM_INTERFACE void AllocateThreadID( void ); +PLATFORM_INTERFACE void FreeThreadID( void ); +#endif + +class PLATFORM_CLASS CThread +{ +public: + CThread(); + virtual ~CThread(); + + //----------------------------------------------------- + + const char *GetName(); + void SetName( const char *pszName ); + + size_t CalcStackDepth( void *pStackVariable ) { return ((byte *)m_pStackBase - (byte *)pStackVariable); } + + //----------------------------------------------------- + // Functions for the other threads + //----------------------------------------------------- + + // Start thread running - error if already running + enum ThreadPriorityEnum_t + { +#ifdef _PS3 + PRIORITY_NORMAL = 1001, + PRIORITY_HIGH = 100, + PRIORITY_LOW = 2001, + PRIORITY_DEFAULT = 1001 +#else + PRIORITY_DEFAULT = 0,//THREAD_PRIORITY_NORMAL, + PRIORITY_NORMAL = 0,//THREAD_PRIORITY_NORMAL, + PRIORITY_HIGH = 1,//THREAD_PRIORITY_ABOVE_NORMAL, + PRIORITY_LOW = -1//THREAD_PRIORITY_BELOW_NORMAL +#endif + }; + virtual bool Start( unsigned nBytesStack = 0, ThreadPriorityEnum_t nPriority = PRIORITY_DEFAULT ); + + // Returns true if thread has been created and hasn't yet exited + bool IsAlive(); + + // This method causes the current thread to wait until this thread + // is no longer alive. + bool Join( unsigned timeout = TT_INFINITE ); + + // Access the thread handle directly + ThreadHandle_t GetThreadHandle(); + +#ifdef _WIN32 + uint GetThreadId(); +#endif + + //----------------------------------------------------- + + int GetResult(); + + //----------------------------------------------------- + // Functions for both this, and maybe, and other threads + //----------------------------------------------------- + + // Forcibly, abnormally, but relatively cleanly stop the thread + void Stop( int exitCode = 0 ); + + // Get the priority + int GetPriority() const; + + // Set the priority + bool SetPriority( int priority ); + + // Suspend a thread, can only call from the thread itself + unsigned Suspend(); + + // Resume a suspended thread + unsigned Resume(); + + // Check if thread is suspended + bool IsSuspended() { return !m_NotSuspendedEvent.Check(); } + + // Force hard-termination of thread. Used for critical failures. + bool Terminate( int exitCode = 0 ); + + //----------------------------------------------------- + // Global methods + //----------------------------------------------------- + + // Get the Thread object that represents the current thread, if any. + // Can return NULL if the current thread was not created using + // CThread + static CThread *GetCurrentCThread(); + + // Offer a context switch. Under Win32, equivalent to Sleep(0) +#ifdef Yield +#undef Yield +#endif + static void Yield(); + + // This method causes the current thread to yield and not to be + // scheduled for further execution until a certain amount of real + // time has elapsed, more or less. Duration is in milliseconds + static void Sleep( unsigned duration ); + +protected: + + // Optional pre-run call, with ability to fail-create. Note Init() + // is forced synchronous with Start() + virtual bool Init(); + + // Thread will run this function on startup, must be supplied by + // derived class, performs the intended action of the thread. + virtual int Run() = 0; + + // Called when the thread exits + virtual void OnExit(); + + // Allow for custom start waiting + virtual bool WaitForCreateComplete( CThreadEvent *pEvent ); + const ThreadId_t GetThreadID() const { return (ThreadId_t)m_threadId; } + +#ifdef PLATFORM_WINDOWS + const ThreadHandle_t GetThreadHandle() const { return (ThreadHandle_t)m_hThread; } + + static unsigned long __stdcall ThreadProc( void * pv ); + typedef unsigned long (__stdcall *ThreadProc_t)( void * ); +#else + static void* ThreadProc( void * pv ); + typedef void* (*ThreadProc_t)( void * pv ); +#endif + + virtual ThreadProc_t GetThreadProc(); + CThreadMutex m_Lock; + CThreadEvent m_ExitEvent; // Set right before the thread's function exits. + +private: + enum Flags + { + SUPPORT_STOP_PROTOCOL = 1 << 0 + }; + + // Thread initially runs this. param is actually 'this'. function + // just gets this and calls ThreadProc + struct ThreadInit_t + { + CThread * pThread; + CThreadEvent *pInitCompleteEvent; + bool * pfInitSuccess; +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + void * ParentStackTrace[THREAD_PARENT_STACK_TRACE_LENGTH]; +#endif + }; + + // make copy constructor and assignment operator inaccessible + CThread( const CThread & ); + CThread &operator=( const CThread & ); + +#ifdef _WIN32 + HANDLE m_hThread; + ThreadId_t m_threadId; +#elif defined( _PS3 ) + sys_ppu_thread_t m_threadId; + volatile sys_ppu_thread_t m_threadZombieId; + + // Mutex and condition variable used by the Suspend / Resume logic + sys_mutex_t m_mutexSuspend; + sys_cond_t m_condSuspend; + + //EAPS3 Event to indicate that a thread has terminated. This helps with the replacing of WaitForMultipleObjects + // on the PS3, since it waits for a thread to finish. + CThreadEvent m_threadEnd; +#elif defined(_POSIX) + pthread_t m_threadId; + volatile pthread_t m_threadZombieId; +#endif + int m_result; + char m_szName[32]; + void * m_pStackBase; + unsigned m_flags; + CThreadManualEvent m_NotSuspendedEvent; +}; + +// The CThread implementation needs to be inlined for performance on the PS3 - It makes a difference of more than 1ms/frame +// Since the dependency checker isn't smart enough to take an #ifdef _PS3 into account, all platforms will inline it. +#ifdef _PS3 +#include "threadtools.inl" +#endif + +//----------------------------------------------------------------------------- +// Simple thread class encompasses the notion of a worker thread, handing +// synchronized communication. +//----------------------------------------------------------------------------- + +// These are internal reserved error results from a call attempt +enum WTCallResult_t +{ + WTCR_FAIL = -1, + WTCR_TIMEOUT = -2, + WTCR_THREAD_GONE = -3, +}; + +class PLATFORM_CLASS CWorkerThread : public CThread +{ +public: + CWorkerThread(); + + //----------------------------------------------------- + // + // Inter-thread communication + // + // Calls in either direction take place on the same "channel." + // Seperate functions are specified to make identities obvious + // + //----------------------------------------------------- + + // Master: Signal the thread, and block for a response + int CallWorker( unsigned, unsigned timeout = TT_INFINITE, bool fBoostWorkerPriorityToMaster = true ); + + // Worker: Signal the thread, and block for a response + int CallMaster( unsigned, unsigned timeout = TT_INFINITE ); + + // Wait for the next request + bool WaitForCall( unsigned dwTimeout, unsigned *pResult = NULL ); + bool WaitForCall( unsigned *pResult = NULL ); + + // Is there a request? + bool PeekCall( unsigned *pParam = NULL ); + + // Reply to the request + void Reply( unsigned ); + + // Wait for a reply in the case when CallWorker() with timeout != TT_INFINITE + int WaitForReply( unsigned timeout = TT_INFINITE ); + + // If you want to do WaitForMultipleObjects you'll need to include + // this handle in your wait list or you won't be responsive + CThreadEvent& GetCallHandle(); // (returns m_EventSend) + + // Find out what the request was + unsigned GetCallParam() const; + + // Boost the worker thread to the master thread, if worker thread is lesser, return old priority + int BoostPriority(); + +protected: + typedef uint32 ( *WaitFunc_t)( uint32 nHandles, CThreadEvent** ppHandles, int bWaitAll, uint32 timeout ); + int Call( unsigned, unsigned timeout, bool fBoost, WaitFunc_t = NULL ); + int WaitForReply( unsigned timeout, WaitFunc_t ); + +private: + CWorkerThread( const CWorkerThread & ); + CWorkerThread &operator=( const CWorkerThread & ); + + CThreadEvent m_EventSend; + CThreadEvent m_EventComplete; + + unsigned m_Param; + int m_ReturnVal; +}; + + +// a unidirectional message queue. A queue of type T. Not especially high speed since each message +// is malloced/freed. Note that if your message class has destructors/constructors, they MUST be +// thread safe! +template<class T> class CMessageQueue +{ + CThreadEvent SignalEvent; // signals presence of data + CThreadMutex QueueAccessMutex; + + // the parts protected by the mutex + struct MsgNode + { + MsgNode *Next; + T Data; + }; + + MsgNode *Head; + MsgNode *Tail; + +public: + CMessageQueue( void ) + { + Head = Tail = NULL; + } + + // check for a message. not 100% reliable - someone could grab the message first + bool MessageWaiting( void ) + { + return ( Head != NULL ); + } + + void WaitMessage( T *pMsg ) + { + for(;;) + { + while( ! MessageWaiting() ) + SignalEvent.Wait(); + QueueAccessMutex.Lock(); + if (! Head ) + { + // multiple readers could make this null + QueueAccessMutex.Unlock(); + continue; + } + *( pMsg ) = Head->Data; + MsgNode *remove_this = Head; + Head = Head->Next; + if (! Head) // if empty, fix tail ptr + Tail = NULL; + QueueAccessMutex.Unlock(); + delete remove_this; + break; + } + } + + void QueueMessage( T const &Msg) + { + MsgNode *new1=new MsgNode; + new1->Data=Msg; + new1->Next=NULL; + QueueAccessMutex.Lock(); + if ( Tail ) + { + Tail->Next=new1; + Tail = new1; + } + else + { + Head = new1; + Tail = new1; + } + SignalEvent.Set(); + QueueAccessMutex.Unlock(); + } +}; + + +//----------------------------------------------------------------------------- +// +// CThreadMutex. Inlining to reduce overhead and to allow client code +// to decide debug status (tracing) +// +//----------------------------------------------------------------------------- + +#ifdef MSVC +typedef struct _RTL_CRITICAL_SECTION RTL_CRITICAL_SECTION; +typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; + +#ifndef _X360 +extern "C" +{ + void __declspec(dllimport) __stdcall InitializeCriticalSection(CRITICAL_SECTION *); + void __declspec(dllimport) __stdcall EnterCriticalSection(CRITICAL_SECTION *); + void __declspec(dllimport) __stdcall LeaveCriticalSection(CRITICAL_SECTION *); + void __declspec(dllimport) __stdcall DeleteCriticalSection(CRITICAL_SECTION *); +}; +#endif +#endif + +//--------------------------------------------------------- +#if !defined(POSIX) || defined( _GAMECONSOLE ) + +inline void CThreadMutex::Lock() +{ +#if defined(_PS3) + #ifndef NO_THREAD_SYNC + sys_mutex_lock( m_Mutex, 0 ); + #endif +#else + #if defined( THREAD_MUTEX_TRACING_ENABLED ) + uint thisThreadID = ThreadGetCurrentId(); + if ( m_bTrace && m_currentOwnerID && ( m_currentOwnerID != thisThreadID ) ) + Msg( _T( "Thread %u about to wait for lock %x owned by %u\n" ), ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID ); + #endif + + LockSilent(); + + #ifdef THREAD_MUTEX_TRACING_ENABLED + if (m_lockCount == 0) + { + // we now own it for the first time. Set owner information + m_currentOwnerID = thisThreadID; + if ( m_bTrace ) + Msg( _T( "Thread %u now owns lock 0x%x\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); + } + m_lockCount++; + #endif +#endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::Unlock() +{ +#if defined( _PS3 ) + + #ifndef NO_THREAD_SYNC + sys_mutex_unlock( m_Mutex ); + #endif + +#else + #ifdef THREAD_MUTEX_TRACING_ENABLED + AssertMsg( m_lockCount >= 1, "Invalid unlock of thread lock" ); + m_lockCount--; + if (m_lockCount == 0) + { + if ( m_bTrace ) + Msg( _T( "Thread %u releasing lock 0x%x\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection ); + m_currentOwnerID = 0; + } + #endif + UnlockSilent(); +#endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::LockSilent() +{ + #ifdef MSVC + EnterCriticalSection((CRITICAL_SECTION *)&m_CriticalSection); + #else + DebuggerBreak(); // should not be called - not defined for this platform/compiler!!! + #endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::UnlockSilent() +{ + #ifdef MSVC + LeaveCriticalSection((CRITICAL_SECTION *)&m_CriticalSection); + #else + DebuggerBreak(); // should not be called - not defined for this platform/compiler!!! + #endif +} + +//--------------------------------------------------------- + +inline bool CThreadMutex::AssertOwnedByCurrentThread() +{ +#ifdef THREAD_MUTEX_TRACING_ENABLED +#ifdef _WIN32 + if (ThreadGetCurrentId() == m_currentOwnerID) + return true; + AssertMsg3( 0, "Expected thread %u as owner of lock 0x%x, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID ); + return false; +#elif defined( _PS3 ) + return true; +#endif +#else + return true; +#endif +} + +//--------------------------------------------------------- + +inline void CThreadMutex::SetTrace( bool bTrace ) +{ +#ifdef _WIN32 +#ifdef THREAD_MUTEX_TRACING_ENABLED + m_bTrace = bTrace; +#endif +#elif defined _PS3 + //EAPS3 +#endif + +} + +//--------------------------------------------------------- + +#elif defined(POSIX) && !defined( _GAMECONSOLE ) + +inline CThreadMutex::CThreadMutex() +{ + // enable recursive locks as we need them + pthread_mutexattr_init( &m_Attr ); + pthread_mutexattr_settype( &m_Attr, PTHREAD_MUTEX_RECURSIVE ); + pthread_mutex_init( &m_Mutex, &m_Attr ); +} + +//--------------------------------------------------------- + +inline CThreadMutex::~CThreadMutex() +{ + pthread_mutex_destroy( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::Lock() +{ + pthread_mutex_lock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::Unlock() +{ + pthread_mutex_unlock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::LockSilent() +{ + pthread_mutex_lock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline void CThreadMutex::UnlockSilent() +{ + pthread_mutex_unlock( &m_Mutex ); +} + +//--------------------------------------------------------- + +inline bool CThreadMutex::AssertOwnedByCurrentThread() +{ + return true; +} + +//--------------------------------------------------------- + +inline void CThreadMutex::SetTrace(bool fTrace) +{ +} + +#else +#error +#endif // POSIX + +//----------------------------------------------------------------------------- +// +// CThreadRWLock inline functions +// +//----------------------------------------------------------------------------- + +inline CThreadRWLock::CThreadRWLock() +: m_CanRead( true ), + m_nWriters( 0 ), + m_nActiveReaders( 0 ), + m_nPendingReaders( 0 ) +{ +} + +inline void CThreadRWLock::LockForRead() +{ + m_mutex.Lock(); + if ( m_nWriters) + { + WaitForRead(); + } + m_nActiveReaders++; + m_mutex.Unlock(); +} + +inline void CThreadRWLock::UnlockRead() +{ + m_mutex.Lock(); + m_nActiveReaders--; + if ( m_nActiveReaders == 0 && m_nWriters != 0 ) + { + m_CanWrite.Set(); + } + m_mutex.Unlock(); +} + + +//----------------------------------------------------------------------------- +// +// CThreadSpinRWLock inline functions +// +//----------------------------------------------------------------------------- + +#ifndef OLD_SPINRWLOCK + +#if defined(TEST_THREAD_SPIN_RW_LOCK) +#define RWLAssert( exp ) if ( exp ) ; else DebuggerBreak(); +#else +#define RWLAssert( exp ) ((void)0) +#endif + +inline bool CThreadSpinRWLock::IsLockedForWrite() +{ + return ( m_lockInfo.m_fWriting == 1 ); +} + +inline bool CThreadSpinRWLock::IsLockedForRead() +{ + return ( m_lockInfo.m_nReaders > 0 ); +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite() +{ + volatile LockInfo_t &curValue = m_lockInfo; + if ( !( curValue.m_i32 & 0x00010000 ) && ThreadInterlockedAssignIf( &curValue.m_i32, 0x00010000, 0 ) ) + { + ThreadMemoryBarrier(); + RWLAssert( m_iWriteDepth == 0 && m_writerId == 0 ); + m_writerId = ThreadGetCurrentId(); +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + m_iWriteDepth++; +#endif + return true; + } + + return false; +} + +inline bool CThreadSpinRWLock::TryLockForWrite_UnforcedInline() +{ + if ( TryLockForWrite() ) + { + return true; + } + +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( m_writerId != ThreadGetCurrentId() ) + { + return false; + } + m_iWriteDepth++; + return true; +#else + return false; +#endif +} + +FORCEINLINE void CThreadSpinRWLock::LockForWrite() +{ + if ( !TryLockForWrite() ) + { + SpinLockForWrite(); + } +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForRead() +{ + volatile LockInfo_t &curValue = m_lockInfo; + if ( !( curValue.m_i32 & 0x00010000 ) ) // !m_lockInfo.m_fWriting + { + LockInfo_t oldValue; + LockInfo_t newValue; + oldValue.m_i32 = ( curValue.m_i32 & 0xffff ); + newValue.m_i32 = oldValue.m_i32 + 1; + + if ( ThreadInterlockedAssignIf( &m_lockInfo.m_i32, newValue.m_i32, oldValue.m_i32 ) ) + { + ThreadMemoryBarrier(); + RWLAssert( m_lockInfo.m_fWriting == 0 ); + return true; + } + } + return false; +} + +inline bool CThreadSpinRWLock::TryLockForRead_UnforcedInline() +{ +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( m_lockInfo.m_i32 & 0x00010000 ) // m_lockInfo.m_fWriting + { + if ( m_writerId == ThreadGetCurrentId() ) + { + m_lockInfo.m_nReaders++; + return true; + } + + return false; + } +#endif + return TryLockForRead(); +} + +FORCEINLINE void CThreadSpinRWLock::LockForRead() +{ + if ( !TryLockForRead() ) + { + SpinLockForRead(); + } +} + +FORCEINLINE void CThreadSpinRWLock::UnlockWrite() +{ + RWLAssert( m_writerId == ThreadGetCurrentId() ); +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( --m_iWriteDepth == 0 ) +#endif + { + m_writerId = 0; + ThreadMemoryBarrier(); + m_lockInfo.m_i32 = 0; + } +} + +#ifndef REENTRANT_THREAD_SPIN_RW_LOCK +FORCEINLINE +#else +inline +#endif +void CThreadSpinRWLock::UnlockRead() +{ + RWLAssert( m_writerId == 0 || ( m_writerId == ThreadGetCurrentId() && m_lockInfo.m_fWriting ) ); +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + if ( !( m_lockInfo.m_i32 & 0x00010000 ) ) // !m_lockInfo.m_fWriting +#endif + { + ThreadMemoryBarrier(); + ThreadInterlockedDecrement( &m_lockInfo.m_i32 ); + RWLAssert( m_writerId == 0 && !m_lockInfo.m_fWriting ); + } +#ifdef REENTRANT_THREAD_SPIN_RW_LOCK + else if ( m_writerId == ThreadGetCurrentId() ) + { + m_lockInfo.m_nReaders--; + } + else + { + RWLAssert( 0 ); + } +#endif +} + +#else +/* (commented out to reduce distraction in colorized editor, remove entirely when new implementation settles) +inline bool CThreadSpinRWLock::AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ) +{ + // Note: using unions guarantees no aliasing bugs. Casting structures through *(int64*)& + // may create hard-to-catch bugs because when you do that, compiler doesn't know that the newly computed pointer + // is actually aliased with LockInfo_t structure. It's rarely a problem in practice, but when it is, it's a royal pain to debug. + return ThreadInterlockedAssignIf64( &m_lockInfo.m_i64, newValue.m_i64, comperand.m_i64 ); +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId ) +{ + // In order to grab a write lock, there can be no readers and no owners of the write lock + if ( m_lockInfo.m_nReaders > 0 || ( m_lockInfo.m_writerId && m_lockInfo.m_writerId != threadId ) ) + { + return false; + } + + static const LockInfo_t oldValue = { {0, 0} }; + LockInfo_t newValue = { { threadId, 0 } }; + if ( AssignIf( newValue, oldValue ) ) + { + ThreadMemoryBarrier(); + return true; + } + return false; +} + +inline bool CThreadSpinRWLock::TryLockForWrite() +{ + m_nWriters++; + if ( !TryLockForWrite( ThreadGetCurrentId() ) ) + { + m_nWriters--; + return false; + } + return true; +} + +FORCEINLINE bool CThreadSpinRWLock::TryLockForRead() +{ + if ( m_nWriters != 0 ) + { + return false; + } + // In order to grab a write lock, the number of readers must not change and no thread can own the write + LockInfo_t oldValue; + LockInfo_t newValue; + + if( IsX360() || IsPS3() ) + { + // this is the code equivalent to original code (see below) that doesn't cause LHS on Xbox360 + // WARNING: This code assumes BIG Endian CPU + oldValue.m_i64 = uint32( m_lockInfo.m_nReaders ); + newValue.m_i64 = oldValue.m_i64 + 1; // NOTE: when we have -1 (or 0xFFFFFFFF) readers, this will result in non-equivalent code + } + else + { + // this is the original code that worked here for a while + oldValue.m_nReaders = m_lockInfo.m_nReaders; + oldValue.m_writerId = 0; + newValue.m_nReaders = oldValue.m_nReaders + 1; + newValue.m_writerId = 0; + } + + if ( AssignIf( newValue, oldValue ) ) + { + ThreadMemoryBarrier(); + return true; + } + return false; +} + +inline void CThreadSpinRWLock::LockForWrite() +{ + const uint32 threadId = ThreadGetCurrentId(); + + m_nWriters++; + + if ( !TryLockForWrite( threadId ) ) + { + ThreadPause(); + SpinLockForWrite( threadId ); + } +} +*/ +#endif + +// read data from a memory address +template<class T> FORCEINLINE T ReadVolatileMemory( T const *pPtr ) +{ + volatile const T * pVolatilePtr = ( volatile const T * ) pPtr; + return *pVolatilePtr; +} + + +//----------------------------------------------------------------------------- + +#if defined( _WIN32 ) +#pragma warning(pop) +#endif + +#if defined( _PS3 ) +BOOL SetEvent( CThreadEvent *pEvent ); +BOOL ResetEvent( CThreadEvent *pEvent ); +DWORD WaitForMultipleObjects(DWORD nCount, CThreadEvent **lppHandles, BOOL bWaitAll, DWORD dwMilliseconds ); +#endif // _PS3 +#endif // THREADTOOLS_H diff --git a/external/vpc/public/tier0/threadtools.inl b/external/vpc/public/tier0/threadtools.inl new file mode 100644 index 0000000..0afe97a --- /dev/null +++ b/external/vpc/public/tier0/threadtools.inl @@ -0,0 +1,629 @@ +#ifndef THREADTOOLS_INL +#define THREADTOOLS_INL + +// This file is included in threadtools.h for PS3 and threadtools.cpp for all other platforms +// +// Do not #include other files here + +#ifndef _PS3 +// this is defined in the .cpp for the PS3 to avoid introducing a dependency for files including the header +CTHREADLOCALPTR(CThread) g_pCurThread; + +#define INLINE_ON_PS3 +#else +// Inlining these functions on PS3 (which are called across PRX boundaries) saves us over 1ms per frame +#define INLINE_ON_PS3 inline +#endif + +INLINE_ON_PS3 CThread::CThread() : +#ifdef _WIN32 +m_hThread( NULL ), +m_threadId( 0 ), +#elif defined( _PS3 ) || defined(_POSIX) +m_threadId( 0 ), +m_threadZombieId( 0 ) , +#endif +m_result( 0 ), +m_flags( 0 ) +{ + m_szName[0] = 0; + m_NotSuspendedEvent.Set(); +} + +//--------------------------------------------------------- + +INLINE_ON_PS3 CThread::~CThread() +{ +#ifdef MSVC + if (m_hThread) +#elif defined(POSIX) && !defined( _PS3 ) + if ( m_threadId ) +#endif + { + if ( IsAlive() ) + { + Msg( "Illegal termination of worker thread! Threads must negotiate an end to the thread before the CThread object is destroyed.\n" ); +#ifdef _WIN32 + + DoNewAssertDialog( __FILE__, __LINE__, "Illegal termination of worker thread! Threads must negotiate an end to the thread before the CThread object is destroyed.\n" ); +#endif + if ( GetCurrentCThread() == this ) + { + Stop(); // BUGBUG: Alfred - this doesn't make sense, this destructor fires from the hosting thread not the thread itself!! + } + } + } +#if defined(POSIX) || defined( _PS3 ) + if ( m_threadZombieId ) + { + // just clean up zombie threads immediately (the destructor is fired from the hosting thread) + Join(); + } +#endif +} + + +//--------------------------------------------------------- + +INLINE_ON_PS3 const char *CThread::GetName() +{ + AUTO_LOCK( m_Lock ); + if ( !m_szName[0] ) + { +#if defined( _WIN32 ) + _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/%p)", this, m_hThread ); +#elif defined( _PS3 ) + snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p)", this ); +#elif defined( POSIX ) + _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/0x%x)", this, (uint)m_threadId ); +#endif + m_szName[sizeof(m_szName) - 1] = 0; + } + return m_szName; +} + +//--------------------------------------------------------- + +INLINE_ON_PS3 void CThread::SetName(const char *pszName) +{ + AUTO_LOCK( m_Lock ); + strncpy( m_szName, pszName, sizeof(m_szName) - 1 ); + m_szName[sizeof(m_szName) - 1] = 0; +} + +//----------------------------------------------------- +// Functions for the other threads +//----------------------------------------------------- + +// Start thread running - error if already running +INLINE_ON_PS3 bool CThread::Start( unsigned nBytesStack, ThreadPriorityEnum_t nPriority ) +{ + AUTO_LOCK( m_Lock ); + + if ( IsAlive() ) + { + AssertMsg( 0, "Tried to create a thread that has already been created!" ); + return false; + } + + bool bInitSuccess = false; + CThreadEvent createComplete; + ThreadInit_t init = { this, &createComplete, &bInitSuccess }; + +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + { + int iValidEntries = GetCallStack_Fast( init.ParentStackTrace, ARRAYSIZE( init.ParentStackTrace ), 0 ); + for( int i = iValidEntries; i < ARRAYSIZE( init.ParentStackTrace ); ++i ) + { + init.ParentStackTrace[i] = NULL; + } + } +#endif + +#ifdef PLATFORM_WINDOWS + m_hThread = (HANDLE)CreateThread( NULL, + nBytesStack, + (LPTHREAD_START_ROUTINE)GetThreadProc(), + new ThreadInit_t(init), + 0, + (LPDWORD)&m_threadId ); + + if( nPriority != PRIORITY_DEFAULT ) + { + SetThreadPriority( m_hThread, nPriority ); + } + + if ( !m_hThread ) + { + AssertMsg1( 0, "Failed to create thread (error 0x%x)", GetLastError() ); + return false; + } +#elif PLATFORM_PS3 + // On the PS3, a stack size of 0 doesn't imply a default stack size, so we need to force it to our + // own default size. + if ( nBytesStack == 0 ) + { + nBytesStack = PS3_SYS_PPU_THREAD_COMMON_STACK_SIZE; + } + + //The thread is about to begin + m_threadEnd.Reset(); + + // sony documentation: + // "If the PPU thread is not joined by sys_ppu_thread_join() after exit, + // it should always be created as non-joinable (not specifying + // SYS_PPU_THREAD_CREATE_JOINABLE). Otherwise, some resources are left + // allocated after termination of the PPU thread as if memory leaks." + const char* threadName=m_szName; + if ( sys_ppu_thread_create( &m_threadId, + (void(*)(uint64_t))GetThreadProc(), + (uint64_t)(new ThreadInit_t( init )), + nPriority, + nBytesStack, + SYS_PPU_THREAD_CREATE_JOINABLE , + threadName ) != CELL_OK ) + { + AssertMsg1( 0, "Failed to create thread (error 0x%x)", errno ); + return false; + } + + bInitSuccess = true; +#elif PLATFORM_POSIX + pthread_attr_t attr; + pthread_attr_init( &attr ); + pthread_attr_setstacksize( &attr, MAX( nBytesStack, 1024u*1024 ) ); + if ( pthread_create( &m_threadId, &attr, (void *(*)(void *))GetThreadProc(), new ThreadInit_t( init ) ) != 0 ) + { + AssertMsg1( 0, "Failed to create thread (error 0x%x)", GetLastError() ); + return false; + } + bInitSuccess = true; +#endif + + + + if ( !WaitForCreateComplete( &createComplete ) ) + { + Msg( "Thread failed to initialize\n" ); +#ifdef _WIN32 + CloseHandle( m_hThread ); + m_hThread = NULL; +#elif defined( _PS3 ) + m_threadEnd.Set(); + m_threadId = NULL; + m_threadZombieId = 0; +#endif + + return false; + } + + if ( !bInitSuccess ) + { + Msg( "Thread failed to initialize\n" ); +#ifdef _WIN32 + CloseHandle( m_hThread ); + m_hThread = NULL; +#elif defined(POSIX) && !defined( _PS3 ) + m_threadId = 0; + m_threadZombieId = 0; +#endif + return false; + } + +#ifdef _WIN32 + if ( !m_hThread ) + { + Msg( "Thread exited immediately\n" ); + } +#endif + +#ifdef _WIN32 + AddThreadHandleToIDMap( m_hThread, m_threadId ); + return !!m_hThread; +#elif defined(POSIX) + return !!m_threadId; +#endif +} + +//--------------------------------------------------------- +// +// Return true if the thread has been created and hasn't yet exited +// + +INLINE_ON_PS3 bool CThread::IsAlive() +{ +#ifdef PLATFORM_WINDOWS + DWORD dwExitCode; + return ( + m_hThread + && GetExitCodeThread(m_hThread, &dwExitCode) + && dwExitCode == STILL_ACTIVE ); +#elif defined(POSIX) + return !!m_threadId; +#endif +} + +// This method causes the current thread to wait until this thread +// is no longer alive. +INLINE_ON_PS3 bool CThread::Join( unsigned timeout ) +{ +#ifdef _WIN32 + if ( m_hThread ) +#elif defined(POSIX) + if ( m_threadId || m_threadZombieId ) +#endif + { + AssertMsg(GetCurrentCThread() != this, _T("Thread cannot be joined with self")); + +#ifdef _WIN32 + return ThreadJoin( (ThreadHandle_t)m_hThread, timeout ); +#elif defined(POSIX) + bool ret = ThreadJoin( (ThreadHandle_t)(m_threadId ? m_threadId : m_threadZombieId), timeout ); + m_threadZombieId = 0; + return ret; +#endif + } + return true; +} + +//--------------------------------------------------------- + +INLINE_ON_PS3 ThreadHandle_t CThread::GetThreadHandle() +{ +#ifdef _WIN32 + return (ThreadHandle_t)m_hThread; +#else + return (ThreadHandle_t)m_threadId; +#endif +} + + +//--------------------------------------------------------- + +INLINE_ON_PS3 int CThread::GetResult() +{ + return m_result; +} + +//----------------------------------------------------- +// Functions for both this, and maybe, and other threads +//----------------------------------------------------- + +// Forcibly, abnormally, but relatively cleanly stop the thread +// + +INLINE_ON_PS3 void CThread::Stop(int exitCode) +{ + if ( !IsAlive() ) + return; + + if ( GetCurrentCThread() == this ) + { +#if !defined( _PS3 ) + m_result = exitCode; + if ( !( m_flags & SUPPORT_STOP_PROTOCOL ) ) + { + OnExit(); + g_pCurThread = NULL; + +#ifdef _WIN32 + CloseHandle( m_hThread ); + RemoveThreadHandleToIDMap( m_hThread ); + m_hThread = NULL; +#else + m_threadId = 0; + m_threadZombieId = 0; +#endif + } + else + { + throw exitCode; + } +#else + AssertMsg( false, "Called CThread::Stop() for a platform that doesn't have it!\n"); +#endif + } + else + AssertMsg( 0, "Only thread can stop self: Use a higher-level protocol"); +} + +//--------------------------------------------------------- + +// Get the priority +INLINE_ON_PS3 int CThread::GetPriority() const +{ +#ifdef _WIN32 + return GetThreadPriority(m_hThread); +#elif defined( _PS3 ) + return ThreadGetPriority( (ThreadHandle_t) m_threadId ); +#elif defined(POSIX) + struct sched_param thread_param; + int policy; + pthread_getschedparam( m_threadId, &policy, &thread_param ); + return thread_param.sched_priority; +#endif +} + +//--------------------------------------------------------- + +// Set the priority +INLINE_ON_PS3 bool CThread::SetPriority(int priority) +{ +#ifdef WIN32 + return ThreadSetPriority( (ThreadHandle_t)m_hThread, priority ); +#else + return ThreadSetPriority( (ThreadHandle_t)m_threadId, priority ); +#endif +} + +//--------------------------------------------------------- + +// Suspend a thread +INLINE_ON_PS3 unsigned CThread::Suspend() +{ + AssertMsg( ThreadGetCurrentId() == (ThreadId_t)m_threadId, "Cannot call CThread::Suspend from outside thread" ); + + if ( ThreadGetCurrentId() != (ThreadId_t)m_threadId ) + { + DebuggerBreakIfDebugging(); + } + + m_NotSuspendedEvent.Reset(); + m_NotSuspendedEvent.Wait(); + + return 0; +} + + +//--------------------------------------------------------- + +INLINE_ON_PS3 unsigned CThread::Resume() +{ + if ( m_NotSuspendedEvent.Check() ) + { + DevWarning( "Called Resume() on a thread that is not suspended!\n" ); + } + m_NotSuspendedEvent.Set(); + return 0; +} + +//--------------------------------------------------------- + +// Force hard-termination of thread. Used for critical failures. +INLINE_ON_PS3 bool CThread::Terminate(int exitCode) +{ +#if defined( _X360 ) + AssertMsg( 0, "Cannot terminate a thread on the Xbox!" ); + return false; +#elif defined( _WIN32 ) + // I hope you know what you're doing! + if (!TerminateThread(m_hThread, exitCode)) + return false; + CloseHandle( m_hThread ); + RemoveThreadHandleToIDMap( m_hThread ); + m_hThread = NULL; +#elif defined( _PS3 ) + m_threadEnd.Set(); + m_threadId = NULL; +#elif defined(POSIX) + pthread_kill( m_threadId, SIGKILL ); + m_threadId = 0; +#endif + return true; +} + +//----------------------------------------------------- +// Global methods +//----------------------------------------------------- + +// Get the Thread object that represents the current thread, if any. +// Can return NULL if the current thread was not created using +// CThread +// + +INLINE_ON_PS3 CThread *CThread::GetCurrentCThread() +{ +#ifdef _PS3 + return GetCurThreadPS3(); +#else + return g_pCurThread; +#endif +} + +//--------------------------------------------------------- +// +// Offer a context switch. Under Win32, equivalent to Sleep(0) +// + +#ifdef Yield +#undef Yield +#endif +INLINE_ON_PS3 void CThread::Yield() +{ +#ifdef _WIN32 + ::Sleep(0); +#elif defined( _PS3 ) + // sys_ppu_thread_yield doesn't seem to function properly, so sleep instead. + sys_timer_usleep( 60 ); +#elif defined(POSIX) + pthread_yield(); +#endif +} + +//--------------------------------------------------------- +// +// This method causes the current thread to yield and not to be +// scheduled for further execution until a certain amount of real +// time has elapsed, more or less. Duration is in milliseconds + +INLINE_ON_PS3 void CThread::Sleep( unsigned duration ) +{ +#ifdef _WIN32 + ::Sleep(duration); +#elif defined (_PS3) + sys_timer_usleep( duration * 1000 ); +#elif defined(POSIX) + usleep( duration * 1000 ); +#endif +} + +//--------------------------------------------------------- + +// Optional pre-run call, with ability to fail-create. Note Init() +// is forced synchronous with Start() +INLINE_ON_PS3 bool CThread::Init() +{ + return true; +} + +//--------------------------------------------------------- + +#if defined( _PS3 ) +INLINE_ON_PS3 int CThread::Run() +{ + return -1; +} +#endif // _PS3 + +// Called when the thread exits +INLINE_ON_PS3 void CThread::OnExit() { } + +// Allow for custom start waiting +INLINE_ON_PS3 bool CThread::WaitForCreateComplete( CThreadEvent *pEvent ) +{ + // Force serialized thread creation... + if (!pEvent->Wait(60000)) + { + AssertMsg( 0, "Probably deadlock or failure waiting for thread to initialize." ); + return false; + } + return true; +} + +//--------------------------------------------------------- +INLINE_ON_PS3 CThread::ThreadProc_t CThread::GetThreadProc() +{ + return ThreadProc; +} + +#ifdef PLATFORM_WINDOWS +unsigned long STDCALL CThread::ThreadProc(LPVOID pv) +#else +INLINE_ON_PS3 void* CThread::ThreadProc(LPVOID pv) +#endif +{ +#if defined( POSIX ) || defined( _PS3 ) + ThreadInit_t *pInit = reinterpret_cast<ThreadInit_t*>(pv); +#else + std::auto_ptr<ThreadInit_t> pInit((ThreadInit_t *)pv); +#endif + +#ifdef _X360 + // Make sure all threads are consistent w.r.t floating-point math + SetupFPUControlWord(); +#endif + AllocateThreadID(); + + CThread *pThread = pInit->pThread; +#ifdef _PS3 + SetCurThreadPS3( pThread ); +#else + g_pCurThread = pThread; +#endif + + pThread->m_pStackBase = AlignValue( &pThread, 4096 ); + + pInit->pThread->m_result = -1; + +#if defined( THREAD_PARENT_STACK_TRACE_ENABLED ) + CStackTop_ReferenceParentStack stackTop( pInit->ParentStackTrace, ARRAYSIZE( pInit->ParentStackTrace ) ); +#endif + + bool bInitSuccess = true; + if ( pInit->pfInitSuccess ) + *(pInit->pfInitSuccess) = false; + +#ifdef _PS3 + *(pInit->pfInitSuccess) = pInit->pThread->Init(); +#else + try + { + bInitSuccess = pInit->pThread->Init(); + } + + catch (...) + { + pInit->pInitCompleteEvent->Set(); + throw; + } +#endif // _PS3 + + if ( pInit->pfInitSuccess ) + *(pInit->pfInitSuccess) = bInitSuccess; + pInit->pInitCompleteEvent->Set(); + if (!bInitSuccess) + return 0; + + if ( !Plat_IsInDebugSession() && (pInit->pThread->m_flags & SUPPORT_STOP_PROTOCOL) ) + { +#ifndef _PS3 + try +#endif + { + pInit->pThread->m_result = pInit->pThread->Run(); + } + +#ifndef _PS3 + catch (...) + { + } +#endif + } + else + { + pInit->pThread->m_result = pInit->pThread->Run(); + } + + pInit->pThread->OnExit(); +#ifdef _PS3 + SetCurThreadPS3( NULL ); +#else + g_pCurThread = NULL; +#endif + FreeThreadID(); + + AUTO_LOCK( pThread->m_Lock ); +#ifdef _WIN32 + CloseHandle( pThread->m_hThread ); + RemoveThreadHandleToIDMap( pThread->m_hThread ); + pThread->m_hThread = NULL; +#elif defined( _PS3 ) + pThread->m_threadZombieId = pThread->m_threadId; + pThread->m_threadEnd.Set(); + pThread->m_threadId = 0; +#elif defined(POSIX) + pThread->m_threadZombieId = pThread->m_threadId; + pThread->m_threadId = 0; +#else +#error +#endif + + pThread->m_ExitEvent.Set(); +#ifdef _PS3 + { + pThread->m_Lock.Unlock(); + sys_ppu_thread_exit( pInit->pThread->m_result ); + // reacquire the lock in case thread exit didn't actually exit the thread, so that + // AUTO_LOCK won't double-unlock the lock (to keep it paired) + pThread->m_Lock.Lock(); + } +#endif + +#if defined( POSIX )|| defined( _PS3 ) + return (void*)pInit->pThread->m_result; +#else + return pInit->pThread->m_result; +#endif +} + +#endif // THREADTOOLS_INL diff --git a/external/vpc/public/tier0/tslist.h b/external/vpc/public/tier0/tslist.h new file mode 100644 index 0000000..d8bc55e --- /dev/null +++ b/external/vpc/public/tier0/tslist.h @@ -0,0 +1,858 @@ +//========== Copyright � 2005, Valve Corporation, All rights reserved. ======== +// +// Purpose: +// +// LIFO from disassembly of Windows API and http://perso.wanadoo.fr/gmem/evenements/jim2002/articles/L17_Fober.pdf +// FIFO from http://perso.wanadoo.fr/gmem/evenements/jim2002/articles/L17_Fober.pdf +// +//============================================================================= + +#ifndef TSLIST_H +#define TSLIST_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#if ( defined( PLATFORM_X360 ) || defined( PLATFORM_WINDOWS_PC64 ) ) +#define USE_NATIVE_SLIST +#endif + +#if defined( USE_NATIVE_SLIST ) && !defined( _X360 ) && !defined( _PS3 ) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +#include "tier0/dbg.h" +#include "tier0/threadtools.h" + +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- + +#if defined(PLATFORM_WINDOWS_PC64) + +#define TSLIST_HEAD_ALIGNMENT 16 //MEMORY_ALLOCATION_ALIGNMENT +#define TSLIST_NODE_ALIGNMENT 16 //MEMORY_ALLOCATION_ALIGNMENT + +#define TSLIST_HEAD_ALIGN ALIGN16 +#define TSLIST_NODE_ALIGN ALIGN16 +#define TSLIST_HEAD_ALIGN_POST ALIGN16_POST +#define TSLIST_NODE_ALIGN_POST ALIGN16_POST + +#else + +#define TSLIST_HEAD_ALIGNMENT 8 +#define TSLIST_NODE_ALIGNMENT 8 + +#define TSLIST_HEAD_ALIGN ALIGN8 +#define TSLIST_NODE_ALIGN ALIGN8 +#define TSLIST_HEAD_ALIGN_POST ALIGN8_POST +#define TSLIST_NODE_ALIGN_POST ALIGN8_POST + +#endif + + +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE bool RunTSQueueTests( int nListSize = 10000, int nTests = 1 ); +PLATFORM_INTERFACE bool RunTSListTests( int nListSize = 10000, int nTests = 1 ); + +//----------------------------------------------------------------------------- +// Lock free list. +//----------------------------------------------------------------------------- +//#define USE_NATIVE_SLIST + +#ifdef USE_NATIVE_SLIST +typedef SLIST_ENTRY TSLNodeBase_t; +typedef SLIST_HEADER TSLHead_t; +#else +struct TSLIST_NODE_ALIGN TSLNodeBase_t +{ + TSLNodeBase_t *Next; // name to match Windows +} +TSLIST_NODE_ALIGN_POST; + +union TSLHead_t +{ + struct Value_t + { + TSLNodeBase_t *Next; + // <sergiy> Depth must be in the least significant halfword when atomically loading into register, + // to avoid carrying digits from Sequence. Carrying digits from Depth to Sequence is ok, + // because Sequence can be pretty much random. We could operate on both of them separately, + // but it could perhaps (?) lead to problems with store forwarding. I don't know 'cause I didn't + // performance-test or design original code, I'm just making it work on PowerPC. + #ifdef PLAT_BIG_ENDIAN + int16 Sequence; + int16 Depth; + #else + int16 Depth; + int16 Sequence; + #endif + } value; + + struct Value32_t + { + TSLNodeBase_t *Next_do_not_use_me; + int32 DepthAndSequence; + } value32; + + int64 value64; +}; +#endif + +//------------------------------------- + +class TSLIST_HEAD_ALIGN CTSListBase +{ +public: + CTSListBase() + { + if ( ((size_t)&m_Head) % TSLIST_HEAD_ALIGNMENT != 0 ) + { + Error( _T( "CTSListBase: Misaligned list\n" ) ); + DebuggerBreak(); + } + +#ifdef USE_NATIVE_SLIST + InitializeSListHead( &m_Head ); +#else + m_Head.value64 = (int64)0; +#endif + } + + ~CTSListBase() + { + Detach(); + } + + TSLNodeBase_t *Push( TSLNodeBase_t *pNode ) + { +#ifdef _DEBUG + if ( (size_t)pNode % TSLIST_NODE_ALIGNMENT != 0 ) + { + Error( _T( "CTSListBase: Misaligned node\n" ) ); + DebuggerBreak(); + } +#endif + +#ifdef USE_NATIVE_SLIST +#ifdef _X360 + // integrated write-release barrier + return (TSLNodeBase_t *)InterlockedPushEntrySListRelease( &m_Head, pNode ); +#else + return (TSLNodeBase_t *)InterlockedPushEntrySList( &m_Head, pNode ); +#endif +#else + TSLHead_t oldHead; + TSLHead_t newHead; + + #if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) + __lwsync(); // write-release barrier + #endif + + for (;;) + { + oldHead.value64 = m_Head.value64; + pNode->Next = oldHead.value.Next; + newHead.value.Next = pNode; + + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence + 0x10001; + + + if ( ThreadInterlockedAssignIf64( &m_Head.value64, newHead.value64, oldHead.value64 ) ) + { + break; + } + ThreadPause(); + }; + + return (TSLNodeBase_t *)oldHead.value.Next; +#endif + } + + TSLNodeBase_t *Pop() + { +#ifdef USE_NATIVE_SLIST +#ifdef _X360 + // integrated read-acquire barrier + TSLNodeBase_t *pNode = (TSLNodeBase_t *)InterlockedPopEntrySListAcquire( &m_Head ); +#else + TSLNodeBase_t *pNode = (TSLNodeBase_t *)InterlockedPopEntrySList( &m_Head ); +#endif + return pNode; +#else + TSLHead_t oldHead; + TSLHead_t newHead; + + for (;;) + { + oldHead.value64 = m_Head.value64; + if ( !oldHead.value.Next ) + return NULL; + + newHead.value.Next = oldHead.value.Next->Next; + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence - 1; + + + if ( ThreadInterlockedAssignIf64( &m_Head.value64, newHead.value64, oldHead.value64 ) ) + { + #if defined( PLATFORM_PS3 ) || defined( PLATFORM_X360 ) + __lwsync(); // read-acquire barrier + #endif + break; + } + ThreadPause(); + }; + + return (TSLNodeBase_t *)oldHead.value.Next; +#endif + } + + TSLNodeBase_t *Detach() + { +#ifdef USE_NATIVE_SLIST + TSLNodeBase_t *pBase = (TSLNodeBase_t *)InterlockedFlushSList( &m_Head ); +#if defined( _X360 ) || defined( _PS3 ) + __lwsync(); // read-acquire barrier +#endif + return pBase; +#else + TSLHead_t oldHead; + TSLHead_t newHead; + + do + { + ThreadPause(); + + oldHead.value64 = m_Head.value64; + if ( !oldHead.value.Next ) + return NULL; + + newHead.value.Next = NULL; + // <sergiy> the reason for AND'ing it instead of poking a short into memory + // is probably to avoid store forward issues, but I'm not sure because + // I didn't construct this code. In any case, leaving it as is on big-endian + newHead.value32.DepthAndSequence = oldHead.value32.DepthAndSequence & 0xffff0000; + + } while( !ThreadInterlockedAssignIf64( &m_Head.value64, newHead.value64, oldHead.value64 ) ); + + return (TSLNodeBase_t *)oldHead.value.Next; +#endif + } + + TSLHead_t *AccessUnprotected() + { + return &m_Head; + } + + int Count() const + { +#ifdef USE_NATIVE_SLIST + return QueryDepthSList( const_cast<TSLHead_t*>( &m_Head ) ); +#else + return m_Head.value.Depth; +#endif + } + +private: + TSLHead_t m_Head; +} +TSLIST_HEAD_ALIGN_POST; + +//------------------------------------- + +template <typename T> +class TSLIST_HEAD_ALIGN CTSSimpleList : public CTSListBase +{ +public: + void Push( T *pNode ) + { + Assert( sizeof(T) >= sizeof(TSLNodeBase_t) ); + CTSListBase::Push( (TSLNodeBase_t *)pNode ); + } + + T *Pop() + { + return (T *)CTSListBase::Pop(); + } +} +TSLIST_HEAD_ALIGN_POST; + +//------------------------------------- +// this is a replacement for CTSList<> and CObjectPool<> that does not +// have a per-item, per-alloc new/delete overhead +// similar to CTSSimpleList except that it allocates it's own pool objects +// and frees them on destruct. Also it does not overlay the TSNodeBase_t memory +// on T's memory +template< class T > +class TSLIST_HEAD_ALIGN CTSPool : public CTSListBase +{ + // packs the node and the item (T) into a single struct and pools those + struct TSLIST_NODE_ALIGN simpleTSPoolStruct_t : public TSLNodeBase_t + { + T elem; + } TSLIST_NODE_ALIGN_POST; + +public: + + ~CTSPool() + { + simpleTSPoolStruct_t *pNode = NULL; + while ( 1 ) + { + pNode = (simpleTSPoolStruct_t *)CTSListBase::Pop(); + if ( !pNode ) + break; + delete pNode; + } + } + + void PutObject( T *pInfo ) + { + char *pElem = (char *)pInfo; + pElem -= offsetof(simpleTSPoolStruct_t,elem); + simpleTSPoolStruct_t *pNode = (simpleTSPoolStruct_t *)pElem; + + CTSListBase::Push( pNode ); + } + + T *GetObject() + { + simpleTSPoolStruct_t *pNode = (simpleTSPoolStruct_t *)CTSListBase::Pop(); + if ( !pNode ) + { + pNode = new simpleTSPoolStruct_t; + } + return &pNode->elem; + } + + // omg windows sdk - why do you #define GetObject()? + FORCEINLINE T *Get() + { + return GetObject(); + } + +} TSLIST_HEAD_ALIGN_POST; +//------------------------------------- + +template <typename T> +class TSLIST_HEAD_ALIGN CTSList : public CTSListBase +{ +public: + struct TSLIST_NODE_ALIGN Node_t : public TSLNodeBase_t + { + Node_t() {} + Node_t( const T &init ) : elem( init ) {} + + T elem; + + } TSLIST_NODE_ALIGN_POST; + + ~CTSList() + { + Purge(); + } + + void Purge() + { + Node_t *pCurrent = Detach(); + Node_t *pNext; + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + } + + void RemoveAll() + { + Purge(); + } + + Node_t *Push( Node_t *pNode ) + { + return (Node_t *)CTSListBase::Push( pNode ); + } + + Node_t *Pop() + { + return (Node_t *)CTSListBase::Pop(); + } + + void PushItem( const T &init ) + { + Push( new Node_t( init ) ); + } + + bool PopItem( T *pResult) + { + Node_t *pNode = Pop(); + if ( !pNode ) + return false; + *pResult = pNode->elem; + delete pNode; + return true; + } + + Node_t *Detach() + { + return (Node_t *)CTSListBase::Detach(); + } + +} TSLIST_HEAD_ALIGN_POST; + +//------------------------------------- + +template <typename T> +class TSLIST_HEAD_ALIGN CTSListWithFreeList : public CTSListBase +{ +public: + struct TSLIST_NODE_ALIGN Node_t : public TSLNodeBase_t + { + Node_t() {} + Node_t( const T &init ) : elem( init ) {} + + T elem; + } TSLIST_NODE_ALIGN_POST; + + ~CTSListWithFreeList() + { + Purge(); + } + + void Purge() + { + Node_t *pCurrent = Detach(); + Node_t *pNext; + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + pCurrent = (Node_t *)m_FreeList.Detach(); + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + delete pCurrent; + pCurrent = pNext; + } + } + + void RemoveAll() + { + Node_t *pCurrent = Detach(); + Node_t *pNext; + while ( pCurrent ) + { + pNext = (Node_t *)pCurrent->Next; + m_FreeList.Push( pCurrent ); + pCurrent = pNext; + } + } + + Node_t *Push( Node_t *pNode ) + { + return (Node_t *)CTSListBase::Push( pNode ); + } + + Node_t *Pop() + { + return (Node_t *)CTSListBase::Pop(); + } + + void PushItem( const T &init ) + { + Node_t *pNode = (Node_t *)m_FreeList.Pop(); + if ( !pNode ) + { + pNode = new Node_t; + } + pNode->elem = init; + Push( pNode ); + } + + bool PopItem( T *pResult) + { + Node_t *pNode = Pop(); + if ( !pNode ) + return false; + *pResult = pNode->elem; + m_FreeList.Push( pNode ); + return true; + } + + Node_t *Detach() + { + return (Node_t *)CTSListBase::Detach(); + } + + void FreeNode( Node_t *pNode ) + { + m_FreeList.Push( pNode ); + } + +private: + CTSListBase m_FreeList; +} TSLIST_HEAD_ALIGN_POST; + +//----------------------------------------------------------------------------- +// Lock free queue +// +// A special consideration: the element type should be simple. This code +// actually dereferences freed nodes as part of pop, but later detects +// that. If the item in the queue is a complex type, only bad things can +// come of that. Also, therefore, if you're using Push/Pop instead of +// push item, be aware that the node memory cannot be freed until +// all threads that might have been popping have completed the pop. +// The PushItem()/PopItem() for handles this by keeping a persistent +// free list. Dont mix Push/PushItem. Note also nodes will be freed at the end, +// and are expected to have been allocated with operator new. +//----------------------------------------------------------------------------- + +template <typename T, bool bTestOptimizer = false, bool bFreeList = true> +class TSLIST_HEAD_ALIGN CTSQueue +{ +public: + struct TSLIST_NODE_ALIGN Node_t + { + Node_t() {} + Node_t( const T &init ) : elem( init ) {} + + Node_t *pNext; + T elem; + } TSLIST_NODE_ALIGN_POST; + + union TSLIST_HEAD_ALIGN NodeLink_t + { + struct Value_t + { + Node_t *pNode; + int32 sequence; + } value; + + int64 value64; + } TSLIST_HEAD_ALIGN_POST; + + CTSQueue() + { + COMPILE_TIME_ASSERT( sizeof(Node_t) >= sizeof(TSLNodeBase_t) ); + if ( ((size_t)&m_Head) % TSLIST_HEAD_ALIGNMENT != 0 ) + { + Error( "CTSQueue: Misaligned queue\n" ); + DebuggerBreak(); + } + if ( ((size_t)&m_Tail) % TSLIST_HEAD_ALIGNMENT != 0 ) + { + Error( "CTSQueue: Misaligned queue\n" ); + DebuggerBreak(); + } + m_Count = 0; + m_Head.value.sequence = m_Tail.value.sequence = 0; + m_Head.value.pNode = m_Tail.value.pNode = new Node_t; // list always contains a dummy node + m_Head.value.pNode->pNext = End(); + } + + ~CTSQueue() + { + Purge(); + Assert( m_Count == 0 ); + Assert( m_Head.value.pNode == m_Tail.value.pNode ); + Assert( m_Head.value.pNode->pNext == End() ); + delete m_Head.value.pNode; + } + + // Note: Purge, RemoveAll, and Validate are *not* threadsafe + void Purge() + { + if ( IsDebug() ) + { + Validate(); + } + + Node_t *pNode; + while ( ( pNode = Pop() ) != NULL ) + { + delete pNode; + } + + while ( bFreeList && ( pNode = (Node_t *)m_FreeNodes.Pop() ) != NULL ) + { + delete pNode; + } + + Assert( m_Count == 0 ); + Assert( m_Head.value.pNode == m_Tail.value.pNode ); + Assert( m_Head.value.pNode->pNext == End() ); + + m_Head.value.sequence = m_Tail.value.sequence = 0; + } + + void RemoveAll() + { + if ( IsDebug() ) + { + Validate(); + } + + Node_t *pNode; + while ( bFreeList && ( pNode = Pop() ) != NULL ) + { + m_FreeNodes.Push( (TSLNodeBase_t *)pNode ); + } + } + + bool Validate() + { + bool bResult = true; + int nNodes = 0; + + if ( m_Count == 0 ) + { + if ( m_Head.value.pNode != m_Tail.value.pNode ) + { + DebuggerBreakIfDebugging(); + bResult = false; + } + } + + Node_t *pNode = m_Head.value.pNode; + while ( pNode != End() ) + { + nNodes++; + pNode = pNode->pNext; + } + + nNodes--;// skip dummy node + + if ( nNodes != m_Count ) + { + DebuggerBreakIfDebugging(); + bResult = false; + } + + if ( !bResult ) + { + Msg( "Corrupt CTSQueueDetected" ); + } + + return bResult; + } + + void FinishPush( Node_t *pNode, const NodeLink_t &oldTail ) + { + NodeLink_t newTail; + + newTail.value.pNode = pNode; + newTail.value.sequence = oldTail.value.sequence + 1; + + ThreadMemoryBarrier(); + + InterlockedCompareExchangeNodeLink( &m_Tail, newTail, oldTail ); + } + + Node_t *Push( Node_t *pNode ) + { +#ifdef _DEBUG + if ( (size_t)pNode % TSLIST_NODE_ALIGNMENT != 0 ) + { + Error( "CTSListBase: Misaligned node\n" ); + DebuggerBreak(); + } +#endif + + NodeLink_t oldTail; + + pNode->pNext = End(); + + for (;;) + { + oldTail.value.sequence = m_Tail.value.sequence; + oldTail.value.pNode = m_Tail.value.pNode; + if ( InterlockedCompareExchangeNode( &(oldTail.value.pNode->pNext), pNode, End() ) == End() ) + { + break; + } + else + { + // Another thread is trying to push, help it along + FinishPush( oldTail.value.pNode->pNext, oldTail ); + } + } + + FinishPush( pNode, oldTail ); // This can fail if another thread pushed between the sequence and node grabs above. Later pushes or pops corrects + + m_Count++; + + return oldTail.value.pNode; + } + + Node_t *Pop() + { + #define TSQUEUE_BAD_NODE_LINK ( (Node_t *)INT_TO_POINTER( 0xdeadbeef ) ) + NodeLink_t * volatile pHead = &m_Head; + NodeLink_t * volatile pTail = &m_Tail; + Node_t * volatile * pHeadNode = &m_Head.value.pNode; + volatile int * volatile pHeadSequence = &m_Head.value.sequence; + Node_t * volatile * pTailNode = &pTail->value.pNode; + + NodeLink_t head; + NodeLink_t newHead; + Node_t *pNext; + int tailSequence; + T elem; + + for (;;) + { + head.value.sequence = *pHeadSequence; // must grab sequence first, which allows condition below to ensure pNext is valid + ThreadMemoryBarrier(); // need a barrier to prevent reordering of these assignments + head.value.pNode = *pHeadNode; + tailSequence = pTail->value.sequence; + pNext = head.value.pNode->pNext; + + if ( pNext && head.value.sequence == *pHeadSequence ) // Checking pNext only to force optimizer to not reorder the assignment to pNext and the compare of the sequence + { + if ( bTestOptimizer ) + { + if ( pNext == TSQUEUE_BAD_NODE_LINK ) + { + Msg( "Bad node link detected\n" ); + continue; + } + } + if ( head.value.pNode == *pTailNode ) + { + if ( pNext == End() ) + { + return NULL; + } + + // Another thread is trying to push, help it along + NodeLink_t &oldTail = head; // just reuse local memory for head to build old tail + oldTail.value.sequence = tailSequence; // reuse head pNode + FinishPush( pNext, oldTail ); + } + else if ( pNext != End() ) + { + elem = pNext->elem; // NOTE: next could be a freed node here, by design + newHead.value.pNode = pNext; + newHead.value.sequence = head.value.sequence + 1; + if ( InterlockedCompareExchangeNodeLink( pHead, newHead, head ) ) + { + ThreadMemoryBarrier(); + + if ( bTestOptimizer ) + { + head.value.pNode->pNext = TSQUEUE_BAD_NODE_LINK; + } + break; + } + } + } + } + + m_Count--; + head.value.pNode->elem = elem; + return head.value.pNode; + } + + void FreeNode( Node_t *pNode ) + { + if ( bFreeList ) + { + m_FreeNodes.Push( (TSLNodeBase_t *)pNode ); + } + else + { + delete pNode; + } + } + + void PushItem( const T &init ) + { + Node_t *pNode; + if ( bFreeList && ( pNode = (Node_t *)m_FreeNodes.Pop() ) != NULL ) + { + pNode->elem = init; + } + else + { + pNode = new Node_t( init ); + } + Push( pNode ); + } + + bool PopItem( T *pResult) + { + Node_t *pNode = Pop(); + if ( !pNode ) + return false; + *pResult = pNode->elem; + if ( bFreeList ) + { + m_FreeNodes.Push( (TSLNodeBase_t *)pNode ); + } + else + { + delete pNode; + } + return true; + } + + int Count() + { + return m_Count; + } + +private: + Node_t *End() { return (Node_t *)this; } // just need a unique signifier + +#ifndef _WIN64 + Node_t *InterlockedCompareExchangeNode( Node_t * volatile *ppNode, Node_t *value, Node_t *comperand ) + { + return (Node_t *)::ThreadInterlockedCompareExchangePointer( (void **)ppNode, value, comperand ); + } + + bool InterlockedCompareExchangeNodeLink( NodeLink_t volatile *pLink, const NodeLink_t &value, const NodeLink_t &comperand ) + { + return ThreadInterlockedAssignIf64( (int64 *)pLink, value.value64, comperand.value64 ); + } + +#else + Node_t *InterlockedCompareExchangeNode( Node_t * volatile *ppNode, Node_t *value, Node_t *comperand ) + { + AUTO_LOCK( m_ExchangeMutex ); + Node_t *retVal = *ppNode; + if ( *ppNode == comperand ) + *ppNode = value; + return retVal; + } + + bool InterlockedCompareExchangeNodeLink( NodeLink_t volatile *pLink, const NodeLink_t &value, const NodeLink_t &comperand ) + { + AUTO_LOCK( m_ExchangeMutex ); + if ( pLink->value64 == comperand.value64 ) + { + pLink->value64 = value.value64; + return true; + } + return false; + } + + CThreadFastMutex m_ExchangeMutex; +#endif + + NodeLink_t m_Head; + NodeLink_t m_Tail; + + CInterlockedInt m_Count; + + CTSListBase m_FreeNodes; +} TSLIST_HEAD_ALIGN_POST; + +#include "tier0/memdbgoff.h" + +#endif // TSLIST_H diff --git a/external/vpc/public/tier0/validator.h b/external/vpc/public/tier0/validator.h new file mode 100644 index 0000000..a3b336e --- /dev/null +++ b/external/vpc/public/tier0/validator.h @@ -0,0 +1,73 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + + +#include "valobject.h" + +#ifndef VALIDATOR_H +#define VALIDATOR_H + +#ifdef _WIN32 +#pragma once +#endif + + +#ifdef DBGFLAG_VALIDATE + + +class CValidator +{ +public: + // Constructors & destructors + CValidator( void ); + ~CValidator( void ); + + // Call this each time we enter a new Validate function + void Push( tchar *pchType, void *pvObj, tchar *pchName ); + + // Call this each time we exit a Validate function + void Pop( void ); + + // Claim ownership of a memory block + void ClaimMemory( void *pvMem ); + + // Finish performing a check and perform necessary computations + void Finalize( void ); + + // Render our results to the console + void RenderObjects( int cubThreshold ); // Render all reported objects + void RenderLeaks( void ); // Render all memory leaks + + // List manipulation functions: + CValObject *FindObject( void *pvObj ); // Returns CValObject containing pvObj, or NULL. + void DiffAgainst( CValidator *pOtherValidator ); // Removes any entries from this validator that are also present in the other. + + // Accessors + bool BMemLeaks( void ) { return m_bMemLeaks; }; + CValObject *PValObjectFirst( void ) { return m_pValObjectFirst; }; + + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures + + +private: + CValObject *m_pValObjectFirst; // Linked list of all ValObjects + CValObject *m_pValObjectLast; // Last ValObject on the linked list + + CValObject *m_pValObjectCur; // Object we're current processing + + int m_cpvOwned; // Total # of blocks owned + + int m_cpubLeaked; // # of leaked memory blocks + int m_cubLeaked; // Amount of leaked memory + bool m_bMemLeaks; // Has any memory leaked? +}; + + +#endif // DBGFLAG_VALIDATE + + +#endif // VALIDATOR_H diff --git a/external/vpc/public/tier0/valobject.h b/external/vpc/public/tier0/valobject.h new file mode 100644 index 0000000..8a2cbf0 --- /dev/null +++ b/external/vpc/public/tier0/valobject.h @@ -0,0 +1,72 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: CValObject is used for tracking individual objects that report +// in to CValidator. Whenever a new object reports in (via CValidator::Push), +// we create a new CValObject to aggregate stats for it. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VALOBJECT_H +#define VALOBJECT_H +#ifdef _WIN32 +#pragma once +#endif + + +#ifdef DBGFLAG_VALIDATE +class CValObject +{ +public: + // Constructors & destructors + CValObject( void ) { }; + ~CValObject( void ); + + void Init( tchar *pchType, void *pvObj, tchar *pchName, CValObject *pValObjectParent, + CValObject *pValObjectPrev ); + + // Our object has claimed ownership of a memory block + void ClaimMemoryBlock( void *pvMem ); + + // A child of ours has claimed ownership of a memory block + void ClaimChildMemoryBlock( int cubUser ); + + // Accessors + tchar *PchType( void ) { return m_rgchType; }; + void *PvObj( void ) { return m_pvObj; }; + tchar *PchName( void ) { return m_rgchName; }; + CValObject *PValObjectParent( void ) { return m_pValObjectParent; }; + int NLevel( void ) { return m_nLevel; }; + CValObject *PValObjectNext( void ) { return m_pValObjectNext; }; + int CpubMemSelf( void ) { return m_cpubMemSelf; }; + int CubMemSelf( void ) { return m_cubMemSelf; }; + int CpubMemTree( void ) { return m_cpubMemTree; }; + int CubMemTree( void ) { return m_cubMemTree; }; + int NUser( void ) { return m_nUser; }; + void SetNUser( int nUser ) { m_nUser = nUser; }; + void SetBNewSinceSnapshot( bool bNewSinceSnapshot ) { m_bNewSinceSnapshot = bNewSinceSnapshot; } + bool BNewSinceSnapshot( void ) { return m_bNewSinceSnapshot; } + +private: + bool m_bNewSinceSnapshot; // If this block is new since the snapshot. + tchar m_rgchType[64]; // Type of the object we represent + tchar m_rgchName[64]; // Name of this particular object + void *m_pvObj; // Pointer to the object we represent + + CValObject *m_pValObjectParent; // Our parent object in the tree. + int m_nLevel; // Our depth in the tree + + CValObject *m_pValObjectNext; // Next ValObject in the linked list + + int m_cpubMemSelf; // # of memory blocks we own directly + int m_cubMemSelf; // Total size of the memory blocks we own directly + + int m_cpubMemTree; // # of memory blocks owned by us and our children + int m_cubMemTree; // Total size of the memory blocks owned by us and our children + + int m_nUser; // Field provided for use by our users +}; +#endif // DBGFLAG_VALIDATE + + +#endif // VALOBJECT_H diff --git a/external/vpc/public/tier0/valve_off.h b/external/vpc/public/tier0/valve_off.h new file mode 100644 index 0000000..954a140 --- /dev/null +++ b/external/vpc/public/tier0/valve_off.h @@ -0,0 +1,33 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This turns off all Valve-specific #defines. Because we sometimes +// call external include files from inside .cpp files, we need to +// wrap those includes like this: +// #include "tier0/valve_off.h" +// #include <external.h> +// #include "tier0/valve_on.h" +// +// $NoKeywords: $ +//=============================================================================// + + +#ifdef STEAM + +//----------------------------------------------------------------------------- +// Unicode-related #defines (see wchartypes.h) +//----------------------------------------------------------------------------- +#undef char + + +//----------------------------------------------------------------------------- +// Memory-related #defines +//----------------------------------------------------------------------------- +#undef malloc +#undef realloc +#undef _expand +#undef free + +#endif // STEAM + +// Allow long to be used in 3rd-party headers +#undef long
\ No newline at end of file diff --git a/external/vpc/public/tier0/valve_on.h b/external/vpc/public/tier0/valve_on.h new file mode 100644 index 0000000..03ab0a7 --- /dev/null +++ b/external/vpc/public/tier0/valve_on.h @@ -0,0 +1,37 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: This turns on all Valve-specific #defines. Because we sometimes +// call external include files from inside .cpp files, we need to +// wrap those includes like this: +// #include "tier0/valve_off.h" +// #include <external.h> +// #include "tier0/valve_on.h" +// +// $NoKeywords: $ +//=============================================================================// + + +#ifdef STEAM +//----------------------------------------------------------------------------- +// Unicode-related #defines (see wchartypes.h) +//----------------------------------------------------------------------------- +#ifdef ENFORCE_WCHAR +#define char DontUseChar_SeeWcharOn.h +#endif + + +//----------------------------------------------------------------------------- +// Memory-related #defines +//----------------------------------------------------------------------------- +#define malloc( cub ) HEY_DONT_USE_MALLOC_USE_PVALLOC +#define realloc( pvOld, cub ) HEY_DONT_USE_REALLOC_USE_PVREALLOC +#define _expand( pvOld, cub ) HEY_DONT_USE_EXPAND_USE_PVEXPAND +#define free( pv ) HEY_DONT_USE_FREE_USE_FREEPV + +#endif + + +// Long is evil because it's treated differently by different compilers +#ifdef DISALLOW_USE_OF_LONG + #define long long_is_the_devil_stop_using_it_use_int32_or_int64 +#endif diff --git a/external/vpc/public/tier0/vprof.h b/external/vpc/public/tier0/vprof.h new file mode 100644 index 0000000..5208e21 --- /dev/null +++ b/external/vpc/public/tier0/vprof.h @@ -0,0 +1,1510 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Real-Time Hierarchical Profiling +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef VPROF_H +#define VPROF_H + +#include "tier0/dbg.h" +#include "tier0/fasttimer.h" +#include "tier0/l2cache.h" +#include "tier0/threadtools.h" +#include "tier0/vprof_sn.h" + +// VProf is enabled by default in all configurations -except- X360 Retail. +#if !( defined( _GAMECONSOLE ) && defined( _CERT ) ) +#define VPROF_ENABLED +#endif + +#if defined(_X360) && defined(VPROF_ENABLED) + +// PIX is always enabled in PROFILE build on X360 +#ifdef PROFILE +#define VPROF_PIX 1 +#endif + +#include "tier0/pmc360.h" +#ifndef USE_PIX +#define VPROF_UNDO_PIX +#undef _PIX_H_ +#undef PIXBeginNamedEvent +#undef PIXEndNamedEvent +#undef PIXSetMarker +#undef PIXNameThread +#define USE_PIX +#include <pix.h> +#undef USE_PIX +#else +#include <pix.h> +#endif +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +// enable this to get detailed nodes beneath budget +//#define VPROF_LEVEL 1 + +#if defined(_X360) || defined(_PS3) +#define VPROF_VXCONSOLE_EXISTS 1 +#endif + +#if defined(_X360) && defined(VPROF_PIX) +#pragma comment( lib, "Xapilibi" ) +#endif + +//----------------------------------------------------------------------------- +// +// Profiling instrumentation macros +// + +#define MAXCOUNTERS 256 + + +#ifdef VPROF_ENABLED + +#define VPROF_VTUNE_GROUP + +#define VPROF( name ) VPROF_(name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0) +#define VPROF_ASSERT_ACCOUNTED( name ) VPROF_(name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, true, 0) +#define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) VPROF_##detail(name,group, bAssertAccounted, budgetFlags) + +#define VPROF_BUDGET( name, group ) VPROF_BUDGET_FLAGS(name, group, BUDGETFLAG_OTHER) +#define VPROF_BUDGET_FLAGS( name, group, flags ) VPROF_(name, 0, group, false, flags) + +#define VPROF_SCOPE_BEGIN( tag ) do { VPROF( tag ) +#define VPROF_SCOPE_END() } while (0) + +#define VPROF_ONLY( expression ) ( expression ) + +#define VPROF_ENTER_SCOPE( name ) g_VProfCurrentProfile.EnterScope( name, 1, VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, 0 ) +#define VPROF_EXIT_SCOPE() g_VProfCurrentProfile.ExitScope() + +#define VPROF_BUDGET_GROUP_ID_UNACCOUNTED 0 + + +// Budgetgroup flags. These are used with VPROF_BUDGET_FLAGS. +// These control which budget panels the groups show up in. +// If a budget group uses VPROF_BUDGET, it gets the default +// which is BUDGETFLAG_OTHER. +#define BUDGETFLAG_CLIENT (1<<0) // Shows up in the client panel. +#define BUDGETFLAG_SERVER (1<<1) // Shows up in the server panel. +#define BUDGETFLAG_OTHER (1<<2) // Unclassified (the client shows these but the dedicated server doesn't). +#define BUDGETFLAG_HIDDEN (1<<15) +#define BUDGETFLAG_ALL 0xFFFF + + +// NOTE: You can use strings instead of these defines. . they are defined here and added +// in vprof.cpp so that they are always in the same order. +#define VPROF_BUDGETGROUP_OTHER_UNACCOUNTED _T("Unaccounted") +#define VPROF_BUDGETGROUP_WORLD_RENDERING _T("World Rendering") +#define VPROF_BUDGETGROUP_DISPLACEMENT_RENDERING _T("Displacement_Rendering") +#define VPROF_BUDGETGROUP_GAME _T("Game") +#define VPROF_BUDGETGROUP_NPCS _T("NPCs") +#define VPROF_BUDGETGROUP_SERVER_ANIM _T("Server Animation") +#define VPROF_BUDGETGROUP_PHYSICS _T("Physics") +#define VPROF_BUDGETGROUP_STATICPROP_RENDERING _T("Static_Prop_Rendering") +#define VPROF_BUDGETGROUP_MODEL_RENDERING _T("Other_Model_Rendering") +#define VPROF_BUDGETGROUP_MODEL_FAST_PATH_RENDERING _T("Fast Path Model Rendering") +#define VPROF_BUDGETGROUP_BRUSH_FAST_PATH_RENDERING _T("Fast Path Brush Rendering") +#define VPROF_BUDGETGROUP_BRUSHMODEL_RENDERING _T("Brush_Model_Rendering") +#define VPROF_BUDGETGROUP_SHADOW_RENDERING _T("Shadow_Rendering") +#define VPROF_BUDGETGROUP_DETAILPROP_RENDERING _T("Detail_Prop_Rendering") +#define VPROF_BUDGETGROUP_PARTICLE_RENDERING _T("Particle/Effect_Rendering") +#define VPROF_BUDGETGROUP_ROPES _T("Ropes") +#define VPROF_BUDGETGROUP_DLIGHT_RENDERING _T("Dynamic_Light_Rendering") +#define VPROF_BUDGETGROUP_OTHER_NETWORKING _T("Networking") +#define VPROF_BUDGETGROUP_CLIENT_ANIMATION _T("Client_Animation") +#define VPROF_BUDGETGROUP_OTHER_SOUND _T("Sound") +#define VPROF_BUDGETGROUP_OTHER_VGUI _T("VGUI") +#define VPROF_BUDGETGROUP_OTHER_FILESYSTEM _T("FileSystem") +#define VPROF_BUDGETGROUP_PREDICTION _T("Prediction") +#define VPROF_BUDGETGROUP_INTERPOLATION _T("Interpolation") +#define VPROF_BUDGETGROUP_SWAP_BUFFERS _T("Swap_Buffers") +#define VPROF_BUDGETGROUP_PLAYER _T("Player") +#define VPROF_BUDGETGROUP_OCCLUSION _T("Occlusion") +#define VPROF_BUDGETGROUP_OVERLAYS _T("Overlays") +#define VPROF_BUDGETGROUP_TOOLS _T("Tools") +#define VPROF_BUDGETGROUP_LIGHTCACHE _T("Light_Cache") +#define VPROF_BUDGETGROUP_DISP_HULLTRACES _T("Displacement_Hull_Traces") +#define VPROF_BUDGETGROUP_TEXTURE_CACHE _T("Texture_Cache") +#define VPROF_BUDGETGROUP_REPLAY _T("Replay") +#define VPROF_BUDGETGROUP_PARTICLE_SIMULATION _T("Particle Simulation") +#define VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING _T("Flashlight Shadows") +#define VPROF_BUDGETGROUP_CLIENT_SIM _T("Client Simulation") // think functions, tempents, etc. +#define VPROF_BUDGETGROUP_STEAM _T("Steam") +#define VPROF_BUDGETGROUP_CVAR_FIND _T("Cvar_Find") +#define VPROF_BUDGETGROUP_CLIENTLEAFSYSTEM _T("ClientLeafSystem") +#define VPROF_BUDGETGROUP_JOBS_COROUTINES _T("Jobs/Coroutines") + +#ifdef VPROF_VXCONSOLE_EXISTS +// update flags +#define VPROF_UPDATE_BUDGET 0x01 // send budget data every frame +#define VPROF_UPDATE_TEXTURE_GLOBAL 0x02 // send global texture data every frame +#define VPROF_UPDATE_TEXTURE_PERFRAME 0x04 // send perframe texture data every frame +#endif + +//------------------------------------- + +#ifndef VPROF_LEVEL +#define VPROF_LEVEL 0 +#endif + +#if !defined( VPROF_SN_LEVEL ) && !defined( _CERT ) +#define VPROF_SN_LEVEL 0 +#endif + +#define VPROF_0(name,group,assertAccounted,budgetFlags) CVProfScope VProf_(name, 0, group, assertAccounted, budgetFlags); + +#if VPROF_LEVEL > 0 +# define VPROF_1(name,group,assertAccounted,budgetFlags) CVProfScope VProf_(name, 1, group, assertAccounted, budgetFlags); +#else +# if VPROF_SN_LEVEL > 0 && defined( _PS3 ) +# define VPROF_1(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_1(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +#if VPROF_LEVEL > 1 +#define VPROF_2(name,group,assertAccounted,budgetFlags) CVProfScope VProf_(name, 2, group, assertAccounted, budgetFlags); +#else +# if VPROF_SN_LEVEL > 1 && defined( _PS3 ) +# define VPROF_2(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_2(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +#if VPROF_LEVEL > 2 +#define VPROF_3(name,group,assertAccounted,budgetFlags) CVProfScope VProf_(name, 3, group, assertAccounted, budgetFlags); +#else +# if VPROF_SN_LEVEL > 2 && defined( _PS3 ) +# define VPROF_3(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_3(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +#if VPROF_LEVEL > 3 +#define VPROF_4(name,group,assertAccounted,budgetFlags) CVProfScope VProf_(name, 4, group, assertAccounted, budgetFlags); +#else +# if VPROF_SN_LEVEL > 3 && defined( _PS3 ) +# define VPROF_4(name,group,assertAccounted,budgetFlags) CVProfSnMarkerScope VProfSn_( name ) +# else +# define VPROF_4(name,group,assertAccounted,budgetFlags) ((void)0) +# endif +#endif + +//------------------------------------- + +#ifdef _MSC_VER +#define VProfCode( code ) \ + if ( 0 ) \ + ; \ + else \ + { \ + VPROF( __FUNCTION__ ": " #code ); \ + code; \ + } +#else +#define VProfCode( code ) \ + if ( 0 ) \ + ; \ + else \ + { \ + VPROF( #code ); \ + code; \ + } +#endif + + +//------------------------------------- + +#define VPROF_INCREMENT_COUNTER(name,amount) do { static CVProfCounter _counter( name ); _counter.Increment( amount ); } while( 0 ) +#define VPROF_INCREMENT_GROUP_COUNTER(name,group,amount) do { static CVProfCounter _counter( name, group ); _counter.Increment( amount ); } while( 0 ) +#define VPROF_SET_COUNTER(name,amount) do { static CVProfCounter _counter( name ); _counter.Set( amount ); } while( 0 ) +#define VPROF_SET_GROUP_COUNTER(name,group,amount) do { static CVProfCounter _counter( name, group ); _counter.Set( amount ); } while( 0 ) + +#else + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 0 ) +# define VPROF( name ) CVProfSnMarkerScope VProfSn_( name ) +# define VPROF_ASSERT_ACCOUNTED( name ) VPROF( name ) +# define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) VPROF_##detail( name, group, bAssertAccounted, budgetFlags ) +# define VPROF_0(name,group,assertAccounted,budgetFlags) VPROF( name ) +# define VPROF_BUDGET( name, group ) VPROF( name ) +# define VPROF_BUDGET_FLAGS( name, group, flags ) VPROF( name ) + +# define VPROF_SCOPE_BEGIN( tag ) do { VPROF( tag ) +# define VPROF_SCOPE_END() } while (0) + +# define VPROF_ONLY( expression ) ( expression ) + +# define VPROF_ENTER_SCOPE( name ) g_pfnPushMarker( name ) +# define VPROF_EXIT_SCOPE() g_pfnPopMarker() +# else +# define VPROF( name ) ((void)0) +# define VPROF_ASSERT_ACCOUNTED( name ) ((void)0) +# define VPROF_( name, detail, group, bAssertAccounted, budgetFlags ) ((void)0) +# define VPROF_0(name,group,assertAccounted,budgetFlags) ((void)0) +# define VPROF_BUDGET( name, group ) ((void)0) +# define VPROF_BUDGET_FLAGS( name, group, flags ) ((void)0) + +# define VPROF_SCOPE_BEGIN( tag ) do { +# define VPROF_SCOPE_END() } while (0) + +# define VPROF_ONLY( expression ) ((void)0) + +# define VPROF_ENTER_SCOPE( name ) +# define VPROF_EXIT_SCOPE() +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 1 ) +# define VPROF_1(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_1(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 2 ) +# define VPROF_2(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_2(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 3 ) +# define VPROF_3(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_3(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + +# if defined( VPROF_SN_LEVEL ) && ( VPROF_SN_LEVEL >= 4 ) +# define VPROF_4(name,group,assertAccounted,budgetFlags) VPROF( name ) +# else +# define VPROF_4(name,group,assertAccounted,budgetFlags) ((void)0) +# endif + + + +#define VPROF_INCREMENT_COUNTER(name,amount) ((void)0) +#define VPROF_INCREMENT_GROUP_COUNTER(name,group,amount) ((void)0) +#define VPROF_SET_COUNTER(name,amount) ((void)0) +#define VPROF_SET_GROUP_COUNTER(name,group,amount) ((void)0) + +#define VPROF_TEST_SPIKE( msec ) ((void)0) + +#define VProfCode( code ) code + +#endif + +//----------------------------------------------------------------------------- + +#ifdef VPROF_ENABLED + +//----------------------------------------------------------------------------- +// +// A node in the call graph hierarchy +// + +class PLATFORM_CLASS CVProfNode +{ +friend class CVProfRecorder; +friend class CVProfile; + +public: + CVProfNode( const tchar * pszName, int detailLevel, CVProfNode *pParent, const tchar *pBudgetGroupName, int budgetFlags ); + ~CVProfNode(); + + CVProfNode *GetSubNode( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, int budgetFlags ); + CVProfNode *GetSubNode( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName ); + CVProfNode *GetParent(); + CVProfNode *GetSibling(); + CVProfNode *GetPrevSibling(); + CVProfNode *GetChild(); + + void MarkFrame(); + void ResetPeak(); + + void Pause(); + void Resume(); + void Reset(); + + void EnterScope(); + bool ExitScope(); + + const tchar *GetName(); + + int GetBudgetGroupID() + { + return m_BudgetGroupID; + } + + // Only used by the record/playback stuff. + void SetBudgetGroupID( int id ) + { + m_BudgetGroupID = id; + } + + int GetCurCalls(); + double GetCurTime(); + int GetPrevCalls(); + double GetPrevTime(); + int GetTotalCalls(); + double GetTotalTime(); + double GetPeakTime(); + + double GetCurTimeLessChildren(); + double GetPrevTimeLessChildren(); + double GetTotalTimeLessChildren(); + + int GetPrevL2CacheMissLessChildren(); + int GetPrevLoadHitStoreLessChildren(); + + void ClearPrevTime(); + + int GetL2CacheMisses(); + + // Not used in the common case... + void SetCurFrameTime( unsigned long milliseconds ); + + void SetClientData( int iClientData ) { m_iClientData = iClientData; } + int GetClientData() const { return m_iClientData; } + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + + +// Used by vprof record/playback. +private: + + void SetUniqueNodeID( int id ) + { + m_iUniqueNodeID = id; + } + + int GetUniqueNodeID() const + { + return m_iUniqueNodeID; + } + + static int s_iCurrentUniqueNodeID; + + +private: + const tchar *m_pszName; + CFastTimer m_Timer; + + // L2 Cache data. + int m_iPrevL2CacheMiss; + int m_iCurL2CacheMiss; + int m_iTotalL2CacheMiss; + +#ifndef _X360 + // L2 Cache data. + CL2Cache m_L2Cache; +#else // 360: + + unsigned int m_iBitFlags; // see enum below for settings + CPMCData m_PMCData; + int m_iPrevLoadHitStores; + int m_iCurLoadHitStores; + int m_iTotalLoadHitStores; + + public: + enum FlagBits + { + kRecordL2 = 0x01, + kCPUTrace = 0x02, ///< cause a PIX trace inside this node. + }; + // call w/ true to enable L2 and LHS recording; false to turn it off + inline void EnableL2andLHS(bool enable) + { + if (enable) + m_iBitFlags |= kRecordL2; + else + m_iBitFlags &= (~kRecordL2); + } + + inline bool IsL2andLHSEnabled( void ) + { + return (m_iBitFlags & kRecordL2) != 0; + } + + int GetLoadHitStores(); + + private: + +#endif + + int m_nRecursions; + + unsigned m_nCurFrameCalls; + CCycleCount m_CurFrameTime; + + unsigned m_nPrevFrameCalls; + CCycleCount m_PrevFrameTime; + + unsigned m_nTotalCalls; + CCycleCount m_TotalTime; + + CCycleCount m_PeakTime; + + CVProfNode *m_pParent; + CVProfNode *m_pChild; + CVProfNode *m_pSibling; + + int m_BudgetGroupID; + + int m_iClientData; + int m_iUniqueNodeID; +}; + +//----------------------------------------------------------------------------- +// +// Coordinator and root node of the profile hierarchy tree +// + +enum VProfReportType_t +{ + VPRT_SUMMARY = ( 1 << 0 ), + VPRT_HIERARCHY = ( 1 << 1 ), + VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY = ( 1 << 2 ), + VPRT_LIST_BY_TIME = ( 1 << 3 ), + VPRT_LIST_BY_TIME_LESS_CHILDREN = ( 1 << 4 ), + VPRT_LIST_BY_AVG_TIME = ( 1 << 5 ), + VPRT_LIST_BY_AVG_TIME_LESS_CHILDREN = ( 1 << 6 ), + VPRT_LIST_BY_PEAK_TIME = ( 1 << 7 ), + VPRT_LIST_BY_PEAK_OVER_AVERAGE = ( 1 << 8 ), + VPRT_LIST_TOP_ITEMS_ONLY = ( 1 << 9 ), + + VPRT_FULL = (0xffffffff & ~(VPRT_HIERARCHY_TIME_PER_FRAME_AND_COUNT_ONLY|VPRT_LIST_TOP_ITEMS_ONLY)), +}; + +enum CounterGroup_t +{ + COUNTER_GROUP_DEFAULT=0, + COUNTER_GROUP_NO_RESET, // The engine doesn't reset these counters. Usually, they are used + // like global variables that can be accessed across modules. + COUNTER_GROUP_TEXTURE_GLOBAL, // Global texture usage counters (totals for what is currently in memory). + COUNTER_GROUP_TEXTURE_PER_FRAME, // Per-frame texture usage counters. + COUNTER_GROUP_GRAPHICS_PER_FRAME, // Misc graphics counters that are reset each frame +}; + +class PLATFORM_CLASS CVProfile +{ +public: + CVProfile(); + ~CVProfile(); + + void Term(); + + // + // Runtime operations + // + + void Start(); + void Stop(); + + void SetTargetThreadId( unsigned id ) { m_TargetThreadId = id; } + unsigned GetTargetThreadId() { return m_TargetThreadId; } + bool InTargetThread() { return ( m_TargetThreadId == ThreadGetCurrentId() ); } + +#ifdef VPROF_VXCONSOLE_EXISTS + enum VXConsoleReportMode_t + { + VXCONSOLE_REPORT_TIME = 0, + VXCONSOLE_REPORT_L2CACHE_MISSES, + VXCONSOLE_REPORT_LOAD_HIT_STORE, + VXCONSOLE_REPORT_COUNT, + }; + + void VXProfileStart(); + void VXProfileUpdate(); + void VXEnableUpdateMode( int event, bool bEnable ); + void VXSendNodes( void ); + + void PMCDisableAllNodes(CVProfNode *pStartNode = NULL); ///< turn off l2 and lhs recording for everywhere + bool PMCEnableL2Upon(const tchar *pszNodeName, bool bRecursive = false); ///< enable l2 and lhs recording for one given node + bool PMCDisableL2Upon(const tchar *pszNodeName, bool bRecursive = false); ///< enable l2 and lhs recording for one given node + + void DumpEnabledPMCNodes( void ); + + void VXConsoleReportMode( VXConsoleReportMode_t mode ); + void VXConsoleReportScale( VXConsoleReportMode_t mode, float flScale ); +#endif + +#ifdef _X360 + + + // the CPU trace mode is actually a small state machine; it can be off, primed for + // single capture, primed for everything-in-a-frame capture, or currently in everything-in-a-frame + // capture. + enum CPUTraceState + { + kDisabled, + kFirstHitNode, // record from the first time we hit the node until that node ends + kAllNodesInFrame_WaitingForMark, // we're going to record all the times a node is hit in a frame, but are waiting for the frame to start + kAllNodesInFrame_Recording, // we're recording all hits on a node this frame. + + // Same as above, but going to record for > 1 frame + kAllNodesInFrame_WaitingForMarkMultiFrame, // we're going to record all the times a node is hit in a frame, but are waiting for the frame to start + kAllNodesInFrame_RecordingMultiFrame, + }; + + // Global switch to turn CPU tracing on or off at all. The idea is you set up a node first, + // then trigger tracing by throwing this to true. It'll reset back to false after the trace + // happens. + inline CPUTraceState GetCPUTraceMode(); + inline void SetCPUTraceEnabled( CPUTraceState enabled, bool bTraceCompleteEvent = false, int nNumFrames = -1 ); + inline void IncrementMultiTraceIndex(); // tick up the counter that gets appended to the multi-per-frame traces + inline unsigned int GetMultiTraceIndex(); // return the counter + void CPUTraceDisableAllNodes( CVProfNode *pStartNode = NULL ); // disable the cpu trace flag wherever it may be + CVProfNode *CPUTraceEnableForNode( const tchar *pszNodeName ); // enable cpu trace on this node only, disabling it wherever else it may be on. + CVProfNode *CPUTraceGetEnabledNode( CVProfNode *pStartNode = NULL ); // return the node enabled for CPU tracing, or NULL. + const char *GetCPUTraceFilename(); // get the filename the trace should write into. + const char *SetCPUTraceFilename( const char *filename ); // set the filename the trace should write into. (don't specify the extension; I'll do that.) + inline bool TraceCompleteEvent( void ); + +#ifdef _X360 + void LatchMultiFrame( int64 cycles ); + void SpewWorstMultiFrame(); +#endif + +#endif + + void EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted ); + void EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ); + void ExitScope(); + + void MarkFrame(); + void ResetPeaks(); + + void Pause(); + void Resume(); + void Reset(); + + bool IsEnabled() const; + int GetDetailLevel() const; + + bool AtRoot() const; + + // + // Queries + // + +#ifdef VPROF_VTUNE_GROUP +# define MAX_GROUP_STACK_DEPTH 1024 + + void EnableVTuneGroup( const tchar *pGroupName ) + { + m_nVTuneGroupID = BudgetGroupNameToBudgetGroupID( pGroupName ); + m_bVTuneGroupEnabled = true; + } + void DisableVTuneGroup( void ) + { + m_bVTuneGroupEnabled = false; + } + + inline void PushGroup( int nGroupID ); + inline void PopGroup( void ); +#endif + + int NumFramesSampled() { return m_nFrames; } + double GetPeakFrameTime(); + double GetTotalTimeSampled(); + double GetTimeLastFrame(); + + CVProfNode *GetRoot(); + CVProfNode *FindNode( CVProfNode *pStartNode, const tchar *pszNode ); + CVProfNode *GetCurrentNode(); + + void OutputReport( int type = VPRT_FULL, const tchar *pszStartNode = NULL, int budgetGroupID = -1 ); + + const tchar *GetBudgetGroupName( int budgetGroupID ); + int GetBudgetGroupFlags( int budgetGroupID ) const; // Returns a combination of BUDGETFLAG_ defines. + int GetNumBudgetGroups( void ); + void GetBudgetGroupColor( int budgetGroupID, int &r, int &g, int &b, int &a ); + int BudgetGroupNameToBudgetGroupID( const tchar *pBudgetGroupName ); + int BudgetGroupNameToBudgetGroupID( const tchar *pBudgetGroupName, int budgetFlagsToORIn ); + void RegisterNumBudgetGroupsChangedCallBack( void (*pCallBack)(void) ); + + int BudgetGroupNameToBudgetGroupIDNoCreate( const tchar *pBudgetGroupName ) { return FindBudgetGroupName( pBudgetGroupName ); } + + void HideBudgetGroup( int budgetGroupID, bool bHide = true ); + void HideBudgetGroup( const tchar *pszName, bool bHide = true ) { HideBudgetGroup( BudgetGroupNameToBudgetGroupID( pszName), bHide ); } + + int *FindOrCreateCounter( const tchar *pName, CounterGroup_t eCounterGroup=COUNTER_GROUP_DEFAULT ); + void ResetCounters( CounterGroup_t eCounterGroup ); + + int GetNumCounters( void ) const; + + const tchar *GetCounterName( int index ) const; + int GetCounterValue( int index ) const; + const tchar *GetCounterNameAndValue( int index, int &val ) const; + CounterGroup_t GetCounterGroup( int index ) const; + + // Performance monitoring events. + void PMEInitialized( bool bInit ) { m_bPMEInit = bInit; } + void PMEEnable( bool bEnable ) { m_bPMEEnabled = bEnable; } + +#ifdef _X360 + bool UsePME( void ) { return ( CPMCData::IsInitialized() && m_bPMEEnabled ); } +#elif defined( _PS3 ) + inline bool UsePME( void ) { return false; } +#else + bool UsePME( void ) { return ( m_bPMEInit && m_bPMEEnabled ); } +#endif + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, tchar *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +protected: + + void FreeNodes_R( CVProfNode *pNode ); + +#ifdef VPROF_VTUNE_GROUP + bool VTuneGroupEnabled() + { + return m_bVTuneGroupEnabled; + } + int VTuneGroupID() + { + return m_nVTuneGroupID; + } +#endif + + void SumTimes( const tchar *pszStartNode, int budgetGroupID ); + void SumTimes( CVProfNode *pNode, int budgetGroupID ); + void DumpNodes( CVProfNode *pNode, int indent, bool bAverageAndCountOnly ); + int FindBudgetGroupName( const tchar *pBudgetGroupName ); + int AddBudgetGroupName( const tchar *pBudgetGroupName, int budgetFlags ); + +#ifdef VPROF_VTUNE_GROUP + bool m_bVTuneGroupEnabled; + int m_nVTuneGroupID; + int m_GroupIDStack[MAX_GROUP_STACK_DEPTH]; + int m_GroupIDStackDepth; +#endif + int m_enabled; + bool m_fAtRoot; // tracked for efficiency of the "not profiling" case + CVProfNode *m_pCurNode; + CVProfNode m_Root; + int m_nFrames; + int m_ProfileDetailLevel; + int m_pausedEnabledDepth; + + class CBudgetGroup + { + public: + tchar *m_pName; + int m_BudgetFlags; + }; + + CBudgetGroup *m_pBudgetGroups; + int m_nBudgetGroupNamesAllocated; + int m_nBudgetGroupNames; + void (*m_pNumBudgetGroupsChangedCallBack)(void); + + // Performance monitoring events. + bool m_bPMEInit; + bool m_bPMEEnabled; + + int m_Counters[MAXCOUNTERS]; + char m_CounterGroups[MAXCOUNTERS]; // (These are CounterGroup_t's). + tchar *m_CounterNames[MAXCOUNTERS]; + int m_NumCounters; + +#ifdef VPROF_VXCONSOLE_EXISTS + int m_UpdateMode; + int m_nFramesRemaining; + int m_nFrameCount; + int64 m_WorstCycles; + char m_WorstTraceFilename[128]; + char m_CPUTraceFilename[128]; + unsigned int m_iSuccessiveTraceIndex; + VXConsoleReportMode_t m_ReportMode; + float m_pReportScale[VXCONSOLE_REPORT_COUNT]; + bool m_bTraceCompleteEvent; +#endif +#ifdef _X360 + CPUTraceState m_iCPUTraceEnabled; +#endif + + unsigned m_TargetThreadId; +}; + +//------------------------------------- + +PLATFORM_INTERFACE CVProfile g_VProfCurrentProfile; + +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE bool g_VProfSignalSpike; + +class CVProfSpikeDetector +{ +public: + CVProfSpikeDetector( float spike ) : + m_timeLast( GetTimeLast() ) + { + m_spike = spike; + m_Timer.Start(); + } + + ~CVProfSpikeDetector() + { + m_Timer.End(); + if ( Plat_FloatTime() - m_timeLast > 2.0 ) + { + m_timeLast = Plat_FloatTime(); + if ( m_Timer.GetDuration().GetMillisecondsF() > m_spike ) + { + g_VProfSignalSpike = true; + } + } + } + +private: + static float &GetTimeLast() { static float timeLast = 0; return timeLast; } + CFastTimer m_Timer; + float m_spike; + float &m_timeLast; +}; + + +// Macro to signal a local spike. Meant as temporary instrumentation, do not leave in code +#define VPROF_TEST_SPIKE( msec ) CVProfSpikeDetector UNIQUE_ID( msec ) + +//----------------------------------------------------------------------------- + +#ifdef VPROF_VTUNE_GROUP +inline void CVProfile::PushGroup( int nGroupID ) +{ + // There is always at least one item on the stack since we force + // the first element to be VPROF_BUDGETGROUP_OTHER_UNACCOUNTED. + Assert( m_GroupIDStackDepth > 0 ); + Assert( m_GroupIDStackDepth < MAX_GROUP_STACK_DEPTH ); + m_GroupIDStack[m_GroupIDStackDepth] = nGroupID; + m_GroupIDStackDepth++; + if( m_GroupIDStack[m_GroupIDStackDepth-2] != nGroupID && + VTuneGroupEnabled() && + nGroupID == VTuneGroupID() ) + { + vtune( true ); + } +} +#endif // VPROF_VTUNE_GROUP + +#ifdef VPROF_VTUNE_GROUP +inline void CVProfile::PopGroup( void ) +{ + m_GroupIDStackDepth--; + // There is always at least one item on the stack since we force + // the first element to be VPROF_BUDGETGROUP_OTHER_UNACCOUNTED. + Assert( m_GroupIDStackDepth > 0 ); + if( m_GroupIDStack[m_GroupIDStackDepth] != m_GroupIDStack[m_GroupIDStackDepth+1] && + VTuneGroupEnabled() && + m_GroupIDStack[m_GroupIDStackDepth+1] == VTuneGroupID() ) + { + vtune( false ); + } +} +#endif // VPROF_VTUNE_GROUP + +//----------------------------------------------------------------------------- + + +class CVProfScope: public CVProfSnMarkerScope +{ +public: + CVProfScope( const tchar * pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ); + ~CVProfScope(); + +private: + bool m_bEnabled; +}; + +//----------------------------------------------------------------------------- +// +// CVProfNode, inline methods +// + +inline CVProfNode::CVProfNode( const tchar * pszName, int detailLevel, CVProfNode *pParent, const tchar *pBudgetGroupName, int budgetFlags ) + : m_pszName( pszName ), + m_nCurFrameCalls( 0 ), + m_nPrevFrameCalls( 0 ), + m_nRecursions( 0 ), + m_pParent( pParent ), + m_pChild( NULL ), + m_pSibling( NULL ), + m_iClientData( -1 ) +#ifdef _X360 + , m_iBitFlags( 0 ) +#endif +{ + m_iUniqueNodeID = s_iCurrentUniqueNodeID++; + + if ( m_iUniqueNodeID > 0 ) + { + m_BudgetGroupID = g_VProfCurrentProfile.BudgetGroupNameToBudgetGroupID( pBudgetGroupName, budgetFlags ); + } + else + { + m_BudgetGroupID = 0; // "m_Root" can't call BudgetGroupNameToBudgetGroupID because g_VProfCurrentProfile not yet initialized + } + + Reset(); + + if( m_pParent && ( m_BudgetGroupID == VPROF_BUDGET_GROUP_ID_UNACCOUNTED ) ) + { + m_BudgetGroupID = m_pParent->GetBudgetGroupID(); + } +} + + +//------------------------------------- + +inline CVProfNode *CVProfNode::GetParent() +{ + Assert( m_pParent ); + return m_pParent; +} + +//------------------------------------- + +inline CVProfNode *CVProfNode::GetSibling() +{ + return m_pSibling; +} + +//------------------------------------- +// Hacky way to the previous sibling, only used from vprof panel at the moment, +// so it didn't seem like it was worth the memory waste to add the reverse +// link per node. + +inline CVProfNode *CVProfNode::GetPrevSibling() +{ + CVProfNode* p = GetParent(); + + if(!p) + return NULL; + + CVProfNode* s; + for( s = p->GetChild(); + s && ( s->GetSibling() != this ); + s = s->GetSibling() ) + ; + + return s; +} + +//------------------------------------- + +inline CVProfNode *CVProfNode::GetChild() +{ + return m_pChild; +} + +//------------------------------------- + +inline const tchar *CVProfNode::GetName() +{ + return m_pszName; +} + +//------------------------------------- + +inline int CVProfNode::GetTotalCalls() +{ + return m_nTotalCalls; +} + +//------------------------------------- + +inline double CVProfNode::GetTotalTime() +{ + return m_TotalTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline int CVProfNode::GetCurCalls() +{ + return m_nCurFrameCalls; +} + +//------------------------------------- + +inline double CVProfNode::GetCurTime() +{ + return m_CurFrameTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline int CVProfNode::GetPrevCalls() +{ + return m_nPrevFrameCalls; +} + +//------------------------------------- + +inline double CVProfNode::GetPrevTime() +{ + return m_PrevFrameTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline double CVProfNode::GetPeakTime() +{ + return m_PeakTime.GetMillisecondsF(); +} + +//------------------------------------- + +inline double CVProfNode::GetTotalTimeLessChildren() +{ + double result = GetTotalTime(); + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->GetTotalTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +//------------------------------------- + +inline double CVProfNode::GetCurTimeLessChildren() +{ + double result = GetCurTime(); + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->GetCurTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +inline double CVProfNode::GetPrevTimeLessChildren() +{ + double result = GetPrevTime(); + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->GetPrevTime(); + pChild = pChild->GetSibling(); + } + return result; +} + +//----------------------------------------------------------------------------- +inline int CVProfNode::GetPrevL2CacheMissLessChildren() +{ + int result = m_iPrevL2CacheMiss; + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->m_iPrevL2CacheMiss; + pChild = pChild->GetSibling(); + } + return result; +} + +//----------------------------------------------------------------------------- +inline int CVProfNode::GetPrevLoadHitStoreLessChildren() +{ +#ifndef _X360 + return 0; +#else + int result = m_iPrevLoadHitStores; + CVProfNode *pChild = GetChild(); + while ( pChild ) + { + result -= pChild->m_iPrevLoadHitStores; + pChild = pChild->GetSibling(); + } + return result; +#endif +} + + +//----------------------------------------------------------------------------- +inline void CVProfNode::ClearPrevTime() +{ + m_PrevFrameTime.Init(); +} + +//----------------------------------------------------------------------------- +inline int CVProfNode::GetL2CacheMisses( void ) +{ +#ifndef _X360 + return m_L2Cache.GetL2CacheMisses(); +#else + return m_iTotalL2CacheMiss; +#endif +} + +#ifdef _X360 +inline int CVProfNode::GetLoadHitStores( void ) +{ + return m_iTotalLoadHitStores; +} +#endif + +//----------------------------------------------------------------------------- +// +// CVProfile, inline methods +// + +//------------------------------------- + +inline bool CVProfile::IsEnabled() const +{ + return ( m_enabled != 0 ); +} + +//------------------------------------- + +inline int CVProfile::GetDetailLevel() const +{ + return m_ProfileDetailLevel; +} + + +//------------------------------------- + +inline bool CVProfile::AtRoot() const +{ + return m_fAtRoot; +} + +//------------------------------------- + +inline void CVProfile::Start() +{ + if ( ++m_enabled == 1 ) + { + m_Root.EnterScope(); +#ifdef VPROF_VXCONSOLE_EXISTS + VXProfileStart(); +#endif +#ifdef _X360 + CPMCData::InitializeOnceProgramWide(); +#endif + } +} + +//------------------------------------- + +inline void CVProfile::Stop() +{ + if ( --m_enabled == 0 ) + m_Root.ExitScope(); +} + +//------------------------------------- + +inline void CVProfile::EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ) +{ + if ( ( m_enabled != 0 || !m_fAtRoot ) && InTargetThread() ) // if became disabled, need to unwind back to root before stopping + { + // Only account for vprof stuff on the primary thread. + //if( !Plat_IsPrimaryThread() ) + // return; + + if ( pszName != m_pCurNode->GetName() ) + { + m_pCurNode = m_pCurNode->GetSubNode( pszName, detailLevel, pBudgetGroupName, budgetFlags ); + } + m_pBudgetGroups[m_pCurNode->GetBudgetGroupID()].m_BudgetFlags |= budgetFlags; + +#if defined( _DEBUG ) && !defined( _X360 ) + // 360 doesn't want this to allow tier0 debug/release .def files to match + if ( bAssertAccounted ) + { + // FIXME + AssertOnce( m_pCurNode->GetBudgetGroupID() != 0 ); + } +#endif + m_pCurNode->EnterScope(); + m_fAtRoot = false; + } +#if defined(_X360) && defined(VPROF_PIX) + if ( m_pCurNode->GetBudgetGroupID() != VPROF_BUDGET_GROUP_ID_UNACCOUNTED ) + PIXBeginNamedEvent( 0, pszName ); +#endif +} + +inline void CVProfile::EnterScope( const tchar *pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted ) +{ + EnterScope( pszName, detailLevel, pBudgetGroupName, bAssertAccounted, BUDGETFLAG_OTHER ); +} + +//------------------------------------- + +inline void CVProfile::ExitScope() +{ +#if defined(_X360) && defined(VPROF_PIX) +/* +#ifdef PIXBeginNamedEvent +#error +#endif +*/ + if ( m_pCurNode->GetBudgetGroupID() != VPROF_BUDGET_GROUP_ID_UNACCOUNTED ) + PIXEndNamedEvent(); +#endif + if ( ( !m_fAtRoot || m_enabled != 0 ) && InTargetThread() ) + { + // Only account for vprof stuff on the primary thread. + //if( !Plat_IsPrimaryThread() ) + // return; + + // ExitScope will indicate whether we should back up to our parent (we may + // be profiling a recursive function) + if (m_pCurNode->ExitScope()) + { + m_pCurNode = m_pCurNode->GetParent(); + } + m_fAtRoot = ( m_pCurNode == &m_Root ); + } +} + +//------------------------------------- + +inline void CVProfile::Pause() +{ + m_pausedEnabledDepth = m_enabled; + m_enabled = 0; + if ( !AtRoot() ) + m_Root.Pause(); +} + +//------------------------------------- + +inline void CVProfile::Resume() +{ + m_enabled = m_pausedEnabledDepth; + if ( !AtRoot() ) + m_Root.Resume(); +} + +//------------------------------------- + +inline void CVProfile::Reset() +{ + m_Root.Reset(); + m_nFrames = 0; +} + +//------------------------------------- + +inline void CVProfile::ResetPeaks() +{ + m_Root.ResetPeak(); +} + +//------------------------------------- + +inline void CVProfile::MarkFrame() +{ + if ( m_enabled ) + { + ++m_nFrames; + m_Root.ExitScope(); + m_Root.MarkFrame(); + m_Root.EnterScope(); + +#ifdef _X360 + // update the CPU trace state machine if enabled + switch ( GetCPUTraceMode() ) + { + case kAllNodesInFrame_WaitingForMark: + // mark! Start recording a zillion traces. + m_iCPUTraceEnabled = kAllNodesInFrame_Recording; + break; + case kAllNodesInFrame_WaitingForMarkMultiFrame: + m_iCPUTraceEnabled = kAllNodesInFrame_RecordingMultiFrame; + break; + case kAllNodesInFrame_Recording: + // end of frame. stop recording if no more frames needed + m_iCPUTraceEnabled = kDisabled; + Msg("Frame ended. Recording no more CPU traces\n"); + + break; + case kAllNodesInFrame_RecordingMultiFrame: + // end of frame. stop recording if no more frames needed + if ( --m_nFramesRemaining == 0 ) + { + m_iCPUTraceEnabled = kDisabled; + Msg("Frames ended. Recording no more CPU traces\n"); + + SpewWorstMultiFrame(); + } + + ++m_nFrameCount; + + break; + default: + // no default + break; + } +#endif + } +} + +//------------------------------------- + +inline double CVProfile::GetTotalTimeSampled() +{ + return m_Root.GetTotalTime(); +} + +//------------------------------------- + +inline double CVProfile::GetPeakFrameTime() +{ + return m_Root.GetPeakTime(); +} + +//------------------------------------- + +inline double CVProfile::GetTimeLastFrame() +{ + return m_Root.GetCurTime(); +} + +//------------------------------------- + +inline CVProfNode *CVProfile::GetRoot() +{ + return &m_Root; +} + +//------------------------------------- + +inline CVProfNode *CVProfile::GetCurrentNode() +{ + return m_pCurNode; +} + + +inline const tchar *CVProfile::GetBudgetGroupName( int budgetGroupID ) +{ + Assert( budgetGroupID >= 0 && budgetGroupID < m_nBudgetGroupNames ); + return m_pBudgetGroups[budgetGroupID].m_pName; +} + +inline int CVProfile::GetBudgetGroupFlags( int budgetGroupID ) const +{ + Assert( budgetGroupID >= 0 && budgetGroupID < m_nBudgetGroupNames ); + return m_pBudgetGroups[budgetGroupID].m_BudgetFlags; +} + +#ifdef _X360 + +inline CVProfile::CPUTraceState CVProfile::GetCPUTraceMode() +{ + return m_iCPUTraceEnabled; +} + +inline void CVProfile::SetCPUTraceEnabled( CPUTraceState enabled, bool bTraceCompleteEvent /*=true*/, int nNumFrames /*= -1*/ ) +{ + m_iCPUTraceEnabled = enabled; + m_bTraceCompleteEvent = bTraceCompleteEvent; + if ( nNumFrames != -1 ) + { + m_nFramesRemaining = nNumFrames; + m_nFrameCount = 0; + m_WorstCycles = 0; + m_WorstTraceFilename[ 0 ] = 0; + } +} + +inline void CVProfile::IncrementMultiTraceIndex() +{ + ++m_iSuccessiveTraceIndex; +} + +inline unsigned int CVProfile::GetMultiTraceIndex() +{ + return m_iSuccessiveTraceIndex; +} + +#endif + + +//----------------------------------------------------------------------------- + +inline CVProfScope::CVProfScope( const tchar * pszName, int detailLevel, const tchar *pBudgetGroupName, bool bAssertAccounted, int budgetFlags ): + CVProfSnMarkerScope( pszName ), + m_bEnabled( g_VProfCurrentProfile.IsEnabled() ) +{ + if ( m_bEnabled ) + { + g_VProfCurrentProfile.EnterScope( pszName, detailLevel, pBudgetGroupName, bAssertAccounted, budgetFlags ); + } +} + +//------------------------------------- + +inline CVProfScope::~CVProfScope() +{ + if ( m_bEnabled ) + { + g_VProfCurrentProfile.ExitScope(); + } +} + +class CVProfCounter +{ +public: + CVProfCounter( const tchar *pName, CounterGroup_t group=COUNTER_GROUP_DEFAULT ) + { + m_pCounter = g_VProfCurrentProfile.FindOrCreateCounter( pName, group ); + Assert( m_pCounter ); + } + ~CVProfCounter() + { + } + void Increment( int val ) + { + Assert( m_pCounter ); + *m_pCounter += val; + } + void Set( int val ) + { + Assert( m_pCounter ); + *m_pCounter = val; + } +private: + int *m_pCounter; +}; + +#endif + +#ifdef _X360 + +#include "xbox/xbox_console.h" +#include "tracerecording.h" +#include "tier1/fmtstr.h" +#pragma comment( lib, "tracerecording.lib" ) +#pragma comment( lib, "xbdm.lib" ) + +class CPIXRecorder +{ +public: + CPIXRecorder() : m_bActive( false ) {} + ~CPIXRecorder() { Stop(); } + + void Start( const char *pszFilename = "capture" ) + { + if ( !m_bActive ) + { + if ( !XTraceStartRecording( CFmtStr( "e:\\%s.pix2", pszFilename ) ) ) + { + Msg( "XTraceStartRecording failed, error code %d\n", GetLastError() ); + } + else + { + m_bActive = true; + } + } + } + + void Stop() + { + if ( m_bActive ) + { + m_bActive = false; + if ( XTraceStopRecording() ) + { + Msg( "CPU trace finished.\n" ); + // signal VXConsole that trace is completed + XBX_rTraceComplete(); + } + } + } + +private: + bool m_bActive; +}; + +#define VPROF_BEGIN_PIX_BLOCK( convar ) \ + { \ + bool bRunPix = 0; \ + static CFastTimer PIXTimer; \ + extern ConVar convar; \ + ConVar &PIXConvar = convar; \ + CPIXRecorder PIXRecorder; \ + { \ + PIXLabel: \ + if ( bRunPix ) \ + { \ + PIXRecorder.Start(); \ + } \ + else \ + { \ + if ( PIXConvar.GetBool() ) \ + { \ + PIXTimer.Start(); \ + } \ + } \ + { + + +#define VPROF_END_PIX_BLOCK() \ + } \ + \ + if ( !bRunPix ) \ + { \ + if ( PIXConvar.GetBool() ) \ + { \ + PIXTimer.End(); \ + if ( PIXTimer.GetDuration().GetMillisecondsF() > PIXConvar.GetFloat() ) \ + { \ + PIXConvar.SetValue( 0 ); \ + bRunPix = true; \ + goto PIXLabel; \ + } \ + } \ + } \ + else \ + { \ + PIXRecorder.Stop(); \ + } \ + } \ + } +#else +#define VPROF_BEGIN_PIX_BLOCK( PIXConvar ) { +#define VPROF_END_PIX_BLOCK() } +#endif + + +#ifdef VPROF_UNDO_PIX +#undef USE_PIX +#undef _PIX_H_ +#undef PIXBeginNamedEvent +#undef PIXEndNamedEvent +#undef PIXSetMarker +#undef PIXNameThread +#include <pix.h> +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif + +//============================================================================= diff --git a/external/vpc/public/tier0/vprof_sn.h b/external/vpc/public/tier0/vprof_sn.h new file mode 100644 index 0000000..ecf776f --- /dev/null +++ b/external/vpc/public/tier0/vprof_sn.h @@ -0,0 +1,31 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +#ifndef TIER_V0PROF_SN_HDR +#define TIER_V0PROF_SN_HDR + +// enable this to get detailed SN Tuner markers. PS3 specific +#if defined( SN_TARGET_PS3 ) && !defined(_CERT) +#define VPROF_SN_LEVEL 0 + +extern "C" void(*g_pfnPushMarker)( const char * pName ); +extern "C" void(*g_pfnPopMarker)(); + +class CVProfSnMarkerScope +{ +public: + CVProfSnMarkerScope( const char * pszName ) + { + g_pfnPushMarker( pszName ); + } + ~CVProfSnMarkerScope() + { + g_pfnPopMarker( ); + } +}; + +#else + +class CVProfSnMarkerScope { public: CVProfSnMarkerScope( const char * ) {} }; + +#endif + +#endif
\ No newline at end of file diff --git a/external/vpc/public/tier0/wchartypes.h b/external/vpc/public/tier0/wchartypes.h new file mode 100644 index 0000000..8446b68 --- /dev/null +++ b/external/vpc/public/tier0/wchartypes.h @@ -0,0 +1,101 @@ +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: All of our code is completely Unicode. Instead of char, you should +// use wchar, uint8, or char8, as explained below. +// +// $NoKeywords: $ +//=============================================================================// + + +#ifndef WCHARTYPES_H +#define WCHARTYPES_H +#ifdef _WIN32 +#pragma once +#endif +#include "stddef.h" +#ifdef _INC_TCHAR +#error ("Must include tier0 type headers before tchar.h") +#endif + +// Temporarily turn off Valve defines +#include "tier0/valve_off.h" + +#if !defined(_WCHAR_T_DEFINED) && !defined( __WCHAR_TYPE__ ) && !defined(GNUC) +typedef unsigned short wchar_t; +#define _WCHAR_T_DEFINED +#endif + +// char8 +// char8 is equivalent to char, and should be used when you really need a char +// (for example, when calling an external function that's declared to take +// chars). +typedef char char8; + +// uint8 +// uint8 is equivalent to byte (but is preferred over byte for clarity). Use this +// whenever you mean a byte (for example, one byte of a network packet). +// uint8 itself is defined in platform.h +typedef unsigned char BYTE; +typedef unsigned char byte; + +// wchar +// wchar is a single character of text (currently 16 bits, as all of our text is +// Unicode). Use this whenever you mean a piece of text (for example, in a string). +typedef wchar_t wchar; +//typedef char wchar; + +// __WFILE__ +// This is a Unicode version of __FILE__ +#define WIDEN2(x) L ## x +#define WIDEN(x) WIDEN2(x) +#define __WFILE__ WIDEN(__FILE__) + +#ifdef STEAM +#ifndef _UNICODE +#define FORCED_UNICODE +#endif +#define _UNICODE +#endif + +#if defined( POSIX ) || defined( _PS3 ) +#define _tcsstr strstr +#define _tcsicmp stricmp +#define _tcscmp strcmp +#define _tcscpy strcpy +#define _tcsncpy strncpy +#define _tcsrchr strrchr +#define _tcslen strlen +#define _tfopen fopen +#define _stprintf sprintf +#define _ftprintf fprintf +#define _vsntprintf _vsnprintf +#define _tprintf printf +#define _sntprintf _snprintf +#define _T(s) s +#else +#include <tchar.h> +#endif + +#if defined(_UNICODE) +typedef wchar tchar; +#define tstring wstring +#define __TFILE__ __WFILE__ +#define TCHAR_IS_WCHAR +#else +typedef char tchar; +#define tstring string +#define __TFILE__ __FILE__ +#define TCHAR_IS_CHAR +#endif + +#ifdef FORCED_UNICODE +#undef _UNICODE +#endif + +// Turn valve defines back on +#include "tier0/valve_on.h" + + +#endif // WCHARTYPES + + diff --git a/external/vpc/public/tier0/win32consoleio.h b/external/vpc/public/tier0/win32consoleio.h new file mode 100644 index 0000000..92b3914 --- /dev/null +++ b/external/vpc/public/tier0/win32consoleio.h @@ -0,0 +1,32 @@ +//======= Copyright � 1996-2006, Valve Corporation, All rights reserved. ====== +// +// Purpose: Win32 Console API helpers +// +//============================================================================= +#ifndef WIN32_CONSOLE_IO_H +#define WIN32_CONSOLE_IO_H + +#if defined( COMPILER_MSVC ) +#pragma once +#endif + +// Function to attach a console for I/O to a Win32 GUI application in a reasonably smart fashion. +PLATFORM_INTERFACE bool SetupWin32ConsoleIO(); + +// Win32 Console Color API Helpers, originally from cmdlib. + +struct Win32ConsoleColorContext_t +{ + int m_InitialColor; + uint16 m_LastColor; + uint16 m_BadColor; + uint16 m_BackgroundFlags; +}; + +PLATFORM_INTERFACE void InitWin32ConsoleColorContext( Win32ConsoleColorContext_t *pContext ); + +PLATFORM_INTERFACE uint16 SetWin32ConsoleColor( Win32ConsoleColorContext_t *pContext, int nRed, int nGreen, int nBlue, int nIntensity ); + +PLATFORM_INTERFACE void RestoreWin32ConsoleColor( Win32ConsoleColorContext_t *pContext, uint16 prevColor ); + +#endif diff --git a/external/vpc/public/tier0/xbox_codeline_defines.h b/external/vpc/public/tier0/xbox_codeline_defines.h new file mode 100644 index 0000000..3f7b544 --- /dev/null +++ b/external/vpc/public/tier0/xbox_codeline_defines.h @@ -0,0 +1,16 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef XBOX_CODELINE_DEFINES_H +#define XBOX_CODELINE_DEFINES_H + + +// In the regular src_main codeline, we leave this out. +//#define IN_XBOX_CODELINE + + +#endif // XBOX_CODELINE_DEFINES_H diff --git a/external/vpc/public/tier1/byteswap.h b/external/vpc/public/tier1/byteswap.h new file mode 100644 index 0000000..b4dea77 --- /dev/null +++ b/external/vpc/public/tier1/byteswap.h @@ -0,0 +1,268 @@ +//========= Copyright � 1996-2006, Valve LLC, All rights reserved. ============ +// +// Purpose: Low level byte swapping routines. +// +// $NoKeywords: $ +//============================================================================= +#ifndef BYTESWAP_H +#define BYTESWAP_H +#if defined(_WIN32) +#pragma once +#endif + +#include "tier0/dbg.h" +#include "datamap.h" // needed for typedescription_t. note datamap.h is tier1 as well. + +class CByteswap +{ +public: + CByteswap() + { + // Default behavior sets the target endian to match the machine native endian (no swap). + SetTargetBigEndian( IsMachineBigEndian() ); + } + + //----------------------------------------------------------------------------- + // Write a single field. + //----------------------------------------------------------------------------- + void SwapFieldToTargetEndian( void* pOutputBuffer, void *pData, typedescription_t *pField ); + + //----------------------------------------------------------------------------- + // Write a block of fields. Works a bit like the saverestore code. + //----------------------------------------------------------------------------- + void SwapFieldsToTargetEndian( void *pOutputBuffer, void *pBaseData, datamap_t *pDataMap ); + + // Swaps fields for the templated type to the output buffer. + template<typename T> inline void SwapFieldsToTargetEndian( T* pOutputBuffer, void *pBaseData, unsigned int objectCount = 1 ) + { + for ( unsigned int i = 0; i < objectCount; ++i, ++pOutputBuffer ) + { + SwapFieldsToTargetEndian( (void*)pOutputBuffer, pBaseData, &T::m_DataMap ); + pBaseData = (byte*)pBaseData + sizeof(T); + } + } + + // Swaps fields for the templated type in place. + template<typename T> inline void SwapFieldsToTargetEndian( T* pOutputBuffer, unsigned int objectCount = 1 ) + { + SwapFieldsToTargetEndian<T>( pOutputBuffer, (void*)pOutputBuffer, objectCount ); + } + + //----------------------------------------------------------------------------- + // True if the current machine is detected as big endian. + // (Endienness is effectively detected at compile time when optimizations are + // enabled) + //----------------------------------------------------------------------------- + static bool IsMachineBigEndian() + { + short nIsBigEndian = 1; + + // if we are big endian, the first byte will be a 0, if little endian, it will be a one. + return (bool)(0 == *(char *)&nIsBigEndian ); + } + + //----------------------------------------------------------------------------- + // Sets the target byte ordering we are swapping to or from. + // + // Braindead Endian Reference: + // x86 is LITTLE Endian + // PowerPC is BIG Endian + //----------------------------------------------------------------------------- + inline void SetTargetBigEndian( bool bigEndian ) + { + m_bBigEndian = bigEndian; + m_bSwapBytes = IsMachineBigEndian() != bigEndian; + } + + // Changes target endian + inline void FlipTargetEndian( void ) + { + m_bSwapBytes = !m_bSwapBytes; + m_bBigEndian = !m_bBigEndian; + } + + // Forces byte swapping state, regardless of endianess + inline void ActivateByteSwapping( bool bActivate ) + { + SetTargetBigEndian( IsMachineBigEndian() != bActivate ); + } + + //----------------------------------------------------------------------------- + // Returns true if the target machine is the same as this one in endianness. + // + // Used to determine when a byteswap needs to take place. + //----------------------------------------------------------------------------- + inline bool IsSwappingBytes( void ) // Are bytes being swapped? + { + return m_bSwapBytes; + } + + inline bool IsTargetBigEndian( void ) // What is the current target endian? + { + return m_bBigEndian; + } + + //----------------------------------------------------------------------------- + // IsByteSwapped() + // + // When supplied with a chunk of input data and a constant or magic number + // (in native format) determines the endienness of the current machine in + // relation to the given input data. + // + // Returns: + // 1 if input is the same as nativeConstant. + // 0 if input is byteswapped relative to nativeConstant. + // -1 if input is not the same as nativeConstant and not byteswapped either. + // + // ( This is useful for detecting byteswapping in magic numbers in structure + // headers for example. ) + //----------------------------------------------------------------------------- + template<typename T> inline int SourceIsNativeEndian( T input, T nativeConstant ) + { + // If it's the same, it isn't byteswapped: + if( input == nativeConstant ) + return 1; + + int output; + LowLevelByteSwap<T>( &output, &input ); + if( output == nativeConstant ) + return 0; + + Assert( 0 ); // if we get here, input is neither a swapped nor unswapped version of nativeConstant. + return -1; + } + + //----------------------------------------------------------------------------- + // Swaps an input buffer full of type T into the given output buffer. + // + // Swaps [count] items from the inputBuffer to the outputBuffer. + // If inputBuffer is omitted or NULL, then it is assumed to be the same as + // outputBuffer - effectively swapping the contents of the buffer in place. + //----------------------------------------------------------------------------- + template<typename T> inline void SwapBuffer( T* outputBuffer, T* inputBuffer = NULL, int count = 1 ) + { + Assert( count >= 0 ); + Assert( outputBuffer ); + + // Fail gracefully in release: + if( count <=0 || !outputBuffer ) + return; + + // Optimization for the case when we are swapping in place. + if( inputBuffer == NULL ) + { + inputBuffer = outputBuffer; + } + + // Swap everything in the buffer: + for( int i = 0; i < count; i++ ) + { + LowLevelByteSwap<T>( &outputBuffer[i], &inputBuffer[i] ); + } + } + + //----------------------------------------------------------------------------- + // Swaps an input buffer full of type T into the given output buffer. + // + // Swaps [count] items from the inputBuffer to the outputBuffer. + // If inputBuffer is omitted or NULL, then it is assumed to be the same as + // outputBuffer - effectively swapping the contents of the buffer in place. + //----------------------------------------------------------------------------- + template<typename T> inline void SwapBufferToTargetEndian( T* outputBuffer, T* inputBuffer = NULL, int count = 1 ) + { + Assert( count >= 0 ); + Assert( outputBuffer ); + + // Fail gracefully in release: + if( count <=0 || !outputBuffer ) + return; + + // Optimization for the case when we are swapping in place. + if( inputBuffer == NULL ) + { + inputBuffer = outputBuffer; + } + + // Are we already the correct endienness? ( or are we swapping 1 byte items? ) + if( !m_bSwapBytes || ( sizeof(T) == 1 ) ) + { + // If we were just going to swap in place then return. + if( !inputBuffer ) + return; + + // Otherwise copy the inputBuffer to the outputBuffer: + if ( outputBuffer != inputBuffer ) + memcpy( outputBuffer, inputBuffer, count * sizeof( T ) ); + return; + + } + + // Swap everything in the buffer: + for( int i = 0; i < count; i++ ) + { + LowLevelByteSwap<T>( &outputBuffer[i], &inputBuffer[i] ); + } + } + +private: + //----------------------------------------------------------------------------- + // The lowest level byte swapping workhorse of doom. output always contains the + // swapped version of input. ( Doesn't compare machine to target endianness ) + //----------------------------------------------------------------------------- + template<typename T> static void LowLevelByteSwap( T *output, T *input ) + { + T temp = *output; +#if defined( _X360 ) + // Intrinsics need the source type to be fixed-point + DWORD* word = (DWORD*)input; + switch( sizeof(T) ) + { + case 8: + { + __storewordbytereverse( *(word+1), 0, &temp ); + __storewordbytereverse( *(word+0), 4, &temp ); + } + break; + + case 4: + __storewordbytereverse( *word, 0, &temp ); + break; + + case 2: + __storeshortbytereverse( *input, 0, &temp ); + break; + + case 1: + V_memcpy( &temp, input, 1 ); + break; + + default: + Assert( "Invalid size in CByteswap::LowLevelByteSwap" && 0 ); + } +#else + for( unsigned int i = 0; i < sizeof(T); i++ ) + { + ((unsigned char* )&temp)[i] = ((unsigned char*)input)[sizeof(T)-(i+1)]; + } +#endif + V_memcpy( output, &temp, sizeof(T) ); + } + +#if defined( _X360 ) + // specialized for void * to get 360 XDK compile working despite changelist 281331 + //----------------------------------------------------------------------------- + // The lowest level byte swapping workhorse of doom. output always contains the + // swapped version of input. ( Doesn't compare machine to target endianness ) + //----------------------------------------------------------------------------- + template<> static void LowLevelByteSwap( void **output, void **input ) + { + AssertMsgOnce( sizeof(void *) == sizeof(unsigned int) , "void *'s on this platform are not four bytes!" ); + __storewordbytereverse( *reinterpret_cast<unsigned int *>(input), 0, output ); + } +#endif + + unsigned int m_bSwapBytes : 1; + unsigned int m_bBigEndian : 1; +}; + +#endif /* !BYTESWAP_H */ diff --git a/external/vpc/public/tier1/characterset.h b/external/vpc/public/tier1/characterset.h new file mode 100644 index 0000000..42ef2c3 --- /dev/null +++ b/external/vpc/public/tier1/characterset.h @@ -0,0 +1,43 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: Shared code for parsing / searching for characters in a string +// using lookup tables +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef CHARACTERSET_H +#define CHARACTERSET_H + +#ifdef _WIN32 +#pragma once +#endif + + +struct characterset_t +{ + char set[256]; +}; + + +// This is essentially a strpbrk() using a precalculated lookup table +//----------------------------------------------------------------------------- +// Purpose: builds a simple lookup table of a group of important characters +// Input : *pSetBuffer - pointer to the buffer for the group +// *pSetString - list of characters to flag +//----------------------------------------------------------------------------- +extern void CharacterSetBuild( characterset_t *pSetBuffer, const char *pSetString ); + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pSetBuffer - pre-build group buffer +// character - character to lookup +// Output : int - 1 if the character was in the set +//----------------------------------------------------------------------------- +#define IN_CHARACTERSET( SetBuffer, character ) ((SetBuffer).set[(unsigned char)(character)]) + + +#endif // CHARACTERSET_H diff --git a/external/vpc/public/tier1/checksum_crc.h b/external/vpc/public/tier1/checksum_crc.h new file mode 100644 index 0000000..4c82376 --- /dev/null +++ b/external/vpc/public/tier1/checksum_crc.h @@ -0,0 +1,31 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Generic CRC functions +// +// $NoKeywords: $ +//=============================================================================// +#ifndef CHECKSUM_CRC_H +#define CHECKSUM_CRC_H +#ifdef _WIN32 +#pragma once +#endif + +typedef uint32 CRC32_t; + +void CRC32_Init( CRC32_t *pulCRC ); +void CRC32_ProcessBuffer( CRC32_t *pulCRC, const void *p, int len ); +void CRC32_Final( CRC32_t *pulCRC ); +CRC32_t CRC32_GetTableEntry( unsigned int slot ); + +inline CRC32_t CRC32_ProcessSingleBuffer( const void *p, int len ) +{ + CRC32_t crc; + + CRC32_Init( &crc ); + CRC32_ProcessBuffer( &crc, p, len ); + CRC32_Final( &crc ); + + return crc; +} + +#endif // CHECKSUM_CRC_H diff --git a/external/vpc/public/tier1/checksum_md5.h b/external/vpc/public/tier1/checksum_md5.h new file mode 100644 index 0000000..3692cf1 --- /dev/null +++ b/external/vpc/public/tier1/checksum_md5.h @@ -0,0 +1,33 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Generic MD5 hashing algo +// +//=============================================================================// + +#ifndef CHECKSUM_MD5_H +#define CHECKSUM_MD5_H + +#ifdef _WIN32 +#pragma once +#endif + +// 16 bytes == 128 bit digest +#define MD5_DIGEST_LENGTH 16 + +// MD5 Hash +typedef struct +{ + unsigned int buf[4]; + unsigned int bits[2]; + unsigned char in[64]; +} MD5Context_t; + +void MD5Init( MD5Context_t *context ); +void MD5Update( MD5Context_t *context, unsigned char const *buf, unsigned int len ); +void MD5Final( unsigned char digest[ MD5_DIGEST_LENGTH ], MD5Context_t *context ); + +char *MD5_Print(unsigned char *digest, int hashlen ); + +unsigned int MD5_PseudoRandom(unsigned int nSeed); + +#endif // CHECKSUM_MD5_H diff --git a/external/vpc/public/tier1/convar.h b/external/vpc/public/tier1/convar.h new file mode 100644 index 0000000..d67a5d4 --- /dev/null +++ b/external/vpc/public/tier1/convar.h @@ -0,0 +1,975 @@ +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $NoKeywords: $ +//===========================================================================// + +#ifndef CONVAR_H +#define CONVAR_H + +#if _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "tier1/iconvar.h" +#include "tier1/utlvector.h" +#include "tier1/utlstring.h" +#include "color.h" +#include "icvar.h" + +#ifdef _WIN32 +#define FORCEINLINE_CVAR FORCEINLINE +#elif POSIX +#define FORCEINLINE_CVAR inline +#elif defined(_PS3) +#define FORCEINLINE_CVAR __attribute__((always_inline)) FORCEINLINE +#else +#error "implement me" +#endif + + +//----------------------------------------------------------------------------- +// Uncomment me to test for threading issues for material system convars +// NOTE: You want to disable all threading when you do this +// +host_thread_mode 0 +r_threaded_particles 0 +sv_parallel_packentities 0 +sv_disable_querycache 0 +//----------------------------------------------------------------------------- +//#define CONVAR_TEST_MATERIAL_THREAD_CONVARS 1 + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class ConVar; +class CCommand; +class ConCommand; +class ConCommandBase; +struct characterset_t; + + + +//----------------------------------------------------------------------------- +// Any executable that wants to use ConVars need to implement one of +// these to hook up access to console variables. +//----------------------------------------------------------------------------- +class IConCommandBaseAccessor +{ +public: + // Flags is a combination of FCVAR flags in cvar.h. + // hOut is filled in with a handle to the variable. + virtual bool RegisterConCommandBase( ConCommandBase *pVar ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Helper method for console development +//----------------------------------------------------------------------------- +#if defined( USE_VXCONSOLE ) +void ConVar_PublishToVXConsole(); +#else +inline void ConVar_PublishToVXConsole() {} +#endif + + +//----------------------------------------------------------------------------- +// Called when a ConCommand needs to execute +//----------------------------------------------------------------------------- +typedef void ( *FnCommandCallbackV1_t )( void ); +typedef void ( *FnCommandCallback_t )( const CCommand &command ); + +#define COMMAND_COMPLETION_MAXITEMS 64 +#define COMMAND_COMPLETION_ITEM_LENGTH 64 + +//----------------------------------------------------------------------------- +// Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings +//----------------------------------------------------------------------------- +typedef int ( *FnCommandCompletionCallback )( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); + + +//----------------------------------------------------------------------------- +// Interface version +//----------------------------------------------------------------------------- +class ICommandCallback +{ +public: + virtual void CommandCallback( const CCommand &command ) = 0; +}; + +class ICommandCompletionCallback +{ +public: + virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: The base console invoked command/cvar interface +//----------------------------------------------------------------------------- +class ConCommandBase +{ + friend class CCvar; + friend class ConVar; + friend class ConCommand; + friend void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor ); + friend void ConVar_PublishToVXConsole(); + + // FIXME: Remove when ConVar changes are done + friend class CDefaultCvar; + +public: + ConCommandBase( void ); + ConCommandBase( const char *pName, const char *pHelpString = 0, + int flags = 0 ); + + virtual ~ConCommandBase( void ); + + virtual bool IsCommand( void ) const; + + // Check flag + virtual bool IsFlagSet( int flag ) const; + // Set flag + virtual void AddFlags( int flags ); + // Clear flag + virtual void RemoveFlags( int flags ); + + virtual int GetFlags() const; + + // Return name of cvar + virtual const char *GetName( void ) const; + + // Return help text for cvar + virtual const char *GetHelpText( void ) const; + + // Deal with next pointer + const ConCommandBase *GetNext( void ) const; + ConCommandBase *GetNext( void ); + + virtual bool IsRegistered( void ) const; + + // Returns the DLL identifier + virtual CVarDLLIdentifier_t GetDLLIdentifier() const; + +protected: + virtual void Create( const char *pName, const char *pHelpString = 0, + int flags = 0 ); + + // Used internally by OneTimeInit to initialize/shutdown + virtual void Init(); + void Shutdown(); + + // Internal copy routine ( uses new operator from correct module ) + char *CopyString( const char *from ); + +private: + // Next ConVar in chain + // Prior to register, it points to the next convar in the DLL. + // Once registered, though, m_pNext is reset to point to the next + // convar in the global list + ConCommandBase *m_pNext; + + // Has the cvar been added to the global list? + bool m_bRegistered; + + // Static data + const char *m_pszName; + const char *m_pszHelpString; + + // ConVar flags + int m_nFlags; + +protected: + // ConVars add themselves to this list for the executable. + // Then ConVar_Register runs through all the console variables + // and registers them into a global list stored in vstdlib.dll + static ConCommandBase *s_pConCommandBases; + + // ConVars in this executable use this 'global' to access values. + static IConCommandBaseAccessor *s_pAccessor; +}; + + +//----------------------------------------------------------------------------- +// Command tokenizer +//----------------------------------------------------------------------------- +class CCommand +{ +public: + CCommand(); + CCommand( int nArgC, const char **ppArgV ); + bool Tokenize( const char *pCommand, characterset_t *pBreakSet = NULL ); + void Reset(); + + int ArgC() const; + const char **ArgV() const; + const char *ArgS() const; // All args that occur after the 0th arg, in string form + const char *GetCommandString() const; // The entire command in string form, including the 0th arg + const char *operator[]( int nIndex ) const; // Gets at arguments + const char *Arg( int nIndex ) const; // Gets at arguments + + // Helper functions to parse arguments to commands. + const char* FindArg( const char *pName ) const; + int FindArgInt( const char *pName, int nDefaultVal ) const; + + static int MaxCommandLength(); + static characterset_t* DefaultBreakSet(); + +private: + enum + { + COMMAND_MAX_ARGC = 64, + COMMAND_MAX_LENGTH = 512, + }; + + int m_nArgc; + int m_nArgv0Size; + char m_pArgSBuffer[ COMMAND_MAX_LENGTH ]; + char m_pArgvBuffer[ COMMAND_MAX_LENGTH ]; + const char* m_ppArgv[ COMMAND_MAX_ARGC ]; +}; + +inline int CCommand::MaxCommandLength() +{ + return COMMAND_MAX_LENGTH - 1; +} + +inline int CCommand::ArgC() const +{ + return m_nArgc; +} + +inline const char **CCommand::ArgV() const +{ + return m_nArgc ? (const char**)m_ppArgv : NULL; +} + +inline const char *CCommand::ArgS() const +{ + return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : ""; +} + +inline const char *CCommand::GetCommandString() const +{ + return m_nArgc ? m_pArgSBuffer : ""; +} + +inline const char *CCommand::Arg( int nIndex ) const +{ + // FIXME: Many command handlers appear to not be particularly careful + // about checking for valid argc range. For now, we're going to + // do the extra check and return an empty string if it's out of range + if ( nIndex < 0 || nIndex >= m_nArgc ) + return ""; + return m_ppArgv[nIndex]; +} + +inline const char *CCommand::operator[]( int nIndex ) const +{ + return Arg( nIndex ); +} + + +//----------------------------------------------------------------------------- +// Purpose: The console invoked command +//----------------------------------------------------------------------------- +class ConCommand : public ConCommandBase +{ +friend class CCvar; + +public: + typedef ConCommandBase BaseClass; + + ConCommand( const char *pName, FnCommandCallbackV1_t callback, + const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); + ConCommand( const char *pName, FnCommandCallback_t callback, + const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); + ConCommand( const char *pName, ICommandCallback *pCallback, + const char *pHelpString = 0, int flags = 0, ICommandCompletionCallback *pCommandCompletionCallback = 0 ); + + virtual ~ConCommand( void ); + + virtual bool IsCommand( void ) const; + + virtual int AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands ); + + virtual bool CanAutoComplete( void ); + + // Invoke the function + virtual void Dispatch( const CCommand &command ); + +private: + // NOTE: To maintain backward compat, we have to be very careful: + // All public virtual methods must appear in the same order always + // since engine code will be calling into this code, which *does not match* + // in the mod code; it's using slightly different, but compatible versions + // of this class. Also: Be very careful about adding new fields to this class. + // Those fields will not exist in the version of this class that is instanced + // in mod code. + + // Call this function when executing the command + union + { + FnCommandCallbackV1_t m_fnCommandCallbackV1; + FnCommandCallback_t m_fnCommandCallback; + ICommandCallback *m_pCommandCallback; + }; + + union + { + FnCommandCompletionCallback m_fnCompletionCallback; + ICommandCompletionCallback *m_pCommandCompletionCallback; + }; + + bool m_bHasCompletionCallback : 1; + bool m_bUsingNewCommandCallback : 1; + bool m_bUsingCommandCallbackInterface : 1; +}; + + +//----------------------------------------------------------------------------- +// Purpose: A console variable +//----------------------------------------------------------------------------- +class ConVar : public ConCommandBase, public IConVar +{ +friend class CCvar; +friend class ConVarRef; +friend class SplitScreenConVarRef; + +public: + typedef ConCommandBase BaseClass; + + ConVar( const char *pName, const char *pDefaultValue, int flags = 0); + + ConVar( const char *pName, const char *pDefaultValue, int flags, + const char *pHelpString ); + ConVar( const char *pName, const char *pDefaultValue, int flags, + const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax ); + ConVar( const char *pName, const char *pDefaultValue, int flags, + const char *pHelpString, FnChangeCallback_t callback ); + ConVar( const char *pName, const char *pDefaultValue, int flags, + const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax, + FnChangeCallback_t callback ); + + virtual ~ConVar( void ); + + virtual bool IsFlagSet( int flag ) const; + virtual const char* GetHelpText( void ) const; + virtual bool IsRegistered( void ) const; + virtual const char *GetName( void ) const; + // Return name of command (usually == GetName(), except in case of FCVAR_SS_ADDED vars + virtual const char *GetBaseName( void ) const; + virtual int GetSplitScreenPlayerSlot() const; + + virtual void AddFlags( int flags ); + virtual int GetFlags() const; + virtual bool IsCommand( void ) const; + + // Install a change callback (there shouldn't already be one....) + void InstallChangeCallback( FnChangeCallback_t callback, bool bInvoke = true ); + void RemoveChangeCallback( FnChangeCallback_t callbackToRemove ); + + int GetChangeCallbackCount() const { return m_pParent->m_fnChangeCallbacks.Count(); } + FnChangeCallback_t GetChangeCallback( int slot ) const { return m_pParent->m_fnChangeCallbacks[ slot ]; } + + // Retrieve value + FORCEINLINE_CVAR float GetFloat( void ) const; + FORCEINLINE_CVAR int GetInt( void ) const; + FORCEINLINE_CVAR Color GetColor( void ) const; + FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); } + FORCEINLINE_CVAR char const *GetString( void ) const; + + // Compiler driven selection for template use + template <typename T> T Get( void ) const; + template <typename T> T Get( T * ) const; + + // Any function that allocates/frees memory needs to be virtual or else you'll have crashes + // from alloc/free across dll/exe boundaries. + + // These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue). + virtual void SetValue( const char *value ); + virtual void SetValue( float value ); + virtual void SetValue( int value ); + virtual void SetValue( Color value ); + + // Reset to default value + void Revert( void ); + + // True if it has a min/max setting + bool HasMin() const; + bool HasMax() const; + + bool GetMin( float& minVal ) const; + bool GetMax( float& maxVal ) const; + + float GetMinValue() const; + float GetMaxValue() const; + + const char *GetDefault( void ) const; + void SetDefault( const char *pszDefault ); + + // Value + struct CVValue_t + { + char *m_pszString; + int m_StringLength; + + // Values + float m_fValue; + int m_nValue; + }; + + FORCEINLINE_CVAR CVValue_t &GetRawValue() + { + return m_Value; + } + FORCEINLINE_CVAR const CVValue_t &GetRawValue() const + { + return m_Value; + } + +private: + bool InternalSetColorFromString( const char *value ); + // Called by CCvar when the value of a var is changing. + virtual void InternalSetValue(const char *value); + // For CVARs marked FCVAR_NEVER_AS_STRING + virtual void InternalSetFloatValue( float fNewValue ); + virtual void InternalSetIntValue( int nValue ); + virtual void InternalSetColorValue( Color value ); + + virtual bool ClampValue( float& value ); + virtual void ChangeStringValue( const char *tempVal, float flOldValue ); + + virtual void Create( const char *pName, const char *pDefaultValue, int flags = 0, + const char *pHelpString = 0, bool bMin = false, float fMin = 0.0, + bool bMax = false, float fMax = false, FnChangeCallback_t callback = 0 ); + + // Used internally by OneTimeInit to initialize. + virtual void Init(); + +protected: + + // This either points to "this" or it points to the original declaration of a ConVar. + // This allows ConVars to exist in separate modules, and they all use the first one to be declared. + // m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar). + ConVar *m_pParent; + + // Static data + const char *m_pszDefaultValue; + + CVValue_t m_Value; + + // Min/Max values + bool m_bHasMin; + float m_fMinVal; + bool m_bHasMax; + float m_fMaxVal; + + // Call this function when ConVar changes + CUtlVector< FnChangeCallback_t > m_fnChangeCallbacks; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a float +// Output : float +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR float ConVar::GetFloat( void ) const +{ +#ifdef CONVAR_TEST_MATERIAL_THREAD_CONVARS + Assert( ThreadInMainThread() || IsFlagSet( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS ) ); +#endif + return m_pParent->m_Value.m_fValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as an int +// Output : int +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR int ConVar::GetInt( void ) const +{ +#ifdef CONVAR_TEST_MATERIAL_THREAD_CONVARS + Assert( ThreadInMainThread() || IsFlagSet( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS ) ); +#endif + return m_pParent->m_Value.m_nValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a color +// Output : Color +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR Color ConVar::GetColor( void ) const +{ +#ifdef CONVAR_TEST_MATERIAL_THREAD_CONVARS + Assert( ThreadInMainThread() || IsFlagSet( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS ) ); +#endif + unsigned char *pColorElement = ((unsigned char *)&m_pParent->m_Value.m_nValue); + return Color( pColorElement[0], pColorElement[1], pColorElement[2], pColorElement[3] ); +} + + +//----------------------------------------------------------------------------- + +template <> FORCEINLINE_CVAR float ConVar::Get<float>( void ) const { return GetFloat(); } +template <> FORCEINLINE_CVAR int ConVar::Get<int>( void ) const { return GetInt(); } +template <> FORCEINLINE_CVAR bool ConVar::Get<bool>( void ) const { return GetBool(); } +template <> FORCEINLINE_CVAR const char * ConVar::Get<const char *>( void ) const { return GetString(); } +template <> FORCEINLINE_CVAR float ConVar::Get<float>( float *p ) const { return ( *p = GetFloat() ); } +template <> FORCEINLINE_CVAR int ConVar::Get<int>( int *p ) const { return ( *p = GetInt() ); } +template <> FORCEINLINE_CVAR bool ConVar::Get<bool>( bool *p ) const { return ( *p = GetBool() ); } +template <> FORCEINLINE_CVAR const char * ConVar::Get<const char *>( char const **p ) const { return ( *p = GetString() ); } + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. +// Output : const char * +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR const char *ConVar::GetString( void ) const +{ +#ifdef CONVAR_TEST_MATERIAL_THREAD_CONVARS + Assert( ThreadInMainThread() || IsFlagSet( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS ) ); +#endif + if ( m_nFlags & FCVAR_NEVER_AS_STRING ) + return "FCVAR_NEVER_AS_STRING"; + + char const *str = m_pParent->m_Value.m_pszString; + return str ? str : ""; +} + +class CSplitScreenAddedConVar : public ConVar +{ + typedef ConVar BaseClass; +public: + CSplitScreenAddedConVar( int nSplitScreenSlot, const char *pName, const ConVar *pBaseVar ) : + BaseClass + ( + pName, + pBaseVar->GetDefault(), + // Keep basevar flags, except remove _SS and add _SS_ADDED instead + ( pBaseVar->GetFlags() & ~FCVAR_SS ) | FCVAR_SS_ADDED, + pBaseVar->GetHelpText(), + pBaseVar->HasMin(), + pBaseVar->GetMinValue(), + pBaseVar->HasMax(), + pBaseVar->GetMaxValue() + ), + m_pBaseVar( pBaseVar ), + m_nSplitScreenSlot( nSplitScreenSlot ) + { + for ( int i = 0; i < pBaseVar->GetChangeCallbackCount(); ++i ) + { + InstallChangeCallback( pBaseVar->GetChangeCallback( i ), false ); + } + Assert( nSplitScreenSlot >= 1 ); + Assert( nSplitScreenSlot < MAX_SPLITSCREEN_CLIENTS ); + Assert( m_pBaseVar ); + Assert( IsFlagSet( FCVAR_SS_ADDED ) ); + Assert( !IsFlagSet( FCVAR_SS ) ); + } + + const ConVar *GetBaseVar() const; + virtual const char *GetBaseName() const; + void SetSplitScreenPlayerSlot( int nSlot ); + virtual int GetSplitScreenPlayerSlot() const; + +protected: + + const ConVar *m_pBaseVar; + int m_nSplitScreenSlot; +}; + +FORCEINLINE_CVAR const ConVar *CSplitScreenAddedConVar::GetBaseVar() const +{ + Assert( m_pBaseVar ); + return m_pBaseVar; +} + +FORCEINLINE_CVAR const char *CSplitScreenAddedConVar::GetBaseName() const +{ + Assert( m_pBaseVar ); + return m_pBaseVar->GetName(); +} + +FORCEINLINE_CVAR void CSplitScreenAddedConVar::SetSplitScreenPlayerSlot( int nSlot ) +{ + m_nSplitScreenSlot = nSlot; +} + +FORCEINLINE_CVAR int CSplitScreenAddedConVar::GetSplitScreenPlayerSlot() const +{ + return m_nSplitScreenSlot; +} + +//----------------------------------------------------------------------------- +// Used to read/write convars that already exist (replaces the FindVar method) +//----------------------------------------------------------------------------- +class ConVarRef +{ +public: + ConVarRef( const char *pName ); + ConVarRef( const char *pName, bool bIgnoreMissing ); + ConVarRef( IConVar *pConVar ); + + void Init( const char *pName, bool bIgnoreMissing ); + bool IsValid() const; + bool IsFlagSet( int nFlags ) const; + IConVar *GetLinkedConVar(); + + // Get/Set value + float GetFloat( void ) const; + int GetInt( void ) const; + Color GetColor( void ) const; + bool GetBool() const { return !!GetInt(); } + const char *GetString( void ) const; + + void SetValue( const char *pValue ); + void SetValue( float flValue ); + void SetValue( int nValue ); + void SetValue( Color value ); + void SetValue( bool bValue ); + + const char *GetName() const; + + const char *GetDefault() const; + + const char *GetBaseName() const; + + int GetSplitScreenPlayerSlot() const; + +private: + // High-speed method to read convar data + IConVar *m_pConVar; + ConVar *m_pConVarState; +}; + + +//----------------------------------------------------------------------------- +// Did we find an existing convar of that name? +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR bool ConVarRef::IsFlagSet( int nFlags ) const +{ + return ( m_pConVar->IsFlagSet( nFlags ) != 0 ); +} + +FORCEINLINE_CVAR IConVar *ConVarRef::GetLinkedConVar() +{ + return m_pConVar; +} + +FORCEINLINE_CVAR const char *ConVarRef::GetName() const +{ + return m_pConVar->GetName(); +} + +FORCEINLINE_CVAR const char *ConVarRef::GetBaseName() const +{ + return m_pConVar->GetBaseName(); +} + +FORCEINLINE_CVAR int ConVarRef::GetSplitScreenPlayerSlot() const +{ + return m_pConVar->GetSplitScreenPlayerSlot(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a float +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR float ConVarRef::GetFloat( void ) const +{ + return m_pConVarState->m_Value.m_fValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as an int +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR int ConVarRef::GetInt( void ) const +{ + return m_pConVarState->m_Value.m_nValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a color +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR Color ConVarRef::GetColor( void ) const +{ + return m_pConVarState->GetColor(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR const char *ConVarRef::GetString( void ) const +{ + Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) ); + return m_pConVarState->m_Value.m_pszString; +} + + +FORCEINLINE_CVAR void ConVarRef::SetValue( const char *pValue ) +{ + m_pConVar->SetValue( pValue ); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue( float flValue ) +{ + m_pConVar->SetValue( flValue ); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue( int nValue ) +{ + m_pConVar->SetValue( nValue ); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue( Color value ) +{ + m_pConVar->SetValue( value ); +} + +FORCEINLINE_CVAR void ConVarRef::SetValue( bool bValue ) +{ + m_pConVar->SetValue( bValue ? 1 : 0 ); +} + +FORCEINLINE_CVAR const char *ConVarRef::GetDefault() const +{ + return m_pConVarState->m_pszDefaultValue; +} + +//----------------------------------------------------------------------------- +// Helper for referencing splitscreen convars (i.e., "name" and "name2") +//----------------------------------------------------------------------------- +class SplitScreenConVarRef +{ +public: + SplitScreenConVarRef( const char *pName ); + SplitScreenConVarRef( const char *pName, bool bIgnoreMissing ); + SplitScreenConVarRef( IConVar *pConVar ); + + void Init( const char *pName, bool bIgnoreMissing ); + bool IsValid() const; + bool IsFlagSet( int nFlags ) const; + + // Get/Set value + float GetFloat( int nSlot ) const; + int GetInt( int nSlot ) const; + Color GetColor( int nSlot ) const; + bool GetBool( int nSlot ) const { return !!GetInt( nSlot ); } + const char *GetString( int nSlot ) const; + + void SetValue( int nSlot, const char *pValue ); + void SetValue( int nSlot, float flValue ); + void SetValue( int nSlot, int nValue ); + void SetValue( int nSlot, Color value ); + void SetValue( int nSlot, bool bValue ); + + const char *GetName( int nSlot ) const; + + const char *GetDefault() const; + + const char *GetBaseName() const; + +private: + struct cv_t + { + IConVar *m_pConVar; + ConVar *m_pConVarState; + }; + + cv_t m_Info[ MAX_SPLITSCREEN_CLIENTS ]; +}; + +//----------------------------------------------------------------------------- +// Did we find an existing convar of that name? +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR bool SplitScreenConVarRef::IsFlagSet( int nFlags ) const +{ + return ( m_Info[ 0 ].m_pConVar->IsFlagSet( nFlags ) != 0 ); +} + +FORCEINLINE_CVAR const char *SplitScreenConVarRef::GetName( int nSlot ) const +{ + return m_Info[ nSlot ].m_pConVar->GetName(); +} + +FORCEINLINE_CVAR const char *SplitScreenConVarRef::GetBaseName() const +{ + return m_Info[ 0 ].m_pConVar->GetBaseName(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a float +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR float SplitScreenConVarRef::GetFloat( int nSlot ) const +{ + return m_Info[ nSlot ].m_pConVarState->m_Value.m_fValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as an int +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR int SplitScreenConVarRef::GetInt( int nSlot ) const +{ + return m_Info[ nSlot ].m_pConVarState->m_Value.m_nValue; +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as an int +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR Color SplitScreenConVarRef::GetColor( int nSlot ) const +{ + return m_Info[ nSlot ].m_pConVarState->GetColor(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. +//----------------------------------------------------------------------------- +FORCEINLINE_CVAR const char *SplitScreenConVarRef::GetString( int nSlot ) const +{ + Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) ); + return m_Info[ nSlot ].m_pConVarState->m_Value.m_pszString; +} + + +FORCEINLINE_CVAR void SplitScreenConVarRef::SetValue( int nSlot, const char *pValue ) +{ + m_Info[ nSlot ].m_pConVar->SetValue( pValue ); +} + +FORCEINLINE_CVAR void SplitScreenConVarRef::SetValue( int nSlot, float flValue ) +{ + m_Info[ nSlot ].m_pConVar->SetValue( flValue ); +} + +FORCEINLINE_CVAR void SplitScreenConVarRef::SetValue( int nSlot, int nValue ) +{ + m_Info[ nSlot ].m_pConVar->SetValue( nValue ); +} + +FORCEINLINE_CVAR void SplitScreenConVarRef::SetValue( int nSlot, Color value ) +{ + m_Info[ nSlot ].m_pConVar->SetValue( value ); +} + +FORCEINLINE_CVAR void SplitScreenConVarRef::SetValue( int nSlot, bool bValue ) +{ + m_Info[ nSlot ].m_pConVar->SetValue( bValue ? 1 : 0 ); +} + +FORCEINLINE_CVAR const char *SplitScreenConVarRef::GetDefault() const +{ + return m_Info[ 0 ].m_pConVarState->m_pszDefaultValue; +} + +//----------------------------------------------------------------------------- +// Called by the framework to register ConCommands with the ICVar +//----------------------------------------------------------------------------- +void ConVar_Register( int nCVarFlag = 0, IConCommandBaseAccessor *pAccessor = NULL ); +void ConVar_Unregister( ); + + +//----------------------------------------------------------------------------- +// Utility methods +//----------------------------------------------------------------------------- +void ConVar_PrintDescription( const ConCommandBase *pVar ); + + +//----------------------------------------------------------------------------- +// Purpose: Utility class to quickly allow ConCommands to call member methods +//----------------------------------------------------------------------------- +#pragma warning (disable : 4355 ) + +template< class T > +class CConCommandMemberAccessor : public ConCommand, public ICommandCallback, public ICommandCompletionCallback +{ + typedef ConCommand BaseClass; + typedef void ( T::*FnMemberCommandCallback_t )( const CCommand &command ); + typedef int ( T::*FnMemberCommandCompletionCallback_t )( const char *pPartial, CUtlVector< CUtlString > &commands ); + +public: + CConCommandMemberAccessor( T* pOwner, const char *pName, FnMemberCommandCallback_t callback, const char *pHelpString = 0, + int flags = 0, FnMemberCommandCompletionCallback_t completionFunc = 0 ) : + BaseClass( pName, this, pHelpString, flags, ( completionFunc != 0 ) ? this : NULL ) + { + m_pOwner = pOwner; + m_Func = callback; + m_CompletionFunc = completionFunc; + } + + ~CConCommandMemberAccessor() + { + Shutdown(); + } + + void SetOwner( T* pOwner ) + { + m_pOwner = pOwner; + } + + virtual void CommandCallback( const CCommand &command ) + { + Assert( m_pOwner && m_Func ); + (m_pOwner->*m_Func)( command ); + } + + virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) + { + Assert( m_pOwner && m_CompletionFunc ); + return (m_pOwner->*m_CompletionFunc)( pPartial, commands ); + } + +private: + T* m_pOwner; + FnMemberCommandCallback_t m_Func; + FnMemberCommandCompletionCallback_t m_CompletionFunc; +}; + +#pragma warning ( default : 4355 ) + + +//----------------------------------------------------------------------------- +// Purpose: Utility macros to quicky generate a simple console command +//----------------------------------------------------------------------------- +#define CON_COMMAND( name, description ) \ + static void name( const CCommand &args ); \ + static ConCommand name##_command( #name, name, description ); \ + static void name( const CCommand &args ) + +#define CON_COMMAND_F( name, description, flags ) \ + static void name( const CCommand &args ); \ + static ConCommand name##_command( #name, name, description, flags ); \ + static void name( const CCommand &args ) + +#define CON_COMMAND_F_COMPLETION( name, description, flags, completion ) \ + static void name( const CCommand &args ); \ + static ConCommand name##_command( #name, name, description, flags, completion ); \ + static void name( const CCommand &args ) + +#define CON_COMMAND_EXTERN( name, _funcname, description ) \ + void _funcname( const CCommand &args ); \ + static ConCommand name##_command( #name, _funcname, description ); \ + void _funcname( const CCommand &args ) + +#define CON_COMMAND_EXTERN_F( name, _funcname, description, flags ) \ + void _funcname( const CCommand &args ); \ + static ConCommand name##_command( #name, _funcname, description, flags ); \ + void _funcname( const CCommand &args ) + +#define CON_COMMAND_MEMBER_F( _thisclass, name, _funcname, description, flags ) \ + void _funcname( const CCommand &args ); \ + friend class CCommandMemberInitializer_##_funcname; \ + class CCommandMemberInitializer_##_funcname \ + { \ + public: \ + CCommandMemberInitializer_##_funcname() : m_ConCommandAccessor( NULL, name, &_thisclass::_funcname, description, flags ) \ + { \ + m_ConCommandAccessor.SetOwner( GET_OUTER( _thisclass, m_##_funcname##_register ) ); \ + } \ + private: \ + CConCommandMemberAccessor< _thisclass > m_ConCommandAccessor; \ + }; \ + \ + CCommandMemberInitializer_##_funcname m_##_funcname##_register; \ + + +#endif // CONVAR_H diff --git a/external/vpc/public/tier1/convar_serverbounded.h b/external/vpc/public/tier1/convar_serverbounded.h new file mode 100644 index 0000000..3616239 --- /dev/null +++ b/external/vpc/public/tier1/convar_serverbounded.h @@ -0,0 +1,53 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Helper class for cvars that have restrictions on their value. +// +//=============================================================================// + +#ifndef CONVAR_SERVERBOUNDED_H +#define CONVAR_SERVERBOUNDED_H +#ifdef _WIN32 +#pragma once +#endif + + +// This class is used to virtualize a ConVar's value, so the client can restrict its +// value while connected to a server. When using this across modules, it's important +// to dynamic_cast it to a ConVar_ServerBounded or you won't get the restricted value. +// +// NOTE: FCVAR_USERINFO vars are not virtualized before they are sent to the server +// (we have no way to detect if the virtualized value would change), so +// if you want to use a bounded cvar's value on the server, you must rebound it +// the same way the client does. +class ConVar_ServerBounded : public ConVar +{ +public: + ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString ) + : ConVar( pName, pDefaultValue, flags, pHelpString ) + { + } + + ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, FnChangeCallback_t callback ) + : ConVar( pName, pDefaultValue, flags, pHelpString, callback ) + { + } + + ConVar_ServerBounded( char const *pName, char const *pDefaultValue, int flags, char const *pHelpString, bool bMin, float fMin, bool bMax, float fMax ) + : ConVar( pName, pDefaultValue, flags, pHelpString, bMin, fMin, bMax, fMax ) {} + + // You must implement GetFloat. + virtual float GetFloat() const = 0; + + // You can optionally implement these. + virtual int GetInt() const { return (int)GetFloat(); } + virtual bool GetBool() const { return ( GetInt() != 0 ); } + + // Use this to get the underlying cvar's value. + float GetBaseFloatValue() const + { + return ConVar::GetFloat(); + } +}; + + +#endif // CONVAR_SERVERBOUNDED_H diff --git a/external/vpc/public/tier1/exprevaluator.h b/external/vpc/public/tier1/exprevaluator.h new file mode 100644 index 0000000..89dffc6 --- /dev/null +++ b/external/vpc/public/tier1/exprevaluator.h @@ -0,0 +1,74 @@ +//===== Copyright � 1996-2006, Valve Corporation, All rights reserved. ======// +// +// Purpose: ExprSimplifier builds a binary tree from an infix expression (in the +// form of a character array). +// +//===========================================================================// + +#ifndef EXPREVALUATOR_H +#define EXPREVALUATOR_H + +#if defined( _WIN32 ) +#pragma once +#endif + +static const char OR_OP = '|'; +static const char AND_OP = '&'; +static const char NOT_OP = '!'; + +#define MAX_IDENTIFIER_LEN 128 +enum Kind {CONDITIONAL, NOT, LITERAL}; + +struct ExprNode +{ + ExprNode *left; // left sub-expression + ExprNode *right; // right sub-expression + Kind kind; // kind of node this is + union + { + char cond; // the conditional + bool value; // the value + } data; +}; + +typedef ExprNode *ExprTree; + +// callback to evaluate a $<symbol> during evaluation, return true or false +typedef bool (*GetSymbolProc_t)( const char *pKey ); +typedef void (*SyntaxErrorProc_t)( const char *pReason ); + +class CExpressionEvaluator +{ +public: + CExpressionEvaluator(); + ~CExpressionEvaluator(); + bool Evaluate( bool &result, const char *pInfixExpression, GetSymbolProc_t pGetSymbolProc = 0, SyntaxErrorProc_t pSyntaxErrorProc = 0 ); + +private: + CExpressionEvaluator( CExpressionEvaluator& ); // prevent copy constructor being used + + char GetNextToken( void ); + void FreeNode( ExprNode *pNode ); + ExprNode *AllocateNode( void ); + void FreeTree( ExprTree &node ); + bool IsConditional( bool &bCondition, const char token ); + bool IsNotOp( const char token ); + bool IsIdentifierOrConstant( const char token ); + bool MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right ); + bool MakeFactor( ExprTree &tree ); + bool MakeTerm( ExprTree &tree ); + bool MakeExpression( ExprTree &tree ); + bool BuildExpression( void ); + bool SimplifyNode( ExprTree &node ); + + ExprTree m_ExprTree; // Tree representation of the expression + char m_CurToken; // Current token read from the input expression + const char *m_pExpression; // Array of the expression characters + int m_CurPosition; // Current position in the input expression + char m_Identifier[MAX_IDENTIFIER_LEN]; // Stores the identifier string + GetSymbolProc_t m_pGetSymbolProc; + SyntaxErrorProc_t m_pSyntaxErrorProc; + bool m_bSetup; +}; + +#endif diff --git a/external/vpc/public/tier1/fmtstr.h b/external/vpc/public/tier1/fmtstr.h new file mode 100644 index 0000000..476f4c5 --- /dev/null +++ b/external/vpc/public/tier1/fmtstr.h @@ -0,0 +1,179 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: A simple class for performing safe and in-expression sprintf-style +// string formatting +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef FMTSTR_H +#define FMTSTR_H + +#include <stdarg.h> +#include <stdio.h> +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier1/strtools.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//============================================================================= + +// using macro to be compatable with GCC +#define FmtStrVSNPrintf( szBuf, nBufSize, bQuietTruncation, ppszFormat ) \ + do \ + { \ + int result; \ + va_list arg_ptr; \ + bool bTruncated = false; \ + static int scAsserted = 0; \ + \ + va_start(arg_ptr, (*(ppszFormat))); \ + result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \ + va_end(arg_ptr); \ + \ + (szBuf)[(nBufSize)-1] = 0; \ + if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \ + { \ + Assert( !bTruncated ); \ + scAsserted++; \ + } \ + } \ + while (0) + + +//----------------------------------------------------------------------------- +// +// Purpose: String formatter with specified size +// + +template <int SIZE_BUF> +class CFmtStrN +{ +public: + CFmtStrN() + { + InitQuietTruncation(); + m_szBuf[0] = 0; + m_nLength = 0; + } + + // Standard C formatting + CFmtStrN(const char *pszFormat, ...) FMTFUNCTION( 2, 3 ) + { + InitQuietTruncation(); + FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat); + FixLength(); + } + + // Use this for pass-through formatting + CFmtStrN(const char ** ppszFormat, ...) + { + InitQuietTruncation(); + FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat); + FixLength(); + } + + // Explicit reformat + const char *sprintf(const char *pszFormat, ...) FMTFUNCTION( 2, 3 ) + { + InitQuietTruncation(); + FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat); + FixLength(); + return m_szBuf; + } + + // Use this for pass-through formatting + void VSprintf(const char **ppszFormat, ...) + { + InitQuietTruncation(); + FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat); + FixLength(); + } + + // Use for access + operator const char *() const { return m_szBuf; } + char *Access() { return m_szBuf; } + CFmtStrN<SIZE_BUF> & operator=( const char *pchValue ) { sprintf( pchValue ); return *this; } + CFmtStrN<SIZE_BUF> & operator+=( const char *pchValue ) { Append( pchValue ); return *this; } + int Length() const { return m_nLength; } + + void Clear() { m_szBuf[0] = 0; m_nLength = 0; } + + void AppendFormat( const char *pchFormat, ... ) { char *pchEnd = m_szBuf + m_nLength; FmtStrVSNPrintf( pchEnd, SIZE_BUF - m_nLength, m_bQuietTruncation, &pchFormat ); FixLength(); } + void AppendFormatV( const char *pchFormat, va_list args ); + void Append( const char *pchValue ) { AppendFormat( pchValue ); } + + void AppendIndent( uint32 unCount, char chIndent = '\t' ); +protected: + virtual void InitQuietTruncation() + { +#ifdef _DEBUG + m_bQuietTruncation = false; +#else + m_bQuietTruncation = true; // Force quiet for release builds +#endif + } + + bool m_bQuietTruncation; + + void FixLength() { m_nLength = V_strlen(m_szBuf); } +private: + char m_szBuf[SIZE_BUF]; + int m_nLength; + +}; + + +// Version which will not assert if strings are truncated + +template <int SIZE_BUF> +class CFmtStrQuietTruncationN : public CFmtStrN<SIZE_BUF> +{ +protected: + virtual void InitQuietTruncation() { this->m_bQuietTruncation = true; } +}; + + +template< int SIZE_BUF > +void CFmtStrN<SIZE_BUF>::AppendIndent( uint32 unCount, char chIndent ) +{ + Assert( Length() + unCount < SIZE_BUF ); + if( Length() + unCount >= SIZE_BUF ) + unCount = SIZE_BUF - (1+Length()); + for ( uint32 x = 0; x < unCount; x++ ) + { + m_szBuf[ m_nLength++ ] = chIndent; + } + m_szBuf[ m_nLength ] = '\0'; +} + +template< int SIZE_BUF > +void CFmtStrN<SIZE_BUF>::AppendFormatV( const char *pchFormat, va_list args ) +{ + int cubPrinted = V_vsnprintf( m_szBuf+Length(), SIZE_BUF - Length(), pchFormat, args ); + m_nLength += cubPrinted; +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Default-sized string formatter +// + +#define FMTSTR_STD_LEN 1024 + +typedef CFmtStrN<FMTSTR_STD_LEN> CFmtStr; +typedef CFmtStrQuietTruncationN<FMTSTR_STD_LEN> CFmtStrQuietTruncation; +typedef CFmtStrN<1024> CFmtStr1024; +typedef CFmtStrN<8192> CFmtStrMax; + +//============================================================================= + +const int k_cchFormattedDate = 64; +const int k_cchFormattedTime = 32; +bool BGetLocalFormattedTime( time_t timeVal, char *pchDate, int cubDate, char *pchTime, int cubTime ); + +#endif // FMTSTR_H diff --git a/external/vpc/public/tier1/functors.h b/external/vpc/public/tier1/functors.h new file mode 100644 index 0000000..5b74787 --- /dev/null +++ b/external/vpc/public/tier1/functors.h @@ -0,0 +1,920 @@ +//========== Copyright © 2006, Valve Corporation, All rights reserved. ======== +// +// Purpose: Implements a generic infrastucture for functors combining +// a number of techniques to provide transparent parameter type +// deduction and packaging. Supports both member and non-member functions. +// +// See also: http://en.wikipedia.org/wiki/Function_object +// +// Note that getting into the guts of this file is not for the +// feint of heart. The core concept here is that the compiler can +// figure out all the parameter types. +// +// E.g.: +// +// struct CMyClass +// { +// void foo( int i) {} +// }; +// +// int bar(int i) { return i; } +// +// CMyClass myInstance; +// +// CFunctor *pFunctor = CreateFunctor( &myInstance, CMyClass::foo, 8675 ); +// CFunctor *pFunctor2 = CreateFunctor( &bar, 309 ); +// +// void CallEm() +// { +// (*pFunctor)(); +// (*pFunctor2)(); +// } +// +//============================================================================= + +#ifndef FUNCTORS_H +#define FUNCTORS_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier1/refcount.h" +#include "tier1/utlenvelope.h" +#include <typeinfo> + + +//----------------------------------------------------------------------------- +// +// Macros used as basis for template generation. Just ignore the man behind the +// curtain +// +//----------------------------------------------------------------------------- + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_0 +#define FUNC_TEMPLATE_ARG_PARAMS_0 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_0 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_0 +#define FUNC_ARG_MEMBERS_0 +#define FUNC_ARG_FORMAL_PARAMS_0 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_0 +#define FUNC_CALL_ARGS_INIT_0 +#define FUNC_SOLO_CALL_ARGS_INIT_0 +#define FUNC_CALL_MEMBER_ARGS_0 +#define FUNC_CALL_ARGS_0 +#define FUNC_CALL_DATA_ARGS_0( _var ) +#define FUNC_FUNCTOR_CALL_ARGS_0 +#define FUNC_TEMPLATE_FUNC_PARAMS_0 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_0 +#define FUNC_VALIDATION_STRING_0 V_snprintf( pString, nBufLen, "method( void )" ); +#define FUNC_SEPARATOR_0 + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_1 typename ARG_TYPE_1 +#define FUNC_TEMPLATE_ARG_PARAMS_1 , typename ARG_TYPE_1 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_1 , ARG_TYPE_1 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_1 ARG_TYPE_1 +#define FUNC_ARG_MEMBERS_1 ARG_TYPE_1 m_arg1 +#define FUNC_ARG_FORMAL_PARAMS_1 , const ARG_TYPE_1 &arg1 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_1 const ARG_TYPE_1 &arg1 +#define FUNC_CALL_ARGS_INIT_1 , m_arg1( arg1 ) +#define FUNC_SOLO_CALL_ARGS_INIT_1 : m_arg1( arg1 ) +#define FUNC_CALL_MEMBER_ARGS_1 m_arg1 +#define FUNC_CALL_ARGS_1 arg1 +#define FUNC_CALL_DATA_ARGS_1( _var ) _var->m_arg1 +#define FUNC_FUNCTOR_CALL_ARGS_1 , arg1 +#define FUNC_TEMPLATE_FUNC_PARAMS_1 , typename FUNC_ARG_TYPE_1 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_1 FUNC_ARG_TYPE_1 +#define FUNC_VALIDATION_STRING_1 V_snprintf( pString, nBufLen, "method( %s )", typeid( ARG_TYPE_1 ).name() ); +#define FUNC_SEPARATOR_1 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_2 typename ARG_TYPE_1, typename ARG_TYPE_2 +#define FUNC_TEMPLATE_ARG_PARAMS_2 , typename ARG_TYPE_1, typename ARG_TYPE_2 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_2 , ARG_TYPE_1, ARG_TYPE_2 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_2 ARG_TYPE_1, ARG_TYPE_2 +#define FUNC_ARG_MEMBERS_2 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2 +#define FUNC_ARG_FORMAL_PARAMS_2 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_2 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2 +#define FUNC_CALL_ARGS_INIT_2 , m_arg1( arg1 ), m_arg2( arg2 ) +#define FUNC_SOLO_CALL_ARGS_INIT_2 : m_arg1( arg1 ), m_arg2( arg2 ) +#define FUNC_CALL_MEMBER_ARGS_2 m_arg1, m_arg2 +#define FUNC_CALL_ARGS_2 arg1, arg2 +#define FUNC_CALL_DATA_ARGS_2( _var ) _var->m_arg1, _var->m_arg2 +#define FUNC_FUNCTOR_CALL_ARGS_2 , arg1, arg2 +#define FUNC_TEMPLATE_FUNC_PARAMS_2 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_2 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2 +#define FUNC_VALIDATION_STRING_2 V_snprintf( pString, nBufLen, "method( %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name() ); +#define FUNC_SEPARATOR_2 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_3 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3 +#define FUNC_TEMPLATE_ARG_PARAMS_3 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_3 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_3 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3 +#define FUNC_ARG_MEMBERS_3 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3 +#define FUNC_ARG_FORMAL_PARAMS_3 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_3 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3 +#define FUNC_CALL_ARGS_INIT_3 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ) +#define FUNC_SOLO_CALL_ARGS_INIT_3 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ) +#define FUNC_CALL_MEMBER_ARGS_3 m_arg1, m_arg2, m_arg3 +#define FUNC_CALL_ARGS_3 arg1, arg2, arg3 +#define FUNC_CALL_DATA_ARGS_3( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3 +#define FUNC_FUNCTOR_CALL_ARGS_3 , arg1, arg2, arg3 +#define FUNC_TEMPLATE_FUNC_PARAMS_3 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_3 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3 +#define FUNC_VALIDATION_STRING_3 V_snprintf( pString, nBufLen, "method( %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name() ); +#define FUNC_SEPARATOR_3 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_4 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4 +#define FUNC_TEMPLATE_ARG_PARAMS_4 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_4 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_4 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4 +#define FUNC_ARG_MEMBERS_4 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4 +#define FUNC_ARG_FORMAL_PARAMS_4 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_4 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4 +#define FUNC_CALL_ARGS_INIT_4 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ) +#define FUNC_SOLO_CALL_ARGS_INIT_4 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ) +#define FUNC_CALL_MEMBER_ARGS_4 m_arg1, m_arg2, m_arg3, m_arg4 +#define FUNC_CALL_ARGS_4 arg1, arg2, arg3, arg4 +#define FUNC_CALL_DATA_ARGS_4( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4 +#define FUNC_FUNCTOR_CALL_ARGS_4 , arg1, arg2, arg3, arg4 +#define FUNC_TEMPLATE_FUNC_PARAMS_4 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_4 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4 +#define FUNC_VALIDATION_STRING_4 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name() ); +#define FUNC_SEPARATOR_4 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_5 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5 +#define FUNC_TEMPLATE_ARG_PARAMS_5 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_5 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_5 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5 +#define FUNC_ARG_MEMBERS_5 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5 +#define FUNC_ARG_FORMAL_PARAMS_5 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_5 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5 +#define FUNC_CALL_ARGS_INIT_5 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ) +#define FUNC_SOLO_CALL_ARGS_INIT_5 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ) +#define FUNC_CALL_MEMBER_ARGS_5 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5 +#define FUNC_CALL_ARGS_5 arg1, arg2, arg3, arg4, arg5 +#define FUNC_CALL_DATA_ARGS_5( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5 +#define FUNC_FUNCTOR_CALL_ARGS_5 , arg1, arg2, arg3, arg4, arg5 +#define FUNC_TEMPLATE_FUNC_PARAMS_5 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_5 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5 +#define FUNC_VALIDATION_STRING_5 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name() ); +#define FUNC_SEPARATOR_5 , + + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_6 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6 +#define FUNC_TEMPLATE_ARG_PARAMS_6 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_6 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_6 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6 +#define FUNC_ARG_MEMBERS_6 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6 +#define FUNC_ARG_FORMAL_PARAMS_6 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_6 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6 +#define FUNC_CALL_ARGS_INIT_6 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ) +#define FUNC_SOLO_CALL_ARGS_INIT_6 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ) +#define FUNC_CALL_MEMBER_ARGS_6 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6 +#define FUNC_CALL_ARGS_6 arg1, arg2, arg3, arg4, arg5, arg6 +#define FUNC_CALL_DATA_ARGS_6( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6 +#define FUNC_FUNCTOR_CALL_ARGS_6 , arg1, arg2, arg3, arg4, arg5, arg6 +#define FUNC_TEMPLATE_FUNC_PARAMS_6 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_6 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6 +#define FUNC_VALIDATION_STRING_6 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name() ); +#define FUNC_SEPARATOR_6 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_7 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7 +#define FUNC_TEMPLATE_ARG_PARAMS_7 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_7 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_7 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7 +#define FUNC_ARG_MEMBERS_7 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; +#define FUNC_ARG_FORMAL_PARAMS_7 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_7 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7 +#define FUNC_CALL_ARGS_INIT_7 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ) +#define FUNC_SOLO_CALL_ARGS_INIT_7 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ) +#define FUNC_CALL_MEMBER_ARGS_7 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7 +#define FUNC_CALL_ARGS_7 arg1, arg2, arg3, arg4, arg5, arg6, arg7 +#define FUNC_CALL_DATA_ARGS_7( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7 +#define FUNC_FUNCTOR_CALL_ARGS_7 , arg1, arg2, arg3, arg4, arg5, arg6, arg7 +#define FUNC_TEMPLATE_FUNC_PARAMS_7 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_7 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7 +#define FUNC_VALIDATION_STRING_7 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name() ); +#define FUNC_SEPARATOR_7 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_8 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8 +#define FUNC_TEMPLATE_ARG_PARAMS_8 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_8 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_8 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8 +#define FUNC_ARG_MEMBERS_8 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; +#define FUNC_ARG_FORMAL_PARAMS_8 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_8 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8 +#define FUNC_CALL_ARGS_INIT_8 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ) +#define FUNC_SOLO_CALL_ARGS_INIT_8 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ) +#define FUNC_CALL_MEMBER_ARGS_8 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8 +#define FUNC_CALL_ARGS_8 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 +#define FUNC_CALL_DATA_ARGS_8( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8 +#define FUNC_FUNCTOR_CALL_ARGS_8 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 +#define FUNC_TEMPLATE_FUNC_PARAMS_8 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_8 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8 +#define FUNC_VALIDATION_STRING_8 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name() ); +#define FUNC_SEPARATOR_8 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_9 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9 +#define FUNC_TEMPLATE_ARG_PARAMS_9 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_9 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_9 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9 +#define FUNC_ARG_MEMBERS_9 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; +#define FUNC_ARG_FORMAL_PARAMS_9 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_9 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9 +#define FUNC_CALL_ARGS_INIT_9 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ) +#define FUNC_SOLO_CALL_ARGS_INIT_9 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ) +#define FUNC_CALL_MEMBER_ARGS_9 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9 +#define FUNC_CALL_ARGS_9 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 +#define FUNC_CALL_DATA_ARGS_9( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9 +#define FUNC_FUNCTOR_CALL_ARGS_9 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 +#define FUNC_TEMPLATE_FUNC_PARAMS_9 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_9 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9 +#define FUNC_VALIDATION_STRING_9 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name() ); +#define FUNC_SEPARATOR_9 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_10 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10 +#define FUNC_TEMPLATE_ARG_PARAMS_10 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_10 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_10 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10 +#define FUNC_ARG_MEMBERS_10 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; +#define FUNC_ARG_FORMAL_PARAMS_10 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_10 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10 +#define FUNC_CALL_ARGS_INIT_10 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ) +#define FUNC_SOLO_CALL_ARGS_INIT_10 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ) +#define FUNC_CALL_MEMBER_ARGS_10 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10 +#define FUNC_CALL_ARGS_10 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 +#define FUNC_CALL_DATA_ARGS_10( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10 +#define FUNC_FUNCTOR_CALL_ARGS_10 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 +#define FUNC_TEMPLATE_FUNC_PARAMS_10 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_10 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10 +#define FUNC_VALIDATION_STRING_10 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name() ); +#define FUNC_SEPARATOR_10 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_11 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11 +#define FUNC_TEMPLATE_ARG_PARAMS_11 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_11 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_11 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11 +#define FUNC_ARG_MEMBERS_11 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11 +#define FUNC_ARG_FORMAL_PARAMS_11 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_11 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11 +#define FUNC_CALL_ARGS_INIT_11 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ) +#define FUNC_SOLO_CALL_ARGS_INIT_11 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ) +#define FUNC_CALL_MEMBER_ARGS_11 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11 +#define FUNC_CALL_ARGS_11 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 +#define FUNC_CALL_DATA_ARGS_11( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11 +#define FUNC_FUNCTOR_CALL_ARGS_11 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 +#define FUNC_TEMPLATE_FUNC_PARAMS_11 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_11 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11 +#define FUNC_VALIDATION_STRING_11 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name() ); +#define FUNC_SEPARATOR_11 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_12 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12 +#define FUNC_TEMPLATE_ARG_PARAMS_12 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_12 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_12 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12 +#define FUNC_ARG_MEMBERS_12 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12 +#define FUNC_ARG_FORMAL_PARAMS_12 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_12 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12 +#define FUNC_CALL_ARGS_INIT_12 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ) +#define FUNC_SOLO_CALL_ARGS_INIT_12 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ) +#define FUNC_CALL_MEMBER_ARGS_12 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12 +#define FUNC_CALL_ARGS_12 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 +#define FUNC_CALL_DATA_ARGS_12( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11, _var->m_arg12 +#define FUNC_FUNCTOR_CALL_ARGS_12 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 +#define FUNC_TEMPLATE_FUNC_PARAMS_12 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_12 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12 +#define FUNC_VALIDATION_STRING_12 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name(), typeid( ARG_TYPE_12 ).name() ); +#define FUNC_SEPARATOR_12 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_13 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13 +#define FUNC_TEMPLATE_ARG_PARAMS_13 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_13 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_13 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13 +#define FUNC_ARG_MEMBERS_13 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12; ARG_TYPE_13 m_arg13 +#define FUNC_ARG_FORMAL_PARAMS_13 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_13 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13 +#define FUNC_CALL_ARGS_INIT_13 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ) +#define FUNC_SOLO_CALL_ARGS_INIT_13 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ) +#define FUNC_CALL_MEMBER_ARGS_13 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13 +#define FUNC_CALL_ARGS_13 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13 +#define FUNC_CALL_DATA_ARGS_13( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11, _var->m_arg12, _var->m_arg13 +#define FUNC_FUNCTOR_CALL_ARGS_13 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13 +#define FUNC_TEMPLATE_FUNC_PARAMS_13 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12, typename FUNC_ARG_TYPE_13 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_13 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13 +#define FUNC_VALIDATION_STRING_13 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name(), typeid( ARG_TYPE_12 ).name(), typeid( ARG_TYPE_13 ).name() ); +#define FUNC_SEPARATOR_13 , + +#define FUNC_SOLO_TEMPLATE_ARG_PARAMS_14 typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13, typename ARG_TYPE_14 +#define FUNC_TEMPLATE_ARG_PARAMS_14 , typename ARG_TYPE_1, typename ARG_TYPE_2, typename ARG_TYPE_3, typename ARG_TYPE_4, typename ARG_TYPE_5, typename ARG_TYPE_6, typename ARG_TYPE_7, typename ARG_TYPE_8, typename ARG_TYPE_9, typename ARG_TYPE_10, typename ARG_TYPE_11, typename ARG_TYPE_12, typename ARG_TYPE_13, typename ARG_TYPE_14 +#define FUNC_BASE_TEMPLATE_ARG_PARAMS_14 , ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13, ARG_TYPE_14 +#define FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_14 ARG_TYPE_1, ARG_TYPE_2, ARG_TYPE_3, ARG_TYPE_4, ARG_TYPE_5, ARG_TYPE_6, ARG_TYPE_7, ARG_TYPE_8, ARG_TYPE_9, ARG_TYPE_10, ARG_TYPE_11, ARG_TYPE_12, ARG_TYPE_13, ARG_TYPE_14 +#define FUNC_ARG_MEMBERS_14 ARG_TYPE_1 m_arg1; ARG_TYPE_2 m_arg2; ARG_TYPE_3 m_arg3; ARG_TYPE_4 m_arg4; ARG_TYPE_5 m_arg5; ARG_TYPE_6 m_arg6; ARG_TYPE_7 m_arg7; ARG_TYPE_8 m_arg8; ARG_TYPE_9 m_arg9; ARG_TYPE_10 m_arg10; ARG_TYPE_11 m_arg11; ARG_TYPE_12 m_arg12; ARG_TYPE_13 m_arg13; ARG_TYPE_14 m_arg14 +#define FUNC_ARG_FORMAL_PARAMS_14 , const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13, const ARG_TYPE_14 &arg14 +#define FUNC_PROXY_ARG_FORMAL_PARAMS_14 const ARG_TYPE_1 &arg1, const ARG_TYPE_2 &arg2, const ARG_TYPE_3 &arg3, const ARG_TYPE_4 &arg4, const ARG_TYPE_5 &arg5, const ARG_TYPE_6 &arg6, const ARG_TYPE_7 &arg7, const ARG_TYPE_8 &arg8, const ARG_TYPE_9 &arg9, const ARG_TYPE_10 &arg10, const ARG_TYPE_11 &arg11, const ARG_TYPE_12 &arg12, const ARG_TYPE_13 &arg13, const ARG_TYPE_14 &arg14 +#define FUNC_CALL_ARGS_INIT_14 , m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ), m_arg14( arg14 ) +#define FUNC_SOLO_CALL_ARGS_INIT_14 : m_arg1( arg1 ), m_arg2( arg2 ), m_arg3( arg3 ), m_arg4( arg4 ), m_arg5( arg5 ), m_arg6( arg6 ), m_arg7( arg7 ), m_arg8( arg8 ), m_arg9( arg9 ), m_arg10( arg10 ), m_arg11( arg11 ), m_arg12( arg12 ), m_arg13( arg13 ), m_arg14( arg14 ) +#define FUNC_CALL_MEMBER_ARGS_14 m_arg1, m_arg2, m_arg3, m_arg4, m_arg5, m_arg6, m_arg7, m_arg8, m_arg9, m_arg10, m_arg11, m_arg12, m_arg13, m_arg14 +#define FUNC_CALL_ARGS_14 arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 +#define FUNC_CALL_DATA_ARGS_14( _var ) _var->m_arg1, _var->m_arg2, _var->m_arg3, _var->m_arg4, _var->m_arg5, _var->m_arg6, _var->m_arg7, _var->m_arg8, _var->m_arg9, _var->m_arg10, _var->m_arg11, _var->m_arg12, _var->m_arg13, _var->m_arg14 +#define FUNC_FUNCTOR_CALL_ARGS_14 , arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14 +#define FUNC_TEMPLATE_FUNC_PARAMS_14 , typename FUNC_ARG_TYPE_1, typename FUNC_ARG_TYPE_2, typename FUNC_ARG_TYPE_3, typename FUNC_ARG_TYPE_4, typename FUNC_ARG_TYPE_5, typename FUNC_ARG_TYPE_6, typename FUNC_ARG_TYPE_7, typename FUNC_ARG_TYPE_8, typename FUNC_ARG_TYPE_9, typename FUNC_ARG_TYPE_10, typename FUNC_ARG_TYPE_11, typename FUNC_ARG_TYPE_12, typename FUNC_ARG_TYPE_13, typename FUNC_ARG_TYPE_14 +#define FUNC_BASE_TEMPLATE_FUNC_PARAMS_14 FUNC_ARG_TYPE_1, FUNC_ARG_TYPE_2, FUNC_ARG_TYPE_3, FUNC_ARG_TYPE_4, FUNC_ARG_TYPE_5, FUNC_ARG_TYPE_6, FUNC_ARG_TYPE_7, FUNC_ARG_TYPE_8, FUNC_ARG_TYPE_9, FUNC_ARG_TYPE_10, FUNC_ARG_TYPE_11, FUNC_ARG_TYPE_12, FUNC_ARG_TYPE_13, FUNC_ARG_TYPE_14 +#define FUNC_VALIDATION_STRING_14 V_snprintf( pString, nBufLen, "method( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )", typeid( ARG_TYPE_1 ).name(), typeid( ARG_TYPE_2 ).name(), typeid( ARG_TYPE_3 ).name(), typeid( ARG_TYPE_4 ).name(), typeid( ARG_TYPE_5 ).name(), typeid( ARG_TYPE_6 ).name(), typeid( ARG_TYPE_7 ).name(), typeid( ARG_TYPE_8 ).name(), typeid( ARG_TYPE_9 ).name(), typeid( ARG_TYPE_10 ).name(), typeid( ARG_TYPE_11 ).name(), typeid( ARG_TYPE_12 ).name(), typeid( ARG_TYPE_13 ).name(), typeid( ARG_TYPE_14 ).name() ); +#define FUNC_SEPARATOR_14 , + +#define FUNC_GENERATE_ALL_BUT0( INNERMACRONAME ) \ + INNERMACRONAME(1); \ + INNERMACRONAME(2); \ + INNERMACRONAME(3); \ + INNERMACRONAME(4); \ + INNERMACRONAME(5); \ + INNERMACRONAME(6); \ + INNERMACRONAME(7); \ + INNERMACRONAME(8); \ + INNERMACRONAME(9); \ + INNERMACRONAME(10);\ + INNERMACRONAME(11);\ + INNERMACRONAME(12);\ + INNERMACRONAME(13);\ + INNERMACRONAME(14) + +#define FUNC_GENERATE_ALL( INNERMACRONAME ) \ + INNERMACRONAME(0); \ + FUNC_GENERATE_ALL_BUT0( INNERMACRONAME ) + + +//----------------------------------------------------------------------------- +// +// Purpose: Base class of all function objects +// +//----------------------------------------------------------------------------- +abstract_class CFunctor : public IRefCounted +{ +public: + CFunctor() + { +#ifdef DEBUG + m_nUserID = 0; +#endif + } + virtual ~CFunctor() {} + virtual void operator()() = 0; + + unsigned m_nUserID; // For debugging +}; + + +//----------------------------------------------------------------------------- +// NOTE: Functor data + functor callback are tied together +// The basic idea is that someone creates the functor data. At a later point, +// the functor data is passed to a functor callback. Validation strings +// are compared in debug builds to ensure the data matches the callback +//----------------------------------------------------------------------------- +abstract_class CFunctorData : public IRefCounted +{ +public: + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const = 0; +}; + +abstract_class CFunctorCallback : public IRefCounted +{ +public: + virtual bool IsEqual( CFunctorCallback *pSrc ) const = 0; + virtual void operator()( CFunctorData *pData ) = 0; + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const = 0; + virtual const char *GetImplClassName() const = 0; + virtual const void *GetTarget() const = 0; +}; + + +//----------------------------------------------------------------------------- +// When calling through a functor, care needs to be taken to not pass objects that might go away. +// Since this code determines the type to store in the functor based on the actual arguments, +// this is achieved by changing the point of call. +// +// See also CUtlEnvelope +//----------------------------------------------------------------------------- +// convert a reference to a passable value +template <typename T> +inline T RefToVal(const T &item) +{ + return item; +} + + +//----------------------------------------------------------------------------- +// This class can be used to pass into a functor a proxy object for a pointer +// to be resolved later. For example, you can execute a "call" on a resource +// whose actual value is not known until a later time +//----------------------------------------------------------------------------- +template <typename T> +class CLateBoundPtr +{ +public: + CLateBoundPtr( T **ppObject ) + : m_ppObject( ppObject ) + { + } + + T *operator->() { return *m_ppObject; } + T &operator *() { return **m_ppObject; } + operator T *() const { return (T*)(*m_ppObject); } + operator void *() { return *m_ppObject; } + +private: + T **m_ppObject; +}; + + +//----------------------------------------------------------------------------- +// +// Purpose: Classes to define memory management policies when operating +// on pointers to members +// +//----------------------------------------------------------------------------- +class CFuncMemPolicyNone +{ +public: + static void OnAcquire(void *pObject) {} + static void OnRelease(void *pObject) {} +}; + +template <class OBJECT_TYPE_PTR = IRefCounted *> +class CFuncMemPolicyRefCount +{ +public: + static void OnAcquire(OBJECT_TYPE_PTR pObject) { pObject->AddRef(); } + static void OnRelease(OBJECT_TYPE_PTR pObject) { pObject->Release(); } +}; + + +//----------------------------------------------------------------------------- +// +// Purpose: Function proxy is a generic facility for holding a function +// pointer. Can be used on own, though primarily for use +// by this file +// +//----------------------------------------------------------------------------- +template <class OBJECT_TYPE_PTR, typename FUNCTION_TYPE, class MEM_POLICY = CFuncMemPolicyNone > +class CMemberFuncProxyBase +{ +public: + bool operator==( const CMemberFuncProxyBase &src ) const + { + return m_pfnProxied == src.m_pfnProxied && m_pObject == src.m_pObject; + } + + const void *GetTarget() const + { + return m_pObject; + } + +protected: + CMemberFuncProxyBase( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied ) + : m_pObject( pObject ), + m_pfnProxied( pfnProxied ) + { + MEM_POLICY::OnAcquire(m_pObject); + } + + ~CMemberFuncProxyBase() + { + MEM_POLICY::OnRelease(m_pObject); + } + + void Set( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied ) + { + m_pfnProxied = pfnProxied; + m_pObject = pObject; + } + + void OnCall() + { + Assert( (void *)m_pObject != NULL ); + } + + FUNCTION_TYPE m_pfnProxied; + OBJECT_TYPE_PTR m_pObject; +}; + + +#define DEFINE_MEMBER_FUNC_PROXY( N ) \ + template <class OBJECT_TYPE_PTR, typename FUNCTION_TYPE FUNC_TEMPLATE_ARG_PARAMS_##N, class MEM_POLICY = CFuncMemPolicyNone> \ + class CMemberFuncProxy##N : public CMemberFuncProxyBase<OBJECT_TYPE_PTR, FUNCTION_TYPE, MEM_POLICY> \ + { \ + public: \ + CMemberFuncProxy##N( OBJECT_TYPE_PTR pObject = NULL, FUNCTION_TYPE pfnProxied = NULL ) \ + : CMemberFuncProxyBase<OBJECT_TYPE_PTR, FUNCTION_TYPE, MEM_POLICY >( pObject, pfnProxied ) \ + { \ + } \ + \ + void operator()( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) \ + { \ + this->OnCall(); \ + ((*this->m_pObject).*this->m_pfnProxied)( FUNC_CALL_ARGS_##N ); \ + } \ + } + +FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNC_PROXY ); + + +//----------------------------------------------------------------------------- +// +// The actual functor implementation +// +//----------------------------------------------------------------------------- + +#include "tier0/memdbgon.h" + +typedef CRefCounted1<CFunctor, CRefCountServiceMT> CFunctorBase; + +#define DEFINE_FUNCTOR_TEMPLATE(N) \ + template <typename FUNC_TYPE FUNC_TEMPLATE_ARG_PARAMS_##N, class FUNCTOR_BASE = CFunctorBase> \ + class CFunctor##N : public CFunctorBase \ + { \ + public: \ + CFunctor##N( FUNC_TYPE pfnProxied FUNC_ARG_FORMAL_PARAMS_##N ) : m_pfnProxied( pfnProxied ) FUNC_CALL_ARGS_INIT_##N {} \ + void operator()() { m_pfnProxied(FUNC_CALL_MEMBER_ARGS_##N); } \ + \ + private: \ + FUNC_TYPE m_pfnProxied; \ + FUNC_ARG_MEMBERS_##N; \ + } + +FUNC_GENERATE_ALL( DEFINE_FUNCTOR_TEMPLATE ); + +#define DEFINE_MEMBER_FUNCTOR( N ) \ + template <class OBJECT_TYPE_PTR, typename FUNCTION_TYPE FUNC_TEMPLATE_ARG_PARAMS_##N, class FUNCTOR_BASE = CFunctorBase, class MEM_POLICY = CFuncMemPolicyNone> \ + class CMemberFunctor##N : public FUNCTOR_BASE \ + { \ + public: \ + CMemberFunctor##N( OBJECT_TYPE_PTR pObject, FUNCTION_TYPE pfnProxied FUNC_ARG_FORMAL_PARAMS_##N ) : m_Proxy( pObject, pfnProxied ) FUNC_CALL_ARGS_INIT_##N {} \ + void operator()() { m_Proxy(FUNC_CALL_MEMBER_ARGS_##N); } \ + \ + private: \ + CMemberFuncProxy##N<OBJECT_TYPE_PTR, FUNCTION_TYPE FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, MEM_POLICY> m_Proxy; \ + FUNC_ARG_MEMBERS_##N; \ + }; + + +FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR ); + +typedef CRefCounted1<CFunctorData, CRefCountServiceMT> CFunctorDataBase; +class CFunctorCallbackBase : public CRefCounted1<CFunctorCallback, CRefCountServiceMT> +{ +protected: + virtual void ValidateFunctorData( CFunctorData *pData ) + { +#ifdef _DEBUG + char pDataString[1024]; + char pCallbackString[1024]; + ComputeValidationString( pCallbackString, sizeof(pCallbackString) ); + pData->ComputeValidationString( pDataString, sizeof(pDataString) ); + bool bMatch = !V_stricmp( pDataString, pCallbackString ); + if ( !bMatch ) + { + Warning( "Functor doesn't match data!\n\tExpected:\t%s\n\tEncountered:\t%s\n", + pCallbackString, pDataString ); + Assert( 0 ); + } +#endif + } +}; + +#define DEFINE_FUNCTOR_DATA_TEMPLATE(N) \ + template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ + class CFunctorData##N : public CFunctorDataBase \ + { \ + public: \ + CFunctorData##N( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) FUNC_SOLO_CALL_ARGS_INIT_##N {} \ + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_##N } \ + FUNC_ARG_MEMBERS_##N; \ + } + +class CFunctorData0 : public CFunctorDataBase +{ +public: + CFunctorData0( ) {} + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_0 } +}; + +FUNC_GENERATE_ALL_BUT0( DEFINE_FUNCTOR_DATA_TEMPLATE ); + +#define DEFINE_FUNCTOR_CALLBACK_TEMPLATE(N) \ + template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ + class CFunctorCallback##N : public CFunctorCallbackBase \ + { \ + typedef void (*Callback_t)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ); \ + public: \ + CFunctorCallback##N( Callback_t pfnProxied ) : m_pfnProxied( pfnProxied ) {} \ + void operator()( CFunctorData *pFunctorDataBase ) \ + { \ + ValidateFunctorData( pFunctorDataBase ); \ + CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N > *pFunctorData = static_cast< CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >* >( pFunctorDataBase ); \ + m_pfnProxied( FUNC_CALL_DATA_ARGS_##N(pFunctorData) ); \ + } \ + virtual bool IsEqual( CFunctorCallback *pSrc ) const { return !V_stricmp( GetImplClassName(), pSrc->GetImplClassName() ) && ( m_pfnProxied == static_cast< CFunctorCallback##N * >( pSrc )->m_pfnProxied ); } \ + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_##N } \ + virtual const char *GetImplClassName() const { return "CFunctorCallback" #N; } \ + virtual const void *GetTarget() const { return m_pfnProxied; } \ + private: \ + Callback_t m_pfnProxied; \ + } + +class CFunctorCallback0 : public CFunctorCallbackBase +{ + typedef void (*Callback_t)( ); +public: + CFunctorCallback0( Callback_t pfnProxied ) : m_pfnProxied( pfnProxied ) {} + void operator()( CFunctorData *pFunctorDataBase ) + { + ValidateFunctorData( pFunctorDataBase ); + m_pfnProxied( ); + } + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_0 } + virtual bool IsEqual( CFunctorCallback *pSrc ) const + { + if ( V_stricmp( GetImplClassName(), pSrc->GetImplClassName() ) ) + return false; + return m_pfnProxied == static_cast< CFunctorCallback0* >( pSrc )->m_pfnProxied; + } + virtual const char *GetImplClassName() const { return "CFunctorCallback0"; } + virtual const void *GetTarget() const { return ( void * )m_pfnProxied; } +private: + Callback_t m_pfnProxied; +}; + +FUNC_GENERATE_ALL_BUT0( DEFINE_FUNCTOR_CALLBACK_TEMPLATE ); + +#define DEFINE_MEMBER_FUNCTOR_CALLBACK_TEMPLATE( N ) \ + template < class FUNCTION_CLASS FUNC_TEMPLATE_ARG_PARAMS_##N, class MEM_POLICY = CFuncMemPolicyNone > \ + class CMemberFunctorCallback##N : public CFunctorCallbackBase \ + { \ + typedef void (FUNCTION_CLASS::*MemberCallback_t)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ); \ + public: \ + CMemberFunctorCallback##N( FUNCTION_CLASS *pObject, MemberCallback_t pfnProxied ) : m_Proxy( pObject, pfnProxied ) {} \ + void operator()( CFunctorData *pFunctorDataBase ) \ + { \ + ValidateFunctorData( pFunctorDataBase ); \ + CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N > *pFunctorData = static_cast< CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >* >( pFunctorDataBase ); \ + m_Proxy( FUNC_CALL_DATA_ARGS_##N( pFunctorData ) ); \ + } \ + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_##N } \ + virtual bool IsEqual( CFunctorCallback *pSrc ) const { return !V_stricmp( GetImplClassName(), pSrc->GetImplClassName() ) && ( m_Proxy == static_cast< CMemberFunctorCallback##N* >( pSrc )->m_Proxy ); } \ + virtual const char *GetImplClassName() const { return "CMemberFunctorCallback" #N; } \ + virtual const void *GetTarget() const { return m_Proxy.GetTarget(); } \ + private: \ + CMemberFuncProxy##N< FUNCTION_CLASS *, MemberCallback_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, MEM_POLICY> m_Proxy; \ + } + +template < class FUNCTION_CLASS, class MEM_POLICY = CFuncMemPolicyNone > +class CMemberFunctorCallback0 : public CFunctorCallbackBase +{ + typedef void (FUNCTION_CLASS::*MemberCallback_t)( ); +public: + CMemberFunctorCallback0( FUNCTION_CLASS *pObject, MemberCallback_t pfnProxied ) : m_Proxy( pObject, pfnProxied ) {} + void operator()( CFunctorData *pFunctorDataBase ) + { + ValidateFunctorData( pFunctorDataBase ); + m_Proxy( ); + } + virtual void ComputeValidationString( char *pString, size_t nBufLen ) const { FUNC_VALIDATION_STRING_0 } + virtual bool IsEqual( CFunctorCallback *pSrc ) const + { + if ( V_stricmp( GetImplClassName(), pSrc->GetImplClassName() ) ) + return false; + return m_Proxy == static_cast< CMemberFunctorCallback0 * >( pSrc )->m_Proxy; + } + virtual const char *GetImplClassName() const { return "CMemberFunctorCallback0"; } + virtual const void *GetTarget() const { return m_Proxy.GetTarget(); } +private: + CMemberFuncProxy0< FUNCTION_CLASS *, MemberCallback_t, MEM_POLICY > m_Proxy; +}; + +FUNC_GENERATE_ALL_BUT0( DEFINE_MEMBER_FUNCTOR_CALLBACK_TEMPLATE ); + + +//----------------------------------------------------------------------------- +// +// The real magic, letting the compiler figure out all the right template parameters +// +//----------------------------------------------------------------------------- + +#define DEFINE_NONMEMBER_FUNCTOR_FACTORY(N) \ + template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline CFunctor *CreateFunctor(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \ + return new CFunctor##N<Func_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N>( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } + +FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY ); + +//------------------------------------- + +#define DEFINE_MEMBER_FUNCTOR_FACTORY(N) \ + template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY ); + +//------------------------------------- + +#define DEFINE_CONST_MEMBER_FUNCTOR_FACTORY(N) \ + template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY ); + +//------------------------------------- + +#define DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY(N) \ + template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline CFunctor *CreateRefCountingFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY ); + +//------------------------------------- + +#define DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY(N) \ + template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline CFunctor *CreateRefCountingFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + +FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY ); + +#define DEFINE_FUNCTOR_DATA_FACTORY(N) \ + template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ + inline CFunctorData *CreateFunctorData( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new CFunctorData##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >( FUNC_CALL_ARGS_##N ); \ + } + +inline CFunctorData *CreateFunctorData() +{ + return new CFunctorData0(); +} + +FUNC_GENERATE_ALL_BUT0( DEFINE_FUNCTOR_DATA_FACTORY ); + +#define DEFINE_FUNCTOR_CALLBACK_FACTORY(N) \ + template < FUNC_SOLO_TEMPLATE_ARG_PARAMS_##N > \ + inline CFunctorCallback *CreateFunctorCallback( void (*pfnProxied)( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \ + { \ + return new CFunctorCallback##N< FUNC_SOLO_BASE_TEMPLATE_ARG_PARAMS_##N >( pfnProxied ); \ + } + +inline CFunctorCallback *CreateFunctorCallback( void (*pfnProxied)() ) +{ + return new CFunctorCallback0( pfnProxied ); +} + +FUNC_GENERATE_ALL_BUT0( DEFINE_FUNCTOR_CALLBACK_FACTORY ); + +#define DEFINE_MEMBER_FUNCTOR_CALLBACK_FACTORY(N) \ + template < typename FUNCTION_CLASS FUNC_TEMPLATE_ARG_PARAMS_##N > \ + inline CFunctorCallback *CreateFunctorCallback( FUNCTION_CLASS *pObject, void ( FUNCTION_CLASS::*pfnProxied )( FUNC_PROXY_ARG_FORMAL_PARAMS_##N ) ) \ + { \ + return new CMemberFunctorCallback##N< FUNCTION_CLASS FUNC_BASE_TEMPLATE_ARG_PARAMS_##N >( pObject, pfnProxied ); \ + } + +FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_CALLBACK_FACTORY ); + + +//----------------------------------------------------------------------------- +// +// Templates to assist early-out direct call code +// +//----------------------------------------------------------------------------- + +#define DEFINE_NONMEMBER_FUNCTOR_DIRECT(N) \ + template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline void FunctorDirectCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ +{ \ + (*pfnProxied)( FUNC_CALL_ARGS_##N ); \ +} + +FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_DIRECT ); + + +//------------------------------------- + +#define DEFINE_MEMBER_FUNCTOR_DIRECT(N) \ + template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline void FunctorDirectCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ +{ \ + ((*pObject).*pfnProxied)(FUNC_CALL_ARGS_##N); \ +} + +FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_DIRECT ); + +//------------------------------------- + +#define DEFINE_CONST_MEMBER_FUNCTOR_DIRECT(N) \ + template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline void FunctorDirectCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ +{ \ + ((*pObject).*pfnProxied)(FUNC_CALL_ARGS_##N); \ +} + +FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_DIRECT ); + +#include "tier0/memdbgoff.h" + +//----------------------------------------------------------------------------- +// Factory class useable as templated traits +//----------------------------------------------------------------------------- + +class CDefaultFunctorFactory +{ +public: + FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY ); + FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY ); + FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY ); + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY ); + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY ); +}; + +template <class CAllocator, class CCustomFunctorBase = CFunctorBase> +class CCustomizedFunctorFactory +{ +public: + void SetAllocator( CAllocator *pAllocator ) + { + m_pAllocator = pAllocator; + } + + #define DEFINE_NONMEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline CFunctor *CreateFunctor( FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + typedef FUNCTION_RETTYPE (*Func_t)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N); \ + return new (m_pAllocator->Alloc( sizeof(CFunctor##N<Func_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>) )) CFunctor##N<Func_t FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \ + } + + FUNC_GENERATE_ALL( DEFINE_NONMEMBER_FUNCTOR_FACTORY_CUSTOM ); + + //------------------------------------- + + #define DEFINE_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline CFunctor *CreateFunctor(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL( DEFINE_MEMBER_FUNCTOR_FACTORY_CUSTOM ); + + //------------------------------------- + + #define DEFINE_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline CFunctor *CreateFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase>(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM ); + + //------------------------------------- + + #define DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline CFunctor *CreateRefCountingFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_FUNCTOR_FACTORY_CUSTOM ); + + //------------------------------------- + + #define DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM(N) \ + template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \ + inline CFunctor *CreateRefCountingFunctor( OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \ + { \ + return new (m_pAllocator->Alloc( sizeof(CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >) )) CMemberFunctor##N<OBJECT_TYPE_PTR, FUNCTION_RETTYPE (FUNCTION_CLASS::*)(FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N) const FUNC_BASE_TEMPLATE_ARG_PARAMS_##N, CCustomFunctorBase, CFuncMemPolicyRefCount<OBJECT_TYPE_PTR> >(pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N); \ + } + + FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_FUNCTOR_FACTORY_CUSTOM ); + +private: + CAllocator *m_pAllocator; + +}; + +//----------------------------------------------------------------------------- + +#endif // FUNCTORS_H diff --git a/external/vpc/public/tier1/generichash.h b/external/vpc/public/tier1/generichash.h new file mode 100644 index 0000000..44733d6 --- /dev/null +++ b/external/vpc/public/tier1/generichash.h @@ -0,0 +1,116 @@ +//======= Copyright � 2005, , Valve Corporation, All rights reserved. ========= +// +// Purpose: Variant Pearson Hash general purpose hashing algorithm described +// by Cargill in C++ Report 1994. Generates a 16-bit result. +// +//============================================================================= + +#ifndef GENERICHASH_H +#define GENERICHASH_H + +#if defined(_WIN32) +#pragma once +#endif + +//----------------------------------------------------------------------------- + +unsigned FASTCALL HashString( const char *pszKey ); +unsigned FASTCALL HashStringCaseless( const char *pszKey ); +unsigned FASTCALL HashStringCaselessConventional( const char *pszKey ); +unsigned FASTCALL Hash4( const void *pKey ); +unsigned FASTCALL Hash8( const void *pKey ); +unsigned FASTCALL Hash12( const void *pKey ); +unsigned FASTCALL Hash16( const void *pKey ); +unsigned FASTCALL HashBlock( const void *pKey, unsigned size ); + +unsigned FASTCALL HashInt( const int key ); + +// hash a uint32 into a uint32 +FORCEINLINE uint32 HashIntAlternate( uint32 n) +{ + n = ( n + 0x7ed55d16 ) + ( n << 12 ); + n = ( n ^ 0xc761c23c ) ^ ( n >> 19 ); + n = ( n + 0x165667b1 ) + ( n << 5 ); + n = ( n + 0xd3a2646c ) ^ ( n << 9 ); + n = ( n + 0xfd7046c5 ) + ( n << 3 ); + n = ( n ^ 0xb55a4f09 ) ^ ( n >> 16 ); + return n; +} + +inline unsigned HashIntConventional( const int n ) // faster but less effective +{ + // first byte + unsigned hash = 0xAAAAAAAA + (n & 0xFF); + // second byte + hash = ( hash << 5 ) + hash + ( (n >> 8) & 0xFF ); + // third byte + hash = ( hash << 5 ) + hash + ( (n >> 16) & 0xFF ); + // fourth byte + hash = ( hash << 5 ) + hash + ( (n >> 24) & 0xFF ); + + return hash; + + /* this is the old version, which would cause a load-hit-store on every + line on a PowerPC, and therefore took hundreds of clocks to execute! + + byte *p = (byte *)&n; + unsigned hash = 0xAAAAAAAA + *p++; + hash = ( ( hash << 5 ) + hash ) + *p++; + hash = ( ( hash << 5 ) + hash ) + *p++; + return ( ( hash << 5 ) + hash ) + *p; + */ +} + +//----------------------------------------------------------------------------- + +template <typename T> +inline unsigned HashItem( const T &item ) +{ + // TODO: Confirm comiler optimizes out unused paths + if ( sizeof(item) == 4 ) + return Hash4( &item ); + else if ( sizeof(item) == 8 ) + return Hash8( &item ); + else if ( sizeof(item) == 12 ) + return Hash12( &item ); + else if ( sizeof(item) == 16 ) + return Hash16( &item ); + else + return HashBlock( &item, sizeof(item) ); +} + +template <> inline unsigned HashItem<int>(const int &key ) +{ + return HashInt( key ); +} + +template <> inline unsigned HashItem<unsigned>(const unsigned &key ) +{ + return HashInt( (int)key ); +} + +template<> inline unsigned HashItem<const char *>(const char * const &pszKey ) +{ + return HashString( pszKey ); +} + +template<> inline unsigned HashItem<char *>(char * const &pszKey ) +{ + return HashString( pszKey ); +} + +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Murmur hash +//----------------------------------------------------------------------------- +uint32 MurmurHash2( const void * key, int len, uint32 seed ); + +// return murmurhash2 of a downcased string +uint32 MurmurHash2LowerCase( char const *pString, uint32 nSeed ); + +uint64 MurmurHash64( const void * key, int len, uint32 seed ); + + +#endif /* !GENERICHASH_H */ diff --git a/external/vpc/public/tier1/iconvar.h b/external/vpc/public/tier1/iconvar.h new file mode 100644 index 0000000..397c111 --- /dev/null +++ b/external/vpc/public/tier1/iconvar.h @@ -0,0 +1,121 @@ +//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $NoKeywords: $ +//===========================================================================// + +#ifndef ICONVAR_H +#define ICONVAR_H + +#if _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "tier0/platform.h" +#include "tier1/strtools.h" +#include "color.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IConVar; +class CCommand; + + +//----------------------------------------------------------------------------- +// ConVar flags +//----------------------------------------------------------------------------- +// The default, no flags at all +#define FCVAR_NONE 0 + +// Command to ConVars and ConCommands +// ConVar Systems +#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc. +#define FCVAR_DEVELOPMENTONLY (1<<1) // Hidden in released products. Flag is removed automatically if ALLOW_DEVELOPMENT_CVARS is defined. +#define FCVAR_GAMEDLL (1<<2) // defined by the game DLL +#define FCVAR_CLIENTDLL (1<<3) // defined by the client DLL +#define FCVAR_HIDDEN (1<<4) // Hidden. Doesn't appear in find or auto complete. Like DEVELOPMENTONLY, but can't be compiled out. + +// ConVar only +#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value +#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. +#define FCVAR_ARCHIVE (1<<7) // set to cause it to be saved to vars.rc +#define FCVAR_NOTIFY (1<<8) // notifies players when changed +#define FCVAR_USERINFO (1<<9) // changes the client's info string + +#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). +#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log +#define FCVAR_NEVER_AS_STRING (1<<12) // never try to print that cvar + +// It's a ConVar that's shared between the client and the server. +// At signon, the values of all such ConVars are sent from the server to the client (skipped for local +// client, of course ) +// If a change is requested it must come from the console (i.e., no remote client changes) +// If a value is changed while a server is active, it's replicated to all connected clients +#define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time +#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats +#define FCVAR_SS (1<<15) // causes varnameN where N == 2 through max splitscreen slots for mod to be autogenerated +#define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file +#define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles +#define FCVAR_SS_ADDED (1<<18) // This is one of the "added" FCVAR_SS variables for the splitscreen players +#define FCVAR_RELEASE (1<<19) // Cvars tagged with this are the only cvars avaliable to customers +#define FCVAR_RELOAD_MATERIALS (1<<20) // If this cvar changes, it forces a material reload +#define FCVAR_RELOAD_TEXTURES (1<<21) // If this cvar changes, if forces a texture reload + +#define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server +#define FCVAR_MATERIAL_SYSTEM_THREAD (1<<23) // Indicates this cvar is read from the material system thread +#define FCVAR_ARCHIVE_GAMECONSOLE (1<<24) // cvar written to config.cfg on the Xbox + +#define FCVAR_SERVER_CAN_EXECUTE (1<<28)// the server is allowed to execute this command on clients via ClientCommand/NET_StringCmd/CBaseClientState::ProcessStringCmd. +#define FCVAR_SERVER_CANNOT_QUERY (1<<29)// If this is set, then the server is not allowed to query this cvar's value (via IServerPluginHelpers::StartQueryCvarValue). +#define FCVAR_CLIENTCMD_CAN_EXECUTE (1<<30) // IVEngineClient::ClientCmd is allowed to execute this command. + // Note: IVEngineClient::ClientCmd_Unrestricted can run any client command. + +#define FCVAR_ACCESSIBLE_FROM_THREADS (1<<25) // used as a debugging tool necessary to check material system thread convars +// #define FCVAR_AVAILABLE (1<<26) +// #define FCVAR_AVAILABLE (1<<27) +// #define FCVAR_AVAILABLE (1<<31) + +#define FCVAR_MATERIAL_THREAD_MASK ( FCVAR_RELOAD_MATERIALS | FCVAR_RELOAD_TEXTURES | FCVAR_MATERIAL_SYSTEM_THREAD ) + +//----------------------------------------------------------------------------- +// Called when a ConVar changes value +// NOTE: For FCVAR_NEVER_AS_STRING ConVars, pOldValue == NULL +//----------------------------------------------------------------------------- +typedef void ( *FnChangeCallback_t )( IConVar *var, const char *pOldValue, float flOldValue ); + + +//----------------------------------------------------------------------------- +// Abstract interface for ConVars +//----------------------------------------------------------------------------- +abstract_class IConVar +{ +public: + // Value set + virtual void SetValue( const char *pValue ) = 0; + virtual void SetValue( float flValue ) = 0; + virtual void SetValue( int nValue ) = 0; + virtual void SetValue( Color value ) = 0; + + // Return name of command + virtual const char *GetName( void ) const = 0; + + // Return name of command (usually == GetName(), except in case of FCVAR_SS_ADDED vars + virtual const char *GetBaseName( void ) const = 0; + + // Accessors.. not as efficient as using GetState()/GetInfo() + // if you call these methods multiple times on the same IConVar + virtual bool IsFlagSet( int nFlag ) const = 0; + + virtual int GetSplitScreenPlayerSlot() const = 0; +}; + + +#endif // ICONVAR_H diff --git a/external/vpc/public/tier1/interface.h b/external/vpc/public/tier1/interface.h new file mode 100644 index 0000000..90b0f11 --- /dev/null +++ b/external/vpc/public/tier1/interface.h @@ -0,0 +1,226 @@ +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +// This header defines the interface convention used in the valve engine. +// To make an interface and expose it: +// 1. The interface must be ALL pure virtuals, and have no data members. +// 2. Define a name for it. +// 3. In its implementation file, use EXPOSE_INTERFACE or EXPOSE_SINGLE_INTERFACE. + +// Versioning +// There are two versioning cases that are handled by this: +// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case, +// you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface. +// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface +// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and +// expose it for the old interface. + +// Static Linking: +// Must mimic unique seperate class 'InterfaceReg' constructors per subsystem. +// Each subsystem can then import and export interfaces as expected. +// This is achieved through unique namespacing 'InterfaceReg' via symbol _SUBSYSTEM. +// Static Linking also needs to generate unique symbols per interface so as to +// provide a 'stitching' method whereby these interface symbols can be referenced +// via the lib's primary module (usually the lib's interface exposure) +// therby stitching all of that lib's code/data together for eventual final exe link inclusion. + +#ifndef INTERFACE_H +#define INTERFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +// TODO: move interface.cpp into tier0 library. +// Need to include platform.h in case _PS3 and other tokens are not yet defined +#include "tier0/platform.h" + +#if defined( POSIX ) && !defined( _PS3 ) + +#include <dlfcn.h> // dlopen,dlclose, et al +#include <unistd.h> + +#define GetProcAddress dlsym + +#ifdef _snprintf +#undef _snprintf +#endif +#define _snprintf snprintf +#endif // POSIX && !_PS3 + +// All interfaces derive from this. +class IBaseInterface +{ +public: + virtual ~IBaseInterface() {} +}; + +#if !defined( _X360 ) +#define CREATEINTERFACE_PROCNAME "CreateInterface" +#else +// x360 only allows ordinal exports, .def files export "CreateInterface" at 1 +#define CREATEINTERFACE_PROCNAME ((const char*)1) +#endif + +typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); +typedef void* (*InstantiateInterfaceFn)(); + +// Used internally to register classes. +class InterfaceReg +{ +public: + InterfaceReg(InstantiateInterfaceFn fn, const char *pName); + +public: + InstantiateInterfaceFn m_CreateFn; + const char *m_pName; + + InterfaceReg *m_pNext; // For the global list. +}; + +// Use this to expose an interface that can have multiple instances. +// e.g.: +// EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" ) +// This will expose a class called CInterfaceImp that implements IInterface (a pure class) +// clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" ) +// +// In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001") +// so that each component can use these names/vtables to communicate +// +// A single class can support multiple interfaces through multiple inheritance +// +// Use this if you want to write the factory function. +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); +#else +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static InterfaceReg __g_Create##interfaceName##_reg(functionName, versionName); \ + } +#endif + +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + static void* __Create##className##_interface() {return static_cast<interfaceName *>( new className );} \ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); +#else +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static void* __Create##className##_interface() {return static_cast<interfaceName *>( new className );} \ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); \ + } +#endif + +// Use this to expose a singleton interface with a global variable you've created. +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ + static void* __Create##className##interfaceName##_interface() {return static_cast<interfaceName *>( &globalVarName );} \ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); +#else +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ + namespace _SUBSYSTEM \ + { \ + static void* __Create##className##interfaceName##_interface() {return static_cast<interfaceName *>( &globalVarName );} \ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); \ + } +#endif + +// Use this to expose a singleton interface. This creates the global variable for you automatically. +#if !defined(_STATIC_LINKED) || !defined(_SUBSYSTEM) +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + static className __g_##className##_singleton; \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) +#else +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + namespace _SUBSYSTEM \ + { \ + static className __g_##className##_singleton; \ + } \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) +#endif + +// load/unload components +class CSysModule; + +// interface return status +enum +{ + IFACE_OK = 0, + IFACE_FAILED +}; + +//----------------------------------------------------------------------------- +// This function is automatically exported and allows you to access any interfaces exposed with the above macros. +// if pReturnCode is set, it will return one of the following values (IFACE_OK, IFACE_FAILED) +// extend this for other error conditions/code +//----------------------------------------------------------------------------- +DLL_EXPORT void* CreateInterface(const char *pName, int *pReturnCode); + +#if defined( _X360 ) +DLL_EXPORT void *CreateInterfaceThunk( const char *pName, int *pReturnCode ); +#endif + +//----------------------------------------------------------------------------- +// UNDONE: This is obsolete, use the module load/unload/get instead!!! +//----------------------------------------------------------------------------- +extern CreateInterfaceFn Sys_GetFactory( CSysModule *pModule ); +extern CreateInterfaceFn Sys_GetFactory( const char *pModuleName ); +extern CreateInterfaceFn Sys_GetFactoryThis( void ); + +//----------------------------------------------------------------------------- +// Load & Unload should be called in exactly one place for each module +// The factory for that module should be passed on to dependent components for +// proper versioning. +//----------------------------------------------------------------------------- +extern CSysModule *Sys_LoadModule( const char *pModuleName ); +extern void Sys_UnloadModule( CSysModule *pModule ); + +// Determines if current process is running with any debug modules +extern bool Sys_RunningWithDebugModules(); + +// This is a helper function to load a module, get its factory, and get a specific interface. +// You are expected to free all of these things. +// Returns false and cleans up if any of the steps fail. +bool Sys_LoadInterface( + const char *pModuleName, + const char *pInterfaceVersionName, + CSysModule **pOutModule, + void **pOutInterface ); + +bool Sys_IsDebuggerPresent(); + +//----------------------------------------------------------------------------- +// Purpose: Place this as a singleton at module scope (e.g.) and use it to get the factory from the specified module name. +// +// When the singleton goes out of scope (.dll unload if at module scope), +// then it'll call Sys_UnloadModule on the module so that the refcount is decremented +// and the .dll actually can unload from memory. +//----------------------------------------------------------------------------- +class CDllDemandLoader +{ +public: + CDllDemandLoader( char const *pchModuleName ); + virtual ~CDllDemandLoader(); + CreateInterfaceFn GetFactory(); + void Unload(); + +private: + + char const *m_pchModuleName; + CSysModule *m_hModule; + bool m_bLoadAttempted; +}; + + +#endif + + + diff --git a/external/vpc/public/tier1/keyvalues.h b/external/vpc/public/tier1/keyvalues.h new file mode 100644 index 0000000..a419dec --- /dev/null +++ b/external/vpc/public/tier1/keyvalues.h @@ -0,0 +1,519 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef KEYVALUES_H +#define KEYVALUES_H + +#ifdef _WIN32 +#pragma once +#endif + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#include "utlvector.h" +#include "color.h" +#include "exprevaluator.h" + + +#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() ) + +#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() ) + +#define FOR_EACH_VALUE( kvRoot, kvValue ) \ + for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() ) + + +class IBaseFileSystem; +class CUtlBuffer; +class Color; +class KeyValues; +class IKeyValuesDumpContext; +typedef void * FileHandle_t; +class CKeyValuesGrowableStringTable; + + +// single byte identifies a xbox kv file in binary format +// strings are pooled from a searchpath/zip mounted symbol table +#define KV_BINARY_POOLED_FORMAT 0xAA + + +#define FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() ) + +#define FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \ + for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() ) + +#define FOR_EACH_VALUE( kvRoot, kvValue ) \ + for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() ) + + +//----------------------------------------------------------------------------- +// Purpose: Simple recursive data access class +// Used in vgui for message parameters and resource files +// Destructor deletes all child KeyValues nodes +// Data is stored in key (string names) - (string/int/float)value pairs called nodes. +// +// About KeyValues Text File Format: + +// It has 3 control characters '{', '}' and '"'. Names and values may be quoted or +// not. The quote '"' character must not be used within name or values, only for +// quoting whole tokens. You may use escape sequences wile parsing and add within a +// quoted token a \" to add quotes within your name or token. When using Escape +// Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ), +// which it's off by default. Non-quoted tokens ends with a whitespace, '{', '}' and '"'. +// So you may use '{' and '}' within quoted tokens, but not for non-quoted tokens. +// An open bracket '{' after a key name indicates a list of subkeys which is finished +// with a closing bracket '}'. Subkeys use the same definitions recursively. +// Whitespaces are space, return, newline and tabulator. Allowed Escape sequences +// are \n, \t, \\, \n and \". The number character '#' is used for macro purposes +// (eg #include), don't use it as first character in key names. +//----------------------------------------------------------------------------- +class KeyValues +{ +public: + // By default, the KeyValues class uses a string table for the key names that is + // limited to 4MB. The game will exit in error if this space is exhausted. In + // general this is preferable for game code for performance and memory fragmentation + // reasons. + // + // If this is not acceptable, you can use this call to switch to a table that can grow + // arbitrarily. This call must be made before any KeyValues objects are allocated or it + // will result in undefined behavior. If you use the growable string table, you cannot + // share KeyValues pointers directly with any other module. You can serialize them across + // module boundaries. These limitations are acceptable in the Steam backend code + // this option was written for, but may not be in other situations. Make sure to + // understand the implications before using this. + static void SetUseGrowableStringTable( bool bUseGrowableTable ); + + explicit KeyValues( const char *setName ); + + // + // AutoDelete class to automatically free the keyvalues. + // Simply construct it with the keyvalues you allocated and it will free them when falls out of scope. + // When you decide that keyvalues shouldn't be deleted call Assign(NULL) on it. + // If you constructed AutoDelete(NULL) you can later assign the keyvalues to be deleted with Assign(pKeyValues). + // + class AutoDelete + { + public: + explicit inline AutoDelete( KeyValues *pKeyValues ) : m_pKeyValues( pKeyValues ) {} + explicit inline AutoDelete( const char *pchKVName ) : m_pKeyValues( new KeyValues( pchKVName ) ) {} + inline ~AutoDelete( void ) { if( m_pKeyValues ) m_pKeyValues->deleteThis(); } + inline void Assign( KeyValues *pKeyValues ) { m_pKeyValues = pKeyValues; } + KeyValues *operator->() { return m_pKeyValues; } + operator KeyValues *() { return m_pKeyValues; } + private: + AutoDelete( AutoDelete const &x ); // forbid + AutoDelete & operator= ( AutoDelete const &x ); // forbid + protected: + KeyValues *m_pKeyValues; + }; + + // + // AutoDeleteInline is useful when you want to hold your keyvalues object inside + // and delete it right after using. + // You can also pass temporary KeyValues object as an argument to a function by wrapping it into KeyValues::AutoDeleteInline + // instance: call_my_function( KeyValues::AutoDeleteInline( new KeyValues( "test" ) ) ) + // + class AutoDeleteInline : public AutoDelete + { + public: + explicit inline AutoDeleteInline( KeyValues *pKeyValues ) : AutoDelete( pKeyValues ) {} + inline operator KeyValues *() const { return m_pKeyValues; } + inline KeyValues * Get() const { return m_pKeyValues; } + }; + + // Quick setup constructors + KeyValues( const char *setName, const char *firstKey, const char *firstValue ); + KeyValues( const char *setName, const char *firstKey, const wchar_t *firstValue ); + KeyValues( const char *setName, const char *firstKey, int firstValue ); + KeyValues( const char *setName, const char *firstKey, const char *firstValue, const char *secondKey, const char *secondValue ); + KeyValues( const char *setName, const char *firstKey, int firstValue, const char *secondKey, int secondValue ); + + // Section name + const char *GetName() const; + void SetName( const char *setName); + + // gets the name as a unique int + int GetNameSymbol() const; + int GetNameSymbolCaseSensitive() const; + + // File access. Set UsesEscapeSequences true, if resource file/buffer uses Escape Sequences (eg \n, \t) + void UsesEscapeSequences(bool state); // default false + bool LoadFromFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL); + bool SaveToFile( IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL); + + // Read from a buffer... Note that the buffer must be null terminated + bool LoadFromBuffer( char const *resourceName, const char *pBuffer, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL ); + + // Read from a utlbuffer... + bool LoadFromBuffer( char const *resourceName, CUtlBuffer &buf, IBaseFileSystem* pFileSystem = NULL, const char *pPathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL ); + + // Find a keyValue, create it if it is not found. + // Set bCreate to true to create the key if it doesn't already exist (which ensures a valid pointer will be returned) + KeyValues *FindKey(const char *keyName, bool bCreate = false); + KeyValues *FindKey(int keySymbol) const; + KeyValues *CreateNewKey(); // creates a new key, with an autogenerated name. name is guaranteed to be an integer, of value 1 higher than the highest other integer key name + void AddSubKey( KeyValues *pSubkey ); // Adds a subkey. Make sure the subkey isn't a child of some other keyvalues + void RemoveSubKey(KeyValues *subKey); // removes a subkey from the list, DOES NOT DELETE IT + void InsertSubKey( int nIndex, KeyValues *pSubKey ); // Inserts the given sub-key before the Nth child location + bool ContainsSubKey( KeyValues *pSubKey ); // Returns true if this key values contains the specified sub key, false otherwise. + void SwapSubKey( KeyValues *pExistingSubKey, KeyValues *pNewSubKey ); // Swaps an existing subkey for a new one, DOES NOT DELETE THE OLD ONE but takes ownership of the new one + void ElideSubKey( KeyValues *pSubKey ); // Removes a subkey but inserts all of its children in its place, in-order (flattens a tree, like firing a manager!) + + // Key iteration. + // + // NOTE: GetFirstSubKey/GetNextKey will iterate keys AND values. Use the functions + // below if you want to iterate over just the keys or just the values. + // + KeyValues *GetFirstSubKey(); // returns the first subkey in the list + KeyValues *GetNextKey(); // returns the next subkey + void SetNextKey( KeyValues * pDat); + + // + // These functions can be used to treat it like a true key/values tree instead of + // confusing values with keys. + // + // So if you wanted to iterate all subkeys, then all values, it would look like this: + // for ( KeyValues *pKey = pRoot->GetFirstTrueSubKey(); pKey; pKey = pKey->GetNextTrueSubKey() ) + // { + // Msg( "Key name: %s\n", pKey->GetName() ); + // } + // for ( KeyValues *pValue = pRoot->GetFirstValue(); pKey; pKey = pKey->GetNextValue() ) + // { + // Msg( "Int value: %d\n", pValue->GetInt() ); // Assuming pValue->GetDataType() == TYPE_INT... + // } + KeyValues* GetFirstTrueSubKey(); + KeyValues* GetNextTrueSubKey(); + + KeyValues* GetFirstValue(); // When you get a value back, you can use GetX and pass in NULL to get the value. + KeyValues* GetNextValue(); + + + // Data access + int GetInt( const char *keyName = NULL, int defaultValue = 0 ); + uint64 GetUint64( const char *keyName = NULL, uint64 defaultValue = 0 ); + float GetFloat( const char *keyName = NULL, float defaultValue = 0.0f ); + const char *GetString( const char *keyName = NULL, const char *defaultValue = "" ); + const wchar_t *GetWString( const char *keyName = NULL, const wchar_t *defaultValue = L"" ); + void *GetPtr( const char *keyName = NULL, void *defaultValue = (void*)0 ); + Color GetColor( const char *keyName = NULL , const Color &defaultColor = Color( 0, 0, 0, 0 ) ); + bool GetBool( const char *keyName = NULL, bool defaultValue = false ) { return GetInt( keyName, defaultValue ? 1 : 0 ) ? true : false; } + bool IsEmpty(const char *keyName = NULL); + + // Data access + int GetInt( int keySymbol, int defaultValue = 0 ); + uint64 GetUint64( int keySymbol, uint64 defaultValue = 0 ); + float GetFloat( int keySymbol, float defaultValue = 0.0f ); + const char *GetString( int keySymbol, const char *defaultValue = "" ); + const wchar_t *GetWString( int keySymbol, const wchar_t *defaultValue = L"" ); + void *GetPtr( int keySymbol, void *defaultValue = (void*)0 ); + Color GetColor( int keySymbol /* default value is all black */); + bool GetBool( int keySymbol, bool defaultValue = false ) { return GetInt( keySymbol, defaultValue ? 1 : 0 ) ? true : false; } + bool IsEmpty( int keySymbol ); + + // Key writing + void SetWString( const char *keyName, const wchar_t *value ); + void SetString( const char *keyName, const char *value ); + void SetInt( const char *keyName, int value ); + void SetUint64( const char *keyName, uint64 value ); + void SetFloat( const char *keyName, float value ); + void SetPtr( const char *keyName, void *value ); + void SetColor( const char *keyName, Color value); + void SetBool( const char *keyName, bool value ) { SetInt( keyName, value ? 1 : 0 ); } + + // Memory allocation (optimized) + void *operator new( size_t iAllocSize ); + void *operator new( size_t iAllocSize, int nBlockUse, const char *pFileName, int nLine ); + void operator delete( void *pMem ); + void operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine ); + + KeyValues& operator=( KeyValues& src ); + + // Adds a chain... if we don't find stuff in this keyvalue, we'll look + // in the one we're chained to. + void ChainKeyValue( KeyValues* pChain ); + + void RecursiveSaveToFile( CUtlBuffer& buf, int indentLevel ); + + bool WriteAsBinary( CUtlBuffer &buffer ) const; + bool ReadAsBinary( CUtlBuffer &buffer ); + + // Allocate & create a new copy of the keys + KeyValues *MakeCopy( void ) const; + + // Make a new copy of all subkeys, add them all to the passed-in keyvalues + void CopySubkeys( KeyValues *pParent ) const; + + // Clear out all subkeys, and the current value + void Clear( void ); + + // Data type + enum types_t + { + TYPE_NONE = 0, + TYPE_STRING, + TYPE_INT, + TYPE_FLOAT, + TYPE_PTR, + TYPE_WSTRING, + TYPE_COLOR, + TYPE_UINT64, + TYPE_COMPILED_INT_BYTE, // hack to collapse 1 byte ints in the compiled format + TYPE_COMPILED_INT_0, // hack to collapse 0 in the compiled format + TYPE_COMPILED_INT_1, // hack to collapse 1 in the compiled format + TYPE_NUMTYPES, + }; + types_t GetDataType(const char *keyName = NULL); + + // Virtual deletion function - ensures that KeyValues object is deleted from correct heap + void deleteThis(); + + void SetStringValue( char const *strValue ); + + // unpack a key values list into a structure + void UnpackIntoStructure( struct KeyValuesUnpackStructure const *pUnpackTable, void *pDest ); + + // Process conditional keys for widescreen support. + bool ProcessResolutionKeys( const char *pResString ); + + // Dump keyvalues recursively into a dump context + bool Dump( IKeyValuesDumpContext *pDump, int nIndentLevel = 0 ); + + // Merge operations describing how two keyvalues can be combined + enum MergeKeyValuesOp_t + { + MERGE_KV_ALL, + MERGE_KV_UPDATE, // update values are copied into storage, adding new keys to storage or updating existing ones + MERGE_KV_DELETE, // update values specify keys that get deleted from storage + MERGE_KV_BORROW, // update values only update existing keys in storage, keys in update that do not exist in storage are discarded + }; + void MergeFrom( KeyValues *kvMerge, MergeKeyValuesOp_t eOp = MERGE_KV_ALL ); + + // Assign keyvalues from a string + static KeyValues * FromString( char const *szName, char const *szStringVal, char const **ppEndOfParse = NULL ); + +protected: + KeyValues( KeyValues& ); // prevent copy constructor being used + + // prevent delete being called except through deleteThis() + ~KeyValues(); + + KeyValues* CreateKey( const char *keyName ); + + void RecursiveCopyKeyValues( KeyValues& src ); + void RemoveEverything(); +// void RecursiveSaveToFile( IBaseFileSystem *filesystem, CUtlBuffer &buffer, int indentLevel ); +// void WriteConvertedString( CUtlBuffer &buffer, const char *pszString ); + + // NOTE: If both filesystem and pBuf are non-null, it'll save to both of them. + // If filesystem is null, it'll ignore f. + void RecursiveSaveToFile( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel ); + void WriteConvertedString( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const char *pszString ); + + void RecursiveLoadFromBuffer( char const *resourceName, CUtlBuffer &buf, GetSymbolProc_t pfnEvaluateSymbolProc ); + + // for handling #include "filename" + void AppendIncludedKeys( CUtlVector< KeyValues * >& includedKeys ); + void ParseIncludedKeys( char const *resourceName, const char *filetoinclude, + IBaseFileSystem* pFileSystem, const char *pPathID, CUtlVector< KeyValues * >& includedKeys, GetSymbolProc_t pfnEvaluateSymbolProc ); + + // For handling #base "filename" + void MergeBaseKeys( CUtlVector< KeyValues * >& baseKeys ); + void RecursiveMergeKeyValues( KeyValues *baseKV ); + + // NOTE: If both filesystem and pBuf are non-null, it'll save to both of them. + // If filesystem is null, it'll ignore f. + void InternalWrite( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, const void *pData, int len ); + + void Init(); + const char * ReadToken( CUtlBuffer &buf, bool &wasQuoted, bool &wasConditional ); + void WriteIndents( IBaseFileSystem *filesystem, FileHandle_t f, CUtlBuffer *pBuf, int indentLevel ); + + void FreeAllocatedValue(); + void AllocateValueBlock(int size); + + bool ReadAsBinaryPooledFormat( CUtlBuffer &buf, IBaseFileSystem *pFileSystem, unsigned int poolKey, GetSymbolProc_t pfnEvaluateSymbolProc ); + + bool EvaluateConditional( const char *pExpressionString, GetSymbolProc_t pfnEvaluateSymbolProc ); + + uint32 m_iKeyName : 24; // keyname is a symbol defined in KeyValuesSystem + uint32 m_iKeyNameCaseSensitive1 : 8; // 1st part of case sensitive symbol defined in KeyValueSystem + + // These are needed out of the union because the API returns string pointers + char *m_sValue; + wchar_t *m_wsValue; + + // we don't delete these + union + { + int m_iValue; + float m_flValue; + void *m_pValue; + unsigned char m_Color[4]; + }; + + char m_iDataType; + char m_bHasEscapeSequences; // true, if while parsing this KeyValue, Escape Sequences are used (default false) + uint16 m_iKeyNameCaseSensitive2; // 2nd part of case sensitive symbol defined in KeyValueSystem; + + KeyValues *m_pPeer; // pointer to next key in list + KeyValues *m_pSub; // pointer to Start of a new sub key list + KeyValues *m_pChain;// Search here if it's not in our list + + GetSymbolProc_t m_pExpressionGetSymbolProc; + +private: + // Statics to implement the optional growable string table + // Function pointers that will determine which mode we are in + static int (*s_pfGetSymbolForString)( const char *name, bool bCreate ); + static const char *(*s_pfGetStringForSymbol)( int symbol ); + static CKeyValuesGrowableStringTable *s_pGrowableStringTable; + +public: + // Functions that invoke the default behavior + static int GetSymbolForStringClassic( const char *name, bool bCreate = true ); + static const char *GetStringForSymbolClassic( int symbol ); + + // Functions that use the growable string table + static int GetSymbolForStringGrowable( const char *name, bool bCreate = true ); + static const char *GetStringForSymbolGrowable( int symbol ); +}; + +typedef KeyValues::AutoDelete KeyValuesAD; + +enum KeyValuesUnpackDestinationTypes_t +{ + UNPACK_TYPE_FLOAT, // dest is a float + UNPACK_TYPE_VECTOR, // dest is a Vector + UNPACK_TYPE_VECTOR_COLOR, // dest is a vector, src is a color + UNPACK_TYPE_STRING, // dest is a char *. unpacker will allocate. + UNPACK_TYPE_INT, // dest is an int + UNPACK_TYPE_FOUR_FLOATS, // dest is an array of 4 floats. source is a string like "1 2 3 4" + UNPACK_TYPE_TWO_FLOATS, // dest is an array of 2 floats. source is a string like "1 2" +}; + +#define UNPACK_FIXED( kname, kdefault, dtype, ofs ) { kname, kdefault, dtype, ofs, 0 } +#define UNPACK_VARIABLE( kname, kdefault, dtype, ofs, sz ) { kname, kdefault, dtype, ofs, sz } +#define UNPACK_END_MARKER { NULL, NULL, UNPACK_TYPE_FLOAT, 0 } + +struct KeyValuesUnpackStructure +{ + char const *m_pKeyName; // null to terminate tbl + char const *m_pKeyDefault; // null ok + KeyValuesUnpackDestinationTypes_t m_eDataType; // UNPACK_TYPE_INT, .. + size_t m_nFieldOffset; // use offsetof to set + size_t m_nFieldSize; // for strings or other variable length +}; + +//----------------------------------------------------------------------------- +// inline methods +//----------------------------------------------------------------------------- +inline int KeyValues::GetInt( int keySymbol, int defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetInt( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline uint64 KeyValues::GetUint64( int keySymbol, uint64 defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetUint64( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline float KeyValues::GetFloat( int keySymbol, float defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetFloat( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline const char *KeyValues::GetString( int keySymbol, const char *defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetString( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline const wchar_t *KeyValues::GetWString( int keySymbol, const wchar_t *defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetWString( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline void *KeyValues::GetPtr( int keySymbol, void *defaultValue ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetPtr( (const char *)NULL, defaultValue ) : defaultValue; +} + +inline Color KeyValues::GetColor( int keySymbol ) +{ + Color defaultValue( 0, 0, 0, 0 ); + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->GetColor( ) : defaultValue; +} + +inline bool KeyValues::IsEmpty( int keySymbol ) +{ + KeyValues *dat = FindKey( keySymbol ); + return dat ? dat->IsEmpty( ) : true; +} + + +// +// KeyValuesDumpContext and generic implementations +// + +class IKeyValuesDumpContext +{ +public: + virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ) = 0; + virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel ) = 0; + virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel ) = 0; +}; + +class IKeyValuesDumpContextAsText : public IKeyValuesDumpContext +{ +public: + virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ); + virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel ); + virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel ); + +public: + virtual bool KvWriteIndent( int nIndentLevel ); + virtual bool KvWriteText( char const *szText ) = 0; +}; + +class CKeyValuesDumpContextAsDevMsg : public IKeyValuesDumpContextAsText +{ +public: + // Overrides developer level to dump in DevMsg, zero to dump as Msg + CKeyValuesDumpContextAsDevMsg( int nDeveloperLevel = 1 ) : m_nDeveloperLevel( nDeveloperLevel ) {} + +public: + virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ); + virtual bool KvWriteText( char const *szText ); + +protected: + int m_nDeveloperLevel; +}; + +inline bool KeyValuesDumpAsDevMsg( KeyValues *pKeyValues, int nIndentLevel = 0, int nDeveloperLevel = 1 ) +{ + CKeyValuesDumpContextAsDevMsg ctx( nDeveloperLevel ); + return pKeyValues->Dump( &ctx, nIndentLevel ); +} + + +#endif // KEYVALUES_H diff --git a/external/vpc/public/tier1/mempool.h b/external/vpc/public/tier1/mempool.h new file mode 100644 index 0000000..67da207 --- /dev/null +++ b/external/vpc/public/tier1/mempool.h @@ -0,0 +1,649 @@ +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef MEMPOOL_H +#define MEMPOOL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/memalloc.h" +#include "tier0/tslist.h" +#include "tier0/platform.h" +#include "tier1/utlvector.h" +#include "tier1/utlrbtree.h" + +//----------------------------------------------------------------------------- +// Purpose: Optimized pool memory allocator +//----------------------------------------------------------------------------- + +typedef void (*MemoryPoolReportFunc_t)( char const* pMsg, ... ); + +class CUtlMemoryPool +{ +public: + // Ways the memory pool can grow when it needs to make a new blob. + enum MemoryPoolGrowType_t + { + GROW_NONE=0, // Don't allow new blobs. + GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates + // get larger and larger each time it allocates one). + GROW_SLOW=2 // New blob size is numElements. + }; + + CUtlMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 ); + ~CUtlMemoryPool(); + + void* Alloc(); // Allocate the element size you specified in the constructor. + void* Alloc( size_t amount ); + void* AllocZero(); // Allocate the element size you specified in the constructor, zero the memory before construction + void* AllocZero( size_t amount ); + void Free(void *pMem); + + // Frees everything + void Clear(); + + // Error reporting... + static void SetErrorReportFunc( MemoryPoolReportFunc_t func ); + + // returns number of allocated blocks + int Count() const { return m_BlocksAllocated; } + int PeakCount() const { return m_PeakAlloc; } + int BlockSize() const { return m_BlockSize; } + int Size() const { return m_NumBlobs * m_BlocksPerBlob * m_BlockSize; } + + bool IsAllocationWithinPool( void *pMem ) const; + +protected: + class CBlob + { + public: + CBlob *m_pPrev, *m_pNext; + int m_NumBytes; // Number of bytes in this blob. + char m_Data[1]; + char m_Padding[3]; // to int align the struct + }; + + // Resets the pool + void Init(); + void AddNewBlob(); + void ReportLeaks(); + + int m_BlockSize; + int m_BlocksPerBlob; + + int m_GrowMode; // GROW_ enum. + + // FIXME: Change m_ppMemBlob into a growable array? + void *m_pHeadOfFreeList; + int m_BlocksAllocated; + int m_PeakAlloc; + unsigned short m_nAlignment; + unsigned short m_NumBlobs; + const char * m_pszAllocOwner; + // CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned + CBlob m_BlobHead; + + static MemoryPoolReportFunc_t g_ReportFunc; +}; + + +//----------------------------------------------------------------------------- +// Multi-thread/Thread Safe Memory Class +//----------------------------------------------------------------------------- +class CMemoryPoolMT : public CUtlMemoryPool +{ +public: + CMemoryPoolMT( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment ) {} + + + void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); } + void* Alloc( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc( amount ); } + void* AllocZero() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero(); } + void* AllocZero( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero( amount ); } + void Free(void *pMem) { AUTO_LOCK( m_mutex ); CUtlMemoryPool::Free( pMem ); } + + // Frees everything + void Clear() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Clear(); } +private: + CThreadFastMutex m_mutex; // @TODO: Rework to use tslist (toml 7/6/2007) +}; + + +//----------------------------------------------------------------------------- +// Wrapper macro to make an allocator that returns particular typed allocations +// and construction and destruction of objects. +//----------------------------------------------------------------------------- +template< class T > +class CClassMemoryPool : public CUtlMemoryPool +{ +public: + CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) : + CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {} + + T* Alloc(); + T* AllocZero(); + void Free( T *pMem ); + + void Clear(); +}; + +//----------------------------------------------------------------------------- +// Specialized pool for aligned data management (e.g., Xbox textures) +//----------------------------------------------------------------------------- +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE = false, int COMPACT_THRESHOLD = 4 > +class CAlignedMemPool +{ + enum + { + BLOCK_SIZE = COMPILETIME_MAX( ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ), 8 ), + }; + +public: + CAlignedMemPool(); + + void *Alloc(); + void Free( void *p ); + + static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight ); + void Compact(); + + int NumTotal() { AUTO_LOCK( m_mutex ); return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); } + int NumAllocated() { AUTO_LOCK( m_mutex ); return NumTotal() - m_nFree; } + int NumFree() { AUTO_LOCK( m_mutex ); return m_nFree; } + + int BytesTotal() { AUTO_LOCK( m_mutex ); return NumTotal() * BLOCK_SIZE; } + int BytesAllocated() { AUTO_LOCK( m_mutex ); return NumAllocated() * BLOCK_SIZE; } + int BytesFree() { AUTO_LOCK( m_mutex ); return NumFree() * BLOCK_SIZE; } + + int ItemSize() { return ITEM_SIZE; } + int BlockSize() { return BLOCK_SIZE; } + int ChunkSize() { return CHUNK_SIZE; } + +private: + struct FreeBlock_t + { + FreeBlock_t *pNext; + byte reserved[ BLOCK_SIZE - sizeof( FreeBlock_t *) ]; + }; + + CUtlVector<void *> m_Chunks; // Chunks are tracked outside blocks (unlike CUtlMemoryPool) to simplify alignment issues + FreeBlock_t * m_pFirstFree; + int m_nFree; + CAllocator m_Allocator; + double m_TimeLastCompact; + + CThreadFastMutex m_mutex; +}; + +//----------------------------------------------------------------------------- +// Pool variant using standard allocation +//----------------------------------------------------------------------------- +template <typename T, int nInitialCount = 0, bool bDefCreateNewIfEmpty = true > +class CObjectPool +{ +public: + CObjectPool() + { + int i = nInitialCount; + while ( i-- > 0 ) + { + m_AvailableObjects.PushItem( new T ); + } + } + + ~CObjectPool() + { + Purge(); + } + + int NumAvailable() + { + return m_AvailableObjects.Count(); + } + + void Purge() + { + T *p = NULL; + while ( m_AvailableObjects.PopItem( &p ) ) + { + delete p; + } + } + + T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty ) + { + T *p = NULL; + if ( !m_AvailableObjects.PopItem( &p ) ) + { + p = ( bCreateNewIfEmpty ) ? new T : NULL; + } + return p; + } + + void PutObject( T *p ) + { + m_AvailableObjects.PushItem( p ); + } + +private: + CTSList<T *> m_AvailableObjects; +}; + +//----------------------------------------------------------------------------- +// Fixed budget pool with overflow to malloc +//----------------------------------------------------------------------------- +template <size_t PROVIDED_ITEM_SIZE, int ITEM_COUNT> +class CFixedBudgetMemoryPool +{ +public: + CFixedBudgetMemoryPool() + { + m_pBase = m_pLimit = 0; + COMPILE_TIME_ASSERT( ITEM_SIZE % 4 == 0 ); + } + + bool Owns( void *p ) + { + return ( p >= m_pBase && p < m_pLimit ); + } + + void *Alloc() + { + MEM_ALLOC_CREDIT_CLASS(); +#ifndef USE_MEM_DEBUG + if ( !m_pBase ) + { + LOCAL_THREAD_LOCK(); + if ( !m_pBase ) + { + byte *pMemory = m_pBase = (byte *)malloc( ITEM_COUNT * ITEM_SIZE ); + m_pLimit = m_pBase + ( ITEM_COUNT * ITEM_SIZE ); + + for ( int i = 0; i < ITEM_COUNT; i++ ) + { + m_freeList.Push( (TSLNodeBase_t *)pMemory ); + pMemory += ITEM_SIZE; + } + } + } + + void *p = m_freeList.Pop(); + if ( p ) + return p; +#endif + return malloc( ITEM_SIZE ); + } + + void Free( void *p ) + { +#ifndef USE_MEM_DEBUG + if ( Owns( p ) ) + m_freeList.Push( (TSLNodeBase_t *)p ); + else +#endif + free( p ); + } + + void Clear() + { +#ifndef USE_MEM_DEBUG + if ( m_pBase ) + { + free( m_pBase ); + } + m_pBase = m_pLimit = 0; + Construct( &m_freeList ); +#endif + } + + bool IsEmpty() + { +#ifndef USE_MEM_DEBUG + if ( m_pBase && m_freeList.Count() != ITEM_COUNT ) + return false; +#endif + return true; + } + + enum + { + ITEM_SIZE = ALIGN_VALUE( PROVIDED_ITEM_SIZE, TSLIST_NODE_ALIGNMENT ) + }; + + CTSListBase m_freeList; + byte *m_pBase; + byte *m_pLimit; +}; + +#define BIND_TO_FIXED_BUDGET_POOL( poolName ) \ + inline void* operator new( size_t size ) { return poolName.Alloc(); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { return poolName.Alloc(); } \ + inline void operator delete( void* p ) { poolName.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { poolName.Free(p); } + +//----------------------------------------------------------------------------- + + +template< class T > +inline T* CClassMemoryPool<T>::Alloc() +{ + T *pRet; + + { + MEM_ALLOC_CREDIT_CLASS(); + pRet = (T*)CUtlMemoryPool::Alloc(); + } + + if ( pRet ) + { + Construct( pRet ); + } + return pRet; +} + +template< class T > +inline T* CClassMemoryPool<T>::AllocZero() +{ + T *pRet; + + { + MEM_ALLOC_CREDIT_CLASS(); + pRet = (T*)CUtlMemoryPool::AllocZero(); + } + + if ( pRet ) + { + Construct( pRet ); + } + return pRet; +} + +template< class T > +inline void CClassMemoryPool<T>::Free(T *pMem) +{ + if ( pMem ) + { + Destruct( pMem ); + } + + CUtlMemoryPool::Free( pMem ); +} + +template< class T > +inline void CClassMemoryPool<T>::Clear() +{ + CUtlRBTree<void *> freeBlocks; + SetDefLessFunc( freeBlocks ); + + void *pCurFree = m_pHeadOfFreeList; + while ( pCurFree != NULL ) + { + freeBlocks.Insert( pCurFree ); + pCurFree = *((void**)pCurFree); + } + + for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) + { + T *p = (T *)pCur->m_Data; + T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes); + while ( p < pLimit ) + { + if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() ) + { + Destruct( p ); + } + p++; + } + } + + CUtlMemoryPool::Clear(); +} + + +//----------------------------------------------------------------------------- +// Macros that make it simple to make a class use a fixed-size allocator +// Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class, +// Put DEFINE_FIXEDSIZE_ALLOCATOR in the CPP file +//----------------------------------------------------------------------------- +#define DECLARE_FIXEDSIZE_ALLOCATOR( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void operator delete( void* p ) { s_Allocator.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \ + private: \ + static CUtlMemoryPool s_Allocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR( _class, _initsize, _grow ) \ + CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") + +#define DEFINE_FIXEDSIZE_ALLOCATOR_ALIGNED( _class, _initsize, _grow, _alignment ) \ + CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", _alignment ) + +#define DECLARE_FIXEDSIZE_ALLOCATOR_MT( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \ + inline void operator delete( void* p ) { s_Allocator.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \ + private: \ + static CMemoryPoolMT s_Allocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \ + CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") + +//----------------------------------------------------------------------------- +// Macros that make it simple to make a class use a fixed-size allocator +// This version allows us to use a memory pool which is externally defined... +// Put DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the private section of a class, +// Put DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL in the CPP file +//----------------------------------------------------------------------------- + +#define DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class ) \ + public: \ + inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \ + inline void operator delete( void* p ) { s_pAllocator->Free(p); } \ + private: \ + static CUtlMemoryPool* s_pAllocator + +#define DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class, _allocator ) \ + CUtlMemoryPool* _class::s_pAllocator = _allocator + + +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD > +inline CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::CAlignedMemPool() + : m_pFirstFree( 0 ), + m_nFree( 0 ), + m_TimeLastCompact( 0 ) +{ + COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE ); + COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) ); +} + +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD > +inline void *CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Alloc() +{ + AUTO_LOCK( m_mutex ); + + if ( !m_pFirstFree ) + { + if ( !GROWMODE && m_Chunks.Count() ) + { + return NULL; + } + + FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE ); + Assert( (unsigned)pNew % ALIGNMENT == 0 ); + m_Chunks.AddToTail( pNew ); + m_nFree = CHUNK_SIZE / BLOCK_SIZE; + m_pFirstFree = pNew; + for ( int i = 0; i < m_nFree - 1; i++ ) + { + pNew->pNext = pNew + 1; + pNew++; + } + pNew->pNext = NULL; + } + + void *p = m_pFirstFree; + m_pFirstFree = m_pFirstFree->pNext; + m_nFree--; + + return p; +} + +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD > +inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Free( void *p ) +{ + AUTO_LOCK( m_mutex ); + + // Insertion sort to encourage allocation clusters in chunks + FreeBlock_t *pFree = ((FreeBlock_t *)p); + FreeBlock_t *pCur = m_pFirstFree; + FreeBlock_t *pPrev = NULL; + + while ( pCur && pFree > pCur ) + { + pPrev = pCur; + pCur = pCur->pNext; + } + + pFree->pNext = pCur; + + if ( pPrev ) + { + pPrev->pNext = pFree; + } + else + { + m_pFirstFree = pFree; + } + m_nFree++; + + if ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD ) + { + double time = Plat_FloatTime(); + double compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0; + if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < time ) + { + Compact(); + m_TimeLastCompact = time; + } + } +} + +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD > +inline int __cdecl CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::CompareChunk( void * const *ppLeft, void * const *ppRight ) +{ + return ((unsigned)*ppLeft) - ((unsigned)*ppRight); +} + +template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD > +inline void CAlignedMemPool<ITEM_SIZE, ALIGNMENT, CHUNK_SIZE, CAllocator, GROWMODE, COMPACT_THRESHOLD>::Compact() +{ + FreeBlock_t *pCur = m_pFirstFree; + FreeBlock_t *pPrev = NULL; + + m_Chunks.Sort( CompareChunk ); + +#ifdef VALIDATE_ALIGNED_MEM_POOL + { + FreeBlock_t *p = m_pFirstFree; + while ( p ) + { + if ( p->pNext && p > p->pNext ) + { + __asm { int 3 } + } + p = p->pNext; + } + + for ( int i = 0; i < m_Chunks.Count(); i++ ) + { + if ( i + 1 < m_Chunks.Count() ) + { + if ( m_Chunks[i] > m_Chunks[i + 1] ) + { + __asm { int 3 } + } + } + } + } +#endif + + int i; + + for ( i = 0; i < m_Chunks.Count(); i++ ) + { + int nBlocksPerChunk = CHUNK_SIZE / BLOCK_SIZE; + FreeBlock_t *pChunkLimit = ((FreeBlock_t *)m_Chunks[i]) + nBlocksPerChunk; + int nFromChunk = 0; + if ( pCur == m_Chunks[i] ) + { + FreeBlock_t *pFirst = pCur; + while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit ) + { + pCur = pCur->pNext; + nFromChunk++; + } + pCur = pFirst; + + } + + while ( pCur && pCur >= m_Chunks[i] && pCur < pChunkLimit ) + { + if ( nFromChunk != nBlocksPerChunk ) + { + if ( pPrev ) + { + pPrev->pNext = pCur; + } + else + { + m_pFirstFree = pCur; + } + pPrev = pCur; + } + else if ( pPrev ) + { + pPrev->pNext = NULL; + } + else + { + m_pFirstFree = NULL; + } + + pCur = pCur->pNext; + } + + if ( nFromChunk == nBlocksPerChunk ) + { + m_Allocator.Free( m_Chunks[i] ); + m_nFree -= nBlocksPerChunk; + m_Chunks[i] = 0; + } + } + + for ( i = m_Chunks.Count() - 1; i >= 0 ; i-- ) + { + if ( !m_Chunks[i] ) + { + m_Chunks.FastRemove( i ); + } + } +} + +#endif // MEMPOOL_H diff --git a/external/vpc/public/tier1/memstack.h b/external/vpc/public/tier1/memstack.h new file mode 100644 index 0000000..f1846d2 --- /dev/null +++ b/external/vpc/public/tier1/memstack.h @@ -0,0 +1,348 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: A fast stack memory allocator that uses virtual memory if available +// +//===========================================================================// + +#ifndef MEMSTACK_H +#define MEMSTACK_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier1/utlvector.h" + +#if defined( _WIN32 ) || defined( _PS3 ) +#define MEMSTACK_VIRTUAL_MEMORY_AVAILABLE +#endif + +//----------------------------------------------------------------------------- + +typedef unsigned MemoryStackMark_t; + +class CMemoryStack +{ +public: + CMemoryStack(); + ~CMemoryStack(); + + bool Init( const char *pszAllocOwner, unsigned maxSize = 0, unsigned commitSize = 0, unsigned initialCommit = 0, unsigned alignment = 16 ); +#ifdef _GAMECONSOLE + bool InitPhysical( const char *pszAllocOwner, uint size, uint nBaseAddrAlignment, uint alignment = 16, uint32 nAdditionalFlags = 0 ); +#endif + void Term(); + + int GetSize(); + int GetMaxSize(); + int GetUsed(); + + void *Alloc( unsigned bytes, bool bClear = false ) RESTRICT; + + MemoryStackMark_t GetCurrentAllocPoint(); + void FreeToAllocPoint( MemoryStackMark_t mark, bool bDecommit = true ); + void FreeAll( bool bDecommit = true ); + + void Access( void **ppRegion, unsigned *pBytes ); + + void PrintContents(); + + void *GetBase(); + const void *GetBase() const { return const_cast<CMemoryStack *>(this)->GetBase(); } + + bool CommitSize( int ); + + void SetAllocOwner( const char *pszAllocOwner ); + +private: + bool CommitTo( byte * ) RESTRICT; + void RegisterAllocation(); + void RegisterDeallocation( bool bShouldSpew ); + + byte *m_pNextAlloc; + byte *m_pCommitLimit; + byte *m_pAllocLimit; + + byte *m_pBase; + bool m_bRegisteredAllocation; + bool m_bPhysical; + char *m_pszAllocOwner; + + unsigned m_maxSize; + unsigned m_alignment; +#ifdef MEMSTACK_VIRTUAL_MEMORY_AVAILABLE + unsigned m_commitSize; + unsigned m_minCommit; +#endif +#if defined( MEMSTACK_VIRTUAL_MEMORY_AVAILABLE ) && defined( _PS3 ) + IVirtualMemorySection *m_pVirtualMemorySection; +#endif +}; + +//------------------------------------- + +FORCEINLINE void *CMemoryStack::Alloc( unsigned bytes, bool bClear ) RESTRICT +{ + Assert( m_pBase ); + + bytes = MAX( bytes, m_alignment ); + bytes = AlignValue( bytes, m_alignment ); + + void *pResult = m_pNextAlloc; + byte *pNextAlloc = m_pNextAlloc + bytes; + + if ( pNextAlloc > m_pCommitLimit ) + { + if ( !CommitTo( pNextAlloc ) ) + { + return NULL; + } + } + + if ( bClear ) + { + memset( pResult, 0, bytes ); + } + + m_pNextAlloc = pNextAlloc; + + return pResult; +} + +//------------------------------------- + +inline bool CMemoryStack::CommitSize( int nBytes ) +{ + if ( GetSize() != nBytes ) + { + return CommitTo( m_pBase + nBytes ); + } + return true; +} + +//------------------------------------- + +inline int CMemoryStack::GetMaxSize() +{ + return m_maxSize; +} + +//------------------------------------- + +inline int CMemoryStack::GetUsed() +{ + return ( m_pNextAlloc - m_pBase ); +} + +//------------------------------------- + +inline void *CMemoryStack::GetBase() +{ + return m_pBase; +} + +//------------------------------------- + +inline MemoryStackMark_t CMemoryStack::GetCurrentAllocPoint() +{ + return ( m_pNextAlloc - m_pBase ); +} + + +//----------------------------------------------------------------------------- +// The CUtlMemoryStack class: +// A fixed memory class +//----------------------------------------------------------------------------- +template< typename T, typename I, size_t MAX_SIZE, size_t COMMIT_SIZE = 0, size_t INITIAL_COMMIT = 0 > +class CUtlMemoryStack +{ +public: + // constructor, destructor + CUtlMemoryStack( int nGrowSize = 0, int nInitSize = 0 ) { m_MemoryStack.Init( "CUtlMemoryStack", MAX_SIZE * sizeof(T), COMMIT_SIZE * sizeof(T), INITIAL_COMMIT * sizeof(T), 4 ); COMPILE_TIME_ASSERT( sizeof(T) % 4 == 0 ); } + CUtlMemoryStack( T* pMemory, int numElements ) { Assert( 0 ); } + + // Can we use this index? + bool IsIdxValid( I i ) const { long x=i; return (x >= 0) && (x < m_nAllocated); } + + // Specify the invalid ('null') index that we'll only return on failure + static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT + static I InvalidIndex() { return INVALID_INDEX; } + + class Iterator_t + { + Iterator_t( I i ) : index( i ) {} + I index; + friend class CUtlMemoryStack<T,I,MAX_SIZE, COMMIT_SIZE, INITIAL_COMMIT>; + public: + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t( m_nAllocated ? 0 : InvalidIndex() ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( it.index < m_nAllocated ? it.index + 1 : InvalidIndex() ); } + I GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { long x=it.index; return x >= 0 && x < m_nAllocated; } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } + + // Gets the base address + T* Base() { return (T*)m_MemoryStack.GetBase(); } + const T* Base() const { return (const T*)m_MemoryStack.GetBase(); } + + // element access + T& operator[]( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& operator[]( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + T& Element( I i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& Element( I i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + + // Attaches the buffer to external memory.... + void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); } + + // Size + int NumAllocated() const { return m_nAllocated; } + int Count() const { return m_nAllocated; } + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow( int num = 1 ) { Assert( num > 0 ); m_nAllocated += num; m_MemoryStack.Alloc( num * sizeof(T) ); } + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ) { Assert( num <= MAX_SIZE ); if ( m_nAllocated < num ) Grow( num - m_nAllocated ); } + + // Memory deallocation + void Purge() { m_MemoryStack.FreeAll(); m_nAllocated = 0; } + + // is the memory externally allocated? + bool IsExternallyAllocated() const { return false; } + + // Set the size by which the memory grows + void SetGrowSize( int size ) { Assert( 0 ); } + + // Identify the owner of this memory stack's memory + void SetAllocOwner( const char *pszAllocOwner ) { m_MemoryStack.SetAllocOwner( pszAllocOwner ); } + +private: + CMemoryStack m_MemoryStack; + int m_nAllocated; +}; + + +#ifdef _X360 +//----------------------------------------------------------------------------- +// A memory stack used for allocating physical memory on the 360 +// Usage pattern anticipates we usually never go over the initial allocation +// When we do so, we're ok with slightly slower allocation +//----------------------------------------------------------------------------- +class CPhysicalMemoryStack +{ +public: + CPhysicalMemoryStack(); + ~CPhysicalMemoryStack(); + + // The physical memory stack is allocated in chunks. We will initially + // allocate nInitChunkCount chunks, which will always be in memory. + // When FreeAll() is called, it will free down to the initial chunk count + // but not below it. + bool Init( size_t nChunkSizeInBytes, size_t nAlignment, int nInitialChunkCount, uint32 nAdditionalFlags ); + void Term(); + + size_t GetSize() const; + size_t GetPeakUsed() const; + size_t GetUsed() const; + size_t GetFramePeakUsed() const; + + MemoryStackMark_t GetCurrentAllocPoint() const; + void FreeToAllocPoint( MemoryStackMark_t mark, bool bUnused = true ); // bUnused is for interface compat with CMemoryStack + void *Alloc( size_t nSizeInBytes, bool bClear = false ) RESTRICT; + void FreeAll( bool bUnused = true ); // bUnused is for interface compat with CMemoryStack + + void PrintContents(); + +private: + void *AllocFromOverflow( size_t nSizeInBytes ); + + struct PhysicalChunk_t + { + uint8 *m_pBase; + uint8 *m_pNextAlloc; + uint8 *m_pAllocLimit; + }; + + PhysicalChunk_t m_InitialChunk; + CUtlVector< PhysicalChunk_t > m_ExtraChunks; + size_t m_nUsage; + size_t m_nFramePeakUsage; + size_t m_nPeakUsage; + size_t m_nAlignment; + size_t m_nChunkSizeInBytes; + int m_nFirstAvailableChunk; + int m_nAdditionalFlags; + PhysicalChunk_t *m_pLastAllocedChunk; +}; + +//------------------------------------- + +FORCEINLINE void *CPhysicalMemoryStack::Alloc( size_t nSizeInBytes, bool bClear ) RESTRICT +{ + if ( nSizeInBytes ) + { + nSizeInBytes = AlignValue( nSizeInBytes, m_nAlignment ); + } + else + { + nSizeInBytes = m_nAlignment; + } + + // Can't do an allocation bigger than the chunk size + Assert( nSizeInBytes <= m_nChunkSizeInBytes ); + + void *pResult = m_InitialChunk.m_pNextAlloc; + uint8 *pNextAlloc = m_InitialChunk.m_pNextAlloc + nSizeInBytes; + if ( pNextAlloc <= m_InitialChunk.m_pAllocLimit ) + { + m_InitialChunk.m_pNextAlloc = pNextAlloc; + m_pLastAllocedChunk = &m_InitialChunk; + } + else + { + pResult = AllocFromOverflow( nSizeInBytes ); + } + + m_nUsage += nSizeInBytes; + m_nFramePeakUsage = MAX( m_nUsage, m_nFramePeakUsage ); + m_nPeakUsage = MAX( m_nUsage, m_nPeakUsage ); + + if ( bClear ) + { + memset( pResult, 0, nSizeInBytes ); + } + + return pResult; +} + +//------------------------------------- + +inline size_t CPhysicalMemoryStack::GetPeakUsed() const +{ + return m_nPeakUsage; +} + +//------------------------------------- + +inline size_t CPhysicalMemoryStack::GetUsed() const +{ + return m_nUsage; +} + +inline size_t CPhysicalMemoryStack::GetFramePeakUsed() const +{ + return m_nFramePeakUsage; +} + +inline MemoryStackMark_t CPhysicalMemoryStack::GetCurrentAllocPoint() const +{ + Assert( m_pLastAllocedChunk ); + return ( m_pLastAllocedChunk->m_pNextAlloc - m_pLastAllocedChunk->m_pBase ); +} + +#endif // _X360 + +#endif // MEMSTACK_H diff --git a/external/vpc/public/tier1/netadr.h b/external/vpc/public/tier1/netadr.h new file mode 100644 index 0000000..c635a33 --- /dev/null +++ b/external/vpc/public/tier1/netadr.h @@ -0,0 +1,73 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// netadr.h +#ifndef NETADR_H +#define NETADR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#undef SetPort + +typedef enum +{ + NA_NULL = 0, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, +} netadrtype_t; + +struct netadr_t +{ +public: + netadr_t() { SetIP( 0 ); SetPort( 0 ); SetType( NA_IP ); } + netadr_t( uint unIP, uint16 usPort ) { SetIP( unIP ); SetPort( usPort ); SetType( NA_IP ); } + netadr_t( const char *pch ) { SetFromString( pch ); } + void Clear(); // invalids Address + + void SetType( netadrtype_t type ); + void SetPort( unsigned short port ); + bool SetFromSockadr(const struct sockaddr *s); + void SetIP(uint8 b1, uint8 b2, uint8 b3, uint8 b4); + void SetIP(uint unIP); // Sets IP. unIP is in host order (little-endian) + void SetIPAndPort( uint unIP, unsigned short usPort ) { SetIP( unIP ); SetPort( usPort ); } + void SetFromString(const char *pch, bool bUseDNS = false ); // if bUseDNS is true then do a DNS lookup if needed + + bool CompareAdr (const netadr_t &a, bool onlyBase = false) const; + bool CompareClassBAdr (const netadr_t &a) const; + bool CompareClassCAdr (const netadr_t &a) const; + + netadrtype_t GetType() const; + unsigned short GetPort() const; + const char* ToString( bool onlyBase = false ) const; // returns xxx.xxx.xxx.xxx:ppppp + void ToSockadr(struct sockaddr *s) const; + unsigned int GetIP() const; + + bool IsLocalhost() const; // true, if this is the localhost IP + bool IsLoopback() const; // true if engine loopback buffers are used + bool IsReservedAdr() const; // true, if this is a private LAN IP + bool IsValid() const; // ip & port != 0 + bool IsBaseAdrValid() const; // ip != 0 + + void SetFromSocket( int hSocket ); + + // These function names are decorated because the Xbox360 defines macros for ntohl and htonl + unsigned long addr_ntohl() const; + unsigned long addr_htonl() const; + bool operator==(const netadr_t &netadr) const {return ( CompareAdr( netadr ) );} + bool operator<(const netadr_t &netadr) const; + +public: // members are public to avoid to much changes + + netadrtype_t type; + unsigned char ip[4]; + unsigned short port; +}; + +#endif // NETADR_H diff --git a/external/vpc/public/tier1/refcount.h b/external/vpc/public/tier1/refcount.h new file mode 100644 index 0000000..58bcf65 --- /dev/null +++ b/external/vpc/public/tier1/refcount.h @@ -0,0 +1,384 @@ +//========== Copyright � 2005, Valve Corporation, All rights reserved. ======== +// +// Purpose: Tools for correctly implementing & handling reference counted +// objects +// +//============================================================================= + +#ifndef REFCOUNT_H +#define REFCOUNT_H + +#include "tier0/threadtools.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Implement a standard reference counted interface. Use of this +// is optional insofar as all the concrete tools only require +// at compile time that the function signatures match. +//----------------------------------------------------------------------------- + +class IRefCounted +{ +public: + virtual int AddRef() = 0; + virtual int Release() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Release a pointer and mark it NULL +//----------------------------------------------------------------------------- + +template <class REFCOUNTED_ITEM_PTR> +inline int SafeRelease( REFCOUNTED_ITEM_PTR &pRef ) +{ + // Use funny syntax so that this works on "auto pointers" + REFCOUNTED_ITEM_PTR *ppRef = &pRef; + if ( *ppRef ) + { + int result = (*ppRef)->Release(); + *ppRef = NULL; + return result; + } + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Maintain a reference across a scope +//----------------------------------------------------------------------------- + +template <class T = IRefCounted> +class CAutoRef +{ +public: + CAutoRef( T *pRef ) + : m_pRef( pRef ) + { + if ( m_pRef ) + m_pRef->AddRef(); + } + + ~CAutoRef() + { + if (m_pRef) + m_pRef->Release(); + } + +private: + T *m_pRef; +}; + +//----------------------------------------------------------------------------- +// Purpose: Do a an inline AddRef then return the pointer, useful when +// returning an object from a function +//----------------------------------------------------------------------------- + +#define RetAddRef( p ) ( (p)->AddRef(), (p) ) +#define InlineAddRef( p ) ( (p)->AddRef(), (p) ) + + +//----------------------------------------------------------------------------- +// Purpose: A class to both hold a pointer to an object and its reference. +// Base exists to support other cleanup models +//----------------------------------------------------------------------------- + +template <class T> +class CBaseAutoPtr +{ +public: + CBaseAutoPtr() : m_pObject(0) {} + CBaseAutoPtr(T *pFrom) : m_pObject(pFrom) {} + + operator const void *() const { return m_pObject; } + operator void *() { return m_pObject; } + + operator const T *() const { return m_pObject; } + operator const T *() { return m_pObject; } + operator T *() { return m_pObject; } + + int operator=( int i ) { AssertMsg( i == 0, "Only NULL allowed on integer assign" ); m_pObject = 0; return 0; } + T * operator=( T *p ) { m_pObject = p; return p; } + + bool operator !() const { return ( !m_pObject ); } + bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (m_pObject != NULL); } + bool operator==( const void *p ) const { return ( m_pObject == p ); } + bool operator!=( const void *p ) const { return ( m_pObject != p ); } + bool operator==( T *p ) const { return operator==( (void *)p ); } + bool operator!=( T *p ) const { return operator!=( (void *)p ); } + bool operator==( const CBaseAutoPtr<T> &p ) const { return operator==( (const void *)p ); } + bool operator!=( const CBaseAutoPtr<T> &p ) const { return operator!=( (const void *)p ); } + + T * operator->() { return m_pObject; } + T & operator *() { return *m_pObject; } + T ** operator &() { return &m_pObject; } + + const T * operator->() const { return m_pObject; } + const T & operator *() const { return *m_pObject; } + T * const * operator &() const { return &m_pObject; } + +protected: + CBaseAutoPtr( const CBaseAutoPtr<T> &from ) : m_pObject( from.m_pObject ) {} + void operator=( const CBaseAutoPtr<T> &from ) { m_pObject = from.m_pObject; } + + T *m_pObject; +}; + +//--------------------------------------------------------- + +template <class T> +class CRefPtr : public CBaseAutoPtr<T> +{ + typedef CBaseAutoPtr<T> BaseClass; +public: + CRefPtr() {} + CRefPtr( T *pInit ) : BaseClass( pInit ) {} + CRefPtr( const CRefPtr<T> &from ) : BaseClass( from ) {} + ~CRefPtr() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->Release(); } + + void operator=( const CRefPtr<T> &from ) { BaseClass::operator=( from ); } + + int operator=( int i ) { return BaseClass::operator=( i ); } + T *operator=( T *p ) { return BaseClass::operator=( p ); } + + operator bool() const { return !BaseClass::operator!(); } + operator bool() { return !BaseClass::operator!(); } + + void SafeRelease() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->Release(); BaseClass::m_pObject = 0; } + void AssignAddRef( T *pFrom ) { SafeRelease(); if (pFrom) pFrom->AddRef(); BaseClass::m_pObject = pFrom; } + void AddRefAssignTo( T *&pTo ) { ::SafeRelease( pTo ); if ( BaseClass::m_pObject ) BaseClass::m_pObject->AddRef(); pTo = BaseClass::m_pObject; } +}; + + +//----------------------------------------------------------------------------- +// Purpose: Traits classes defining reference count threading model +//----------------------------------------------------------------------------- + +class CRefMT +{ +public: + static int Increment( int *p) { return ThreadInterlockedIncrement( (int32 *)p ); } + static int Decrement( int *p) { return ThreadInterlockedDecrement( (int32 *)p ); } +}; + +class CRefST +{ +public: + static int Increment( int *p) { return ++(*p); } + static int Decrement( int *p) { return --(*p); } +}; + +//----------------------------------------------------------------------------- +// Purpose: Actual reference counting implementation. Pulled out to reduce +// code bloat. +//----------------------------------------------------------------------------- + +template <const bool bSelfDelete, typename CRefThreading = CRefMT> +class NO_VTABLE CRefCountServiceBase +{ +protected: + CRefCountServiceBase() + : m_iRefs( 1 ) + { + } + + virtual ~CRefCountServiceBase() + { + } + + virtual bool OnFinalRelease() + { + return true; + } + + int GetRefCount() const + { + return m_iRefs; + } + + int DoAddRef() + { + return CRefThreading::Increment( &m_iRefs ); + } + + int DoRelease() + { + int result = CRefThreading::Decrement( &m_iRefs ); + if ( result ) + return result; + if ( OnFinalRelease() && bSelfDelete ) + delete this; + return 0; + } + +private: + int m_iRefs; +}; + +class CRefCountServiceNull +{ +protected: + static int DoAddRef() { return 1; } + static int DoRelease() { return 1; } +}; + +template <typename CRefThreading = CRefMT> +class NO_VTABLE CRefCountServiceDestruct +{ +protected: + CRefCountServiceDestruct() + : m_iRefs( 1 ) + { + } + + virtual ~CRefCountServiceDestruct() + { + } + + int GetRefCount() const + { + return m_iRefs; + } + + int DoAddRef() + { + return CRefThreading::Increment( &m_iRefs ); + } + + int DoRelease() + { + int result = CRefThreading::Decrement( &m_iRefs ); + if ( result ) + return result; + this->~CRefCountServiceDestruct(); + return 0; + } + +private: + int m_iRefs; +}; + + +typedef CRefCountServiceBase<true, CRefST> CRefCountServiceST; +typedef CRefCountServiceBase<false, CRefST> CRefCountServiceNoDeleteST; + +typedef CRefCountServiceBase<true, CRefMT> CRefCountServiceMT; +typedef CRefCountServiceBase<false, CRefMT> CRefCountServiceNoDeleteMT; + +// Default to threadsafe +typedef CRefCountServiceNoDeleteMT CRefCountServiceNoDelete; +typedef CRefCountServiceMT CRefCountService; + +//----------------------------------------------------------------------------- +// Purpose: Base classes to implement reference counting +//----------------------------------------------------------------------------- + +template < class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted : public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//------------------------------------- + +template < class BASE1, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted1 : public BASE1, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted1() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//------------------------------------- + +template < class BASE1, class BASE2, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted2 : public BASE1, public BASE2, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted2() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//------------------------------------- + +template < class BASE1, class BASE2, class BASE3, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted3 : public BASE1, public BASE2, public BASE3, + public REFCOUNT_SERVICE +{ + virtual ~CRefCounted3() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//------------------------------------- + +template < class BASE1, class BASE2, class BASE3, class BASE4, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted4 : public BASE1, public BASE2, public BASE3, public BASE4, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted4() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//------------------------------------- + +template < class BASE1, class BASE2, class BASE3, class BASE4, class BASE5, class REFCOUNT_SERVICE = CRefCountService > +class NO_VTABLE CRefCounted5 : public BASE1, public BASE2, public BASE3, public BASE4, public BASE5, + public REFCOUNT_SERVICE +{ +public: + virtual ~CRefCounted5() {} + int AddRef() { return REFCOUNT_SERVICE::DoAddRef(); } + int Release() { return REFCOUNT_SERVICE::DoRelease(); } +}; + +//----------------------------------------------------------------------------- +// Purpose: Class to throw around a reference counted item to debug +// referencing problems +//----------------------------------------------------------------------------- +#ifdef _DEBUG +template <class BASE_REFCOUNTED, int FINAL_REFS = 0, const char *pszName = (const char *)NULL > +class CRefDebug : public BASE_REFCOUNTED +{ +public: + CRefDebug() + { + AssertMsg( this->GetRefCount() == 1, "Expected initial ref count of 1" ); + DevMsg( "%s:create 0x%x\n", ( pszName ) ? pszName : "", this ); + } + + virtual ~CRefDebug() + { + AssertDevMsg( this->GetRefCount() == FINAL_REFS, "Object still referenced on destroy?" ); + DevMsg( "%s:destroy 0x%x\n", ( pszName ) ? pszName : "", this ); + } + + int AddRef() + { + DevMsg( "%s:(0x%x)->AddRef() --> %d\n", ( pszName ) ? pszName : "", this, this->GetRefCount() + 1 ); + return BASE_REFCOUNTED::AddRef(); + } + + int Release() + { + DevMsg( "%s:(0x%x)->Release() --> %d\n", ( pszName ) ? pszName : "", this, this->GetRefCount() - 1 ); + Assert( this->GetRefCount() > 0 ); + return BASE_REFCOUNTED::Release(); + } +}; +#endif + +//----------------------------------------------------------------------------- + +#endif // REFCOUNT_H diff --git a/external/vpc/public/tier1/stringpool.h b/external/vpc/public/tier1/stringpool.h new file mode 100644 index 0000000..67dfb51 --- /dev/null +++ b/external/vpc/public/tier1/stringpool.h @@ -0,0 +1,106 @@ +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef STRINGPOOL_H +#define STRINGPOOL_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "utlrbtree.h" +#include "utlvector.h" +#include "utlbuffer.h" + +//----------------------------------------------------------------------------- +// Purpose: Allocates memory for strings, checking for duplicates first, +// reusing exising strings if duplicate found. +//----------------------------------------------------------------------------- + +enum StringPoolCase_t +{ + StringPoolCaseInsensitive, + StringPoolCaseSensitive +}; + +class CStringPool +{ +public: + CStringPool( StringPoolCase_t caseSensitivity = StringPoolCaseInsensitive ); + ~CStringPool(); + + unsigned int Count() const; + + const char * Allocate( const char *pszValue ); + // This feature is deliberately not supported because it's pretty dangerous + // given current uses of CStringPool, which assume they can copy string pointers without + // any refcounts. + //void Free( const char *pszValue ); + void FreeAll(); + + // searches for a string already in the pool + const char * Find( const char *pszValue ); + +protected: + typedef CUtlRBTree<const char *, unsigned short> CStrSet; + + CStrSet m_Strings; +}; + +//----------------------------------------------------------------------------- +// Purpose: A reference counted string pool. +// +// Elements are stored more efficiently than in the conventional string pool, +// quicker to look up, and storage is tracked via reference counts. +// +// At some point this should replace CStringPool +//----------------------------------------------------------------------------- +class CCountedStringPool +{ +public: // HACK, hash_item_t structure should not be public. + + struct hash_item_t + { + char* pString; + unsigned short nNextElement; + unsigned char nReferenceCount; + unsigned char pad; + }; + + enum + { + INVALID_ELEMENT = 0, + MAX_REFERENCE = 0xFF, + HASH_TABLE_SIZE = 1024 + }; + + CUtlVector<unsigned short> m_HashTable; // Points to each element + CUtlVector<hash_item_t> m_Elements; + unsigned short m_FreeListStart; + StringPoolCase_t m_caseSensitivity; + +public: + CCountedStringPool( StringPoolCase_t caseSensitivity = StringPoolCaseInsensitive ); + virtual ~CCountedStringPool(); + + void FreeAll(); + + char *FindString( const char* pIntrinsic ); + char *ReferenceString( const char* pIntrinsic ); + void DereferenceString( const char* pIntrinsic ); + + // These are only reliable if there are less than 64k strings in your string pool + unsigned short FindStringHandle( const char* pIntrinsic ); + unsigned short ReferenceStringHandle( const char* pIntrinsic ); + char *HandleToString( unsigned short handle ); + void SpewStrings(); + unsigned Hash( const char *pszKey ); + + bool SaveToBuffer( CUtlBuffer &buffer ); + bool RestoreFromBuffer( CUtlBuffer &buffer );}; + +#endif // STRINGPOOL_H diff --git a/external/vpc/public/tier1/strtools.h b/external/vpc/public/tier1/strtools.h new file mode 100644 index 0000000..62d335f --- /dev/null +++ b/external/vpc/public/tier1/strtools.h @@ -0,0 +1,589 @@ +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef TIER1_STRTOOLS_H +#define TIER1_STRTOOLS_H + +#include "tier0/basetypes.h" + +#ifdef _WIN32 +#pragma once +#elif POSIX +#include <ctype.h> +#include <wchar.h> +#include <math.h> +#include <wctype.h> +#endif + +#include <string.h> +#include <stdlib.h> + + +// 3d memcpy. Copy (up-to) 3 dimensional data with arbitrary source and destination +// strides. Optimizes to just a single memcpy when possible. For 2d data, set numslices to 1. +void CopyMemory3D( void *pDestAdr, void const *pSrcAdr, + int nNumCols, int nNumRows, int nNumSlices, // dimensions of copy + int nSrcBytesPerRow, int nSrcBytesPerSlice, // strides for source. + int nDestBytesPerRow, int nDestBytesPerSlice // strides for dest + ); + + + + +template< class T, class I > class CUtlMemory; +template< class T, class A > class CUtlVector; + + +//----------------------------------------------------------------------------- +// Portable versions of standard string functions +//----------------------------------------------------------------------------- +void _V_memset ( void *dest, int fill, int count ); +void _V_memcpy ( void *dest, const void *src, int count ); +void _V_memmove ( void *dest, const void *src, int count ); +int _V_memcmp ( const void *m1, const void *m2, int count ); +int _V_strlen ( const char *str ); +void _V_strcpy ( char *dest, const char *src ); +char* _V_strrchr ( const char *s, char c ); +int _V_strcmp ( const char *s1, const char *s2 ); +int _V_wcscmp ( const wchar_t *s1, const wchar_t *s2 ); +int _V_stricmp ( const char *s1, const char *s2 ); +char* _V_strstr ( const char *s1, const char *search ); +char* _V_strupr ( char *start ); +char* _V_strlower ( char *start ); +int _V_wcslen ( const wchar_t *pwch ); + +wchar_t* _V_wcslower (const char* file, int line, wchar_t *start); +wchar_t* _V_wcsupr (const char* file, int line, wchar_t *start); + +#ifdef POSIX +inline char *strupr( char *start ) +{ + char *str = start; + while( str && *str ) + { + *str = (char)toupper(*str); + str++; + } + return start; +} + +inline char *strlwr( char *start ) +{ + char *str = start; + while( str && *str ) + { + *str = (char)tolower(*str); + str++; + } + return start; +} + +inline wchar_t *_wcslwr( wchar_t *start ) +{ + wchar_t *str = start; + while( str && *str ) + { + *str = (wchar_t)towlower(static_cast<wint_t>(*str)); + str++; + } + return start; +}; + +inline wchar_t *_wcsupr( wchar_t *start ) +{ + wchar_t *str = start; + while( str && *str ) + { + *str = (wchar_t)towupper(static_cast<wint_t>(*str)); + str++; + } + return start; +}; + +#endif // POSIX + +// there are some users of these via tier1 templates in used in tier0. but tier0 can't depend on vstdlib which means in tier0 we always need the inlined ones +#if ( !defined( TIER0_DLL_EXPORT ) ) + +#if !defined( _DEBUG ) && defined( _PS3 ) + +#include "tier1/strtools_inlines.h" + +// To avoid cross-prx calls, making the V_* fucntions that don't do anything but debug checks and call through to the non V_* function +// go ahead and call the non-V_* functions directly. +#define V_memset(dest, fill, count) memset ((dest), (fill), (count)) +#define V_memcpy(dest, src, count) memcpy ((dest), (src), (count)) +#define V_memmove(dest, src, count) memmove ((dest), (src), (count)) +#define V_memcmp(m1, m2, count) memcmp ((m1), (m2), (count)) +#define V_strcpy(dest, src) strcpy ((dest), (src)) +#define V_strcmp(s1, s2) strcmp ((s1), (s2)) +#define V_strupr(start) strupr ((start)) +#define V_strlower(start) strlwr ((start)) +#define V_wcslen(pwch) wcslen ((pwch)) +// To avoid cross-prx calls, using inline versions of these custom functions: +#define V_strlen(str) _V_strlen_inline ((str)) +#define V_strrchr(s, c) _V_strrchr_inline ((s), (c)) +#define V_wcscmp(s1, s2) _V_wcscmp_inline ((s1), (s2)) +#define V_stricmp(s1, s2 ) _V_stricmp_inline ((s1), (s2) ) +#define V_strstr(s1, search ) _V_strstr_inline ((s1), (search) ) + +#else + +#define V_memset(dest, fill, count) _V_memset ((dest), (fill), (count)) +#define V_memcpy(dest, src, count) _V_memcpy ((dest), (src), (count)) +#define V_memmove(dest, src, count) _V_memmove ((dest), (src), (count)) +#define V_memcmp(m1, m2, count) _V_memcmp ((m1), (m2), (count)) +#define V_strlen(str) _V_strlen ((str)) +#define V_strcpy(dest, src) _V_strcpy ((dest), (src)) +#define V_strrchr(s, c) _V_strrchr ((s), (c)) +#define V_strcmp(s1, s2) _V_strcmp ((s1), (s2)) +#define V_wcscmp(s1, s2) _V_wcscmp ((s1), (s2)) +#define V_stricmp(s1, s2 ) _V_stricmp ((s1), (s2) ) +#define V_strstr(s1, search ) _V_strstr ((s1), (search) ) +#define V_strupr(start) _V_strupr ((start)) +#define V_strlower(start) _V_strlower ((start)) +#define V_wcslen(pwch) _V_wcslen ((pwch)) + +#endif + +#else + +inline void V_memset (void *dest, int fill, int count) { memset( dest, fill, count ); } +inline void V_memcpy (void *dest, const void *src, int count) { memcpy( dest, src, count ); } +inline void V_memmove (void *dest, const void *src, int count) { memmove( dest, src, count ); } +inline int V_memcmp (const void *m1, const void *m2, int count){ return memcmp( m1, m2, count ); } +inline int V_strlen (const char *str) { return (int) strlen ( str ); } +inline void V_strcpy (char *dest, const char *src) { strcpy( dest, src ); } +inline int V_wcslen(const wchar_t *pwch) { return (int)wcslen(pwch); } +inline char* V_strrchr (const char *s, char c) { return (char*)strrchr( s, c ); } +inline int V_strcmp (const char *s1, const char *s2) { return strcmp( s1, s2 ); } +inline int V_wcscmp (const wchar_t *s1, const wchar_t *s2) { return wcscmp( s1, s2 ); } +inline int V_stricmp( const char *s1, const char *s2 ) { return stricmp( s1, s2 ); } +inline char* V_strstr( const char *s1, const char *search ) { return (char*)strstr( s1, search ); } +#ifndef COMPILER_PS3 +inline char* V_strupr (char *start) { return strupr( start ); } +inline char* V_strlower (char *start) { return strlwr( start ); } +inline wchar_t* V_wcsupr (wchar_t *start) { return _wcsupr( start ); } +#endif + +#endif + + +int V_strncmp (const char *s1, const char *s2, int count); +int V_strcasecmp (const char *s1, const char *s2); +int V_strncasecmp (const char *s1, const char *s2, int n); +int V_strnicmp (const char *s1, const char *s2, int n); +int V_atoi (const char *str); +int64 V_atoi64(const char *str); +uint64 V_atoui64(const char *str); +float V_atof (const char *str); +char* V_stristr( char* pStr, const char* pSearch ); +const char* V_stristr( const char* pStr, const char* pSearch ); +const char* V_strnistr( const char* pStr, const char* pSearch, int n ); +const char* V_strnchr( const char* pStr, char c, int n ); + +// returns string immediately following prefix, (ie str+strlen(prefix)) or NULL if prefix not found +const char *StringAfterPrefix ( const char *str, const char *prefix ); +const char *StringAfterPrefixCaseSensitive( const char *str, const char *prefix ); +inline bool StringHasPrefix ( const char *str, const char *prefix ) { return StringAfterPrefix ( str, prefix ) != NULL; } +inline bool StringHasPrefixCaseSensitive( const char *str, const char *prefix ) { return StringAfterPrefixCaseSensitive( str, prefix ) != NULL; } + + +// Normalizes a float string in place. +// (removes leading zeros, trailing zeros after the decimal point, and the decimal point itself where possible) +void V_normalizeFloatString( char* pFloat ); + +inline bool V_isspace(int c) +{ + // The standard white-space characters are the following: space, tab, carriage-return, newline, vertical tab, and form-feed. In the C locale, V_isspace() returns true only for the standard white-space characters. + //return c == ' ' || c == 9 /*horizontal tab*/ || c == '\r' || c == '\n' || c == 11 /*vertical tab*/ || c == '\f'; + // codes of whitespace symbols: 9 HT, 10 \n, 11 VT, 12 form feed, 13 \r, 32 space + + // easy to understand version, validated: + // return ((1 << (c-1)) & 0x80001F00) != 0 && ((c-1)&0xE0) == 0; + + // 5% faster on Core i7, 35% faster on Xbox360, no branches, validated: + #ifdef _X360 + return ((1 << (c-1)) & 0x80001F00 & ~(-int((c-1)&0xE0))) != 0; + #else + // this is 11% faster on Core i7 than the previous, VC2005 compiler generates a seemingly unbalanced search tree that's faster + switch(c) + { + case ' ': + case 9: + case '\r': + case '\n': + case 11: + case '\f': + return true; + default: + return false; + } + #endif +} + + +// These are versions of functions that guarantee NULL termination. +// +// maxLen is the maximum number of bytes in the destination string. +// pDest[maxLen-1] is always NULL terminated if pSrc's length is >= maxLen. +// +// This means the last parameter can usually be a sizeof() of a string. +void V_strncpy( char *pDest, const char *pSrc, int maxLen ); +int V_snprintf( char *pDest, int destLen, const char *pFormat, ... ) FMTFUNCTION( 3, 4 ); +void V_wcsncpy( wchar_t *pDest, wchar_t const *pSrc, int maxLenInBytes ); +int V_snwprintf( wchar_t *pDest, int maxLenInNumWideCharacters, const wchar_t *pFormat, ... ); + +#define COPY_ALL_CHARACTERS -1 +char *V_strncat(char *, const char *, size_t maxLenInBytes, int max_chars_to_copy=COPY_ALL_CHARACTERS ); +wchar_t *V_wcsncat(wchar_t *, const wchar_t *, int maxLenInBytes, int max_chars_to_copy=COPY_ALL_CHARACTERS ); +char *V_strnlwr(char *, size_t); + + +// UNDONE: Find a non-compiler-specific way to do this +#ifdef _WIN32 +#ifndef _VA_LIST_DEFINED + +#ifdef _M_ALPHA + +struct va_list +{ + char *a0; /* pointer to first homed integer argument */ + int offset; /* byte offset of next parameter */ +}; + +#else // !_M_ALPHA + +typedef char * va_list; + +#endif // !_M_ALPHA + +#define _VA_LIST_DEFINED + +#endif // _VA_LIST_DEFINED + +#elif POSIX +#include <stdarg.h> +#endif + +#ifdef _WIN32 +#define CORRECT_PATH_SEPARATOR '\\' +#define CORRECT_PATH_SEPARATOR_S "\\" +#define INCORRECT_PATH_SEPARATOR '/' +#define INCORRECT_PATH_SEPARATOR_S "/" +#elif POSIX || defined( _PS3 ) +#define CORRECT_PATH_SEPARATOR '/' +#define CORRECT_PATH_SEPARATOR_S "/" +#define INCORRECT_PATH_SEPARATOR '\\' +#define INCORRECT_PATH_SEPARATOR_S "\\" +#endif + +int V_vsnprintf( char *pDest, int maxLen, const char *pFormat, va_list params ); +int V_vsnprintfRet( char *pDest, int maxLen, const char *pFormat, va_list params, bool *pbTruncated ); + +// Prints out a pretified memory counter string value ( e.g., 7,233.27 Mb, 1,298.003 Kb, 127 bytes ) +char *V_pretifymem( float value, int digitsafterdecimal = 2, bool usebinaryonek = false ); + +// Prints out a pretified integer with comma separators (eg, 7,233,270,000) +char *V_pretifynum( int64 value ); + +// Functions for converting hexidecimal character strings back into binary data etc. +// +// e.g., +// int output; +// V_hextobinary( "ffffffff", 8, &output, sizeof( output ) ); +// would make output == 0xfffffff or -1 +// Similarly, +// char buffer[ 9 ]; +// V_binarytohex( &output, sizeof( output ), buffer, sizeof( buffer ) ); +// would put "ffffffff" into buffer (note null terminator!!!) +void V_hextobinary( char const *in, int numchars, byte *out, int maxoutputbytes ); +void V_binarytohex( const byte *in, int inputbytes, char *out, int outsize ); + +// Tools for working with filenames +// Extracts the base name of a file (no path, no extension, assumes '/' or '\' as path separator) +void V_FileBase( const char *in, char *out,int maxlen ); +// Remove the final characters of ppath if it's '\' or '/'. +void V_StripTrailingSlash( char *ppath ); +// Remove any extension from in and return resulting string in out +void V_StripExtension( const char *in, char *out, int outLen ); +// Make path end with extension if it doesn't already have an extension +void V_DefaultExtension( char *path, const char *extension, int pathStringLength ); +// Strips any current extension from path and ensures that extension is the new extension. +// NOTE: extension string MUST include the . character +void V_SetExtension( char *path, const char *extension, int pathStringLength ); +// Removes any filename from path ( strips back to previous / or \ character ) +void V_StripFilename( char *path ); +// Remove the final directory from the path +bool V_StripLastDir( char *dirName, int maxlen ); +// Returns a pointer to the unqualified file name (no path) of a file name +const char * V_UnqualifiedFileName( const char * in ); +char * V_UnqualifiedFileName( char * in ); +// Given a path and a filename, composes "path\filename", inserting the (OS correct) separator if necessary +void V_ComposeFileName( const char *path, const char *filename, char *dest, int destSize ); + +// Copy out the path except for the stuff after the final pathseparator +bool V_ExtractFilePath( const char *path, char *dest, int destSize ); +// Copy out the file extension into dest +void V_ExtractFileExtension( const char *path, char *dest, int destSize ); + +const char *V_GetFileExtension( const char * path ); + +// returns a pointer to just the filename part of the path +// (everything after the last path seperator) +const char *V_GetFileName( const char * path ); + +// This removes "./" and "../" from the pathname. pFilename should be a full pathname. +// Returns false if it tries to ".." past the root directory in the drive (in which case +// it is an invalid path). +bool V_RemoveDotSlashes( char *pFilename, char separator = CORRECT_PATH_SEPARATOR ); + +// If pPath is a relative path, this function makes it into an absolute path +// using the current working directory as the base, or pStartingDir if it's non-NULL. +// Returns false if it runs out of room in the string, or if pPath tries to ".." past the root directory. +void V_MakeAbsolutePath( char *pOut, int outLen, const char *pPath, const char *pStartingDir = NULL ); + +// Creates a relative path given two full paths +// The first is the full path of the file to make a relative path for. +// The second is the full path of the directory to make the first file relative to +// Returns false if they can't be made relative (on separate drives, for example) +bool V_MakeRelativePath( const char *pFullPath, const char *pDirectory, char *pRelativePath, int nBufLen ); + +// Fixes up a file name, removing dot slashes, fixing slashes, converting to lowercase, etc. +void V_FixupPathName( char *pOut, size_t nOutLen, const char *pPath ); + +// Adds a path separator to the end of the string if there isn't one already. Returns false if it would run out of space. +void V_AppendSlash( char *pStr, int strSize ); + +// Returns true if the path is an absolute path. +bool V_IsAbsolutePath( const char *pPath ); + +// Scans pIn and replaces all occurences of pMatch with pReplaceWith. +// Writes the result to pOut. +// Returns true if it completed successfully. +// If it would overflow pOut, it fills as much as it can and returns false. +bool V_StrSubst( const char *pIn, const char *pMatch, const char *pReplaceWith, + char *pOut, int outLen, bool bCaseSensitive=false ); + + +// Split the specified string on the specified separator. +// Returns a list of strings separated by pSeparator. +// You are responsible for freeing the contents of outStrings (call outStrings.PurgeAndDeleteElements). +void V_SplitString( const char *pString, const char *pSeparator, CUtlVector<char*, CUtlMemory<char*, int> > &outStrings ); + +// Just like V_SplitString, but it can use multiple possible separators. +void V_SplitString2( const char *pString, const char **pSeparators, int nSeparators, CUtlVector<char*, CUtlMemory<char*, int> > &outStrings ); + +// Returns false if the buffer is not large enough to hold the working directory name. +bool V_GetCurrentDirectory( char *pOut, int maxLen ); + +// Set the working directory thus. +bool V_SetCurrentDirectory( const char *pDirName ); + + +// This function takes a slice out of pStr and stores it in pOut. +// It follows the Python slice convention: +// Negative numbers wrap around the string (-1 references the last character). +// Large numbers are clamped to the end of the string. +void V_StrSlice( const char *pStr, int firstChar, int lastCharNonInclusive, char *pOut, int outSize ); + +// Chop off the left nChars of a string. +void V_StrLeft( const char *pStr, int nChars, char *pOut, int outSize ); + +// Chop off the right nChars of a string. +void V_StrRight( const char *pStr, int nChars, char *pOut, int outSize ); + +// change "special" characters to have their c-style backslash sequence. like \n, \r, \t, ", etc. +// returns a pointer to a newly allocated string, which you must delete[] when finished with. +char *V_AddBackSlashesToSpecialChars( char const *pSrc ); + +// Force slashes of either type to be = separator character +void V_FixSlashes( char *pname, char separator = CORRECT_PATH_SEPARATOR ); + +// This function fixes cases of filenames like materials\\blah.vmt or somepath\otherpath\\ and removes the extra double slash. +void V_FixDoubleSlashes( char *pStr ); + +// Convert multibyte to wchar + back +// Specify -1 for nInSize for null-terminated string +void V_strtowcs( const char *pString, int nInSize, wchar_t *pWString, int nOutSize ); +void V_wcstostr( const wchar_t *pWString, int nInSize, char *pString, int nOutSize ); + +// buffer-safe strcat +inline void V_strcat( char *dest, const char *src, int maxLenInBytes ) +{ + V_strncat( dest, src, maxLenInBytes, COPY_ALL_CHARACTERS ); +} + +// buffer-safe strcat +inline void V_wcscat( wchar_t *dest, const wchar_t *src, int maxLenInBytes ) +{ + V_wcsncat( dest, src, maxLenInBytes, COPY_ALL_CHARACTERS ); +} + +// Convert from a string to an array of integers. +void V_StringToIntArray( int *pVector, int count, const char *pString ); + +// Convert from a string to a 4 byte color value. +void V_StringToColor32( color32 *color, const char *pString ); + +// Convert \r\n (Windows linefeeds) to \n (Unix linefeeds). +void V_TranslateLineFeedsToUnix( char *pStr ); + +//----------------------------------------------------------------------------- +// generic unique name helper functions +//----------------------------------------------------------------------------- + +// returns -1 if no match, nDefault if pName==prefix, and N if pName==prefix+N +inline int V_IndexAfterPrefix( const char *pName, const char *prefix, int nDefault = 0 ) +{ + if ( !pName || !prefix ) + return -1; + + const char *pIndexStr = StringAfterPrefix( pName, prefix ); + if ( !pIndexStr ) + return -1; + + if ( !*pIndexStr ) + return nDefault; + + return atoi( pIndexStr ); +} + +// returns startindex if none found, 2 if "prefix" found, and n+1 if "prefixn" found +template < class NameArray > +int V_GenerateUniqueNameIndex( const char *prefix, const NameArray &nameArray, int startindex = 0 ) +{ + if ( !prefix ) + return 0; + + int freeindex = startindex; + + int nNames = nameArray.Count(); + for ( int i = 0; i < nNames; ++i ) + { + int index = V_IndexAfterPrefix( nameArray[ i ], prefix, 1 ); // returns -1 if no match, 0 for exact match, N for + if ( index >= freeindex ) + { + // TODO - check that there isn't more junk after the index in pElementName + freeindex = index + 1; + } + } + + return freeindex; +} + +template < class NameArray > +bool V_GenerateUniqueName( char *name, int memsize, const char *prefix, const NameArray &nameArray ) +{ + if ( name == NULL || memsize == 0 ) + return false; + + if ( prefix == NULL ) + { + name[ 0 ] = '\0'; + return false; + } + + int prefixLength = V_strlen( prefix ); + if ( prefixLength + 1 > memsize ) + { + name[ 0 ] = '\0'; + return false; + } + + int i = V_GenerateUniqueNameIndex( prefix, nameArray ); + if ( i <= 0 ) + { + V_strncpy( name, prefix, memsize ); + return true; + } + + int newlen = prefixLength + ( int )log10( ( float )i ) + 1; + if ( newlen + 1 > memsize ) + { + V_strncpy( name, prefix, memsize ); + return false; + } + + V_snprintf( name, memsize, "%s%d", prefix, i ); + return true; +} + + +extern bool V_StringToBin( const char*pString, void *pBin, uint nBinSize ); +extern bool V_BinToString( char*pString, void *pBin, uint nBinSize ); + +template<typename T> +struct BinString_t +{ + BinString_t(){} + BinString_t( const char *pStr ) + { + V_strncpy( m_string, pStr, sizeof(m_string) ); + ToBin(); + } + BinString_t( const T & that ) + { + m_bin = that; + ToString(); + } + bool ToBin() + { + return V_StringToBin( m_string, &m_bin, sizeof( m_bin ) ); + } + void ToString() + { + V_BinToString( m_string, &m_bin, sizeof( m_bin ) ); + } + T m_bin; + char m_string[sizeof(T)*2+2]; // 0-terminated string representing the binary data in hex +}; + +template <typename T> +inline BinString_t<T> MakeBinString( const T& that ) +{ + return BinString_t<T>( that ); +} + + + + + + +#if defined(_PS3) || defined(POSIX) +#define PRI_WS_FOR_WS L"%ls" +#define PRI_WS_FOR_S "%ls" +#define PRI_S_FOR_WS L"%s" +#define PRI_S_FOR_S "%s" +#else +#define PRI_WS_FOR_WS L"%s" +#define PRI_WS_FOR_S "%S" +#define PRI_S_FOR_WS L"%S" +#define PRI_S_FOR_S "%s" +#endif + +namespace AsianWordWrap +{ + // Functions used by Asian language line wrapping to determine if a character can end a line, begin a line, or be broken up when repeated (eg: "...") + bool CanEndLine( wchar_t wcCandidate ); + bool CanBeginLine( wchar_t wcCandidate ); + bool CanBreakRepeated( wchar_t wcCandidate ); + + // Used to determine if we can break a line between the first two characters passed; calls the above functions on each character + bool CanBreakAfter( const wchar_t* wsz ); +} + +// We use this function to determine where it is permissible to break lines +// of text while wrapping them. On most platforms, the native iswspace() function +// returns FALSE for the "non-breaking space" characters 0x00a0 and 0x202f, and so we don't +// break on them. On the 360, however, iswspace returns TRUE for them. So, on that +// platform, we work around it by defining this wrapper which returns false +// for and calls through to the library function for everything else. +int isbreakablewspace( wchar_t ch ); + +#endif // TIER1_STRTOOLS_H diff --git a/external/vpc/public/tier1/tier1.h b/external/vpc/public/tier1/tier1.h new file mode 100644 index 0000000..c4d89c6 --- /dev/null +++ b/external/vpc/public/tier1/tier1.h @@ -0,0 +1,85 @@ +//===== Copyright � 2005-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + + +#ifndef TIER1_H +#define TIER1_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "appframework/iappsystem.h" +#include "tier1/convar.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Call this to connect to/disconnect from all tier 1 libraries. +// It's up to the caller to check the globals it cares about to see if ones are missing +//----------------------------------------------------------------------------- +void ConnectTier1Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount ); +void DisconnectTier1Libraries(); + + +//----------------------------------------------------------------------------- +// Helper empty implementation of an IAppSystem for tier2 libraries +//----------------------------------------------------------------------------- +template< class IInterface, int ConVarFlag = 0 > +class CTier1AppSystem : public CTier0AppSystem< IInterface > +{ + typedef CTier0AppSystem< IInterface > BaseClass; + +public: + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + + ConnectTier1Libraries( &factory, 1 ); + return true; + } + + virtual void Disconnect() + { + DisconnectTier1Libraries(); + BaseClass::Disconnect(); + } + + virtual InitReturnVal_t Init() + { + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + if ( g_pCVar ) + { + ConVar_Register( ConVarFlag ); + } + return INIT_OK; + } + + virtual void Shutdown() + { + if ( g_pCVar ) + { + ConVar_Unregister( ); + } + BaseClass::Shutdown( ); + } + + virtual AppSystemTier_t GetTier() + { + return APP_SYSTEM_TIER1; + } +}; + + +#endif // TIER1_H + diff --git a/external/vpc/public/tier1/utlblockmemory.h b/external/vpc/public/tier1/utlblockmemory.h new file mode 100644 index 0000000..81ba5e5 --- /dev/null +++ b/external/vpc/public/tier1/utlblockmemory.h @@ -0,0 +1,349 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable memory class. +//===========================================================================// + +#ifndef UTLBLOCKMEMORY_H +#define UTLBLOCKMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "tier0/platform.h" +#include "mathlib/mathlib.h" + +#include "tier0/memalloc.h" +#include "tier0/memdbgon.h" + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + +//----------------------------------------------------------------------------- + +#ifdef UTBLOCKLMEMORY_TRACK +#define UTLBLOCKMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "||Sum of all UtlBlockMemory||", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#define UTLBLOCKMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "||Sum of all UtlBlockMemory||", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#else +#define UTLBLOCKMEMORY_TRACK_ALLOC() ((void)0) +#define UTLBLOCKMEMORY_TRACK_FREE() ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// The CUtlBlockMemory class: +// A growable memory class that allocates non-sequential blocks, but is indexed sequentially +//----------------------------------------------------------------------------- +template< class T, class I > +class CUtlBlockMemory +{ +public: + // constructor, destructor + CUtlBlockMemory( int nGrowSize = 0, int nInitSize = 0 ); + ~CUtlBlockMemory(); + + // Set the size by which the memory grows - round up to the next power of 2 + void Init( int nGrowSize = 0, int nInitSize = 0 ); + + // here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL + T* Base() { return NULL; } + const T* Base() const { return NULL; } + + class Iterator_t + { + public: + Iterator_t( I i ) : index( i ) {} + I index; + + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); } + I GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } + + // element access + T& operator[]( I i ); + const T& operator[]( I i ) const; + T& Element( I i ); + const T& Element( I i ) const; + + // Can we use this index? + bool IsIdxValid( I i ) const; + static I InvalidIndex() { return ( I )-1; } + + void Swap( CUtlBlockMemory< T, I > &mem ); + + // Size + int NumAllocated() const; + int Count() const { return NumAllocated(); } + + // Grows memory by max(num,growsize) rounded up to the next power of 2, and returns the allocation index/ptr + void Grow( int num = 1 ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + + // Purge all but the given number of elements + void Purge( int numElements ); + +protected: + int Index( int major, int minor ) const { return ( major << m_nIndexShift ) | minor; } + int MajorIndex( int i ) const { return i >> m_nIndexShift; } + int MinorIndex( int i ) const { return i & m_nIndexMask; } + void ChangeSize( int nBlocks ); + int NumElementsInBlock() const { return m_nIndexMask + 1; } + + T** m_pMemory; + int m_nBlocks; + int m_nIndexMask : 27; + int m_nIndexShift : 5; +}; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T, class I > +CUtlBlockMemory<T,I>::CUtlBlockMemory( int nGrowSize, int nInitAllocationCount ) +: m_pMemory( 0 ), m_nBlocks( 0 ), m_nIndexMask( 0 ), m_nIndexShift( 0 ) +{ + Init( nGrowSize, nInitAllocationCount ); +} + +template< class T, class I > +CUtlBlockMemory<T,I>::~CUtlBlockMemory() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Fast swap +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlBlockMemory<T,I>::Swap( CUtlBlockMemory< T, I > &mem ) +{ + V_swap( m_pMemory, mem.m_pMemory ); + V_swap( m_nBlocks, mem.m_nBlocks ); + V_swap( m_nIndexMask, mem.m_nIndexMask ); + V_swap( m_nIndexShift, mem.m_nIndexShift ); +} + + +//----------------------------------------------------------------------------- +// Set the size by which the memory grows - round up to the next power of 2 +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlBlockMemory<T,I>::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ ) +{ + Purge(); + + if ( nGrowSize == 0) + { + // default grow size is smallest size s.t. c++ allocation overhead is ~6% of block size + nGrowSize = ( 127 + sizeof( T ) ) / sizeof( T ); + } + nGrowSize = SmallestPowerOfTwoGreaterOrEqual( nGrowSize ); + m_nIndexMask = nGrowSize - 1; + + m_nIndexShift = 0; + while ( nGrowSize > 1 ) + { + nGrowSize >>= 1; + ++m_nIndexShift; + } + Assert( m_nIndexMask + 1 == ( 1 << m_nIndexShift ) ); + + Grow( nInitSize ); +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T, class I > +inline T& CUtlBlockMemory<T,I>::operator[]( I i ) +{ + Assert( IsIdxValid(i) ); + T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + +template< class T, class I > +inline const T& CUtlBlockMemory<T,I>::operator[]( I i ) const +{ + Assert( IsIdxValid(i) ); + const T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + +template< class T, class I > +inline T& CUtlBlockMemory<T,I>::Element( I i ) +{ + Assert( IsIdxValid(i) ); + T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + +template< class T, class I > +inline const T& CUtlBlockMemory<T,I>::Element( I i ) const +{ + Assert( IsIdxValid(i) ); + const T *pBlock = m_pMemory[ MajorIndex( i ) ]; + return pBlock[ MinorIndex( i ) ]; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T, class I > +inline int CUtlBlockMemory<T,I>::NumAllocated() const +{ + return m_nBlocks * NumElementsInBlock(); +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T, class I > +inline bool CUtlBlockMemory<T,I>::IsIdxValid( I i ) const +{ + return ( i >= 0 ) && ( MajorIndex( i ) < m_nBlocks ); +} + +template< class T, class I > +void CUtlBlockMemory<T,I>::Grow( int num ) +{ + if ( num <= 0 ) + return; + + int nBlockSize = NumElementsInBlock(); + int nBlocks = ( num + nBlockSize - 1 ) / nBlockSize; + + ChangeSize( m_nBlocks + nBlocks ); +} + +template< class T, class I > +void CUtlBlockMemory<T,I>::ChangeSize( int nBlocks ) +{ + UTLBLOCKMEMORY_TRACK_FREE(); // this must stay before the recalculation of m_nBlocks, since it implicitly uses the old value + + int nBlocksOld = m_nBlocks; + m_nBlocks = nBlocks; + + UTLBLOCKMEMORY_TRACK_ALLOC(); // this must stay after the recalculation of m_nBlocks, since it implicitly uses the new value + + // free old blocks if shrinking + for ( int i = m_nBlocks; i < nBlocksOld; ++i ) + { + UTLBLOCKMEMORY_TRACK_FREE(); + free( (void*)m_pMemory[ i ] ); + } + + if ( m_pMemory ) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T**)realloc( m_pMemory, m_nBlocks * sizeof(T*) ); + Assert( m_pMemory ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T**)malloc( m_nBlocks * sizeof(T*) ); + Assert( m_pMemory ); + } + + if ( !m_pMemory ) + { + Error( "CUtlBlockMemory overflow!\n" ); + } + + // allocate new blocks if growing + int nBlockSize = NumElementsInBlock(); + for ( int i = nBlocksOld; i < m_nBlocks; ++i ) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory[ i ] = (T*)malloc( nBlockSize * sizeof( T ) ); + Assert( m_pMemory[ i ] ); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T, class I > +inline void CUtlBlockMemory<T,I>::EnsureCapacity( int num ) +{ + Grow( num - NumAllocated() ); +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlBlockMemory<T,I>::Purge() +{ + if ( !m_pMemory ) + return; + + for ( int i = 0; i < m_nBlocks; ++i ) + { + UTLBLOCKMEMORY_TRACK_FREE(); + free( (void*)m_pMemory[ i ] ); + } + m_nBlocks = 0; + + UTLBLOCKMEMORY_TRACK_FREE(); + free( (void*)m_pMemory ); + m_pMemory = 0; +} + +template< class T, class I > +void CUtlBlockMemory<T,I>::Purge( int numElements ) +{ + Assert( numElements >= 0 ); + + int nAllocated = NumAllocated(); + if ( numElements > nAllocated ) + { + // Ensure this isn't a grow request in disguise. + Assert( numElements <= nAllocated ); + return; + } + + if ( numElements <= 0 ) + { + Purge(); + return; + } + + int nBlockSize = NumElementsInBlock(); + int nBlocksOld = m_nBlocks; + int nBlocks = ( numElements + nBlockSize - 1 ) / nBlockSize; + + // If the number of blocks is the same as the allocated number of blocks, we are done. + if ( nBlocks == m_nBlocks ) + return; + + ChangeSize( nBlocks ); +} + +#include "tier0/memdbgoff.h" + +#endif // UTLBLOCKMEMORY_H diff --git a/external/vpc/public/tier1/utlbuffer.h b/external/vpc/public/tier1/utlbuffer.h new file mode 100644 index 0000000..5832750 --- /dev/null +++ b/external/vpc/public/tier1/utlbuffer.h @@ -0,0 +1,1398 @@ +//====== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. =======// +// +// Purpose: +// +// $NoKeywords: $ +// +// Serialization/unserialization buffer +//=============================================================================// + +#ifndef UTLBUFFER_H +#define UTLBUFFER_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "unitlib/unitlib.h" // just here for tests - remove before checking in!!! + +#include "tier1/utlmemory.h" +#include "tier1/byteswap.h" +#include <stdarg.h> + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +struct characterset_t; + + +//----------------------------------------------------------------------------- +// Description of character conversions for string output +// Here's an example of how to use the macros to define a character conversion +// BEGIN_CHAR_CONVERSION( CStringConversion, '\\' ) +// { '\n', "n" }, +// { '\t', "t" } +// END_CHAR_CONVERSION( CStringConversion, '\\' ) +//----------------------------------------------------------------------------- +class CUtlCharConversion +{ +public: + struct ConversionArray_t + { + char m_nActualChar; + char *m_pReplacementString; + }; + + CUtlCharConversion( char nEscapeChar, const char *pDelimiter, int nCount, ConversionArray_t *pArray ); + char GetEscapeChar() const; + const char *GetDelimiter() const; + int GetDelimiterLength() const; + + const char *GetConversionString( char c ) const; + int GetConversionLength( char c ) const; + int MaxConversionLength() const; + + // Finds a conversion for the passed-in string, returns length + virtual char FindConversion( const char *pString, int *pLength ); + +protected: + struct ConversionInfo_t + { + int m_nLength; + char *m_pReplacementString; + }; + + char m_nEscapeChar; + const char *m_pDelimiter; + int m_nDelimiterLength; + int m_nCount; + int m_nMaxConversionLength; + char m_pList[256]; + ConversionInfo_t m_pReplacements[256]; +}; + +#define BEGIN_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \ + static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = { + +#define END_CHAR_CONVERSION( _name, _delimiter, _escapeChar ) \ + }; \ + CUtlCharConversion _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name ); + +#define BEGIN_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \ + static CUtlCharConversion::ConversionArray_t s_pConversionArray ## _name[] = { + +#define END_CUSTOM_CHAR_CONVERSION( _className, _name, _delimiter, _escapeChar ) \ + }; \ + _className _name( _escapeChar, _delimiter, sizeof( s_pConversionArray ## _name ) / sizeof( CUtlCharConversion::ConversionArray_t ), s_pConversionArray ## _name ); + +//----------------------------------------------------------------------------- +// Character conversions for C strings +//----------------------------------------------------------------------------- +CUtlCharConversion *GetCStringCharConversion(); + +//----------------------------------------------------------------------------- +// Character conversions for quoted strings, with no escape sequences +//----------------------------------------------------------------------------- +CUtlCharConversion *GetNoEscCharConversion(); + + +//----------------------------------------------------------------------------- +// Macro to set overflow functions easily +//----------------------------------------------------------------------------- +#define SetUtlBufferOverflowFuncs( _get, _put ) \ + SetOverflowFuncs( static_cast <UtlBufferOverflowFunc_t>( _get ), static_cast <UtlBufferOverflowFunc_t>( _put ) ) + + +#define FMSTRRETTYPE static const char * +#ifdef LINUX +// gcc 4.3 is techinically correct and doesn't like the storage specifier, +// unfortunately, that makes gcc on the mac and VS wind up with multiply defined +// symbols at link time +#define FMSTRRETTYPE const char * +#endif + +typedef unsigned short ushort; + +template < class A > +static const char *GetFmtStr( int nRadix = 10, bool bPrint = true ) { Assert( 0 ); return ""; } + +template <> FMSTRRETTYPE GetFmtStr< short > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%hd"; } +template <> FMSTRRETTYPE GetFmtStr< ushort > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%hu"; } +template <> FMSTRRETTYPE GetFmtStr< int > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%d"; } +template <> FMSTRRETTYPE GetFmtStr< uint > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 || nRadix == 16 ); return nRadix == 16 ? "%x" : "%u"; } +template <> FMSTRRETTYPE GetFmtStr< int64 > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%lld"; } +template <> FMSTRRETTYPE GetFmtStr< float > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return "%f"; } +template <> FMSTRRETTYPE GetFmtStr< double > ( int nRadix, bool bPrint ) { Assert( nRadix == 10 ); return bPrint ? "%.15lf" : "%lf"; } // force Printf to print DBL_DIG=15 digits of precision for doubles - defaults to FLT_DIG=6 + + +//----------------------------------------------------------------------------- +// Command parsing.. +//----------------------------------------------------------------------------- +class CUtlBuffer +{ +// Brian has on his todo list to revisit this as there are issues in some cases with CUtlVector using operator = instead of copy construtor in InsertMultiple, etc. +// The unsafe case is something like this: +// CUtlVector< CUtlBuffer > vecFoo; +// +// CUtlBuffer buf; +// buf.Put( xxx ); +// vecFoo.Insert( buf ); +// +// This will cause memory corruption when vecFoo is cleared +// +//private: +// // Disallow copying +// CUtlBuffer( const CUtlBuffer & );// { Assert( 0 ); } +// CUtlBuffer &operator=( const CUtlBuffer & );// { Assert( 0 ); return *this; } + +public: + enum SeekType_t + { + SEEK_HEAD = 0, + SEEK_CURRENT, + SEEK_TAIL + }; + + // flags + enum BufferFlags_t + { + TEXT_BUFFER = 0x1, // Describes how get + put work (as strings, or binary) + EXTERNAL_GROWABLE = 0x2, // This is used w/ external buffers and causes the utlbuf to switch to reallocatable memory if an overflow happens when Putting. + CONTAINS_CRLF = 0x4, // For text buffers only, does this contain \n or \n\r? + READ_ONLY = 0x8, // For external buffers; prevents null termination from happening. + AUTO_TABS_DISABLED = 0x10, // Used to disable/enable push/pop tabs + }; + + // Overflow functions when a get or put overflows + typedef bool (CUtlBuffer::*UtlBufferOverflowFunc_t)( int nSize ); + + // Constructors for growable + external buffers for serialization/unserialization + CUtlBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 ); + CUtlBuffer( const void* pBuffer, int size, int nFlags = 0 ); + // This one isn't actually defined so that we catch contructors that are trying to pass a bool in as the third param. + CUtlBuffer( const void *pBuffer, int size, bool crap ); + + unsigned char GetFlags() const; + + // NOTE: This will assert if you attempt to recast it in a way that + // is not compatible. The only valid conversion is binary-> text w/CRLF + void SetBufferType( bool bIsText, bool bContainsCRLF ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Access for direct read into buffer + void * AccessForDirectRead( int nBytes ); + + // Attaches the buffer to external memory.... + void SetExternalBuffer( void* pMemory, int nSize, int nInitialPut, int nFlags = 0 ); + bool IsExternallyAllocated() const; + void AssumeMemory( void *pMemory, int nSize, int nInitialPut, int nFlags = 0 ); + void *Detach(); + void* DetachMemory(); + + FORCEINLINE void ActivateByteSwappingIfBigEndian( void ) + { + if ( ( IsX360() || IsPS3() ) ) + ActivateByteSwapping( true ); + } + + + // Controls endian-ness of binary utlbufs - default matches the current platform + void ActivateByteSwapping( bool bActivate ); + void SetBigEndian( bool bigEndian ); + bool IsBigEndian( void ); + + // Resets the buffer; but doesn't free memory + void Clear(); + + // Clears out the buffer; frees memory + void Purge(); + + // Dump the buffer to stdout + void Spew( ); + + // Read stuff out. + // Binary mode: it'll just read the bits directly in, and characters will be + // read for strings until a null character is reached. + // Text mode: it'll parse the file, turning text #s into real numbers. + // GetString will read a string until a space is reached + char GetChar( ); + unsigned char GetUnsignedChar( ); + short GetShort( ); + unsigned short GetUnsignedShort( ); + int GetInt( ); + int64 GetInt64( ); + unsigned int GetIntHex( ); + unsigned int GetUnsignedInt( ); + float GetFloat( ); + double GetDouble( ); + void * GetPtr(); + void GetString( char* pString, int nMaxChars = 0 ); + void Get( void* pMem, int size ); + void GetLine( char* pLine, int nMaxChars = 0 ); + + // Used for getting objects that have a byteswap datadesc defined + template <typename T> void GetObjects( T *dest, int count = 1 ); + + // This will get at least 1 byte and up to nSize bytes. + // It will return the number of bytes actually read. + int GetUpTo( void *pMem, int nSize ); + + // This version of GetString converts \" to \\ and " to \, etc. + // It also reads a " at the beginning and end of the string + void GetDelimitedString( CUtlCharConversion *pConv, char *pString, int nMaxChars = 0 ); + char GetDelimitedChar( CUtlCharConversion *pConv ); + + // This will return the # of characters of the string about to be read out + // NOTE: The count will *include* the terminating 0!! + // In binary mode, it's the number of characters until the next 0 + // In text mode, it's the number of characters until the next space. + int PeekStringLength(); + + // This version of PeekStringLength converts \" to \\ and " to \, etc. + // It also reads a " at the beginning and end of the string + // NOTE: The count will *include* the terminating 0!! + // In binary mode, it's the number of characters until the next 0 + // In text mode, it's the number of characters between "s (checking for \") + // Specifying false for bActualSize will return the pre-translated number of characters + // including the delimiters and the escape characters. So, \n counts as 2 characters when bActualSize == false + // and only 1 character when bActualSize == true + int PeekDelimitedStringLength( CUtlCharConversion *pConv, bool bActualSize = true ); + + // Just like scanf, but doesn't work in binary mode + int Scanf( const char* pFmt, ... ); + int VaScanf( const char* pFmt, va_list list ); + + // Eats white space, advances Get index + void EatWhiteSpace(); + + // Eats C++ style comments + bool EatCPPComment(); + + // (For text buffers only) + // Parse a token from the buffer: + // Grab all text that lies between a starting delimiter + ending delimiter + // (skipping whitespace that leads + trails both delimiters). + // If successful, the get index is advanced and the function returns true, + // otherwise the index is not advanced and the function returns false. + bool ParseToken( const char *pStartingDelim, const char *pEndingDelim, char* pString, int nMaxLen ); + + // Advance the get index until after the particular string is found + // Do not eat whitespace before starting. Return false if it failed + // String test is case-insensitive. + bool GetToken( const char *pToken ); + + // Parses the next token, given a set of character breaks to stop at + // Returns the length of the token parsed in bytes (-1 if none parsed) + int ParseToken( characterset_t *pBreaks, char *pTokenBuf, int nMaxLen, bool bParseComments = true ); + + // Write stuff in + // Binary mode: it'll just write the bits directly in, and strings will be + // written with a null terminating character + // Text mode: it'll convert the numbers to text versions + // PutString will not write a terminating character + void PutChar( char c ); + void PutUnsignedChar( unsigned char uc ); + void PutShort( short s ); + void PutUnsignedShort( unsigned short us ); + void PutInt( int i ); + void PutInt64( int64 i ); + void PutUnsignedInt( unsigned int u ); + void PutFloat( float f ); + void PutDouble( double d ); + void PutPtr( void * ); // Writes the pointer, not the pointed to + void PutString( const char* pString ); + void Put( const void* pMem, int size ); + + // Used for putting objects that have a byteswap datadesc defined + template <typename T> void PutObjects( T *src, int count = 1 ); + + // This version of PutString converts \ to \\ and " to \", etc. + // It also places " at the beginning and end of the string + void PutDelimitedString( CUtlCharConversion *pConv, const char *pString ); + void PutDelimitedChar( CUtlCharConversion *pConv, char c ); + + // Just like printf, writes a terminating zero in binary mode + void Printf( const char* pFmt, ... ) FMTFUNCTION( 2, 3 ); + void VaPrintf( const char* pFmt, va_list list ); + + // What am I writing (put)/reading (get)? + void* PeekPut( int offset = 0 ); + const void* PeekGet( int offset = 0 ) const; + const void* PeekGet( int nMaxSize, int nOffset ); + + // Where am I writing (put)/reading (get)? + int TellPut( ) const; + int TellGet( ) const; + + // What's the most I've ever written? + int TellMaxPut( ) const; + + // How many bytes remain to be read? + // NOTE: This is not accurate for streaming text files; it overshoots + int GetBytesRemaining() const; + + // Change where I'm writing (put)/reading (get) + void SeekPut( SeekType_t type, int offset ); + void SeekGet( SeekType_t type, int offset ); + + // Buffer base + const void* Base() const; + void* Base(); + + // memory allocation size, does *not* reflect size written or read, + // use TellPut or TellGet for that + int Size() const; + + // Am I a text buffer? + bool IsText() const; + + // Can I grow if I'm externally allocated? + bool IsGrowable() const; + + // Am I valid? (overflow or underflow error), Once invalid it stays invalid + bool IsValid() const; + + // Do I contain carriage return/linefeeds? + bool ContainsCRLF() const; + + // Am I read-only + bool IsReadOnly() const; + + // Converts a buffer from a CRLF buffer to a CR buffer (and back) + // Returns false if no conversion was necessary (and outBuf is left untouched) + // If the conversion occurs, outBuf will be cleared. + bool ConvertCRLF( CUtlBuffer &outBuf ); + + // Push/pop pretty-printing tabs + void PushTab(); + void PopTab(); + + // Temporarily disables pretty print + void EnableTabs( bool bEnable ); + +#if !defined( _GAMECONSOLE ) + // Swap my internal memory with another buffer, + // and copy all of its other members + void SwapCopy( CUtlBuffer &other ) ; +#endif + +protected: + // error flags + enum + { + PUT_OVERFLOW = 0x1, + GET_OVERFLOW = 0x2, + MAX_ERROR_FLAG = GET_OVERFLOW, + }; + + void SetOverflowFuncs( UtlBufferOverflowFunc_t getFunc, UtlBufferOverflowFunc_t putFunc ); + + bool OnPutOverflow( int nSize ); + bool OnGetOverflow( int nSize ); + +protected: + // Checks if a get/put is ok + bool CheckPut( int size ); + bool CheckGet( int size ); + + // NOTE: Pass in nPut here even though it is just a copy of m_Put. This is almost always called immediately + // after modifying m_Put and this lets it stay in a register + void AddNullTermination( int nPut ); + + // Methods to help with pretty-printing + bool WasLastCharacterCR(); + void PutTabs(); + + // Help with delimited stuff + char GetDelimitedCharInternal( CUtlCharConversion *pConv ); + void PutDelimitedCharInternal( CUtlCharConversion *pConv, char c ); + + // Default overflow funcs + bool PutOverflow( int nSize ); + bool GetOverflow( int nSize ); + + // Does the next bytes of the buffer match a pattern? + bool PeekStringMatch( int nOffset, const char *pString, int nLen ); + + // Peek size of line to come, check memory bound + int PeekLineLength(); + + // How much whitespace should I skip? + int PeekWhiteSpace( int nOffset ); + + // Checks if a peek get is ok + bool CheckPeekGet( int nOffset, int nSize ); + + // Call this to peek arbitrarily long into memory. It doesn't fail unless + // it can't read *anything* new + bool CheckArbitraryPeekGet( int nOffset, int &nIncrement ); + + template <typename T> void GetType( T& dest ); + template <typename T> void GetTypeBin( T& dest ); + template <typename T> bool GetTypeText( T &value, int nRadix = 10 ); + template <typename T> void GetObject( T *src ); + + template <typename T> void PutType( T src ); + template <typename T> void PutTypeBin( T src ); + template <typename T> void PutObject( T *src ); + + // be sure to also update the copy constructor + // and SwapCopy() when adding members. + CUtlMemory<unsigned char> m_Memory; + int m_Get; + int m_Put; + + unsigned char m_Error; + unsigned char m_Flags; + unsigned char m_Reserved; +#if defined( _GAMECONSOLE ) + unsigned char pad; +#endif + + int m_nTab; + int m_nMaxPut; + int m_nOffset; + + UtlBufferOverflowFunc_t m_GetOverflowFunc; + UtlBufferOverflowFunc_t m_PutOverflowFunc; + + CByteswap m_Byteswap; +}; + + +// Stream style output operators for CUtlBuffer +inline CUtlBuffer &operator<<( CUtlBuffer &b, char v ) +{ + b.PutChar( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned char v ) +{ + b.PutUnsignedChar( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, short v ) +{ + b.PutShort( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned short v ) +{ + b.PutUnsignedShort( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, int v ) +{ + b.PutInt( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, unsigned int v ) +{ + b.PutUnsignedInt( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, float v ) +{ + b.PutFloat( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, double v ) +{ + b.PutDouble( v ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, const char *pv ) +{ + b.PutString( pv ); + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, const Vector &v ) +{ + b << v.x << " " << v.y << " " << v.z; + return b; +} + +inline CUtlBuffer &operator<<( CUtlBuffer &b, const Vector2D &v ) +{ + b << v.x << " " << v.y; + return b; +} + + +class CUtlInplaceBuffer : public CUtlBuffer +{ +public: + CUtlInplaceBuffer( int growSize = 0, int initSize = 0, int nFlags = 0 ); + + // + // Routines returning buffer-inplace-pointers + // +public: + // + // Upon success, determines the line length, fills out the pointer to the + // beginning of the line and the line length, advances the "get" pointer + // offset by the line length and returns "true". + // + // If end of file is reached or upon error returns "false". + // + // Note: the returned length of the line is at least one character because the + // trailing newline characters are also included as part of the line. + // + // Note: the pointer returned points into the local memory of this buffer, in + // case the buffer gets relocated or destroyed the pointer becomes invalid. + // + // e.g.: ------------- + // + // char *pszLine; + // int nLineLen; + // while ( pUtlInplaceBuffer->InplaceGetLinePtr( &pszLine, &nLineLen ) ) + // { + // ... + // } + // + // ------------- + // + // @param ppszInBufferPtr on return points into this buffer at start of line + // @param pnLineLength on return holds num bytes accessible via (*ppszInBufferPtr) + // + // @returns true if line was successfully read + // false when EOF is reached or error occurs + // + bool InplaceGetLinePtr( /* out */ char **ppszInBufferPtr, /* out */ int *pnLineLength ); + + // + // Determines the line length, advances the "get" pointer offset by the line length, + // replaces the newline character with null-terminator and returns the initial pointer + // to now null-terminated line. + // + // If end of file is reached or upon error returns NULL. + // + // Note: the pointer returned points into the local memory of this buffer, in + // case the buffer gets relocated or destroyed the pointer becomes invalid. + // + // e.g.: ------------- + // + // while ( char *pszLine = pUtlInplaceBuffer->InplaceGetLinePtr() ) + // { + // ... + // } + // + // ------------- + // + // @returns ptr-to-zero-terminated-line if line was successfully read and buffer modified + // NULL when EOF is reached or error occurs + // + char * InplaceGetLinePtr( void ); +}; + + +//----------------------------------------------------------------------------- +// Where am I reading? +//----------------------------------------------------------------------------- +inline int CUtlBuffer::TellGet( ) const +{ + return m_Get; +} + + +//----------------------------------------------------------------------------- +// How many bytes remain to be read? +//----------------------------------------------------------------------------- +inline int CUtlBuffer::GetBytesRemaining() const +{ + return m_nMaxPut - TellGet(); +} + + +//----------------------------------------------------------------------------- +// What am I reading? +//----------------------------------------------------------------------------- +inline const void* CUtlBuffer::PeekGet( int offset ) const +{ + return &m_Memory[ m_Get + offset - m_nOffset ]; +} + + +//----------------------------------------------------------------------------- +// Unserialization +//----------------------------------------------------------------------------- + +template <typename T> +inline void CUtlBuffer::GetObject( T *dest ) +{ + if ( CheckGet( sizeof(T) ) ) + { + if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) + { + *dest = *(T *)PeekGet(); + } + else + { + m_Byteswap.SwapFieldsToTargetEndian<T>( dest, (T*)PeekGet() ); + } + m_Get += sizeof(T); + } + else + { + V_memset( &dest, 0, sizeof(T) ); + } +} + + +template <typename T> +inline void CUtlBuffer::GetObjects( T *dest, int count ) +{ + for ( int i = 0; i < count; ++i, ++dest ) + { + GetObject<T>( dest ); + } +} + + +template <typename T> +inline void CUtlBuffer::GetTypeBin( T &dest ) +{ + if ( CheckGet( sizeof(T) ) ) + { + if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) + { + dest = *(T *)PeekGet(); + } + else + { + m_Byteswap.SwapBufferToTargetEndian<T>( &dest, (T*)PeekGet() ); + } + m_Get += sizeof(T); + } + else + { + dest = 0; + } +} + +template <> +inline void CUtlBuffer::GetTypeBin< float >( float &dest ) +{ + if ( CheckGet( sizeof( float ) ) ) + { + uintp pData = (uintp)PeekGet(); + if ( ( IsX360() || IsPS3() ) && ( pData & 0x03 ) ) + { + // handle unaligned read + ((unsigned char*)&dest)[0] = ((unsigned char*)pData)[0]; + ((unsigned char*)&dest)[1] = ((unsigned char*)pData)[1]; + ((unsigned char*)&dest)[2] = ((unsigned char*)pData)[2]; + ((unsigned char*)&dest)[3] = ((unsigned char*)pData)[3]; + } + else + { + // aligned read + dest = *(float *)pData; + } + if ( m_Byteswap.IsSwappingBytes() ) + { + m_Byteswap.SwapBufferToTargetEndian< float >( &dest, &dest ); + } + m_Get += sizeof( float ); + } + else + { + dest = 0; + } +} + +template <> +inline void CUtlBuffer::GetTypeBin< double >( double &dest ) +{ + if ( CheckGet( sizeof( double ) ) ) + { + uintp pData = (uintp)PeekGet(); + if ( ( IsX360() || IsPS3() ) && ( pData & 0x07 ) ) + { + // handle unaligned read + ((unsigned char*)&dest)[0] = ((unsigned char*)pData)[0]; + ((unsigned char*)&dest)[1] = ((unsigned char*)pData)[1]; + ((unsigned char*)&dest)[2] = ((unsigned char*)pData)[2]; + ((unsigned char*)&dest)[3] = ((unsigned char*)pData)[3]; + ((unsigned char*)&dest)[4] = ((unsigned char*)pData)[4]; + ((unsigned char*)&dest)[5] = ((unsigned char*)pData)[5]; + ((unsigned char*)&dest)[6] = ((unsigned char*)pData)[6]; + ((unsigned char*)&dest)[7] = ((unsigned char*)pData)[7]; + } + else + { + // aligned read + dest = *(double *)pData; + } + if ( m_Byteswap.IsSwappingBytes() ) + { + m_Byteswap.SwapBufferToTargetEndian< double >( &dest, &dest ); + } + m_Get += sizeof( double ); + } + else + { + dest = 0; + } +} + +template < class T > +inline T StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + Assert( 0 ); + *ppEnd = pString; + return 0; +} + +template <> +inline int8 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( int8 )strtol( pString, ppEnd, nRadix ); +} + +template <> +inline uint8 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( uint8 )strtoul( pString, ppEnd, nRadix ); +} + +template <> +inline int16 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( int16 )strtol( pString, ppEnd, nRadix ); +} + +template <> +inline uint16 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( uint16 )strtoul( pString, ppEnd, nRadix ); +} + +template <> +inline int32 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( int32 )strtol( pString, ppEnd, nRadix ); +} + +template <> +inline uint32 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + return ( uint32 )strtoul( pString, ppEnd, nRadix ); +} + +template <> +inline int64 StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ +#if defined(_PS3) || defined(POSIX) + return ( int64 )strtoll( pString, ppEnd, nRadix ); +#else // !_PS3 + return ( int64 )_strtoi64( pString, ppEnd, nRadix ); +#endif // _PS3 +} + +template <> +inline float StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + NOTE_UNUSED( nRadix ); + return ( float )strtod( pString, ppEnd ); +} + +template <> +inline double StringToNumber( char *pString, char **ppEnd, int nRadix ) +{ + NOTE_UNUSED( nRadix ); + return ( double )strtod( pString, ppEnd ); +} + +template <typename T> +inline bool CUtlBuffer::GetTypeText( T &value, int nRadix /*= 10*/ ) +{ + // NOTE: This is not bullet-proof; it assumes numbers are < 128 characters + int nLength = 128; + if ( !CheckArbitraryPeekGet( 0, nLength ) ) + { + value = 0; + return false; + } + + char *pStart = (char*)PeekGet(); + char* pEnd = pStart; + value = StringToNumber< T >( pStart, &pEnd, nRadix ); + + int nBytesRead = (int)( pEnd - pStart ); + if ( nBytesRead == 0 ) + return false; + + m_Get += nBytesRead; + return true; +} + +template <typename T> +inline void CUtlBuffer::GetType( T &dest ) +{ + if (!IsText()) + { + GetTypeBin( dest ); + } + else + { + GetTypeText( dest ); + } +} + +inline char CUtlBuffer::GetChar( ) +{ + // LEGACY WARNING: this behaves differently than GetUnsignedChar() + char c; + GetTypeBin( c ); // always reads as binary + return c; +} + +inline unsigned char CUtlBuffer::GetUnsignedChar( ) +{ + // LEGACY WARNING: this behaves differently than GetChar() + unsigned char c; + if (!IsText()) + { + GetTypeBin( c ); + } + else + { + c = ( unsigned char )GetUnsignedShort(); + } + return c; +} + +inline short CUtlBuffer::GetShort( ) +{ + short s; + GetType( s ); + return s; +} + +inline unsigned short CUtlBuffer::GetUnsignedShort( ) +{ + unsigned short s; + GetType( s ); + return s; +} + +inline int CUtlBuffer::GetInt( ) +{ + int i; + GetType( i ); + return i; +} + +inline int64 CUtlBuffer::GetInt64( ) +{ + int64 i; + GetType( i ); + return i; +} + +inline unsigned int CUtlBuffer::GetIntHex( ) +{ + uint i; + if (!IsText()) + { + GetTypeBin( i ); + } + else + { + GetTypeText( i, 16 ); + } + return i; +} + +inline unsigned int CUtlBuffer::GetUnsignedInt( ) +{ + unsigned int i; + GetType( i ); + return i; +} + +inline float CUtlBuffer::GetFloat( ) +{ + float f; + GetType( f ); + return f; +} + +inline double CUtlBuffer::GetDouble( ) +{ + double d; + GetType( d ); + return d; +} + +inline void *CUtlBuffer::GetPtr( ) +{ + void *p; + // LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal +#ifndef X64BITS + p = ( void* )GetUnsignedInt(); +#else + p = ( void* )GetInt64(); +#endif + return p; +} + +//----------------------------------------------------------------------------- +// Where am I writing? +//----------------------------------------------------------------------------- +inline unsigned char CUtlBuffer::GetFlags() const +{ + return m_Flags; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::IsExternallyAllocated() const +{ + return m_Memory.IsExternallyAllocated(); +} + + +//----------------------------------------------------------------------------- +// Where am I writing? +//----------------------------------------------------------------------------- +inline int CUtlBuffer::TellPut( ) const +{ + return m_Put; +} + + +//----------------------------------------------------------------------------- +// What's the most I've ever written? +//----------------------------------------------------------------------------- +inline int CUtlBuffer::TellMaxPut( ) const +{ + return m_nMaxPut; +} + + +//----------------------------------------------------------------------------- +// What am I reading? +//----------------------------------------------------------------------------- +inline void* CUtlBuffer::PeekPut( int offset ) +{ + return &m_Memory[m_Put + offset - m_nOffset]; +} + + +//----------------------------------------------------------------------------- +// Various put methods +//----------------------------------------------------------------------------- + +template <typename T> +inline void CUtlBuffer::PutObject( T *src ) +{ + if ( CheckPut( sizeof(T) ) ) + { + if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) + { + *(T *)PeekPut() = *src; + } + else + { + m_Byteswap.SwapFieldsToTargetEndian<T>( (T*)PeekPut(), src ); + } + m_Put += sizeof(T); + AddNullTermination( m_Put ); + } +} + + +template <typename T> +inline void CUtlBuffer::PutObjects( T *src, int count ) +{ + for ( int i = 0; i < count; ++i, ++src ) + { + PutObject<T>( src ); + } +} + + +template <typename T> +inline void CUtlBuffer::PutTypeBin( T src ) +{ + if ( CheckPut( sizeof(T) ) ) + { + if ( !m_Byteswap.IsSwappingBytes() || ( sizeof( T ) == 1 ) ) + { + *(T *)PeekPut() = src; + } + else + { + m_Byteswap.SwapBufferToTargetEndian<T>( (T*)PeekPut(), &src ); + } + m_Put += sizeof(T); + AddNullTermination( m_Put ); + } +} + +#if defined( _GAMECONSOLE ) +template <> +inline void CUtlBuffer::PutTypeBin< float >( float src ) +{ + if ( CheckPut( sizeof( src ) ) ) + { + if ( m_Byteswap.IsSwappingBytes() ) + { + m_Byteswap.SwapBufferToTargetEndian<float>( &src, &src ); + } + + // + // Write the data + // + unsigned pData = (unsigned)PeekPut(); + if ( pData & 0x03 ) + { + // handle unaligned write + byte* dst = (byte*)pData; + byte* srcPtr = (byte*)&src; + dst[0] = srcPtr[0]; + dst[1] = srcPtr[1]; + dst[2] = srcPtr[2]; + dst[3] = srcPtr[3]; + } + else + { + *(float *)pData = src; + } + + m_Put += sizeof(float); + AddNullTermination( m_Put ); + } +} + +template <> +inline void CUtlBuffer::PutTypeBin< double >( double src ) +{ + if ( CheckPut( sizeof( src ) ) ) + { + if ( m_Byteswap.IsSwappingBytes() ) + { + m_Byteswap.SwapBufferToTargetEndian<double>( &src, &src ); + } + + // + // Write the data + // + unsigned pData = (unsigned)PeekPut(); + if ( pData & 0x07 ) + { + // handle unaligned write + byte* dst = (byte*)pData; + byte* srcPtr = (byte*)&src; + dst[0] = srcPtr[0]; + dst[1] = srcPtr[1]; + dst[2] = srcPtr[2]; + dst[3] = srcPtr[3]; + dst[4] = srcPtr[4]; + dst[5] = srcPtr[5]; + dst[6] = srcPtr[6]; + dst[7] = srcPtr[7]; + } + else + { + *(double *)pData = src; + } + + m_Put += sizeof(double); + AddNullTermination( m_Put ); + } +} +#endif + +template <typename T> +inline void CUtlBuffer::PutType( T src ) +{ + if (!IsText()) + { + PutTypeBin( src ); + } + else + { + Printf( GetFmtStr< T >(), src ); + } +} + +//----------------------------------------------------------------------------- +// Methods to help with pretty-printing +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::WasLastCharacterCR() +{ + if ( !IsText() || (TellPut() == 0) ) + return false; + return ( *( const char * )PeekPut( -1 ) == '\n' ); +} + +inline void CUtlBuffer::PutTabs() +{ + int nTabCount = ( m_Flags & AUTO_TABS_DISABLED ) ? 0 : m_nTab; + for (int i = nTabCount; --i >= 0; ) + { + PutTypeBin<char>( '\t' ); + } +} + + +//----------------------------------------------------------------------------- +// Push/pop pretty-printing tabs +//----------------------------------------------------------------------------- +inline void CUtlBuffer::PushTab( ) +{ + ++m_nTab; +} + +inline void CUtlBuffer::PopTab() +{ + if ( --m_nTab < 0 ) + { + m_nTab = 0; + } +} + + +//----------------------------------------------------------------------------- +// Temporarily disables pretty print +//----------------------------------------------------------------------------- +inline void CUtlBuffer::EnableTabs( bool bEnable ) +{ + if ( bEnable ) + { + m_Flags &= ~AUTO_TABS_DISABLED; + } + else + { + m_Flags |= AUTO_TABS_DISABLED; + } +} + +inline void CUtlBuffer::PutChar( char c ) +{ + if ( WasLastCharacterCR() ) + { + PutTabs(); + } + + PutTypeBin( c ); +} + +inline void CUtlBuffer::PutUnsignedChar( unsigned char c ) +{ + if (!IsText()) + { + PutTypeBin( c ); + } + else + { + PutUnsignedShort( c ); + } +} + +inline void CUtlBuffer::PutShort( short s ) +{ + PutType( s ); +} + +inline void CUtlBuffer::PutUnsignedShort( unsigned short s ) +{ + PutType( s ); +} + +inline void CUtlBuffer::PutInt( int i ) +{ + PutType( i ); +} + +inline void CUtlBuffer::PutInt64( int64 i ) +{ + PutType( i ); +} + +inline void CUtlBuffer::PutUnsignedInt( unsigned int u ) +{ + PutType( u ); +} + +inline void CUtlBuffer::PutFloat( float f ) +{ + PutType( f ); +} + +inline void CUtlBuffer::PutDouble( double d ) +{ + PutType( d ); +} + +inline void CUtlBuffer::PutPtr( void *p ) +{ + // LEGACY WARNING: in text mode, PutPtr writes 32 bit pointers in hex, while GetPtr reads 32 or 64 bit pointers in decimal + if (!IsText()) + { + PutTypeBin( p ); + } + else + { + Printf( "0x%p", p ); + } +} + +//----------------------------------------------------------------------------- +// Am I a text buffer? +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::IsText() const +{ + return (m_Flags & TEXT_BUFFER) != 0; +} + + +//----------------------------------------------------------------------------- +// Can I grow if I'm externally allocated? +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::IsGrowable() const +{ + return (m_Flags & EXTERNAL_GROWABLE) != 0; +} + + +//----------------------------------------------------------------------------- +// Am I valid? (overflow or underflow error), Once invalid it stays invalid +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::IsValid() const +{ + return m_Error == 0; +} + + +//----------------------------------------------------------------------------- +// Do I contain carriage return/linefeeds? +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::ContainsCRLF() const +{ + return IsText() && ((m_Flags & CONTAINS_CRLF) != 0); +} + + +//----------------------------------------------------------------------------- +// Am I read-only +//----------------------------------------------------------------------------- +inline bool CUtlBuffer::IsReadOnly() const +{ + return (m_Flags & READ_ONLY) != 0; +} + + +//----------------------------------------------------------------------------- +// Buffer base and size +//----------------------------------------------------------------------------- +inline const void* CUtlBuffer::Base() const +{ + return m_Memory.Base(); +} + +inline void* CUtlBuffer::Base() +{ + return m_Memory.Base(); +} + +inline int CUtlBuffer::Size() const +{ + return m_Memory.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Clears out the buffer; frees memory +//----------------------------------------------------------------------------- +inline void CUtlBuffer::Clear() +{ + m_Get = 0; + m_Put = 0; + m_Error = 0; + m_nOffset = 0; + m_nMaxPut = -1; + AddNullTermination( m_Put ); +} + +inline void CUtlBuffer::Purge() +{ + m_Get = 0; + m_Put = 0; + m_nOffset = 0; + m_nMaxPut = 0; + m_Error = 0; + m_Memory.Purge(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +inline void *CUtlBuffer::AccessForDirectRead( int nBytes ) +{ + Assert( m_Get == 0 && m_Put == 0 && m_nMaxPut == 0 ); + EnsureCapacity( nBytes ); + m_nMaxPut = nBytes; + return Base(); +} + +inline void *CUtlBuffer::Detach() +{ + void *p = m_Memory.Detach(); + Clear(); + return p; +} + +//----------------------------------------------------------------------------- + +inline void CUtlBuffer::Spew( ) +{ + SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + + char pTmpLine[1024]; + while( IsValid() && GetBytesRemaining() ) + { + V_memset( pTmpLine, 0, sizeof(pTmpLine) ); + Get( pTmpLine, MIN( ( size_t )GetBytesRemaining(), sizeof(pTmpLine)-1 ) ); + Msg( _T( "%s" ), pTmpLine ); + } +} + +#if !defined(_GAMECONSOLE) +inline void CUtlBuffer::SwapCopy( CUtlBuffer &other ) +{ + m_Get = other.m_Get; + m_Put = other.m_Put; + m_Error = other.m_Error; + m_Flags = other.m_Flags; + m_Reserved = other.m_Reserved; + m_nTab = other.m_nTab; + m_nMaxPut = other.m_nMaxPut; + m_nOffset = other.m_nOffset; + m_GetOverflowFunc = other.m_GetOverflowFunc; + m_PutOverflowFunc = other.m_PutOverflowFunc; + m_Byteswap = other.m_Byteswap; + + m_Memory.Swap( other.m_Memory ); +} +#endif + +#endif // UTLBUFFER_H + diff --git a/external/vpc/public/tier1/utldict.h b/external/vpc/public/tier1/utldict.h new file mode 100644 index 0000000..cb6d4f1 --- /dev/null +++ b/external/vpc/public/tier1/utldict.h @@ -0,0 +1,338 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======// +// +// Purpose: A dictionary mapping from symbol to structure +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLDICT_H +#define UTLDICT_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "tier1/utlmap.h" + +// Include this because tons of code was implicitly getting utlsymbol or utlvector via utldict.h +#include "tier1/utlsymbol.h" + +#include "tier0/memdbgon.h" + +enum EDictCompareType +{ + k_eDictCompareTypeCaseSensitive=0, + k_eDictCompareTypeCaseInsensitive=1, + k_eDictCompareTypeFilenames // Slashes and backslashes count as the same character.. +}; + + +//----------------------------------------------------------------------------- +// A dictionary mapping from symbol to structure +//----------------------------------------------------------------------------- +#define FOR_EACH_DICT( dictName, iteratorName ) \ + for( int iteratorName=dictName.First(); iteratorName != dictName.InvalidIndex(); iteratorName = dictName.Next( iteratorName ) ) + +// faster iteration, but in an unspecified order +#define FOR_EACH_DICT_FAST( dictName, iteratorName ) \ + for ( int iteratorName = 0; iteratorName < dictName.MaxElement(); ++iteratorName ) if ( !dictName.IsValidIndex( iteratorName ) ) continue; else + + +//----------------------------------------------------------------------------- +// A dictionary mapping from symbol to structure +//----------------------------------------------------------------------------- +template <class T, class I = int > +class CUtlDict +{ +public: + // constructor, destructor + // Left at growSize = 0, the memory will first allocate 1 element and double in size + // at each increment. + CUtlDict( int compareType = k_eDictCompareTypeCaseInsensitive, int growSize = 0, int initSize = 0 ); + ~CUtlDict( ); + + void EnsureCapacity( int ); + + // gets particular elements + T& Element( I i ); + const T& Element( I i ) const; + T& operator[]( I i ); + const T& operator[]( I i ) const; + + // gets element names + char *GetElementName( I i ); + char const *GetElementName( I i ) const; + + void SetElementName( I i, char const *pName ); + + // Number of elements + unsigned int Count() const; + + // Checks if a node is valid and in the tree + bool IsValidIndex( I i ) const; + + // Invalid index + static I InvalidIndex(); + + // Insert method (inserts in order) + I Insert( const char *pName, const T &element ); + I Insert( const char *pName ); + + // Find method + I Find( const char *pName ) const; + + // Remove methods + void RemoveAt( I i ); + void Remove( const char *pName ); + void RemoveAll( ); + + // Purge memory + void Purge(); + void PurgeAndDeleteElements(); // Call delete on each element. + + // Iteration methods + I First() const; + I Next( I i ) const; + + // Nested typedefs, for code that might need + // to fish out the index type from a given dict + typedef I IndexType_t; + +protected: + typedef CUtlMap<const char *, T, I> DictElementMap_t; + DictElementMap_t m_Elements; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template <class T, class I> +CUtlDict<T, I>::CUtlDict( int compareType, int growSize, int initSize ) : m_Elements( growSize, initSize ) +{ + if ( compareType == k_eDictCompareTypeFilenames ) + { + m_Elements.SetLessFunc( CaselessStringLessThanIgnoreSlashes ); + } + else if ( compareType == k_eDictCompareTypeCaseInsensitive ) + { + m_Elements.SetLessFunc( CaselessStringLessThan ); + } + else + { + m_Elements.SetLessFunc( StringLessThan ); + } +} + +template <class T, class I> +CUtlDict<T, I>::~CUtlDict() +{ + Purge(); +} + +template <class T, class I> +inline void CUtlDict<T, I>::EnsureCapacity( int num ) +{ + return m_Elements.EnsureCapacity( num ); +} + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- +template <class T, class I> +inline T& CUtlDict<T, I>::Element( I i ) +{ + return m_Elements[i]; +} + +template <class T, class I> +inline const T& CUtlDict<T, I>::Element( I i ) const +{ + return m_Elements[i]; +} + +//----------------------------------------------------------------------------- +// gets element names +//----------------------------------------------------------------------------- +template <class T, class I> +inline char *CUtlDict<T, I>::GetElementName( I i ) +{ + return (char *)m_Elements.Key( i ); +} + +template <class T, class I> +inline char const *CUtlDict<T, I>::GetElementName( I i ) const +{ + return m_Elements.Key( i ); +} + +template <class T, class I> +inline T& CUtlDict<T, I>::operator[]( I i ) +{ + return Element(i); +} + +template <class T, class I> +inline const T & CUtlDict<T, I>::operator[]( I i ) const +{ + return Element(i); +} + +template <class T, class I> +inline void CUtlDict<T, I>::SetElementName( I i, char const *pName ) +{ + MEM_ALLOC_CREDIT_CLASS(); + // TODO: This makes a copy of the old element + // TODO: This relies on the rb tree putting the most recently + // removed element at the head of the insert list + free( (void *)m_Elements.Key( i ) ); + m_Elements.Reinsert( strdup( pName ), i ); +} + +//----------------------------------------------------------------------------- +// Num elements +//----------------------------------------------------------------------------- +template <class T, class I> +inline unsigned int CUtlDict<T, I>::Count() const +{ + return m_Elements.Count(); +} + + +//----------------------------------------------------------------------------- +// Checks if a node is valid and in the tree +//----------------------------------------------------------------------------- +template <class T, class I> +inline bool CUtlDict<T, I>::IsValidIndex( I i ) const +{ + return m_Elements.IsValidIndex(i); +} + + +//----------------------------------------------------------------------------- +// Invalid index +//----------------------------------------------------------------------------- +template <class T, class I> +inline I CUtlDict<T, I>::InvalidIndex() +{ + return DictElementMap_t::InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// Delete a node from the tree +//----------------------------------------------------------------------------- +template <class T, class I> +void CUtlDict<T, I>::RemoveAt(I elem) +{ + free( (void *)m_Elements.Key( elem ) ); + m_Elements.RemoveAt(elem); +} + + +//----------------------------------------------------------------------------- +// remove a node in the tree +//----------------------------------------------------------------------------- +template <class T, class I> void CUtlDict<T, I>::Remove( const char *search ) +{ + I node = Find( search ); + if (node != InvalidIndex()) + { + RemoveAt(node); + } +} + + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree +//----------------------------------------------------------------------------- +template <class T, class I> +void CUtlDict<T, I>::RemoveAll() +{ + typename DictElementMap_t::IndexType_t index = m_Elements.FirstInorder(); + while ( index != m_Elements.InvalidIndex() ) + { + const char *pKey = m_Elements.Key( index ); + free( const_cast<char*>(pKey) ); + index = m_Elements.NextInorder( index ); + } + + m_Elements.RemoveAll(); +} + +template <class T, class I> +void CUtlDict<T, I>::Purge() +{ + RemoveAll(); +} + + +template <class T, class I> +void CUtlDict<T, I>::PurgeAndDeleteElements() +{ + // Delete all the elements. + I index = m_Elements.FirstInorder(); + while ( index != m_Elements.InvalidIndex() ) + { + const char* pKey = m_Elements.Key( index ); + free( const_cast<char*>(pKey) ); + delete m_Elements[index]; + index = m_Elements.NextInorder( index ); + } + + m_Elements.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// inserts a node into the tree +//----------------------------------------------------------------------------- +template <class T, class I> +I CUtlDict<T, I>::Insert( const char *pName, const T &element ) +{ + MEM_ALLOC_CREDIT_CLASS(); + return m_Elements.Insert( strdup( pName ), element ); +} + +template <class T, class I> +I CUtlDict<T, I>::Insert( const char *pName ) +{ + MEM_ALLOC_CREDIT_CLASS(); + return m_Elements.Insert( strdup( pName ) ); +} + + +//----------------------------------------------------------------------------- +// finds a node in the tree +//----------------------------------------------------------------------------- +template <class T, class I> +I CUtlDict<T, I>::Find( const char *pName ) const +{ + MEM_ALLOC_CREDIT_CLASS(); + if ( pName ) + return m_Elements.Find( pName ); + else + return InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// Iteration methods +//----------------------------------------------------------------------------- +template <class T, class I> +I CUtlDict<T, I>::First() const +{ + return m_Elements.FirstInorder(); +} + +template <class T, class I> +I CUtlDict<T, I>::Next( I i ) const +{ + return m_Elements.NextInorder(i); +} + +#include "tier0/memdbgoff.h" + +#endif // UTLDICT_H diff --git a/external/vpc/public/tier1/utlenvelope.h b/external/vpc/public/tier1/utlenvelope.h new file mode 100644 index 0000000..28e434b --- /dev/null +++ b/external/vpc/public/tier1/utlenvelope.h @@ -0,0 +1,241 @@ +//========== Copyright � 2005, Valve Corporation, All rights reserved. ======== +// +// Purpose: A class to wrap data for transport over a boundary like a thread +// or window. +// +//============================================================================= + +#include "tier1/utlstring.h" +#include "tier0/basetypes.h" + +#ifndef UTLENVELOPE_H +#define UTLENVELOPE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +//----------------------------------------------------------------------------- + +class CUtlDataEnvelope +{ +public: + CUtlDataEnvelope( const void *pData, int nBytes ); + CUtlDataEnvelope( const CUtlDataEnvelope &from ); + ~CUtlDataEnvelope(); + + CUtlDataEnvelope &operator=( const CUtlDataEnvelope &from ); + + operator void *(); + operator void *() const; + +private: + void Assign( const void *pData, int nBytes ); + void Assign( const CUtlDataEnvelope &from ); + void Purge(); + + // TODO: switch to a reference counted array? + union + { + byte *m_pData; + byte m_data[4]; + }; + int m_nBytes; +}; + + +//----------------------------------------------------------------------------- + +template <typename T> +class CUtlEnvelope : protected CUtlDataEnvelope +{ +public: + CUtlEnvelope( const T *pData, int nElems = 1 ); + CUtlEnvelope( const CUtlEnvelope<T> &from ); + + CUtlEnvelope<T> &operator=( const CUtlEnvelope<T> &from ); + + operator T *(); + operator T *() const; + + operator void *(); + operator void *() const; +}; + +//----------------------------------------------------------------------------- + +template <> +class CUtlEnvelope<const char *> +{ +public: + CUtlEnvelope( const char *pData ) + { + m_string = pData; + } + + CUtlEnvelope( const CUtlEnvelope<const char *> &from ) + { + m_string = from.m_string; + } + + CUtlEnvelope<const char *> &operator=( const CUtlEnvelope<const char *> &from ) + { + m_string = from.m_string; + return *this; + } + + operator char *() + { + return (char *) m_string.Get(); + } + + operator char *() const + { + return (char *) m_string.Get(); + } + + operator void *() + { + return (void *) m_string.Get(); + } + + operator void *() const + { + return (void *) m_string.Get(); + } + +private: + CUtlString m_string; +}; + +//----------------------------------------------------------------------------- + +#include "tier0/memdbgon.h" + +inline void CUtlDataEnvelope::Assign( const void *pData, int nBytes ) +{ + if ( pData ) + { + m_nBytes = nBytes; + if ( m_nBytes > 4 ) + { + m_pData = new byte[nBytes]; + memcpy( m_pData, pData, nBytes ); + } + else + { + memcpy( m_data, pData, nBytes ); + } + } + else + { + m_pData = NULL; + m_nBytes = 0; + } +} + +inline void CUtlDataEnvelope::Assign( const CUtlDataEnvelope &from ) +{ + Assign( from.operator void *(), from.m_nBytes ); +} + +inline void CUtlDataEnvelope::Purge() +{ + if (m_nBytes > 4) + delete [] m_pData; + m_nBytes = 0; +} + +inline CUtlDataEnvelope::CUtlDataEnvelope( const void *pData, int nBytes ) +{ + Assign( pData, nBytes ); +} + +inline CUtlDataEnvelope::CUtlDataEnvelope( const CUtlDataEnvelope &from ) +{ + Assign( from ); +} + +inline CUtlDataEnvelope::~CUtlDataEnvelope() +{ + Purge(); +} + +inline CUtlDataEnvelope &CUtlDataEnvelope::operator=( const CUtlDataEnvelope &from ) +{ + Purge(); + Assign( from ); + return *this; +} + +inline CUtlDataEnvelope::operator void *() +{ + if ( !m_nBytes ) + { + return NULL; + } + + return ( m_nBytes > 4) ? m_pData : m_data; +} + +inline CUtlDataEnvelope::operator void *() const +{ + if ( !m_nBytes ) + { + return NULL; + } + + return ( m_nBytes > 4) ? (void *)m_pData : (void *)m_data; +} + +//----------------------------------------------------------------------------- + +template <typename T> +inline CUtlEnvelope<T>::CUtlEnvelope( const T *pData, int nElems ) + : CUtlDataEnvelope( pData, sizeof(T) * nElems ) +{ +} + +template <typename T> +inline CUtlEnvelope<T>::CUtlEnvelope( const CUtlEnvelope<T> &from ) + : CUtlDataEnvelope( from ) +{ + +} + +template <typename T> +inline CUtlEnvelope<T> &CUtlEnvelope<T>::operator=( const CUtlEnvelope<T> &from ) +{ + CUtlDataEnvelope::operator=( from ); + return *this; +} + +template <typename T> +inline CUtlEnvelope<T>::operator T *() +{ + return (T *)CUtlDataEnvelope::operator void *(); +} + +template <typename T> +inline CUtlEnvelope<T>::operator T *() const +{ + return (T *)( (const_cast<CUtlEnvelope<T> *>(this))->operator T *() ); +} + +template <typename T> +inline CUtlEnvelope<T>::operator void *() +{ + return CUtlDataEnvelope::operator void *(); +} + +template <typename T> +inline CUtlEnvelope<T>::operator void *() const +{ + return ( (const_cast<CUtlEnvelope<T> *>(this))->operator void *() ); +} + +//----------------------------------------------------------------------------- + +#include "tier0/memdbgoff.h" + +#endif // UTLENVELOPE_H diff --git a/external/vpc/public/tier1/utlfixedmemory.h b/external/vpc/public/tier1/utlfixedmemory.h new file mode 100644 index 0000000..a124889 --- /dev/null +++ b/external/vpc/public/tier1/utlfixedmemory.h @@ -0,0 +1,354 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable memory class. +//===========================================================================// + +#ifndef UTLFIXEDMEMORY_H +#define UTLFIXEDMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "tier0/platform.h" + +#include "tier0/memalloc.h" +#include "tier0/memdbgon.h" + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + +//----------------------------------------------------------------------------- + +#ifdef UTLFIXEDMEMORY_TRACK +#define UTLFIXEDMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "||Sum of all UtlFixedMemory||", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#define UTLFIXEDMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "||Sum of all UtlFixedMemory||", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 ) +#else +#define UTLFIXEDMEMORY_TRACK_ALLOC() ((void)0) +#define UTLFIXEDMEMORY_TRACK_FREE() ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// The CUtlFixedMemory class: +// A growable memory class that allocates non-sequential blocks, but is indexed sequentially +//----------------------------------------------------------------------------- +template< class T > +class CUtlFixedMemory +{ +public: + // constructor, destructor + CUtlFixedMemory( int nGrowSize = 0, int nInitSize = 0 ); + ~CUtlFixedMemory(); + + // Set the size by which the memory grows + void Init( int nGrowSize = 0, int nInitSize = 0 ); + + // here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL + T* Base() { return NULL; } + const T* Base() const { return NULL; } + +protected: + struct BlockHeader_t; + +public: + class Iterator_t + { + public: + Iterator_t( BlockHeader_t *p, int i ) : m_pBlockHeader( p ), m_nIndex( i ) {} + BlockHeader_t *m_pBlockHeader; + int m_nIndex; + + bool operator==( const Iterator_t it ) const { return m_pBlockHeader == it.m_pBlockHeader && m_nIndex == it.m_nIndex; } + bool operator!=( const Iterator_t it ) const { return m_pBlockHeader != it.m_pBlockHeader || m_nIndex != it.m_nIndex; } + }; + Iterator_t First() const { return m_pBlocks ? Iterator_t( m_pBlocks, 0 ) : InvalidIterator(); } + Iterator_t Next( const Iterator_t &it ) const + { + Assert( IsValidIterator( it ) ); + if ( !IsValidIterator( it ) ) + return InvalidIterator(); + + BlockHeader_t * RESTRICT pHeader = it.m_pBlockHeader; + if ( it.m_nIndex + 1 < pHeader->m_nBlockSize ) + return Iterator_t( pHeader, it.m_nIndex + 1 ); + + return pHeader->m_pNext ? Iterator_t( pHeader->m_pNext, 0 ) : InvalidIterator(); + } + int GetIndex( const Iterator_t &it ) const + { + Assert( IsValidIterator( it ) ); + if ( !IsValidIterator( it ) ) + return InvalidIndex(); + + return ( int )( HeaderToBlock( it.m_pBlockHeader ) + it.m_nIndex ); + } + bool IsIdxAfter( int i, const Iterator_t &it ) const + { + Assert( IsValidIterator( it ) ); + if ( !IsValidIterator( it ) ) + return false; + + if ( IsInBlock( i, it.m_pBlockHeader ) ) + return i > GetIndex( it ); + + for ( BlockHeader_t * RESTRICT pbh = it.m_pBlockHeader->m_pNext; pbh; pbh = pbh->m_pNext ) + { + if ( IsInBlock( i, pbh ) ) + return true; + } + return false; + } + bool IsValidIterator( const Iterator_t &it ) const { return it.m_pBlockHeader && it.m_nIndex >= 0 && it.m_nIndex < it.m_pBlockHeader->m_nBlockSize; } + Iterator_t InvalidIterator() const { return Iterator_t( NULL, -1 ); } + + // element access + T& operator[]( int i ); + const T& operator[]( int i ) const; + T& Element( int i ); + const T& Element( int i ) const; + + // Can we use this index? + bool IsIdxValid( int i ) const; + + // Specify the invalid ('null') index that we'll only return on failure + static const int INVALID_INDEX = 0; // For use with COMPILE_TIME_ASSERT + static int InvalidIndex() { return INVALID_INDEX; } + + // Size + int NumAllocated() const; + int Count() const { return NumAllocated(); } + + // Grows memory by max(num,growsize), and returns the allocation index/ptr + void Grow( int num = 1 ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + +protected: + // Fast swap - WARNING: Swap invalidates all ptr-based indices!!! + void Swap( CUtlFixedMemory< T > &mem ); + + bool IsInBlock( int i, BlockHeader_t *pBlockHeader ) const + { + T *p = ( T* )i; + const T *p0 = HeaderToBlock( pBlockHeader ); + return p >= p0 && p < p0 + pBlockHeader->m_nBlockSize; + } + + struct BlockHeader_t + { + BlockHeader_t *m_pNext; + int m_nBlockSize; + }; + + const T *HeaderToBlock( const BlockHeader_t *pHeader ) const { return ( T* )( pHeader + 1 ); } + const BlockHeader_t *BlockToHeader( const T *pBlock ) const { return ( BlockHeader_t* )( pBlock ) - 1; } + + BlockHeader_t* m_pBlocks; + int m_nAllocationCount; + int m_nGrowSize; +}; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T > +CUtlFixedMemory<T>::CUtlFixedMemory( int nGrowSize, int nInitAllocationCount ) +: m_pBlocks( 0 ), m_nAllocationCount( 0 ), m_nGrowSize( 0 ) +{ + Init( nGrowSize, nInitAllocationCount ); +} + +template< class T > +CUtlFixedMemory<T>::~CUtlFixedMemory() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Fast swap - WARNING: Swap invalidates all ptr-based indices!!! +//----------------------------------------------------------------------------- +template< class T > +void CUtlFixedMemory<T>::Swap( CUtlFixedMemory< T > &mem ) +{ + V_swap( m_pBlocks, mem.m_pBlocks ); + V_swap( m_nAllocationCount, mem.m_nAllocationCount ); + V_swap( m_nGrowSize, mem.m_nGrowSize ); +} + + +//----------------------------------------------------------------------------- +// Set the size by which the memory grows - round up to the next power of 2 +//----------------------------------------------------------------------------- +template< class T > +void CUtlFixedMemory<T>::Init( int nGrowSize /* = 0 */, int nInitSize /* = 0 */ ) +{ + Purge(); + + m_nGrowSize = nGrowSize; + + Grow( nInitSize ); +} + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T > +inline T& CUtlFixedMemory<T>::operator[]( int i ) +{ + Assert( IsIdxValid(i) ); + return *( T* )i; +} + +template< class T > +inline const T& CUtlFixedMemory<T>::operator[]( int i ) const +{ + Assert( IsIdxValid(i) ); + return *( T* )i; +} + +template< class T > +inline T& CUtlFixedMemory<T>::Element( int i ) +{ + Assert( IsIdxValid(i) ); + return *( T* )i; +} + +template< class T > +inline const T& CUtlFixedMemory<T>::Element( int i ) const +{ + Assert( IsIdxValid(i) ); + return *( T* )i; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T > +inline int CUtlFixedMemory<T>::NumAllocated() const +{ + return m_nAllocationCount; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T > +inline bool CUtlFixedMemory<T>::IsIdxValid( int i ) const +{ +#ifdef _DEBUG + for ( BlockHeader_t *pbh = m_pBlocks; pbh; pbh = pbh->m_pNext ) + { + if ( IsInBlock( i, pbh ) ) + return true; + } + return false; +#else + return i != InvalidIndex(); +#endif +} + +template< class T > +void CUtlFixedMemory<T>::Grow( int num ) +{ + if ( num <= 0 ) + return; + + int nBlockSize = m_nGrowSize; + if ( nBlockSize == 0 ) + { + if ( m_nAllocationCount ) + { + nBlockSize = m_nAllocationCount; + } + else + { + // Compute an allocation which is at least as big as a cache line... + nBlockSize = ( 31 + sizeof( T ) ) / sizeof( T ); + Assert( nBlockSize ); + } + } + if ( nBlockSize < num ) + { + int n = ( num + nBlockSize -1 ) / nBlockSize; + Assert( n * nBlockSize >= num ); + Assert( ( n - 1 ) * nBlockSize < num ); + nBlockSize *= n; + } + m_nAllocationCount += nBlockSize; + + MEM_ALLOC_CREDIT_CLASS(); + BlockHeader_t * RESTRICT pBlockHeader = ( BlockHeader_t* )malloc( sizeof( BlockHeader_t ) + nBlockSize * sizeof( T ) ); + if ( !pBlockHeader ) + { + Error( "CUtlFixedMemory overflow!\n" ); + } + pBlockHeader->m_pNext = NULL; + pBlockHeader->m_nBlockSize = nBlockSize; + + if ( !m_pBlocks ) + { + m_pBlocks = pBlockHeader; + } + else + { +#if 1 // IsIdxAfter assumes that newly allocated blocks are at the end + BlockHeader_t * RESTRICT pbh = m_pBlocks; + while ( pbh->m_pNext ) + { + pbh = pbh->m_pNext; + } + pbh->m_pNext = pBlockHeader; +#else + pBlockHeader = m_pBlocks; + pBlockHeader->m_pNext = m_pBlocks; +#endif + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T > +inline void CUtlFixedMemory<T>::EnsureCapacity( int num ) +{ + Grow( num - NumAllocated() ); +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T > +void CUtlFixedMemory<T>::Purge() +{ + if ( !m_pBlocks ) + return; + + for ( BlockHeader_t *pbh = m_pBlocks; pbh; ) + { + BlockHeader_t *pFree = pbh; + pbh = pbh->m_pNext; + free( pFree ); + } + m_pBlocks = NULL; + m_nAllocationCount = 0; +} + +#include "tier0/memdbgoff.h" + +#endif // UTLFIXEDMEMORY_H diff --git a/external/vpc/public/tier1/utlgraph.h b/external/vpc/public/tier1/utlgraph.h new file mode 100644 index 0000000..9b9482e --- /dev/null +++ b/external/vpc/public/tier1/utlgraph.h @@ -0,0 +1,658 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLGRAPH_H +#define UTLGRAPH_H + +#include "tier1/utlmap.h" +#include "tier1/utlvector.h" +#include <limits.h> + + + +//------------------------------------- + + +//----------------------------------------------------------------------------- +// A Graph class +// +// Nodes must have a unique Node ID. +// +// Edges are unidirectional, specified from the beginning node. +// +//----------------------------------------------------------------------------- + +template <class T, class C > +class CUtlGraphVisitor; + +template <class T, class C = int > +class CUtlGraph +{ +public: + typedef int I; + typedef I IndexType_t; + typedef T NodeID_t; + typedef C CostType_t; + + typedef CUtlGraphVisitor<T,C> Visitor_t; + + struct Edge_t + { + IndexType_t m_DestinationNode; + CostType_t m_EdgeCost; + + Edge_t( IndexType_t i = 0 ) + { + m_DestinationNode = i; + m_EdgeCost = 0; + } + + bool operator==(const Edge_t &that ) const + { + return m_DestinationNode == that.m_DestinationNode; + } + + static int SortFn( const Edge_t *plhs, const Edge_t *prhs ) + { + if ( plhs->m_EdgeCost < prhs->m_EdgeCost ) + return -1; + else if ( plhs->m_EdgeCost > prhs->m_EdgeCost ) + return 1; + else return 0; + } + }; + + typedef CUtlVector<Edge_t> vecEdges_t; + + // constructor, destructor + CUtlGraph( ); + ~CUtlGraph(); + + // Add an edge + bool AddEdge( T SourceNode, T DestNode, C nCost ); + + // Remove an edge + bool RemoveEdge( T SourceNode, T DestNode ); + + // gets particular elements + T& Element( I i ); + T const &Element( I i ) const; + T& operator[]( I i ); + T const &operator[]( I i ) const; + + // Find a node + I Find( T Node ) { return m_Nodes.Find( Node ); } + I Find( T Node ) const { return m_Nodes.Find( Node ); } + + // Num elements + unsigned int Count() const { return m_Nodes.Count() ; } + + // Max "size" of the vector + I MaxElement() const { return m_Nodes.MaxElement(); } + + // Checks if a node is valid and in the graph + bool IsValidIndex( I i ) const { return m_Nodes.IsValidIndex( i ); } + + // Checks if the graph as a whole is valid + bool IsValid() const { return m_Nodes.IsValid(); } + + // Invalid index + static I InvalidIndex() { return CUtlMap< NodeID_t, vecEdges_t*>::InvalidIndex(); } + + // Remove methods + void RemoveAt( I i ); + void RemoveAll(); + + // Makes sure we have enough memory allocated to store a requested # of elements + void EnsureCapacity( int num ); + + // Create Path Matrix once you've added all nodes and edges + void CreatePathMatrix(); + + // For Visitor classes + vecEdges_t *GetEdges( I i ); + + // shortest path costs + vecEdges_t *GetPathCosts( I i ); + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, const char *pchName ); +#endif // DBGFLAG_VALIDATE + +protected: + + struct Node_t + { + vecEdges_t *m_pvecEdges; + vecEdges_t *m_pvecPaths; + + Node_t() + { + m_pvecEdges = NULL; + m_pvecPaths = NULL; + } + }; + + CUtlMap< NodeID_t, Node_t > m_Nodes; +}; + + +//----------------------------------------------------------------------------- +// A Graph "visitor" class +// +// From the specified beginning point, visits each node in an expanding radius +// +//----------------------------------------------------------------------------- +template <class T, class C = int > +class CUtlGraphVisitor +{ +public: + CUtlGraphVisitor( CUtlGraph<T, C> &graph ); + + bool Begin( T StartNode ); + bool Advance(); + + T CurrentNode(); + C AccumulatedCost(); + int CurrentRadius(); + +private: + + typedef typename CUtlGraph<T,C>::IndexType_t IndexType_t; + typedef typename CUtlGraph<T,C>::Edge_t Edge_t; + typedef CUtlVector<Edge_t> vecEdges_t; + + CUtlGraph<T, C> &m_Graph; + + vecEdges_t m_vecVisitQueue; + int m_iVisiting; + int m_nCurrentRadius; + + vecEdges_t m_vecFringeQueue; + + CUtlVector<T> m_vecNodesVisited; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template <class T, class C > +inline CUtlGraph<T, C>::CUtlGraph() +{ + SetDefLessFunc( m_Nodes ); +} + +template <class T, class C > +inline CUtlGraph<T, C>::~CUtlGraph() +{ + RemoveAll(); +} + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- + +template <class T, class C > +inline T &CUtlGraph<T, C>::Element( I i ) +{ + return m_Nodes.Key( i ); +} + +template <class T, class C > +inline T const &CUtlGraph<T, C>::Element( I i ) const +{ + return m_Nodes.Key( i ); +} + +template <class T, class C > +inline T &CUtlGraph<T, C>::operator[]( I i ) +{ + return Element(i); +} + +template <class T, class C > +inline T const &CUtlGraph<T, C>::operator[]( I i ) const +{ + return Element(i); +} + +//----------------------------------------------------------------------------- +// +// various accessors +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree +//----------------------------------------------------------------------------- + +template <class T, class C > +void CUtlGraph<T, C>::RemoveAll() +{ + FOR_EACH_MAP_FAST( m_Nodes, iNode ) + { + delete m_Nodes[iNode].m_pvecEdges; + delete m_Nodes[iNode].m_pvecPaths; + } + + m_Nodes.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- +template <class T, class C > +void CUtlGraph<T, C>::EnsureCapacity( int num ) +{ + m_Nodes.EnsureCapacity(num); +} + +//----------------------------------------------------------------------------- +// Add an edge +//----------------------------------------------------------------------------- +template <class T, class C > +bool CUtlGraph<T, C>::AddEdge( T SourceNode, T DestNode, C nCost ) +{ + I iSrcNode = m_Nodes.Find( SourceNode ); + if ( !m_Nodes.IsValidIndex( iSrcNode ) ) + { + Node_t Node; + Node.m_pvecEdges = new vecEdges_t(); + Node.m_pvecPaths = new vecEdges_t(); + iSrcNode = m_Nodes.Insert( SourceNode, Node ); + } + + I iDstNode = m_Nodes.Find( DestNode ); + if ( !m_Nodes.IsValidIndex( iDstNode ) ) + { + Node_t Node; + Node.m_pvecEdges = new vecEdges_t(); + Node.m_pvecPaths = new vecEdges_t(); + iDstNode = m_Nodes.Insert( DestNode, Node ); + } + + vecEdges_t &vecEdges = *m_Nodes[iSrcNode].m_pvecEdges; + +#ifdef _DEBUG + FOR_EACH_VEC( vecEdges, iEdge ) + { + if ( vecEdges[iEdge].m_DestinationNode == iDstNode ) + return false; + } +#endif + + Edge_t newEdge; + newEdge.m_DestinationNode = iDstNode; + newEdge.m_EdgeCost = nCost; + + vecEdges[ vecEdges.AddToTail() ] = newEdge; + + return true; +} + +//----------------------------------------------------------------------------- +// Remove an edge +//----------------------------------------------------------------------------- +template <class T, class C > +bool CUtlGraph<T, C>::RemoveEdge( T SourceNode, T DestNode ) +{ + I iSrcNode = m_Nodes.Find( SourceNode ); + if ( !m_Nodes.IsValidIndex( iSrcNode ) ) + return false; + + I iDstNode = m_Nodes.Find( DestNode ); + if ( !m_Nodes.IsValidIndex( iDstNode ) ) + return false; + + vecEdges_t &vecEdges = *m_Nodes[iSrcNode].m_pvecEdges; + + FOR_EACH_VEC( vecEdges, iEdge ) + { + if ( vecEdges[iEdge].m_DestinationNode == iDstNode ) + { + // could use FastRemove, but nodes won't have that + // many edges, and the elements are small, and + // preserving the original ordering is nice + vecEdges.Remove( iEdge ); + return true; + } + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Get all of a Node's edges +//----------------------------------------------------------------------------- +template <class T, class C > +typename CUtlGraph<T, C>::vecEdges_t *CUtlGraph<T, C>::GetEdges( I i ) +{ + return m_Nodes[i].m_pvecEdges; +} + +//----------------------------------------------------------------------------- +// Get all of a Node's edges +//----------------------------------------------------------------------------- +template <class T, class C > +typename CUtlGraph<T, C>::vecEdges_t *CUtlGraph<T, C>::GetPathCosts( I i ) +{ + return m_Nodes[i].m_pvecPaths; +} + + +//----------------------------------------------------------------------------- +// Data and memory validation +//----------------------------------------------------------------------------- +#ifdef DBGFLAG_VALIDATE +template <class T, class C > +void CUtlGraph<T, C>::Validate( CValidator &validator, const char *pchName ) +{ +#ifdef _WIN32 + validator.Push( typeid(*this).raw_name(), this, pchName ); +#else + validator.Push( typeid(*this).name(), this, pchName ); +#endif + + ValidateObj( m_Nodes ); + + FOR_EACH_MAP_FAST( m_Nodes, iNode ) + { + validator.ClaimMemory( m_Nodes[iNode].m_pvecEdges ); + ValidateObj( *m_Nodes[iNode].m_pvecEdges ); + validator.ClaimMemory( m_Nodes[iNode].m_pvecPaths ); + ValidateObj( *m_Nodes[iNode].m_pvecPaths ); + } + + validator.Pop(); +} +#endif // DBGFLAG_VALIDATE + + +//----------------------------------------------------------------------------- +// Get all of a Node's edges +//----------------------------------------------------------------------------- +template <class T, class C > +void CUtlGraph<T, C>::CreatePathMatrix() +{ + int n = MaxElement(); + + // Notes + // Because CUtlMap stores its nodes in essentially a vector, + // we know that we can use its indices in our own path matrix + // vectors safely (they will be numbers in the range (0,N) where + // N is largest number of nodes ever present in the graph). + // + // This lets us very quickly access previous best-path estimates + // by indexing into a node's vecPaths directly. + // + // When we are all done, we can then compact the vector, removing + // "null" paths, and then sorting by cost. + + // Initialize matrix with all edges + FOR_EACH_MAP_FAST( m_Nodes, iNode ) + { + vecEdges_t &vecEdges = *m_Nodes.Element( iNode ).m_pvecEdges; + vecEdges_t &vecPaths = *m_Nodes.Element( iNode ).m_pvecPaths; + + vecPaths.RemoveAll(); + vecPaths.AddMultipleToTail( n ); + FOR_EACH_VEC( vecPaths, iPath ) + { + vecPaths[iPath].m_DestinationNode = InvalidIndex(); + } + + // Path to self + vecPaths[iNode].m_DestinationNode = iNode; + // zero cost to self + vecPaths[iNode].m_EdgeCost = 0; + + FOR_EACH_VEC( vecEdges, iEdge ) + { + // Path to a neighbor node - we know exactly what the cost is + Edge_t &edge = vecEdges[iEdge]; + vecPaths[ edge.m_DestinationNode ].m_DestinationNode = edge.m_DestinationNode; + vecPaths[ edge.m_DestinationNode ].m_EdgeCost = edge.m_EdgeCost; + } + } + + // Floyd-Warshall + // for k:= 0 to n-1 + // for each (i,j) in (0..n-1) + // path[i][j] = min( path[i][j], path[i][k]+path[k][j] ); + for ( int k = 0; k < n; ++ k ) + { + if ( !m_Nodes.IsValidIndex( k ) ) + continue; + + // All current known paths from K + vecEdges_t &destMapFromK = *m_Nodes[k].m_pvecPaths; + + for ( int i = 0; i < n; ++i ) + { + if ( !m_Nodes.IsValidIndex( i ) ) + continue; + + // All current known paths from J + vecEdges_t &destMapFromI = *m_Nodes[i].m_pvecPaths; + + // Path from I to K? + int iFromIToK = k; + bool bFromIToK = destMapFromI[iFromIToK].m_DestinationNode != InvalidIndex(); + CostType_t cIToK = ( bFromIToK ) ? destMapFromI[iFromIToK].m_EdgeCost : INT_MAX; + + for ( int j = 0; j < n; ++ j ) + { + if ( !m_Nodes.IsValidIndex( j ) ) + continue; + + // Path from I to J already? + int iFromIToJ = j; + bool bFromIToJ = destMapFromI[iFromIToJ].m_DestinationNode != InvalidIndex(); + CostType_t cIToJ = ( bFromIToJ ) ? destMapFromI[iFromIToJ].m_EdgeCost : INT_MAX; + + // Path from K to J? + int iFromKToJ = j; + bool bFromKToJ = destMapFromK[iFromKToJ].m_DestinationNode != InvalidIndex(); + CostType_t cKToJ = ( bFromKToJ ) ? destMapFromK[iFromKToJ].m_EdgeCost : INT_MAX; + + // Is the new path valid? + bool bNewPathFound = ( bFromIToK && bFromKToJ ); + + if ( bNewPathFound ) + { + if ( bFromIToJ ) + { + // Pick min of previous best and current path + destMapFromI[iFromIToJ].m_EdgeCost = min( cIToJ, cIToK + cKToJ ); + } + else + { + // Current path is the first, hence the best so far + destMapFromI[iFromIToJ].m_DestinationNode = iFromIToJ; + destMapFromI[iFromIToJ].m_EdgeCost = cIToK + cKToJ; + } + } + } + } + } + + // Clean up and sort the paths + FOR_EACH_MAP_FAST( m_Nodes, iNode ) + { + vecEdges_t &vecPaths = *m_Nodes.Element( iNode ).m_pvecPaths; + FOR_EACH_VEC( vecPaths, iPath ) + { + Edge_t &edge = vecPaths[iPath]; + if ( edge.m_DestinationNode == InvalidIndex() ) + { + // No path to this destination was found. + // Remove this entry from the vector. + vecPaths.FastRemove( iPath ); + --iPath; // adjust for the removal + } + } + + // Sort the vector by cost, given that it + // is likely consumers will want to + // iterate destinations in that order. + vecPaths.Sort( Edge_t::SortFn ); + } +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +template <class T, class C > +CUtlGraphVisitor<T, C>::CUtlGraphVisitor( CUtlGraph<T,C> &graph ) +: m_Graph( graph ) +{ + m_iVisiting = 0; + m_nCurrentRadius = 0; +} + + +//----------------------------------------------------------------------------- +// Begin visiting the nodes in the graph. Returns false if the start node +// does not exist +//----------------------------------------------------------------------------- +template <class T, class C > +bool CUtlGraphVisitor<T, C>::Begin( T StartNode ) +{ + m_vecVisitQueue.RemoveAll(); + m_vecFringeQueue.RemoveAll(); + m_vecNodesVisited.RemoveAll(); + m_iVisiting = 0; + m_nCurrentRadius = 0; + + IndexType_t iStartNode = m_Graph.Find( StartNode ); + + if ( !m_Graph.IsValidIndex( iStartNode ) ) + return false; + + vecEdges_t *pvecEdges = m_Graph.GetEdges( iStartNode ); + + Edge_t edge; + edge.m_DestinationNode = iStartNode; + edge.m_EdgeCost = 0; + + m_vecVisitQueue[ m_vecVisitQueue.AddToTail() ] = edge; + + m_vecNodesVisited[ m_vecNodesVisited.AddToTail() ] = iStartNode; + + m_vecFringeQueue = *pvecEdges; + + // cells actually get marked as "visited" as soon as we put + // them in the fringe queue, so we don't put them in the *next* + // fringe queue (we build the fringe queue before we actually visit + // the nodes in the new visit queue). + FOR_EACH_VEC( m_vecFringeQueue, iFringe ) + { + m_vecNodesVisited[ m_vecNodesVisited.AddToTail() ] = m_vecFringeQueue[iFringe].m_DestinationNode; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Advance to the next node. Returns false when all nodes have been visited +//----------------------------------------------------------------------------- +template <class T, class C> +bool CUtlGraphVisitor<T, C>::Advance() +{ + m_iVisiting++; + + // Is the VisitQueue empty? move outward one radius if so + + if ( m_iVisiting >= m_vecVisitQueue.Count() ) + { + m_nCurrentRadius++; + m_iVisiting = 0; + m_vecVisitQueue = m_vecFringeQueue; + m_vecFringeQueue.RemoveAll(); + + if ( !m_vecVisitQueue.Count() ) + return false; + + // create new fringe queue + FOR_EACH_VEC( m_vecVisitQueue, iNode ) + { + Edge_t &node = m_vecVisitQueue[iNode]; + vecEdges_t &vecEdges = *m_Graph.GetEdges( node.m_DestinationNode ); + FOR_EACH_VEC( vecEdges, iEdge ) + { + Edge_t &edge = vecEdges[iEdge]; + if ( m_vecNodesVisited.InvalidIndex() == m_vecNodesVisited.Find( edge.m_DestinationNode ) ) + { + m_vecNodesVisited[ m_vecNodesVisited.AddToTail() ] = edge.m_DestinationNode; + + int iNewFringeNode = m_vecFringeQueue.AddToTail(); + m_vecFringeQueue[ iNewFringeNode ] = edge; + // Accumulate the cost to get to the current point + m_vecFringeQueue[ iNewFringeNode ].m_EdgeCost += node.m_EdgeCost; + } + } + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Get the current node in the visit sequence +//----------------------------------------------------------------------------- +template <class T, class C> +T CUtlGraphVisitor<T, C>::CurrentNode() +{ + if ( m_iVisiting >= m_vecVisitQueue.Count() ) + { + AssertMsg( false, "Visitor invalid" ); + return T(); + } + + return m_Graph[ m_vecVisitQueue[ m_iVisiting ].m_DestinationNode ]; +} + + +//----------------------------------------------------------------------------- +// Get the accumulated cost to traverse the graph to the current node +//----------------------------------------------------------------------------- +template <class T, class C> +C CUtlGraphVisitor<T, C>::AccumulatedCost() +{ + if ( m_iVisiting >= m_vecVisitQueue.Count() ) + { + AssertMsg( false, "Visitor invalid" ); + return C(); + } + + return m_vecVisitQueue[ m_iVisiting ].m_EdgeCost; +} + + +//----------------------------------------------------------------------------- +// Get the current radius from the start point to this node +//----------------------------------------------------------------------------- +template <class T, class C> +int CUtlGraphVisitor<T, C>::CurrentRadius() +{ + if ( m_iVisiting >= m_vecVisitQueue.Count() ) + { + AssertMsg( false, "Visitor invalid" ); + return 0; + } + + return m_nCurrentRadius; +} + +#endif // UTLGRAPH_H diff --git a/external/vpc/public/tier1/utlhash.h b/external/vpc/public/tier1/utlhash.h new file mode 100644 index 0000000..aaddb29 --- /dev/null +++ b/external/vpc/public/tier1/utlhash.h @@ -0,0 +1,1299 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// Serialization/unserialization buffer +//=============================================================================// + +#ifndef UTLHASH_H +#define UTLHASH_H +#pragma once + +#include <limits.h> +#include "utlmemory.h" +#include "utlvector.h" +#include "utllinkedlist.h" +#include "utllinkedlist.h" +#include "commonmacros.h" +#include "generichash.h" + +typedef unsigned int UtlHashHandle_t; + +template<class Data, typename C = bool (*)( Data const&, Data const& ), typename K = unsigned int (*)( Data const& ) > +class CUtlHash +{ +public: + // compare and key functions - implemented by the + typedef C CompareFunc_t; + typedef K KeyFunc_t; + + // constructor/deconstructor + CUtlHash( int bucketCount = 0, int growCount = 0, int initCount = 0, + CompareFunc_t compareFunc = 0, KeyFunc_t keyFunc = 0 ); + ~CUtlHash(); + + // invalid handle + static UtlHashHandle_t InvalidHandle( void ) { return ( UtlHashHandle_t )~0; } + bool IsValidHandle( UtlHashHandle_t handle ) const; + + // size + int Count( void ) const; + + // memory + void Purge( void ); + + // insertion methods + UtlHashHandle_t Insert( Data const &src ); + UtlHashHandle_t Insert( Data const &src, bool *pDidInsert ); + UtlHashHandle_t AllocEntryFromKey( Data const &src ); + + // removal methods + void Remove( UtlHashHandle_t handle ); + void RemoveAll(); + + // retrieval methods + UtlHashHandle_t Find( Data const &src ) const; + + Data &Element( UtlHashHandle_t handle ); + Data const &Element( UtlHashHandle_t handle ) const; + Data &operator[]( UtlHashHandle_t handle ); + Data const &operator[]( UtlHashHandle_t handle ) const; + + UtlHashHandle_t GetFirstHandle() const; + UtlHashHandle_t GetNextHandle( UtlHashHandle_t h ) const; + + // debugging!! + void Log( const char *filename ); + void Dump(); + +protected: + + int GetBucketIndex( UtlHashHandle_t handle ) const; + int GetKeyDataIndex( UtlHashHandle_t handle ) const; + UtlHashHandle_t BuildHandle( int ndxBucket, int ndxKeyData ) const; + + bool DoFind( Data const &src, unsigned int *pBucket, int *pIndex ) const; + +protected: + + // handle upper 16 bits = bucket index (bucket heads) + // handle lower 16 bits = key index (bucket list) + typedef CUtlVector<Data> HashBucketList_t; + CUtlVector<HashBucketList_t> m_Buckets; + + CompareFunc_t m_CompareFunc; // function used to handle unique compares on data + KeyFunc_t m_KeyFunc; // function used to generate the key value + + bool m_bPowerOfTwo; // if the bucket value is a power of two, + unsigned int m_ModMask; // use the mod mask to "mod" +}; + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +CUtlHash<Data, C, K>::CUtlHash( int bucketCount, int growCount, int initCount, + CompareFunc_t compareFunc, KeyFunc_t keyFunc ) : + m_CompareFunc( compareFunc ), + m_KeyFunc( keyFunc ) +{ + bucketCount = MIN(bucketCount, 65536); + m_Buckets.SetSize( bucketCount ); + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + m_Buckets[ndxBucket].SetSize( initCount ); + m_Buckets[ndxBucket].SetGrowSize( growCount ); + } + + // check to see if the bucket count is a power of 2 and set up + // optimizations appropriately + m_bPowerOfTwo = IsPowerOfTwo( bucketCount ); + m_ModMask = m_bPowerOfTwo ? (bucketCount-1) : 0; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +CUtlHash<Data, C, K>::~CUtlHash() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline bool CUtlHash<Data, C, K>::IsValidHandle( UtlHashHandle_t handle ) const +{ + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + // ndxBucket and ndxKeyData can't possibly be less than zero -- take a + // look at the definition of the Get..Index functions for why. However, + // if you override those functions, you will need to override this one + // as well. + if( /*( ndxBucket >= 0 ) && */ ( ndxBucket < m_Buckets.Count() ) ) + { + if( /*( ndxKeyData >= 0 ) && */ ( ndxKeyData < m_Buckets[ndxBucket].Count() ) ) + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline int CUtlHash<Data, C, K>::Count( void ) const +{ + int count = 0; + + int bucketCount = m_Buckets.Count(); + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + count += m_Buckets[ndxBucket].Count(); + } + + return count; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline int CUtlHash<Data, C, K>::GetBucketIndex( UtlHashHandle_t handle ) const +{ + return ( ( ( handle >> 16 ) & 0x0000ffff ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline int CUtlHash<Data, C, K>::GetKeyDataIndex( UtlHashHandle_t handle ) const +{ + return ( handle & 0x0000ffff ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline UtlHashHandle_t CUtlHash<Data, C, K>::BuildHandle( int ndxBucket, int ndxKeyData ) const +{ + Assert( ( ndxBucket >= 0 ) && ( ndxBucket < 65536 ) ); + Assert( ( ndxKeyData >= 0 ) && ( ndxKeyData < 65536 ) ); + + UtlHashHandle_t handle = ndxKeyData; + handle |= ( ndxBucket << 16 ); + + return handle; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline void CUtlHash<Data, C, K>::Purge( void ) +{ + int bucketCount = m_Buckets.Count(); + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + m_Buckets[ndxBucket].Purge(); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline bool CUtlHash<Data, C, K>::DoFind( Data const &src, unsigned int *pBucket, int *pIndex ) const +{ + // generate the data "key" + unsigned int key = m_KeyFunc( src ); + + // hash the "key" - get the correct hash table "bucket" + unsigned int ndxBucket; + if( m_bPowerOfTwo ) + { + *pBucket = ndxBucket = ( key & m_ModMask ); + } + else + { + int bucketCount = m_Buckets.Count(); + *pBucket = ndxBucket = key % bucketCount; + } + + int ndxKeyData = 0; + const CUtlVector<Data> &bucket = m_Buckets[ndxBucket]; + int keyDataCount = bucket.Count(); + for( ndxKeyData = 0; ndxKeyData < keyDataCount; ndxKeyData++ ) + { + if( m_CompareFunc( bucket.Element( ndxKeyData ), src ) ) + break; + } + + if( ndxKeyData == keyDataCount ) + return false; + + *pIndex = ndxKeyData; + return true; +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline UtlHashHandle_t CUtlHash<Data, C, K>::Find( Data const &src ) const +{ + unsigned int ndxBucket; + int ndxKeyData = 0; + + if ( DoFind( src, &ndxBucket, &ndxKeyData ) ) + { + return ( BuildHandle( ndxBucket, ndxKeyData ) ); + } + return ( InvalidHandle() ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline UtlHashHandle_t CUtlHash<Data, C, K>::Insert( Data const &src ) +{ + unsigned int ndxBucket; + int ndxKeyData = 0; + + if ( DoFind( src, &ndxBucket, &ndxKeyData ) ) + { + return ( BuildHandle( ndxBucket, ndxKeyData ) ); + } + + ndxKeyData = m_Buckets[ndxBucket].AddToTail( src ); + + return ( BuildHandle( ndxBucket, ndxKeyData ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline UtlHashHandle_t CUtlHash<Data, C, K>::Insert( Data const &src, bool *pDidInsert ) +{ + unsigned int ndxBucket; + int ndxKeyData = 0; + + if ( DoFind( src, &ndxBucket, &ndxKeyData ) ) + { + *pDidInsert = false; + return ( BuildHandle( ndxBucket, ndxKeyData ) ); + } + + *pDidInsert = true; + ndxKeyData = m_Buckets[ndxBucket].AddToTail( src ); + + return ( BuildHandle( ndxBucket, ndxKeyData ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline UtlHashHandle_t CUtlHash<Data, C, K>::AllocEntryFromKey( Data const &src ) +{ + unsigned int ndxBucket; + int ndxKeyData = 0; + + if ( DoFind( src, &ndxBucket, &ndxKeyData ) ) + { + return ( BuildHandle( ndxBucket, ndxKeyData ) ); + } + + ndxKeyData = m_Buckets[ndxBucket].AddToTail(); + + return ( BuildHandle( ndxBucket, ndxKeyData ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline void CUtlHash<Data, C, K>::Remove( UtlHashHandle_t handle ) +{ + Assert( IsValidHandle( handle ) ); + + // check to see if the bucket exists + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + if( m_Buckets[ndxBucket].IsValidIndex( ndxKeyData ) ) + { + m_Buckets[ndxBucket].FastRemove( ndxKeyData ); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline void CUtlHash<Data, C, K>::RemoveAll() +{ + int bucketCount = m_Buckets.Count(); + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + m_Buckets[ndxBucket].RemoveAll(); + } +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline Data &CUtlHash<Data, C, K>::Element( UtlHashHandle_t handle ) +{ + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + return ( m_Buckets[ndxBucket].Element( ndxKeyData ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline Data const &CUtlHash<Data, C, K>::Element( UtlHashHandle_t handle ) const +{ + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + return ( m_Buckets[ndxBucket].Element( ndxKeyData ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline Data &CUtlHash<Data, C, K>::operator[]( UtlHashHandle_t handle ) +{ + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + return ( m_Buckets[ndxBucket].Element( ndxKeyData ) ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline Data const &CUtlHash<Data, C, K>::operator[]( UtlHashHandle_t handle ) const +{ + int ndxBucket = GetBucketIndex( handle ); + int ndxKeyData = GetKeyDataIndex( handle ); + + return ( m_Buckets[ndxBucket].Element( ndxKeyData ) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline UtlHashHandle_t CUtlHash<Data, C, K>::GetFirstHandle() const +{ + return GetNextHandle( ( UtlHashHandle_t )-1 ); +} + +template<class Data, typename C, typename K> +inline UtlHashHandle_t CUtlHash<Data, C, K>::GetNextHandle( UtlHashHandle_t handle ) const +{ + ++handle; // start at the first possible handle after the one given + + int bi = GetBucketIndex( handle ); + int ki = GetKeyDataIndex( handle ); + + int nBuckets = m_Buckets.Count(); + for ( ; bi < nBuckets; ++bi ) + { + if ( ki < m_Buckets[ bi ].Count() ) + return BuildHandle( bi, ki ); + + ki = 0; + } + + return InvalidHandle(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline void CUtlHash<Data, C, K>::Log( const char *filename ) +{ + FILE *pDebugFp; + pDebugFp = fopen( filename, "w" ); + if( !pDebugFp ) + return; + + int maxBucketSize = 0; + int numBucketsEmpty = 0; + + int bucketCount = m_Buckets.Count(); + fprintf( pDebugFp, "\n%d Buckets\n", bucketCount ); + + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + int count = m_Buckets[ndxBucket].Count(); + + if( count > maxBucketSize ) { maxBucketSize = count; } + if( count == 0 ) + numBucketsEmpty++; + + fprintf( pDebugFp, "Bucket %d: %d\n", ndxBucket, count ); + } + + fprintf( pDebugFp, "\nBucketHeads Used: %d\n", bucketCount - numBucketsEmpty ); + fprintf( pDebugFp, "Max Bucket Size: %d\n", maxBucketSize ); + + fclose( pDebugFp ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, typename C, typename K> +inline void CUtlHash<Data, C, K>::Dump( ) +{ + int maxBucketSize = 0; + int numBucketsEmpty = 0; + + int bucketCount = m_Buckets.Count(); + Msg( "\n%d Buckets\n", bucketCount ); + + for( int ndxBucket = 0; ndxBucket < bucketCount; ndxBucket++ ) + { + int count = m_Buckets[ndxBucket].Count(); + + if( count > maxBucketSize ) { maxBucketSize = count; } + if( count == 0 ) + numBucketsEmpty++; + + Msg( "Bucket %d: %d\n", ndxBucket, count ); + } + + Msg( "\nBucketHeads Used: %d\n", bucketCount - numBucketsEmpty ); + Msg( "Max Bucket Size: %d\n", maxBucketSize ); +} + +//============================================================================= +// +// Fast Hash +// +// Number of buckets must be a power of 2. +// Key must be 32-bits (unsigned int). +// +typedef int UtlHashFastHandle_t; + +#define UTLHASH_POOL_SCALAR 2 + +class CUtlHashFastNoHash +{ +public: + static int Hash( int key, int bucketMask ) + { + return ( key & bucketMask ); + } +}; + +class CUtlHashFastGenericHash +{ +public: + static int Hash( int key, int bucketMask ) + { + return ( HashIntConventional( key ) & bucketMask ); + } +}; + +template<class Data, class HashFuncs = CUtlHashFastNoHash > +class CUtlHashFast +{ +public: + + // Constructor/Deconstructor. + CUtlHashFast(); + ~CUtlHashFast(); + + // Memory. + void Purge( void ); + + // Invalid handle. + static UtlHashFastHandle_t InvalidHandle( void ) { return ( UtlHashFastHandle_t )~0; } + inline bool IsValidHandle( UtlHashFastHandle_t hHash ) const; + + // Initialize. + bool Init( int nBucketCount ); + + // Size not available; count is meaningless for multilists. + // int Count( void ) const; + + // Insertion. + UtlHashFastHandle_t Insert( unsigned int uiKey, const Data &data ); + UtlHashFastHandle_t FastInsert( unsigned int uiKey, const Data &data ); + + // Removal. + void Remove( UtlHashFastHandle_t hHash ); + void RemoveAll( void ); + + // Retrieval. + UtlHashFastHandle_t Find( unsigned int uiKey ) const; + + Data &Element( UtlHashFastHandle_t hHash ); + Data const &Element( UtlHashFastHandle_t hHash ) const; + Data &operator[]( UtlHashFastHandle_t hHash ); + Data const &operator[]( UtlHashFastHandle_t hHash ) const; + + // Iteration + struct UtlHashFastIterator_t + { + int bucket; + UtlHashFastHandle_t handle; + + UtlHashFastIterator_t(int _bucket, const UtlHashFastHandle_t &_handle) + : bucket(_bucket), handle(_handle) {}; + // inline operator UtlHashFastHandle_t() const { return handle; }; + }; + inline UtlHashFastIterator_t First() const; + inline UtlHashFastIterator_t Next( const UtlHashFastIterator_t &hHash ) const; + inline bool IsValidIterator( const UtlHashFastIterator_t &iter ) const; + inline Data &operator[]( const UtlHashFastIterator_t &iter ) { return (*this)[iter.handle]; } + inline Data const &operator[]( const UtlHashFastIterator_t &iter ) const { return (*this)[iter.handle]; } + +//protected: + + // Templatized for memory tracking purposes + template <typename HashData> + struct HashFastData_t_ + { + unsigned int m_uiKey; + HashData m_Data; + }; + + typedef HashFastData_t_<Data> HashFastData_t; + + unsigned int m_uiBucketMask; + CUtlVector<UtlHashFastHandle_t> m_aBuckets; + CUtlFixedLinkedList<HashFastData_t> m_aDataPool; + +}; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> CUtlHashFast<Data,HashFuncs>::CUtlHashFast() +{ + Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Deconstructor +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> CUtlHashFast<Data,HashFuncs>::~CUtlHashFast() +{ + Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Destroy dynamically allocated hash data. +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::Purge( void ) +{ + m_aBuckets.Purge(); + m_aDataPool.Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Initialize the hash - set bucket count and hash grow amount. +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> bool CUtlHashFast<Data,HashFuncs>::Init( int nBucketCount ) +{ + // Verify the bucket count is power of 2. + if ( !IsPowerOfTwo( nBucketCount ) ) + return false; + + // Set the bucket size. + m_aBuckets.SetSize( nBucketCount ); + for ( int iBucket = 0; iBucket < nBucketCount; ++iBucket ) + { + m_aBuckets[iBucket] = m_aDataPool.InvalidIndex(); + } + + // Set the mod mask. + m_uiBucketMask = nBucketCount - 1; + + // Calculate the grow size. + int nGrowSize = UTLHASH_POOL_SCALAR * nBucketCount; + m_aDataPool.SetGrowSize( nGrowSize ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Return the number of elements in the hash. +// Not available because count isn't accurately maintained for multilists. +//----------------------------------------------------------------------------- +/* +template<class Data, class HashFuncs> inline int CUtlHashFast<Data,HashFuncs>::Count( void ) const +{ + return m_aDataPool.Count(); +} +*/ + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), with +// a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::Insert( unsigned int uiKey, const Data &data ) +{ + // Check to see if that key already exists in the buckets (should be unique). + UtlHashFastHandle_t hHash = Find( uiKey ); + if( hHash != InvalidHandle() ) + return hHash; + + return FastInsert( uiKey, data ); +} + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), +// without a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::FastInsert( unsigned int uiKey, const Data &data ) +{ + // Get a new element from the pool. + int iHashData = m_aDataPool.Alloc( true ); + HashFastData_t *pHashData = &m_aDataPool[iHashData]; + if ( !pHashData ) + return InvalidHandle(); + + // Add data to new element. + pHashData->m_uiKey = uiKey; + pHashData->m_Data = data; + + // Link element. + int iBucket = HashFuncs::Hash( uiKey, m_uiBucketMask ); + m_aDataPool.LinkBefore( m_aBuckets[iBucket], iHashData ); + m_aBuckets[iBucket] = iHashData; + + return iHashData; +} + +//----------------------------------------------------------------------------- +// Purpose: Remove a given element from the hash. +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::Remove( UtlHashFastHandle_t hHash ) +{ + int iBucket = HashFuncs::Hash( m_aDataPool[hHash].m_uiKey, m_uiBucketMask ); + if ( m_aBuckets[iBucket] == hHash ) + { + // It is a bucket head. + m_aBuckets[iBucket] = m_aDataPool.Next( hHash ); + } + else + { + // Not a bucket head. + m_aDataPool.Unlink( hHash ); + } + + // Remove the element. + m_aDataPool.Remove( hHash ); +} + +//----------------------------------------------------------------------------- +// Purpose: Remove all elements from the hash +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> inline void CUtlHashFast<Data,HashFuncs>::RemoveAll( void ) +{ + m_aBuckets.RemoveAll(); + m_aDataPool.RemoveAll(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> inline UtlHashFastHandle_t CUtlHashFast<Data,HashFuncs>::Find( unsigned int uiKey ) const +{ + // hash the "key" - get the correct hash table "bucket" + int iBucket = HashFuncs::Hash( uiKey, m_uiBucketMask ); + + for ( int iElement = m_aBuckets[iBucket]; iElement != m_aDataPool.InvalidIndex(); iElement = m_aDataPool.Next( iElement ) ) + { + if ( m_aDataPool[iElement].m_uiKey == uiKey ) + return iElement; + } + + return InvalidHandle(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> inline Data &CUtlHashFast<Data,HashFuncs>::Element( UtlHashFastHandle_t hHash ) +{ + return ( m_aDataPool[hHash].m_Data ); +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> inline Data const &CUtlHashFast<Data,HashFuncs>::Element( UtlHashFastHandle_t hHash ) const +{ + return ( m_aDataPool[hHash].m_Data ); +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> inline Data &CUtlHashFast<Data,HashFuncs>::operator[]( UtlHashFastHandle_t hHash ) +{ + return ( m_aDataPool[hHash].m_Data ); +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> inline Data const &CUtlHashFast<Data,HashFuncs>::operator[]( UtlHashFastHandle_t hHash ) const +{ + return ( m_aDataPool[hHash].m_Data ); +} + +//----------------------------------------------------------------------------- +// Purpose: For iterating over the whole hash, return the index of the first element +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> + typename CUtlHashFast<Data,HashFuncs>::UtlHashFastIterator_t + CUtlHashFast<Data,HashFuncs>::First() const +{ + // walk through the buckets to find the first one that has some data + int bucketCount = m_aBuckets.Count(); + const UtlHashFastHandle_t invalidIndex = m_aDataPool.InvalidIndex(); + for ( int bucket = 0 ; bucket < bucketCount ; ++bucket ) + { + UtlHashFastHandle_t iElement = m_aBuckets[bucket]; // get the head of the bucket + if (iElement != invalidIndex) + return UtlHashFastIterator_t(bucket,iElement); + } + + // if we are down here, the list is empty + return UtlHashFastIterator_t(-1, invalidIndex); +} + +//----------------------------------------------------------------------------- +// Purpose: For iterating over the whole hash, return the next element after +// the param one. Or an invalid iterator. +//----------------------------------------------------------------------------- +template<class Data, class HashFuncs> + typename CUtlHashFast<Data,HashFuncs>::UtlHashFastIterator_t + CUtlHashFast<Data,HashFuncs>::Next( const typename CUtlHashFast<Data,HashFuncs>::UtlHashFastIterator_t &iter ) const +{ + // look for the next entry in the current bucket + UtlHashFastHandle_t next = m_aDataPool.Next(iter.handle); + const UtlHashFastHandle_t invalidIndex = m_aDataPool.InvalidIndex(); + if (next != invalidIndex) + { + // this bucket still has more elements in it + return UtlHashFastIterator_t(iter.bucket, next); + } + + // otherwise look for the next bucket with data + int bucketCount = m_aBuckets.Count(); + for ( int bucket = iter.bucket+1 ; bucket < bucketCount ; ++bucket ) + { + UtlHashFastHandle_t next = m_aBuckets[bucket]; // get the head of the bucket + if (next != invalidIndex) + return UtlHashFastIterator_t( bucket, next ); + } + + // if we're here, there's no more data to be had + return UtlHashFastIterator_t(-1, invalidIndex); +} + +template<class Data, class HashFuncs> + bool CUtlHashFast<Data,HashFuncs>::IsValidIterator( const typename CUtlHashFast::UtlHashFastIterator_t &iter ) const +{ + return ( (iter.bucket >= 0) && (m_aDataPool.IsValidIndex(iter.handle)) ); +} + + +template<class Data, class HashFuncs> inline bool CUtlHashFast<Data,HashFuncs>::IsValidHandle( UtlHashFastHandle_t hHash ) const +{ + return m_aDataPool.IsValidIndex(hHash); +} + +//============================================================================= +// +// Fixed Hash +// +// Number of buckets must be a power of 2. +// Key must be 32-bits (unsigned int). +// +typedef int UtlHashFixedHandle_t; + +template <int NUM_BUCKETS> +class CUtlHashFixedGenericHash +{ +public: + static int Hash( int key, int bucketMask ) + { + int hash = HashIntConventional( key ); + if ( NUM_BUCKETS <= USHRT_MAX ) + { + hash ^= ( hash >> 16 ); + } + if ( NUM_BUCKETS <= UCHAR_MAX ) + { + hash ^= ( hash >> 8 ); + } + return ( hash & bucketMask ); + } +}; + +template<class Data, int NUM_BUCKETS, class CHashFuncs = CUtlHashFastNoHash > +class CUtlHashFixed +{ +public: + + // Constructor/Deconstructor. + CUtlHashFixed(); + ~CUtlHashFixed(); + + // Memory. + void Purge( void ); + + // Invalid handle. + static UtlHashFixedHandle_t InvalidHandle( void ) { return ( UtlHashFixedHandle_t )~0; } + + // Size. + int Count( void ); + + // Insertion. + UtlHashFixedHandle_t Insert( unsigned int uiKey, const Data &data ); + UtlHashFixedHandle_t FastInsert( unsigned int uiKey, const Data &data ); + + // Removal. + void Remove( UtlHashFixedHandle_t hHash ); + void RemoveAll( void ); + + // Retrieval. + UtlHashFixedHandle_t Find( unsigned int uiKey ); + + Data &Element( UtlHashFixedHandle_t hHash ); + Data const &Element( UtlHashFixedHandle_t hHash ) const; + Data &operator[]( UtlHashFixedHandle_t hHash ); + Data const &operator[]( UtlHashFixedHandle_t hHash ) const; + + //protected: + + // Templatized for memory tracking purposes + template <typename Data_t> + struct HashFixedData_t_ + { + unsigned int m_uiKey; + Data_t m_Data; + }; + + typedef HashFixedData_t_<Data> HashFixedData_t; + + enum + { + BUCKET_MASK = NUM_BUCKETS - 1 + }; + CUtlPtrLinkedList<HashFixedData_t> m_aBuckets[NUM_BUCKETS]; + int m_nElements; +}; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::CUtlHashFixed() +{ + Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Deconstructor +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::~CUtlHashFixed() +{ + Purge(); +} + +//----------------------------------------------------------------------------- +// Purpose: Destroy dynamically allocated hash data. +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Purge( void ) +{ + RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return the number of elements in the hash. +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline int CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Count( void ) +{ + return m_nElements; +} + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), with +// a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Insert( unsigned int uiKey, const Data &data ) +{ + // Check to see if that key already exists in the buckets (should be unique). + UtlHashFixedHandle_t hHash = Find( uiKey ); + if( hHash != InvalidHandle() ) + return hHash; + + return FastInsert( uiKey, data ); +} + +//----------------------------------------------------------------------------- +// Purpose: Insert data into the hash table given its key (unsigned int), +// without a check to see if the element already exists within the tree. +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::FastInsert( unsigned int uiKey, const Data &data ) +{ + int iBucket = HashFuncs::Hash( uiKey, NUM_BUCKETS - 1 ); + UtlPtrLinkedListIndex_t iElem = m_aBuckets[iBucket].AddToHead(); + + HashFixedData_t *pHashData = &m_aBuckets[iBucket][iElem]; + + Assert( (UtlPtrLinkedListIndex_t)pHashData == iElem ); + + // Add data to new element. + pHashData->m_uiKey = uiKey; + pHashData->m_Data = data; + + m_nElements++; + return (UtlHashFixedHandle_t)pHashData; +} + +//----------------------------------------------------------------------------- +// Purpose: Remove a given element from the hash. +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Remove( UtlHashFixedHandle_t hHash ) +{ + HashFixedData_t *pHashData = (HashFixedData_t *)hHash; + Assert( Find(pHashData->m_uiKey) != InvalidHandle() ); + int iBucket = HashFuncs::Hash( pHashData->m_uiKey, NUM_BUCKETS - 1 ); + m_aBuckets[iBucket].Remove( (UtlPtrLinkedListIndex_t)pHashData ); + m_nElements--; +} + +//----------------------------------------------------------------------------- +// Purpose: Remove all elements from the hash +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline void CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::RemoveAll( void ) +{ + for ( int i = 0; i < NUM_BUCKETS; i++ ) + { + m_aBuckets[i].RemoveAll(); + } + m_nElements = 0; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline UtlHashFixedHandle_t CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Find( unsigned int uiKey ) +{ + int iBucket = HashFuncs::Hash( uiKey, NUM_BUCKETS - 1 ); + CUtlPtrLinkedList<HashFixedData_t> &bucket = m_aBuckets[iBucket]; + + for ( UtlPtrLinkedListIndex_t iElement = bucket.Head(); iElement != bucket.InvalidIndex(); iElement = bucket.Next( iElement ) ) + { + if ( bucket[iElement].m_uiKey == uiKey ) + return (UtlHashFixedHandle_t)iElement; + } + + return InvalidHandle(); +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Element( UtlHashFixedHandle_t hHash ) +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data const &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::Element( UtlHashFixedHandle_t hHash ) const +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::operator[]( UtlHashFixedHandle_t hHash ) +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +//----------------------------------------------------------------------------- +// Purpose: Return data given a hash handle. +//----------------------------------------------------------------------------- +template<class Data, int NUM_BUCKETS, class HashFuncs> inline Data const &CUtlHashFixed<Data,NUM_BUCKETS,HashFuncs>::operator[]( UtlHashFixedHandle_t hHash ) const +{ + return ((HashFixedData_t *)hHash)->m_Data; +} + +class CDefaultHash32 +{ +public: + static inline uint32 HashKey32( uint32 nKey ) { return HashIntConventional(nKey); } +}; + +class CPassthroughHash32 +{ +public: + static inline uint32 HashKey32( uint32 nKey ) { return nKey; } +}; + + +// This is a simpler hash for scalar types that stores the entire hash + buckets in a single linear array +// This is much more cache friendly for small (e.g. 32-bit) types stored in the hash +template<class Data, class CHashFunction = CDefaultHash32> +class CUtlScalarHash +{ +public: + + // Constructor/Destructor. + CUtlScalarHash(); + ~CUtlScalarHash(); + + // Memory. + // void Purge( void ); + + // Invalid handle. + static const UtlHashFastHandle_t InvalidHandle( void ) { return (unsigned int)~0; } + + // Initialize. + bool Init( int nBucketCount ); + + // Size. + int Count( void ) const { return m_dataCount; } + + // Insertion. + UtlHashFastHandle_t Insert( unsigned int uiKey, const Data &data ); + + // Removal. + void FindAndRemove( unsigned int uiKey, const Data &dataRecord ); + void Remove( UtlHashFastHandle_t hHash ); + void RemoveAll( void ); + void Grow(); + + // Retrieval. Finds by uiKey and then by comparing dataRecord + UtlHashFastHandle_t Find( unsigned int uiKey, const Data &dataRecord ) const; + UtlHashFastHandle_t FindByUniqueKey( unsigned int uiKey ) const; + + Data &Element( UtlHashFastHandle_t hHash ) { Assert(unsigned(hHash)<=m_uiBucketMask); return m_pData[hHash].m_Data; } + Data const &Element( UtlHashFastHandle_t hHash ) const { Assert(unsigned(hHash)<=m_uiBucketMask); return m_pData[hHash].m_Data; } + Data &operator[]( UtlHashFastHandle_t hHash ) { Assert(unsigned(hHash)<=m_uiBucketMask); return m_pData[hHash].m_Data; } + Data const &operator[]( UtlHashFastHandle_t hHash ) const { Assert(unsigned(hHash)<=m_uiBucketMask); return m_pData[hHash].m_Data; } + + unsigned int Key( UtlHashFastHandle_t hHash ) const { Assert(unsigned(hHash)<=m_uiBucketMask); return m_pData[hHash].m_uiKey; } + + UtlHashFastHandle_t FirstInorder() const + { + return NextInorder(-1); + } + UtlHashFastHandle_t NextInorder( UtlHashFastHandle_t nStart ) const + { + int nElementCount = m_maxData * 2; + unsigned int nUnusedListElement = (unsigned int)InvalidHandle(); + for ( int i = nStart+1; i < nElementCount; i++ ) + { + if ( m_pData[i].m_uiKey != nUnusedListElement ) + return i; + } + return nUnusedListElement; + } + + //protected: + + struct HashScalarData_t + { + unsigned int m_uiKey; + Data m_Data; + }; + + unsigned int m_uiBucketMask; + HashScalarData_t *m_pData; + int m_maxData; + int m_dataCount; +}; + +template<class Data, class CHashFunction> CUtlScalarHash<Data, CHashFunction>::CUtlScalarHash() +{ + m_pData = NULL; + m_uiBucketMask = 0; + m_maxData = 0; + m_dataCount = 0; +} + +template<class Data, class CHashFunction> CUtlScalarHash<Data, CHashFunction>::~CUtlScalarHash() +{ + delete[] m_pData; +} + +template<class Data, class CHashFunction> bool CUtlScalarHash<Data, CHashFunction>::Init( int nBucketCount ) +{ + Assert(m_dataCount==0); + m_maxData = SmallestPowerOfTwoGreaterOrEqual(nBucketCount); + int elementCount = m_maxData * 2; + m_pData = new HashScalarData_t[elementCount]; + m_uiBucketMask = elementCount - 1; + RemoveAll(); + return true; +} + +template<class Data, class CHashFunction> void CUtlScalarHash<Data, CHashFunction>::Grow() +{ + ASSERT_NO_REENTRY(); + int oldElementCount = m_maxData * 2; + HashScalarData_t *pOldData = m_pData; + + // Grow to a minimum size of 16 + m_maxData = MAX( oldElementCount, 16 ); + int elementCount = m_maxData * 2; + m_pData = new HashScalarData_t[elementCount]; + m_uiBucketMask = elementCount-1; + m_dataCount = 0; + for ( int i = 0; i < elementCount; i++ ) + { + m_pData[i].m_uiKey = InvalidHandle(); + } + for ( int i = 0; i < oldElementCount; i++ ) + { + if ( pOldData[i].m_uiKey != (unsigned)InvalidHandle() ) + { + Insert( pOldData[i].m_uiKey, pOldData[i].m_Data ); + } + } + delete[] pOldData; +} + +template<class Data, class CHashFunction> UtlHashFastHandle_t CUtlScalarHash<Data, CHashFunction>::Insert( unsigned int uiKey, const Data &data ) +{ + if ( m_dataCount >= m_maxData ) + { + Grow(); + } + m_dataCount++; + Assert(uiKey != (uint)InvalidHandle()); // This hash stores less data by assuming uiKey != ~0 + int index = CHashFunction::HashKey32(uiKey) & m_uiBucketMask; + unsigned int endOfList = (unsigned int)InvalidHandle(); + while ( m_pData[index].m_uiKey != endOfList ) + { + index = (index+1) & m_uiBucketMask; + } + m_pData[index].m_uiKey = uiKey; + m_pData[index].m_Data = data; + + return index; +} + +// Removal. +template<class Data, class CHashFunction> void CUtlScalarHash<Data, CHashFunction>::Remove( UtlHashFastHandle_t hHash ) +{ + int mid = (m_uiBucketMask+1) / 2; + int lastRemoveIndex = hHash; + // remove the item + m_pData[lastRemoveIndex].m_uiKey = InvalidHandle(); + m_dataCount--; + + // now search for any items needing to be swapped down + unsigned int endOfList = (unsigned int)InvalidHandle(); + for ( int index = (hHash+1) & m_uiBucketMask; m_pData[index].m_uiKey != endOfList; index = (index+1) & m_uiBucketMask ) + { + int ideal = CHashFunction::HashKey32(m_pData[index].m_uiKey) & m_uiBucketMask; + + // is the ideal index for this element <= (in a wrapped buffer sense) the ideal index of the removed element? + // if so, swap + int diff = ideal - lastRemoveIndex; + if ( diff > mid ) + { + diff -= (m_uiBucketMask+1); + } + if ( diff < -mid ) + { + diff += (m_uiBucketMask+1); + } + + // should I swap this? + if ( diff <= 0 ) + { + m_pData[lastRemoveIndex] = m_pData[index]; + lastRemoveIndex = index; + m_pData[index].m_uiKey = InvalidHandle(); + } + } +} + +template<class Data, class CHashFunction> void CUtlScalarHash<Data, CHashFunction>::FindAndRemove( unsigned int uiKey, const Data &dataRecord ) +{ + int index = CHashFunction::HashKey32(uiKey) & m_uiBucketMask; + unsigned int endOfList = (unsigned int)InvalidHandle(); + while ( m_pData[index].m_uiKey != endOfList ) + { + if ( m_pData[index].m_uiKey == uiKey && m_pData[index].m_Data == dataRecord ) + { + Remove(index); + return; + } + index = (index+1) & m_uiBucketMask; + } +} + +template<class Data, class CHashFunction> void CUtlScalarHash<Data, CHashFunction>::RemoveAll( void ) +{ + int elementCount = m_maxData * 2; + for ( int i = 0; i < elementCount; i++ ) + { + m_pData[i].m_uiKey = (unsigned)InvalidHandle(); + } + m_dataCount = 0; +} + +// Retrieval. +template<class Data, class CHashFunction> UtlHashFastHandle_t CUtlScalarHash<Data, CHashFunction>::Find( unsigned int uiKey, const Data &dataRecord ) const +{ + if ( m_pData == NULL ) + return InvalidHandle(); + int index = CHashFunction::HashKey32(uiKey) & m_uiBucketMask; + unsigned int endOfList = (unsigned int)InvalidHandle(); + while ( m_pData[index].m_uiKey != endOfList ) + { + if ( m_pData[index].m_uiKey == uiKey && m_pData[index].m_Data == dataRecord ) + return index; + index = (index+1) & m_uiBucketMask; + } + return InvalidHandle(); +} + +template<class Data, class CHashFunction> UtlHashFastHandle_t CUtlScalarHash<Data, CHashFunction>::FindByUniqueKey( unsigned int uiKey ) const +{ + if ( m_pData == NULL ) + return InvalidHandle(); + int index = CHashFunction::HashKey32(uiKey) & m_uiBucketMask; + unsigned int endOfList = (unsigned int)InvalidHandle(); + while ( m_pData[index].m_uiKey != endOfList ) + { + if ( m_pData[index].m_uiKey == uiKey ) + return index; + index = (index+1) & m_uiBucketMask; + } + return InvalidHandle(); +} + + +#endif // UTLHASH_H diff --git a/external/vpc/public/tier1/utllinkedlist.h b/external/vpc/public/tier1/utllinkedlist.h new file mode 100644 index 0000000..fcd5ba9 --- /dev/null +++ b/external/vpc/public/tier1/utllinkedlist.h @@ -0,0 +1,1087 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Linked list container class +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLLINKEDLIST_H +#define UTLLINKEDLIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/basetypes.h" +#include "utlmemory.h" +#include "utlfixedmemory.h" +#include "utlblockmemory.h" +#include "tier0/dbg.h" + +// define to enable asserts griping about things you shouldn't be doing with multilists +// #define MULTILIST_PEDANTIC_ASSERTS 1 + +// This is a useful macro to iterate from head to tail in a linked list. +#define FOR_EACH_LL( listName, iteratorName ) \ + for( int iteratorName=listName.Head(); iteratorName != listName.InvalidIndex(); iteratorName = listName.Next( iteratorName ) ) + +//----------------------------------------------------------------------------- +// class CUtlLinkedList: +// description: +// A lovely index-based linked list! T is the class type, I is the index +// type, which usually should be an unsigned short or smaller. However, +// you must avoid using 16- or 8-bit arithmetic on PowerPC architectures; +// therefore you should not use UtlLinkedListElem_t::I as the type of +// a local variable... ever. PowerPC integer arithmetic must be 32- or +// 64-bit only; otherwise performance plummets. +//----------------------------------------------------------------------------- + +template <class T, class I> +struct UtlLinkedListElem_t +{ + T m_Element; + I m_Previous; + I m_Next; + +private: + // No copy constructor for these... + UtlLinkedListElem_t( const UtlLinkedListElem_t& ); +}; + + +// Class S is the storage type; the type you can use to save off indices in +// persistent memory. Class I is the iterator type, which is what should be used +// in local scopes. I defaults to be S, but be aware that on the 360, 16-bit +// arithmetic is catastrophically slow. Therefore you should try to save shorts +// in memory, but always operate on 32's or 64's in local scope. +// The ideal parameter order would be TSMI (you are more likely to override M than I) +// but since M depends on I we can't have the defaults in that order, alas. +template <class T, class S = unsigned short, bool ML = false, class I = S, class M = CUtlMemory< UtlLinkedListElem_t<T, S>, I > > +class CUtlLinkedList +{ +public: + typedef T ElemType_t; + typedef S IndexType_t; // should really be called IndexStorageType_t, but that would be a huge change + typedef I IndexLocalType_t; + typedef M MemoryAllocator_t; + + // constructor, destructor + CUtlLinkedList( int growSize = 0, int initSize = 0 ); + ~CUtlLinkedList(); + + // gets particular elements + T& Element( I i ); + T const& Element( I i ) const; + T& operator[]( I i ); + T const& operator[]( I i ) const; + + // Make sure we have a particular amount of memory + void EnsureCapacity( int num ); + + void SetGrowSize( int growSize ); + + // Memory deallocation + void Purge(); + + // Delete all the elements then call Purge. + void PurgeAndDeleteElements(); + + // Insertion methods.... + I InsertBefore( I before ); + I InsertAfter( I after ); + I AddToHead( ); + I AddToTail( ); + + I InsertBefore( I before, T const& src ); + I InsertAfter( I after, T const& src ); + I AddToHead( T const& src ); + I AddToTail( T const& src ); + + // Find an element and return its index or InvalidIndex() if it couldn't be found. + I Find( const T &src ) const; + + // Look for the element. If it exists, remove it and return true. Otherwise, return false. + bool FindAndRemove( const T &src ); + + // Removal methods + void Remove( I elem ); + void RemoveAll(); + + // Allocation/deallocation methods + // If multilist == true, then list list may contain many + // non-connected lists, and IsInList and Head + Tail are meaningless... + I Alloc( bool multilist = false ); + void Free( I elem ); + + // Identify the owner of this linked list's memory: + void SetAllocOwner( const char *pszAllocOwner ); + + // list modification + void LinkBefore( I before, I elem ); + void LinkAfter( I after, I elem ); + void Unlink( I elem ); + void LinkToHead( I elem ); + void LinkToTail( I elem ); + + // invalid index (M will never allocate an element at this index) + inline static S InvalidIndex() { return ( S )M::InvalidIndex(); } + + // Is a given index valid to use? (representible by S and not the invalid index) + static bool IndexInRange( I index ); + + inline static size_t ElementSize() { return sizeof( ListElem_t ); } + + // list statistics + int Count() const; + I MaxElementIndex() const; + I NumAllocated( void ) const { return m_NumAlloced; } + + // Traversing the list + I Head() const; + I Tail() const; + I Previous( I i ) const; + I Next( I i ) const; + + // Are nodes in the list or valid? + bool IsValidIndex( I i ) const; + bool IsInList( I i ) const; + +protected: + + // What the linked list element looks like + typedef UtlLinkedListElem_t<T, S> ListElem_t; + + // constructs the class + I AllocInternal( bool multilist = false ); + void ConstructList(); + + // Gets at the list element.... + ListElem_t& InternalElement( I i ) { return m_Memory[i]; } + ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; } + + // copy constructors not allowed + CUtlLinkedList( CUtlLinkedList<T, S, ML, I, M> const& list ) { Assert(0); } + + M m_Memory; + I m_Head; + I m_Tail; + I m_FirstFree; + I m_ElementCount; // The number actually in the list + I m_NumAlloced; // The number of allocated elements + typename M::Iterator_t m_LastAlloc; // the last index allocated + + // For debugging purposes; + // it's in release builds so this can be used in libraries correctly + ListElem_t *m_pElements; + + FORCEINLINE M const &Memory( void ) const + { + return m_Memory; + } + + void ResetDbgInfo() + { + m_pElements = m_Memory.Base(); + } +}; + + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T > +class CUtlFixedLinkedList : public CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > > +{ +public: + CUtlFixedLinkedList( int growSize = 0, int initSize = 0 ) + : CUtlLinkedList< T, intp, true, intp, CUtlFixedMemory< UtlLinkedListElem_t< T, intp > > >( growSize, initSize ) {} + + bool IsValidIndex( intp i ) const + { + if ( !this->Memory().IsIdxValid( i ) ) + return false; + +#ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElementIndex + if ( this->Memory().IsIdxAfter( i, this->m_LastAlloc ) ) + { + Assert( 0 ); + return false; // don't read values that have been allocated, but not constructed + } +#endif + + return ( this->Memory()[ i ].m_Previous != i ) || ( this->Memory()[ i ].m_Next == i ); + } + +private: + int MaxElementIndex() const { Assert( 0 ); return this->InvalidIndex(); } // fixedmemory containers don't support iteration from 0..maxelements-1 + void ResetDbgInfo() {} +}; + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T, class I = unsigned short > +class CUtlBlockLinkedList : public CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > > +{ +public: + CUtlBlockLinkedList( int growSize = 0, int initSize = 0 ) + : CUtlLinkedList< T, I, true, I, CUtlBlockMemory< UtlLinkedListElem_t< T, I >, I > >( growSize, initSize ) {} +protected: + void ResetDbgInfo() {} +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template <class T, class S, bool ML, class I, class M> +CUtlLinkedList<T,S,ML,I,M>::CUtlLinkedList( int growSize, int initSize ) : + m_Memory( growSize, initSize ), m_LastAlloc( m_Memory.InvalidIterator() ) +{ + // Prevent signed non-int datatypes + COMPILE_TIME_ASSERT( sizeof(S) == 4 || ( ( (S)-1 ) > 0 ) ); + ConstructList(); + ResetDbgInfo(); +} + +template <class T, class S, bool ML, class I, class M> +CUtlLinkedList<T,S,ML,I,M>::~CUtlLinkedList( ) +{ + RemoveAll(); +} + +template <class T, class S, bool ML, class I, class M> +void CUtlLinkedList<T,S,ML,I,M>::ConstructList() +{ + m_Head = InvalidIndex(); + m_Tail = InvalidIndex(); + m_FirstFree = InvalidIndex(); + m_ElementCount = 0; + m_NumAlloced = 0; +} + + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- + +template <class T, class S, bool ML, class I, class M> +inline T& CUtlLinkedList<T,S,ML,I,M>::Element( I i ) +{ + return m_Memory[i].m_Element; +} + +template <class T, class S, bool ML, class I, class M> +inline T const& CUtlLinkedList<T,S,ML,I,M>::Element( I i ) const +{ + return m_Memory[i].m_Element; +} + +template <class T, class S, bool ML, class I, class M> +inline T& CUtlLinkedList<T,S,ML,I,M>::operator[]( I i ) +{ + return m_Memory[i].m_Element; +} + +template <class T, class S, bool ML, class I, class M> +inline T const& CUtlLinkedList<T,S,ML,I,M>::operator[]( I i ) const +{ + return m_Memory[i].m_Element; +} + +//----------------------------------------------------------------------------- +// list statistics +//----------------------------------------------------------------------------- + +template <class T, class S, bool ML, class I, class M> +inline int CUtlLinkedList<T,S,ML,I,M>::Count() const +{ +#ifdef MULTILIST_PEDANTIC_ASSERTS + AssertMsg( !ML, "CUtlLinkedList::Count() is meaningless for linked lists." ); +#endif + return m_ElementCount; +} + +template <class T, class S, bool ML, class I, class M> +inline I CUtlLinkedList<T,S,ML,I,M>::MaxElementIndex() const +{ + return m_Memory.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Traversing the list +//----------------------------------------------------------------------------- + +template <class T, class S, bool ML, class I, class M> +inline I CUtlLinkedList<T,S,ML,I,M>::Head() const +{ + return m_Head; +} + +template <class T, class S, bool ML, class I, class M> +inline I CUtlLinkedList<T,S,ML,I,M>::Tail() const +{ + return m_Tail; +} + +template <class T, class S, bool ML, class I, class M> +inline I CUtlLinkedList<T,S,ML,I,M>::Previous( I i ) const +{ + Assert( IsValidIndex(i) ); + return InternalElement(i).m_Previous; +} + +template <class T, class S, bool ML, class I, class M> +inline I CUtlLinkedList<T,S,ML,I,M>::Next( I i ) const +{ + Assert( IsValidIndex(i) ); + return InternalElement(i).m_Next; +} + + +//----------------------------------------------------------------------------- +// Are nodes in the list or valid? +//----------------------------------------------------------------------------- + +#pragma warning(push) +#pragma warning( disable: 4310 ) // Allows "(I)(S)M::INVALID_INDEX" below +template <class T, class S, bool ML, class I, class M> +inline bool CUtlLinkedList<T,S,ML,I,M>::IndexInRange( I index ) // Static method +{ + // Since S is not necessarily the type returned by M, we need to check that M returns indices + // which are representable by S. A common case is 'S === unsigned short', 'I == int', in which + // case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in S), and will + // happily return elements at index 65535 and above. + + // Do some static checks here: + // 'I' needs to be able to store 'S' + COMPILE_TIME_ASSERT( sizeof(I) >= sizeof(S) ); + // 'S' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges) + COMPILE_TIME_ASSERT( ( sizeof(S) > 2 ) || ( ( (S)-1 ) > 0 ) ); + // M::INVALID_INDEX should be storable in S to avoid ambiguities (e.g. with 65536) + COMPILE_TIME_ASSERT( ( M::INVALID_INDEX == -1 ) || ( M::INVALID_INDEX == (S)M::INVALID_INDEX ) ); + + return ( ( (S)index == index ) && ( (S)index != InvalidIndex() ) ); +} +#pragma warning(pop) + +template <class T, class S, bool ML, class I, class M> +inline bool CUtlLinkedList<T,S,ML,I,M>::IsValidIndex( I i ) const +{ + if ( !m_Memory.IsIdxValid( i ) ) + return false; + + if ( m_Memory.IsIdxAfter( i, m_LastAlloc ) ) + return false; // don't read values that have been allocated, but not constructed + + return ( m_Memory[ i ].m_Previous != i ) || ( m_Memory[ i ].m_Next == i ); +} + +template <class T, class S, bool ML, class I, class M> +inline bool CUtlLinkedList<T,S,ML,I,M>::IsInList( I i ) const +{ + if ( !m_Memory.IsIdxValid( i ) || m_Memory.IsIdxAfter( i, m_LastAlloc ) ) + return false; // don't read values that have been allocated, but not constructed + + return Previous( i ) != i; +} + +/* +template <class T> +inline bool CUtlFixedLinkedList<T>::IsInList( int i ) const +{ + return m_Memory.IsIdxValid( i ) && (Previous( i ) != i); +} +*/ + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- + +template< class T, class S, bool ML, class I, class M > +void CUtlLinkedList<T,S,ML,I,M>::EnsureCapacity( int num ) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + +template< class T, class S, bool ML, class I, class M > +void CUtlLinkedList<T,S,ML,I,M>::SetGrowSize( int growSize ) +{ + RemoveAll(); + m_Memory.Init( growSize ); + ResetDbgInfo(); +} + +template< class T, class S, bool ML, class I, class M > +void CUtlLinkedList<T,S,ML,I,M>::SetAllocOwner( const char *pszAllocOwner ) +{ + m_Memory.SetAllocOwner( pszAllocOwner ); +} + + +//----------------------------------------------------------------------------- +// Deallocate memory +//----------------------------------------------------------------------------- + +template <class T, class S, bool ML, class I, class M> +void CUtlLinkedList<T,S,ML,I,M>::Purge() +{ + RemoveAll(); + + m_Memory.Purge(); + m_FirstFree = InvalidIndex(); + m_NumAlloced = 0; + + //Routing "m_LastAlloc = m_Memory.InvalidIterator();" through a local const to sidestep an internal compiler error on 360 builds + const typename M::Iterator_t scInvalidIterator = m_Memory.InvalidIterator(); + m_LastAlloc = scInvalidIterator; + ResetDbgInfo(); +} + + +template<class T, class S, bool ML, class I, class M> +void CUtlLinkedList<T,S,ML,I,M>::PurgeAndDeleteElements() +{ + I iNext; + for( I i=Head(); i != InvalidIndex(); i=iNext ) + { + iNext = Next(i); + delete Element(i); + } + + Purge(); +} + + +//----------------------------------------------------------------------------- +// Node allocation/deallocation +//----------------------------------------------------------------------------- +template <class T, class S, bool ML, class I, class M> +I CUtlLinkedList<T,S,ML,I,M>::AllocInternal( bool multilist ) +{ + Assert( !multilist || ML ); +#ifdef MULTILIST_PEDANTIC_ASSERTS + Assert( multilist == ML ); +#endif + I elem; + if ( m_FirstFree == InvalidIndex() ) + { + Assert( m_Memory.IsValidIterator( m_LastAlloc ) || m_ElementCount == 0 ); + + typename M::Iterator_t it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First(); + + if ( !m_Memory.IsValidIterator( it ) ) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.Grow(); + ResetDbgInfo(); + + it = m_Memory.IsValidIterator( m_LastAlloc ) ? m_Memory.Next( m_LastAlloc ) : m_Memory.First(); + + Assert( m_Memory.IsValidIterator( it ) ); + if ( !m_Memory.IsValidIterator( it ) ) + { + ExecuteNTimes( 10, Warning( "CUtlLinkedList overflow! (exhausted memory allocator)\n" ) ); + return InvalidIndex(); + } + } + + // We can overflow before the utlmemory overflows, since S != I + if ( !IndexInRange( m_Memory.GetIndex( it ) ) ) + { + ExecuteNTimes( 10, Warning( "CUtlLinkedList overflow! (exhausted index range)\n" ) ); + return InvalidIndex(); + } + + m_LastAlloc = it; + elem = m_Memory.GetIndex( m_LastAlloc ); + m_NumAlloced++; + } + else + { + elem = m_FirstFree; + m_FirstFree = InternalElement( m_FirstFree ).m_Next; + } + + if ( !multilist ) + { + InternalElement( elem ).m_Next = elem; + InternalElement( elem ).m_Previous = elem; + } + else + { + InternalElement( elem ).m_Next = InvalidIndex(); + InternalElement( elem ).m_Previous = InvalidIndex(); + } + + return elem; +} + +template <class T, class S, bool ML, class I, class M> +I CUtlLinkedList<T,S,ML,I,M>::Alloc( bool multilist ) +{ + I elem = AllocInternal( multilist ); + if ( elem == InvalidIndex() ) + return elem; + + Construct( &Element(elem) ); + + return elem; +} + +template <class T, class S, bool ML, class I, class M> +void CUtlLinkedList<T,S,ML,I,M>::Free( I elem ) +{ + Assert( IsValidIndex(elem) && IndexInRange( elem ) ); + Unlink(elem); + + ListElem_t &internalElem = InternalElement(elem); + Destruct( &internalElem.m_Element ); + internalElem.m_Next = m_FirstFree; + m_FirstFree = elem; +} + +//----------------------------------------------------------------------------- +// Insertion methods; allocates and links (uses default constructor) +//----------------------------------------------------------------------------- + +template <class T, class S, bool ML, class I, class M> +I CUtlLinkedList<T,S,ML,I,M>::InsertBefore( I before ) +{ + // Make a new node + I newNode = AllocInternal(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkBefore( before, newNode ); + + // Construct the data + Construct( &Element(newNode) ); + + return newNode; +} + +template <class T, class S, bool ML, class I, class M> +I CUtlLinkedList<T,S,ML,I,M>::InsertAfter( I after ) +{ + // Make a new node + I newNode = AllocInternal(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkAfter( after, newNode ); + + // Construct the data + Construct( &Element(newNode) ); + + return newNode; +} + +template <class T, class S, bool ML, class I, class M> +inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( ) +{ + return InsertAfter( InvalidIndex() ); +} + +template <class T, class S, bool ML, class I, class M> +inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( ) +{ + return InsertBefore( InvalidIndex() ); +} + + +//----------------------------------------------------------------------------- +// Insertion methods; allocates and links (uses copy constructor) +//----------------------------------------------------------------------------- + +template <class T, class S, bool ML, class I, class M> +I CUtlLinkedList<T,S,ML,I,M>::InsertBefore( I before, T const& src ) +{ + // Make a new node + I newNode = AllocInternal(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkBefore( before, newNode ); + + // Construct the data + CopyConstruct( &Element(newNode), src ); + + return newNode; +} + +template <class T, class S, bool ML, class I, class M> +I CUtlLinkedList<T,S,ML,I,M>::InsertAfter( I after, T const& src ) +{ + // Make a new node + I newNode = AllocInternal(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkAfter( after, newNode ); + + // Construct the data + CopyConstruct( &Element(newNode), src ); + + return newNode; +} + +template <class T, class S, bool ML, class I, class M> +inline I CUtlLinkedList<T,S,ML,I,M>::AddToHead( T const& src ) +{ + return InsertAfter( InvalidIndex(), src ); +} + +template <class T, class S, bool ML, class I, class M> +inline I CUtlLinkedList<T,S,ML,I,M>::AddToTail( T const& src ) +{ + return InsertBefore( InvalidIndex(), src ); +} + + +//----------------------------------------------------------------------------- +// Removal methods +//----------------------------------------------------------------------------- + +template<class T, class S, bool ML, class I, class M> +I CUtlLinkedList<T,S,ML,I,M>::Find( const T &src ) const +{ + for ( I i=Head(); i != InvalidIndex(); i = Next( i ) ) + { + if ( Element( i ) == src ) + return i; + } + return InvalidIndex(); +} + + +template<class T, class S, bool ML, class I, class M> +bool CUtlLinkedList<T,S,ML,I,M>::FindAndRemove( const T &src ) +{ + I i = Find( src ); + if ( i == InvalidIndex() ) + { + return false; + } + else + { + Remove( i ); + return true; + } +} + + +template <class T, class S, bool ML, class I, class M> +void CUtlLinkedList<T,S,ML,I,M>::Remove( I elem ) +{ + Free( elem ); +} + +template <class T, class S, bool ML, class I, class M> +void CUtlLinkedList<T,S,ML,I,M>::RemoveAll() +{ + // Have to do some convoluted stuff to invoke the destructor on all + // valid elements for the multilist case (since we don't have all elements + // connected to each other in a list). + + if ( m_LastAlloc == m_Memory.InvalidIterator() ) + { + Assert( m_Head == InvalidIndex() ); + Assert( m_Tail == InvalidIndex() ); + Assert( m_FirstFree == InvalidIndex() ); + Assert( m_ElementCount == 0 ); + return; + } + + if ( ML ) + { + for ( typename M::Iterator_t it = m_Memory.First(); it != m_Memory.InvalidIterator(); it = m_Memory.Next( it ) ) + { + I i = m_Memory.GetIndex( it ); + if ( IsValidIndex( i ) ) // skip elements already in the free list + { + ListElem_t &internalElem = InternalElement( i ); + Destruct( &internalElem.m_Element ); + internalElem.m_Previous = i; + internalElem.m_Next = m_FirstFree; + m_FirstFree = i; + } + + if ( it == m_LastAlloc ) + break; // don't destruct elements that haven't ever been constructed + } + } + else + { + I i = Head(); + I next; + while ( i != InvalidIndex() ) + { + next = Next( i ); + ListElem_t &internalElem = InternalElement( i ); + Destruct( &internalElem.m_Element ); + internalElem.m_Previous = i; + internalElem.m_Next = next == InvalidIndex() ? m_FirstFree : next; + i = next; + } + if ( Head() != InvalidIndex() ) + { + m_FirstFree = Head(); + } + } + + // Clear everything else out + m_Head = InvalidIndex(); + m_Tail = InvalidIndex(); + m_ElementCount = 0; +} + + +//----------------------------------------------------------------------------- +// list modification +//----------------------------------------------------------------------------- + +template <class T, class S, bool ML, class I, class M> +void CUtlLinkedList<T,S,ML,I,M>::LinkBefore( I before, I elem ) +{ + Assert( IsValidIndex(elem) ); + + // Unlink it if it's in the list at the moment + Unlink(elem); + + ListElem_t * pNewElem = &InternalElement(elem); + + // The element *after* our newly linked one is the one we linked before. + pNewElem->m_Next = before; + + S newElem_mPrevious; // we need to hang on to this for the compairson against InvalidIndex() + // below; otherwise we get a a load-hit-store on pNewElem->m_Previous, even + // with + if (before == InvalidIndex()) + { + // In this case, we're linking to the end of the list, so reset the tail + newElem_mPrevious = m_Tail; + pNewElem->m_Previous = m_Tail; + m_Tail = elem; + } + else + { + // Here, we're not linking to the end. Set the prev pointer to point to + // the element we're linking. + Assert( IsInList(before) ); + ListElem_t * beforeElem = &InternalElement(before); + pNewElem->m_Previous = newElem_mPrevious = beforeElem->m_Previous; + beforeElem->m_Previous = elem; + } + + // Reset the head if we linked to the head of the list + if (newElem_mPrevious == InvalidIndex()) + m_Head = elem; + else + InternalElement(newElem_mPrevious).m_Next = elem; + + // one more element baby + ++m_ElementCount; +} + +template <class T, class S, bool ML, class I, class M> +void CUtlLinkedList<T,S,ML,I,M>::LinkAfter( I after, I elem ) +{ + Assert( IsValidIndex(elem) ); + + // Unlink it if it's in the list at the moment + if ( IsInList(elem) ) + Unlink(elem); + + ListElem_t& newElem = InternalElement(elem); + + // The element *before* our newly linked one is the one we linked after + newElem.m_Previous = after; + if (after == InvalidIndex()) + { + // In this case, we're linking to the head of the list, reset the head + newElem.m_Next = m_Head; + m_Head = elem; + } + else + { + // Here, we're not linking to the end. Set the next pointer to point to + // the element we're linking. + Assert( IsInList(after) ); + ListElem_t& afterElem = InternalElement(after); + newElem.m_Next = afterElem.m_Next; + afterElem.m_Next = elem; + } + + // Reset the tail if we linked to the tail of the list + if (newElem.m_Next == InvalidIndex()) + m_Tail = elem; + else + InternalElement(newElem.m_Next).m_Previous = elem; + + // one more element baby + ++m_ElementCount; +} + +template <class T, class S, bool ML, class I, class M> +void CUtlLinkedList<T,S,ML,I,M>::Unlink( I elem ) +{ + Assert( IsValidIndex(elem) ); + if (IsInList(elem)) + { + ListElem_t * pOldElem = &m_Memory[ elem ]; + + // If we're the first guy, reset the head + // otherwise, make our previous node's next pointer = our next + if ( pOldElem->m_Previous != InvalidIndex() ) + { + m_Memory[ pOldElem->m_Previous ].m_Next = pOldElem->m_Next; + } + else + { + m_Head = pOldElem->m_Next; + } + + // If we're the last guy, reset the tail + // otherwise, make our next node's prev pointer = our prev + if ( pOldElem->m_Next != InvalidIndex() ) + { + m_Memory[ pOldElem->m_Next ].m_Previous = pOldElem->m_Previous; + } + else + { + m_Tail = pOldElem->m_Previous; + } + + // This marks this node as not in the list, + // but not in the free list either + pOldElem->m_Previous = pOldElem->m_Next = elem; + + // One less puppy + --m_ElementCount; + } +} + +template <class T, class S, bool ML, class I, class M> +inline void CUtlLinkedList<T,S,ML,I,M>::LinkToHead( I elem ) +{ + LinkAfter( InvalidIndex(), elem ); +} + +template <class T, class S, bool ML, class I, class M> +inline void CUtlLinkedList<T,S,ML,I,M>::LinkToTail( I elem ) +{ + LinkBefore( InvalidIndex(), elem ); +} + + +//----------------------------------------------------------------------------- +// Class to drop in to replace a CUtlLinkedList that needs to be more memory agressive +//----------------------------------------------------------------------------- + +DECLARE_POINTER_HANDLE( UtlPtrLinkedListIndex_t ); // to enforce correct usage + +template < typename T > +class CUtlPtrLinkedList +{ +public: + CUtlPtrLinkedList() + : m_pFirst( NULL ), + m_nElems( 0 ) + { + COMPILE_TIME_ASSERT( sizeof(IndexType_t) == sizeof(Node_t *) ); + } + + ~CUtlPtrLinkedList() + { + RemoveAll(); + } + + typedef UtlPtrLinkedListIndex_t IndexType_t; + + T &operator[]( IndexType_t i ) + { + return (( Node_t * )i)->elem; + } + + const T &operator[]( IndexType_t i ) const + { + return (( Node_t * )i)->elem; + } + + IndexType_t AddToTail() + { + return DoInsertBefore( (IndexType_t)m_pFirst, NULL ); + } + + IndexType_t AddToTail( T const& src ) + { + return DoInsertBefore( (IndexType_t)m_pFirst, &src ); + } + + IndexType_t AddToHead() + { + IndexType_t result = DoInsertBefore( (IndexType_t)m_pFirst, NULL ); + m_pFirst = ((Node_t *)result); + return result; + } + + IndexType_t AddToHead( T const& src ) + { + IndexType_t result = DoInsertBefore( (IndexType_t)m_pFirst, &src ); + m_pFirst = ((Node_t *)result); + return result; + } + + IndexType_t InsertBefore( IndexType_t before ) + { + return DoInsertBefore( before, NULL ); + } + + IndexType_t InsertAfter( IndexType_t after ) + { + Node_t *pBefore = ((Node_t *)after)->next; + return DoInsertBefore( pBefore, NULL ); + } + + IndexType_t InsertBefore( IndexType_t before, T const& src ) + { + return DoInsertBefore( before, &src ); + } + + IndexType_t InsertAfter( IndexType_t after, T const& src ) + { + Node_t *pBefore = ((Node_t *)after)->next; + return DoInsertBefore( pBefore, &src ); + } + + void Remove( IndexType_t elem ) + { + Node_t *p = (Node_t *)elem; + + if ( p->pNext == p ) + { + m_pFirst = NULL; + } + else + { + if ( m_pFirst == p ) + { + m_pFirst = p->pNext; + } + p->pNext->pPrev = p->pPrev; + p->pPrev->pNext = p->pNext; + } + + delete p; + m_nElems--; + } + + void RemoveAll() + { + Node_t *p = m_pFirst; + if ( p ) + { + do + { + Node_t *pNext = p->pNext; + delete p; + p = pNext; + } while( p != m_pFirst ); + } + + m_pFirst = NULL; + m_nElems = 0; + } + + int Count() const + { + return m_nElems; + } + + IndexType_t Head() const + { + return (IndexType_t)m_pFirst; + } + + IndexType_t Next( IndexType_t i ) const + { + Node_t *p = ((Node_t *)i)->pNext; + if ( p != m_pFirst ) + { + return (IndexType_t)p; + } + return NULL; + } + + bool IsValidIndex( IndexType_t i ) const + { + Node_t *p = ((Node_t *)i); + return ( p && p->pNext && p->pPrev ); + } + + inline static IndexType_t InvalidIndex() + { + return NULL; + } +private: + + struct Node_t + { + Node_t() {} + Node_t( const T &_elem ) : elem( _elem ) {} + + T elem; + Node_t *pPrev, *pNext; + }; + + Node_t *AllocNode( const T *pCopyFrom ) + { + MEM_ALLOC_CREDIT_CLASS(); + Node_t *p; + + if ( !pCopyFrom ) + { + p = new Node_t; + } + else + { + p = new Node_t( *pCopyFrom ); + } + + return p; + } + + IndexType_t DoInsertBefore( IndexType_t before, const T *pCopyFrom ) + { + Node_t *p = AllocNode( pCopyFrom ); + Node_t *pBefore = (Node_t *)before; + if ( pBefore ) + { + p->pNext = pBefore; + p->pPrev = pBefore->pPrev; + pBefore->pPrev = p; + p->pPrev->pNext = p; + } + else + { + Assert( !m_pFirst ); + m_pFirst = p->pNext = p->pPrev = p; + } + + m_nElems++; + return (IndexType_t)p; + } + + Node_t *m_pFirst; + unsigned m_nElems; +}; + +//----------------------------------------------------------------------------- + +#endif // UTLLINKEDLIST_H diff --git a/external/vpc/public/tier1/utlmap.h b/external/vpc/public/tier1/utlmap.h new file mode 100644 index 0000000..aeca2b4 --- /dev/null +++ b/external/vpc/public/tier1/utlmap.h @@ -0,0 +1,248 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLMAP_H +#define UTLMAP_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include "utlrbtree.h" + +//----------------------------------------------------------------------------- +// +// Purpose: An associative container. Pretty much identical to std::map. +// +//----------------------------------------------------------------------------- + +// This is a useful macro to iterate from start to end in order in a map +#define FOR_EACH_MAP( mapName, iteratorName ) \ + for ( int iteratorName = (mapName).FirstInorder(); (mapName).IsUtlMap && iteratorName != (mapName).InvalidIndex(); iteratorName = (mapName).NextInorder( iteratorName ) ) + +// faster iteration, but in an unspecified order +#define FOR_EACH_MAP_FAST( mapName, iteratorName ) \ + for ( int iteratorName = 0; (mapName).IsUtlMap && iteratorName < (mapName).MaxElement(); ++iteratorName ) if ( !(mapName).IsValidIndex( iteratorName ) ) continue; else + +struct base_utlmap_t +{ +public: + static const bool IsUtlMap = true; // Used to match this at compiletime +}; + +#if defined( GNUC ) && defined( DEBUG ) +const bool base_utlmap_t::IsUtlMap SELECTANY; +#endif + +template <typename K, typename T, typename I = unsigned short> +class CUtlMap : public base_utlmap_t +{ +public: + typedef K KeyType_t; + typedef T ElemType_t; + typedef I IndexType_t; + + // Less func typedef + // Returns true if the first parameter is "less" than the second + typedef bool (*LessFunc_t)( const KeyType_t &, const KeyType_t & ); + + // constructor, destructor + // Left at growSize = 0, the memory will first allocate 1 element and double in size + // at each increment. + // LessFunc_t is required, but may be set after the constructor using SetLessFunc() below + CUtlMap( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0 ) + : m_Tree( growSize, initSize, CKeyLess( lessfunc ) ) + { + } + + CUtlMap( LessFunc_t lessfunc ) + : m_Tree( CKeyLess( lessfunc ) ) + { + } + + void EnsureCapacity( int num ) { m_Tree.EnsureCapacity( num ); } + + // gets particular elements + ElemType_t & Element( IndexType_t i ) { return m_Tree.Element( i ).elem; } + const ElemType_t & Element( IndexType_t i ) const { return m_Tree.Element( i ).elem; } + ElemType_t & operator[]( IndexType_t i ) { return m_Tree.Element( i ).elem; } + const ElemType_t & operator[]( IndexType_t i ) const { return m_Tree.Element( i ).elem; } + KeyType_t & Key( IndexType_t i ) { return m_Tree.Element( i ).key; } + const KeyType_t & Key( IndexType_t i ) const { return m_Tree.Element( i ).key; } + + + // Num elements + unsigned int Count() const { return m_Tree.Count(); } + + // Max "size" of the vector + IndexType_t MaxElement() const { return m_Tree.MaxElement(); } + + // Checks if a node is valid and in the map + bool IsValidIndex( IndexType_t i ) const { return m_Tree.IsValidIndex( i ); } + + // Checks if the map as a whole is valid + bool IsValid() const { return m_Tree.IsValid(); } + + // Invalid index + static IndexType_t InvalidIndex() { return CTree::InvalidIndex(); } + + // Sets the less func + void SetLessFunc( LessFunc_t func ) + { + m_Tree.SetLessFunc( CKeyLess( func ) ); + } + + // Insert method (inserts in order) + IndexType_t Insert( const KeyType_t &key, const ElemType_t &insert ) + { + Node_t node; + node.key = key; + node.elem = insert; + return m_Tree.Insert( node ); + } + + IndexType_t Insert( const KeyType_t &key ) + { + Node_t node; + node.key = key; + return m_Tree.Insert( node ); + } + + // Find method + IndexType_t Find( const KeyType_t &key ) const + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.Find( dummyNode ); + } + + // Remove methods + void RemoveAt( IndexType_t i ) { m_Tree.RemoveAt( i ); } + bool Remove( const KeyType_t &key ) + { + Node_t dummyNode; + dummyNode.key = key; + return m_Tree.Remove( dummyNode ); + } + + void RemoveAll( ) { m_Tree.RemoveAll(); } + void Purge( ) { m_Tree.Purge(); } + + // Purges the list and calls delete on each element in it. + void PurgeAndDeleteElements(); + + // Iteration + IndexType_t FirstInorder() const { return m_Tree.FirstInorder(); } + IndexType_t NextInorder( IndexType_t i ) const { return m_Tree.NextInorder( i ); } + IndexType_t PrevInorder( IndexType_t i ) const { return m_Tree.PrevInorder( i ); } + IndexType_t LastInorder() const { return m_Tree.LastInorder(); } + + // If you change the search key, this can be used to reinsert the + // element into the map. + void Reinsert( const KeyType_t &key, IndexType_t i ) + { + m_Tree[i].key = key; + m_Tree.Reinsert(i); + } + + IndexType_t InsertOrReplace( const KeyType_t &key, const ElemType_t &insert ) + { + IndexType_t i = Find( key ); + if ( i != InvalidIndex() ) + { + Element( i ) = insert; + return i; + } + + return Insert( key, insert ); + } + + void Swap( CUtlMap< K, T, I > &that ) + { + m_Tree.Swap( that.m_Tree ); + } + + + struct Node_t + { + Node_t() + { + } + + Node_t( const Node_t &from ) + : key( from.key ), + elem( from.elem ) + { + } + + KeyType_t key; + ElemType_t elem; + }; + + class CKeyLess + { + public: + CKeyLess( LessFunc_t lessFunc ) : m_LessFunc(lessFunc) {} + + bool operator!() const + { + return !m_LessFunc; + } + + bool operator()( const Node_t &left, const Node_t &right ) const + { + return m_LessFunc( left.key, right.key ); + } + + LessFunc_t m_LessFunc; + }; + + typedef CUtlRBTree<Node_t, I, CKeyLess> CTree; + + CTree *AccessTree() { return &m_Tree; } + +protected: + CTree m_Tree; +}; + +//----------------------------------------------------------------------------- + +// Purges the list and calls delete on each element in it. +template< typename K, typename T, typename I > +inline void CUtlMap<K, T, I>::PurgeAndDeleteElements() +{ + for ( I i = 0; i < MaxElement(); ++i ) + { + if ( !IsValidIndex( i ) ) + continue; + + delete Element( i ); + } + + Purge(); +} + +//----------------------------------------------------------------------------- + +// This is horrible and slow and meant to be used only when you're dealing with really +// non-time/memory-critical code and desperately want to copy a whole map element-by-element +// for whatever reason. +template < typename K, typename T, typename I > +void DeepCopyMap( const CUtlMap<K,T,I>& pmapIn, CUtlMap<K,T,I> *out_pmapOut ) +{ + Assert( out_pmapOut ); + + out_pmapOut->Purge(); + FOR_EACH_MAP_FAST( pmapIn, i ) + { + out_pmapOut->Insert( i, pmapIn[i] ); + } +} + +#endif // UTLMAP_H diff --git a/external/vpc/public/tier1/utlmemory.h b/external/vpc/public/tier1/utlmemory.h new file mode 100644 index 0000000..40e6a19 --- /dev/null +++ b/external/vpc/public/tier1/utlmemory.h @@ -0,0 +1,1090 @@ +//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable memory class. +//===========================================================================// + +#ifndef UTLMEMORY_H +#define UTLMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/dbg.h" +#include <string.h> +#include "tier0/platform.h" + +#include "tier0/memalloc.h" +#include "mathlib/mathlib.h" +#include "tier0/memdbgon.h" + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + + +//----------------------------------------------------------------------------- + + +#ifdef UTLMEMORY_TRACK +#define UTLMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "||Sum of all UtlMemory||", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 ) +#define UTLMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "||Sum of all UtlMemory||", 0, m_nAllocationCount * sizeof(T), m_nAllocationCount * sizeof(T), 0 ) +#else +#define UTLMEMORY_TRACK_ALLOC() ((void)0) +#define UTLMEMORY_TRACK_FREE() ((void)0) +#endif + + +//----------------------------------------------------------------------------- +// The CUtlMemory class: +// A growable memory class which doubles in size by default. +//----------------------------------------------------------------------------- +template< class T, class I = int > +class CUtlMemory +{ +public: + // constructor, destructor + CUtlMemory( int nGrowSize = 0, int nInitSize = 0 ); + CUtlMemory( T* pMemory, int numElements ); + CUtlMemory( const T* pMemory, int numElements ); + ~CUtlMemory(); + + // Set the size by which the memory grows + void Init( int nGrowSize = 0, int nInitSize = 0 ); + + class Iterator_t + { + public: + Iterator_t( I i ) : index( i ) {} + I index; + + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); } + I GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( I i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } + + // element access + T& operator[]( I i ); + const T& operator[]( I i ) const; + T& Element( I i ); + const T& Element( I i ) const; + + // Can we use this index? + bool IsIdxValid( I i ) const; + + // Specify the invalid ('null') index that we'll only return on failure + static const I INVALID_INDEX = ( I )-1; // For use with COMPILE_TIME_ASSERT + static I InvalidIndex() { return INVALID_INDEX; } + + // Gets the base address (can change when adding elements!) + T* Base(); + const T* Base() const; + + // Attaches the buffer to external memory.... + void SetExternalBuffer( T* pMemory, int numElements ); + void SetExternalBuffer( const T* pMemory, int numElements ); + void AssumeMemory( T *pMemory, int nSize ); + T* Detach(); + void *DetachMemory(); + + // Fast swap + void Swap( CUtlMemory< T, I > &mem ); + + // Switches the buffer from an external memory buffer to a reallocatable buffer + // Will copy the current contents of the external buffer to the reallocatable buffer + void ConvertToGrowableMemory( int nGrowSize ); + + // Size + int NumAllocated() const; + int Count() const; + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow( int num = 1 ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + + // Purge all but the given number of elements + void Purge( int numElements ); + + // is the memory externally allocated? + bool IsExternallyAllocated() const; + + // is the memory read only? + bool IsReadOnly() const; + + // Set the size by which the memory grows + void SetGrowSize( int size ); + +protected: + void ValidateGrowSize() + { +#ifdef _X360 + if ( m_nGrowSize && m_nGrowSize != EXTERNAL_BUFFER_MARKER ) + { + // Max grow size at 128 bytes on XBOX + const int MAX_GROW = 128; + if ( m_nGrowSize * sizeof(T) > MAX_GROW ) + { + m_nGrowSize = max( 1, MAX_GROW / sizeof(T) ); + } + } +#endif + } + + enum + { + EXTERNAL_BUFFER_MARKER = -1, + EXTERNAL_CONST_BUFFER_MARKER = -2, + }; + + T* m_pMemory; + int m_nAllocationCount; + int m_nGrowSize; +}; + + +//----------------------------------------------------------------------------- +// The CUtlMemory class: +// A growable memory class which doubles in size by default. +//----------------------------------------------------------------------------- +template< class T, size_t SIZE, class I = int > +class CUtlMemoryFixedGrowable : public CUtlMemory< T, I > +{ + typedef CUtlMemory< T, I > BaseClass; + +public: + CUtlMemoryFixedGrowable( int nGrowSize = 0, int nInitSize = SIZE ) : BaseClass( m_pFixedMemory, SIZE ) + { + Assert( nInitSize == 0 || nInitSize == SIZE ); + m_nMallocGrowSize = nGrowSize; + } + + void Grow( int nCount = 1 ) + { + if ( this->IsExternallyAllocated() ) + { + this->ConvertToGrowableMemory( m_nMallocGrowSize ); + } + BaseClass::Grow( nCount ); + } + + void EnsureCapacity( int num ) + { + if ( CUtlMemory<T>::m_nAllocationCount >= num ) + return; + + if ( this->IsExternallyAllocated() ) + { + // Can't grow a buffer whose memory was externally allocated + this->ConvertToGrowableMemory( m_nMallocGrowSize ); + } + + BaseClass::EnsureCapacity( num ); + } + +private: + int m_nMallocGrowSize; + T m_pFixedMemory[ SIZE ]; +}; + +//----------------------------------------------------------------------------- +// The CUtlMemoryFixed class: +// A fixed memory class +//----------------------------------------------------------------------------- +template< typename T, size_t SIZE, int nAlignment = 0 > +class CUtlMemoryFixed +{ +public: + // constructor, destructor + CUtlMemoryFixed( int nGrowSize = 0, int nInitSize = 0 ) { Assert( nInitSize == 0 || nInitSize == SIZE ); } + CUtlMemoryFixed( T* pMemory, int numElements ) { Assert( 0 ); } + + // Can we use this index? + bool IsIdxValid( int i ) const { return (i >= 0) && (i < SIZE); } + + // Specify the invalid ('null') index that we'll only return on failure + static const int INVALID_INDEX = -1; // For use with COMPILE_TIME_ASSERT + static int InvalidIndex() { return INVALID_INDEX; } + + // Gets the base address + T* Base() { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); } + const T* Base() const { if ( nAlignment == 0 ) return (T*)(&m_Memory[0]); else return (T*)AlignValue( &m_Memory[0], nAlignment ); } + + // element access + T& operator[]( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& operator[]( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + T& Element( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& Element( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + + // Attaches the buffer to external memory.... + void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); } + + // Size + int NumAllocated() const { return SIZE; } + int Count() const { return SIZE; } + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow( int num = 1 ) { Assert( 0 ); } + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ) { Assert( num <= SIZE ); } + + // Memory deallocation + void Purge() {} + + // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryFixed) + void Purge( int numElements ) { Assert( 0 ); } + + // is the memory externally allocated? + bool IsExternallyAllocated() const { return false; } + + // Set the size by which the memory grows + void SetGrowSize( int size ) {} + + class Iterator_t + { + public: + Iterator_t( int i ) : index( i ) {} + int index; + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { return Iterator_t( IsIdxValid( 0 ) ? 0 : InvalidIndex() ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( IsIdxValid( it.index + 1 ) ? it.index + 1 : InvalidIndex() ); } + int GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( int i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ); } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex() ); } + +private: + char m_Memory[ SIZE*sizeof(T) + nAlignment ]; +}; + +#ifdef _LINUX +#define REMEMBER_ALLOC_SIZE_FOR_VALGRIND 1 +#endif + +//----------------------------------------------------------------------------- +// The CUtlMemoryConservative class: +// A dynamic memory class that tries to minimize overhead (itself small, no custom grow factor) +//----------------------------------------------------------------------------- +template< typename T > +class CUtlMemoryConservative +{ + +public: + // constructor, destructor + CUtlMemoryConservative( int nGrowSize = 0, int nInitSize = 0 ) : m_pMemory( NULL ) + { +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + m_nCurAllocSize = 0; +#endif + + } + CUtlMemoryConservative( T* pMemory, int numElements ) { Assert( 0 ); } + ~CUtlMemoryConservative() { if ( m_pMemory ) free( m_pMemory ); } + + // Can we use this index? + bool IsIdxValid( int i ) const { return ( IsDebug() ) ? ( i >= 0 && i < NumAllocated() ) : ( i >= 0 ); } + static int InvalidIndex() { return -1; } + + // Gets the base address + T* Base() { return m_pMemory; } + const T* Base() const { return m_pMemory; } + + // element access + T& operator[]( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& operator[]( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + T& Element( int i ) { Assert( IsIdxValid(i) ); return Base()[i]; } + const T& Element( int i ) const { Assert( IsIdxValid(i) ); return Base()[i]; } + + // Attaches the buffer to external memory.... + void SetExternalBuffer( T* pMemory, int numElements ) { Assert( 0 ); } + + // Size + FORCEINLINE void RememberAllocSize( size_t sz ) + { +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + m_nCurAllocSize = sz; +#endif + } + + size_t AllocSize( void ) const + { +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + return m_nCurAllocSize; +#else + return ( m_pMemory ) ? g_pMemAlloc->GetSize( m_pMemory ) : 0; +#endif + } + + int NumAllocated() const + { + return AllocSize() / sizeof( T ); + } + int Count() const + { + return NumAllocated(); + } + + FORCEINLINE void ReAlloc( size_t sz ) + { + m_pMemory = (T*)realloc( m_pMemory, sz ); + RememberAllocSize( sz ); + } + // Grows the memory, so that at least allocated + num elements are allocated + void Grow( int num = 1 ) + { + int nCurN = NumAllocated(); + ReAlloc( ( nCurN + num ) * sizeof( T ) ); + } + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ) + { + size_t nSize = sizeof( T ) * MAX( num, Count() ); + ReAlloc( nSize ); + } + + // Memory deallocation + void Purge() + { + free( m_pMemory ); + RememberAllocSize( 0 ); + m_pMemory = NULL; + } + + // Purge all but the given number of elements + void Purge( int numElements ) { ReAlloc( numElements * sizeof(T) ); } + + // is the memory externally allocated? + bool IsExternallyAllocated() const { return false; } + + // Set the size by which the memory grows + void SetGrowSize( int size ) {} + + class Iterator_t + { + public: + Iterator_t( int i, int _limit ) : index( i ), limit( _limit ) {} + int index; + int limit; + bool operator==( const Iterator_t it ) const { return index == it.index; } + bool operator!=( const Iterator_t it ) const { return index != it.index; } + }; + Iterator_t First() const { int limit = NumAllocated(); return Iterator_t( limit ? 0 : InvalidIndex(), limit ); } + Iterator_t Next( const Iterator_t &it ) const { return Iterator_t( ( it.index + 1 < it.limit ) ? it.index + 1 : InvalidIndex(), it.limit ); } + int GetIndex( const Iterator_t &it ) const { return it.index; } + bool IsIdxAfter( int i, const Iterator_t &it ) const { return i > it.index; } + bool IsValidIterator( const Iterator_t &it ) const { return IsIdxValid( it.index ) && ( it.index < it.limit ); } + Iterator_t InvalidIterator() const { return Iterator_t( InvalidIndex(), 0 ); } + +private: + T *m_pMemory; +#ifdef REMEMBER_ALLOC_SIZE_FOR_VALGRIND + size_t m_nCurAllocSize; +#endif + +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T, class I > +CUtlMemory<T,I>::CUtlMemory( int nGrowSize, int nInitAllocationCount ) : m_pMemory(0), + m_nAllocationCount( nInitAllocationCount ), m_nGrowSize( nGrowSize ) +{ + ValidateGrowSize(); + Assert( nGrowSize >= 0 ); + if (m_nAllocationCount) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); + } +} + +template< class T, class I > +CUtlMemory<T,I>::CUtlMemory( T* pMemory, int numElements ) : m_pMemory(pMemory), + m_nAllocationCount( numElements ) +{ + // Special marker indicating externally supplied modifyable memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T, class I > +CUtlMemory<T,I>::CUtlMemory( const T* pMemory, int numElements ) : m_pMemory( (T*)pMemory ), + m_nAllocationCount( numElements ) +{ + // Special marker indicating externally supplied modifyable memory + m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; +} + +template< class T, class I > +CUtlMemory<T,I>::~CUtlMemory() +{ + Purge(); + +#ifdef _DEBUG + m_pMemory = reinterpret_cast< T* >( 0xFEFEBAAD ); + m_nAllocationCount = 0x7BADF00D; +#endif +} + +template< class T, class I > +void CUtlMemory<T,I>::Init( int nGrowSize /*= 0*/, int nInitSize /*= 0*/ ) +{ + Purge(); + + m_nGrowSize = nGrowSize; + m_nAllocationCount = nInitSize; + ValidateGrowSize(); + Assert( nGrowSize >= 0 ); + if (m_nAllocationCount) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); + } +} + +//----------------------------------------------------------------------------- +// Fast swap +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory<T,I>::Swap( CUtlMemory<T,I> &mem ) +{ + V_swap( m_nGrowSize, mem.m_nGrowSize ); + V_swap( m_pMemory, mem.m_pMemory ); + V_swap( m_nAllocationCount, mem.m_nAllocationCount ); +} + + +//----------------------------------------------------------------------------- +// Switches the buffer from an external memory buffer to a reallocatable buffer +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory<T,I>::ConvertToGrowableMemory( int nGrowSize ) +{ + if ( !IsExternallyAllocated() ) + return; + + m_nGrowSize = nGrowSize; + if (m_nAllocationCount) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + + int nNumBytes = m_nAllocationCount * sizeof(T); + T *pMemory = (T*)malloc( nNumBytes ); + memcpy( pMemory, m_pMemory, nNumBytes ); + m_pMemory = pMemory; + } + else + { + m_pMemory = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory<T,I>::SetExternalBuffer( T* pMemory, int numElements ) +{ + // Blow away any existing allocated memory + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = numElements; + + // Indicate that we don't own the memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T, class I > +void CUtlMemory<T,I>::SetExternalBuffer( const T* pMemory, int numElements ) +{ + // Blow away any existing allocated memory + Purge(); + + m_pMemory = const_cast<T*>( pMemory ); + m_nAllocationCount = numElements; + + // Indicate that we don't own the memory + m_nGrowSize = EXTERNAL_CONST_BUFFER_MARKER; +} + +template< class T, class I > +void CUtlMemory<T,I>::AssumeMemory( T* pMemory, int numElements ) +{ + // Blow away any existing allocated memory + Purge(); + + // Simply take the pointer but don't mark us as external + m_pMemory = pMemory; + m_nAllocationCount = numElements; +} + +template< class T, class I > +void *CUtlMemory<T,I>::DetachMemory() +{ + if ( IsExternallyAllocated() ) + return NULL; + + void *pMemory = m_pMemory; + m_pMemory = 0; + m_nAllocationCount = 0; + return pMemory; +} + +template< class T, class I > +inline T* CUtlMemory<T,I>::Detach() +{ + return (T*)DetachMemory(); +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T, class I > +inline T& CUtlMemory<T,I>::operator[]( I i ) +{ + Assert( !IsReadOnly() ); + Assert( IsIdxValid(i) ); + return m_pMemory[i]; +} + +template< class T, class I > +inline const T& CUtlMemory<T,I>::operator[]( I i ) const +{ + Assert( IsIdxValid(i) ); + return m_pMemory[i]; +} + +template< class T, class I > +inline T& CUtlMemory<T,I>::Element( I i ) +{ + Assert( !IsReadOnly() ); + Assert( IsIdxValid(i) ); + return m_pMemory[i]; +} + +template< class T, class I > +inline const T& CUtlMemory<T,I>::Element( I i ) const +{ + Assert( IsIdxValid(i) ); + return m_pMemory[i]; +} + + +//----------------------------------------------------------------------------- +// is the memory externally allocated? +//----------------------------------------------------------------------------- +template< class T, class I > +bool CUtlMemory<T,I>::IsExternallyAllocated() const +{ + return (m_nGrowSize < 0); +} + + +//----------------------------------------------------------------------------- +// is the memory read only? +//----------------------------------------------------------------------------- +template< class T, class I > +bool CUtlMemory<T,I>::IsReadOnly() const +{ + return (m_nGrowSize == EXTERNAL_CONST_BUFFER_MARKER); +} + + +template< class T, class I > +void CUtlMemory<T,I>::SetGrowSize( int nSize ) +{ + Assert( !IsExternallyAllocated() ); + Assert( nSize >= 0 ); + m_nGrowSize = nSize; + ValidateGrowSize(); +} + + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- +template< class T, class I > +inline T* CUtlMemory<T,I>::Base() +{ + Assert( !IsReadOnly() ); + return m_pMemory; +} + +template< class T, class I > +inline const T *CUtlMemory<T,I>::Base() const +{ + return m_pMemory; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T, class I > +inline int CUtlMemory<T,I>::NumAllocated() const +{ + return m_nAllocationCount; +} + +template< class T, class I > +inline int CUtlMemory<T,I>::Count() const +{ + return m_nAllocationCount; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T, class I > +inline bool CUtlMemory<T,I>::IsIdxValid( I i ) const +{ + // GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0). + // We get the warning even if we cast inside the expression. It only goes away if we assign to another variable. + long x = i; + return ( x >= 0 ) && ( x < m_nAllocationCount ); +} + +//----------------------------------------------------------------------------- +// Grows the memory +//----------------------------------------------------------------------------- +inline int UtlMemory_CalcNewAllocationCount( int nAllocationCount, int nGrowSize, int nNewSize, int nBytesItem ) +{ + if ( nGrowSize ) + { + nAllocationCount = ((1 + ((nNewSize - 1) / nGrowSize)) * nGrowSize); + } + else + { + if ( !nAllocationCount ) + { + // Compute an allocation which is at least as big as a cache line... + nAllocationCount = (31 + nBytesItem) / nBytesItem; + } + + while (nAllocationCount < nNewSize) + { +#ifndef _X360 + nAllocationCount *= 2; +#else + int nNewAllocationCount = ( nAllocationCount * 9) / 8; // 12.5 % + if ( nNewAllocationCount > nAllocationCount ) + nAllocationCount = nNewAllocationCount; + else + nAllocationCount *= 2; +#endif + } + } + + return nAllocationCount; +} + +template< class T, class I > +void CUtlMemory<T,I>::Grow( int num ) +{ + Assert( num > 0 ); + + if ( IsExternallyAllocated() ) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + // Make sure we have at least numallocated + num allocations. + // Use the grow rules specified for this memory (in m_nGrowSize) + int nAllocationRequested = m_nAllocationCount + num; + + UTLMEMORY_TRACK_FREE(); + + int nNewAllocationCount = UtlMemory_CalcNewAllocationCount( m_nAllocationCount, m_nGrowSize, nAllocationRequested, sizeof(T) ); + + // if m_nAllocationRequested wraps index type I, recalculate + if ( ( int )( I )nNewAllocationCount < nAllocationRequested ) + { + if ( ( int )( I )nNewAllocationCount == 0 && ( int )( I )( nNewAllocationCount - 1 ) >= nAllocationRequested ) + { + --nNewAllocationCount; // deal w/ the common case of m_nAllocationCount == MAX_USHORT + 1 + } + else + { + if ( ( int )( I )nAllocationRequested != nAllocationRequested ) + { + // we've been asked to grow memory to a size s.t. the index type can't address the requested amount of memory + Assert( 0 ); + return; + } + while ( ( int )( I )nNewAllocationCount < nAllocationRequested ) + { + nNewAllocationCount = ( nNewAllocationCount + nAllocationRequested ) / 2; + } + } + } + + m_nAllocationCount = nNewAllocationCount; + + UTLMEMORY_TRACK_ALLOC(); + + if (m_pMemory) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) ); + Assert( m_pMemory ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); + Assert( m_pMemory ); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T, class I > +inline void CUtlMemory<T,I>::EnsureCapacity( int num ) +{ + if (m_nAllocationCount >= num) + return; + + if ( IsExternallyAllocated() ) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + m_nAllocationCount = num; + + UTLMEMORY_TRACK_ALLOC(); + + if (m_pMemory) + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)malloc( m_nAllocationCount * sizeof(T) ); + } +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMemory<T,I>::Purge() +{ + if ( !IsExternallyAllocated() ) + { + if (m_pMemory) + { + UTLMEMORY_TRACK_FREE(); + free( (void*)m_pMemory ); + m_pMemory = 0; + } + m_nAllocationCount = 0; + } +} + +template< class T, class I > +void CUtlMemory<T,I>::Purge( int numElements ) +{ + Assert( numElements >= 0 ); + + if( numElements > m_nAllocationCount ) + { + // Ensure this isn't a grow request in disguise. + Assert( numElements <= m_nAllocationCount ); + return; + } + + // If we have zero elements, simply do a purge: + if( numElements == 0 ) + { + Purge(); + return; + } + + if ( IsExternallyAllocated() ) + { + // Can't shrink a buffer whose memory was externally allocated, fail silently like purge + return; + } + + // If the number of elements is the same as the allocation count, we are done. + if( numElements == m_nAllocationCount ) + { + return; + } + + + if( !m_pMemory ) + { + // Allocation count is non zero, but memory is null. + Assert( m_pMemory ); + return; + } + + UTLMEMORY_TRACK_FREE(); + + m_nAllocationCount = numElements; + + UTLMEMORY_TRACK_ALLOC(); + + // Allocation count > 0, shrink it down. + MEM_ALLOC_CREDIT_CLASS(); + m_pMemory = (T*)realloc( m_pMemory, m_nAllocationCount * sizeof(T) ); +} + +//----------------------------------------------------------------------------- +// The CUtlMemory class: +// A growable memory class which doubles in size by default. +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +class CUtlMemoryAligned : public CUtlMemory<T> +{ +public: + // constructor, destructor + CUtlMemoryAligned( int nGrowSize = 0, int nInitSize = 0 ); + CUtlMemoryAligned( T* pMemory, int numElements ); + CUtlMemoryAligned( const T* pMemory, int numElements ); + ~CUtlMemoryAligned(); + + // Attaches the buffer to external memory.... + void SetExternalBuffer( T* pMemory, int numElements ); + void SetExternalBuffer( const T* pMemory, int numElements ); + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow( int num = 1 ); + + // Makes sure we've got at least this much memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + + // Purge all but the given number of elements (NOT IMPLEMENTED IN CUtlMemoryAligned) + void Purge( int numElements ) { Assert( 0 ); } + +private: + void *Align( const void *pAddr ); +}; + + +//----------------------------------------------------------------------------- +// Aligns a pointer +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void *CUtlMemoryAligned<T, nAlignment>::Align( const void *pAddr ) +{ + size_t nAlignmentMask = nAlignment - 1; + return (void*)( ((size_t)pAddr + nAlignmentMask) & (~nAlignmentMask) ); +} + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned( int nGrowSize, int nInitAllocationCount ) +{ + CUtlMemory<T>::m_pMemory = 0; + CUtlMemory<T>::m_nAllocationCount = nInitAllocationCount; + CUtlMemory<T>::m_nGrowSize = nGrowSize; + this->ValidateGrowSize(); + + // Alignment must be a power of two + COMPILE_TIME_ASSERT( (nAlignment & (nAlignment-1)) == 0 ); + Assert( (nGrowSize >= 0) && (nGrowSize != CUtlMemory<T>::EXTERNAL_BUFFER_MARKER) ); + if ( CUtlMemory<T>::m_nAllocationCount ) + { + UTLMEMORY_TRACK_ALLOC(); + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory<T>::m_pMemory = (T*)_aligned_malloc( nInitAllocationCount * sizeof(T), nAlignment ); + } +} + +template< class T, int nAlignment > +CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned( T* pMemory, int numElements ) +{ + // Special marker indicating externally supplied memory + CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_BUFFER_MARKER; + + CUtlMemory<T>::m_pMemory = (T*)Align( pMemory ); + CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T); +} + +template< class T, int nAlignment > +CUtlMemoryAligned<T, nAlignment>::CUtlMemoryAligned( const T* pMemory, int numElements ) +{ + // Special marker indicating externally supplied memory + CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_CONST_BUFFER_MARKER; + + CUtlMemory<T>::m_pMemory = (T*)Align( pMemory ); + CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T); +} + +template< class T, int nAlignment > +CUtlMemoryAligned<T, nAlignment>::~CUtlMemoryAligned() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void CUtlMemoryAligned<T, nAlignment>::SetExternalBuffer( T* pMemory, int numElements ) +{ + // Blow away any existing allocated memory + Purge(); + + CUtlMemory<T>::m_pMemory = (T*)Align( pMemory ); + CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T); + + // Indicate that we don't own the memory + CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_BUFFER_MARKER; +} + +template< class T, int nAlignment > +void CUtlMemoryAligned<T, nAlignment>::SetExternalBuffer( const T* pMemory, int numElements ) +{ + // Blow away any existing allocated memory + Purge(); + + CUtlMemory<T>::m_pMemory = (T*)Align( pMemory ); + CUtlMemory<T>::m_nAllocationCount = ( (int)(pMemory + numElements) - (int)CUtlMemory<T>::m_pMemory ) / sizeof(T); + + // Indicate that we don't own the memory + CUtlMemory<T>::m_nGrowSize = CUtlMemory<T>::EXTERNAL_CONST_BUFFER_MARKER; +} + + +//----------------------------------------------------------------------------- +// Grows the memory +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void CUtlMemoryAligned<T, nAlignment>::Grow( int num ) +{ + Assert( num > 0 ); + + if ( this->IsExternallyAllocated() ) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + // Make sure we have at least numallocated + num allocations. + // Use the grow rules specified for this memory (in m_nGrowSize) + int nAllocationRequested = CUtlMemory<T>::m_nAllocationCount + num; + + CUtlMemory<T>::m_nAllocationCount = UtlMemory_CalcNewAllocationCount( CUtlMemory<T>::m_nAllocationCount, CUtlMemory<T>::m_nGrowSize, nAllocationRequested, sizeof(T) ); + + UTLMEMORY_TRACK_ALLOC(); + + if ( CUtlMemory<T>::m_pMemory ) + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory<T>::m_pMemory = (T*)MemAlloc_ReallocAligned( CUtlMemory<T>::m_pMemory, CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment ); + Assert( CUtlMemory<T>::m_pMemory ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory<T>::m_pMemory = (T*)MemAlloc_AllocAligned( CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment ); + Assert( CUtlMemory<T>::m_pMemory ); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +inline void CUtlMemoryAligned<T, nAlignment>::EnsureCapacity( int num ) +{ + if ( CUtlMemory<T>::m_nAllocationCount >= num ) + return; + + if ( this->IsExternallyAllocated() ) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + UTLMEMORY_TRACK_FREE(); + + CUtlMemory<T>::m_nAllocationCount = num; + + UTLMEMORY_TRACK_ALLOC(); + + if ( CUtlMemory<T>::m_pMemory ) + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory<T>::m_pMemory = (T*)MemAlloc_ReallocAligned( CUtlMemory<T>::m_pMemory, CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment ); + } + else + { + MEM_ALLOC_CREDIT_CLASS(); + CUtlMemory<T>::m_pMemory = (T*)MemAlloc_AllocAligned( CUtlMemory<T>::m_nAllocationCount * sizeof(T), nAlignment ); + } +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T, int nAlignment > +void CUtlMemoryAligned<T, nAlignment>::Purge() +{ + if ( !this->IsExternallyAllocated() ) + { + if ( CUtlMemory<T>::m_pMemory ) + { + UTLMEMORY_TRACK_FREE(); + MemAlloc_FreeAligned( CUtlMemory<T>::m_pMemory ); + CUtlMemory<T>::m_pMemory = 0; + } + CUtlMemory<T>::m_nAllocationCount = 0; + } +} + +#include "tier0/memdbgoff.h" + +#endif // UTLMEMORY_H diff --git a/external/vpc/public/tier1/utlmultilist.h b/external/vpc/public/tier1/utlmultilist.h new file mode 100644 index 0000000..68e2a98 --- /dev/null +++ b/external/vpc/public/tier1/utlmultilist.h @@ -0,0 +1,769 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Multiple linked list container class +// +// $Revision: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLMULTILIST_H +#define UTLMULTILIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utllinkedlist.h" + +// memdbgon must be the last include file in a .h file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// class CUtlMultiList: +// description: +// A lovely index-based linked list! T is the class type, I is the index +// type, which usually should be an unsigned short or smaller. +// This list can contain multiple lists +//----------------------------------------------------------------------------- +template <class T, class I> +class CUtlMultiList +{ +protected: + // What the linked list element looks like + struct ListElem_t + { + T m_Element; + I m_Previous; + I m_Next; + }; + + struct List_t + { + I m_Head; + I m_Tail; + I m_Count; + }; + + typedef CUtlMemory<ListElem_t> M; // Keep naming similar to CUtlLinkedList +public: + typedef I ListHandle_t; + + // constructor, destructor + CUtlMultiList( int growSize = 0, int initSize = 0 ); + CUtlMultiList( void *pMemory, int memsize ); + ~CUtlMultiList( ); + + // gets particular elements + T& Element( I i ); + T const& Element( I i ) const; + T& operator[]( I i ); + T const& operator[]( I i ) const; + + // Make sure we have a particular amount of memory + void EnsureCapacity( int num ); + + // Memory deallocation + void Purge(); + + // List Creation/deletion + ListHandle_t CreateList(); + void DestroyList( ListHandle_t list ); + bool IsValidList( ListHandle_t list ) const; + + // Insertion methods (call default constructor).... + I InsertBefore( ListHandle_t list, I before ); + I InsertAfter( ListHandle_t list, I after ); + I AddToHead( ListHandle_t list ); + I AddToTail( ListHandle_t list ); + + // Insertion methods (call copy constructor).... + I InsertBefore( ListHandle_t list, I before, T const& src ); + I InsertAfter( ListHandle_t list, I after, T const& src ); + I AddToHead( ListHandle_t list, T const& src ); + I AddToTail( ListHandle_t list, T const& src ); + + // Removal methods + void Remove( ListHandle_t list, I elem ); + + // Removes all items in a single list + void RemoveAll( ListHandle_t list ); + + // Removes all items in all lists + void RemoveAll(); + + // Allocation/deallocation methods + // NOTE: To free, it must *not* be in a list! + I Alloc( ); + void Free( I elem ); + + // list modification + void LinkBefore( ListHandle_t list, I before, I elem ); + void LinkAfter( ListHandle_t list, I after, I elem ); + void Unlink( ListHandle_t list, I elem ); + void LinkToHead( ListHandle_t list, I elem ); + void LinkToTail( ListHandle_t list, I elem ); + + // invalid index + static I InvalidIndex() { return (I)~0; } + static bool IndexInRange( int index ); + static size_t ElementSize() { return sizeof(ListElem_t); } + + // list statistics + int Count( ListHandle_t list ) const; + int TotalCount( ) const; + I MaxElementIndex() const; + + // Traversing the list + I Head( ListHandle_t list ) const; + I Tail( ListHandle_t list ) const; + I Previous( I element ) const; + I Next( I element ) const; + + // Are nodes in a list or valid? + bool IsValidIndex( I i ) const; + bool IsInList( I i ) const; + +protected: + // constructs the class + void ConstructList( ); + + // Gets at the list element.... + ListElem_t& InternalElement( I i ) { return m_Memory[i]; } + ListElem_t const& InternalElement( I i ) const { return m_Memory[i]; } + + // A test for debug mode only... + bool IsElementInList( ListHandle_t list, I elem ) const; + + // copy constructors not allowed + CUtlMultiList( CUtlMultiList<T, I> const& list ) { Assert(0); } + + M m_Memory; + CUtlLinkedList<List_t, I> m_List; + I* m_pElementList; + + I m_FirstFree; + I m_TotalElements; + int m_MaxElementIndex; // The number allocated (use int so we can catch overflow) + + void ResetDbgInfo() + { + m_pElements = m_Memory.Base(); + +#ifdef _DEBUG + // Allocate space for the element list (which list is each element in) + if (m_Memory.NumAllocated() > 0) + { + if (!m_pElementList) + { + m_pElementList = (I*)malloc( m_Memory.NumAllocated() * sizeof(I) ); + } + else + { + m_pElementList = (I*)realloc( m_pElementList, m_Memory.NumAllocated() * sizeof(I) ); + } + } +#endif + } + + // For debugging purposes; + // it's in release builds so this can be used in libraries correctly + ListElem_t *m_pElements; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template <class T, class I> +CUtlMultiList<T,I>::CUtlMultiList( int growSize, int initSize ) : + m_Memory(growSize, initSize), m_pElementList(0) +{ + ConstructList(); +} + +template <class T, class I> +CUtlMultiList<T,I>::CUtlMultiList( void* pMemory, int memsize ) : + m_Memory((ListElem_t *)pMemory, memsize/sizeof(ListElem_t)), m_pElementList(0) +{ + ConstructList(); +} + +template <class T, class I> +CUtlMultiList<T,I>::~CUtlMultiList( ) +{ + RemoveAll(); + if (m_pElementList) + free(m_pElementList); +} + +template <class T, class I> +void CUtlMultiList<T,I>::ConstructList( ) +{ + m_FirstFree = InvalidIndex(); + m_TotalElements = 0; + m_MaxElementIndex = 0; + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- +template <class T, class I> +inline T& CUtlMultiList<T,I>::Element( I i ) +{ + return m_Memory[i].m_Element; +} + +template <class T, class I> +inline T const& CUtlMultiList<T,I>::Element( I i ) const +{ + return m_Memory[i].m_Element; +} + +template <class T, class I> +inline T& CUtlMultiList<T,I>::operator[]( I i ) +{ + return m_Memory[i].m_Element; +} + +template <class T, class I> +inline T const& CUtlMultiList<T,I>::operator[]( I i ) const +{ + return m_Memory[i].m_Element; +} + + +//----------------------------------------------------------------------------- +// list creation/destruction +//----------------------------------------------------------------------------- +template <class T, class I> +typename CUtlMultiList<T,I>::ListHandle_t CUtlMultiList<T,I>::CreateList() +{ + ListHandle_t l = m_List.AddToTail(); + m_List[l].m_Head = m_List[l].m_Tail = InvalidIndex(); + m_List[l].m_Count = 0; + return l; +} + +template <class T, class I> +void CUtlMultiList<T,I>::DestroyList( ListHandle_t list ) +{ + Assert( IsValidList(list) ); + RemoveAll( list ); + m_List.Remove(list); +} + +template <class T, class I> +bool CUtlMultiList<T,I>::IsValidList( ListHandle_t list ) const +{ + return m_List.IsValidIndex(list); +} + + +//----------------------------------------------------------------------------- +// list statistics +//----------------------------------------------------------------------------- +template <class T, class I> +inline int CUtlMultiList<T,I>::TotalCount() const +{ + return m_TotalElements; +} + +template <class T, class I> +inline int CUtlMultiList<T,I>::Count( ListHandle_t list ) const +{ + Assert( IsValidList(list) ); + return m_List[list].m_Count; +} + +template <class T, class I> +inline I CUtlMultiList<T,I>::MaxElementIndex() const +{ + return m_MaxElementIndex; +} + + +//----------------------------------------------------------------------------- +// Traversing the list +//----------------------------------------------------------------------------- +template <class T, class I> +inline I CUtlMultiList<T,I>::Head(ListHandle_t list) const +{ + Assert( IsValidList(list) ); + return m_List[list].m_Head; +} + +template <class T, class I> +inline I CUtlMultiList<T,I>::Tail(ListHandle_t list) const +{ + Assert( IsValidList(list) ); + return m_List[list].m_Tail; +} + +template <class T, class I> +inline I CUtlMultiList<T,I>::Previous( I i ) const +{ + Assert( IsValidIndex(i) ); + return InternalElement(i).m_Previous; +} + +template <class T, class I> +inline I CUtlMultiList<T,I>::Next( I i ) const +{ + Assert( IsValidIndex(i) ); + return InternalElement(i).m_Next; +} + + +//----------------------------------------------------------------------------- +// Are nodes in the list or valid? +//----------------------------------------------------------------------------- + +template <class T, class I> +inline bool CUtlMultiList<T,I>::IndexInRange( int index ) // Static method +{ + // Since I is not necessarily the type returned by M (int), we need to check that M returns + // indices which are representable by I. A common case is 'I === unsigned short', in which case + // case CUtlMemory will have 'InvalidIndex == (int)-1' (which casts to 65535 in I), and will + // happily return elements at index 65535 and above. + + // Do a couple of static checks here: the invalid index should be (I)~0 given how we use m_MaxElementIndex, + // and 'I' should be unsigned (to avoid signed arithmetic errors for plausibly exhaustible ranges). + COMPILE_TIME_ASSERT( (I)M::INVALID_INDEX == (I)~0 ); + COMPILE_TIME_ASSERT( ( sizeof(I) > 2 ) || ( ( (I)-1 ) > 0 ) ); + + return ( ( (I)index == index ) && ( (I)index != InvalidIndex() ) ); +} + +template <class T, class I> +inline bool CUtlMultiList<T,I>::IsValidIndex( I i ) const +{ + // GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0). + // We get the warning even if we cast inside the expression. It only goes away if we assign to another variable. + long x = i; + + return (i < m_MaxElementIndex) && (x >= 0) && + ((m_Memory[i].m_Previous != i) || (m_Memory[i].m_Next == i)); +} + +template <class T, class I> +inline bool CUtlMultiList<T,I>::IsInList( I i ) const +{ + // GCC warns if I is an unsigned type and we do a ">= 0" against it (since the comparison is always 0). + // We get the warning even if we cast inside the expression. It only goes away if we assign to another variable. + long x = i; + return (i < m_MaxElementIndex) && (x >= 0) && (Previous(i) != i); +} + + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- +template< class T, class I > +void CUtlMultiList<T, I>::EnsureCapacity( int num ) +{ + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Deallocate memory +//----------------------------------------------------------------------------- +template <class T, class I> +void CUtlMultiList<T,I>::Purge() +{ + RemoveAll(); + m_List.Purge(); + m_Memory.Purge( ); + m_List.Purge(); + m_FirstFree = InvalidIndex(); + m_TotalElements = 0; + m_MaxElementIndex = 0; + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Node allocation/deallocation +//----------------------------------------------------------------------------- +template <class T, class I> +I CUtlMultiList<T,I>::Alloc( ) +{ + I elem; + if (m_FirstFree == InvalidIndex()) + { + // We can overflow before the utlmemory overflows, since we have have I != int + if ( !IndexInRange( m_MaxElementIndex ) ) + { + ExecuteNTimes( 10, Warning( "CUtlMultiList overflow! (exhausted index range)\n" ) ); + return InvalidIndex(); + } + + // Nothing in the free list; add. + // Since nothing is in the free list, m_TotalElements == total # of elements + // the list knows about. + if (m_MaxElementIndex == m_Memory.NumAllocated()) + { + m_Memory.Grow(); + ResetDbgInfo(); + + if ( m_MaxElementIndex >= m_Memory.NumAllocated() ) + { + ExecuteNTimes( 10, Warning( "CUtlMultiList overflow! (exhausted memory allocator)\n" ) ); + return InvalidIndex(); + } + } + + elem = (I)m_MaxElementIndex; + ++m_MaxElementIndex; + } + else + { + elem = m_FirstFree; + m_FirstFree = InternalElement(m_FirstFree).m_Next; + } + + // Mark the element as not being in a list + InternalElement(elem).m_Next = InternalElement(elem).m_Previous = elem; + + ++m_TotalElements; + + Construct( &Element(elem) ); + + return elem; +} + +template <class T, class I> +void CUtlMultiList<T,I>::Free( I elem ) +{ + Assert( IsValidIndex(elem) && !IsInList(elem) ); + Destruct( &Element(elem) ); + InternalElement(elem).m_Next = m_FirstFree; + m_FirstFree = elem; + --m_TotalElements; +} + + +//----------------------------------------------------------------------------- +// A test for debug mode only... +//----------------------------------------------------------------------------- +template <class T, class I> +inline bool CUtlMultiList<T,I>::IsElementInList( ListHandle_t list, I elem ) const +{ + if (!m_pElementList) + return true; + + return m_pElementList[elem] == list; +} + + +//----------------------------------------------------------------------------- +// list modification +//----------------------------------------------------------------------------- +template <class T, class I> +void CUtlMultiList<T,I>::LinkBefore( ListHandle_t list, I before, I elem ) +{ + Assert( IsValidIndex(elem) && IsValidList(list) ); + + // Unlink it if it's in the list at the moment + Unlink(list, elem); + + ListElem_t& newElem = InternalElement(elem); + + // The element *after* our newly linked one is the one we linked before. + newElem.m_Next = before; + + if (before == InvalidIndex()) + { + // In this case, we're linking to the end of the list, so reset the tail + newElem.m_Previous = m_List[list].m_Tail; + m_List[list].m_Tail = elem; + } + else + { + // Here, we're not linking to the end. Set the prev pointer to point to + // the element we're linking. + Assert( IsInList(before) ); + ListElem_t& beforeElem = InternalElement(before); + newElem.m_Previous = beforeElem.m_Previous; + beforeElem.m_Previous = elem; + } + + // Reset the head if we linked to the head of the list + if (newElem.m_Previous == InvalidIndex()) + m_List[list].m_Head = elem; + else + InternalElement(newElem.m_Previous).m_Next = elem; + + // one more element baby + ++m_List[list].m_Count; + + // Store the element into the list + if (m_pElementList) + m_pElementList[elem] = list; +} + +template <class T, class I> +void CUtlMultiList<T,I>::LinkAfter( ListHandle_t list, I after, I elem ) +{ + Assert( IsValidIndex(elem) ); + + // Unlink it if it's in the list at the moment + Unlink(list, elem); + + ListElem_t& newElem = InternalElement(elem); + + // The element *before* our newly linked one is the one we linked after + newElem.m_Previous = after; + if (after == InvalidIndex()) + { + // In this case, we're linking to the head of the list, reset the head + newElem.m_Next = m_List[list].m_Head; + m_List[list].m_Head = elem; + } + else + { + // Here, we're not linking to the end. Set the next pointer to point to + // the element we're linking. + Assert( IsInList(after) ); + ListElem_t& afterElem = InternalElement(after); + newElem.m_Next = afterElem.m_Next; + afterElem.m_Next = elem; + } + + // Reset the tail if we linked to the tail of the list + if (newElem.m_Next == InvalidIndex()) + m_List[list].m_Tail = elem; + else + InternalElement(newElem.m_Next).m_Previous = elem; + + // one more element baby + ++m_List[list].m_Count; + + // Store the element into the list + if (m_pElementList) + m_pElementList[elem] = list; +} + +template <class T, class I> +void CUtlMultiList<T,I>::Unlink( ListHandle_t list, I elem ) +{ + Assert( IsValidIndex(elem) && IsValidList(list) ); + + if (IsInList(elem)) + { + // Make sure the element is in the right list + Assert( IsElementInList( list, elem ) ); + ListElem_t& oldElem = InternalElement(elem); + + // If we're the first guy, reset the head + // otherwise, make our previous node's next pointer = our next + if (oldElem.m_Previous != InvalidIndex()) + InternalElement(oldElem.m_Previous).m_Next = oldElem.m_Next; + else + m_List[list].m_Head = oldElem.m_Next; + + // If we're the last guy, reset the tail + // otherwise, make our next node's prev pointer = our prev + if (oldElem.m_Next != InvalidIndex()) + InternalElement(oldElem.m_Next).m_Previous = oldElem.m_Previous; + else + m_List[list].m_Tail = oldElem.m_Previous; + + // This marks this node as not in the list, + // but not in the free list either + oldElem.m_Previous = oldElem.m_Next = elem; + + // One less puppy + --m_List[list].m_Count; + + // Store the element into the list + if (m_pElementList) + m_pElementList[elem] = m_List.InvalidIndex(); + } +} + +template <class T, class I> +inline void CUtlMultiList<T,I>::LinkToHead( ListHandle_t list, I elem ) +{ + LinkAfter( list, InvalidIndex(), elem ); +} + +template <class T, class I> +inline void CUtlMultiList<T,I>::LinkToTail( ListHandle_t list, I elem ) +{ + LinkBefore( list, InvalidIndex(), elem ); +} + + +//----------------------------------------------------------------------------- +// Insertion methods; allocates and links (uses default constructor) +//----------------------------------------------------------------------------- +template <class T, class I> +I CUtlMultiList<T,I>::InsertBefore( ListHandle_t list, I before ) +{ + // Make a new node + I newNode = Alloc(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkBefore( list, before, newNode ); + + // Construct the data + Construct( &Element(newNode) ); + + return newNode; +} + +template <class T, class I> +I CUtlMultiList<T,I>::InsertAfter( ListHandle_t list, I after ) +{ + // Make a new node + I newNode = Alloc(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkAfter( list, after, newNode ); + + // Construct the data + Construct( &Element(newNode) ); + + return newNode; +} + +template <class T, class I> +inline I CUtlMultiList<T,I>::AddToHead( ListHandle_t list ) +{ + return InsertAfter( list, InvalidIndex() ); +} + +template <class T, class I> +inline I CUtlMultiList<T,I>::AddToTail( ListHandle_t list ) +{ + return InsertBefore( list, InvalidIndex() ); +} + + +//----------------------------------------------------------------------------- +// Insertion methods; allocates and links (uses copy constructor) +//----------------------------------------------------------------------------- +template <class T, class I> +I CUtlMultiList<T,I>::InsertBefore( ListHandle_t list, I before, T const& src ) +{ + // Make a new node + I newNode = Alloc(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkBefore( list, before, newNode ); + + // Construct the data + CopyConstruct( &Element(newNode), src ); + + return newNode; +} + +template <class T, class I> +I CUtlMultiList<T,I>::InsertAfter( ListHandle_t list, I after, T const& src ) +{ + // Make a new node + I newNode = Alloc(); + if ( newNode == InvalidIndex() ) + return newNode; + + // Link it in + LinkAfter( list, after, newNode ); + + // Construct the data + CopyConstruct( &Element(newNode), src ); + + return newNode; +} + +template <class T, class I> +inline I CUtlMultiList<T,I>::AddToHead( ListHandle_t list, T const& src ) +{ + return InsertAfter( list, InvalidIndex(), src ); +} + +template <class T, class I> +inline I CUtlMultiList<T,I>::AddToTail( ListHandle_t list, T const& src ) +{ + return InsertBefore( list, InvalidIndex(), src ); +} + + +//----------------------------------------------------------------------------- +// Removal methods +//----------------------------------------------------------------------------- +template <class T, class I> +void CUtlMultiList<T,I>::Remove( ListHandle_t list, I elem ) +{ + if (IsInList(elem)) + Unlink(list, elem); + Free( elem ); +} + +// Removes all items in a single list +template <class T, class I> +void CUtlMultiList<T,I>::RemoveAll( ListHandle_t list ) +{ + Assert( IsValidList(list) ); + I i = Head(list); + I next; + while( i != InvalidIndex() ) + { + next = Next(i); + Remove(list, i); + i = next; + } +} + + +template <class T, class I> +void CUtlMultiList<T,I>::RemoveAll() +{ + if (m_MaxElementIndex == 0) + return; + + // Put everything into the free list + I prev = InvalidIndex(); + for (int i = (int)m_MaxElementIndex; --i >= 0; ) + { + // Invoke the destructor + if (IsValidIndex((I)i)) + Destruct( &Element((I)i) ); + + // next points to the next free list item + InternalElement((I)i).m_Next = prev; + + // Indicates it's in the free list + InternalElement((I)i).m_Previous = (I)i; + prev = (I)i; + } + + // First free points to the first element + m_FirstFree = 0; + + // Clear everything else out + for (I list = m_List.Head(); list != m_List.InvalidIndex(); list = m_List.Next(list) ) + { + m_List[list].m_Head = InvalidIndex(); + m_List[list].m_Tail = InvalidIndex(); + m_List[list].m_Count = 0; + } + + m_TotalElements = 0; +} + + +#include "tier0/memdbgoff.h" + +#endif // UTLMULTILIST_H diff --git a/external/vpc/public/tier1/utlqueue.h b/external/vpc/public/tier1/utlqueue.h new file mode 100644 index 0000000..d816407 --- /dev/null +++ b/external/vpc/public/tier1/utlqueue.h @@ -0,0 +1,176 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLQUEUE_H +#define UTLQUEUE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + +// T is the type stored in the queue +template< class T, class M = CUtlMemory< T > > +class CUtlQueue +{ +public: + + // constructor: lessfunc is required, but may be set after the constructor with + // SetLessFunc + CUtlQueue( int growSize = 0, int initSize = 0 ); + CUtlQueue( T *pMemory, int numElements ); + + // element access + T& operator[]( int i ); + T const& operator[]( int i ) const; + T& Element( int i ); + T const& Element( int i ) const; + + // return the item from the front of the queue and delete it + T const& RemoveAtHead(); + // return the item from the end of the queue and delete it + T const& RemoveAtTail(); + + // return item at the front of the queue + T const& Head(); + // return item at the end of the queue + T const& Tail(); + + // put a new item on the queue to the tail. + void Insert( T const &element ); + + // checks if an element of this value already exists on the queue, returns true if it does + bool Check( T const element ); + + // Returns the count of elements in the queue + int Count() const { return m_heap.Count(); } + + // Is element index valid? + bool IsIdxValid( int i ) const; + + // doesn't deallocate memory + void RemoveAll() { m_heap.RemoveAll(); } + + // Memory deallocation + void Purge() { m_heap.Purge(); } + +protected: + CUtlVector<T, M> m_heap; + T m_current; +}; + +//----------------------------------------------------------------------------- +// The CUtlQueueFixed class: +// A queue class with a fixed allocation scheme +//----------------------------------------------------------------------------- +template< class T, size_t MAX_SIZE > +class CUtlQueueFixed : public CUtlQueue< T, CUtlMemoryFixed<T, MAX_SIZE > > +{ + typedef CUtlQueue< T, CUtlMemoryFixed<T, MAX_SIZE > > BaseClass; +public: + + // constructor, destructor + CUtlQueueFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + CUtlQueueFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + +template< class T, class M > +inline CUtlQueue<T, M>::CUtlQueue( int growSize, int initSize ) : + m_heap(growSize, initSize) +{ +} + +template< class T, class M > +inline CUtlQueue<T, M>::CUtlQueue( T *pMemory, int numElements ) : + m_heap(pMemory, numElements) +{ +} + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- + +template< class T, class M > +inline T& CUtlQueue<T,M>::operator[]( int i ) +{ + return m_heap[i]; +} + +template< class T, class M > +inline T const& CUtlQueue<T,M>::operator[]( int i ) const +{ + return m_heap[i]; +} + +template< class T, class M > +inline T& CUtlQueue<T,M>::Element( int i ) +{ + return m_heap[i]; +} + +template< class T, class M > +inline T const& CUtlQueue<T,M>::Element( int i ) const +{ + return m_heap[i]; +} + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- + +template< class T, class M > +inline bool CUtlQueue<T,M>::IsIdxValid( int i ) const +{ + return (i >= 0) && (i < m_heap.Count()); +} + +template <class T, class M> +inline T const& CUtlQueue<T, M>::RemoveAtHead() +{ + m_current = m_heap[0]; + m_heap.Remove((int)0); + return m_current; +} + +template <class T, class M> +inline T const& CUtlQueue<T, M>::RemoveAtTail() +{ + m_current = m_heap[ m_heap.Count() - 1 ]; + m_heap.Remove((int)(m_heap.Count() - 1)); + return m_current; +} + +template <class T, class M> +inline T const& CUtlQueue<T, M>::Head() +{ + m_current = m_heap[0]; + return m_current; +} + +template <class T, class M> +inline T const& CUtlQueue<T, M>::Tail() +{ + m_current = m_heap[ m_heap.Count() - 1 ]; + return m_current; +} + +template <class T, class M> +void CUtlQueue<T, M>::Insert( T const &element ) +{ + int index = m_heap.AddToTail(); + m_heap[index] = element; +} + +template <class T, class M> +bool CUtlQueue<T, M>::Check( T const element ) +{ + int index = m_heap.Find(element); + return ( index != -1 ); +} + + +#endif // UTLQUEUE_H diff --git a/external/vpc/public/tier1/utlrbtree.h b/external/vpc/public/tier1/utlrbtree.h new file mode 100644 index 0000000..5031cca --- /dev/null +++ b/external/vpc/public/tier1/utlrbtree.h @@ -0,0 +1,1581 @@ +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef UTLRBTREE_H +#define UTLRBTREE_H + +#include "tier1/utlmemory.h" +#include "tier1/utlfixedmemory.h" +#include "tier1/utlblockmemory.h" + + +// This is a useful macro to iterate from start to end in order in a map +#define FOR_EACH_UTLRBTREE( treeName, iteratorName ) \ + for ( int iteratorName = treeName.FirstInorder(); iteratorName != treeName.InvalidIndex(); iteratorName = treeName.NextInorder( iteratorName ) ) + + +//----------------------------------------------------------------------------- +// Tool to generate a default compare function for any type that implements +// operator<, including all simple types +//----------------------------------------------------------------------------- + +template <typename T > +class CDefOps +{ +public: + static bool LessFunc( const T &lhs, const T &rhs ) { return ( lhs < rhs ); } +}; + +#define DefLessFunc( type ) CDefOps< type >::LessFunc + +//------------------------------------- + +inline bool StringLessThan( const char * const &lhs, const char * const &rhs) { + if ( !lhs ) return false; + if ( !rhs ) return true; + return ( strcmp( lhs, rhs) < 0 ); +} + +inline bool CaselessStringLessThan( const char * const &lhs, const char * const &rhs ) { + if ( !lhs ) return false; + if ( !rhs ) return true; + return ( stricmp( lhs, rhs) < 0 ); +} + + +// Same as CaselessStringLessThan, but it ignores differences in / and \. +inline bool CaselessStringLessThanIgnoreSlashes( const char * const &lhs, const char * const &rhs ) +{ + const char *pa = lhs; + const char *pb = rhs; + while ( *pa && *pb ) + { + char a = *pa; + char b = *pb; + + // Check for dir slashes. + if ( a == '/' || a == '\\' ) + { + if ( b != '/' && b != '\\' ) + return ('/' < b); + } + else + { + if ( a >= 'a' && a <= 'z' ) + a = 'A' + (a - 'a'); + + if ( b >= 'a' && b <= 'z' ) + b = 'A' + (b - 'a'); + + if ( a > b ) + return false; + else if ( a < b ) + return true; + } + ++pa; + ++pb; + } + + // Filenames also must be the same length. + if ( *pa != *pb ) + { + // If pa shorter than pb then it's "less" + return ( !*pa ); + } + + return false; +} + +//------------------------------------- +// inline these two templates to stop multiple definitions of the same code +template <> inline bool CDefOps<const char *>::LessFunc( const char * const &lhs, const char * const &rhs ) { return StringLessThan( lhs, rhs ); } +template <> inline bool CDefOps<char *>::LessFunc( char * const &lhs, char * const &rhs ) { return StringLessThan( lhs, rhs ); } + +//------------------------------------- + +template <typename RBTREE_T> +void SetDefLessFunc( RBTREE_T &RBTree ) +{ + RBTree.SetLessFunc( DefLessFunc( typename RBTREE_T::KeyType_t ) ); +} + +//----------------------------------------------------------------------------- +// A red-black binary search tree +//----------------------------------------------------------------------------- + +template < class I > +struct UtlRBTreeLinks_t +{ + I m_Left; + I m_Right; + I m_Parent; + I m_Tag; +}; + +template < class T, class I > +struct UtlRBTreeNode_t : public UtlRBTreeLinks_t< I > +{ + T m_Data; +}; + +template < class T, class I = unsigned short, typename L = bool (*)( const T &, const T & ), class M = CUtlMemory< UtlRBTreeNode_t< T, I >, I > > +class CUtlRBTree +{ +public: + + typedef T KeyType_t; + typedef T ElemType_t; + typedef I IndexType_t; + + // Less func typedef + // Returns true if the first parameter is "less" than the second + typedef L LessFunc_t; + + // constructor, destructor + // Left at growSize = 0, the memory will first allocate 1 element and double in size + // at each increment. + // LessFunc_t is required, but may be set after the constructor using SetLessFunc() below + CUtlRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ); + CUtlRBTree( const LessFunc_t &lessfunc ); + ~CUtlRBTree( ); + + void EnsureCapacity( int num ); + + // NOTE: CopyFrom is fast but dangerous! It just memcpy's all nodes - it does NOT run copy constructors, so + // it is not a true deep copy (i.e 'T' must be POD for this to work - e.g CUtlString will not work). + void CopyFrom( const CUtlRBTree<T, I, L, M> &other ); + + // gets particular elements + T& Element( I i ); + T const &Element( I i ) const; + T& operator[]( I i ); + T const &operator[]( I i ) const; + + // Gets the root + I Root() const; + + // Num elements + unsigned int Count() const; + + // Max "size" of the vector + // it's not generally safe to iterate from index 0 to MaxElement()-1 (you could do this as a potential + // iteration optimization, IF CUtlMemory is the allocator, and IF IsValidIndex() is tested for each element... + // but this should be implemented inside the CUtlRBTree iteration API, if anywhere) + I MaxElement() const; + + // Gets the children + I Parent( I i ) const; + I LeftChild( I i ) const; + I RightChild( I i ) const; + + // Tests if a node is a left or right child + bool IsLeftChild( I i ) const; + bool IsRightChild( I i ) const; + + // Tests if root or leaf + bool IsRoot( I i ) const; + bool IsLeaf( I i ) const; + + // Checks if a node is valid and in the tree + bool IsValidIndex( I i ) const; + + // Checks if the tree as a whole is valid + bool IsValid() const; + + // Invalid index + static I InvalidIndex(); + + // returns the tree depth (not a very fast operation) + int Depth( I node ) const; + int Depth() const; + + // Sets the less func + void SetLessFunc( const LessFunc_t &func ); + + // Allocation method + I NewNode(); + + // Insert method (inserts in order) + // NOTE: the returned 'index' will be valid as long as the element remains in the tree + // (other elements being added/removed will not affect it) + I Insert( T const &insert ); + void Insert( const T *pArray, int nItems ); + I InsertIfNotFound( T const &insert ); + + // Find method + I Find( T const &search ) const; + + // Remove methods + void RemoveAt( I i ); + bool Remove( T const &remove ); + void RemoveAll( ); + void Purge(); + + // Allocation, deletion + void FreeNode( I i ); + + // Iteration + I FirstInorder() const; + I NextInorder( I i ) const; + I PrevInorder( I i ) const; + I LastInorder() const; + + I FirstPreorder() const; + I NextPreorder( I i ) const; + I PrevPreorder( I i ) const; + I LastPreorder( ) const; + + I FirstPostorder() const; + I NextPostorder( I i ) const; + + // If you change the search key, this can be used to reinsert the + // element into the tree. + void Reinsert( I elem ); + + // swap in place + void Swap( CUtlRBTree< T, I, L > &that ); + +private: + // Can't copy the tree this way! + CUtlRBTree<T, I, L, M>& operator=( const CUtlRBTree<T, I, L, M> &other ); + +protected: + enum NodeColor_t + { + RED = 0, + BLACK + }; + + typedef UtlRBTreeNode_t< T, I > Node_t; + typedef UtlRBTreeLinks_t< I > Links_t; + + // Sets the children + void SetParent( I i, I parent ); + void SetLeftChild( I i, I child ); + void SetRightChild( I i, I child ); + void LinkToParent( I i, I parent, bool isLeft ); + + // Gets at the links + Links_t const &Links( I i ) const; + Links_t &Links( I i ); + + // Checks if a link is red or black + bool IsRed( I i ) const; + bool IsBlack( I i ) const; + + // Sets/gets node color + NodeColor_t Color( I i ) const; + void SetColor( I i, NodeColor_t c ); + + // operations required to preserve tree balance + void RotateLeft(I i); + void RotateRight(I i); + void InsertRebalance(I i); + void RemoveRebalance(I i); + + // Insertion, removal + I InsertAt( I parent, bool leftchild ); + + // copy constructors not allowed + CUtlRBTree( CUtlRBTree<T, I, L, M> const &tree ); + + // Inserts a node into the tree, doesn't copy the data in. + void FindInsertionPosition( T const &insert, I &parent, bool &leftchild ); + + // Remove and add back an element in the tree. + void Unlink( I elem ); + void Link( I elem ); + + // Used for sorting. + LessFunc_t m_LessFunc; + + M m_Elements; + I m_Root; + I m_NumElements; + I m_FirstFree; + typename M::Iterator_t m_LastAlloc; // the last index allocated + + Node_t* m_pElements; + + FORCEINLINE M const &Elements( void ) const + { + return m_Elements; + } + + + void ResetDbgInfo() + { + m_pElements = (Node_t*)m_Elements.Base(); + } +}; + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T, class I = int, typename L = bool (*)( const T &, const T & ) > +class CUtlFixedRBTree : public CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > +{ +public: + + typedef L LessFunc_t; + + CUtlFixedRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ) + : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >( growSize, initSize, lessfunc ) {} + CUtlFixedRBTree( const LessFunc_t &lessfunc ) + : CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > >( lessfunc ) {} + + typedef CUtlRBTree< T, I, L, CUtlFixedMemory< UtlRBTreeNode_t< T, I > > > BaseClass; + bool IsValidIndex( I i ) const + { + if ( !BaseClass::Elements().IsIdxValid( i ) ) + return false; + +#ifdef _DEBUG // it's safe to skip this here, since the only way to get indices after m_LastAlloc is to use MaxElement() + if ( BaseClass::Elements().IsIdxAfter( i, this->m_LastAlloc ) ) + { + Assert( 0 ); + return false; // don't read values that have been allocated, but not constructed + } +#endif + + return LeftChild(i) != i; + } + +protected: + void ResetDbgInfo() {} + +private: + // this doesn't make sense for fixed rbtrees, since there's no useful max pointer, and the index space isn't contiguous anyways + I MaxElement() const; +}; + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T, class I = unsigned short, typename L = bool (*)( const T &, const T & ) > +class CUtlBlockRBTree : public CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > > +{ +public: + typedef L LessFunc_t; + CUtlBlockRBTree( int growSize = 0, int initSize = 0, const LessFunc_t &lessfunc = 0 ) + : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >( growSize, initSize, lessfunc ) {} + CUtlBlockRBTree( const LessFunc_t &lessfunc ) + : CUtlRBTree< T, I, L, CUtlBlockMemory< UtlRBTreeNode_t< T, I >, I > >( lessfunc ) {} +protected: + void ResetDbgInfo() {} +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline CUtlRBTree<T, I, L, M>::CUtlRBTree( int growSize, int initSize, const LessFunc_t &lessfunc ) : +m_LessFunc( lessfunc ), +m_Elements( growSize, initSize ), +m_Root( InvalidIndex() ), +m_NumElements( 0 ), +m_FirstFree( InvalidIndex() ), +m_LastAlloc( m_Elements.InvalidIterator() ) +{ + ResetDbgInfo(); +} + +template < class T, class I, typename L, class M > +inline CUtlRBTree<T, I, L, M>::CUtlRBTree( const LessFunc_t &lessfunc ) : +m_Elements( 0, 0 ), +m_LessFunc( lessfunc ), +m_Root( InvalidIndex() ), +m_NumElements( 0 ), +m_FirstFree( InvalidIndex() ), +m_LastAlloc( m_Elements.InvalidIterator() ) +{ + ResetDbgInfo(); +} + +template < class T, class I, typename L, class M > +inline CUtlRBTree<T, I, L, M>::~CUtlRBTree() +{ + Purge(); +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree<T, I, L, M>::EnsureCapacity( int num ) +{ + m_Elements.EnsureCapacity( num ); +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree<T, I, L, M>::CopyFrom( const CUtlRBTree<T, I, L, M> &other ) +{ + Purge(); + m_Elements.EnsureCapacity( other.m_Elements.Count() ); + memcpy( m_Elements.Base(), other.m_Elements.Base(), other.m_Elements.Count() * sizeof( UtlRBTreeNode_t< T, I > ) ); + m_LessFunc = other.m_LessFunc; + m_Root = other.m_Root; + m_NumElements = other.m_NumElements; + m_FirstFree = other.m_FirstFree; + m_LastAlloc = other.m_LastAlloc; + ResetDbgInfo(); +} + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline T &CUtlRBTree<T, I, L, M>::Element( I i ) +{ + return m_Elements[i].m_Data; +} + +template < class T, class I, typename L, class M > +inline T const &CUtlRBTree<T, I, L, M>::Element( I i ) const +{ + return m_Elements[i].m_Data; +} + +template < class T, class I, typename L, class M > +inline T &CUtlRBTree<T, I, L, M>::operator[]( I i ) +{ + return Element(i); +} + +template < class T, class I, typename L, class M > +inline T const &CUtlRBTree<T, I, L, M>::operator[]( I i ) const +{ + return Element(i); +} + +//----------------------------------------------------------------------------- +// +// various accessors +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Gets the root +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree<T, I, L, M>::Root() const +{ + return m_Root; +} + +//----------------------------------------------------------------------------- +// Num elements +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline unsigned int CUtlRBTree<T, I, L, M>::Count() const +{ + return (unsigned int)m_NumElements; +} + +//----------------------------------------------------------------------------- +// Max "size" of the vector +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree<T, I, L, M>::MaxElement() const +{ + return ( I )m_Elements.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Gets the children +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree<T, I, L, M>::Parent( I i ) const +{ + return Links(i).m_Parent; +} + +template < class T, class I, typename L, class M > +inline I CUtlRBTree<T, I, L, M>::LeftChild( I i ) const +{ + return Links(i).m_Left; +} + +template < class T, class I, typename L, class M > +inline I CUtlRBTree<T, I, L, M>::RightChild( I i ) const +{ + return Links(i).m_Right; +} + +//----------------------------------------------------------------------------- +// Tests if a node is a left or right child +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree<T, I, L, M>::IsLeftChild( I i ) const +{ + return LeftChild(Parent(i)) == i; +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree<T, I, L, M>::IsRightChild( I i ) const +{ + return RightChild(Parent(i)) == i; +} + + +//----------------------------------------------------------------------------- +// Tests if root or leaf +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree<T, I, L, M>::IsRoot( I i ) const +{ + return i == m_Root; +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree<T, I, L, M>::IsLeaf( I i ) const +{ + return (LeftChild(i) == InvalidIndex()) && (RightChild(i) == InvalidIndex()); +} + + +//----------------------------------------------------------------------------- +// Checks if a node is valid and in the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree<T, I, L, M>::IsValidIndex( I i ) const +{ + if ( !m_Elements.IsIdxValid( i ) ) + return false; + + if ( m_Elements.IsIdxAfter( i, m_LastAlloc ) ) + return false; // don't read values that have been allocated, but not constructed + + return LeftChild(i) != i; +} + + +//----------------------------------------------------------------------------- +// Invalid index +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline I CUtlRBTree<T, I, L, M>::InvalidIndex() +{ + return ( I )M::InvalidIndex(); +} + + +//----------------------------------------------------------------------------- +// returns the tree depth (not a very fast operation) +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline int CUtlRBTree<T, I, L, M>::Depth() const +{ + return Depth(Root()); +} + +//----------------------------------------------------------------------------- +// Sets the children +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline void CUtlRBTree<T, I, L, M>::SetParent( I i, I parent ) +{ + Links(i).m_Parent = parent; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree<T, I, L, M>::SetLeftChild( I i, I child ) +{ + Links(i).m_Left = child; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree<T, I, L, M>::SetRightChild( I i, I child ) +{ + Links(i).m_Right = child; +} + +//----------------------------------------------------------------------------- +// Gets at the links +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree<T, I, L, M>::Links_t const &CUtlRBTree<T, I, L, M>::Links( I i ) const +{ + // Sentinel node, makes life easier + static Links_t s_Sentinel = + { + InvalidIndex(), InvalidIndex(), InvalidIndex(), CUtlRBTree<T, I, L, M>::BLACK + }; + + return (i != InvalidIndex()) ? *(Links_t*)&m_Elements[i] : *(Links_t*)&s_Sentinel; +} + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree<T, I, L, M>::Links_t &CUtlRBTree<T, I, L, M>::Links( I i ) +{ + Assert(i != InvalidIndex()); + return *(Links_t *)&m_Elements[i]; +} + +//----------------------------------------------------------------------------- +// Checks if a link is red or black +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree<T, I, L, M>::IsRed( I i ) const +{ + return (Links(i).m_Tag == RED); +} + +template < class T, class I, typename L, class M > +inline bool CUtlRBTree<T, I, L, M>::IsBlack( I i ) const +{ + return (Links(i).m_Tag == BLACK); +} + + +//----------------------------------------------------------------------------- +// Sets/gets node color +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +inline typename CUtlRBTree<T, I, L, M>::NodeColor_t CUtlRBTree<T, I, L, M>::Color( I i ) const +{ + return (NodeColor_t)Links(i).m_Tag; +} + +template < class T, class I, typename L, class M > +inline void CUtlRBTree<T, I, L, M>::SetColor( I i, typename CUtlRBTree<T, I, L, M>::NodeColor_t c ) +{ + Links(i).m_Tag = (I)c; +} + +//----------------------------------------------------------------------------- +// Allocates/ deallocates nodes +//----------------------------------------------------------------------------- +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::NewNode() +{ + I elem; + + // Nothing in the free list; add. + if ( m_FirstFree == InvalidIndex() ) + { + Assert( m_Elements.IsValidIterator( m_LastAlloc ) || m_NumElements == 0 ); + typename M::Iterator_t it = m_Elements.IsValidIterator( m_LastAlloc ) ? m_Elements.Next( m_LastAlloc ) : m_Elements.First(); + if ( !m_Elements.IsValidIterator( it ) ) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Elements.Grow(); + + it = m_Elements.IsValidIterator( m_LastAlloc ) ? m_Elements.Next( m_LastAlloc ) : m_Elements.First(); + + Assert( m_Elements.IsValidIterator( it ) ); + if ( !m_Elements.IsValidIterator( it ) ) + { + Error( "CUtlRBTree overflow!\n" ); + } + } + m_LastAlloc = it; + elem = m_Elements.GetIndex( m_LastAlloc ); + Assert( m_Elements.IsValidIterator( m_LastAlloc ) ); + } + else + { + elem = m_FirstFree; + m_FirstFree = Links( m_FirstFree ).m_Right; + } + +#ifdef _DEBUG + // reset links to invalid.... + Links_t &node = Links( elem ); + node.m_Left = node.m_Right = node.m_Parent = InvalidIndex(); +#endif + + Construct( &Element( elem ) ); + ResetDbgInfo(); + + return elem; +} +#pragma warning(pop) + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::FreeNode( I i ) +{ + Assert( IsValidIndex(i) && (i != InvalidIndex()) ); + Destruct( &Element(i) ); + SetLeftChild( i, i ); // indicates it's in not in the tree + SetRightChild( i, m_FirstFree ); + m_FirstFree = i; +} + + +//----------------------------------------------------------------------------- +// Rotates node i to the left +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::RotateLeft(I elem) +{ + I rightchild = RightChild(elem); + SetRightChild( elem, LeftChild(rightchild) ); + if (LeftChild(rightchild) != InvalidIndex()) + SetParent( LeftChild(rightchild), elem ); + + if (rightchild != InvalidIndex()) + SetParent( rightchild, Parent(elem) ); + if (!IsRoot(elem)) + { + if (IsLeftChild(elem)) + SetLeftChild( Parent(elem), rightchild ); + else + SetRightChild( Parent(elem), rightchild ); + } + else + m_Root = rightchild; + + SetLeftChild( rightchild, elem ); + if (elem != InvalidIndex()) + SetParent( elem, rightchild ); +} + + +//----------------------------------------------------------------------------- +// Rotates node i to the right +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::RotateRight(I elem) +{ + I leftchild = LeftChild(elem); + SetLeftChild( elem, RightChild(leftchild) ); + if (RightChild(leftchild) != InvalidIndex()) + SetParent( RightChild(leftchild), elem ); + + if (leftchild != InvalidIndex()) + SetParent( leftchild, Parent(elem) ); + if (!IsRoot(elem)) + { + if (IsRightChild(elem)) + SetRightChild( Parent(elem), leftchild ); + else + SetLeftChild( Parent(elem), leftchild ); + } + else + m_Root = leftchild; + + SetRightChild( leftchild, elem ); + if (elem != InvalidIndex()) + SetParent( elem, leftchild ); +} + + +//----------------------------------------------------------------------------- +// Rebalances the tree after an insertion +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::InsertRebalance(I elem) +{ + while ( !IsRoot(elem) && (Color(Parent(elem)) == RED) ) + { + I parent = Parent(elem); + I grandparent = Parent(parent); + + /* we have a violation */ + if (IsLeftChild(parent)) + { + I uncle = RightChild(grandparent); + if (IsRed(uncle)) + { + /* uncle is RED */ + SetColor(parent, BLACK); + SetColor(uncle, BLACK); + SetColor(grandparent, RED); + elem = grandparent; + } + else + { + /* uncle is BLACK */ + if (IsRightChild(elem)) + { + /* make x a left child, will change parent and grandparent */ + elem = parent; + RotateLeft(elem); + parent = Parent(elem); + grandparent = Parent(parent); + } + /* recolor and rotate */ + SetColor(parent, BLACK); + SetColor(grandparent, RED); + RotateRight(grandparent); + } + } + else + { + /* mirror image of above code */ + I uncle = LeftChild(grandparent); + if (IsRed(uncle)) + { + /* uncle is RED */ + SetColor(parent, BLACK); + SetColor(uncle, BLACK); + SetColor(grandparent, RED); + elem = grandparent; + } + else + { + /* uncle is BLACK */ + if (IsLeftChild(elem)) + { + /* make x a right child, will change parent and grandparent */ + elem = parent; + RotateRight(parent); + parent = Parent(elem); + grandparent = Parent(parent); + } + /* recolor and rotate */ + SetColor(parent, BLACK); + SetColor(grandparent, RED); + RotateLeft(grandparent); + } + } + } + SetColor( m_Root, BLACK ); +} + + +//----------------------------------------------------------------------------- +// Insert a node into the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::InsertAt( I parent, bool leftchild ) +{ + I i = NewNode(); + LinkToParent( i, parent, leftchild ); + ++m_NumElements; + + Assert(IsValid()); + + return i; +} + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::LinkToParent( I i, I parent, bool isLeft ) +{ + Links_t &elem = Links(i); + elem.m_Parent = parent; + elem.m_Left = elem.m_Right = InvalidIndex(); + elem.m_Tag = RED; + + /* insert node in tree */ + if (parent != InvalidIndex()) + { + if (isLeft) + Links(parent).m_Left = i; + else + Links(parent).m_Right = i; + } + else + { + m_Root = i; + } + + InsertRebalance(i); +} + +//----------------------------------------------------------------------------- +// Rebalance the tree after a deletion +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::RemoveRebalance(I elem) +{ + while (elem != m_Root && IsBlack(elem)) + { + I parent = Parent(elem); + + // If elem is the left child of the parent + if (elem == LeftChild(parent)) + { + // Get our sibling + I sibling = RightChild(parent); + if (IsRed(sibling)) + { + SetColor(sibling, BLACK); + SetColor(parent, RED); + RotateLeft(parent); + + // We may have a new parent now + parent = Parent(elem); + sibling = RightChild(parent); + } + if ( (IsBlack(LeftChild(sibling))) && (IsBlack(RightChild(sibling))) ) + { + if (sibling != InvalidIndex()) + SetColor(sibling, RED); + elem = parent; + } + else + { + if (IsBlack(RightChild(sibling))) + { + SetColor(LeftChild(sibling), BLACK); + SetColor(sibling, RED); + RotateRight(sibling); + + // rotation may have changed this + parent = Parent(elem); + sibling = RightChild(parent); + } + SetColor( sibling, Color(parent) ); + SetColor( parent, BLACK ); + SetColor( RightChild(sibling), BLACK ); + RotateLeft( parent ); + elem = m_Root; + } + } + else + { + // Elem is the right child of the parent + I sibling = LeftChild(parent); + if (IsRed(sibling)) + { + SetColor(sibling, BLACK); + SetColor(parent, RED); + RotateRight(parent); + + // We may have a new parent now + parent = Parent(elem); + sibling = LeftChild(parent); + } + if ( (IsBlack(RightChild(sibling))) && (IsBlack(LeftChild(sibling))) ) + { + if (sibling != InvalidIndex()) + SetColor( sibling, RED ); + elem = parent; + } + else + { + if (IsBlack(LeftChild(sibling))) + { + SetColor( RightChild(sibling), BLACK ); + SetColor( sibling, RED ); + RotateLeft( sibling ); + + // rotation may have changed this + parent = Parent(elem); + sibling = LeftChild(parent); + } + SetColor( sibling, Color(parent) ); + SetColor( parent, BLACK ); + SetColor( LeftChild(sibling), BLACK ); + RotateRight( parent ); + elem = m_Root; + } + } + } + SetColor( elem, BLACK ); +} + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::Unlink( I elem ) +{ + if ( elem != InvalidIndex() ) + { + I x, y; + + if ((LeftChild(elem) == InvalidIndex()) || + (RightChild(elem) == InvalidIndex())) + { + /* y has a NIL node as a child */ + y = elem; + } + else + { + /* find tree successor with a NIL node as a child */ + y = RightChild(elem); + while (LeftChild(y) != InvalidIndex()) + y = LeftChild(y); + } + + /* x is y's only child */ + if (LeftChild(y) != InvalidIndex()) + x = LeftChild(y); + else + x = RightChild(y); + + /* remove y from the parent chain */ + if (x != InvalidIndex()) + SetParent( x, Parent(y) ); + if (!IsRoot(y)) + { + if (IsLeftChild(y)) + SetLeftChild( Parent(y), x ); + else + SetRightChild( Parent(y), x ); + } + else + m_Root = x; + + // need to store this off now, we'll be resetting y's color + NodeColor_t ycolor = Color(y); + if (y != elem) + { + // Standard implementations copy the data around, we cannot here. + // Hook in y to link to the same stuff elem used to. + SetParent( y, Parent(elem) ); + SetRightChild( y, RightChild(elem) ); + SetLeftChild( y, LeftChild(elem) ); + + if (!IsRoot(elem)) + if (IsLeftChild(elem)) + SetLeftChild( Parent(elem), y ); + else + SetRightChild( Parent(elem), y ); + else + m_Root = y; + + if (LeftChild(y) != InvalidIndex()) + SetParent( LeftChild(y), y ); + if (RightChild(y) != InvalidIndex()) + SetParent( RightChild(y), y ); + + SetColor( y, Color(elem) ); + } + + if ((x != InvalidIndex()) && (ycolor == BLACK)) + RemoveRebalance(x); + } +} + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::Link( I elem ) +{ + if ( elem != InvalidIndex() ) + { + I parent = InvalidIndex(); + bool leftchild = false; + + FindInsertionPosition( Element( elem ), parent, leftchild ); + + LinkToParent( elem, parent, leftchild ); + + Assert(IsValid()); + } +} + +//----------------------------------------------------------------------------- +// Delete a node from the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::RemoveAt(I elem) +{ + if ( elem != InvalidIndex() ) + { + Unlink( elem ); + + FreeNode(elem); + --m_NumElements; + + Assert(IsValid()); + } +} + + +//----------------------------------------------------------------------------- +// remove a node in the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > bool CUtlRBTree<T, I, L, M>::Remove( T const &search ) +{ + I node = Find( search ); + if (node != InvalidIndex()) + { + RemoveAt(node); + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::RemoveAll() +{ + // Have to do some convoluted stuff to invoke the destructor on all + // valid elements for the multilist case (since we don't have all elements + // connected to each other in a list). + + if ( m_LastAlloc == m_Elements.InvalidIterator() ) + { + Assert( m_Root == InvalidIndex() ); + Assert( m_FirstFree == InvalidIndex() ); + Assert( m_NumElements == 0 ); + return; + } + + for ( typename M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next( it ) ) + { + I i = m_Elements.GetIndex( it ); + if ( IsValidIndex( i ) ) // skip elements in the free list + { + Destruct( &Element( i ) ); + SetRightChild( i, m_FirstFree ); + SetLeftChild( i, i ); + m_FirstFree = i; + } + + if ( it == m_LastAlloc ) + break; // don't destruct elements that haven't ever been constucted + } + + // Clear everything else out + m_Root = InvalidIndex(); + m_NumElements = 0; + + Assert( IsValid() ); +} + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree and purges memory +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::Purge() +{ + RemoveAll(); + m_FirstFree = InvalidIndex(); + m_Elements.Purge(); + m_LastAlloc = m_Elements.InvalidIterator(); +} + + +//----------------------------------------------------------------------------- +// iteration +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::FirstInorder() const +{ + I i = m_Root; + while (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::NextInorder( I i ) const +{ + Assert(IsValidIndex(i)); + + if (RightChild(i) != InvalidIndex()) + { + i = RightChild(i); + while (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + return i; + } + + I parent = Parent(i); + while (IsRightChild(i)) + { + i = parent; + if (i == InvalidIndex()) break; + parent = Parent(i); + } + return parent; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::PrevInorder( I i ) const +{ + Assert(IsValidIndex(i)); + + if (LeftChild(i) != InvalidIndex()) + { + i = LeftChild(i); + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + return i; + } + + I parent = Parent(i); + while (IsLeftChild(i)) + { + i = parent; + if (i == InvalidIndex()) break; + parent = Parent(i); + } + return parent; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::LastInorder() const +{ + I i = m_Root; + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::FirstPreorder() const +{ + return m_Root; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::NextPreorder( I i ) const +{ + if (LeftChild(i) != InvalidIndex()) + return LeftChild(i); + + if (RightChild(i) != InvalidIndex()) + return RightChild(i); + + I parent = Parent(i); + while( parent != InvalidIndex()) + { + if (IsLeftChild(i) && (RightChild(parent) != InvalidIndex())) + return RightChild(parent); + i = parent; + parent = Parent(parent); + } + return InvalidIndex(); +} + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::PrevPreorder( I i ) const +{ + Assert(0); // not implemented yet + return InvalidIndex(); +} + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::LastPreorder() const +{ + I i = m_Root; + while (1) + { + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + + if (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + else + break; + } + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::FirstPostorder() const +{ + I i = m_Root; + while (!IsLeaf(i)) + { + if (LeftChild(i)) + i = LeftChild(i); + else + i = RightChild(i); + } + return i; +} + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::NextPostorder( I i ) const +{ + I parent = Parent(i); + if (parent == InvalidIndex()) + return InvalidIndex(); + + if (IsRightChild(i)) + return parent; + + if (RightChild(parent) == InvalidIndex()) + return parent; + + i = RightChild(parent); + while (!IsLeaf(i)) + { + if (LeftChild(i)) + i = LeftChild(i); + else + i = RightChild(i); + } + return i; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::Reinsert( I elem ) +{ + Unlink( elem ); + Link( elem ); +} + + +//----------------------------------------------------------------------------- +// returns the tree depth (not a very fast operation) +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +int CUtlRBTree<T, I, L, M>::Depth( I node ) const +{ + if (node == InvalidIndex()) + return 0; + + int depthright = Depth( RightChild(node) ); + int depthleft = Depth( LeftChild(node) ); + return MAX( depthright, depthleft ) + 1; +} + + +//#define UTLTREE_PARANOID + +//----------------------------------------------------------------------------- +// Makes sure the tree is valid after every operation +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +bool CUtlRBTree<T, I, L, M>::IsValid() const +{ + if ( !Count() ) + return true; + + if ( m_LastAlloc == m_Elements.InvalidIterator() ) + return false; + + if ( !m_Elements.IsIdxValid( Root() ) ) + return false; + + if ( Parent( Root() ) != InvalidIndex() ) + return false; + +#ifdef UTLTREE_PARANOID + + // First check to see that mNumEntries matches reality. + // count items on the free list + int numFree = 0; + for ( int i = m_FirstFree; i != InvalidIndex(); i = RightChild( i ) ) + { + ++numFree; + if ( !m_Elements.IsIdxValid( i ) ) + return false; + } + + // iterate over all elements, looking for validity + // based on the self pointers + int nElements = 0; + int numFree2 = 0; + for ( M::Iterator_t it = m_Elements.First(); it != m_Elements.InvalidIterator(); it = m_Elements.Next( it ) ) + { + I i = m_Elements.GetIndex( it ); + if ( !IsValidIndex( i ) ) + { + ++numFree2; + } + else + { + ++nElements; + + int right = RightChild( i ); + int left = LeftChild( i ); + if ( ( right == left ) && ( right != InvalidIndex() ) ) + return false; + + if ( right != InvalidIndex() ) + { + if ( !IsValidIndex( right ) ) + return false; + if ( Parent( right ) != i ) + return false; + if ( IsRed( i ) && IsRed( right ) ) + return false; + } + + if ( left != InvalidIndex() ) + { + if ( !IsValidIndex( left ) ) + return false; + if ( Parent( left ) != i ) + return false; + if ( IsRed( i ) && IsRed( left ) ) + return false; + } + } + + if ( it == m_LastAlloc ) + break; + } + if ( numFree2 != numFree ) + return false; + + if ( nElements != m_NumElements ) + return false; + +#endif // UTLTREE_PARANOID + + return true; +} + + +//----------------------------------------------------------------------------- +// Sets the less func +//----------------------------------------------------------------------------- + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::SetLessFunc( const typename CUtlRBTree<T, I, L, M>::LessFunc_t &func ) +{ + if (!m_LessFunc) + { + m_LessFunc = func; + } + else if ( Count() > 0 ) + { + // need to re-sort the tree here.... + Assert(0); + } +} + + +//----------------------------------------------------------------------------- +// inserts a node into the tree +//----------------------------------------------------------------------------- + +// Inserts a node into the tree, doesn't copy the data in. +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::FindInsertionPosition( T const &insert, I &parent, bool &leftchild ) +{ + Assert( !!m_LessFunc ); + + /* find where node belongs */ + I current = m_Root; + parent = InvalidIndex(); + leftchild = false; + while (current != InvalidIndex()) + { + parent = current; + if (m_LessFunc( insert, Element(current) )) + { + leftchild = true; current = LeftChild(current); + } + else + { + leftchild = false; current = RightChild(current); + } + } +} + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::Insert( T const &insert ) +{ + // use copy constructor to copy it in + I parent = InvalidIndex(); + bool leftchild = false; + FindInsertionPosition( insert, parent, leftchild ); + I newNode = InsertAt( parent, leftchild ); + CopyConstruct( &Element( newNode ), insert ); + return newNode; +} + + +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::Insert( const T *pArray, int nItems ) +{ + while ( nItems-- ) + { + Insert( *pArray++ ); + } +} + + +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::InsertIfNotFound( T const &insert ) +{ + // use copy constructor to copy it in + I parent; + bool leftchild; + + I current = m_Root; + parent = InvalidIndex(); + leftchild = false; + while (current != InvalidIndex()) + { + parent = current; + if (m_LessFunc( insert, Element(current) )) + { + leftchild = true; current = LeftChild(current); + } + else if (m_LessFunc( Element(current), insert )) + { + leftchild = false; current = RightChild(current); + } + else + // Match found, no insertion + return InvalidIndex(); + } + + I newNode = InsertAt( parent, leftchild ); + CopyConstruct( &Element( newNode ), insert ); + return newNode; +} + + +//----------------------------------------------------------------------------- +// finds a node in the tree +//----------------------------------------------------------------------------- +template < class T, class I, typename L, class M > +I CUtlRBTree<T, I, L, M>::Find( T const &search ) const +{ + Assert( !!m_LessFunc ); + + I current = m_Root; + while (current != InvalidIndex()) + { + if (m_LessFunc( search, Element(current) )) + current = LeftChild(current); + else if (m_LessFunc( Element(current), search )) + current = RightChild(current); + else + break; + } + return current; +} + + +//----------------------------------------------------------------------------- +// swap in place +//----------------------------------------------------------------------------- +template < class T, class I, typename L, class M > +void CUtlRBTree<T, I, L, M>::Swap( CUtlRBTree< T, I, L > &that ) +{ + m_Elements.Swap( that.m_Elements ); + V_swap( m_LessFunc, that.m_LessFunc ); + V_swap( m_Root, that.m_Root ); + V_swap( m_NumElements, that.m_NumElements ); + V_swap( m_FirstFree, that.m_FirstFree ); + V_swap( m_pElements, that.m_pElements ); + V_swap( m_LastAlloc, that.m_LastAlloc ); + Assert( IsValid() ); + Assert( m_Elements.IsValidIterator( m_LastAlloc ) || ( m_NumElements == 0 && m_FirstFree == InvalidIndex() ) ); +} + + +#endif // UTLRBTREE_H diff --git a/external/vpc/public/tier1/utlsortvector.h b/external/vpc/public/tier1/utlsortvector.h new file mode 100644 index 0000000..c12de27 --- /dev/null +++ b/external/vpc/public/tier1/utlsortvector.h @@ -0,0 +1,354 @@ +//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======// +// +// $Header: $ +// $NoKeywords: $ +// +// A growable array class that keeps all elements in order using binary search +//===========================================================================// + +#ifndef UTLSORTVECTOR_H +#define UTLSORTVECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + + +//----------------------------------------------------------------------------- +// class CUtlSortVector: +// description: +// This in an sorted order-preserving vector. Items may be inserted or removed +// at any point in the vector. When an item is inserted, all elements are +// moved down by one element using memmove. When an item is removed, all +// elements are shifted back down. Items are searched for in the vector +// using a binary search technique. Clients must pass in a Less() function +// into the constructor of the vector to determine the sort order. +//----------------------------------------------------------------------------- + +#ifndef _WIN32 +// gcc has no qsort_s, so i need to use a static var to hold the sort context. this makes cutlsortvector _not_ thread sfae under linux +extern void *g_pUtlSortVectorQSortContext; +#endif + +template <class T> +class CUtlSortVectorDefaultLess +{ +public: + bool Less( const T& lhs, const T& rhs, void * ) + { + return lhs < rhs; + } +}; + +template <class T, class LessFunc = CUtlSortVectorDefaultLess<T>, class BaseVector = CUtlVector<T> > +class CUtlSortVector : public BaseVector +{ +public: + + // constructor + CUtlSortVector( int nGrowSize = 0, int initSize = 0 ); + CUtlSortVector( T* pMemory, int numElements ); + + // inserts (copy constructs) an element in sorted order into the list + int Insert( const T& src ); + + // Finds an element within the list using a binary search + int Find( const T& search ) const; + int FindLessOrEqual( const T& search ) const; + int FindLess( const T& search ) const; + template <typename K> + int FindAs( const K& key ) const; + + // Removes a particular element + void Remove( const T& search ); + void Remove( int i ); + + // Allows methods to set a context to be used with the less function.. + void SetLessContext( void *pCtx ); + + // Note that you can only use this index until sorting is redone!!! + int InsertNoSort( const T& src ); + void RedoSort( bool bForceSort = false ); + +protected: + // No copy constructor + CUtlSortVector( const CUtlSortVector<T, LessFunc> & ); + + // never call these; illegal for this class + int AddToHead(); + int AddToTail(); + int InsertBefore( int elem ); + int InsertAfter( int elem ); + int AddToHead( const T& src ); + int AddToTail( const T& src ); + int InsertBefore( int elem, const T& src ); + int InsertAfter( int elem, const T& src ); + int AddMultipleToHead( int num ); + int AddMultipleToTail( int num, const T *pToCopy=NULL ); + int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL ); + int InsertMultipleAfter( int elem, int num ); + int AddVectorToTail( CUtlVector<T> const &src ); + + struct QSortContext_t + { + void *m_pLessContext; + LessFunc *m_pLessFunc; + }; + +#ifdef _WIN32 + static int CompareHelper( void *context, const T *lhs, const T *rhs ) + { + QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( context ); + if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) ) + return -1; + if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) ) + return 1; + return 0; + } +#else + static int CompareHelper( const T *lhs, const T *rhs ) + { + QSortContext_t *ctx = reinterpret_cast< QSortContext_t * >( g_pUtlSortVectorQSortContext ); + if ( ctx->m_pLessFunc->Less( *lhs, *rhs, ctx->m_pLessContext ) ) + return -1; + if ( ctx->m_pLessFunc->Less( *rhs, *lhs, ctx->m_pLessContext ) ) + return 1; + return 0; + } +#endif + + void *m_pLessContext; + bool m_bNeedsSort; + +private: + void QuickSort( LessFunc& less, int X, int I ); +}; + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( int nGrowSize, int initSize ) : + m_pLessContext(NULL), BaseVector( nGrowSize, initSize ), m_bNeedsSort( false ) +{ +} + +template <class T, class LessFunc, class BaseVector> +CUtlSortVector<T, LessFunc, BaseVector>::CUtlSortVector( T* pMemory, int numElements ) : + m_pLessContext(NULL), BaseVector( pMemory, numElements ), m_bNeedsSort( false ) +{ +} + +//----------------------------------------------------------------------------- +// Allows methods to set a context to be used with the less function.. +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +void CUtlSortVector<T, LessFunc, BaseVector>::SetLessContext( void *pCtx ) +{ + m_pLessContext = pCtx; +} + +//----------------------------------------------------------------------------- +// grows the vector +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::Insert( const T& src ) +{ + AssertFatal( !m_bNeedsSort ); + + int pos = FindLessOrEqual( src ) + 1; + this->GrowVector(); + this->ShiftElementsRight(pos); + CopyConstruct<T>( &this->Element(pos), src ); + return pos; +} + +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::InsertNoSort( const T& src ) +{ + m_bNeedsSort = true; + int lastElement = BaseVector::m_Size; + // Just stick the new element at the end of the vector, but don't do a sort + this->GrowVector(); + this->ShiftElementsRight(lastElement); + CopyConstruct( &this->Element(lastElement), src ); + return lastElement; +} + +template <class T, class LessFunc, class BaseVector> +void CUtlSortVector<T, LessFunc, BaseVector>::QuickSort( LessFunc& less, int nLower, int nUpper ) +{ +#ifdef _WIN32 + typedef int (__cdecl *QSortCompareFunc_t)(void *context, const void *, const void *); + if ( this->Count() > 1 ) + { + QSortContext_t ctx; + ctx.m_pLessContext = m_pLessContext; + ctx.m_pLessFunc = &less; + + qsort_s( Base(), Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector<T, LessFunc>::CompareHelper, &ctx ); + } +#else + typedef int (__cdecl *QSortCompareFunc_t)( const void *, const void *); + if ( this->Count() > 1 ) + { + QSortContext_t ctx; + ctx.m_pLessContext = m_pLessContext; + ctx.m_pLessFunc = &less; + g_pUtlSortVectorQSortContext = &ctx; + + qsort( this->Base(), this->Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector<T, LessFunc>::CompareHelper ); + } +#endif +} + +template <class T, class LessFunc, class BaseVector> +void CUtlSortVector<T, LessFunc, BaseVector>::RedoSort( bool bForceSort /*= false */ ) +{ + if ( !m_bNeedsSort && !bForceSort ) + return; + + m_bNeedsSort = false; + LessFunc less; + QuickSort( less, 0, this->Count() - 1 ); +} + +//----------------------------------------------------------------------------- +// finds a particular element +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::Find( const T& src ) const +{ + AssertFatal( !m_bNeedsSort ); + + LessFunc less; + + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if ( less.Less( this->Element(mid), src, m_pLessContext ) ) + { + start = mid + 1; + } + else if ( less.Less( src, this->Element(mid), m_pLessContext ) ) + { + end = mid - 1; + } + else + { + return mid; + } + } + return -1; +} + +//----------------------------------------------------------------------------- +// finds a particular element +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +template <typename K> +int CUtlSortVector<T, LessFunc, BaseVector>::FindAs( const K& key ) const +{ + AssertFatal( !m_bNeedsSort ); + + LessFunc less; + + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + int nResult = less.Compare( this->Element(mid), key, m_pLessContext ); + if ( nResult < 0 ) + { + start = mid + 1; + } + else if ( nResult > 0 ) + { + end = mid - 1; + } + else + { + return mid; + } + } + return -1; +} + +//----------------------------------------------------------------------------- +// finds a particular element +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::FindLessOrEqual( const T& src ) const +{ + AssertFatal( !m_bNeedsSort ); + + LessFunc less; + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if ( less.Less( this->Element(mid), src, m_pLessContext ) ) + { + start = mid + 1; + } + else if ( less.Less( src, this->Element(mid), m_pLessContext ) ) + { + end = mid - 1; + } + else + { + return mid; + } + } + return end; +} + +template <class T, class LessFunc, class BaseVector> +int CUtlSortVector<T, LessFunc, BaseVector>::FindLess( const T& src ) const +{ + AssertFatal( !m_bNeedsSort ); + + LessFunc less; + int start = 0, end = this->Count() - 1; + while (start <= end) + { + int mid = (start + end) >> 1; + if ( less.Less( this->Element(mid), src, m_pLessContext ) ) + { + start = mid + 1; + } + else + { + end = mid - 1; + } + } + return end; +} + + +//----------------------------------------------------------------------------- +// Removes a particular element +//----------------------------------------------------------------------------- +template <class T, class LessFunc, class BaseVector> +void CUtlSortVector<T, LessFunc, BaseVector>::Remove( const T& search ) +{ + AssertFatal( !m_bNeedsSort ); + + int pos = Find(search); + if (pos != -1) + { + BaseVector::Remove(pos); + } +} + +template <class T, class LessFunc, class BaseVector> +void CUtlSortVector<T, LessFunc, BaseVector>::Remove( int i ) +{ + BaseVector::Remove( i ); +} + +#endif // UTLSORTVECTOR_H diff --git a/external/vpc/public/tier1/utlstack.h b/external/vpc/public/tier1/utlstack.h new file mode 100644 index 0000000..c7ab48d --- /dev/null +++ b/external/vpc/public/tier1/utlstack.h @@ -0,0 +1,331 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +// A stack based on a growable array +//=============================================================================// + +#ifndef UTLSTACK_H +#define UTLSTACK_H + +#include <assert.h> +#include <string.h> +#include "utlmemory.h" + + +//----------------------------------------------------------------------------- +// The CUtlStack class: +// A growable stack class which doubles in size by default. +// It will always keep all elements consecutive in memory, and may move the +// elements around in memory (via a realloc) when elements are pushed or +// popped. Clients should therefore refer to the elements of the stack +// by index (they should *never* maintain pointers to elements in the stack). +//----------------------------------------------------------------------------- + +template< class T, class M = CUtlMemory< T > > +class CUtlStack +{ +public: + // constructor, destructor + CUtlStack( int growSize = 0, int initSize = 0 ); + ~CUtlStack(); + + void CopyFrom( const CUtlStack<T, M> &from ); + + // element access + T& operator[]( int i ); + T const& operator[]( int i ) const; + T& Element( int i ); + T const& Element( int i ) const; + + // Gets the base address (can change when adding elements!) + T* Base(); + T const* Base() const; + + // Looks at the stack top + T& Top(); + T const& Top() const; + + // Size + int Count() const; + + // Is element index valid? + bool IsIdxValid( int i ) const; + + // Adds an element, uses default constructor + int Push(); + + // Adds an element, uses copy constructor + int Push( T const& src ); + + // Pops the stack + void Pop(); + void Pop( T& oldTop ); + void PopMultiple( int num ); + + // Makes sure we have enough memory allocated to store a requested # of elements + void EnsureCapacity( int num ); + + // Clears the stack, no deallocation + void Clear(); + + // Memory deallocation + void Purge(); + +private: + // Grows the stack allocation + void GrowStack(); + + // For easier access to the elements through the debugger + void ResetDbgInfo(); + + M m_Memory; + int m_Size; + + // For easier access to the elements through the debugger + T* m_pElements; +}; + + +//----------------------------------------------------------------------------- +// For easier access to the elements through the debugger +//----------------------------------------------------------------------------- + +template< class T, class M > +inline void CUtlStack<T,M>::ResetDbgInfo() +{ + m_pElements = m_Memory.Base(); +} + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T, class M > +CUtlStack<T,M>::CUtlStack( int growSize, int initSize ) : + m_Memory(growSize, initSize), m_Size(0) +{ + ResetDbgInfo(); +} + +template< class T, class M > +CUtlStack<T,M>::~CUtlStack() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// copy into +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack<T,M>::CopyFrom( const CUtlStack<T, M> &from ) +{ + Purge(); + EnsureCapacity( from.Count() ); + for ( int i = 0; i < from.Count(); i++ ) + { + Push( from[i] ); + } +} + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- + +template< class T, class M > +inline T& CUtlStack<T,M>::operator[]( int i ) +{ + assert( IsIdxValid(i) ); + return m_Memory[i]; +} + +template< class T, class M > +inline T const& CUtlStack<T,M>::operator[]( int i ) const +{ + assert( IsIdxValid(i) ); + return m_Memory[i]; +} + +template< class T, class M > +inline T& CUtlStack<T,M>::Element( int i ) +{ + assert( IsIdxValid(i) ); + return m_Memory[i]; +} + +template< class T, class M > +inline T const& CUtlStack<T,M>::Element( int i ) const +{ + assert( IsIdxValid(i) ); + return m_Memory[i]; +} + + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- + +template< class T, class M > +inline T* CUtlStack<T,M>::Base() +{ + return m_Memory.Base(); +} + +template< class T, class M > +inline T const* CUtlStack<T,M>::Base() const +{ + return m_Memory.Base(); +} + +//----------------------------------------------------------------------------- +// Returns the top of the stack +//----------------------------------------------------------------------------- + +template< class T, class M > +inline T& CUtlStack<T,M>::Top() +{ + assert( m_Size > 0 ); + return Element(m_Size-1); +} + +template< class T, class M > +inline T const& CUtlStack<T,M>::Top() const +{ + assert( m_Size > 0 ); + return Element(m_Size-1); +} + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- + +template< class T, class M > +inline int CUtlStack<T,M>::Count() const +{ + return m_Size; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- + +template< class T, class M > +inline bool CUtlStack<T,M>::IsIdxValid( int i ) const +{ + return (i >= 0) && (i < m_Size); +} + +//----------------------------------------------------------------------------- +// Grows the stack +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack<T,M>::GrowStack() +{ + if (m_Size >= m_Memory.NumAllocated()) + m_Memory.Grow(); + + ++m_Size; + + ResetDbgInfo(); +} + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack<T,M>::EnsureCapacity( int num ) +{ + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses default constructor +//----------------------------------------------------------------------------- + +template< class T, class M > +int CUtlStack<T,M>::Push() +{ + GrowStack(); + Construct( &Element(m_Size-1) ); + return m_Size - 1; +} + +//----------------------------------------------------------------------------- +// Adds an element, uses copy constructor +//----------------------------------------------------------------------------- + +template< class T, class M > +int CUtlStack<T,M>::Push( T const& src ) +{ + GrowStack(); + CopyConstruct( &Element(m_Size-1), src ); + return m_Size - 1; +} + + +//----------------------------------------------------------------------------- +// Pops the stack +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack<T,M>::Pop() +{ + assert( m_Size > 0 ); + Destruct( &Element(m_Size-1) ); + --m_Size; +} + +template< class T, class M > +void CUtlStack<T,M>::Pop( T& oldTop ) +{ + assert( m_Size > 0 ); + oldTop = Top(); + Pop(); +} + +template< class T, class M > +void CUtlStack<T,M>::PopMultiple( int num ) +{ + assert( m_Size >= num ); + for ( int i = 0; i < num; ++i ) + Destruct( &Element( m_Size - i - 1 ) ); + m_Size -= num; +} + + +//----------------------------------------------------------------------------- +// Element removal +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack<T,M>::Clear() +{ + for (int i = m_Size; --i >= 0; ) + Destruct(&Element(i)); + + m_Size = 0; +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- + +template< class T, class M > +void CUtlStack<T,M>::Purge() +{ + Clear(); + m_Memory.Purge( ); + ResetDbgInfo(); +} + +#endif // UTLSTACK_H diff --git a/external/vpc/public/tier1/utlstring.h b/external/vpc/public/tier1/utlstring.h new file mode 100644 index 0000000..0bd60f0 --- /dev/null +++ b/external/vpc/public/tier1/utlstring.h @@ -0,0 +1,373 @@ +//====== Copyright � 1996-2004, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +#ifndef UTLSTRING_H +#define UTLSTRING_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/utlmemory.h" +#include "tier1/strtools.h" +#include "limits.h" + + +//----------------------------------------------------------------------------- +// Base class, containing simple memory management +//----------------------------------------------------------------------------- +class CUtlBinaryBlock +{ +public: + CUtlBinaryBlock( int growSize = 0, int initSize = 0 ); + ~CUtlBinaryBlock() + { +#ifdef _DEBUG + m_nActualLength = 0x7BADF00D; +#else + m_nActualLength = 0; +#endif + } + + // NOTE: nInitialLength indicates how much of the buffer starts full + CUtlBinaryBlock( void* pMemory, int nSizeInBytes, int nInitialLength ); + CUtlBinaryBlock( const void* pMemory, int nSizeInBytes ); + CUtlBinaryBlock( const CUtlBinaryBlock& src ); + + void Get( void *pValue, int nMaxLen ) const; + void Set( const void *pValue, int nLen ); + const void *Get( ) const; + void *Get( ); + + unsigned char& operator[]( int i ); + const unsigned char& operator[]( int i ) const; + + int Length() const; + void SetLength( int nLength ); // Undefined memory will result + bool IsEmpty() const; + void Clear(); + void Purge(); + + bool IsReadOnly() const; + + CUtlBinaryBlock &operator=( const CUtlBinaryBlock &src ); + + // Test for equality + bool operator==( const CUtlBinaryBlock &src ) const; + +private: + CUtlMemory<unsigned char> m_Memory; + int m_nActualLength; +}; + + +//----------------------------------------------------------------------------- +// class inlines +//----------------------------------------------------------------------------- +inline const void *CUtlBinaryBlock::Get( ) const +{ + return m_Memory.Base(); +} + +inline void *CUtlBinaryBlock::Get( ) +{ + return m_Memory.Base(); +} + +inline int CUtlBinaryBlock::Length() const +{ + return m_nActualLength; +} + +inline unsigned char& CUtlBinaryBlock::operator[]( int i ) +{ + return m_Memory[i]; +} + +inline const unsigned char& CUtlBinaryBlock::operator[]( int i ) const +{ + return m_Memory[i]; +} + +inline bool CUtlBinaryBlock::IsReadOnly() const +{ + return m_Memory.IsReadOnly(); +} + +inline bool CUtlBinaryBlock::IsEmpty() const +{ + return Length() == 0; +} + +inline void CUtlBinaryBlock::Clear() +{ + SetLength( 0 ); +} + +inline void CUtlBinaryBlock::Purge() +{ + SetLength( 0 ); + m_Memory.Purge(); +} + + +//----------------------------------------------------------------------------- +// Simple string class. +// NOTE: This is *not* optimal! Use in tools, but not runtime code +//----------------------------------------------------------------------------- +class CUtlString +{ +public: + typedef enum + { + PATTERN_NONE = 0x00000000, + PATTERN_DIRECTORY = 0x00000001 + } TUtlStringPattern; + +public: + CUtlString(); + CUtlString( const char *pString ); + CUtlString( const CUtlString& string ); + + // Attaches the string to external memory. Useful for avoiding a copy + CUtlString( void* pMemory, int nSizeInBytes, int nInitialLength ); + CUtlString( const void* pMemory, int nSizeInBytes ); + + const char *Get( ) const; + void Set( const char *pValue ); + + void Clear() { Set( NULL ); } + + // Converts to c-strings + operator const char*() const; + + // for compatibility switching items from UtlSymbol + const char *String() const { return Get(); } + + // Returns strlen + int Length() const; + bool IsEmpty() const; + + // Sets the length (used to serialize into the buffer ) + // Note: If nLen != 0, then this adds an extra byte for a null-terminator. + void SetLength( int nLen ); + char *Get(); + void Purge(); + + // Case Change + void ToLower( ); + + void Append( const char *pchAddition ); + + // Strips the trailing slash + void StripTrailingSlash(); + + CUtlString &operator=( const CUtlString &src ); + CUtlString &operator=( const char *src ); + + // Test for equality + bool operator==( const CUtlString &src ) const; + bool operator==( const char *src ) const; + bool operator!=( const CUtlString &src ) const { return !operator==( src ); } + bool operator!=( const char *src ) const { return !operator==( src ); } + + // If these are not defined, CUtlString as rhs will auto-convert + // to const char* and do logical operations on the raw pointers. Ugh. + inline friend bool operator==( const char *lhs, const CUtlString &rhs ) { return rhs.operator==( lhs ); } + inline friend bool operator!=( const char *lhs, const CUtlString &rhs ) { return rhs.operator!=( lhs ); } + + CUtlString &operator+=( const CUtlString &rhs ); + CUtlString &operator+=( const char *rhs ); + CUtlString &operator+=( char c ); + CUtlString &operator+=( int rhs ); + CUtlString &operator+=( double rhs ); + + CUtlString operator+( const char *pOther ) const; + + bool MatchesPattern( const CUtlString &Pattern, int nFlags = 0 ) const; // case SENSITIVE, use * for wildcard in pattern string + + int Format( const char *pFormat, ... ); + void SetDirect( const char *pValue, int nChars ); + + // Defining AltArgumentType_t hints that associative container classes should + // also implement Find/Insert/Remove functions that take const char* params. + typedef const char *AltArgumentType_t; + + // Take a piece out of the string. + // If you only specify nStart, it'll go from nStart to the end. + // You can use negative numbers and it'll wrap around to the start. + CUtlString Slice( int32 nStart=0, int32 nEnd=INT_MAX ) const; + + // Grab a substring starting from the left or the right side. + CUtlString Left( int32 nChars ) const; + CUtlString Right( int32 nChars ) const; + + // Replace all instances of one character with another. + CUtlString Replace( char cFrom, char cTo ) const; + + // Calls right through to V_MakeAbsolutePath. + CUtlString AbsPath( const char *pStartingDir=NULL ) const; + + // Gets the filename (everything except the path.. c:\a\b\c\somefile.txt -> somefile.txt). + CUtlString UnqualifiedFilename() const; + + // Strips off one directory. Uses V_StripLastDir but strips the last slash also! + CUtlString DirName() const; + + // Works like V_ComposeFileName. + static CUtlString PathJoin( const char *pStr1, const char *pStr2 ); + + // These can be used for utlvector sorts. + static int __cdecl SortCaseInsensitive( const CUtlString *pString1, const CUtlString *pString2 ); + static int __cdecl SortCaseSensitive( const CUtlString *pString1, const CUtlString *pString2 ); + +private: + CUtlBinaryBlock m_Storage; +}; + +//----------------------------------------------------------------------------- +// Inline methods +//----------------------------------------------------------------------------- +inline bool CUtlString::IsEmpty() const +{ + return Length() == 0; +} + +inline int __cdecl CUtlString::SortCaseInsensitive( const CUtlString *pString1, const CUtlString *pString2 ) +{ + return V_stricmp( pString1->String(), pString2->String() ); +} + +inline int __cdecl CUtlString::SortCaseSensitive( const CUtlString *pString1, const CUtlString *pString2 ) +{ + return V_strcmp( pString1->String(), pString2->String() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Implementation of low-level string functionality for character types. +//----------------------------------------------------------------------------- + +template < typename T > +class StringFuncs +{ +public: + static T *Duplicate( const T *pValue ); + static void Copy( T *out_pOut, const T *pIn, int iLength ); + static int Compare( const T *pLhs, const T *pRhs ); + static int Length( const T *pValue ); + static const T *FindChar( const T *pStr, const T cSearch ); + static const T *EmptyString(); +}; + +template < > +class StringFuncs<char> +{ +public: + static char *Duplicate( const char *pValue ) { return strdup( pValue ); } + static void Copy( char *out_pOut, const char *pIn, int iLength ) { strncpy( out_pOut, pIn, iLength ); } + static int Compare( const char *pLhs, const char *pRhs ) { return strcmp( pLhs, pRhs ); } + static int Length( const char *pValue ) { return strlen( pValue ); } + static const char *FindChar( const char *pStr, const char cSearch ) { return strchr( pStr, cSearch ); } + static const char *EmptyString() { return ""; } +}; + +template < > +class StringFuncs<wchar_t> +{ +public: + static wchar_t *Duplicate( const wchar_t *pValue ) { return wcsdup( pValue ); } + static void Copy( wchar_t *out_pOut, const wchar_t *pIn, int iLength ) { wcsncpy( out_pOut, pIn, iLength ); } + static int Compare( const wchar_t *pLhs, const wchar_t *pRhs ) { return wcscmp( pLhs, pRhs ); } + static int Length( const wchar_t *pValue ) { return wcslen( pValue ); } + static const wchar_t *FindChar( const wchar_t *pStr, const wchar_t cSearch ) { return wcschr( pStr, cSearch ); } + static const wchar_t *EmptyString() { return L""; } +}; + +//----------------------------------------------------------------------------- +// Dirt-basic auto-release string class. Not intended for manipulation, +// can be stored in a container or forwarded as a functor parameter. +// Note the benefit over CUtlString: sizeof(CUtlConstString) == sizeof(char*). +// Also note: null char* pointers are treated identically to empty strings. +//----------------------------------------------------------------------------- + +template < typename T = char > +class CUtlConstStringBase +{ +public: + CUtlConstStringBase() : m_pString( NULL ) {} + CUtlConstStringBase( const T *pString ) : m_pString( NULL ) { Set( pString ); } + CUtlConstStringBase( const CUtlConstStringBase& src ) : m_pString( NULL ) { Set( src.m_pString ); } + ~CUtlConstStringBase() { Set( NULL ); } + + void Set( const T *pValue ); + void Clear() { Set( NULL ); } + + const T *Get() const { return m_pString ? m_pString : StringFuncs<T>::EmptyString(); } + operator const T*() const { return m_pString ? m_pString : StringFuncs<T>::EmptyString(); } + + bool IsEmpty() const { return m_pString == NULL; } // Note: empty strings are never stored by Set + + int Compare( const T *rhs ) const; + + // Logical ops + bool operator<( const T *rhs ) const { return Compare( rhs ) < 0; } + bool operator==( const T *rhs ) const { return Compare( rhs ) == 0; } + bool operator!=( const T *rhs ) const { return Compare( rhs ) != 0; } + bool operator<( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) < 0; } + bool operator==( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) == 0; } + bool operator!=( const CUtlConstStringBase &rhs ) const { return Compare( rhs.m_pString ) != 0; } + + // If these are not defined, CUtlConstString as rhs will auto-convert + // to const char* and do logical operations on the raw pointers. Ugh. + inline friend bool operator<( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) > 0; } + inline friend bool operator==( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) == 0; } + inline friend bool operator!=( const T *lhs, const CUtlConstStringBase &rhs ) { return rhs.Compare( lhs ) != 0; } + + CUtlConstStringBase &operator=( const T *src ) { Set( src ); return *this; } + CUtlConstStringBase &operator=( const CUtlConstStringBase &src ) { Set( src.m_pString ); return *this; } + + // Defining AltArgumentType_t is a hint to containers that they should + // implement Find/Insert/Remove functions that take const char* params. + typedef const T *AltArgumentType_t; + +protected: + const T *m_pString; +}; + +template < typename T > +void CUtlConstStringBase<T>::Set( const T *pValue ) +{ + if ( pValue != m_pString ) + { + free( ( void* ) m_pString ); + m_pString = pValue && pValue[0] ? StringFuncs<T>::Duplicate( pValue ) : NULL; + } +} + +template < typename T > +int CUtlConstStringBase<T>::Compare( const T *rhs ) const +{ + if ( m_pString ) + { + if ( rhs ) + return StringFuncs<T>::Compare( m_pString, rhs ); + else + return 1; + } + else + { + if ( rhs ) + return -1; + else + return 0; + } +} + +typedef CUtlConstStringBase<char> CUtlConstString; +typedef CUtlConstStringBase<wchar_t> CUtlConstWideString; + + +#endif // UTLSTRING_H diff --git a/external/vpc/public/tier1/utlsymbol.h b/external/vpc/public/tier1/utlsymbol.h new file mode 100644 index 0000000..06b8f04 --- /dev/null +++ b/external/vpc/public/tier1/utlsymbol.h @@ -0,0 +1,345 @@ +//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: Defines a symbol table +// +// $Header: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef UTLSYMBOL_H +#define UTLSYMBOL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/threadtools.h" +#include "tier1/utlrbtree.h" +#include "tier1/utlvector.h" +#include "tier1/utlbuffer.h" +#include "tier1/utllinkedlist.h" +#include "tier1/stringpool.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class CUtlSymbolTable; +class CUtlSymbolTableMT; + + +//----------------------------------------------------------------------------- +// This is a symbol, which is a easier way of dealing with strings. +//----------------------------------------------------------------------------- +typedef unsigned short UtlSymId_t; + +#define UTL_INVAL_SYMBOL ((UtlSymId_t)~0) + +class CUtlSymbol +{ +public: + // constructor, destructor + CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) {} + CUtlSymbol( UtlSymId_t id ) : m_Id(id) {} + CUtlSymbol( const char* pStr ); + CUtlSymbol( CUtlSymbol const& sym ) : m_Id(sym.m_Id) {} + + // operator= + CUtlSymbol& operator=( CUtlSymbol const& src ) { m_Id = src.m_Id; return *this; } + + // operator== + bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; } + bool operator==( const char* pStr ) const; + + // Is valid? + bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; } + + // Gets at the symbol + operator UtlSymId_t () const { return m_Id; } + + // Gets the string associated with the symbol + const char* String( ) const; + + // Modules can choose to disable the static symbol table so to prevent accidental use of them. + static void DisableStaticSymbolTable(); + + // Methods with explicit locking mechanism. Only use for optimization reasons. + static void LockTableForRead(); + static void UnlockTableForRead(); + const char * StringNoLock() const; + +protected: + UtlSymId_t m_Id; + + // Initializes the symbol table + static void Initialize(); + + // returns the current symbol table + static CUtlSymbolTableMT* CurrTable(); + + // The standard global symbol table + static CUtlSymbolTableMT* s_pSymbolTable; + + static bool s_bAllowStaticSymbolTable; + + friend class CCleanupUtlSymbolTable; +}; + + +//----------------------------------------------------------------------------- +// CUtlSymbolTable: +// description: +// This class defines a symbol table, which allows us to perform mappings +// of strings to symbols and back. The symbol class itself contains +// a static version of this class for creating global strings, but this +// class can also be instanced to create local symbol tables. +// +// This class stores the strings in a series of string pools. The first +// two bytes of each string are decorated with a hash to speed up +// comparisons. +//----------------------------------------------------------------------------- + +class CUtlSymbolTable +{ +public: + // constructor, destructor + CUtlSymbolTable( int growSize = 0, int initSize = 16, bool caseInsensitive = false ); + ~CUtlSymbolTable(); + + // Finds and/or creates a symbol based on the string + CUtlSymbol AddString( const char* pString ); + + // Finds the symbol for pString + CUtlSymbol Find( const char* pString ) const; + + // Look up the string associated with a particular symbol + const char* String( CUtlSymbol id ) const; + + // Remove all symbols in the table. + void RemoveAll(); + + int GetNumStrings( void ) const + { + return m_Lookup.Count(); + } + + // We store one of these at the beginning of every string to speed + // up comparisons. + typedef unsigned short hashDecoration_t; + +protected: + class CStringPoolIndex + { + public: + inline CStringPoolIndex() + { + } + + inline CStringPoolIndex( unsigned short iPool, unsigned short iOffset ) + : m_iPool(iPool), m_iOffset(iOffset) + {} + + inline bool operator==( const CStringPoolIndex &other ) const + { + return m_iPool == other.m_iPool && m_iOffset == other.m_iOffset; + } + + unsigned short m_iPool; // Index into m_StringPools. + unsigned short m_iOffset; // Index into the string pool. + }; + + class CLess + { + public: + CLess( int ignored = 0 ) {} // permits default initialization to NULL in CUtlRBTree + bool operator!() const { return false; } + bool operator()( const CStringPoolIndex &left, const CStringPoolIndex &right ) const; + }; + + // Stores the symbol lookup + class CTree : public CUtlRBTree<CStringPoolIndex, unsigned short, CLess> + { + public: + CTree( int growSize, int initSize ) : CUtlRBTree<CStringPoolIndex, unsigned short, CLess>( growSize, initSize ) {} + friend class CUtlSymbolTable::CLess; // Needed to allow CLess to calculate pointer to symbol table + }; + + struct StringPool_t + { + int m_TotalLen; // How large is + int m_SpaceUsed; + char m_Data[1]; + }; + + CTree m_Lookup; + + bool m_bInsensitive; + mutable unsigned short m_nUserSearchStringHash; + mutable const char* m_pUserSearchString; + + // stores the string data + CUtlVector<StringPool_t*> m_StringPools; + +private: + int FindPoolWithSpace( int len ) const; + const char* StringFromIndex( const CStringPoolIndex &index ) const; + const char* DecoratedStringFromIndex( const CStringPoolIndex &index ) const; + + friend class CLess; + friend class CSymbolHash; + +}; + +class CUtlSymbolTableMT : public CUtlSymbolTable +{ +public: + CUtlSymbolTableMT( int growSize = 0, int initSize = 32, bool caseInsensitive = false ) + : CUtlSymbolTable( growSize, initSize, caseInsensitive ) + { + } + + CUtlSymbol AddString( const char* pString ) + { + m_lock.LockForWrite(); + CUtlSymbol result = CUtlSymbolTable::AddString( pString ); + m_lock.UnlockWrite(); + return result; + } + + CUtlSymbol Find( const char* pString ) const + { + m_lock.LockForWrite(); + CUtlSymbol result = CUtlSymbolTable::Find( pString ); + m_lock.UnlockWrite(); + return result; + } + + const char* String( CUtlSymbol id ) const + { + m_lock.LockForRead(); + const char *pszResult = CUtlSymbolTable::String( id ); + m_lock.UnlockRead(); + return pszResult; + } + + const char * StringNoLock( CUtlSymbol id ) const + { + return CUtlSymbolTable::String( id ); + } + + void LockForRead() + { + m_lock.LockForRead(); + } + + void UnlockForRead() + { + m_lock.UnlockRead(); + } + +private: +#ifdef WIN32 + mutable CThreadSpinRWLock m_lock; +#else + mutable CThreadRWLock m_lock; +#endif +}; + + + +//----------------------------------------------------------------------------- +// CUtlFilenameSymbolTable: +// description: +// This class defines a symbol table of individual filenames, stored more +// efficiently than a standard symbol table. Internally filenames are broken +// up into file and path entries, and a file handle class allows convenient +// access to these. +//----------------------------------------------------------------------------- + +// The handle is a CUtlSymbol for the dirname and the same for the filename, the accessor +// copies them into a static char buffer for return. +typedef void* FileNameHandle_t; + +// Symbol table for more efficiently storing filenames by breaking paths and filenames apart. +// Refactored from Basefilesystem.h +class CUtlFilenameSymbolTable +{ + // Internal representation of a FileHandle_t + // If we get more than 64K filenames, we'll have to revisit... + // Right now CUtlSymbol is a short, so this packs into an int/void * pointer size... + struct FileNameHandleInternal_t + { + FileNameHandleInternal_t() + { + path = 0; + file = 0; + } + + // Part before the final '/' character + unsigned short path; + // Part after the final '/', including extension + unsigned short file; + }; + +public: + FileNameHandle_t FindOrAddFileName( const char *pFileName ); + FileNameHandle_t FindFileName( const char *pFileName ); + int PathIndex(const FileNameHandle_t &handle) { return (( const FileNameHandleInternal_t * )&handle)->path; } + bool String( const FileNameHandle_t& handle, char *buf, int buflen ); + void RemoveAll(); + void SpewStrings(); + bool SaveToBuffer( CUtlBuffer &buffer ); + bool RestoreFromBuffer( CUtlBuffer &buffer ); + +private: + CCountedStringPool m_StringPool; + mutable CThreadSpinRWLock m_lock; +}; + +// This creates a simple class that includes the underlying CUtlSymbol +// as a private member and then instances a private symbol table to +// manage those symbols. Avoids the possibility of the code polluting the +// 'global'/default symbol table, while letting the code look like +// it's just using = and .String() to look at CUtlSymbol type objects +// +// NOTE: You can't pass these objects between .dlls in an interface (also true of CUtlSymbol of course) +// +#define DECLARE_PRIVATE_SYMBOLTYPE( typename ) \ + class typename \ + { \ + public: \ + typename(); \ + typename( const char* pStr ); \ + typename& operator=( typename const& src ); \ + bool operator==( typename const& src ) const; \ + const char* String( ) const; \ + private: \ + CUtlSymbol m_SymbolId; \ + }; + +// Put this in the .cpp file that uses the above typename +#define IMPLEMENT_PRIVATE_SYMBOLTYPE( typename ) \ + static CUtlSymbolTable g_##typename##SymbolTable; \ + typename::typename() \ + { \ + m_SymbolId = UTL_INVAL_SYMBOL; \ + } \ + typename::typename( const char* pStr ) \ + { \ + m_SymbolId = g_##typename##SymbolTable.AddString( pStr ); \ + } \ + typename& typename::operator=( typename const& src ) \ + { \ + m_SymbolId = src.m_SymbolId; \ + return *this; \ + } \ + bool typename::operator==( typename const& src ) const \ + { \ + return ( m_SymbolId == src.m_SymbolId ); \ + } \ + const char* typename::String( ) const \ + { \ + return g_##typename##SymbolTable.String( m_SymbolId ); \ + } + +#endif // UTLSYMBOL_H diff --git a/external/vpc/public/tier1/utlvector.h b/external/vpc/public/tier1/utlvector.h new file mode 100644 index 0000000..f98698f --- /dev/null +++ b/external/vpc/public/tier1/utlvector.h @@ -0,0 +1,1275 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======// +// +// Purpose: +// +// $NoKeywords: $ +// +// A growable array class that maintains a free list and keeps elements +// in the same location +//=============================================================================// + +#ifndef UTLVECTOR_H +#define UTLVECTOR_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include <string.h> +#include "tier0/platform.h" +#include "tier0/dbg.h" +#include "tier0/threadtools.h" +#include "tier1/utlmemory.h" +#include "tier1/utlblockmemory.h" +#include "tier1/strtools.h" + +#define FOR_EACH_VEC( vecName, iteratorName ) \ + for ( int iteratorName = 0; iteratorName < (vecName).Count(); iteratorName++ ) +#define FOR_EACH_VEC_BACK( vecName, iteratorName ) \ + for ( int iteratorName = (vecName).Count()-1; iteratorName >= 0; iteratorName-- ) + +//----------------------------------------------------------------------------- +// The CUtlVector class: +// A growable array class which doubles in size by default. +// It will always keep all elements consecutive in memory, and may move the +// elements around in memory (via a PvRealloc) when elements are inserted or +// removed. Clients should therefore refer to the elements of the vector +// by index (they should *never* maintain pointers to elements in the vector). +//----------------------------------------------------------------------------- +template< class T, class A = CUtlMemory<T> > +class CUtlVector +{ + typedef A CAllocator; +public: + typedef T ElemType_t; + + // constructor, destructor + CUtlVector( int growSize = 0, int initSize = 0 ); + CUtlVector( T* pMemory, int allocationCount, int numElements = 0 ); + ~CUtlVector(); + + // Copy the array. + CUtlVector<T, A>& operator=( const CUtlVector<T, A> &other ); + + // element access + T& operator[]( int i ); + const T& operator[]( int i ) const; + T& Element( int i ); + const T& Element( int i ) const; + T& Head(); + const T& Head() const; + T& Tail(); + const T& Tail() const; + + // Gets the base address (can change when adding elements!) + T* Base() { return m_Memory.Base(); } + const T* Base() const { return m_Memory.Base(); } + + // Returns the number of elements in the vector + int Count() const; + + // Is element index valid? + bool IsValidIndex( int i ) const; + static int InvalidIndex(); + + // Adds an element, uses default constructor + int AddToHead(); + int AddToTail(); + int InsertBefore( int elem ); + int InsertAfter( int elem ); + + // Adds an element, uses copy constructor + int AddToHead( const T& src ); + int AddToTail( const T& src ); + int InsertBefore( int elem, const T& src ); + int InsertAfter( int elem, const T& src ); + + // Adds multiple elements, uses default constructor + int AddMultipleToHead( int num ); + int AddMultipleToTail( int num ); + int AddMultipleToTail( int num, const T *pToCopy ); + int InsertMultipleBefore( int elem, int num ); + int InsertMultipleBefore( int elem, int num, const T *pToCopy ); + int InsertMultipleAfter( int elem, int num ); + + // Calls RemoveAll() then AddMultipleToTail. + void SetSize( int size ); + void SetCount( int count ); + void SetCountNonDestructively( int count ); //sets count by adding or removing elements to tail TODO: This should probably be the default behavior for SetCount + + // Calls SetSize and copies each element. + void CopyArray( const T *pArray, int size ); + + // Fast swap + void Swap( CUtlVector< T, A > &vec ); + + // Add the specified array to the tail. + int AddVectorToTail( CUtlVector<T, A> const &src ); + + // Finds an element (element needs operator== defined) + int Find( const T& src ) const; + void FillWithValue( const T& src ); + + bool HasElement( const T& src ) const; + + // Makes sure we have enough memory allocated to store a requested # of elements + void EnsureCapacity( int num ); + + // Makes sure we have at least this many elements + void EnsureCount( int num ); + + // Element removal + void FastRemove( int elem ); // doesn't preserve order + void Remove( int elem ); // preserves order, shifts elements + bool FindAndRemove( const T& src ); // removes first occurrence of src, preserves order, shifts elements + bool FindAndFastRemove( const T& src ); // removes first occurrence of src, doesn't preserve order + void RemoveMultiple( int elem, int num ); // preserves order, shifts elements + void RemoveMultipleFromHead(int num); // removes num elements from tail + void RemoveMultipleFromTail(int num); // removes num elements from tail + void RemoveAll(); // doesn't deallocate memory + + // Memory deallocation + void Purge(); + + // Purges the list and calls delete on each element in it. + void PurgeAndDeleteElements(); + + // Compacts the vector to the number of elements actually in use + void Compact(); + + // Set the size by which it grows when it needs to allocate more memory. + void SetGrowSize( int size ) { m_Memory.SetGrowSize( size ); } + + int NumAllocated() const; // Only use this if you really know what you're doing! + + void Sort( int (__cdecl *pfnCompare)(const T *, const T *) ); + + // Call this to quickly sort non-contiguously allocated vectors + void InPlaceQuickSort( int (__cdecl *pfnCompare)(const T *, const T *) ); + +#ifdef DBGFLAG_VALIDATE + void Validate( CValidator &validator, char *pchName ); // Validate our internal structures +#endif // DBGFLAG_VALIDATE + +protected: + // Can't copy this unless we explicitly do it! + CUtlVector( CUtlVector const& vec ) { Assert(0); } + + // Grows the vector + void GrowVector( int num = 1 ); + + + // Shifts elements.... + void ShiftElementsRight( int elem, int num = 1 ); + void ShiftElementsLeft( int elem, int num = 1 ); + + CAllocator m_Memory; + int m_Size; + +#ifndef _X360 + // For easier access to the elements through the debugger + // it's in release builds so this can be used in libraries correctly + T *m_pElements; + + inline void ResetDbgInfo() + { + m_pElements = Base(); + } +#else + inline void ResetDbgInfo() {} +#endif + +private: + void InPlaceQuickSort_r( int (__cdecl *pfnCompare)(const T *, const T *), int nLeft, int nRight ); +}; + + +// this is kind of ugly, but until C++ gets templatized typedefs in C++0x, it's our only choice +template < class T > +class CUtlBlockVector : public CUtlVector< T, CUtlBlockMemory< T, int > > +{ +public: + CUtlBlockVector( int growSize = 0, int initSize = 0 ) + : CUtlVector< T, CUtlBlockMemory< T, int > >( growSize, initSize ) {} +}; + +//----------------------------------------------------------------------------- +// The CUtlVectorMT class: +// An array class with spurious mutex protection. Nothing is actually protected +// unless you call Lock and Unlock. Also, the Mutex_t is actually not a type +// but a member which probably isn't used. +//----------------------------------------------------------------------------- + +template< class BASE_UTLVECTOR, class MUTEX_TYPE = CThreadFastMutex > +class CUtlVectorMT : public BASE_UTLVECTOR, public MUTEX_TYPE +{ + typedef BASE_UTLVECTOR BaseClass; +public: + // MUTEX_TYPE Mutex_t; + + // constructor, destructor + CUtlVectorMT( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + CUtlVectorMT( typename BaseClass::ElemType_t* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorFixed class: +// A array class with a fixed allocation scheme +//----------------------------------------------------------------------------- +template< class T, size_t MAX_SIZE > +class CUtlVectorFixed : public CUtlVector< T, CUtlMemoryFixed<T, MAX_SIZE > > +{ + typedef CUtlVector< T, CUtlMemoryFixed<T, MAX_SIZE > > BaseClass; +public: + + // constructor, destructor + CUtlVectorFixed( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + CUtlVectorFixed( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorFixedGrowable class: +// A array class with a fixed allocation scheme backed by a dynamic one +//----------------------------------------------------------------------------- +template< class T, size_t MAX_SIZE > +class CUtlVectorFixedGrowable : public CUtlVector< T, CUtlMemoryFixedGrowable<T, MAX_SIZE > > +{ + typedef CUtlVector< T, CUtlMemoryFixedGrowable<T, MAX_SIZE > > BaseClass; + +public: + // constructor, destructor + CUtlVectorFixedGrowable( int growSize = 0 ) : BaseClass( growSize, MAX_SIZE ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorConservative class: +// A array class with a conservative allocation scheme +//----------------------------------------------------------------------------- +template< class T > +class CUtlVectorConservative : public CUtlVector< T, CUtlMemoryConservative<T> > +{ + typedef CUtlVector< T, CUtlMemoryConservative<T> > BaseClass; +public: + + // constructor, destructor + CUtlVectorConservative( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + CUtlVectorConservative( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} +}; + + +//----------------------------------------------------------------------------- +// The CUtlVectorUltra Conservative class: +// A array class with a very conservative allocation scheme, with customizable allocator +// Especialy useful if you have a lot of vectors that are sparse, or if you're +// carefully packing holders of vectors +//----------------------------------------------------------------------------- +#pragma warning(push) +#pragma warning(disable : 4200) // warning C4200: nonstandard extension used : zero-sized array in struct/union +#pragma warning(disable : 4815 ) // warning C4815: 'staticData' : zero-sized array in stack object will have no elements + +class CUtlVectorUltraConservativeAllocator +{ +public: + static void *Alloc( size_t nSize ) + { + return malloc( nSize ); + } + + static void *Realloc( void *pMem, size_t nSize ) + { + return realloc( pMem, nSize ); + } + + static void Free( void *pMem ) + { + free( pMem ); + } + + static size_t GetSize( void *pMem ) + { + return mallocsize( pMem ); + } + +}; + +template <typename T, typename A = CUtlVectorUltraConservativeAllocator > +class CUtlVectorUltraConservative : private A +{ +public: + CUtlVectorUltraConservative() + { + m_pData = StaticData(); + } + + ~CUtlVectorUltraConservative() + { + RemoveAll(); + } + + int Count() const + { + return m_pData->m_Size; + } + + static int InvalidIndex() + { + return -1; + } + + inline bool IsValidIndex( int i ) const + { + return (i >= 0) && (i < Count()); + } + + T& operator[]( int i ) + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + const T& operator[]( int i ) const + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + T& Element( int i ) + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + const T& Element( int i ) const + { + Assert( IsValidIndex( i ) ); + return m_pData->m_Elements[i]; + } + + void EnsureCapacity( int num ) + { + int nCurCount = Count(); + if ( num <= nCurCount ) + { + return; + } + if ( m_pData == StaticData() ) + { + m_pData = (Data_t *)A::Alloc( sizeof(int) + ( num * sizeof(T) ) ); + m_pData->m_Size = 0; + } + else + { + int nNeeded = sizeof(int) + ( num * sizeof(T) ); + int nHave = A::GetSize( m_pData ); + if ( nNeeded > nHave ) + { + m_pData = (Data_t *)A::Realloc( m_pData, nNeeded ); + } + } + } + + int AddToTail( const T& src ) + { + int iNew = Count(); + EnsureCapacity( Count() + 1 ); + m_pData->m_Elements[iNew] = src; + m_pData->m_Size++; + return iNew; + } + + void RemoveAll() + { + if ( Count() ) + { + for (int i = m_pData->m_Size; --i >= 0; ) + { + Destruct(&m_pData->m_Elements[i]); + } + } + if ( m_pData != StaticData() ) + { + A::Free( m_pData ); + m_pData = StaticData(); + + } + } + + void PurgeAndDeleteElements() + { + if ( m_pData != StaticData() ) + { + for( int i=0; i < m_pData->m_Size; i++ ) + { + delete Element(i); + } + RemoveAll(); + } + } + + void FastRemove( int elem ) + { + Assert( IsValidIndex(elem) ); + + Destruct( &Element(elem) ); + if (Count() > 0) + { + if ( elem != m_pData->m_Size -1 ) + memcpy( &Element(elem), &Element(m_pData->m_Size-1), sizeof(T) ); + --m_pData->m_Size; + } + if ( !m_pData->m_Size ) + { + A::Free( m_pData ); + m_pData = StaticData(); + } + } + + void Remove( int elem ) + { + Destruct( &Element(elem) ); + ShiftElementsLeft(elem); + --m_pData->m_Size; + if ( !m_pData->m_Size ) + { + A::Free( m_pData ); + m_pData = StaticData(); + } + } + + int Find( const T& src ) const + { + int nCount = Count(); + for ( int i = 0; i < nCount; ++i ) + { + if (Element(i) == src) + return i; + } + return -1; + } + + bool FindAndRemove( const T& src ) + { + int elem = Find( src ); + if ( elem != -1 ) + { + Remove( elem ); + return true; + } + return false; + } + + + bool FindAndFastRemove( const T& src ) + { + int elem = Find( src ); + if ( elem != -1 ) + { + FastRemove( elem ); + return true; + } + return false; + } + + struct Data_t + { + int m_Size; + T m_Elements[]; + }; + + Data_t *m_pData; +private: + void ShiftElementsLeft( int elem, int num = 1 ) + { + int Size = Count(); + Assert( IsValidIndex(elem) || ( Size == 0 ) || ( num == 0 )); + int numToMove = Size - elem - num; + if ((numToMove > 0) && (num > 0)) + { + V_memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) ); + +#ifdef _DEBUG + V_memset( &Element(Size-num), 0xDD, num * sizeof(T) ); +#endif + } + } + + + + static Data_t *StaticData() + { + static Data_t staticData; + Assert( staticData.m_Size == 0 ); + return &staticData; + } +}; + +#pragma warning(pop) + + +//----------------------------------------------------------------------------- +// The CCopyableUtlVector class: +// A array class that allows copy construction (so you can nest a CUtlVector inside of another one of our containers) +// WARNING - this class lets you copy construct which can be an expensive operation if you don't carefully control when it happens +// Only use this when nesting a CUtlVector() inside of another one of our container classes (i.e a CUtlMap) +//----------------------------------------------------------------------------- +template< class T > +class CCopyableUtlVector : public CUtlVector< T, CUtlMemory<T> > +{ + typedef CUtlVector< T, CUtlMemory<T> > BaseClass; +public: + CCopyableUtlVector( int growSize = 0, int initSize = 0 ) : BaseClass( growSize, initSize ) {} + CCopyableUtlVector( T* pMemory, int numElements ) : BaseClass( pMemory, numElements ) {} + virtual ~CCopyableUtlVector() {} + CCopyableUtlVector( CCopyableUtlVector const& vec ) { CopyArray( vec.Base(), vec.Count() ); } +}; + +// TODO (Ilya): It seems like all the functions in CUtlVector are simple enough that they should be inlined. + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline CUtlVector<T, A>::CUtlVector( int growSize, int initSize ) : + m_Memory(growSize, initSize), m_Size(0) +{ + ResetDbgInfo(); +} + +template< typename T, class A > +inline CUtlVector<T, A>::CUtlVector( T* pMemory, int allocationCount, int numElements ) : + m_Memory(pMemory, allocationCount), m_Size(numElements) +{ + ResetDbgInfo(); +} + +template< typename T, class A > +inline CUtlVector<T, A>::~CUtlVector() +{ + Purge(); +} + +template< typename T, class A > +inline CUtlVector<T, A>& CUtlVector<T, A>::operator=( const CUtlVector<T, A> &other ) +{ + int nCount = other.Count(); + SetSize( nCount ); + for ( int i = 0; i < nCount; i++ ) + { + (*this)[ i ] = other[ i ]; + } + return *this; +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< typename T, class A > +inline T& CUtlVector<T, A>::operator[]( int i ) +{ + Assert( i < m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline const T& CUtlVector<T, A>::operator[]( int i ) const +{ + Assert( i < m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline T& CUtlVector<T, A>::Element( int i ) +{ + Assert( i < m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline const T& CUtlVector<T, A>::Element( int i ) const +{ + Assert( i < m_Size ); + return m_Memory[ i ]; +} + +template< typename T, class A > +inline T& CUtlVector<T, A>::Head() +{ + Assert( m_Size > 0 ); + return m_Memory[ 0 ]; +} + +template< typename T, class A > +inline const T& CUtlVector<T, A>::Head() const +{ + Assert( m_Size > 0 ); + return m_Memory[ 0 ]; +} + +template< typename T, class A > +inline T& CUtlVector<T, A>::Tail() +{ + Assert( m_Size > 0 ); + return m_Memory[ m_Size - 1 ]; +} + +template< typename T, class A > +inline const T& CUtlVector<T, A>::Tail() const +{ + Assert( m_Size > 0 ); + return m_Memory[ m_Size - 1 ]; +} + + +//----------------------------------------------------------------------------- +// Count +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector<T, A>::Count() const +{ + return m_Size; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< typename T, class A > +inline bool CUtlVector<T, A>::IsValidIndex( int i ) const +{ + return (i >= 0) && (i < m_Size); +} + + +//----------------------------------------------------------------------------- +// Returns in invalid index +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector<T, A>::InvalidIndex() +{ + return -1; +} + + +//----------------------------------------------------------------------------- +// Grows the vector +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::GrowVector( int num ) +{ + if (m_Size + num > m_Memory.NumAllocated()) + { + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.Grow( m_Size + num - m_Memory.NumAllocated() ); + } + + m_Size += num; + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Sorts the vector +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::Sort( int (__cdecl *pfnCompare)(const T *, const T *) ) +{ + typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *); + if ( Count() <= 1 ) + return; + + if ( Base() ) + { + qsort( Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare) ); + } + else + { + Assert( 0 ); + // this path is untested + // if you want to sort vectors that use a non-sequential memory allocator, + // you'll probably want to patch in a quicksort algorithm here + // I just threw in this bubble sort to have something just in case... + + for ( int i = m_Size - 1; i >= 0; --i ) + { + for ( int j = 1; j <= i; ++j ) + { + if ( pfnCompare( &Element( j - 1 ), &Element( j ) ) < 0 ) + { + V_swap( Element( j - 1 ), Element( j ) ); + } + } + } + } +} + + +//---------------------------------------------------------------------------------------------- +// Private function that does the in-place quicksort for non-contiguously allocated vectors. +//---------------------------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::InPlaceQuickSort_r( int (__cdecl *pfnCompare)(const T *, const T *), int nLeft, int nRight ) +{ + int nPivot; + int nLeftIdx = nLeft; + int nRightIdx = nRight; + + if ( nRight - nLeft > 0 ) + { + nPivot = ( nLeft + nRight ) / 2; + + while ( ( nLeftIdx <= nPivot ) && ( nRightIdx >= nPivot ) ) + { + while ( ( pfnCompare( &Element( nLeftIdx ), &Element( nPivot ) ) < 0 ) && ( nLeftIdx <= nPivot ) ) + { + nLeftIdx++; + } + + while ( ( pfnCompare( &Element( nRightIdx ), &Element( nPivot ) ) > 0 ) && ( nRightIdx >= nPivot ) ) + { + nRightIdx--; + } + + V_swap( Element( nLeftIdx ), Element( nRightIdx ) ); + + nLeftIdx++; + nRightIdx--; + + if ( ( nLeftIdx - 1 ) == nPivot ) + { + nPivot = nRightIdx = nRightIdx + 1; + } + else if ( nRightIdx + 1 == nPivot ) + { + nPivot = nLeftIdx = nLeftIdx - 1; + } + } + + InPlaceQuickSort_r( pfnCompare, nLeft, nPivot - 1 ); + InPlaceQuickSort_r( pfnCompare, nPivot + 1, nRight ); + } +} + + +//---------------------------------------------------------------------------------------------- +// Call this to quickly sort non-contiguously allocated vectors. Sort uses a slower bubble sort. +//---------------------------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::InPlaceQuickSort( int (__cdecl *pfnCompare)(const T *, const T *) ) +{ + InPlaceQuickSort_r( pfnCompare, 0, Count() - 1 ); +} + + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::EnsureCapacity( int num ) +{ + MEM_ALLOC_CREDIT_CLASS(); + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Makes sure we have at least this many elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::EnsureCount( int num ) +{ + if (Count() < num) + { + AddMultipleToTail( num - Count() ); + } +} + + +//----------------------------------------------------------------------------- +// Shifts elements +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::ShiftElementsRight( int elem, int num ) +{ + Assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 )); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + V_memmove( &Element(elem+num), &Element(elem), numToMove * sizeof(T) ); +} + +template< typename T, class A > +void CUtlVector<T, A>::ShiftElementsLeft( int elem, int num ) +{ + Assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 )); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + { + V_memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) ); + +#ifdef _DEBUG + V_memset( &Element(m_Size-num), 0xDD, num * sizeof(T) ); +#endif + } +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses default constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector<T, A>::AddToHead() +{ + return InsertBefore(0); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::AddToTail() +{ + return InsertBefore( m_Size ); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::InsertAfter( int elem ) +{ + return InsertBefore( elem + 1 ); +} + +template< typename T, class A > +int CUtlVector<T, A>::InsertBefore( int elem ) +{ + // Can insert at the end + Assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(); + ShiftElementsRight(elem); + Construct( &Element(elem) ); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses copy constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector<T, A>::AddToHead( const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + return InsertBefore( 0, src ); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::AddToTail( const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + return InsertBefore( m_Size, src ); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::InsertAfter( int elem, const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + return InsertBefore( elem + 1, src ); +} + +template< typename T, class A > +int CUtlVector<T, A>::InsertBefore( int elem, const T& src ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || (&src < Base()) || (&src >= (Base() + Count()) ) ); + + // Can insert at the end + Assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(); + ShiftElementsRight(elem); + CopyConstruct( &Element(elem), src ); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds multiple elements, uses default constructor +//----------------------------------------------------------------------------- +template< typename T, class A > +inline int CUtlVector<T, A>::AddMultipleToHead( int num ) +{ + return InsertMultipleBefore( 0, num ); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::AddMultipleToTail( int num ) +{ + return InsertMultipleBefore( m_Size, num ); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::AddMultipleToTail( int num, const T *pToCopy ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || !pToCopy || (pToCopy + num <= Base()) || (pToCopy >= (Base() + Count()) ) ); + + return InsertMultipleBefore( m_Size, num, pToCopy ); +} + +template< typename T, class A > +int CUtlVector<T, A>::InsertMultipleAfter( int elem, int num ) +{ + return InsertMultipleBefore( elem + 1, num ); +} + + +template< typename T, class A > +void CUtlVector<T, A>::SetCount( int count ) +{ + RemoveAll(); + AddMultipleToTail( count ); +} + +template< typename T, class A > +inline void CUtlVector<T, A>::SetSize( int size ) +{ + SetCount( size ); +} + +template< typename T, class A > +void CUtlVector<T, A>::SetCountNonDestructively( int count ) +{ + int delta = count - m_Size; + if(delta > 0) AddMultipleToTail( delta ); + else if(delta < 0) RemoveMultipleFromTail( -delta ); +} + +template< typename T, class A > +void CUtlVector<T, A>::CopyArray( const T *pArray, int size ) +{ + // Can't insert something that's in the list... reallocation may hose us + Assert( (Base() == NULL) || !pArray || (Base() >= (pArray + size)) || (pArray >= (Base() + Count()) ) ); + + SetSize( size ); + for( int i=0; i < size; i++ ) + { + (*this)[i] = pArray[i]; + } +} + +template< typename T, class A > +void CUtlVector<T, A>::Swap( CUtlVector< T, A > &vec ) +{ + m_Memory.Swap( vec.m_Memory ); + V_swap( m_Size, vec.m_Size ); +#ifndef _X360 + V_swap( m_pElements, vec.m_pElements ); +#endif +} + +template< typename T, class A > +int CUtlVector<T, A>::AddVectorToTail( CUtlVector const &src ) +{ + Assert( &src != this ); + + int base = Count(); + + // Make space. + int nSrcCount = src.Count(); + EnsureCapacity( base + nSrcCount ); + + // Copy the elements. + m_Size += nSrcCount; + for ( int i=0; i < nSrcCount; i++ ) + { + CopyConstruct( &Element(base+i), src[i] ); + } + return base; +} + +template< typename T, class A > +inline int CUtlVector<T, A>::InsertMultipleBefore( int elem, int num ) +{ + if( num == 0 ) + return elem; + + // Can insert at the end + Assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(num); + ShiftElementsRight( elem, num ); + + // Invoke default constructors + for (int i = 0; i < num; ++i ) + { + Construct( &Element( elem+i ) ); + } + + return elem; +} + +template< typename T, class A > +inline int CUtlVector<T, A>::InsertMultipleBefore( int elem, int num, const T *pToInsert ) +{ + if( num == 0 ) + return elem; + + // Can insert at the end + Assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(num); + ShiftElementsRight( elem, num ); + + // Invoke default constructors + if ( !pToInsert ) + { + for (int i = 0; i < num; ++i ) + { + Construct( &Element( elem+i ) ); + } + } + else + { + for ( int i=0; i < num; i++ ) + { + CopyConstruct( &Element( elem+i ), pToInsert[i] ); + } + } + + return elem; +} + + +//----------------------------------------------------------------------------- +// Finds an element (element needs operator== defined) +//----------------------------------------------------------------------------- +template< typename T, class A > +int CUtlVector<T, A>::Find( const T& src ) const +{ + for ( int i = 0; i < Count(); ++i ) + { + if (Element(i) == src) + return i; + } + return -1; +} + +template< typename T, class A > +void CUtlVector<T, A>::FillWithValue( const T& src ) +{ + for ( int i = 0; i < Count(); i++ ) + { + Element(i) = src; + } +} + +template< typename T, class A > +bool CUtlVector<T, A>::HasElement( const T& src ) const +{ + return ( Find(src) >= 0 ); +} + + +//----------------------------------------------------------------------------- +// Element removal +//----------------------------------------------------------------------------- +template< typename T, class A > +void CUtlVector<T, A>::FastRemove( int elem ) +{ + Assert( IsValidIndex(elem) ); + + Destruct( &Element(elem) ); + if (m_Size > 0) + { + if ( elem != m_Size -1 ) + memcpy( &Element(elem), &Element(m_Size-1), sizeof(T) ); + --m_Size; + } +} + +template< typename T, class A > +void CUtlVector<T, A>::Remove( int elem ) +{ + Destruct( &Element(elem) ); + ShiftElementsLeft(elem); + --m_Size; +} + +template< typename T, class A > +bool CUtlVector<T, A>::FindAndRemove( const T& src ) +{ + int elem = Find( src ); + if ( elem != -1 ) + { + Remove( elem ); + return true; + } + return false; +} + +template< typename T, class A > +bool CUtlVector<T, A>::FindAndFastRemove( const T& src ) +{ + int elem = Find( src ); + if ( elem != -1 ) + { + FastRemove( elem ); + return true; + } + return false; +} + +template< typename T, class A > +void CUtlVector<T, A>::RemoveMultiple( int elem, int num ) +{ + Assert( elem >= 0 ); + Assert( elem + num <= Count() ); + + for (int i = elem + num; --i >= elem; ) + Destruct(&Element(i)); + + ShiftElementsLeft(elem, num); + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector<T, A>::RemoveMultipleFromHead( int num ) +{ + Assert( num <= Count() ); + + for (int i = num; --i >= 0; ) + Destruct(&Element(i)); + + ShiftElementsLeft(0, num); + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector<T, A>::RemoveMultipleFromTail( int num ) +{ + Assert( num <= Count() ); + + for (int i = m_Size-num; i < m_Size; i++) + Destruct(&Element(i)); + + m_Size -= num; +} + +template< typename T, class A > +void CUtlVector<T, A>::RemoveAll() +{ + for (int i = m_Size; --i >= 0; ) + { + Destruct(&Element(i)); + } + + m_Size = 0; +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- + +template< typename T, class A > +inline void CUtlVector<T, A>::Purge() +{ + RemoveAll(); + m_Memory.Purge(); + ResetDbgInfo(); +} + + +template< typename T, class A > +inline void CUtlVector<T, A>::PurgeAndDeleteElements() +{ + for( int i=0; i < m_Size; i++ ) + { + delete Element(i); + } + Purge(); +} + +template< typename T, class A > +inline void CUtlVector<T, A>::Compact() +{ + m_Memory.Purge(m_Size); +} + +template< typename T, class A > +inline int CUtlVector<T, A>::NumAllocated() const +{ + return m_Memory.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Data and memory validation +//----------------------------------------------------------------------------- +#ifdef DBGFLAG_VALIDATE +template< typename T, class A > +void CUtlVector<T, A>::Validate( CValidator &validator, char *pchName ) +{ + validator.Push( typeid(*this).name(), this, pchName ); + + m_Memory.Validate( validator, "m_Memory" ); + + validator.Pop(); +} +#endif // DBGFLAG_VALIDATE + +// A vector class for storing pointers, so that the elements pointed to by the pointers are deleted +// on exit. +template<class T> class CUtlVectorAutoPurge : public CUtlVector< T, CUtlMemory< T, int> > +{ +public: + ~CUtlVectorAutoPurge( void ) + { + this->PurgeAndDeleteElements(); + } + +}; + +// easy string list class with dynamically allocated strings. For use with V_SplitString, etc. +// Frees the dynamic strings in destructor. +class CUtlStringList : public CUtlVectorAutoPurge< char *> +{ +public: + void CopyAndAddToTail( char const *pString ) // clone the string and add to the end + { + char *pNewStr = new char[1 + strlen( pString )]; + V_strcpy( pNewStr, pString ); + AddToTail( pNewStr ); + } + + static int __cdecl SortFunc( char * const * sz1, char * const * sz2 ) + { + return strcmp( *sz1, *sz2 ); + } + +}; + + + +// <Sergiy> placing it here a few days before Cert to minimize disruption to the rest of codebase +class CSplitString: public CUtlVector<char*, CUtlMemory<char*, int> > +{ +public: + CSplitString(const char *pString, const char *pSeparator); + CSplitString(const char *pString, const char **pSeparators, int nSeparators); + ~CSplitString(); + // + // NOTE: If you want to make Construct() public and implement Purge() here, you'll have to free m_szBuffer there + // +private: + void Construct(const char *pString, const char **pSeparators, int nSeparators); + void PurgeAndDeleteElements(); +private: + char *m_szBuffer; // a copy of original string, with '\0' instead of separators +}; + + +#endif // CCVECTOR_H diff --git a/external/vpc/public/tier2/tier2.h b/external/vpc/public/tier2/tier2.h new file mode 100644 index 0000000..29f16bb --- /dev/null +++ b/external/vpc/public/tier2/tier2.h @@ -0,0 +1,122 @@ +//===== Copyright � 2005-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: A higher level link library for general use in the game and tools. +// +//===========================================================================// + + +#ifndef TIER2_H +#define TIER2_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "tier1/tier1.h" + + +//----------------------------------------------------------------------------- +// Call this to connect to/disconnect from all tier 2 libraries. +// It's up to the caller to check the globals it cares about to see if ones are missing +//----------------------------------------------------------------------------- +void ConnectTier2Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount ); +void DisconnectTier2Libraries(); + + +//----------------------------------------------------------------------------- +// Call this to get the file system set up to stdio for utilities, etc: +//----------------------------------------------------------------------------- +void InitDefaultFileSystem(void); +void ShutdownDefaultFileSystem(void); + + +//----------------------------------------------------------------------------- +// for simple utilities using valve libraries, call the entry point below in main(). It will +// init a filesystem for you, init mathlib, and create the command line. Note that this function +// may modify argc/argv because it filters out arguments (like -allowdebug). +//----------------------------------------------------------------------------- +void InitCommandLineProgram( int &argc, char ** &argv ); + + +//----------------------------------------------------------------------------- +// Helper empty implementation of an IAppSystem for tier2 libraries +//----------------------------------------------------------------------------- +template< class IInterface, int ConVarFlag = 0 > +class CTier2AppSystem : public CTier1AppSystem< IInterface, ConVarFlag > +{ + typedef CTier1AppSystem< IInterface, ConVarFlag > BaseClass; + +public: + virtual bool Connect( CreateInterfaceFn factory ) + { + if ( !BaseClass::Connect( factory ) ) + return false; + + ConnectTier2Libraries( &factory, 1 ); + return true; + } + + virtual InitReturnVal_t Init() + { + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + return INIT_OK; + } + + virtual AppSystemTier_t GetTier() + { + return APP_SYSTEM_TIER2; + } + + virtual void Shutdown() + { + BaseClass::Shutdown(); + } + + virtual void Disconnect() + { + DisconnectTier2Libraries(); + BaseClass::Disconnect(); + } +}; + + +//----------------------------------------------------------------------------- +// Distance fade information +//----------------------------------------------------------------------------- +enum FadeMode_t +{ + // These map directly to cpu_level, and g_aFadeData contains settings for each given cpu_level. + // The exception is 'FADE_MODE_LEVEL', which refers to level-specific values in the map entity. + FADE_MODE_NONE = 0, + FADE_MODE_LOW, + FADE_MODE_MED, + FADE_MODE_HIGH, + FADE_MODE_360, + FADE_MODE_LEVEL, + + FADE_MODE_COUNT, +}; + +struct FadeData_t +{ + float m_flPixelMin; // Size (height in pixels) above which objects start to fade in + float m_flPixelMax; // Size (height in pixels) above which objects are fully faded in + float m_flWidth; // Reference screen res w.r.t which the above pixel values were chosen + float m_flFadeDistScale; // Scale factor applied before entity distance-based fade is calculated +}; + +// see tier2.cpp for data! +extern FadeData_t g_aFadeData[FADE_MODE_COUNT]; + + +//----------------------------------------------------------------------------- +// Used by the resource system for fast resource frame counter +//----------------------------------------------------------------------------- +extern uint32 g_nResourceFrameCount; + + +#endif // TIER2_H + diff --git a/external/vpc/public/unitlib/unitlib.h b/external/vpc/public/unitlib/unitlib.h new file mode 100644 index 0000000..66b1aec --- /dev/null +++ b/external/vpc/public/unitlib/unitlib.h @@ -0,0 +1,271 @@ +//====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef UNITLIB_H +#define UNITLIB_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + + +//----------------------------------------------------------------------------- +// Usage model for the UnitTest library +// +// The general methodology here is that clients are expected to create unit +// test DLLs that statically link to the unit test DLL and which implement +// tests of various libraries. The unit test application will dynamically +// load all DLLs in a directory, which causes them to install their test cases +// into the unit test system. The application then runs through all tests and +// executes them all, displaying the results. +// +// *** NOTE: The test suites are compiled in both debug and release builds, +// even though it's expected to only be useful in debug builds. This is because +// I couldn't come up with a good way of disabling the code in release builds. +// (The only options I could come up with would still compile in the functions, +// just not install them into the unit test library, or would make it so that +// you couldn't step through the unit test code). +// +// Even though this is the case, there's no reason not to add test cases +// directly into your shipping DLLs, as long as you surround the code with +// #ifdef _DEBUG. To error check a project to make sure it's not compiling +// in unit tests in Release build, just don't link in unitlib.lib in Release. +// You can of course also put your test suites into separate DLLs. +// +// All tests inherit from the ITestCase interface. There are two major kinds +// of tests; the first is a single test case meant to run a piece of +// code and check its results match expected values using the Assert macros. +// The second kind is a test suite which is simply a list of other tests. +// +// The following classes and macros are used to easily create unit test cases +// and suites: +// +// Use DEFINE_TESTSUITE to define a particular test suite, and DEFINE_TESTCASE +// to add as many test cases as you like to that test suite, as follows: +// +// DEFINE_TESTSUITE( VectorTestSuite ) +// +// DEFINE_TESTCASE( VectorAdditionTest, VectorTestSuite ) +// { +// .. test code here .. +// } +// +// Note that the definition of the test suite can occur in a different file +// as the test case. A link error will occur if the test suite to which a +// test case is added has not been defined. +// +// To create a test case that is not part of a suite, use... +// +// DEFINE_TESTCASE_NOSUITE( VectorAdditionTest ) +// { +// .. test code here .. +// } +// +// You can also create a suite which is a child of another suite using +// +// DEFINE_SUBSUITE( VectorTestSuite, MathTestSuite ) +// +//----------------------------------------------------------------------------- + + + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- +#ifdef TIER0_DLL_EXPORT +#define UNITLIB_DLL_EXPORT +#endif + + +#ifdef UNITLIB_DLL_EXPORT +#define UNITLIB_INTERFACE DLL_EXPORT +#define UNITLIB_CLASS_INTERFACE DLL_CLASS_EXPORT +#define UNITLIB_GLOBAL_INTERFACE DLL_GLOBAL_EXPORT +#else +#define UNITLIB_INTERFACE DLL_IMPORT +#define UNITLIB_CLASS_INTERFACE DLL_CLASS_IMPORT +#define UNITLIB_GLOBAL_INTERFACE DLL_GLOBAL_IMPORT +#endif + + +//----------------------------------------------------------------------------- +// All unit test libraries can be asked for a unit test +// AppSystem to perform connection +//----------------------------------------------------------------------------- +#define UNITTEST_INTERFACE_VERSION "UnitTestV001" + + +//----------------------------------------------------------------------------- +// +// NOTE: All classes and interfaces below you shouldn't use directly. +// Use the DEFINE_TESTSUITE and DEFINE_TESTCASE macros instead. +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Test case + suite interface +//----------------------------------------------------------------------------- +class ITestCase +{ +public: + // This returns the test name + virtual char const* GetName() = 0; + + // This runs the test + virtual void RunTest() = 0; +}; + +class ITestSuite : public ITestCase +{ +public: + // Add a test to the suite... + virtual void AddTest( ITestCase* pTest ) = 0; +}; + + + +//----------------------------------------------------------------------------- +// This is the main function exported by the unit test library used by +// unit test DLLs to install their test cases into a list to be run +//----------------------------------------------------------------------------- +UNITLIB_INTERFACE void UnitTestInstallTestCase( ITestCase* pTest ); + + +//----------------------------------------------------------------------------- +// These are the methods used by the unit test running program to run all tests +//----------------------------------------------------------------------------- +UNITLIB_INTERFACE int UnitTestCount(); +UNITLIB_INTERFACE ITestCase* GetUnitTest( int i ); + + +//----------------------------------------------------------------------------- +// Helper for unit test DLLs to expose IAppSystems +//----------------------------------------------------------------------------- +#define USE_UNITTEST_APPSYSTEM( _className ) \ + static _className s_UnitTest ## _className; \ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR( _className, IAppSystem, UNITTEST_INTERFACE_VERSION, s_UnitTest ## _className ); + + +//----------------------------------------------------------------------------- +// Base class for test cases +//----------------------------------------------------------------------------- +class UNITLIB_CLASS_INTERFACE CTestCase : public ITestCase +{ +public: + CTestCase( char const* pName, ITestSuite* pParent = 0 ); + ~CTestCase(); + + // Returns the test name + char const* GetName(); + +private: + char* m_pName; +}; + + +//----------------------------------------------------------------------------- +// Test suite class +//----------------------------------------------------------------------------- +class UNITLIB_CLASS_INTERFACE CTestSuite : public ITestSuite +{ +public: + CTestSuite( char const* pName, ITestSuite* pParent = 0 ); + ~CTestSuite(); + + // This runs the test + void RunTest(); + + // Add a test to the suite... + void AddTest( ITestCase* pTest ); + + // Returns the test name + char const* GetName(); + +protected: + int m_TestCount; + ITestCase** m_ppTestCases; + char* m_pName; +}; + +#define TESTSUITE_CLASS( _suite ) \ + class CTS ## _suite : public CTestSuite \ + { \ + public: \ + CTS ## _suite(); \ + }; + +#define TESTSUITE_ACCESSOR( _suite ) \ + CTS ## _suite* GetTS ## _suite() \ + { \ + static CTS ## _suite s_TS ## _suite; \ + return &s_TS ## _suite; \ + } + +#define FWD_DECLARE_TESTSUITE( _suite ) \ + class CTS ## _suite; \ + CTS ## _suite* GetTS ## _suite(); + +#define DEFINE_TESTSUITE( _suite ) \ + TESTSUITE_CLASS( _suite ) \ + TESTSUITE_ACCESSOR( _suite ) \ + CTS ## _suite::CTS ## _suite() : CTestSuite( #_suite ) {} + +#define DEFINE_SUBSUITE( _suite, _parent ) \ + TESTSUITE_CLASS( _suite ) \ + TESTSUITE_ACCESSOR( _suite ) \ + FWD_DECLARE_TESTSUITE( _parent ) \ + CTS ## _suite::CTS ## _suite() : CTestSuite( #_suite, GetTS ## _parent() ) {} + +#define TESTCASE_CLASS( _case ) \ + class CTC ## _case : public CTestCase \ + { \ + public: \ + CTC ## _case (); \ + void RunTest(); \ + }; + +#define DEFINE_TESTCASE_NOSUITE( _case ) \ + TESTCASE_CLASS( _case ) \ + CTC ## _case::CTC ## _case () : CTestCase( #_case ) {} \ + \ + CTC ## _case s_TC ## _case; \ + \ + void CTC ## _case ::RunTest() + +#define DEFINE_TESTCASE( _case, _suite ) \ + TESTCASE_CLASS( _case ) \ + FWD_DECLARE_TESTSUITE( _suite ) \ + CTC ## _case::CTC ## _case () : CTestCase( #_case, GetTS ## _suite() ) {} \ + \ + CTC ## _case s_TC ## _case; \ + \ + void CTC ## _case ::RunTest() + + +#define _Shipping_AssertMsg( _exp, _msg, _executeExp, _bFatal ) \ + do { \ + if (!(_exp)) \ + { \ + LoggingResponse_t ret = Log_Assert( "%s (%d) : %s\n", __TFILE__, __LINE__, _msg ); \ + _executeExp; \ + if ( ret == LR_DEBUGGER ) \ + { \ + if ( !ShouldUseNewAssertDialog() || DoNewAssertDialog( __TFILE__, __LINE__, _msg ) ) \ + DebuggerBreak(); \ + if ( _bFatal ) \ + _ExitOnFatalAssert( __TFILE__, __LINE__ ); \ + } \ + } \ + } while (0) + +#define Shipping_Assert( _exp ) _Shipping_AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) + + +#endif // UNITLIB_H diff --git a/external/vpc/public/vstdlib/cvar.h b/external/vpc/public/vstdlib/cvar.h new file mode 100644 index 0000000..1f26e0d --- /dev/null +++ b/external/vpc/public/vstdlib/cvar.h @@ -0,0 +1,25 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#if !defined( CVAR_H ) +#define CVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vstdlib/vstdlib.h" +#include "icvar.h" + + +//----------------------------------------------------------------------------- +// Returns a CVar dictionary for tool usage +//----------------------------------------------------------------------------- +VSTDLIB_INTERFACE CreateInterfaceFn VStdLib_GetICVarFactory(); + + +#endif // CVAR_H diff --git a/external/vpc/public/vstdlib/ikeyvaluessystem.h b/external/vpc/public/vstdlib/ikeyvaluessystem.h new file mode 100644 index 0000000..3477ed3 --- /dev/null +++ b/external/vpc/public/vstdlib/ikeyvaluessystem.h @@ -0,0 +1,56 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// +#ifndef VSTDLIB_IKEYVALUESSYSTEM_H +#define VSTDLIB_IKEYVALUESSYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vstdlib/vstdlib.h" + +// handle to a KeyValues key name symbol +typedef int HKeySymbol; +#define INVALID_KEY_SYMBOL (-1) + +//----------------------------------------------------------------------------- +// Purpose: Interface to shared data repository for KeyValues (included in vgui_controls.lib) +// allows for central data storage point of KeyValues symbol table +//----------------------------------------------------------------------------- +class IKeyValuesSystem +{ +public: + // registers the size of the KeyValues in the specified instance + // so it can build a properly sized memory pool for the KeyValues objects + // the sizes will usually never differ but this is for versioning safety + virtual void RegisterSizeofKeyValues(int size) = 0; + + // allocates/frees a KeyValues object from the shared mempool + virtual void *AllocKeyValuesMemory(int size) = 0; + virtual void FreeKeyValuesMemory(void *pMem) = 0; + + // symbol table access (used for key names) + virtual HKeySymbol GetSymbolForString( const char *name, bool bCreate = true ) = 0; + virtual const char *GetStringForSymbol(HKeySymbol symbol) = 0; + + // for debugging, adds KeyValues record into global list so we can track memory leaks + virtual void AddKeyValuesToMemoryLeakList(void *pMem, HKeySymbol name) = 0; + virtual void RemoveKeyValuesFromMemoryLeakList(void *pMem) = 0; + + // set/get a value for keyvalues resolution symbol + // e.g.: SetKeyValuesExpressionSymbol( "LOWVIOLENCE", true ) - enables [$LOWVIOLENCE] + virtual void SetKeyValuesExpressionSymbol( const char *name, bool bValue ) = 0; + virtual bool GetKeyValuesExpressionSymbol( const char *name ) = 0; + + // symbol table access from code with case-preserving requirements (used for key names) + virtual HKeySymbol GetSymbolForStringCaseSensitive( HKeySymbol &hCaseInsensitiveSymbol, const char *name, bool bCreate = true ) = 0; +}; + +VSTDLIB_INTERFACE IKeyValuesSystem *KeyValuesSystem(); + +// #define KEYVALUESSYSTEM_INTERFACE_VERSION "KeyValuesSystem002" + +#endif // VSTDLIB_IKEYVALUESSYSTEM_H diff --git a/external/vpc/public/vstdlib/pch_vstdlib.h b/external/vpc/public/vstdlib/pch_vstdlib.h new file mode 100644 index 0000000..03754dd --- /dev/null +++ b/external/vpc/public/vstdlib/pch_vstdlib.h @@ -0,0 +1,51 @@ +//======== (C) Copyright 1999, 2000 Valve, L.L.C. All rights reserved. ======== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//============================================================================= + + +#pragma warning(disable: 4514) + +// First include standard libraries +#include <stdio.h> +#include <ctype.h> +#include <math.h> +#include <malloc.h> +#include <memory.h> +#include <ctype.h> + +// Next, include public +#include "tier0/basetypes.h" +#include "tier0/dbg.h" +#include "tier0/valobject.h" + +// Next, include vstdlib +#include "vstdlib/vstdlib.h" +#include "tier1/strtools.h" +#include "vstdlib/random.h" +#include "tier1/keyvalues.h" +#include "tier1/utlmemory.h" +#include "tier1/utlrbtree.h" +#include "tier1/utlvector.h" +#include "tier1/utllinkedlist.h" +#include "tier1/utlmultilist.h" +#include "tier1/utlsymbol.h" +#include "tier0/icommandline.h" +#include "tier1/netadr.h" +#include "tier1/mempool.h" +#include "tier1/utlbuffer.h" +#include "tier1/utlstring.h" +#include "tier1/utlmap.h" + +#include "tier0/memdbgon.h" + + + diff --git a/external/vpc/public/vstdlib/random.h b/external/vpc/public/vstdlib/random.h new file mode 100644 index 0000000..3f05a1d --- /dev/null +++ b/external/vpc/public/vstdlib/random.h @@ -0,0 +1,111 @@ +//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: Random number generator +// +// $Workfile: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef VSTDLIB_RANDOM_H +#define VSTDLIB_RANDOM_H + +#include "vstdlib/vstdlib.h" +#include "tier0/basetypes.h" +#include "tier0/threadtools.h" +#include "tier1/interface.h" + +#define NTAB 32 + +#pragma warning(push) +#pragma warning( disable:4251 ) + +//----------------------------------------------------------------------------- +// A generator of uniformly distributed random numbers +//----------------------------------------------------------------------------- +class IUniformRandomStream +{ +public: + // Sets the seed of the random number generator + virtual void SetSeed( int iSeed ) = 0; + + // Generates random numbers + virtual float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f ) = 0; + virtual int RandomInt( int iMinVal, int iMaxVal ) = 0; + virtual float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f ) = 0; +}; + + +//----------------------------------------------------------------------------- +// The standard generator of uniformly distributed random numbers +//----------------------------------------------------------------------------- +class VSTDLIB_CLASS CUniformRandomStream : public IUniformRandomStream +{ +public: + CUniformRandomStream(); + + // Sets the seed of the random number generator + virtual void SetSeed( int iSeed ); + + // Generates random numbers + virtual float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f ); + virtual int RandomInt( int iMinVal, int iMaxVal ); + virtual float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f ); + +private: + int GenerateRandomNumber(); + + int m_idum; + int m_iy; + int m_iv[NTAB]; + + CThreadFastMutex m_mutex; +}; + + +//----------------------------------------------------------------------------- +// A generator of gaussian distributed random numbers +//----------------------------------------------------------------------------- +class VSTDLIB_CLASS CGaussianRandomStream +{ +public: + // Passing in NULL will cause the gaussian stream to use the + // installed global random number generator + CGaussianRandomStream( IUniformRandomStream *pUniformStream = NULL ); + + // Attaches to a random uniform stream + void AttachToStream( IUniformRandomStream *pUniformStream = NULL ); + + // Generates random numbers + float RandomFloat( float flMean = 0.0f, float flStdDev = 1.0f ); + +private: + IUniformRandomStream *m_pUniformStream; + bool m_bHaveValue; + float m_flRandomValue; + + CThreadFastMutex m_mutex; +}; + + +//----------------------------------------------------------------------------- +// A couple of convenience functions to access the library's global uniform stream +//----------------------------------------------------------------------------- +VSTDLIB_INTERFACE void RandomSeed( int iSeed ); +VSTDLIB_INTERFACE float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f ); +VSTDLIB_INTERFACE float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f ); +VSTDLIB_INTERFACE int RandomInt( int iMinVal, int iMaxVal ); +VSTDLIB_INTERFACE float RandomGaussianFloat( float flMean = 0.0f, float flStdDev = 1.0f ); + + +//----------------------------------------------------------------------------- +// Installs a global random number generator, which will affect the Random functions above +//----------------------------------------------------------------------------- +VSTDLIB_INTERFACE void InstallUniformRandomStream( IUniformRandomStream *pStream ); + + +#pragma warning(pop) + +#endif // VSTDLIB_RANDOM_H + + + diff --git a/external/vpc/public/vstdlib/vstdlib.h b/external/vpc/public/vstdlib/vstdlib.h new file mode 100644 index 0000000..ffdb31a --- /dev/null +++ b/external/vpc/public/vstdlib/vstdlib.h @@ -0,0 +1,40 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef VSTDLIB_H +#define VSTDLIB_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- +#ifdef STATIC_VSTDLIB +#define VSTDLIB_INTERFACE +#define VSTDLIB_OVERLOAD +#define VSTDLIB_CLASS +#define VSTDLIB_GLOBAL +#else +#ifdef VSTDLIB_DLL_EXPORT +#define VSTDLIB_INTERFACE DLL_EXPORT +#define VSTDLIB_OVERLOAD DLL_GLOBAL_EXPORT +#define VSTDLIB_CLASS DLL_CLASS_EXPORT +#define VSTDLIB_GLOBAL DLL_GLOBAL_EXPORT +#else +#define VSTDLIB_INTERFACE DLL_IMPORT +#define VSTDLIB_OVERLOAD DLL_GLOBAL_IMPORT +#define VSTDLIB_CLASS DLL_CLASS_IMPORT +#define VSTDLIB_GLOBAL DLL_GLOBAL_IMPORT +#endif +#endif + +#endif // VSTDLIB_H diff --git a/external/vpc/public/vstdlib/vstrtools.h b/external/vpc/public/vstdlib/vstrtools.h new file mode 100644 index 0000000..04b351c --- /dev/null +++ b/external/vpc/public/vstdlib/vstrtools.h @@ -0,0 +1,275 @@ +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Functions for UCS/UTF/Unicode string operations. These functions are in vstdlib +// instead of tier1, because on PS/3 they need to load and initialize a system module, +// which is more frugal to do from a single place rather than multiple times in different PRX'es. +// The functions themselves aren't supposed to be called frequently enough for the DLL/PRX boundary +// marshalling, if any, to have any measureable impact on performance. +// +#ifndef VSTRTOOLS_HDR +#define VSTRTOOLS_HDR + +#include "tier0/platform.h" +#include "tier0/basetypes.h" +#include "tier1/strtools.h" + +#ifdef STATIC_VSTDLIB +#define VSTRTOOLS_INTERFACE +#else +#ifdef VSTDLIB_DLL_EXPORT +#define VSTRTOOLS_INTERFACE DLL_EXPORT +#else +#define VSTRTOOLS_INTERFACE DLL_IMPORT +#endif +#endif + +// conversion functions wchar_t <-> char, returning the number of characters converted +VSTRTOOLS_INTERFACE int V_UTF8ToUnicode( const char *pUTF8, wchar_t *pwchDest, int cubDestSizeInBytes ); +VSTRTOOLS_INTERFACE int V_UnicodeToUTF8( const wchar_t *pUnicode, char *pUTF8, int cubDestSizeInBytes ); +VSTRTOOLS_INTERFACE int V_UCS2ToUnicode( const ucs2 *pUCS2, wchar_t *pUnicode, int cubDestSizeInBytes ); +VSTRTOOLS_INTERFACE int V_UCS2ToUTF8( const ucs2 *pUCS2, char *pUTF8, int cubDestSizeInBytes ); +VSTRTOOLS_INTERFACE int V_UnicodeToUCS2( const wchar_t *pUnicode, int cubSrcInBytes, char *pUCS2, int cubDestSizeInBytes ); +VSTRTOOLS_INTERFACE int V_UTF8ToUCS2( const char *pUTF8, int cubSrcInBytes, ucs2 *pUCS2, int cubDestSizeInBytes ); + +// copy at most n bytes into destination, will not corrupt utf-8 multi-byte sequences +VSTRTOOLS_INTERFACE void * V_UTF8_strncpy( char *pDest, const char *pSrc, size_t nMaxBytes ); + + +// +// This utility class is for performing UTF-8 <-> UTF-16 conversion. +// It is intended for use with function/method parameters. +// +// For example, you can call +// FunctionTakingUTF16( CStrAutoEncode( utf8_string ).ToWString() ) +// or +// FunctionTakingUTF8( CStrAutoEncode( utf16_string ).ToString() ) +// +// The converted string is allocated off the heap, and destroyed when +// the object goes out of scope. +// +// if the string cannot be converted, NULL is returned. +// +// This class doesn't have any conversion operators; the intention is +// to encourage the developer to get used to having to think about which +// encoding is desired. +// +class CStrAutoEncode +{ +public: + + // ctor + explicit CStrAutoEncode( const char *pch ) + { + m_pch = pch; + m_pwch = NULL; +#if !defined( WIN32 ) && !defined(_WIN32) + m_pucs2 = NULL; + m_bCreatedUCS2 = false; +#endif + m_bCreatedUTF16 = false; + } + + // ctor + explicit CStrAutoEncode( const wchar_t *pwch ) + { + m_pch = NULL; + m_pwch = pwch; +#if !defined( WIN32 ) && !defined(_WIN32) + m_pucs2 = NULL; + m_bCreatedUCS2 = false; +#endif + m_bCreatedUTF16 = true; + } + +#if !defined(WIN32) && !defined(_WINDOWS) && !defined(_WIN32) && !defined(_PS3) + explicit CStrAutoEncode( const ucs2 *pwch ) + { + m_pch = NULL; + m_pwch = NULL; + m_pucs2 = pwch; + m_bCreatedUCS2 = true; + m_bCreatedUTF16 = false; + } +#endif + + // returns the UTF-8 string, converting on the fly. + const char* ToString() + { + PopulateUTF8(); + return m_pch; + } + + // returns the UTF-8 string - a writable pointer. + // only use this if you don't want to call const_cast + // yourself. We need this for cases like CreateProcess. + char* ToStringWritable() + { + PopulateUTF8(); + return const_cast< char* >( m_pch ); + } + + // returns the UTF-16 string, converting on the fly. + const wchar_t* ToWString() + { + PopulateUTF16(); + return m_pwch; + } + +#if !defined( WIN32 ) && !defined(_WIN32) + // returns the UTF-16 string, converting on the fly. + const ucs2* ToUCS2String() + { + PopulateUCS2(); + return m_pucs2; + } +#endif + + // returns the UTF-16 string - a writable pointer. + // only use this if you don't want to call const_cast + // yourself. We need this for cases like CreateProcess. + wchar_t* ToWStringWritable() + { + PopulateUTF16(); + return const_cast< wchar_t* >( m_pwch ); + } + + // dtor + ~CStrAutoEncode() + { + // if we're "native unicode" then the UTF-8 string is something we allocated, + // and vice versa. + if ( m_bCreatedUTF16 ) + { + delete [] m_pch; + } + else + { + delete [] m_pwch; + } +#if !defined( WIN32 ) && !defined(_WIN32) + if ( !m_bCreatedUCS2 && m_pucs2 ) + delete [] m_pucs2; +#endif + } + +private: + // ensure we have done any conversion work required to farm out a + // UTF-8 encoded string. + // + // We perform two heap allocs here; the first one is the worst-case + // (four bytes per Unicode code point). This is usually quite pessimistic, + // so we perform a second allocation that's just the size we need. + void PopulateUTF8() + { + if ( !m_bCreatedUTF16 ) + return; // no work to do + if ( m_pwch == NULL ) + return; // don't have a UTF-16 string to convert + if ( m_pch != NULL ) + return; // already been converted to UTF-8; no work to do + + // each Unicode code point can expand to as many as four bytes in UTF-8; we + // also need to leave room for the terminating NUL. + uint32 cbMax = 4 * static_cast<uint32>( V_wcslen( m_pwch ) ) + 1; + char *pchTemp = new char[ cbMax ]; + if ( V_UnicodeToUTF8( m_pwch, pchTemp, cbMax ) ) + { + uint32 cchAlloc = static_cast<uint32>( V_strlen( pchTemp ) ) + 1; + char *pchHeap = new char[ cchAlloc ]; + V_strncpy( pchHeap, pchTemp, cchAlloc ); + delete [] pchTemp; + m_pch = pchHeap; + } + else + { + // do nothing, and leave the UTF-8 string NULL + delete [] pchTemp; + } + } + + // ensure we have done any conversion work required to farm out a + // UTF-16 encoded string. + // + // We perform two heap allocs here; the first one is the worst-case + // (one code point per UTF-8 byte). This is sometimes pessimistic, + // so we perform a second allocation that's just the size we need. + void PopulateUTF16() + { + if ( m_bCreatedUTF16 ) + return; // no work to do + if ( m_pch == NULL ) + return; // no UTF-8 string to convert + if ( m_pwch != NULL ) + return; // already been converted to UTF-16; no work to do + + uint32 cchMax = static_cast<uint32>( V_strlen( m_pch ) ) + 1; + wchar_t *pwchTemp = new wchar_t[ cchMax ]; + if ( V_UTF8ToUnicode( m_pch, pwchTemp, cchMax * sizeof( wchar_t ) ) ) + { + uint32 cchAlloc = static_cast<uint32>( V_wcslen( pwchTemp ) ) + 1; + wchar_t *pwchHeap = new wchar_t[ cchAlloc ]; + V_wcsncpy( pwchHeap, pwchTemp, cchAlloc * sizeof( wchar_t ) ); + delete [] pwchTemp; + m_pwch = pwchHeap; + } + else + { + // do nothing, and leave the UTF-16 string NULL + delete [] pwchTemp; + } + } + +#if !defined( WIN32 ) && !defined(_WIN32) + // ensure we have done any conversion work required to farm out a + // UTF-16 encoded string. + // + // We perform two heap allocs here; the first one is the worst-case + // (one code point per UTF-8 byte). This is sometimes pessimistic, + // so we perform a second allocation that's just the size we need. + void PopulateUCS2() + { + if ( m_bCreatedUCS2 ) + return; + if ( m_pch == NULL ) + return; // no UTF-8 string to convert + if ( m_pucs2 != NULL ) + return; // already been converted to UTF-16; no work to do + + uint32 cchMax = static_cast<uint32>( V_strlen( m_pch ) ) + 1; + ucs2 *pwchTemp = new ucs2[ cchMax ]; + if ( V_UTF8ToUCS2( m_pch, cchMax, pwchTemp, cchMax * sizeof( ucs2 ) ) ) + { + uint32 cchAlloc = cchMax; + ucs2 *pwchHeap = new ucs2[ cchAlloc ]; + memcpy( pwchHeap, pwchTemp, cchAlloc * sizeof( ucs2 ) ); + delete [] pwchTemp; + m_pucs2 = pwchHeap; + } + else + { + // do nothing, and leave the UTF-16 string NULL + delete [] pwchTemp; + } + } +#endif + + // one of these pointers is an owned pointer; whichever + // one is the encoding OTHER than the one we were initialized + // with is the pointer we've allocated and must free. + const char *m_pch; + const wchar_t *m_pwch; +#if !defined( WIN32 ) && !defined(_WIN32) + const ucs2 *m_pucs2; + bool m_bCreatedUCS2; +#endif + // "created as UTF-16", means our owned string is the UTF-8 string not the UTF-16 one. + bool m_bCreatedUTF16; + +}; + + +#define V_UTF8ToUnicode V_UTF8ToUnicode +#define V_UnicodeToUTF8 V_UnicodeToUTF8 + + +#endif
\ No newline at end of file diff --git a/external/vpc/public/winlite.h b/external/vpc/public/winlite.h new file mode 100644 index 0000000..dc2a0bd --- /dev/null +++ b/external/vpc/public/winlite.h @@ -0,0 +1,31 @@ +//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef WINLITE_H +#define WINLITE_H +#pragma once + +#ifdef _WIN32 +// +// Prevent tons of unused windows definitions +// +#define WIN32_LEAN_AND_MEAN +#define NOWINRES +#define NOSERVICE +#define NOMCX +#define NOIME +#if !defined( _X360 ) +#pragma warning(push, 1) +#pragma warning(disable: 4005) +#include <windows.h> +#pragma warning(pop) +#endif +#undef PostMessage + +#endif // WIN32 +#endif // WINLITE_H |