This commit is contained in:
Huoji's
2023-10-03 04:07:50 +08:00
parent f08e0b90fa
commit 8f3005e9b2
50 changed files with 11966 additions and 107 deletions

1397
csgo2/sdk/public/bitvec.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,10 @@
#include "../tier1/bufferstring.h"
#include "../convar/convar.hpp"
#include "../protobuf-2.6.1/src/google/protobuf/message.h"
#include "string_t.h"
struct vis_info_t;
struct string_t;
class IHLTVServer;
class IHLTVDirector;
class CSteamID;
@@ -17,7 +20,111 @@ class CPlayerBitVec;
class edict_t;
class CGamestatsData;
class KeyValues;
class CGlobalVars;
enum GlobalVarsUsageWarning_t
{
GV_RENDERTIME_CALLED_DURING_SIMULATION,
GV_CURTIME_CALLED_DURING_RENDERING
};
enum MapLoadType_t
{
MapLoad_NewGame = 0,
MapLoad_LoadGame,
MapLoad_Transition,
MapLoad_Background,
};
typedef void (*FnGlobalVarsWarningFunc)(GlobalVarsUsageWarning_t);
//-----------------------------------------------------------------------------
// Purpose: Global variables used by shared code
//-----------------------------------------------------------------------------
class CGlobalVarsBase
{
public:
CGlobalVarsBase();
public:
// Absolute time (per frame still - Use Plat_FloatTime() for a high precision real time
// perf clock, but not that it doesn't obey host_timescale/host_framerate)
float realtime;
// Absolute frame counter - continues to increase even if game is paused
int framecount;
// Non-paused frametime
float absoluteframetime;
float absoluteframestarttimestddev;
int maxClients;
// zer0k: Command queue related
int unknown1;
int unknown2;
FnGlobalVarsWarningFunc m_pfnWarningFunc;
// Time spent on last server or client frame (has nothing to do with think intervals)
float frametime;
// Current time
//
// On the client, this (along with tickcount) takes a different meaning based on what
// piece of code you're in:
//
// - While receiving network packets (like in PreDataUpdate/PostDataUpdate and proxies),
// this is set to the SERVER TICKCOUNT for that packet. There is no interval between
// the server ticks.
// [server_current_Tick * tick_interval]
//
// - While rendering, this is the exact client clock
// [client_current_tick * tick_interval + interpolation_amount]
//
// - During prediction, this is based on the client's current tick:
// [client_current_tick * tick_interval]
float curtime;
float rendertime;
// zer0k: Command queue + interpolation related
float unknown3;
float unknown4;
bool m_bInSimulation;
bool m_bEnableAssertions;
// Simulation ticks - does not increase when game is paused
int tickcount;
// Simulation tick interval
float interval_per_tick;
};
inline CGlobalVarsBase::CGlobalVarsBase()
{
}
class CGlobalVars : public CGlobalVarsBase
{
public:
CGlobalVars();
public:
// Current map
string_t mapname;
string_t startspot;
MapLoadType_t eLoadType; // How the current map was loaded
bool mp_teamplay;
// current maxentities
int maxEntities;
int serverCount;
};
inline CGlobalVars::CGlobalVars() :
CGlobalVarsBase()
{
serverCount = 0;
}
class CSharedEdictChangeInfo;
class IAchievementMgr;
class CCommandContext;

133
csgo2/sdk/public/iserver.h Normal file
View File

@@ -0,0 +1,133 @@
#pragma once
#include "../sdk.h"
class GameSessionConfiguration_t { };
class IGameSpawnGroupMgr;
struct EventServerAdvanceTick_t;
struct EventServerPollNetworking_t;
struct EventServerProcessNetworking_t;
struct EventServerSimulate_t;
struct EventServerPostSimulate_t;
struct server_state_t;
class IPrerequisite;
class CServerChangelevelState;
class ISource2WorldSession;
class INetworkGameClient;
class GameSessionConfiguration_t;
typedef int HGameResourceManifest;
struct SpawnGroupDesc_t;
struct EngineLoopState_t;
struct EventMapRegistrationType_t;
class ILoopModeFactory;
struct ActiveLoop_t;
struct EventClientOutput_t;
class ISwitchLoopModeStatusNotify;
class IAddonListChangeNotify;
enum ESpawnGroupUnloadOption
{
};
class IConnectionlessPacketHandler
{
public:
virtual ~IConnectionlessPacketHandler(void) {};
virtual bool ProcessConnectionlessPacket(const void* addr, void* bf) = 0; // process a connectionless packet
};
class INetworkGameServer : public IConnectionlessPacketHandler
{
public:
virtual void Init(const GameSessionConfiguration_t&, const char*) = 0;
virtual void SetGameSpawnGroupMgr(IGameSpawnGroupMgr*) = 0;
virtual void SetGameSessionManifest(HGameResourceManifest*) = 0;
virtual void RegisterLoadingSpawnGroups(void*) = 0;
virtual void Shutdown(void) = 0;
virtual void AddRef(void) = 0;
virtual void Release(void) = 0;
virtual CGlobalVars* GetGlobals(void) = 0;
virtual bool IsActive(void) const = 0;
virtual void SetServerTick(int tick) = 0;
virtual int GetServerTick(void) const = 0; // returns game world tick
virtual void SetFinalSimulationTickThisFrame(int) = 0;
virtual int GetMaxClients(void) const = 0; // returns current client limit
virtual float GetTickInterval(void) const = 0; // tick interval in seconds
virtual void ServerAdvanceTick(const EventServerAdvanceTick_t&) = 0;
virtual void ServerPollNetworking(const EventServerPollNetworking_t&) = 0;
virtual void ServerProcessNetworking(const EventServerProcessNetworking_t&) = 0;
virtual void ServerSimulate(const EventServerSimulate_t&) = 0;
virtual void ServerPostSimulate(const EventServerPostSimulate_t&) = 0;
virtual void LoadSpawnGroup(const SpawnGroupDesc_t&) = 0;
virtual void AsyncUnloadSpawnGroup(unsigned int, ESpawnGroupUnloadOption) = 0;
virtual void PrintSpawnGroupStatus(void) const = 0;
virtual float GetTimescale(void) const = 0; // returns the game time scale (multiplied in conjunction with host_timescale)
virtual bool IsSaveRestoreAllowed(void) const = 0;
virtual void SetMapName(const char* pszNewName) = 0;
virtual const char* GetMapName(void) const = 0; // current map name (BSP)
virtual const char* GetAddonName(void) const = 0;
virtual bool IsBackgroundMap(void) const = 0;
virtual float GetTime(void) const = 0; // returns game world time
virtual int GetMapVersion(void) const = 0;
virtual void ActivateServer(void) = 0;
virtual void PrepareForAssetLoad(void) = 0;
virtual int GetServerNetworkAddress(void) = 0;
virtual SpawnGroupHandle_t FindSpawnGroupByName(const char* pszName) = 0;
virtual void MakeSpawnGroupActive(SpawnGroupHandle_t) = 0;
virtual void SynchronouslySpawnGroup(SpawnGroupHandle_t) = 0;
virtual void SetServerState(server_state_t) = 0;
virtual void SpawnServer(const char*) = 0;
virtual void GetSpawnGroupLoadingStatus(SpawnGroupHandle_t) = 0;
virtual void SetSpawnGroupDescription(SpawnGroupHandle_t, const char*) = 0;
virtual void* StartChangeLevel(const char*, const char* pszLandmark, void*) = 0;
virtual void FinishChangeLevel(CServerChangelevelState*) = 0;
virtual bool IsChangelevelPending(void) const = 0;
virtual void GetAllLoadingSpawnGroups(void* pOut) = 0;
virtual void PreserveSteamID(void) = 0;
virtual void OnKickById(const CCommandContext& context, const CCommand& args) = 0;
virtual void OnKickByName(const CCommandContext& context, const CCommand& args) = 0;
};
class IEngineService : public IAppSystem
{
public:
virtual void* GetServiceDependencies(void) = 0;
virtual const char* GetName(void) const = 0;
virtual bool ShouldActivate(const char*) = 0;
virtual void OnLoopActivate(const EngineLoopState_t& loopState, /*CEventDispatcher<CEventIDManager_Default>*/ void*) = 0;
virtual void OnLoopDeactivate(const EngineLoopState_t& loopState, /*CEventDispatcher<CEventIDManager_Default>*/ void*) = 0;
virtual bool IsActive(void) const = 0;
virtual void SetActive(bool) = 0;
virtual void SetName(const char* pszName) = 0;
virtual void RegisterEventMap( /*CEventDispatcher<CEventIDManager_Default>*/ void*, EventMapRegistrationType_t) = 0;
virtual uint16_t GetServiceIndex(void) = 0;
virtual void SetServiceIndex(uint16_t index) = 0;
};
class INetworkServerService : public IEngineService
{
public:
virtual ~INetworkServerService() {}
virtual INetworkGameServer * GetIGameServer(void) = 0;
virtual bool IsActiveInGame(void) const = 0;
virtual bool IsMultiplayer(void) const = 0;
virtual void StartupServer(const GameSessionConfiguration_t& config, ISource2WorldSession* pWorldSession, const char*) = 0;
virtual void SetGameSpawnGroupMgr(IGameSpawnGroupMgr* pMgr) = 0;
virtual void AddServerPrerequisites(const GameSessionConfiguration_t&, const char*, void*, bool) = 0;
virtual void SetServerSocket(int) = 0;
virtual bool IsServerRunning(void) const = 0;
virtual void DisconnectGameNow( /*ENetworkDisconnectionReason*/ int) = 0;
virtual void PrintSpawnGroupStatus(void) const = 0;
virtual void SetFinalSimulationTickThisFrame(int) = 0;
virtual void* GetGameServer(void) = 0;
virtual int GetTickInterval(void) const = 0;
virtual void ProcessSocket(void) = 0;
virtual int GetServerNetworkAddress(void) = 0;
virtual bool GameLoadFailed(void) const = 0;
virtual void SetGameLoadFailed(bool bFailed) = 0;
virtual void SetGameLoadStarted(void) = 0;
virtual void StartChangeLevel(void) = 0;
virtual void PreserveSteamID(void) = 0;
virtual unsigned long GetServerSerializersCRC(void) = 0;
virtual void* GetServerSerializersMsg(void) = 0;
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include "../sdk.h"
FORCEINLINE unsigned int SmallestPowerOfTwoGreaterOrEqual(unsigned int x)
{
x -= 1;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x + 1;
}

114
csgo2/sdk/public/string_t.h Normal file
View File

@@ -0,0 +1,114 @@
//========= Copyright ?1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Defines the more complete set of operations on the string_t defined
// These should be used instead of direct manipulation to allow more
// flexibility in future ports or optimization.
//
// $NoKeywords: $
//=============================================================================//
#include <cstddef>
#ifndef STRING_T_H
#define STRING_T_H
#if defined( _WIN32 )
#pragma once
#endif
#ifndef NO_STRING_T
#ifdef WEAK_STRING_T
typedef int string_t;
//-----------------------------------------------------------------------------
// Purpose: The correct way to specify the NULL string as a constant.
//-----------------------------------------------------------------------------
#define NULL_STRING 0
//-----------------------------------------------------------------------------
// Purpose: Given a string_t, make a C string. By convention the result string
// pointer should be considered transient and should not be stored.
//-----------------------------------------------------------------------------
#define STRING( offset ) ( ( offset ) ? reinterpret_cast<const char *>( offset ) : "" )
//-----------------------------------------------------------------------------
// Purpose: Given a C string, obtain a string_t
//-----------------------------------------------------------------------------
#define MAKE_STRING( str ) ( ( *str != 0 ) ? reinterpret_cast<int>( str ) : 0 )
//-----------------------------------------------------------------------------
#define IDENT_STRINGS( s1, s2 ) ( *((void **)&(s1)) == *((void **)&(s2)) )
//-----------------------------------------------------------------------------
#else // Strong string_t
//-----------------------------------------------------------------------------
struct string_t
{
public:
bool operator!() const { return ( pszValue == NULL ); }
bool operator==( const string_t &rhs ) const { return ( pszValue == rhs.pszValue ); }
bool operator!=( const string_t &rhs ) const { return ( pszValue != rhs.pszValue ); }
bool operator<( const string_t &rhs ) const { return ((void *)pszValue < (void *)rhs.pszValue ); }
const char *ToCStr() const { return ( pszValue ) ? pszValue : ""; }
protected:
const char *pszValue;
};
//-----------------------------------------------------------------------------
struct castable_string_t : public string_t // string_t is used in unions, hence, no constructor allowed
{
castable_string_t() { pszValue = NULL; }
castable_string_t( const char *pszFrom ) { pszValue = (pszFrom && *pszFrom) ? pszFrom : 0; }
};
//-----------------------------------------------------------------------------
// Purpose: The correct way to specify the NULL string as a constant.
//-----------------------------------------------------------------------------
#define NULL_STRING castable_string_t()
//-----------------------------------------------------------------------------
// Purpose: Given a string_t, make a C string. By convention the result string
// pointer should be considered transient and should not be stored.
//-----------------------------------------------------------------------------
#define STRING( string_t_obj ) (string_t_obj).ToCStr()
//-----------------------------------------------------------------------------
// Purpose: Given a C string, obtain a string_t
//-----------------------------------------------------------------------------
#define MAKE_STRING( c_str ) castable_string_t( c_str )
//-----------------------------------------------------------------------------
#define IDENT_STRINGS( s1, s2 ) ( *((void **)&(s1)) == *((void **)&(s2)) )
//-----------------------------------------------------------------------------
#endif
#else // NO_STRING_T
typedef const char *string_t;
#define NULL_STRING 0
#define STRING( c_str ) ( c_str )
#define MAKE_STRING( c_str ) ( c_str )
#define IDENT_STRINGS( s1, s2 ) ( *((void **)&(s1)) == *((void **)&(s2)) )
#endif // NO_STRING_T
//=============================================================================
#endif // STRING_T_H

200
csgo2/sdk/public/utlmap.h Normal file
View File

@@ -0,0 +1,200 @@
//========= Copyright ?1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Header: $
// $NoKeywords: $
//=============================================================================//
#ifndef UTLMAP_H
#define UTLMAP_H
#ifdef _WIN32
#pragma once
#endif
#include "../sdk.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(); 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; iteratorName < mapName.MaxElement(); ++iteratorName ) if ( !mapName.IsValidIndex( iteratorName ) ) continue; else
template <typename K, typename T, typename I = short unsigned int, typename LF = bool (*)(const K&, const K&)>
class CUtlMap
{
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 LF 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
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(); }
// 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;
};
//-----------------------------------------------------------------------------
#endif // UTLMAP_H

1546
csgo2/sdk/public/utlrbtree.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,6 @@
#pragma once
#include <limits.h>
#include <cstdint>
#define CORRECT_PATH_SEPARATOR '\\'
#define CORRECT_PATH_SEPARATOR_S "\\"
#define INCORRECT_PATH_SEPARATOR '/'
@@ -29,4 +31,31 @@ enum EUniverse
// k_EUniverseRC = 5, // no such universe anymore
k_EUniverseMax
};
#define Plat_FastMemset memset
#define Plat_FastMemcpy memcpy
#define RESTRICT __restrict
#define RESTRICT_FUNC __declspec(restrict)
#define FORCEINLINE_TEMPLATE __forceinline
#define PAD_NUMBER(number, boundary) \
( ((number) + ((boundary)-1)) / (boundary) ) * (boundary)
typedef __int64 intp;
#ifndef Assert
#define Assert
#endif // !Assert
template <class T>
inline T* Construct(T* pMemory)
{
return ::new(pMemory) T;
}
template <class T>
inline void Destruct(T* pMemory)
{
pMemory->~T();
#ifdef _DEBUG
memset((void*)pMemory, 0xDD, sizeof(T));
#endif
}
#include "../head.h"

View File

@@ -1,5 +1,5 @@
#pragma once
#include <stdint.h>
#include <cstring>
#include "UtlMemory.hpp"
#define _Utl_Vector_assert

View File

@@ -0,0 +1,345 @@
//===== Copyright <20> 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 "../sdk.h"
#ifdef _MSC_VER
#pragma warning (disable:4100)
#pragma warning (disable:4514)
#endif
//-----------------------------------------------------------------------------
#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 not used, 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" );
__debugbreak();
}
// 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 );
}
#endif // UTLBLOCKMEMORY_H

View File

@@ -0,0 +1,337 @@
//===== Copyright <20> 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 "../sdk.h"
#ifdef _MSC_VER
#pragma warning (disable:4100)
#pragma warning (disable:4514)
#endif
//-----------------------------------------------------------------------------
#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 not used, 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;
intp 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
{
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();
}
intp GetIndex( const Iterator_t &it ) const
{
if ( !IsValidIterator( it ) )
return InvalidIndex();
return ( intp )( HeaderToBlock( it.m_pBlockHeader ) + it.m_nIndex );
}
bool IsIdxAfter( intp i, const Iterator_t &it ) const
{
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, INVALID_INDEX ); }
// element access
T& operator[]( intp i );
const T& operator[]( intp i ) const;
T& Element( intp i );
const T& Element( intp i ) const;
// Can we use this index?
bool IsIdxValid( intp i ) const;
// Specify the invalid ('null') index that we'll only return on failure
static const intp INVALID_INDEX = 0; // For use with COMPILE_TIME_ASSERT
static intp 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( intp 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;
intp 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[]( intp i )
{
return *( T* )i;
}
template< class T >
inline const T& CUtlFixedMemory<T>::operator[]( intp i ) const
{
return *( T* )i;
}
template< class T >
inline T& CUtlFixedMemory<T>::Element( intp i )
{
return *( T* )i;
}
template< class T >
inline const T& CUtlFixedMemory<T>::Element( intp i ) const
{
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( intp 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 );
}
}
if ( nBlockSize < num )
{
int n = ( num + nBlockSize -1 ) / nBlockSize;
nBlockSize *= n;
}
m_nAllocationCount += nBlockSize;
MEM_ALLOC_CREDIT_CLASS();
BlockHeader_t * RESTRICT pBlockHeader = ( BlockHeader_t* )malloc( sizeof( BlockHeader_t ) + nBlockSize * sizeof( T ) );
if ( !pBlockHeader )
{
__debugbreak();
}
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;
}
#endif // UTLFIXEDMEMORY_H