initial
This commit is contained in:
28
gcsdk/gcsdk_game_include.vpc
Normal file
28
gcsdk/gcsdk_game_include.vpc
Normal file
@@ -0,0 +1,28 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// gcsdk_include.vpc
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$MacroRequired "PLATFORM"
|
||||
$MacroRequired GENERATED_PROTO_DIR
|
||||
|
||||
$include "$SRCDIR\gcsdk\steammessages_include.vpc"
|
||||
|
||||
$MacroRequired PROTOBUF_BUILDER_INCLUDED
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$AdditionalIncludeDirectories "$BASE;$SRCDIR\gcsdk\steamextra"
|
||||
}
|
||||
}
|
||||
|
||||
$Project
|
||||
{
|
||||
$Folder "Link Libraries"
|
||||
{
|
||||
$Lib gcsdk
|
||||
}
|
||||
}
|
||||
74
gcsdk/steamextra/tier1/murmurhash3.cpp
Normal file
74
gcsdk/steamextra/tier1/murmurhash3.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
//======= Copyright © Valve Corporation, All rights reserved. =================
|
||||
//
|
||||
// Public domain MurmurHash3 by Austin Appleby is a very solid general-purpose
|
||||
// hash with a 32-bit output. References:
|
||||
// http://code.google.com/p/smhasher/ (home of MurmurHash3)
|
||||
// https://sites.google.com/site/murmurhash/avalanche
|
||||
// http://www.strchr.com/hash_functions
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include <stdafx.h>
|
||||
#include "murmurhash3.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
uint32 MurmurHash3_32( const void * key, size_t len, uint32 seed, bool bCaselessStringVariant )
|
||||
{
|
||||
const uint8 * data = (const uint8*)key;
|
||||
const ptrdiff_t nblocks = len / 4;
|
||||
uint32 uSourceBitwiseAndMask = 0xDFDFDFDF | ((uint32)bCaselessStringVariant - 1);
|
||||
|
||||
uint32 h1 = seed;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint32 * blocks = (const uint32 *)(data + nblocks*4);
|
||||
|
||||
for(ptrdiff_t i = -nblocks; i; i++)
|
||||
{
|
||||
uint32 k1 = LittleDWord(blocks[i]);
|
||||
k1 &= uSourceBitwiseAndMask;
|
||||
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = (k1 << 15) | (k1 >> 17);
|
||||
k1 *= 0x1b873593;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = (h1 << 13) | (h1 >> 19);
|
||||
h1 = h1*5+0xe6546b64;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8 * tail = (const uint8*)(data + nblocks*4);
|
||||
|
||||
uint32 k1 = 0;
|
||||
|
||||
switch(len & 3)
|
||||
{
|
||||
case 3: k1 ^= tail[2] << 16;
|
||||
case 2: k1 ^= tail[1] << 8;
|
||||
case 1: k1 ^= tail[0];
|
||||
k1 &= uSourceBitwiseAndMask;
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = (k1 << 15) | (k1 >> 17);
|
||||
k1 *= 0x1b873593;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
|
||||
h1 ^= h1 >> 16;
|
||||
h1 *= 0x85ebca6b;
|
||||
h1 ^= h1 >> 13;
|
||||
h1 *= 0xc2b2ae35;
|
||||
h1 ^= h1 >> 16;
|
||||
|
||||
return h1;
|
||||
}
|
||||
100
gcsdk/steamextra/tier1/murmurhash3.h
Normal file
100
gcsdk/steamextra/tier1/murmurhash3.h
Normal file
@@ -0,0 +1,100 @@
|
||||
//======= Copyright © Valve Corporation, All rights reserved. =================
|
||||
//
|
||||
// Public domain MurmurHash3 by Austin Appleby is a very solid general-purpose
|
||||
// hash with a 32-bit output. References:
|
||||
// http://code.google.com/p/smhasher/ (home of MurmurHash3)
|
||||
// https://sites.google.com/site/murmurhash/avalanche
|
||||
// http://www.strchr.com/hash_functions
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef MURMURHASH3_H
|
||||
#define MURMURHASH3_H
|
||||
|
||||
#if defined(_WIN32)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
uint32 MurmurHash3_32( const void *key, size_t len, uint32 seed, bool bCaselessStringVariant = false );
|
||||
|
||||
inline uint32 MurmurHash3String( const char *pszKey, size_t len )
|
||||
{
|
||||
return MurmurHash3_32( pszKey, len, 1047 /*anything will do for a seed*/, false );
|
||||
}
|
||||
|
||||
inline uint32 MurmurHash3StringCaseless( const char *pszKey, size_t len )
|
||||
{
|
||||
return MurmurHash3_32( pszKey, len, 1047 /*anything will do for a seed*/, true );
|
||||
}
|
||||
|
||||
inline uint32 MurmurHash3String( const char *pszKey )
|
||||
{
|
||||
return MurmurHash3String( pszKey, strlen( pszKey ) );
|
||||
}
|
||||
|
||||
inline uint32 MurmurHash3StringCaseless( const char *pszKey )
|
||||
{
|
||||
return MurmurHash3StringCaseless( pszKey, strlen( pszKey ) );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline uint32 MurmurHash3Item( const T &item )
|
||||
{
|
||||
return MurmurHash3_32( &item, sizeof(item), 1047 );
|
||||
}
|
||||
|
||||
inline uint32 MurmurHash3Int( uint32 h )
|
||||
{
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
inline uint32 MurmurHash3Item( const uint32 &item )
|
||||
{
|
||||
return MurmurHash3Int( item );
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint32 MurmurHash3Item( const int32 &item )
|
||||
{
|
||||
return MurmurHash3Int( item );
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct MurmurHash3Functor
|
||||
{
|
||||
typedef uint32 TargetType;
|
||||
TargetType operator()(const T &key) const
|
||||
{
|
||||
return MurmurHash3Item( key );
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MurmurHash3Functor<char *>
|
||||
{
|
||||
typedef uint32 TargetType;
|
||||
TargetType operator()(const char *key) const
|
||||
{
|
||||
return MurmurHash3String( key );
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MurmurHash3Functor<const char *>
|
||||
{
|
||||
typedef uint32 TargetType;
|
||||
TargetType operator()(const char *key) const
|
||||
{
|
||||
return MurmurHash3String( key );
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MURMURHASH3_H
|
||||
234
gcsdk/steamextra/tier1/tsmempool.cpp
Normal file
234
gcsdk/steamextra/tier1/tsmempool.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
//=========== (C) Copyright 2000 Valve, L.L.C. All rights reserved. ===========
|
||||
//
|
||||
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||||
// The contents may be used and/or copied only with the written permission of
|
||||
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||||
// the agreement/contract under which the contents have been supplied.
|
||||
//
|
||||
// Purpose:
|
||||
//=============================================================================
|
||||
|
||||
|
||||
//#include "pch_vstdlib.h"
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "tier0/tslist.h"
|
||||
#include "tier0/t0constants.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static const uint k_cubBytesAllocatedToConsiderFreeingMemory = 5 * k_nMegabyte;
|
||||
static const int k_cBlocksAllocatedToConsiderFreeingMemory = 10;
|
||||
|
||||
typedef TSLNodeBase_t FreeListItem_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CThreadSafeMemoryPool::CThreadSafeMemoryPool( int blockSize, int numElements, int growMode )
|
||||
{
|
||||
m_ptslistFreeBlocks = new CTSListBase;
|
||||
|
||||
// round up to the nearest 8-byte boundary
|
||||
if ( blockSize % TSLIST_NODE_ALIGNMENT != 0 )
|
||||
{
|
||||
blockSize += TSLIST_NODE_ALIGNMENT - (blockSize % TSLIST_NODE_ALIGNMENT);
|
||||
}
|
||||
Assert( blockSize % TSLIST_NODE_ALIGNMENT == 0 );
|
||||
Assert( blockSize > sizeof(FreeListItem_t) );
|
||||
m_nGrowMode = growMode;
|
||||
m_cubBlockSize = blockSize;
|
||||
m_nGrowSize = numElements;
|
||||
m_cubAllocated = 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees the memory contained in the mempool
|
||||
//-----------------------------------------------------------------------------
|
||||
CThreadSafeMemoryPool::~CThreadSafeMemoryPool()
|
||||
{
|
||||
AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
|
||||
FOR_EACH_VEC( m_vecBlockSets, i )
|
||||
{
|
||||
_aligned_free( m_vecBlockSets[i].m_pubBlockSet );
|
||||
}
|
||||
|
||||
delete m_ptslistFreeBlocks;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees everything
|
||||
//-----------------------------------------------------------------------------
|
||||
void CThreadSafeMemoryPool::Clear()
|
||||
{
|
||||
AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
|
||||
ClearNoLock();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees everything
|
||||
//-----------------------------------------------------------------------------
|
||||
void CThreadSafeMemoryPool::ClearNoLock()
|
||||
{
|
||||
FOR_EACH_VEC( m_vecBlockSets, i )
|
||||
{
|
||||
_aligned_free( m_vecBlockSets[i].m_pubBlockSet );
|
||||
}
|
||||
m_ptslistFreeBlocks->Detach();
|
||||
m_cubAllocated = 0;
|
||||
m_cBlocksInUse = 0;
|
||||
m_vecBlockSets.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allocates a single block of memory from the pool.
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CThreadSafeMemoryPool::Alloc()
|
||||
{
|
||||
return Alloc( m_cubBlockSize );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allocates a single block of memory from the pool.
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CThreadSafeMemoryPool::Alloc( unsigned int amount )
|
||||
{
|
||||
// loop attempting to get memory
|
||||
// there appears to be a case where memory corruption can get this into an infinite loop
|
||||
// normally 1 or 2 attempts are necessary to get a block, so if we hit 1000 we know something is wrong
|
||||
int cAttempts = 1000;
|
||||
while ( --cAttempts )
|
||||
{
|
||||
// pull first from the free list
|
||||
m_threadRWLock.LockForRead();
|
||||
FreeListItem_t *pFreeListItem = m_ptslistFreeBlocks->Pop();
|
||||
if ( pFreeListItem )
|
||||
{
|
||||
m_threadRWLock.UnlockRead();
|
||||
m_cBlocksInUse++;
|
||||
return (void *)pFreeListItem;
|
||||
}
|
||||
m_threadRWLock.UnlockRead();
|
||||
|
||||
// no free items, add a new block
|
||||
|
||||
// switch from a read lock to a write lock
|
||||
AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
|
||||
|
||||
// another thread may have allocated memory; try the free list again if so
|
||||
if ( m_ptslistFreeBlocks->Count() > 0 )
|
||||
continue;
|
||||
|
||||
size_t cubBlob = m_nGrowSize * m_cubBlockSize;
|
||||
if ( m_nGrowMode == GROW_FAST )
|
||||
{
|
||||
cubBlob *= (m_vecBlockSets.Count() + 1);
|
||||
}
|
||||
|
||||
// don't grow if we're told not to
|
||||
if ( m_nGrowMode == GROW_NONE && m_vecBlockSets.Count() == 1 )
|
||||
return NULL;
|
||||
|
||||
// allocate, but we can fail
|
||||
byte *pBlobBase = (byte *)MemAlloc_AllocAligned( cubBlob, TSLIST_NODE_ALIGNMENT /*, (m_nGrowMode == GROW_TIL_YOU_CANT)*/ );
|
||||
if ( !pBlobBase )
|
||||
return NULL;
|
||||
|
||||
byte *pBlobEnd = pBlobBase + cubBlob;
|
||||
// add all the items to the pool
|
||||
for ( byte *pBlob = pBlobBase; pBlob < pBlobEnd; pBlob += m_cubBlockSize )
|
||||
{
|
||||
m_ptslistFreeBlocks->Push( (FreeListItem_t *)pBlob );
|
||||
}
|
||||
|
||||
m_cubAllocated += cubBlob;
|
||||
BlockSet_t blockSet = { pBlobBase, cubBlob };
|
||||
m_vecBlockSets.AddToTail( blockSet );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees a block of memory
|
||||
//-----------------------------------------------------------------------------
|
||||
void CThreadSafeMemoryPool::Free( void *pMem )
|
||||
{
|
||||
Free( pMem, m_cubBlockSize );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees a block of memory
|
||||
//-----------------------------------------------------------------------------
|
||||
void CThreadSafeMemoryPool::Free( void *pMem, int cubAlloc )
|
||||
{
|
||||
m_threadRWLock.LockForRead();
|
||||
|
||||
// push the item back onto the free list
|
||||
m_ptslistFreeBlocks->Push( (FreeListItem_t *)pMem );
|
||||
m_cBlocksInUse--;
|
||||
|
||||
m_threadRWLock.UnlockRead();
|
||||
|
||||
// if we're completely free, and have too much memory allocated, free some
|
||||
if ( m_cBlocksInUse == 0
|
||||
&& m_cubAllocated >= k_cubBytesAllocatedToConsiderFreeingMemory
|
||||
&& m_vecBlockSets.Count() >= k_cBlocksAllocatedToConsiderFreeingMemory )
|
||||
{
|
||||
AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
|
||||
|
||||
// check again nothing is in use
|
||||
if ( m_cBlocksInUse == 0 )
|
||||
{
|
||||
// free all the blocks
|
||||
ClearNoLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: display
|
||||
//-----------------------------------------------------------------------------
|
||||
void CThreadSafeMemoryPool::PrintStats()
|
||||
{
|
||||
AUTO_LOCK_SPIN_WRITE( m_threadRWLock );
|
||||
int cBlocksInUse = m_cBlocksInUse;
|
||||
Msg( "Block size: %-11s Alloc'd: %8d Num blobs: %5d (%s)\n", Q_pretifymem( m_cubBlockSize, 2, true ),
|
||||
cBlocksInUse, m_vecBlockSets.Count(), Q_pretifymem( m_cubAllocated, 2, true ) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: data accessor
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t CThreadSafeMemoryPool::CubTotalSize()
|
||||
{
|
||||
return m_cubAllocated;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: data accessor
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t CThreadSafeMemoryPool::CubSizeInUse()
|
||||
{
|
||||
return m_cBlocksInUse * m_cubBlockSize;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: data accessor
|
||||
//-----------------------------------------------------------------------------
|
||||
int CThreadSafeMemoryPool::Count()
|
||||
{
|
||||
return m_cBlocksInUse;
|
||||
}
|
||||
166
gcsdk/steamextra/tier1/tsmempool.h
Normal file
166
gcsdk/steamextra/tier1/tsmempool.h
Normal file
@@ -0,0 +1,166 @@
|
||||
//=========== (C) Copyright 2000 Valve, L.L.C. All rights reserved. ===========
|
||||
//
|
||||
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||||
// The contents may be used and/or copied only with the written permission of
|
||||
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||||
// the agreement/contract under which the contents have been supplied.
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef TSMEMPOOL_H
|
||||
#define TSMEMPOOL_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#undef new
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Optimized pool memory allocator
|
||||
//-----------------------------------------------------------------------------
|
||||
class CThreadSafeMemoryPool
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
GROW_NONE=0, // Don't allow new blobs.
|
||||
GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates get larger and larger each time it allocates one).
|
||||
GROW_SLOW=2, // New blob size is numElements.
|
||||
GROW_TIL_YOU_CANT=3 // GROW_SLOW til alloc fails - then STOP and dont assert!
|
||||
};
|
||||
|
||||
CThreadSafeMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST );
|
||||
~CThreadSafeMemoryPool();
|
||||
|
||||
void *Alloc(); // Allocate the element size you specified in the constructor.
|
||||
void *Alloc( unsigned int cubAlloc );
|
||||
void Free( void *pMem );
|
||||
void Free( void *pMem, int cubAlloc );
|
||||
|
||||
// Frees everything
|
||||
void Clear();
|
||||
|
||||
// display
|
||||
void PrintStats();
|
||||
size_t CubTotalSize();
|
||||
size_t CubSizeInUse();
|
||||
int Count();
|
||||
|
||||
static void * operator new( size_t size )
|
||||
{
|
||||
CThreadSafeMemoryPool *pNode = (CThreadSafeMemoryPool *)MemAlloc_AllocAlignedFileLine( size, 8, __FILE__, __LINE__
|
||||
#ifdef STEAM
|
||||
, true // new operator
|
||||
#endif
|
||||
);
|
||||
return pNode;
|
||||
}
|
||||
|
||||
static void * operator new( size_t size, int nBlockUse, const char *pFileName, int nLine )
|
||||
{
|
||||
CThreadSafeMemoryPool *pNode = (CThreadSafeMemoryPool *)MemAlloc_AllocAlignedFileLine( size, 8, pFileName, nLine
|
||||
#ifdef STEAM
|
||||
, true // new operator
|
||||
#endif
|
||||
);
|
||||
return pNode;
|
||||
}
|
||||
|
||||
static void operator delete( void *p)
|
||||
{
|
||||
MemAlloc_FreeAligned( p
|
||||
#ifdef STEAM
|
||||
, true // new operator
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
static void operator delete( void *p, int nBlockUse, const char *pFileName, int nLine )
|
||||
{
|
||||
MemAlloc_FreeAligned( p
|
||||
#ifdef STEAM
|
||||
, true // new operator
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
// These ain't gonna work
|
||||
static void * operator new[] ( size_t size );
|
||||
static void operator delete [] ( void *p);
|
||||
|
||||
// CThreadSpinRWLock needs 8 byte alignment to work but we new() CThreadSafeMemoryPool
|
||||
// so simply place it at the start of the class to make sure it fits on the 8-byte boundary
|
||||
CThreadSpinRWLock m_threadRWLock;
|
||||
|
||||
int m_nGrowMode;
|
||||
int m_cubBlockSize;
|
||||
int m_nGrowSize;
|
||||
|
||||
void ClearNoLock();
|
||||
|
||||
CInterlockedInt m_cBlocksInUse;
|
||||
size_t m_cubAllocated;
|
||||
|
||||
struct BlockSet_t
|
||||
{
|
||||
byte *m_pubBlockSet;
|
||||
size_t m_cubAllocated;
|
||||
};
|
||||
CUtlVector<BlockSet_t> m_vecBlockSets;
|
||||
|
||||
class CTSListBase *m_ptslistFreeBlocks;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Wrapper macro to make an allocator that returns particular typed allocations
|
||||
// and construction and destruction of objects.
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
class CThreadSafeClassMemoryPool : public CThreadSafeMemoryPool
|
||||
{
|
||||
public:
|
||||
CThreadSafeClassMemoryPool(int numElements, int growMode = GROW_FAST) :
|
||||
CThreadSafeMemoryPool( sizeof(T), numElements, growMode ) {}
|
||||
|
||||
T* Alloc();
|
||||
void Free( T *pMem );
|
||||
};
|
||||
|
||||
|
||||
template< class T >
|
||||
T* CThreadSafeClassMemoryPool<T>::Alloc()
|
||||
{
|
||||
T *pRet = (T*)CThreadSafeMemoryPool::Alloc();
|
||||
if ( pRet )
|
||||
{
|
||||
Construct( pRet );
|
||||
}
|
||||
return pRet;
|
||||
}
|
||||
|
||||
|
||||
template< class T >
|
||||
void CThreadSafeClassMemoryPool<T>::Free(T *pMem)
|
||||
{
|
||||
if ( pMem )
|
||||
{
|
||||
Destruct( pMem );
|
||||
}
|
||||
|
||||
CThreadSafeMemoryPool::Free( pMem );
|
||||
}
|
||||
|
||||
|
||||
#endif // TSMEMPOOL_H
|
||||
351
gcsdk/steamextra/tier1/tsmultimempool.cpp
Normal file
351
gcsdk/steamextra/tier1/tsmultimempool.cpp
Normal file
@@ -0,0 +1,351 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include <stdafx.h>
|
||||
#include "tier0/t0constants.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static const int k_cubMemBlockPrefixSize = sizeof(uint32);
|
||||
|
||||
#define ALLOCSIZE_TO_LOOKUP( cubAlloc ) ( (cubAlloc - 1) >> 5 )
|
||||
#define LOOKUP_TO_ALLOCSIZE( iLookup ) ( (iLookup << 5) + 1 )
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor, the sizes in pMemPoolConfig must be in ascending order
|
||||
//-----------------------------------------------------------------------------
|
||||
CThreadSafeMultiMemoryPool::CThreadSafeMultiMemoryPool( const MemPoolConfig_t *pMemPoolConfig, int cnMemPoolConfig, int nGrowMode /*= GROW_FAST*/ )
|
||||
{
|
||||
m_cubReallocedTotal = 0;
|
||||
m_MapRawAllocation.SetLessFunc( DefLessFunc( void * ) );
|
||||
|
||||
for ( int iMemPoolConfig = 0; iMemPoolConfig < cnMemPoolConfig; iMemPoolConfig++ )
|
||||
{
|
||||
MemPoolRecord_t memPoolRecord;
|
||||
// verify that the mem pool sizes are in ascending order
|
||||
Assert( iMemPoolConfig == 0 || ( iMemPoolConfig > 0 && pMemPoolConfig[ iMemPoolConfig - 1 ].m_cubBlockSize < pMemPoolConfig[ iMemPoolConfig].m_cubBlockSize ) );
|
||||
AssertMsg( pMemPoolConfig[ iMemPoolConfig].m_cubBlockSize % 32 == 0, "Mempools sizes must be multiples of 32" );
|
||||
// add an int to the block size so we can note the alloc size
|
||||
memPoolRecord.m_pMemPool = new CThreadSafeMemoryPool( pMemPoolConfig[ iMemPoolConfig ].m_cubBlockSize + k_cubMemBlockPrefixSize,
|
||||
pMemPoolConfig[ iMemPoolConfig ].m_cubDefaultPoolSize, nGrowMode );
|
||||
Assert( memPoolRecord.m_pMemPool );
|
||||
memPoolRecord.m_nBlockSize = pMemPoolConfig[ iMemPoolConfig ].m_cubBlockSize;
|
||||
m_VecMemPool.AddToTail( memPoolRecord );
|
||||
|
||||
// update the largest blocksize
|
||||
m_nBlockSizeMax = MAX( m_nBlockSizeMax, memPoolRecord.m_nBlockSize );
|
||||
}
|
||||
|
||||
// build the lookup table
|
||||
int nLookupMax = m_nBlockSizeMax >> 5;
|
||||
m_VecMemPoolLookup.AddMultipleToTail( nLookupMax );
|
||||
for ( int i = 0; i < nLookupMax; i++ )
|
||||
{
|
||||
uint32 cubAllocSize = LOOKUP_TO_ALLOCSIZE( i );
|
||||
for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
|
||||
{
|
||||
if ( m_VecMemPool[iMemPool].m_nBlockSize >= cubAllocSize )
|
||||
{
|
||||
m_VecMemPoolLookup[i] = &m_VecMemPool[iMemPool];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_DEBUG)
|
||||
// validate the lookup table
|
||||
for ( int i = 1; i < (int)m_nBlockSizeMax; i++ )
|
||||
{
|
||||
for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
|
||||
{
|
||||
if ( (int)m_VecMemPool[iMemPool].m_nBlockSize >= i )
|
||||
{
|
||||
AssertMsg( m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP(i)] == &m_VecMemPool[iMemPool], "Invalid mempool block size, can't generate lookup table" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CThreadSafeMultiMemoryPool::~CThreadSafeMultiMemoryPool()
|
||||
{
|
||||
AUTO_LOCK( m_mutexRawAllocations );
|
||||
|
||||
for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool ++ )
|
||||
{
|
||||
delete m_VecMemPool[iMemPool].m_pMemPool;
|
||||
}
|
||||
|
||||
FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
|
||||
{
|
||||
FreePv( m_MapRawAllocation[iRawAllocation].m_pvMem );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allocates a block of memory at of least nAllocSize bytes
|
||||
// Input : nAllocSize - number of bytes to alloc
|
||||
// Output : pointer to memory alloc'd, NULL on error
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CThreadSafeMultiMemoryPool::Alloc( uint32 cubAllocSize )
|
||||
{
|
||||
if ( cubAllocSize == 0 )
|
||||
return NULL;
|
||||
|
||||
if ( cubAllocSize <= m_nBlockSizeMax )
|
||||
{
|
||||
MemPoolRecord_t *pMemPoolRecord = m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP( cubAllocSize )];
|
||||
void *pvMem = pMemPoolRecord->m_pMemPool->Alloc( cubAllocSize + k_cubMemBlockPrefixSize );
|
||||
*(uint32 *)pvMem = cubAllocSize;
|
||||
return ( (char *)pvMem + k_cubMemBlockPrefixSize );
|
||||
}
|
||||
|
||||
|
||||
// can't fit in our mem pools, alloc it in our one off buffer
|
||||
RawAllocation_t rawAllocation;
|
||||
rawAllocation.m_nBlockSize = cubAllocSize;
|
||||
rawAllocation.m_pvMem = PvAlloc( cubAllocSize + k_cubMemBlockPrefixSize );
|
||||
if ( !rawAllocation.m_pvMem )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
*(uint32 *)rawAllocation.m_pvMem = rawAllocation.m_nBlockSize;
|
||||
AUTO_LOCK( m_mutexRawAllocations );
|
||||
m_MapRawAllocation.Insert( rawAllocation.m_pvMem, rawAllocation );
|
||||
return ( (char *)rawAllocation.m_pvMem + k_cubMemBlockPrefixSize );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Free a previously alloc'd block
|
||||
// Input : pMem - memory to free
|
||||
//-----------------------------------------------------------------------------
|
||||
void CThreadSafeMultiMemoryPool::Free( void *pvMem )
|
||||
{
|
||||
if ( !pvMem )
|
||||
return;
|
||||
|
||||
uint32 cubAllocSize = *( (uint32 *)pvMem - 1 );
|
||||
|
||||
if ( cubAllocSize <= m_nBlockSizeMax )
|
||||
{
|
||||
MemPoolRecord_t *pMemPoolRecord = m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP( cubAllocSize )];
|
||||
pMemPoolRecord->m_pMemPool->Free( (char *)pvMem - k_cubMemBlockPrefixSize, cubAllocSize + k_cubMemBlockPrefixSize );
|
||||
return;
|
||||
}
|
||||
|
||||
AUTO_LOCK( m_mutexRawAllocations );
|
||||
|
||||
// must have been alloc'd from the raw heap, find it in map
|
||||
void *pvAllocedMem = (char *)pvMem - k_cubMemBlockPrefixSize;
|
||||
int iRawAllocation = m_MapRawAllocation.Find( pvAllocedMem );
|
||||
if ( m_MapRawAllocation.InvalidIndex() == iRawAllocation )
|
||||
{
|
||||
AssertMsg3( false, "CThreadSafeMultiMemoryPool::Free: raw allocation %p (original alloc: %p, %d bytes) not found in allocation map",
|
||||
pvMem, pvAllocedMem, cubAllocSize );
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
FreePv( m_MapRawAllocation[iRawAllocation].m_pvMem );
|
||||
m_MapRawAllocation.RemoveAt( iRawAllocation);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return the size alloc'd for this block
|
||||
// Input : pMem - memory to report
|
||||
// Output : size in bytes of this memory
|
||||
//-----------------------------------------------------------------------------
|
||||
int CThreadSafeMultiMemoryPool::CubAllocSize(void *pvMem)
|
||||
{
|
||||
if ( !pvMem )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return *(((uint32 *)pvMem) -1);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees all previously alloc'd memory
|
||||
//-----------------------------------------------------------------------------
|
||||
void CThreadSafeMultiMemoryPool::Clear()
|
||||
{
|
||||
AUTO_LOCK( m_mutexRawAllocations );
|
||||
|
||||
for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
|
||||
{
|
||||
m_VecMemPool[iMemPool].m_pMemPool->Clear();
|
||||
}
|
||||
|
||||
FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
|
||||
{
|
||||
FreePv( m_MapRawAllocation[iRawAllocation].m_pvMem );
|
||||
}
|
||||
m_MapRawAllocation.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: print to the console info about our storage
|
||||
//-----------------------------------------------------------------------------
|
||||
void CThreadSafeMultiMemoryPool::PrintStats()
|
||||
{
|
||||
for ( int iMemPool= 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
|
||||
{
|
||||
m_VecMemPool[iMemPool].m_pMemPool->PrintStats();
|
||||
}
|
||||
int cubRawBytesAllocd = 0;
|
||||
AUTO_LOCK( m_mutexRawAllocations );
|
||||
FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
|
||||
{
|
||||
cubRawBytesAllocd += m_MapRawAllocation[iRawAllocation].m_nBlockSize;
|
||||
}
|
||||
Msg( "Raw bytes alloc'd: %s\n", Q_pretifymem( cubRawBytesAllocd, 2, true ) );
|
||||
Msg( "Cumulative bytes re-alloced: %s\n", Q_pretifymem( m_cubReallocedTotal, 2, true ) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: return the total mem alloced by this pool in MB
|
||||
//-----------------------------------------------------------------------------
|
||||
int CThreadSafeMultiMemoryPool::CMBPoolSize() const
|
||||
{
|
||||
uint64 cubRawBytesAllocd = 0;
|
||||
for ( int iMemPool= 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
|
||||
{
|
||||
cubRawBytesAllocd += ( m_VecMemPool[iMemPool].m_pMemPool->CubTotalSize() );
|
||||
}
|
||||
AUTO_LOCK( m_mutexRawAllocations );
|
||||
FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
|
||||
{
|
||||
cubRawBytesAllocd += m_MapRawAllocation[iRawAllocation].m_nBlockSize;
|
||||
}
|
||||
|
||||
return ( cubRawBytesAllocd / k_nMegabyte );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: return the total mem alloced by this pool in MB
|
||||
//-----------------------------------------------------------------------------
|
||||
int CThreadSafeMultiMemoryPool::CMBPoolSizeInUse() const
|
||||
{
|
||||
uint64 cubRawBytesAllocd = 0;
|
||||
for ( int iMemPool= 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
|
||||
{
|
||||
cubRawBytesAllocd += ( m_VecMemPool[iMemPool].m_pMemPool->CubSizeInUse() );
|
||||
}
|
||||
AUTO_LOCK( m_mutexRawAllocations );
|
||||
FOR_EACH_MAP_FAST( m_MapRawAllocation, iRawAllocation )
|
||||
{
|
||||
cubRawBytesAllocd += m_MapRawAllocation[iRawAllocation].m_nBlockSize;
|
||||
}
|
||||
|
||||
return ( cubRawBytesAllocd / k_nMegabyte );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: return number of mempool blocks alloc'd
|
||||
//-----------------------------------------------------------------------------
|
||||
int CThreadSafeMultiMemoryPool::Count()
|
||||
{
|
||||
int cCount = 0;
|
||||
for ( int iMemPool = 0; iMemPool < m_VecMemPool.Count(); iMemPool++ )
|
||||
{
|
||||
cCount += m_VecMemPool[iMemPool].m_pMemPool->Count();
|
||||
}
|
||||
return cCount;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: reallocate an existing block of memory to a new size (and copy the data
|
||||
// Input: pvMem - a pointer to the existing memory
|
||||
// cubAlloc - number of bytes to alloc
|
||||
// Output: returns a pointer to the memory allocated (NULL on error)
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CThreadSafeMultiMemoryPool::ReAlloc( void *pvMem, uint32 cubAlloc )
|
||||
{
|
||||
uint32 cubOldAlloc = CubAllocSize(pvMem);
|
||||
if ( pvMem && cubAlloc <= cubOldAlloc )
|
||||
return pvMem;
|
||||
|
||||
if ( cubOldAlloc > m_nBlockSizeMax )
|
||||
{
|
||||
AUTO_LOCK( m_mutexRawAllocations );
|
||||
// okay, must have been alloc'd from the raw heap, search for it
|
||||
void *pvAllocedMem = (char *)pvMem - k_cubMemBlockPrefixSize;
|
||||
int iRawAllocation = m_MapRawAllocation.Find( pvAllocedMem );
|
||||
if ( m_MapRawAllocation.InvalidIndex() == iRawAllocation )
|
||||
{
|
||||
AssertMsg3( false, "CThreadSafeMultiMemoryPool::ReAlloc: raw allocation %p (original alloc: %p, %d bytes) not found in allocation map",
|
||||
pvMem, pvAllocedMem, cubOldAlloc );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// realloc the memory
|
||||
void *pvNewMem = PvRealloc( pvAllocedMem, cubAlloc + k_cubMemBlockPrefixSize );
|
||||
if ( !pvNewMem )
|
||||
{
|
||||
m_MapRawAllocation.RemoveAt( iRawAllocation );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// update our tracking
|
||||
*(uint32 *)pvNewMem = cubAlloc;
|
||||
if ( pvAllocedMem == pvNewMem )
|
||||
{
|
||||
// if pointer is the same, use the same map entry with the same key (the pointer given to caller)
|
||||
m_MapRawAllocation[iRawAllocation].m_pvMem = pvNewMem;
|
||||
m_MapRawAllocation[iRawAllocation].m_nBlockSize = cubAlloc;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if pointer changed, need to remove the old entry and re-insert with new key
|
||||
m_MapRawAllocation.RemoveAt( iRawAllocation );
|
||||
RawAllocation_t rawAllocation;
|
||||
rawAllocation.m_pvMem = pvNewMem;
|
||||
rawAllocation.m_nBlockSize = cubAlloc;
|
||||
m_MapRawAllocation.Insert( rawAllocation.m_pvMem, rawAllocation );
|
||||
}
|
||||
return ( (char *)pvNewMem + k_cubMemBlockPrefixSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
// see if we can stay in the same block
|
||||
MemPoolRecord_t *pMemPoolRecord = m_VecMemPoolLookup[ALLOCSIZE_TO_LOOKUP( cubOldAlloc )];
|
||||
if ( cubAlloc <= pMemPoolRecord->m_nBlockSize )
|
||||
{
|
||||
// re-assign the size
|
||||
*((uint32 *)pvMem - 1) = cubAlloc;
|
||||
return pvMem;
|
||||
}
|
||||
|
||||
void *pvNewMem = Alloc( cubAlloc );
|
||||
if ( !pvNewMem )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
m_cubReallocedTotal += cubOldAlloc;
|
||||
Q_memcpy( pvNewMem, pvMem, cubOldAlloc );
|
||||
Free( pvMem ); // now free the old memory buffer we had
|
||||
return pvNewMem;
|
||||
}
|
||||
}
|
||||
|
||||
93
gcsdk/steamextra/tier1/tsmultimempool.h
Normal file
93
gcsdk/steamextra/tier1/tsmultimempool.h
Normal file
@@ -0,0 +1,93 @@
|
||||
//=========== (C) Copyright 2000 Valve, L.L.C. All rights reserved. ===========
|
||||
//
|
||||
// The copyright to the contents herein is the property of Valve, L.L.C.
|
||||
// The contents may be used and/or copied only with the written permission of
|
||||
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
|
||||
// the agreement/contract under which the contents have been supplied.
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef TSMULTIMEMPOOL_H
|
||||
#define TSMULTIMEMPOOL_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier1/utlmap.h"
|
||||
#include "tier1/mempool.h"
|
||||
#include "tier1/tsmempool.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A container of a range of mem pool sizes (for network buffers for example)
|
||||
// and a raw alloc capability (for sizes greater than any contained mem pool).
|
||||
//-----------------------------------------------------------------------------
|
||||
class CThreadSafeMultiMemoryPool
|
||||
{
|
||||
public:
|
||||
struct MemPoolConfig_t
|
||||
{
|
||||
uint32 m_cubBlockSize;
|
||||
uint32 m_cubDefaultPoolSize;
|
||||
};
|
||||
|
||||
CThreadSafeMultiMemoryPool( const MemPoolConfig_t *pnBlock, int cnMemPoolConfig, int nGrowMode = CUtlMemoryPool::GROW_FAST );
|
||||
~CThreadSafeMultiMemoryPool();
|
||||
|
||||
// Allocate a block of at least nAllocSize bytes
|
||||
void* Alloc( uint32 cubAlloc );
|
||||
// Free a previously alloc'd block
|
||||
void Free(void *pvMem);
|
||||
// ReAllocate a previously allocated block to a new size
|
||||
void* ReAlloc( void *pvMem, uint32 cubAlloc );
|
||||
|
||||
// Frees everything
|
||||
void Clear();
|
||||
|
||||
// alloc size for this bit of alloc'd memory
|
||||
int CubAllocSize( void *pvMem );
|
||||
// prints details about our contained memory
|
||||
void PrintStats();
|
||||
|
||||
// total number of alloc'd elements
|
||||
int Count();
|
||||
|
||||
// Return the total size in MB allocated for this pool
|
||||
int CMBPoolSize() const;
|
||||
// Return the amount of memory in use
|
||||
int CMBPoolSizeInUse() const;
|
||||
|
||||
private:
|
||||
struct MemPoolRecord_t
|
||||
{
|
||||
CThreadSafeMemoryPool *m_pMemPool;
|
||||
uint32 m_nBlockSize;
|
||||
};
|
||||
|
||||
CUtlVector<MemPoolRecord_t> m_VecMemPool; // stores our list of mem pools
|
||||
|
||||
uint32 m_nBlockSizeMax;
|
||||
CUtlVector<MemPoolRecord_t *> m_VecMemPoolLookup; // quick lookup table of mempools
|
||||
|
||||
struct RawAllocation_t
|
||||
{
|
||||
void *m_pvMem;
|
||||
uint32 m_nBlockSize;
|
||||
};
|
||||
CUtlMap<void *,RawAllocation_t,int> m_MapRawAllocation; // stores our list of raw alloc'd mem
|
||||
CThreadFastMutex m_mutexRawAllocations;
|
||||
|
||||
uint32 m_cubReallocedTotal;
|
||||
};
|
||||
|
||||
|
||||
#endif // TSMULTIMEMPOOL_H
|
||||
693
gcsdk/steamextra/tier1/utlhashmaplarge.h
Normal file
693
gcsdk/steamextra/tier1/utlhashmaplarge.h
Normal file
@@ -0,0 +1,693 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. =================//
|
||||
//
|
||||
// Purpose: index-based hash map container well suited for large and growing
|
||||
// datasets. It uses less memory than other hash maps and incrementally
|
||||
// rehashes to reduce reallocation spikes.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef UTLHASHMAPLARGE_H
|
||||
#define UTLHASHMAPLARGE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "bitvec.h"
|
||||
#include "murmurhash3.h"
|
||||
|
||||
// fast mod for power of 2 numbers
|
||||
namespace basetypes
|
||||
{
|
||||
template <class T>
|
||||
inline bool IsPowerOf2(T n)
|
||||
{
|
||||
return n > 0 && (n & (n-1)) == 0;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline T2 ModPowerOf2(T1 a, T2 b)
|
||||
{
|
||||
return T2(a) & (b-1);
|
||||
}
|
||||
}
|
||||
|
||||
// default comparison operator
|
||||
template <typename T>
|
||||
class CDefEquals
|
||||
{
|
||||
public:
|
||||
CDefEquals() {}
|
||||
CDefEquals( int i ) {}
|
||||
inline bool operator()( const T &lhs, const T &rhs ) const { return ( lhs == rhs ); }
|
||||
inline bool operator!() const { return false; }
|
||||
};
|
||||
|
||||
|
||||
// Specialization to compare pointers
|
||||
template <typename T>
|
||||
class CDefEquals<T*>
|
||||
{
|
||||
public:
|
||||
CDefEquals() {}
|
||||
CDefEquals( int i ) {}
|
||||
inline bool operator()( const T *lhs, const T *rhs ) const
|
||||
{
|
||||
if ( lhs == rhs )
|
||||
return true;
|
||||
else if ( NULL == lhs || NULL == rhs )
|
||||
return false;
|
||||
else
|
||||
return ( *lhs == *rhs );
|
||||
}
|
||||
inline bool operator!() const { return false; }
|
||||
};
|
||||
|
||||
|
||||
// Hash specialization for CUtlStrings
|
||||
template<>
|
||||
struct MurmurHash3Functor<CUtlString>
|
||||
{
|
||||
typedef uint32 TargetType ;
|
||||
TargetType operator()(const CUtlString &strKey) const
|
||||
{
|
||||
return MurmurHash3Functor<const char*>()( strKey.String() );
|
||||
}
|
||||
};
|
||||
|
||||
//hash 3 function for a general case sensitive string compares
|
||||
struct MurmurHash3ConstCharPtr
|
||||
{
|
||||
typedef uint32 TargetType ;
|
||||
TargetType operator()( const char* pszKey ) const { return MurmurHash3Functor<const char*>()( pszKey ); }
|
||||
};
|
||||
struct CaseSensitiveStrEquals
|
||||
{
|
||||
bool operator()( const char* pszLhs, const char* pszRhs ) const { return strcmp( pszLhs, pszRhs ) == 0; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Purpose: An associative container. Pretty much identical to CUtlMap without the ability to walk in-order
|
||||
// This container is well suited for large and growing datasets. It uses less
|
||||
// memory than other hash maps and incrementally rehashes to reduce reallocation spikes.
|
||||
// However, it is slower (by about 20%) than CUtlHashTable
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L = CDefEquals<K>, typename H = MurmurHash3Functor<K> >
|
||||
class CUtlHashMapLarge : public base_utlmap_t
|
||||
{
|
||||
public:
|
||||
// This enum exists so that FOR_EACH_MAP and FOR_EACH_MAP_FAST cannot accidentally
|
||||
// be used on a type that is not a CUtlMap. If the code compiles then all is well.
|
||||
// The check for IsUtlMap being true should be free.
|
||||
// Using an enum rather than a static const bool ensures that this trick works even
|
||||
// with optimizations disabled on gcc.
|
||||
enum CompileTimeCheck
|
||||
{
|
||||
IsUtlMap = 1
|
||||
};
|
||||
|
||||
typedef K KeyType_t;
|
||||
typedef T ElemType_t;
|
||||
typedef int IndexType_t;
|
||||
typedef L EqualityFunc_t;
|
||||
typedef H HashFunc_t;
|
||||
|
||||
CUtlHashMapLarge()
|
||||
{
|
||||
m_cElements = 0;
|
||||
m_nMaxElement = 0;
|
||||
m_nMinRehashedBucket = InvalidIndex();
|
||||
m_nMaxRehashedBucket = InvalidIndex();
|
||||
m_iNodeFreeListHead = InvalidIndex();
|
||||
}
|
||||
|
||||
CUtlHashMapLarge( int cElementsExpected )
|
||||
{
|
||||
m_cElements = 0;
|
||||
m_nMaxElement = 0;
|
||||
m_nMinRehashedBucket = InvalidIndex();
|
||||
m_nMaxRehashedBucket = InvalidIndex();
|
||||
m_iNodeFreeListHead = InvalidIndex();
|
||||
EnsureCapacity( cElementsExpected );
|
||||
}
|
||||
|
||||
~CUtlHashMapLarge()
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
// gets particular elements
|
||||
ElemType_t & Element( IndexType_t i ) { return m_memNodes.Element( i ).m_elem; }
|
||||
const ElemType_t & Element( IndexType_t i ) const { return m_memNodes.Element( i ).m_elem; }
|
||||
ElemType_t & operator[]( IndexType_t i ) { return m_memNodes.Element( i ).m_elem; }
|
||||
const ElemType_t & operator[]( IndexType_t i ) const { return m_memNodes.Element( i ).m_elem; }
|
||||
KeyType_t & Key( IndexType_t i ) { return m_memNodes.Element( i ).m_key; }
|
||||
const KeyType_t & Key( IndexType_t i ) const { return m_memNodes.Element( i ).m_key; }
|
||||
|
||||
// Num elements
|
||||
IndexType_t Count() const { return m_cElements; }
|
||||
|
||||
// Max "size" of the vector
|
||||
IndexType_t MaxElement() const { return m_nMaxElement; }
|
||||
|
||||
// Checks if a node is valid and in the map
|
||||
bool IsValidIndex( IndexType_t i ) const { return i >= 0 && i < m_nMaxElement && !IsFreeNodeID( m_memNodes[i].m_iNextNode ); }
|
||||
|
||||
// Invalid index
|
||||
static IndexType_t InvalidIndex() { return -1; }
|
||||
|
||||
// Insert method
|
||||
IndexType_t Insert( const KeyType_t &key, const ElemType_t &insert ) { return InsertInternal( key, insert, eInsert_UpdateExisting ); }
|
||||
IndexType_t Insert( const KeyType_t &key ) { return InsertInternal( key, ElemType_t(), eInsert_UpdateExisting ); }
|
||||
IndexType_t InsertWithDupes( const KeyType_t &key, const ElemType_t &insert ) { return InsertInternal( key, insert, eInsert_CreateDupes ); }
|
||||
IndexType_t FindOrInsert( const KeyType_t &key, const ElemType_t &insert ) { return InsertInternal( key, insert, eInsert_LeaveExisting ); }
|
||||
IndexType_t InsertOrReplace( const KeyType_t &key, const ElemType_t &insert ) { return InsertInternal( key, insert, eInsert_UpdateExisting ); }
|
||||
|
||||
|
||||
// Finds an element
|
||||
IndexType_t Find( const KeyType_t &key ) const;
|
||||
|
||||
// has an element
|
||||
bool HasElement( const KeyType_t &key ) const
|
||||
{
|
||||
return Find( key ) != InvalidIndex();
|
||||
}
|
||||
|
||||
void EnsureCapacity( int num );
|
||||
|
||||
void RemoveAt( IndexType_t i );
|
||||
bool Remove( const KeyType_t &key )
|
||||
{
|
||||
int iMap = Find( key );
|
||||
if ( iMap != InvalidIndex() )
|
||||
{
|
||||
RemoveAt( iMap );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void RemoveAll();
|
||||
void Purge();
|
||||
void PurgeAndDeleteElements();
|
||||
|
||||
void Swap( CUtlHashMapLarge<K,T,L,H> &rhs )
|
||||
{
|
||||
m_vecHashBuckets.Swap( rhs.m_vecHashBuckets );
|
||||
V_swap( m_bitsMigratedBuckets, rhs.m_bitsMigratedBuckets );
|
||||
m_memNodes.Swap( rhs.m_memNodes );
|
||||
V_swap( m_iNodeFreeListHead, rhs.m_iNodeFreeListHead );
|
||||
V_swap( m_cElements, rhs.m_cElements );
|
||||
V_swap( m_nMaxElement, rhs.m_nMaxElement );
|
||||
V_swap( m_nMinRehashedBucket, rhs.m_nMinRehashedBucket );
|
||||
V_swap( m_nMaxRehashedBucket, rhs.m_nMaxRehashedBucket );
|
||||
V_swap( m_EqualityFunc, rhs.m_EqualityFunc );
|
||||
V_swap( m_HashFunc, rhs.m_HashFunc );
|
||||
}
|
||||
|
||||
private:
|
||||
enum EInsertPolicy { eInsert_UpdateExisting, eInsert_LeaveExisting, eInsert_CreateDupes };
|
||||
IndexType_t InsertInternal( const KeyType_t &key, const ElemType_t &insert, EInsertPolicy ePolicy );
|
||||
|
||||
inline IndexType_t FreeNodeIDToIndex( IndexType_t i ) const { return (0-i)-3; }
|
||||
inline IndexType_t FreeNodeIndexToID( IndexType_t i ) const { return (-3)-i; }
|
||||
inline bool IsFreeNodeID( IndexType_t i ) const { return i < InvalidIndex(); }
|
||||
|
||||
int FindInBucket( int iBucket, const KeyType_t &key ) const;
|
||||
int AllocNode();
|
||||
void RehashNodesInBucket( int iBucket );
|
||||
void LinkNodeIntoBucket( int iBucket, int iNewNode );
|
||||
void UnlinkNodeFromBucket( int iBucket, int iNewNode );
|
||||
bool RemoveNodeFromBucket( int iBucket, int iNodeToRemove );
|
||||
void IncrementalRehash();
|
||||
|
||||
struct HashBucket_t
|
||||
{
|
||||
IndexType_t m_iNode;
|
||||
};
|
||||
CUtlVector<HashBucket_t> m_vecHashBuckets;
|
||||
|
||||
CLargeVarBitVec m_bitsMigratedBuckets;
|
||||
|
||||
struct Node_t
|
||||
{
|
||||
KeyType_t m_key;
|
||||
ElemType_t m_elem;
|
||||
int m_iNextNode;
|
||||
};
|
||||
CUtlMemory<Node_t> m_memNodes;
|
||||
IndexType_t m_iNodeFreeListHead;
|
||||
|
||||
IndexType_t m_cElements;
|
||||
IndexType_t m_nMaxElement;
|
||||
IndexType_t m_nMinRehashedBucket, m_nMaxRehashedBucket;
|
||||
EqualityFunc_t m_EqualityFunc;
|
||||
HashFunc_t m_HashFunc;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: inserts an item into the map
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMapLarge<K,T,L,H>::InsertInternal( const KeyType_t &key, const ElemType_t &insert, EInsertPolicy ePolicy )
|
||||
{
|
||||
// make sure we have room in the hash table
|
||||
if ( m_cElements >= m_vecHashBuckets.Count() )
|
||||
EnsureCapacity( MAX( 16, m_vecHashBuckets.Count() * 2 ) );
|
||||
if ( m_cElements >= m_memNodes.Count() )
|
||||
m_memNodes.Grow( m_memNodes.Count() * 2 );
|
||||
|
||||
// rehash incrementally
|
||||
IncrementalRehash();
|
||||
|
||||
// hash the item
|
||||
uint32 hash = m_HashFunc( key );
|
||||
|
||||
// migrate data forward, if necessary
|
||||
int cBucketsToModAgainst = m_vecHashBuckets.Count() >> 1;
|
||||
int iBucket = basetypes::ModPowerOf2(hash, cBucketsToModAgainst);
|
||||
while ( iBucket >= m_nMinRehashedBucket
|
||||
&& !m_bitsMigratedBuckets.Get( iBucket ) )
|
||||
{
|
||||
RehashNodesInBucket( iBucket );
|
||||
cBucketsToModAgainst >>= 1;
|
||||
iBucket = basetypes::ModPowerOf2(hash, cBucketsToModAgainst);
|
||||
}
|
||||
|
||||
// prevent duplicates if necessary
|
||||
if ( ( ePolicy != eInsert_CreateDupes ) && m_cElements )
|
||||
{
|
||||
// look in the bucket to see if we have a conflict
|
||||
int iBucket2 = basetypes::ModPowerOf2( hash, m_vecHashBuckets.Count() );
|
||||
IndexType_t iNode = FindInBucket( iBucket2, key );
|
||||
if ( iNode != InvalidIndex() )
|
||||
{
|
||||
// a duplicate - update in place (matching CUtlMap)
|
||||
if( ePolicy == eInsert_UpdateExisting )
|
||||
{
|
||||
m_memNodes[iNode].m_elem = insert;
|
||||
}
|
||||
return iNode;
|
||||
}
|
||||
}
|
||||
|
||||
// make an item
|
||||
int iNewNode = AllocNode();
|
||||
m_memNodes[iNewNode].m_iNextNode = InvalidIndex();
|
||||
CopyConstruct( &m_memNodes[iNewNode].m_key, key );
|
||||
CopyConstruct( &m_memNodes[iNewNode].m_elem, insert );
|
||||
|
||||
iBucket = basetypes::ModPowerOf2( hash, m_vecHashBuckets.Count() );
|
||||
|
||||
// link ourselves in
|
||||
// ::OutputDebugStr( CFmtStr( "insert %d into bucket %d\n", key, iBucket ).Access() );
|
||||
LinkNodeIntoBucket( iBucket, iNewNode );
|
||||
|
||||
// return the new node
|
||||
return iNewNode;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: grows the map to fit the specified amount
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMapLarge<K,T,L,H>::EnsureCapacity( int amount )
|
||||
{
|
||||
m_memNodes.EnsureCapacity( amount );
|
||||
// ::OutputDebugStr( CFmtStr( "grown m_memNodes from %d to %d\n", m_cElements, m_memNodes.Count() ).Access() );
|
||||
|
||||
if ( amount <= m_vecHashBuckets.Count() )
|
||||
return;
|
||||
int cBucketsNeeded = MAX( 16, m_vecHashBuckets.Count() );
|
||||
while ( cBucketsNeeded < amount )
|
||||
cBucketsNeeded *= 2;
|
||||
|
||||
// ::OutputDebugStr( CFmtStr( "grown m_vecHashBuckets from %d to %d\n", m_vecHashBuckets.Count(), cBucketsNeeded ).Access() );
|
||||
|
||||
// grow the hash buckets
|
||||
int grow = cBucketsNeeded - m_vecHashBuckets.Count();
|
||||
int iFirst = m_vecHashBuckets.AddMultipleToTail( grow );
|
||||
// clear all the new data to invalid bits
|
||||
memset( &m_vecHashBuckets[iFirst], 0xFFFFFFFF, grow*sizeof(m_vecHashBuckets[iFirst]) );
|
||||
Assert( basetypes::IsPowerOf2( m_vecHashBuckets.Count() ) );
|
||||
|
||||
// we'll have to rehash, all the buckets that existed before growth
|
||||
m_nMinRehashedBucket = 0;
|
||||
m_nMaxRehashedBucket = iFirst;
|
||||
if ( m_cElements > 0 )
|
||||
{
|
||||
// remove all the current bits
|
||||
m_bitsMigratedBuckets.Resize( 0 );
|
||||
// re-add new bits; these will all be reset to 0
|
||||
m_bitsMigratedBuckets.Resize( m_vecHashBuckets.Count() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// no elements - no rehashing
|
||||
m_nMinRehashedBucket = m_vecHashBuckets.Count();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets a new node, from the free list if possible
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMapLarge<K,T,L,H>::AllocNode()
|
||||
{
|
||||
// if we're out of free elements, get the max
|
||||
if ( m_cElements == m_nMaxElement )
|
||||
{
|
||||
m_cElements++;
|
||||
return m_nMaxElement++;
|
||||
}
|
||||
|
||||
// pull from the free list
|
||||
Assert( m_iNodeFreeListHead != InvalidIndex() );
|
||||
int iNewNode = m_iNodeFreeListHead;
|
||||
m_iNodeFreeListHead = FreeNodeIDToIndex( m_memNodes[iNewNode].m_iNextNode );
|
||||
m_cElements++;
|
||||
return iNewNode;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: takes a bucket of nodes and re-hashes them into a more optimal bucket
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMapLarge<K,T,L,H>::RehashNodesInBucket( int iBucketSrc )
|
||||
{
|
||||
// mark us as migrated
|
||||
m_bitsMigratedBuckets.Set( iBucketSrc );
|
||||
|
||||
// walk the list of items, re-hashing them
|
||||
IndexType_t iNode = m_vecHashBuckets[iBucketSrc].m_iNode;
|
||||
while ( iNode != InvalidIndex() )
|
||||
{
|
||||
IndexType_t iNodeNext = m_memNodes[iNode].m_iNextNode;
|
||||
Assert( iNodeNext != iNode );
|
||||
|
||||
// work out where the node should go
|
||||
const KeyType_t &key = m_memNodes[iNode].m_key;
|
||||
uint32 hash = m_HashFunc( key );
|
||||
int iBucketDest = basetypes::ModPowerOf2( hash, m_vecHashBuckets.Count() );
|
||||
|
||||
// if the hash bucket has changed, move it
|
||||
if ( iBucketDest != iBucketSrc )
|
||||
{
|
||||
// ::OutputDebugStr( CFmtStr( "moved key %d from bucket %d to %d\n", key, iBucketSrc, iBucketDest ).Access() );
|
||||
|
||||
// remove from this bucket list
|
||||
UnlinkNodeFromBucket( iBucketSrc, iNode );
|
||||
|
||||
// link into new bucket list
|
||||
LinkNodeIntoBucket( iBucketDest, iNode );
|
||||
}
|
||||
iNode = iNodeNext;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: searches for an item by key, returning the index handle
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMapLarge<K,T,L,H>::Find( const KeyType_t &key ) const
|
||||
{
|
||||
if ( m_cElements == 0 )
|
||||
return InvalidIndex();
|
||||
|
||||
// hash the item
|
||||
uint32 hash = m_HashFunc( key );
|
||||
|
||||
// find the bucket
|
||||
int cBucketsToModAgainst = m_vecHashBuckets.Count();
|
||||
int iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
|
||||
|
||||
// look in the bucket for the item
|
||||
int iNode = FindInBucket( iBucket, key );
|
||||
if ( iNode != InvalidIndex() )
|
||||
return iNode;
|
||||
|
||||
// not found? we may have to look in older buckets
|
||||
cBucketsToModAgainst >>= 1;
|
||||
while ( cBucketsToModAgainst >= m_nMinRehashedBucket )
|
||||
{
|
||||
iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
|
||||
|
||||
if ( !m_bitsMigratedBuckets.Get( iBucket ) )
|
||||
{
|
||||
int iNode2 = FindInBucket( iBucket, key );
|
||||
if ( iNode2 != InvalidIndex() )
|
||||
return iNode2;
|
||||
}
|
||||
|
||||
cBucketsToModAgainst >>= 1;
|
||||
}
|
||||
|
||||
return InvalidIndex();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: searches for an item by key, returning the index handle
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline int CUtlHashMapLarge<K,T,L,H>::FindInBucket( int iBucket, const KeyType_t &key ) const
|
||||
{
|
||||
if ( m_vecHashBuckets[iBucket].m_iNode != InvalidIndex() )
|
||||
{
|
||||
IndexType_t iNode = m_vecHashBuckets[iBucket].m_iNode;
|
||||
Assert( iNode < m_nMaxElement );
|
||||
while ( iNode != InvalidIndex() )
|
||||
{
|
||||
// equality check
|
||||
if ( m_EqualityFunc( key, m_memNodes[iNode].m_key ) )
|
||||
return iNode;
|
||||
|
||||
iNode = m_memNodes[iNode].m_iNextNode;
|
||||
}
|
||||
}
|
||||
|
||||
return InvalidIndex();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: links a node into a bucket
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
void CUtlHashMapLarge<K,T,L,H>::LinkNodeIntoBucket( int iBucket, int iNewNode )
|
||||
{
|
||||
// add into the start of the bucket's list
|
||||
m_memNodes[iNewNode].m_iNextNode = m_vecHashBuckets[iBucket].m_iNode;
|
||||
m_vecHashBuckets[iBucket].m_iNode = iNewNode;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: unlinks a node from the bucket
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
void CUtlHashMapLarge<K,T,L,H>::UnlinkNodeFromBucket( int iBucket, int iNodeToUnlink )
|
||||
{
|
||||
int iNodeNext = m_memNodes[iNodeToUnlink].m_iNextNode;
|
||||
|
||||
// if it's the first node, just update the bucket to point to the new place
|
||||
int iNode = m_vecHashBuckets[iBucket].m_iNode;
|
||||
if ( iNode == iNodeToUnlink )
|
||||
{
|
||||
m_vecHashBuckets[iBucket].m_iNode = iNodeNext;
|
||||
return;
|
||||
}
|
||||
|
||||
// walk the list to find where
|
||||
while ( iNode != InvalidIndex() )
|
||||
{
|
||||
if ( m_memNodes[iNode].m_iNextNode == iNodeToUnlink )
|
||||
{
|
||||
m_memNodes[iNode].m_iNextNode = iNodeNext;
|
||||
return;
|
||||
}
|
||||
iNode = m_memNodes[iNode].m_iNextNode;
|
||||
}
|
||||
|
||||
// should always be valid to unlink
|
||||
Assert( false );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: removes a single item from the map
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMapLarge<K,T,L,H>::RemoveAt( IndexType_t i )
|
||||
{
|
||||
if ( !IsValidIndex( i ) )
|
||||
{
|
||||
Assert( false );
|
||||
return;
|
||||
}
|
||||
|
||||
// unfortunately, we have to re-hash to find which bucket we're in
|
||||
uint32 hash = m_HashFunc( m_memNodes[i].m_key );
|
||||
int cBucketsToModAgainst = m_vecHashBuckets.Count();
|
||||
int iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
|
||||
if ( RemoveNodeFromBucket( iBucket, i ) )
|
||||
return;
|
||||
|
||||
// wasn't found; look in older buckets
|
||||
cBucketsToModAgainst >>= 1;
|
||||
while ( cBucketsToModAgainst >= m_nMinRehashedBucket )
|
||||
{
|
||||
iBucket = basetypes::ModPowerOf2( hash, cBucketsToModAgainst );
|
||||
|
||||
if ( !m_bitsMigratedBuckets.Get( iBucket ) )
|
||||
{
|
||||
if ( RemoveNodeFromBucket( iBucket, i ) )
|
||||
return;
|
||||
}
|
||||
|
||||
cBucketsToModAgainst >>= 1;
|
||||
}
|
||||
|
||||
// never found, container is busted
|
||||
Assert( false );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: removes a node from the bucket, return true if it was found
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline bool CUtlHashMapLarge<K,T,L,H>::RemoveNodeFromBucket( IndexType_t iBucket, int iNodeToRemove )
|
||||
{
|
||||
IndexType_t iNode = m_vecHashBuckets[iBucket].m_iNode;
|
||||
while ( iNode != InvalidIndex() )
|
||||
{
|
||||
if ( iNodeToRemove == iNode )
|
||||
{
|
||||
// found it, remove
|
||||
UnlinkNodeFromBucket( iBucket, iNodeToRemove );
|
||||
Destruct( &m_memNodes[iNode].m_key );
|
||||
Destruct( &m_memNodes[iNode].m_elem );
|
||||
|
||||
// link into free list
|
||||
m_memNodes[iNode].m_iNextNode = FreeNodeIndexToID( m_iNodeFreeListHead );
|
||||
m_iNodeFreeListHead = iNode;
|
||||
m_cElements--;
|
||||
if ( m_cElements == 0 )
|
||||
{
|
||||
m_nMinRehashedBucket = m_vecHashBuckets.Count();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
iNode = m_memNodes[iNode].m_iNextNode;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: removes all items from the hash map
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMapLarge<K,T,L,H>::RemoveAll()
|
||||
{
|
||||
FOR_EACH_MAP_FAST( *this, i )
|
||||
{
|
||||
Destruct( &m_memNodes[i].m_key );
|
||||
Destruct( &m_memNodes[i].m_elem );
|
||||
}
|
||||
|
||||
m_cElements = 0;
|
||||
m_nMaxElement = 0;
|
||||
m_iNodeFreeListHead = InvalidIndex();
|
||||
m_nMinRehashedBucket = m_vecHashBuckets.Count();
|
||||
m_nMaxRehashedBucket = InvalidIndex();
|
||||
m_bitsMigratedBuckets.Resize( 0 );
|
||||
memset( m_vecHashBuckets.Base(), 0xFF, m_vecHashBuckets.Count() * sizeof(HashBucket_t) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: removes all items from the hash map and releases memory
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMapLarge<K,T,L,H>::Purge()
|
||||
{
|
||||
FOR_EACH_MAP_FAST( *this, i )
|
||||
{
|
||||
Destruct( &m_memNodes[i].m_key );
|
||||
Destruct( &m_memNodes[i].m_elem );
|
||||
}
|
||||
|
||||
m_cElements = 0;
|
||||
m_nMaxElement = 0;
|
||||
m_iNodeFreeListHead = InvalidIndex();
|
||||
m_nMinRehashedBucket = InvalidIndex();
|
||||
m_nMaxRehashedBucket = InvalidIndex();
|
||||
|
||||
m_bitsMigratedBuckets.Resize( 0 );
|
||||
m_memNodes.Purge();
|
||||
m_vecHashBuckets.Purge();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: removes and deletes all items from the hash map and releases memory
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMapLarge<K,T,L,H>::PurgeAndDeleteElements()
|
||||
{
|
||||
FOR_EACH_MAP_FAST( *this, i )
|
||||
{
|
||||
delete this->Element( i );
|
||||
}
|
||||
|
||||
Purge();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: rehashes buckets
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename K, typename T, typename L, typename H>
|
||||
inline void CUtlHashMapLarge<K,T,L,H>::IncrementalRehash()
|
||||
{
|
||||
if ( m_nMinRehashedBucket < m_nMaxRehashedBucket )
|
||||
{
|
||||
while ( m_nMinRehashedBucket < m_nMaxRehashedBucket )
|
||||
{
|
||||
// see if the bucket needs rehashing
|
||||
if ( m_vecHashBuckets[m_nMinRehashedBucket].m_iNode != InvalidIndex()
|
||||
&& !m_bitsMigratedBuckets.Get(m_nMinRehashedBucket) )
|
||||
{
|
||||
// rehash this bucket
|
||||
RehashNodesInBucket( m_nMinRehashedBucket );
|
||||
// only actively do one - don't want to do it too fast since we may be on a rapid growth path
|
||||
++m_nMinRehashedBucket;
|
||||
break;
|
||||
}
|
||||
|
||||
// nothing to rehash in that bucket - increment and look again
|
||||
++m_nMinRehashedBucket;
|
||||
}
|
||||
|
||||
if ( m_nMinRehashedBucket >= m_nMaxRehashedBucket )
|
||||
{
|
||||
// we're done; don't need any bits anymore
|
||||
m_nMinRehashedBucket = m_vecHashBuckets.Count();
|
||||
m_nMaxRehashedBucket = InvalidIndex();
|
||||
m_bitsMigratedBuckets.Resize( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // UTLHASHMAPLARGE_H
|
||||
14
gcsdk/steamextra/tier1/utlstringbuilder.cpp
Normal file
14
gcsdk/steamextra/tier1/utlstringbuilder.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. =================//
|
||||
//
|
||||
// Purpose: Larger string builder functions go here.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include <stdafx.h>
|
||||
#include "tier0/t0constants.h"
|
||||
#include "utlstringbuilder.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
44
gcsdk/steamextra/tier1/utlstringbuilder.h
Normal file
44
gcsdk/steamextra/tier1/utlstringbuilder.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//====== Copyright © Valve Corporation, All rights reserved. ==================
|
||||
//
|
||||
// Purpose: String class thats more suited to frequent modification/appends
|
||||
// than CUtlString. Copied from Steam's tier1 utlstring.h instead of
|
||||
// a full utlstring.h merge because the files differed nearly 100%.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef UTLSTRINGBUILDER_H
|
||||
#define UTLSTRINGBUILDER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier1/utlmemory.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier1/utlstring.h"
|
||||
#if 0
|
||||
#include "limits.h"
|
||||
#include "tier1/utlbinaryblock.h"
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Data and memory validation
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
inline void CUtlStringBuilder::Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
validator.Push( typeid(*this).raw_name(), this, pchName );
|
||||
#else
|
||||
validator.Push( typeid(*this).name(), this, pchName );
|
||||
#endif
|
||||
|
||||
if ( m_data.IsHeap() )
|
||||
validator.ClaimMemory( Access() );
|
||||
|
||||
validator.Pop();
|
||||
}
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
|
||||
|
||||
#endif // UTLSTRINGBUILDER_H
|
||||
799
gcsdk/steammessages.proto
Normal file
799
gcsdk/steammessages.proto
Normal file
@@ -0,0 +1,799 @@
|
||||
//====== Copyright 1996-2010, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: The file defines our Google Protocol Buffers which are used in over
|
||||
// the wire messages between servers as well as between clients and servers.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
// We care more about speed than code size
|
||||
option optimize_for = SPEED;
|
||||
|
||||
// We don't use the service generation functionality
|
||||
option cc_generic_services = false;
|
||||
|
||||
|
||||
//
|
||||
// STYLE NOTES:
|
||||
//
|
||||
// Use CamelCase CMsgMyMessageName style names for messages.
|
||||
//
|
||||
// Use lowercase _ delimited names like my_steam_id for field names, this is non-standard for Steam,
|
||||
// but plays nice with the Google formatted code generation.
|
||||
//
|
||||
// Try not to use required fields ever. Only do so if you are really really sure you'll never want them removed.
|
||||
// Optional should be preffered as it will make versioning easier and cleaner in the future if someone refactors
|
||||
// your message and wants to remove or rename fields.
|
||||
//
|
||||
// Use fixed64 for JobId_t, GID_t, or SteamID. This is appropriate for any field that is normally
|
||||
// going to be larger than 2^56. Otherwise use int64 for 64 bit values that are frequently smaller
|
||||
// than 2^56 as it will safe space on the wire in those cases.
|
||||
//
|
||||
// Similar to fixed64, use fixed32 for RTime32 or other 32 bit values that are frequently larger than
|
||||
// 2^28. It will safe space in those cases, otherwise use int32 which will safe space for smaller values.
|
||||
// An exception to this rule for RTime32 is if the value will frequently be zero rather than set to an actual
|
||||
// time.
|
||||
//
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
extend google.protobuf.FieldOptions {
|
||||
optional bool key_field = 60000 [ default = false ];
|
||||
}
|
||||
|
||||
|
||||
extend google.protobuf.MessageOptions{
|
||||
// Allows us to customize the pooling for different messages
|
||||
optional int32 msgpool_soft_limit = 60000 [default=32];
|
||||
optional int32 msgpool_hard_limit = 60001 [default=384];
|
||||
}
|
||||
|
||||
enum GCProtoBufMsgSrc
|
||||
{
|
||||
GCProtoBufMsgSrc_Unspecified = 0;
|
||||
GCProtoBufMsgSrc_FromSystem = 1;
|
||||
GCProtoBufMsgSrc_FromSteamID = 2;
|
||||
GCProtoBufMsgSrc_FromGC = 3;
|
||||
GCProtoBufMsgSrc_ReplySystem = 4;
|
||||
};
|
||||
|
||||
//
|
||||
// Message header, every protcol buffer based message starts with this.
|
||||
//
|
||||
message CMsgProtoBufHeader
|
||||
{
|
||||
option (msgpool_soft_limit) = 256;
|
||||
option (msgpool_hard_limit) = 1024;
|
||||
|
||||
// All fields here are optional.
|
||||
|
||||
// Client message header fields
|
||||
optional fixed64 client_steam_id = 1; // SteamID of the client sending this, typically set in all client originated messages.
|
||||
optional int32 client_session_id = 2; // SessionID of the client on the CM
|
||||
|
||||
// Source appId for inter-gc messages
|
||||
optional uint32 source_app_id = 3; // appId of source GC message sender
|
||||
|
||||
// Job routing (may be set on client or inter-server messages)
|
||||
optional fixed64 job_id_source = 10 [ default = 0xFFFFFFFFFFFFFFFF ]; // JobID that sent this message
|
||||
optional fixed64 job_id_target = 11 [ default = 0xFFFFFFFFFFFFFFFF ]; // The target job which is expected to be waiting on this message
|
||||
optional string target_job_name = 12; // the type of job to start when this message is received
|
||||
|
||||
optional int32 eresult = 13 [default = 2]; // For response jobs, the corresponding eresult
|
||||
optional string error_message = 14; // Optionally an error message in case of failure. Mostly used for debugging purpose.
|
||||
|
||||
// Where did this message originally enter the system? From a client, from another GC, etc
|
||||
optional GCProtoBufMsgSrc gc_msg_src = 200;
|
||||
// If this came from another GC, what is the GC that it came from
|
||||
optional uint32 gc_dir_index_source = 201;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Used to serialize CWebAPIKey objects.
|
||||
//
|
||||
message CMsgWebAPIKey
|
||||
{
|
||||
optional uint32 status = 1 [ default = 0xFF ];
|
||||
optional uint32 account_id = 2 [ default = 0 ];
|
||||
optional uint32 publisher_group_id = 3 [ default = 0 ];
|
||||
optional uint32 key_id = 4;
|
||||
optional string domain = 5;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// An HTTP request message
|
||||
//
|
||||
message CMsgHttpRequest
|
||||
{
|
||||
message RequestHeader
|
||||
{
|
||||
optional string name = 1;
|
||||
optional string value = 2;
|
||||
}
|
||||
|
||||
message QueryParam
|
||||
{
|
||||
optional string name = 1;
|
||||
optional bytes value = 2;
|
||||
}
|
||||
|
||||
optional uint32 request_method = 1;
|
||||
optional string hostname = 2;
|
||||
optional string url = 3;
|
||||
repeated RequestHeader headers = 4;
|
||||
repeated QueryParam get_params = 5;
|
||||
repeated QueryParam post_params = 6;
|
||||
optional bytes body = 7;
|
||||
optional uint32 absolute_timeout = 8;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// A web API request
|
||||
//
|
||||
message CMsgWebAPIRequest
|
||||
{
|
||||
optional string UNUSED_job_name = 1; // no longer used
|
||||
optional string interface_name = 2;
|
||||
optional string method_name = 3;
|
||||
optional uint32 version = 4;
|
||||
optional CMsgWebAPIKey api_key = 5;
|
||||
optional CMsgHttpRequest request = 6;
|
||||
optional uint32 routing_app_id = 7;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// An HTTP response
|
||||
//
|
||||
message CMsgHttpResponse
|
||||
{
|
||||
message ResponseHeader
|
||||
{
|
||||
optional string name = 1;
|
||||
optional string value = 2;
|
||||
}
|
||||
|
||||
optional uint32 status_code = 1;
|
||||
repeated ResponseHeader headers = 2;
|
||||
optional bytes body = 3;
|
||||
}
|
||||
|
||||
//
|
||||
// Message struct for k_EMsgAMFindAccounts
|
||||
//
|
||||
message CMsgAMFindAccounts
|
||||
{
|
||||
optional uint32 search_type = 1;
|
||||
optional string search_string = 2;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Message struct for k_EMsgAMFindAccountsResponse
|
||||
//
|
||||
message CMsgAMFindAccountsResponse
|
||||
{
|
||||
repeated fixed64 steam_id = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EMsgNotifyWatchdog
|
||||
//
|
||||
message CMsgNotifyWatchdog
|
||||
{
|
||||
optional uint32 source = 1; // Alert source
|
||||
optional uint32 alert_type = 2; // type of alert
|
||||
optional uint32 alert_destination = 3; // destination for alert
|
||||
optional bool critical = 4; // Is the alert critical
|
||||
optional uint32 time = 5; // world time that alert occurred
|
||||
optional uint32 appid = 6; // app to forward the alert to for alerts with alert_type set to AppID
|
||||
optional string text = 7; // Alert text
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgGetLicenses
|
||||
//
|
||||
message CMsgAMGetLicenses
|
||||
{
|
||||
optional fixed64 steamid = 1; // the steam ID to fetch licenses for
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Used by CMsgAMGetLicensesResponse
|
||||
//
|
||||
message CMsgPackageLicense
|
||||
{
|
||||
optional uint32 package_id = 1; // ID of the package this license is for
|
||||
optional uint32 time_created = 2; // RTime32 when the license was granted
|
||||
optional uint32 owner_id = 3; // the original owner if this license. if this is different from given steamid, it's a borrowed package
|
||||
}
|
||||
|
||||
//
|
||||
// k_EMsgAMGetLicensesResponse
|
||||
//
|
||||
message CMsgAMGetLicensesResponse
|
||||
{
|
||||
repeated CMsgPackageLicense license = 1; // the list of licenses the user owns
|
||||
optional uint32 result = 2; // result code, k_EResultOK on success
|
||||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// k_EMsgAMGetUserGameStats
|
||||
//
|
||||
message CMsgAMGetUserGameStats
|
||||
{
|
||||
optional fixed64 steam_id = 1; // ID of user
|
||||
optional fixed64 game_id = 2; // Game ID of stats to get
|
||||
repeated uint32 stats = 3;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// k_EMsgAMGetUserGameStatsResponse
|
||||
//
|
||||
message CMsgAMGetUserGameStatsResponse
|
||||
{
|
||||
optional fixed64 steam_id = 1; // ID of user
|
||||
optional fixed64 game_id = 2; // Game ID
|
||||
optional int32 eresult = 3 [default = 2]; // EResult with result of query. (Fields following are only valid if this is EResultOK.)
|
||||
|
||||
message Stats
|
||||
{
|
||||
optional uint32 stat_id = 1;
|
||||
optional uint32 stat_value = 2; // There are 4 of these, really only 8 bits each. Yay for compression!
|
||||
}
|
||||
|
||||
message Achievement_Blocks
|
||||
{
|
||||
optional uint32 achievement_id = 1;
|
||||
optional uint32 achievement_bit_id = 2;
|
||||
optional fixed32 unlock_time = 3; // There are only 32 of these, matching the achievment bitfields, we check on the receiver that
|
||||
}
|
||||
|
||||
repeated Stats stats = 4;
|
||||
|
||||
repeated Achievement_Blocks achievement_blocks = 5;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// k_EMsgAdminGCGetCommandList
|
||||
message CMsgGCGetCommandList
|
||||
{
|
||||
optional uint32 app_id = 1;
|
||||
optional string command_prefix = 2; // prefix of the command to filter by
|
||||
};
|
||||
|
||||
// k_EMsgAdminGCGetCommandListResponse
|
||||
message CMsgGCGetCommandListResponse
|
||||
{
|
||||
repeated string command_name = 1; // a list of command names
|
||||
};
|
||||
|
||||
//
|
||||
// k_EGCMsgMemCachedGet
|
||||
//
|
||||
message CGCMsgMemCachedGet
|
||||
{
|
||||
repeated string keys = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgMemCachedGetResponse
|
||||
//
|
||||
message CGCMsgMemCachedGetResponse
|
||||
{
|
||||
message ValueTag
|
||||
{
|
||||
optional bool found = 1;
|
||||
optional bytes value = 2;
|
||||
}
|
||||
|
||||
repeated ValueTag values = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgMemCachedSet
|
||||
//
|
||||
message CGCMsgMemCachedSet
|
||||
{
|
||||
message KeyPair
|
||||
{
|
||||
optional string name = 1;
|
||||
optional bytes value = 2;
|
||||
}
|
||||
|
||||
repeated KeyPair keys = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgMemCachedDelete
|
||||
//
|
||||
message CGCMsgMemCachedDelete
|
||||
{
|
||||
repeated string keys = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgMemCachedStats
|
||||
//
|
||||
message CGCMsgMemCachedStats
|
||||
{
|
||||
// Nothing, yet.
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgMemCachedStatsResponse
|
||||
//
|
||||
message CGCMsgMemCachedStatsResponse
|
||||
{
|
||||
optional uint64 curr_connections = 1;
|
||||
optional uint64 cmd_get = 2;
|
||||
optional uint64 cmd_set = 3;
|
||||
optional uint64 cmd_flush = 4;
|
||||
optional uint64 get_hits = 5;
|
||||
optional uint64 get_misses = 6;
|
||||
optional uint64 delete_hits = 7;
|
||||
optional uint64 delete_misses = 8;
|
||||
optional uint64 bytes_read = 9;
|
||||
optional uint64 bytes_written = 10;
|
||||
optional uint64 limit_maxbytes = 11;
|
||||
optional uint64 curr_items = 12;
|
||||
optional uint64 evictions = 13;
|
||||
optional uint64 bytes = 14;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgSQLStats
|
||||
//
|
||||
message CGCMsgSQLStats
|
||||
{
|
||||
optional uint32 schema_catalog = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgSQLStatsResponse
|
||||
//
|
||||
message CGCMsgSQLStatsResponse
|
||||
{
|
||||
optional uint32 threads = 1;
|
||||
optional uint32 threads_connected = 2;
|
||||
optional uint32 threads_active = 3;
|
||||
optional uint32 operations_submitted = 4;
|
||||
optional uint32 prepared_statements_executed = 5;
|
||||
optional uint32 non_prepared_statements_executed = 6;
|
||||
optional uint32 deadlock_retries = 7;
|
||||
optional uint32 operations_timed_out_in_queue = 8;
|
||||
optional uint32 errors = 9;
|
||||
}
|
||||
|
||||
// k_EMsgAMAddFreeLicense
|
||||
message CMsgAMAddFreeLicense
|
||||
{
|
||||
optional fixed64 steamid = 1; // SteamID of account
|
||||
optional uint32 ip_public = 2; // IP of client (zero if not a client-initiated message)
|
||||
optional uint32 packageid = 3; // ID for package to purchase. Should be k_uPackageIdInvalid if shopping cart gid set
|
||||
optional string store_country_code = 4; // country code to use for purchase
|
||||
};
|
||||
|
||||
// k_EMsgAMAddFreeLicenseResponse
|
||||
message CMsgAMAddFreeLicenseResponse
|
||||
{
|
||||
optional int32 eresult = 1 [default = 2]; // EResult with result of Purchase.
|
||||
optional int32 purchase_result_detail = 2; // Detailed result information
|
||||
optional fixed64 transid = 3; // ID of the created transaction
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// k_EGCMsgGetIPLocation
|
||||
//
|
||||
message CGCMsgGetIPLocation
|
||||
{
|
||||
repeated fixed32 ips = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgGetIPLocationResponse
|
||||
//
|
||||
message CIPLocationInfo
|
||||
{
|
||||
optional uint32 ip = 1;
|
||||
optional float latitude = 2;
|
||||
optional float longitude = 3;
|
||||
optional string country = 4;
|
||||
optional string state = 5;
|
||||
optional string city = 6;
|
||||
}
|
||||
|
||||
message CGCMsgGetIPLocationResponse
|
||||
{
|
||||
repeated CIPLocationInfo infos = 1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// k_EGCMsgSystemStatsSchema
|
||||
//
|
||||
message CGCMsgSystemStatsSchema
|
||||
{
|
||||
optional uint32 gc_app_id = 1;
|
||||
optional bytes schema_kv = 2;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgGetSystemStats
|
||||
//
|
||||
message CGCMsgGetSystemStats
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgGetSystemStatsResponse
|
||||
//
|
||||
message CGCMsgGetSystemStatsResponse
|
||||
{
|
||||
optional uint32 gc_app_id = 1;
|
||||
optional bytes stats_kv = 2;
|
||||
// statically included in GCHost's stats
|
||||
optional uint32 active_jobs = 3;
|
||||
optional uint32 yielding_jobs = 4;
|
||||
optional uint32 user_sessions = 5;
|
||||
optional uint32 game_server_sessions = 6;
|
||||
optional uint32 socaches = 7;
|
||||
optional uint32 socaches_to_unload = 8;
|
||||
optional uint32 socaches_loading = 9;
|
||||
optional uint32 writeback_queue = 10;
|
||||
optional uint32 steamid_locks = 11;
|
||||
optional uint32 logon_queue = 12;
|
||||
optional uint32 logon_jobs = 13;
|
||||
}
|
||||
|
||||
// k_EGCMsgSendEmail
|
||||
message CMsgAMSendEmail
|
||||
{
|
||||
message ReplacementToken
|
||||
{
|
||||
optional string token_name = 1;
|
||||
optional string token_value = 2;
|
||||
}
|
||||
message PersonaNameReplacementToken
|
||||
{
|
||||
optional fixed64 steamid = 1;
|
||||
optional string token_name = 2;
|
||||
}
|
||||
optional fixed64 steamid = 1;
|
||||
optional uint32 email_msg_type = 2;
|
||||
optional uint32 email_format = 3;
|
||||
repeated PersonaNameReplacementToken persona_name_tokens = 5;
|
||||
|
||||
optional uint32 source_gc = 6;
|
||||
repeated ReplacementToken tokens = 7;
|
||||
}
|
||||
|
||||
// k_EGCMsgSendEmailResponse
|
||||
message CMsgAMSendEmailResponse
|
||||
{
|
||||
optional uint32 eresult = 1 [default = 2];
|
||||
}
|
||||
|
||||
// k_EGCMsgGetEmailTemplate
|
||||
message CMsgGCGetEmailTemplate
|
||||
{
|
||||
optional uint32 app_id = 1;
|
||||
optional uint32 email_msg_type = 2;
|
||||
optional int32 email_lang = 3;
|
||||
optional int32 email_format = 4;
|
||||
}
|
||||
|
||||
// k_EGCMsgGetEmailTemplateResponse
|
||||
message CMsgGCGetEmailTemplateResponse
|
||||
{
|
||||
optional uint32 eresult = 1 [default = 2];
|
||||
optional bool template_exists = 2;
|
||||
optional string template = 3;
|
||||
}
|
||||
|
||||
// k_EMsgAMGrantGuestPasses2
|
||||
message CMsgAMGrantGuestPasses2
|
||||
{
|
||||
optional fixed64 steam_id = 1;
|
||||
optional uint32 package_id = 2;
|
||||
optional int32 passes_to_grant = 3;
|
||||
optional int32 days_to_expiration = 4;
|
||||
optional int32 action = 5;
|
||||
}
|
||||
|
||||
// k_EMsgAMGrantGuestPasses2Response
|
||||
message CMsgAMGrantGuestPasses2Response
|
||||
{
|
||||
optional int32 eresult = 1 [default = 2];
|
||||
optional int32 passes_granted = 2 [default = 0];
|
||||
}
|
||||
|
||||
// k_EGCMsgGetAccountDetails
|
||||
message CGCSystemMsg_GetAccountDetails
|
||||
{
|
||||
option (msgpool_soft_limit) = 128;
|
||||
option (msgpool_hard_limit) = 512;
|
||||
|
||||
optional fixed64 steamid = 1; // User to get details for
|
||||
optional uint32 appid = 2; // appid of the source GC
|
||||
}
|
||||
|
||||
message CGCSystemMsg_GetAccountDetails_Response
|
||||
{
|
||||
option (msgpool_soft_limit) = 128;
|
||||
option (msgpool_hard_limit) = 512;
|
||||
|
||||
optional uint32 eresult_deprecated = 1 [ default = 2 ]; // Result of the request
|
||||
optional string account_name = 2; // Login name for the user
|
||||
optional string persona_name = 3; // Diplay name for the user
|
||||
optional bool is_profile_public = 4; // Is the user's profile public
|
||||
optional bool is_inventory_public = 5; // Is the user's inventory public
|
||||
//optional bool is_trusted = 6; // Is the user trusted
|
||||
optional bool is_vac_banned = 7; // Is the user vac banned
|
||||
optional bool is_cyber_cafe = 8; // Is the user a cybe cafe
|
||||
optional bool is_school_account = 9; // Is the user a school account
|
||||
optional bool is_limited = 10; // Is the user limited
|
||||
optional bool is_subscribed = 11; // Is the user subscribed to this app
|
||||
optional uint32 package = 12; // The package the user owns the app through
|
||||
optional bool is_free_trial_account = 13; // Is the user playing the game for free
|
||||
optional uint32 free_trial_expiration = 14; // If the user is playing for free, when does it expire?
|
||||
optional bool is_low_violence = 15; // Is the user restricted to low-violence for this app
|
||||
optional bool is_account_locked_down = 16; // Is the user's account locked
|
||||
optional bool is_community_banned = 17; // Is the user banned from performing community actions
|
||||
optional bool is_trade_banned = 18; // Is the user banned from trading items to other users on Steam
|
||||
optional uint32 trade_ban_expiration = 19; // The time at which the user is unbanned from trading
|
||||
optional uint32 accountid = 20; // The account ID of the user we're responding about
|
||||
optional uint32 suspension_end_time = 21; // If suspended (ban that ends), the date/time the suspension ends
|
||||
optional string currency = 22; // The currency associated with this account
|
||||
optional uint32 steam_level = 23; // The Steam level of the user
|
||||
optional uint32 friend_count = 24; // Number of friends
|
||||
optional uint32 account_creation_time = 25; // Time when the account was created
|
||||
optional bool is_steamguard_enabled = 27; // Is SteamGuard enabled
|
||||
optional bool is_phone_verified = 28; // Has a verified phone number
|
||||
optional bool is_two_factor_auth_enabled = 29; // Has SteamGuard two factor auth
|
||||
optional uint32 two_factor_enabled_time = 30; // Time two factor was added
|
||||
optional uint32 phone_verification_time = 31; // Time phone was verified
|
||||
optional uint64 phone_id = 33; // Phone identifier
|
||||
optional bool is_phone_identifying = 34; // Phone is identifying
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// k_EGCMsgGetPersonaNames
|
||||
//
|
||||
message CMsgGCGetPersonaNames
|
||||
{
|
||||
repeated fixed64 steamids = 1; // Users whose persona names we want
|
||||
}
|
||||
|
||||
message CMsgGCGetPersonaNames_Response
|
||||
{
|
||||
message PersonaName
|
||||
{
|
||||
optional fixed64 steamid = 1; // User we could get a name for
|
||||
optional string persona_name = 2; // Display name for that user
|
||||
}
|
||||
|
||||
repeated PersonaName succeeded_lookups = 1; // Users we could get names for
|
||||
repeated fixed64 failed_lookup_steamids = 2; // Users we failed to get a names for
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// k_EGCMsgCheckFriendship
|
||||
//
|
||||
message CMsgGCCheckFriendship
|
||||
{
|
||||
optional fixed64 steamid_left = 1; // User whose friends list we'll load
|
||||
optional fixed64 steamid_right = 2; // User to look for in the list we load
|
||||
}
|
||||
|
||||
message CMsgGCCheckFriendship_Response
|
||||
{
|
||||
optional bool success = 1; // Whether the API calls all succeeded
|
||||
optional bool found_friendship = 2; // Denotes whether the users are friends (false on API failure)
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// k_EGCMsgMasterSetDirectory
|
||||
//
|
||||
message CMsgGCMsgMasterSetDirectory
|
||||
{
|
||||
message SubGC
|
||||
{
|
||||
optional uint32 dir_index = 1; // The index in the GC directory indicating what role this GC serves
|
||||
optional string name = 2; // A string to give the GC a name for asserts/logs/connection, etc
|
||||
optional string box = 3; // The box that this GC is expected to be associated with
|
||||
optional string command_line = 4; // Additional command line parameters to provide for this GC instance
|
||||
optional string gc_binary = 5; // The binary that should be launched for this GC. This can be left blank to launch the default binary
|
||||
}
|
||||
|
||||
optional uint32 master_dir_index = 1; // The index of the master GC so that it knows how to setup the routing tables to include the master and sub GCs
|
||||
repeated SubGC dir = 2; // A listing of the various sub GCs that the GCH should create
|
||||
}
|
||||
|
||||
message CMsgGCMsgMasterSetDirectory_Response
|
||||
{
|
||||
optional int32 eresult = 1 [default = 2]; // Could the GC start the processes? It doesn't mean they will all get initialized and each sub GC still needs to ack, but catches failure earlier
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgWebAPIJobRequestForwardResponse
|
||||
//
|
||||
message CMsgGCMsgWebAPIJobRequestForwardResponse
|
||||
{
|
||||
optional uint32 dir_index = 1; // The directory index of the GC which has been delegated to handle this particular WebAPI request
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgGetPurchaseTrustStatus
|
||||
//
|
||||
message CGCSystemMsg_GetPurchaseTrust_Request
|
||||
{
|
||||
optional fixed64 steamid = 1; // User to get details for
|
||||
}
|
||||
|
||||
message CGCSystemMsg_GetPurchaseTrust_Response
|
||||
{
|
||||
optional bool has_prior_purchase_history = 1; // The user has prior purchase history with no recent gaps in purchase activity
|
||||
optional bool has_no_recent_password_resets = 2; // The user hasn't had their password reset recently
|
||||
optional bool is_wallet_cash_trusted = 3; // False if the user has recently used a new payment method to fund his or her wallet
|
||||
optional uint32 time_all_trusted = 4; // The time that the user will be trusted in all of the given fields if he or she were to complete a microtransaction right now
|
||||
}
|
||||
|
||||
// k_EMsgGCHAccountVacStatusChange
|
||||
message CMsgGCHAccountVacStatusChange
|
||||
{
|
||||
optional fixed64 steam_id = 1;
|
||||
optional uint32 app_id = 2;
|
||||
optional uint32 rtime_vacban_starts = 3;
|
||||
optional bool is_banned_now = 4;
|
||||
optional bool is_banned_future = 5;
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgGetPartnerAccountLink
|
||||
//
|
||||
message CMsgGCGetPartnerAccountLink
|
||||
{
|
||||
optional fixed64 steamid = 1; // User whose partner account link details we want to get
|
||||
}
|
||||
|
||||
message CMsgGCGetPartnerAccountLink_Response
|
||||
{
|
||||
optional uint32 pwid = 1; // Perfect World ID (not specified if not linked)
|
||||
optional uint32 nexonid = 2; // Nexon ID (not specified if not linked)
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// k_EGCMsgMasterSetWebAPIRouting and k_EGCMsgMasterSetClientMsgRouting
|
||||
//
|
||||
message CMsgGCRoutingInfo
|
||||
{
|
||||
enum RoutingMethod
|
||||
{
|
||||
RANDOM = 0; // random instead of round-robin so that we don't need to track state per routing pool
|
||||
DISCARD = 1;
|
||||
CLIENT_STEAMID = 2;
|
||||
PROTOBUF_FIELD_UINT64 = 3;
|
||||
WEBAPI_PARAM_UINT64 = 4;
|
||||
}
|
||||
|
||||
repeated uint32 dir_index = 1; // One or more directory indices which are potential targets for this route
|
||||
optional RoutingMethod method = 2 [ default = RANDOM ]; // Method by which the route choses its target from multiple dir_index values
|
||||
optional RoutingMethod fallback = 3 [ default = DISCARD ]; // Fallback method to use when default method is not applicable (eg, field can't be parsed)
|
||||
optional uint32 protobuf_field = 4; // For PROTOBUF_FIELD_UINT64, the protobuf field number to decode as a uint64 for routing
|
||||
optional string webapi_param = 5; // For WEBAPI_PARAM_UINT64 method, the case-insensitive name of the webapi parameter
|
||||
}
|
||||
|
||||
message CMsgGCMsgMasterSetWebAPIRouting
|
||||
{
|
||||
message Entry
|
||||
{
|
||||
optional string interface_name = 1;
|
||||
optional string method_name = 2;
|
||||
optional CMsgGCRoutingInfo routing = 3;
|
||||
}
|
||||
repeated Entry entries = 1;
|
||||
}
|
||||
|
||||
message CMsgGCMsgMasterSetClientMsgRouting
|
||||
{
|
||||
message Entry
|
||||
{
|
||||
optional uint32 msg_type = 1; // Client message ID to be routed; top bit is ignored for historical reasons
|
||||
optional CMsgGCRoutingInfo routing = 2;
|
||||
}
|
||||
repeated Entry entries = 1;
|
||||
}
|
||||
|
||||
message CMsgGCMsgMasterSetWebAPIRouting_Response
|
||||
{
|
||||
optional int32 eresult = 1 [ default = 2 ]; // Success or failure code from the GCH when processing k_EGCMsgMasterSetWebAPIRouting
|
||||
}
|
||||
|
||||
message CMsgGCMsgMasterSetClientMsgRouting_Response
|
||||
{
|
||||
optional int32 eresult = 1 [ default = 2 ]; // Success or failure code from the GCH when processing k_EGCMsgMasterSetClientMsgRouting
|
||||
}
|
||||
|
||||
|
||||
// k_EGCMsgSetOptions
|
||||
message CMsgGCMsgSetOptions
|
||||
{
|
||||
enum Option
|
||||
{
|
||||
// Notifications (aka "data streams" - unsoliticed messages from Steam) - default disabled, specify to opt-in
|
||||
NOTIFY_USER_SESSIONS = 0;
|
||||
NOTIFY_SERVER_SESSIONS = 1;
|
||||
NOTIFY_ACHIEVEMENTS = 2;
|
||||
NOTIFY_VAC_ACTION = 3;
|
||||
|
||||
// todo: other options? should start options higher up, like 20+, to save room for streams?
|
||||
}
|
||||
repeated Option options = 1;
|
||||
|
||||
|
||||
// The client_msg_ranges field indicates which client messages, if any, this GC should receive copies of
|
||||
message MessageRange
|
||||
{
|
||||
required uint32 low = 1;
|
||||
required uint32 high = 2;
|
||||
}
|
||||
repeated MessageRange client_msg_ranges = 2;
|
||||
}
|
||||
|
||||
|
||||
// k_EMsgGCHUpdateSession
|
||||
message CMsgGCHUpdateSession
|
||||
{
|
||||
optional fixed64 steam_id = 1;
|
||||
optional uint32 app_id = 2;
|
||||
optional bool online = 3;
|
||||
optional fixed64 server_steam_id = 4; // For a game client, the steam_id of the current server
|
||||
optional uint32 server_addr = 5; // The IP address of the current server (or self for server state)
|
||||
optional uint32 server_port = 6; // The IP port of the server (or self for server state)
|
||||
optional uint32 os_type = 7;
|
||||
optional uint32 client_addr = 8; // For a game client, the public IP address of the client
|
||||
|
||||
message ExtraField
|
||||
{
|
||||
optional string name = 1;
|
||||
optional string value = 2;
|
||||
}
|
||||
repeated ExtraField extra_fields = 9;
|
||||
optional fixed64 owner_id = 10; // owner Steam ID, different from player ID if borrowed
|
||||
|
||||
optional uint32 cm_session_sysid = 11; // routing info for client session that is playing the game
|
||||
optional uint32 cm_session_identifier = 12;
|
||||
repeated uint32 depot_ids = 13; // list of depots in packages that confer app, if requested k_EGCStreamDepots
|
||||
}
|
||||
|
||||
//
|
||||
// k_EGCMsgVSReportedSuspiciousActivity
|
||||
//
|
||||
message CMsgNotificationOfSuspiciousActivity
|
||||
{
|
||||
optional fixed64 steamid = 1;
|
||||
optional uint32 appid = 2;
|
||||
|
||||
message MultipleGameInstances
|
||||
{
|
||||
optional uint32 app_instance_count = 1;
|
||||
repeated fixed64 other_steamids = 2;
|
||||
}
|
||||
optional MultipleGameInstances multiple_instances = 3;
|
||||
}
|
||||
|
||||
// Do not remove this comment due to a bug on the Mac OS X protobuf compiler
|
||||
|
||||
13
gcsdk/steammessages_include.vpc
Normal file
13
gcsdk/steammessages_include.vpc
Normal file
@@ -0,0 +1,13 @@
|
||||
$MacroRequired PROTOBUF_BUILDER_INCLUDED
|
||||
|
||||
$Project
|
||||
{
|
||||
$Folder "Protobuf Files"
|
||||
{
|
||||
$File "$SRCDIR/gcsdk/steammessages.proto"
|
||||
$Folder "Generated Files"
|
||||
{
|
||||
$DynamicFile "$GENERATED_PROTO_DIR/steammessages.pb.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user