添加项目文件。

This commit is contained in:
Huoji's
2023-10-01 02:28:13 +08:00
parent ee12160e20
commit effb823be9
73 changed files with 7735 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
#include "convar.hpp"
inline const char** CCommand::ArgV() const
{
return ArgC() ? (const char**)m_Args.Base() : NULL;
}
inline const char* CCommand::ArgS() const
{
return m_nArgv0Size ? (m_ArgSBuffer.Base() + m_nArgv0Size) : "";
}
inline const char* CCommand::operator[](int nIndex) const
{
return Arg(nIndex);
}

128
csgo2/sdk/convar/convar.hpp Normal file
View File

@@ -0,0 +1,128 @@
#include "../sdk.h"
#include "../tier1/UtlVector.hpp"
struct characterset_t
{
char set[256];
};
class ConCommandBase
{
friend class CCvar;
friend class ConCommand;
protected:
ConCommandBase(void);
public:
~ConCommandBase(void);
// Check flag
bool IsFlagSet(int64_t flag) const;
// Set flag
void AddFlags(int64_t flags);
// Clear flag
void RemoveFlags(int64_t flags);
int64_t GetFlags() const;
// Return name of cvar
const char* GetName(void) const;
// Return help text for cvar
const char* GetHelpText(void) const;
private:
// Static data
const char* m_pszName;
const char* m_pszHelpString;
// ConVar flags
int64_t m_nFlags;
};
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);
}
void EnsureCapacity(int num)
{
if (CUtlMemory<T>::m_nAllocationCount >= num)
return;
BaseClass::EnsureCapacity(num);
}
private:
T m_pFixedMemory[SIZE];
};
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) {}
};
class CCommand
{
public:
CCommand();
CCommand(int nArgC, const char** ppArgV);
virtual bool Tokenize(const char* pCommand, characterset_t* pBreakSet = NULL);
virtual void Reset();
int ArgC() const {
return m_Args.Count();
}
const char** ArgV() const;
const char* ArgS() const; // All args that occur after the 0th arg, in string form
const char* GetCommandString() const
{
return ArgC() ? m_ArgSBuffer.Base() : "";
}
const char* operator[](int nIndex) const; // Gets at arguments
const char* 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 >= ArgC())
return "";
return m_Args[nIndex];
}
// Helper functions to parse arguments to commands.
//
// Returns index of argument, or -1 if no such argument.
int FindArg(const char* pName) const;
int FindArgInt(const char* pName, int nDefaultVal) const;
static int MaxCommandLength()
{
return COMMAND_MAX_LENGTH - 1;
}
static characterset_t* DefaultBreakSet();
private:
enum
{
COMMAND_MAX_ARGC = 64,
COMMAND_MAX_LENGTH = 512,
};
int m_nArgv0Size;
CUtlVectorFixedGrowable<char, COMMAND_MAX_LENGTH> m_ArgSBuffer;
CUtlVectorFixedGrowable<char, COMMAND_MAX_LENGTH> m_ArgvBuffer;
CUtlVectorFixedGrowable<char*, COMMAND_MAX_ARGC> m_Args;
};

View File

@@ -0,0 +1,151 @@
#pragma once
#include "../sdk.h"
#include "../player/playerslot.h"
#include "../player/player.h"
#include "../handle/basehandle.h"
#include "../interfaces/interfaces.h"
class CMsgSource1LegacyGameEvent;
class CUtlString;
class IToolGameEventAPI
{
virtual void unk001(void*) = 0;
};
struct UnkGameEventStruct_t {
UnkGameEventStruct_t(const char* keyName) {
m_Unk = 0;
m_Key = keyName;
}
uint64_t m_Unk;
const char* m_Key;
};
class IGameEvent
{
public:
virtual ~IGameEvent() {};
virtual const char* GetName() const = 0; // get event name
virtual int GetID() const = 0;
virtual bool IsReliable() const = 0; // if event handled reliable
virtual bool IsLocal() const = 0; // if event is never networked
virtual bool IsEmpty(const char* keyName = NULL) = 0; // check if data field exists
// Data access
virtual bool GetBool(const char* keyName = NULL, bool defaultValue = false) = 0;
virtual int GetInt(const char* keyName = NULL, int defaultValue = 0) = 0;
virtual uint64_t GetUint64(const char* keyName = NULL, uint64_t defaultValue = 0) = 0;
virtual float GetFloat(const char* keyName = NULL, float defaultValue = 0.0f) = 0;
virtual const char* GetString(const char* keyName = NULL, const char* defaultValue = "") = 0;
virtual void* GetPtr(const char* keyName = NULL, void* defaultValue = NULL) = 0;
/* These function prototypes and names are very speculative and might be incorrect */
virtual CEntityHandle GetEHandle(UnkGameEventStruct_t* keyName, CEntityHandle defaultValue) = 0;
virtual CEntityHandle GetStrictEHandle(UnkGameEventStruct_t* keyName, CEntityHandle defaultValue) = 0;
virtual CEntityHandle GetEHandle2(UnkGameEventStruct_t* keyName, CEntityHandle defaultValue) = 0;
virtual CPlayerSlot* GetPlayerSlot(UnkGameEventStruct_t* keyName = NULL) = 0;
virtual CBasePlayer* GetPlayer(UnkGameEventStruct_t* keyName = NULL) = 0;
virtual void* GetPlayerPawn(UnkGameEventStruct_t* keyName = NULL) = 0;
virtual CEntityHandle GetPlayerControllerEHandle(UnkGameEventStruct_t* keyName = NULL) = 0;
virtual CEntityHandle GetPlayerControllerEHandle2(UnkGameEventStruct_t* keyName = NULL) = 0;
/* ============================================================ */
virtual void SetBool(const char* keyName, bool value) = 0;
virtual void SetInt(const char* keyName, int value) = 0;
virtual void SetUint64(const char* keyName, uint64_t value) = 0;
virtual void SetFloat(const char* keyName, float value) = 0;
virtual void SetString(const char* keyName, const char* value) = 0;
virtual void SetPtr(const char* keyName, void* value) = 0;
/* These function prototypes and names are very speculative and might be incorrect */
virtual void SetEHandleStrict(const char* keyName, CEntityHandle handle) = 0;
virtual void SetEHandle(const char* keyName, CEntityHandle handle) = 0;
// Also sets the _pawn key
virtual void SetPlayerSlot(const char* keyName, CPlayerSlot value) = 0;
virtual void SetPlayer(const char* keyName, CBasePlayer* value) = 0;
/* ============================================================ */
virtual bool HasKey(const char* keyName) = 0;
// Something script vm related
virtual void unk001() = 0;
//virtual KeyValues* GetDataKeys() const = 0;
};
class IGameEventListener2
{
public:
virtual ~IGameEventListener2(void) {};
// FireEvent is called by EventManager if event just occured
// KeyValue memory will be freed by manager if not needed anymore
virtual void FireGameEvent(IGameEvent* event) = 0;
};
class IGameEventManager2 : public IBaseInterface, public IToolGameEventAPI
{
public:
virtual ~IGameEventManager2(void) {};
// load game event descriptions from a file eg "resource\gameevents.res"
virtual int LoadEventsFromFile(const char* filename, bool bSearchAll) = 0;
// removes all and anything
virtual void Reset() = 0;
// adds a listener for a particular event
virtual bool AddListener(IGameEventListener2* listener, const char* name, bool bServerSide) = 0;
// returns true if this listener is listens to given event
virtual bool FindListener(IGameEventListener2* listener, const char* name) = 0;
// removes a listener
virtual void RemoveListener(IGameEventListener2* listener) = 0;
// create an event by name, but doesn't fire it. returns NULL is event is not
// known or no listener is registered for it. bForce forces the creation even if no listener is active
virtual IGameEvent* CreateEvent(const char* name, bool bForce = false, int* pCookie = NULL) = 0;
// fires a server event created earlier, if bDontBroadcast is set, event is not send to clients
virtual bool FireEvent(IGameEvent* event, bool bDontBroadcast = false) = 0;
// fires an event for the local client only, should be used only by client code
virtual bool FireEventClientSide(IGameEvent* event) = 0;
// create a new copy of this event, must be free later
virtual IGameEvent* DuplicateEvent(IGameEvent* event) = 0;
// if an event was created but not fired for some reason, it has to bee freed, same UnserializeEvent
virtual void FreeEvent(IGameEvent* event) = 0;
// write/read event to/from bitbuffer
virtual bool SerializeEvent(IGameEvent* event, CMsgSource1LegacyGameEvent* ev) = 0;
virtual IGameEvent* UnserializeEvent(const CMsgSource1LegacyGameEvent& ev) = 0; // create new KeyValues, must be deleted
virtual int LookupEventId(const char* name) = 0;
virtual void PrintEventToString(IGameEvent* event, CUtlString& out) = 0;
virtual bool HasEventDescriptor(const char* name) = 0;
};
class CGameEventManager : public IGameEventManager2
{
public: // IGameEventManager functions
virtual ~CGameEventManager() = 0;
virtual int LoadEventsFromFile(const char* filename) = 0;
virtual void Reset() = 0;
virtual bool AddListener(IGameEventListener2* listener, const char* name, bool bServerSide) = 0;
virtual bool FindListener(IGameEventListener2* listener, const char* name) = 0;
virtual void RemoveListener(IGameEventListener2* listener) = 0;
virtual IGameEvent* CreateEvent(const char* name, bool bForce = false) = 0;
virtual IGameEvent* DuplicateEvent(IGameEvent* event) = 0;
virtual bool FireEvent(IGameEvent* event, bool bDontBroadcast = false) = 0;
virtual bool FireEventClientSide(IGameEvent* event) = 0;
};

View File

@@ -0,0 +1,16 @@
#pragma once
#include "../sdk.h"
class CEntityHandle
{
public:
union
{
uint32_t m_Index;
struct
{
uint32_t m_EntityIndex : 15;
uint32_t m_Serial : 17;
} m_Parts;
};
};

View File

@@ -0,0 +1,21 @@
#include "../sdk.h"
class IBaseInterface
{
public:
virtual ~IBaseInterface() {}
};
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.
};

View File

@@ -0,0 +1,3 @@
#pragma once
#include "../sdk.h"
class CBasePlayer;

View File

@@ -0,0 +1,24 @@
#pragma once
#include "../sdk.h"
class CPlayerSlot
{
public:
CPlayerSlot(int slot) : m_Data(slot)
{
}
int Get() const
{
return m_Data;
}
bool operator==(const CPlayerSlot& other) const {
return other.m_Data == m_Data;
}
bool operator!=(const CPlayerSlot& other) const {
return other.m_Data != m_Data;
}
private:
int m_Data;
};

View File

@@ -0,0 +1,63 @@
#pragma once
#include "../sdk.h"
struct AppSystemInfo_t
{
const char* m_pModuleName;
const char* m_pInterfaceName;
};
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_TIER4,
APP_SYSTEM_TIER_OTHER,
};
enum BuildType_t
{
kBuildTypeRelease = 2
};
class IAppSystem
{
public:
// Here's where the app systems get to learn about each other
virtual bool Connect(void* 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;
virtual void PreShutdown() = 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(void* factory, const char* pInterfaceName) = 0;
// Returns whether or not the app system is a singleton
virtual bool IsSingleton() = 0;
virtual BuildType_t GetBuildType() = 0;
};

119
csgo2/sdk/public/eiface.h Normal file
View File

@@ -0,0 +1,119 @@
#pragma once
#include "../sdk.h"
#include "IAppSystem.h"
#include "../tier1/bufferstring.h"
#include "../convar/convar.hpp"
struct vis_info_t;
class IHLTVServer;
class IHLTVDirector;
class CSteamID;
struct CEntityIndex
{
CEntityIndex(int index)
{
_index = index;
}
int Get() const
{
return _index;
}
int _index;
bool operator==(const CEntityIndex& other) const { return other._index == _index; }
bool operator!=(const CEntityIndex& other) const { return other._index != _index; }
};
//-----------------------------------------------------------------------------
// Purpose: Player / Client related functions
//-----------------------------------------------------------------------------
class ISource2GameClients : public IAppSystem
{
public:
virtual void OnClientConnected(CPlayerSlot slot, const char* pszName, uint64_t xuid, const char* pszNetworkID, const char* pszAddress, bool bFakePlayer) = 0;
// Called when the client attempts to connect (doesn't get called for bots)
// returning false would reject the connection with the pRejectReason message
virtual bool ClientConnect(CPlayerSlot slot, const char* pszName, uint64_t xuid, const char* pszNetworkID, bool unk1, CBufferString* pRejectReason);
// Client is connected and should be put in the game
// type values could be:
// 0 - player
// 1 - fake player (bot)
// 2 - unknown
virtual void ClientPutInServer(CPlayerSlot slot, char const* pszName, int type, uint64_t xuid) = 0;
// Client is going active
// If bLoadGame is true, don't spawn the player because its state is already setup.
virtual void ClientActive(CPlayerSlot slot, bool bLoadGame, const char* pszName, uint64_t xuid) = 0;
virtual void ClientFullyConnect(CPlayerSlot slot) = 0;
// Client is disconnecting from server
virtual void ClientDisconnect(CPlayerSlot slot, /* ENetworkDisconnectionReason */ int reason,
const char* pszName, uint64_t xuid, const char* pszNetworkID) = 0;
// Sets the client index for the client who typed the command into his/her console
// virtual void SetCommandClient( CPlayerSlot slot) = 0;
// The client has typed a command at the console
virtual void ClientCommand(CPlayerSlot slot, const CCommand& args) = 0;
// A player changed one/several replicated cvars (name etc)
virtual void ClientSettingsChanged(CPlayerSlot slot) = 0;
// Determine PVS origin and set PVS for the player/viewentity
virtual void ClientSetupVisibility(CPlayerSlot slot, vis_info_t* visinfo) = 0;
// A block of CUserCmds has arrived from the user, decode them and buffer for execution during player simulation
virtual float ProcessUsercmds(CPlayerSlot slot, void* buf, int numcmds, bool ignore, bool paused) = 0;
virtual bool IsPlayerSlotOccupied(CPlayerSlot slot) = 0;
virtual bool IsPlayerAlive(CPlayerSlot slot) = 0;
virtual int GetPlayerScore(CPlayerSlot slot) = 0;
// Get the ear position for a specified client
virtual void ClientEarPosition(CPlayerSlot slot, void* pEarOrigin) = 0;
// Anything this game .dll wants to add to the bug reporter text (e.g., the entity/model under the picker crosshair)
// can be added here
virtual void GetBugReportInfo(CBufferString& buf) = 0;
// TERROR: A player sent a voice packet
virtual void ClientVoice(CPlayerSlot slot) = 0;
// A user has had their network id setup and validated
virtual void NetworkIDValidated(const char* pszUserName, const char* pszNetworkID) = 0;
// The client has submitted a keyvalues command
virtual void ClientCommandKeyValues(CPlayerSlot slot, void* pKeyValues) = 0;
virtual bool ClientCanPause(CPlayerSlot slot) = 0;
virtual void HLTVClientFullyConnect(int index, const CSteamID& steamID) = 0;
virtual bool CanHLTVClientConnect(int index, const CSteamID& steamID, int* pRejectReason) = 0;
virtual void StartHLTVServer(CEntityIndex index) = 0;
virtual void SendHLTVStatusMessage(IHLTVServer*, bool, bool, const char*, int, int, int) = 0;
virtual IHLTVDirector* GetHLTVDirector(void) = 0;
virtual void unk002(CPlayerSlot slot) = 0;
virtual void unk003(CPlayerSlot slot) = 0;
// Something NetMessage related
virtual void unk004() = 0;
// Something pawn related
virtual void unk005() = 0;
virtual void unk006() = 0;
virtual void unk007() = 0;
virtual void unk008() = 0;
};
typedef ISource2GameClients IServerGameClients;

21
csgo2/sdk/sdk.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#define CORRECT_PATH_SEPARATOR '\\'
#define CORRECT_PATH_SEPARATOR_S "\\"
#define INCORRECT_PATH_SEPARATOR '/'
#define INCORRECT_PATH_SEPARATOR_S "/"
#define FMTFUNCTION( a, b )
enum EStringConvertErrorPolicy
{
_STRINGCONVERTFLAG_SKIP = 1,
_STRINGCONVERTFLAG_FAIL = 2,
_STRINGCONVERTFLAG_ASSERT = 4,
STRINGCONVERT_REPLACE = 0,
STRINGCONVERT_SKIP = _STRINGCONVERTFLAG_SKIP,
STRINGCONVERT_FAIL = _STRINGCONVERTFLAG_FAIL,
STRINGCONVERT_ASSERT_REPLACE = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_REPLACE,
STRINGCONVERT_ASSERT_SKIP = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_SKIP,
STRINGCONVERT_ASSERT_FAIL = _STRINGCONVERTFLAG_ASSERT + STRINGCONVERT_FAIL,
};
#include "../pch.h"

View File

@@ -0,0 +1,699 @@
#pragma once
#include <malloc.h>
#define UTLMEMORY_TRACK_ALLOC()
#define MEM_ALLOC_CREDIT_CLASS()
#define UTLMEMORY_TRACK_FREE()
#define assert
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;
bool IsIdxValid(I i) const;
static const I INVALID_INDEX = (I)-1; // For use with COMPILE_TIME_ASSERT
static I InvalidIndex() { return INVALID_INDEX; }
T* Base();
const T* Base() const;
void SetExternalBuffer(T* pMemory, int numElements);
void SetExternalBuffer(const T* pMemory, int numElements);
void AssumeMemory(T *pMemory, int nSize);
T* Detach();
void *DetachMemory();
void Swap(CUtlMemory< T, I > &mem);
void ConvertToGrowableMemory(int nGrowSize);
int NumAllocated() const;
int Count() const;
void Grow(int num = 1);
void EnsureCapacity(int num);
void Purge();
void Purge(int numElements);
bool IsExternallyAllocated() const;
bool IsReadOnly() const;
void SetGrowSize(int size);
protected:
void ValidateGrowSize()
{
}
enum
{
EXTERNAL_BUFFER_MARKER = -1,
EXTERNAL_CONST_BUFFER_MARKER = -2,
};
T* m_pMemory;
int m_nAllocationCount;
int m_nGrowSize;
};
//-----------------------------------------------------------------------------
// 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) {
m_pMemory = (T*)new unsigned char[m_nAllocationCount * sizeof(T)];
//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();
}
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) {
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;
}
auto oldAllocationCount = m_nAllocationCount;
// 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;
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;
if(m_pMemory) {
auto ptr = new unsigned char[m_nAllocationCount * sizeof(T)];
memcpy(ptr, m_pMemory, oldAllocationCount * sizeof(T));
m_pMemory = (T*)ptr;
} else {
m_pMemory = (T*)new unsigned char[m_nAllocationCount * sizeof(T)];
}
}
//-----------------------------------------------------------------------------
// 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;
}
m_nAllocationCount = num;
if(m_pMemory) {
m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T));
} else {
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) {
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;
}
m_nAllocationCount = numElements;
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;
}
}

View File

@@ -0,0 +1,309 @@
#include "UtlString.hpp"
#define NOMINMAX
#include <Windows.h>
#include <stdio.h>
//-----------------------------------------------------------------------------
// Base class, containing simple memory management
//-----------------------------------------------------------------------------
CUtlBinaryBlock::CUtlBinaryBlock(int growSize, int initSize) : m_Memory(growSize, initSize)
{
m_nActualLength = 0;
}
CUtlBinaryBlock::CUtlBinaryBlock(void* pMemory, int nSizeInBytes, int nInitialLength) : m_Memory((unsigned char*)pMemory, nSizeInBytes)
{
m_nActualLength = nInitialLength;
}
CUtlBinaryBlock::CUtlBinaryBlock(const void* pMemory, int nSizeInBytes) : m_Memory((const unsigned char*)pMemory, nSizeInBytes)
{
m_nActualLength = nSizeInBytes;
}
CUtlBinaryBlock::CUtlBinaryBlock(const CUtlBinaryBlock& src)
{
Set(src.Get(), src.Length());
}
void CUtlBinaryBlock::Get(void *pValue, int nLen) const
{
assert(nLen > 0);
if(m_nActualLength < nLen) {
nLen = m_nActualLength;
}
if(nLen > 0) {
memcpy(pValue, m_Memory.Base(), nLen);
}
}
void CUtlBinaryBlock::SetLength(int nLength)
{
assert(!m_Memory.IsReadOnly());
m_nActualLength = nLength;
if(nLength > m_Memory.NumAllocated()) {
int nOverFlow = nLength - m_Memory.NumAllocated();
m_Memory.Grow(nOverFlow);
// If the reallocation failed, clamp length
if(nLength > m_Memory.NumAllocated()) {
m_nActualLength = m_Memory.NumAllocated();
}
}
#ifdef _DEBUG
if(m_Memory.NumAllocated() > m_nActualLength) {
memset(((char *)m_Memory.Base()) + m_nActualLength, 0xEB, m_Memory.NumAllocated() - m_nActualLength);
}
#endif
}
void CUtlBinaryBlock::Set(const void *pValue, int nLen)
{
assert(!m_Memory.IsReadOnly());
if(!pValue) {
nLen = 0;
}
SetLength(nLen);
if(m_nActualLength) {
if(((const char *)m_Memory.Base()) >= ((const char *)pValue) + nLen ||
((const char *)m_Memory.Base()) + m_nActualLength <= ((const char *)pValue)) {
memcpy(m_Memory.Base(), pValue, m_nActualLength);
} else {
memmove(m_Memory.Base(), pValue, m_nActualLength);
}
}
}
CUtlBinaryBlock &CUtlBinaryBlock::operator=(const CUtlBinaryBlock &src)
{
assert(!m_Memory.IsReadOnly());
Set(src.Get(), src.Length());
return *this;
}
bool CUtlBinaryBlock::operator==(const CUtlBinaryBlock &src) const
{
if(src.Length() != Length())
return false;
return !memcmp(src.Get(), Get(), Length());
}
//-----------------------------------------------------------------------------
// Simple string class.
//-----------------------------------------------------------------------------
CUtlString::CUtlString()
{
}
CUtlString::CUtlString(const char *pString)
{
Set(pString);
}
CUtlString::CUtlString(const CUtlString& string)
{
Set(string.Get());
}
// Attaches the string to external memory. Useful for avoiding a copy
CUtlString::CUtlString(void* pMemory, int nSizeInBytes, int nInitialLength) : m_Storage(pMemory, nSizeInBytes, nInitialLength)
{
}
CUtlString::CUtlString(const void* pMemory, int nSizeInBytes) : m_Storage(pMemory, nSizeInBytes)
{
}
void CUtlString::Set(const char *pValue)
{
assert(!m_Storage.IsReadOnly());
int nLen = pValue ? strlen(pValue) + 1 : 0;
m_Storage.Set(pValue, nLen);
}
// Returns strlen
int CUtlString::Length() const
{
return m_Storage.Length() ? m_Storage.Length() - 1 : 0;
}
// Sets the length (used to serialize into the buffer )
void CUtlString::SetLength(int nLen)
{
assert(!m_Storage.IsReadOnly());
// Add 1 to account for the NULL
m_Storage.SetLength(nLen > 0 ? nLen + 1 : 0);
}
const char *CUtlString::Get() const
{
if(m_Storage.Length() == 0) {
return "";
}
return reinterpret_cast<const char*>(m_Storage.Get());
}
// Converts to c-strings
CUtlString::operator const char*() const
{
return Get();
}
char *CUtlString::Get()
{
assert(!m_Storage.IsReadOnly());
if(m_Storage.Length() == 0) {
// In general, we optimise away small mallocs for empty strings
// but if you ask for the non-const bytes, they must be writable
// so we can't return "" here, like we do for the const version - jd
m_Storage.SetLength(1);
m_Storage[0] = '\0';
}
return reinterpret_cast<char*>(m_Storage.Get());
}
CUtlString &CUtlString::operator=(const CUtlString &src)
{
assert(!m_Storage.IsReadOnly());
m_Storage = src.m_Storage;
return *this;
}
CUtlString &CUtlString::operator=(const char *src)
{
assert(!m_Storage.IsReadOnly());
Set(src);
return *this;
}
bool CUtlString::operator==(const CUtlString &src) const
{
return m_Storage == src.m_Storage;
}
bool CUtlString::operator==(const char *src) const
{
return (strcmp(Get(), src) == 0);
}
CUtlString &CUtlString::operator+=(const CUtlString &rhs)
{
assert(!m_Storage.IsReadOnly());
const int lhsLength(Length());
const int rhsLength(rhs.Length());
const int requestedLength(lhsLength + rhsLength);
SetLength(requestedLength);
const int allocatedLength(Length());
const int copyLength(allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength);
memcpy(Get() + lhsLength, rhs.Get(), copyLength);
m_Storage[allocatedLength] = '\0';
return *this;
}
CUtlString &CUtlString::operator+=(const char *rhs)
{
assert(!m_Storage.IsReadOnly());
const int lhsLength(Length());
const int rhsLength(strlen(rhs));
const int requestedLength(lhsLength + rhsLength);
SetLength(requestedLength);
const int allocatedLength(Length());
const int copyLength(allocatedLength - lhsLength < rhsLength ? allocatedLength - lhsLength : rhsLength);
memcpy(Get() + lhsLength, rhs, copyLength);
m_Storage[allocatedLength] = '\0';
return *this;
}
CUtlString &CUtlString::operator+=(char c)
{
assert(!m_Storage.IsReadOnly());
int nLength = Length();
SetLength(nLength + 1);
m_Storage[nLength] = c;
m_Storage[nLength + 1] = '\0';
return *this;
}
CUtlString &CUtlString::operator+=(int rhs)
{
assert(!m_Storage.IsReadOnly());
assert(sizeof(rhs) == 4);
char tmpBuf[12]; // Sufficient for a signed 32 bit integer [ -2147483648 to +2147483647 ]
snprintf(tmpBuf, sizeof(tmpBuf), "%d", rhs);
tmpBuf[sizeof(tmpBuf) - 1] = '\0';
return operator+=(tmpBuf);
}
CUtlString &CUtlString::operator+=(double rhs)
{
assert(!m_Storage.IsReadOnly());
char tmpBuf[256]; // How big can doubles be??? Dunno.
snprintf(tmpBuf, sizeof(tmpBuf), "%lg", rhs);
tmpBuf[sizeof(tmpBuf) - 1] = '\0';
return operator+=(tmpBuf);
}
int CUtlString::Format(const char *pFormat, ...)
{
assert(!m_Storage.IsReadOnly());
char tmpBuf[4096]; //< Nice big 4k buffer, as much memory as my first computer had, a Radio Shack Color Computer
va_list marker;
va_start(marker, pFormat);
int len = _vsnprintf_s(tmpBuf, 4096, sizeof(tmpBuf) - 1, pFormat, marker);
va_end(marker);
// Len < 0 represents an overflow
if(len < 0) {
len = sizeof(tmpBuf) - 1;
tmpBuf[sizeof(tmpBuf) - 1] = 0;
}
Set(tmpBuf);
return len;
}
//-----------------------------------------------------------------------------
// Strips the trailing slash
//-----------------------------------------------------------------------------
void CUtlString::StripTrailingSlash()
{
if(IsEmpty())
return;
int nLastChar = Length() - 1;
char c = m_Storage[nLastChar];
if(c == '\\' || c == '/') {
m_Storage[nLastChar] = 0;
m_Storage.SetLength(m_Storage.Length() - 1);
}
}

View File

@@ -0,0 +1,204 @@
#pragma once
#include <cstdint>
#include <cstring>
#include "UtlMemory.hpp"
class CUtlBinaryBlock
{
public:
CUtlBinaryBlock(int growSize = 0, int initSize = 0);
// 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:
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);
// Set directly and don't look for a null terminator in pValue.
void SetDirect(const char *pValue, int nChars);
// 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 uint8_t for a null-terminator.
void SetLength(int nLen);
char *Get();
void Clear();
void Purge();
// 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); }
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);
CUtlString operator+(int rhs);
int Format(const char *pFormat, ...);
// 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_t nStart = 0, int32_t nEnd = INT32_MAX);
// Grab a substring starting from the left or the right side.
CUtlString Left(int32_t nChars);
CUtlString Right(int32_t nChars);
// Replace all instances of one character with another.
CUtlString Replace(char cFrom, char cTo);
// Calls right through to V_MakeAbsolutePath.
CUtlString AbsPath(const char *pStartingDir = NULL);
// Gets the filename (everything except the path.. c:\a\b\c\somefile.txt -> somefile.txt).
CUtlString UnqualifiedFilename();
// Strips off one directory. Uses V_StripLastDir but strips the last slash also!
CUtlString DirName();
// 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 _stricmp(pString1->String(), pString2->String());
}
inline int __cdecl CUtlString::SortCaseSensitive(const CUtlString *pString1, const CUtlString *pString2)
{
return strcmp(pString1->String(), pString2->String());
}

View File

@@ -0,0 +1,766 @@
#pragma once
#include <cstring>
#include "UtlMemory.hpp"
template <class T>
inline T* CopyConstruct(T* pMemory, T const& src)
{
return ::new(pMemory) T(src);
}
template< class T, class A = CUtlMemory<T> >
class CUtlVector
{
typedef T *iterator;
typedef const T *const_iterator;
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
void CopyArray(const T *pArray, int size); //Calls SetSize and copies each element.
// 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 GetOffset(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
void Purge(); // Memory deallocation
// 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 *));
iterator begin() { return Base(); }
const_iterator begin() const { return Base(); }
iterator end() { return Base() + Count(); }
const_iterator end() const { return Base() + Count(); }
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);
public:
CAllocator m_Memory;
int m_Size;
// 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();
}
};
//-----------------------------------------------------------------------------
// 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()) {
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));
}
}
}
}
}
//-----------------------------------------------------------------------------
// 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))
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)) {
memmove(&Element(elem), &Element(elem + num), numToMove * sizeof(T));
#ifdef _DEBUG
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>::GetOffset(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 (GetOffset(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 = GetOffset(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 = GetOffset(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)];
strcpy_s(pNewStr, 1 + strlen(pString), pString);
AddToTail(pNewStr);
}
static int __cdecl SortFunc(char * const * sz1, char * const * sz2)
{
return strcmp(*sz1, *sz2);
}
};

View File

@@ -0,0 +1,272 @@
#pragma once
#include "../sdk.h"
#define DLL_CLASS_IMPORT __declspec( dllimport )
class CFormatStringElement;
class IFormatOutputStream;
template<size_t MAX_SIZE, bool AllowHeapAllocation>
class CBufferStringGrowable;
/*
Main idea of CBufferString is to provide the base class for the CBufferStringGrowable wich implements stack allocation
with the ability to convert to the heap allocation if allowed.
Example usage of CBufferStringGrowable class:
* Basic buffer allocation:
```
CBufferStringGrowable<256> buff;
buff.Insert(0, "Hello World!");
printf("Result: %s\n", buff.Get());
```
additionaly the heap allocation of the buffer could be disabled, by providing ``AllowHeapAllocation`` template argument,
by disabling heap allocation, if the buffer capacity is not enough to perform the operation, the app would exit with an Assert;
* Additional usage:
CBufferString::IsStackAllocated() - could be used to check if the buffer is stack allocated;
CBufferString::IsHeapAllocated() - could be used to check if the buffer is heap allocated;
CBufferString::Get() - would return a pointer to the data, or an empty string if it's not allocated.
* Additionaly current length of the buffer could be read via CBufferString::GetTotalNumber()
and currently allocated amount of bytes could be read via CBufferString::GetAllocatedNumber()
* Most, if not all the functions would ensure the buffer capacity and enlarge it when needed,
in case of stack allocated buffers, it would switch to heap allocation instead.
*/
class CBufferString
{
protected:
// You shouldn't be initializing this class, use CBufferStringGrowable instead.
CBufferString() {}
public:
enum EAllocationOption_t
{
UNK1 = -1,
UNK2 = 0,
UNK3 = (1 << 1),
UNK4 = (1 << 8),
UNK5 = (1 << 9),
ALLOW_HEAP_ALLOCATION = (1 << 31)
};
enum EAllocationFlags_t
{
LENGTH_MASK = (1 << 30) - 1,
FLAGS_MASK = ~LENGTH_MASK,
STACK_ALLOCATION_MARKER = (1 << 30),
HEAP_ALLOCATION_MARKER = (1 << 31)
};
public:
DLL_CLASS_IMPORT const char *AppendConcat(int, const char * const *, const int *, bool bIgnoreAlignment = false);
DLL_CLASS_IMPORT const char *AppendConcat(const char *, const char *, ...) FMTFUNCTION(3, 4);
DLL_CLASS_IMPORT const char *AppendConcatV(const char *, const char *, va_list, bool bIgnoreAlignment = false);
DLL_CLASS_IMPORT const char *Concat(const char *, const char *, ...) FMTFUNCTION(3, 4);
DLL_CLASS_IMPORT int AppendFormat(const char *pFormat, ...) FMTFUNCTION(2, 3);
DLL_CLASS_IMPORT int AppendFormatV(const char *pFormat, va_list pData);
DLL_CLASS_IMPORT const char *AppendRepeat(char cChar, int nChars, bool bIgnoreAlignment = false);
DLL_CLASS_IMPORT const char *ComposeFileName(const char *pPath, const char *pFile, char cSeparator);
DLL_CLASS_IMPORT const char *ConvertIn(unsigned int const *pData, int nSize, bool bIgnoreAlignment = false);
DLL_CLASS_IMPORT const char *ConvertIn(wchar_t const *pData, int nSize, bool bIgnoreAlignment = false);
DLL_CLASS_IMPORT const char *DefaultExtension(const char *pExt);
DLL_CLASS_IMPORT bool EndsWith(const char *pMatch) const;
DLL_CLASS_IMPORT bool EndsWith_FastCaseInsensitive(const char *pMatch) const;
// Ensures the nCapacity condition is met and grows the local buffer if needed.
// Returns pResultingBuffer pointer to the newly allocated data, as well as resulting capacity that was allocated in bytes.
DLL_CLASS_IMPORT int EnsureCapacity(int nCapacity, char **pResultingBuffer, bool bIgnoreAlignment = false, bool bForceGrow = true);
DLL_CLASS_IMPORT int EnsureAddedCapacity(int nCapacity, char **pResultingBuffer, bool bIgnoreAlignment = false, bool bForceGrow = true);
DLL_CLASS_IMPORT char *EnsureLength(int nCapacity, bool bIgnoreAlignment = false, int *pNewCapacity = NULL);
DLL_CLASS_IMPORT char *EnsureOwnedAllocation(CBufferString::EAllocationOption_t eAlloc);
DLL_CLASS_IMPORT const char *EnsureTrailingSlash(char cSeparator, bool bDontAppendIfEmpty = true);
DLL_CLASS_IMPORT const char *ExtendPath(const char *pPath, char cSeparator);
DLL_CLASS_IMPORT const char *ExtractFileBase(const char *pPath);
DLL_CLASS_IMPORT const char *ExtractFileExtension(const char *pPath);
DLL_CLASS_IMPORT const char *ExtractFilePath(const char *pPath, bool);
DLL_CLASS_IMPORT const char *ExtractFirstDir(const char *pPath);
DLL_CLASS_IMPORT const char *FixSlashes(char cSeparator = CORRECT_PATH_SEPARATOR);
DLL_CLASS_IMPORT const char *FixupPathName(char cSeparator);
DLL_CLASS_IMPORT int Format(const char *pFormat, ...) FMTFUNCTION(2, 3);
DLL_CLASS_IMPORT void FormatTo(IFormatOutputStream* pOutputStream, CFormatStringElement pElement) const;
protected:
// Returns aligned size based on capacity requested
DLL_CLASS_IMPORT static int GetAllocChars(int nSize, int nCapacity);
public:
// Inserts the nCount bytes of data from pBuf buffer at nIndex position.
// If nCount is -1, it would count the bytes of the input buffer manualy.
// Returns the resulting char buffer (Same as to what CBufferString->Get() returns).
DLL_CLASS_IMPORT const char *Insert(int nIndex, const char *pBuf, int nCount = -1, bool bIgnoreAlignment = false);
DLL_CLASS_IMPORT char *GetInsertPtr(int nIndex, int nChars, bool bIgnoreAlignment = false, int *pNewCapacity = NULL);
DLL_CLASS_IMPORT char *GetReplacePtr(int nIndex, int nOldChars, int nNewChars, bool bIgnoreAlignment = false, int *pNewCapacity = NULL);
DLL_CLASS_IMPORT int GrowByChunks(int, int);
// Wrapper around V_MakeAbsolutePath()
DLL_CLASS_IMPORT const char *MakeAbsolutePath(const char *pPath, const char *pStartingDir);
// Wrapper around V_MakeAbsolutePath() but also does separator fixup
DLL_CLASS_IMPORT const char *MakeFixedAbsolutePath(const char *pPath, const char *pStartingDir, char cSeparator = CORRECT_PATH_SEPARATOR);
// Wrapper around V_MakeRelativePath()
DLL_CLASS_IMPORT const char *MakeRelativePath(const char *pFullPath, const char *pDirectory);
DLL_CLASS_IMPORT void MoveFrom(CBufferString &pOther);
DLL_CLASS_IMPORT void Purge(int nLength);
DLL_CLASS_IMPORT char *Relinquish(CBufferString::EAllocationOption_t eAlloc);
DLL_CLASS_IMPORT const char *RemoveAt(int nIndex, int nChars);
DLL_CLASS_IMPORT const char *RemoveAtUTF8(int nByteIndex, int nCharacters);
DLL_CLASS_IMPORT const char *RemoveDotSlashes(char cSeparator);
DLL_CLASS_IMPORT int RemoveWhitespace();
DLL_CLASS_IMPORT const char *RemoveFilePath();
DLL_CLASS_IMPORT const char *RemoveFirstDir(CBufferString *pRemovedDir);
DLL_CLASS_IMPORT const char *RemoveToFileBase();
DLL_CLASS_IMPORT bool RemovePartialUTF8Tail(bool);
DLL_CLASS_IMPORT const char *RemoveTailUTF8(int nIndex);
DLL_CLASS_IMPORT int Replace(char cFrom, char cTo);
DLL_CLASS_IMPORT int Replace(const char *pMatch, const char *pReplace, bool bDontUseStrStr = false);
DLL_CLASS_IMPORT const char *ReplaceAt(int nIndex, int nOldChars, const char *pData, int nDataLen = -1, bool bIgnoreAlignment = false);
DLL_CLASS_IMPORT const char *ReplaceAt(int nIndex, const char *pData, int nDataLen = -1, bool bIgnoreAlignment = false);
DLL_CLASS_IMPORT const char *ReverseChars(int nIndex, int nChars);
// Appends the pExt to the local buffer, also appends '.' in between even if it wasn't provided in pExt.
DLL_CLASS_IMPORT const char *SetExtension(const char *pExt);
DLL_CLASS_IMPORT char *SetLength(int nLen, bool bIgnoreAlignment = false, int *pNewCapacity = NULL);
DLL_CLASS_IMPORT void SetPtr(char *pBuf, int nBufferChars, int, bool, bool);
// Frees the buffer (if it was heap allocated) and writes "~DSTRCT" to the local buffer.
DLL_CLASS_IMPORT void SetUnusable();
DLL_CLASS_IMPORT const char *ShortenPath(bool);
DLL_CLASS_IMPORT bool StartsWith(const char *pMatch) const;
DLL_CLASS_IMPORT bool StartsWith_FastCaseInsensitive(const char *pMatch) const;
DLL_CLASS_IMPORT const char *StrAppendFormat(const char *pFormat, ...) FMTFUNCTION(2, 3);
DLL_CLASS_IMPORT const char *StrFormat(const char *pFormat, ...) FMTFUNCTION(2, 3);
DLL_CLASS_IMPORT const char *StripExtension();
DLL_CLASS_IMPORT const char *StripTrailingSlash();
DLL_CLASS_IMPORT void ToLowerFast(int nStart);
DLL_CLASS_IMPORT void ToUpperFast(int nStart);
DLL_CLASS_IMPORT const char *Trim(const char *pTrimChars = "\t\r\n ");
DLL_CLASS_IMPORT const char *TrimHead(const char *pTrimChars = "\t\r\n ");
DLL_CLASS_IMPORT const char *TrimTail(const char *pTrimChars = "\t\r\n ");
DLL_CLASS_IMPORT const char *TruncateAt(int nIndex, bool bIgnoreAlignment = false);
DLL_CLASS_IMPORT const char *TruncateAt(const char *pStr, bool bIgnoreAlignment = false);
DLL_CLASS_IMPORT int UnicodeCaseConvert(int, EStringConvertErrorPolicy eErrorPolicy);
// Casts to CBufferStringGrowable. Very dirty solution until someone figures out the sane one.
template<size_t MAX_SIZE = 8, bool AllowHeapAllocation = true, typename T = CBufferStringGrowable<MAX_SIZE, AllowHeapAllocation>>
T *ToGrowable()
{
return (T *)this;
}
};
template<size_t MAX_SIZE, bool AllowHeapAllocation = true>
class CBufferStringGrowable : public CBufferString
{
friend class CBufferString;
public:
CBufferStringGrowable() : m_nAllocated(STACK_ALLOCATION_MARKER | (MAX_SIZE & LENGTH_MASK)), m_nTotalCount(0), m_Memory()
{
if (AllowHeapAllocation)
{
m_nAllocated |= ALLOW_HEAP_ALLOCATION;
}
}
~CBufferStringGrowable()
{
if (IsHeapAllocated() && m_Memory.m_pString)
{
#if PLATFORM_WINDOWS
g_pMemAlloc->Free((void*)m_Memory.m_pString);
#else
delete[] m_Memory.m_pString;
#endif
}
}
inline int GetAllocatedNumber() const
{
return m_nAllocated & LENGTH_MASK;
}
inline int GetTotalNumber() const
{
return m_nTotalCount & LENGTH_MASK;
}
inline bool IsStackAllocated() const
{
return (m_nAllocated & STACK_ALLOCATION_MARKER) != 0;
}
inline bool IsHeapAllocated() const
{
return (m_nTotalCount & HEAP_ALLOCATION_MARKER) != 0;
}
inline bool IsInputStringUnsafe(const char *pData) const
{
return ((void *)pData >= this && (void *)pData < &this[1]) ||
(GetAllocatedNumber() != 0 && pData >= Get() && pData < (Get() + GetAllocatedNumber()));
}
inline const char *Get() const
{
if (IsStackAllocated())
{
return m_Memory.m_szString;
}
else if (GetAllocatedNumber() != 0)
{
return m_Memory.m_pString;
}
return StringFuncs<char>::EmptyString();
}
private:
int m_nTotalCount;
int m_nAllocated;
union
{
const char *m_pString;
const char m_szString[MAX_SIZE];
} m_Memory;
};