//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "utlhashtable.h" #ifndef GC #include "igamesystem.h" #endif #include "gamestringpool.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //----------------------------------------------------------------------------- // Purpose: The actual storage for pooled per-level strings //----------------------------------------------------------------------------- #ifdef GC class CGameStringPool #else class CGameStringPool : public CBaseGameSystem #endif { virtual char const *Name() { return "CGameStringPool"; } virtual void LevelShutdownPostEntity() { FreeAll(); } void FreeAll() { #if 0 && _DEBUG m_Strings.DbgCheckIntegrity(); m_KeyLookupCache.DbgCheckIntegrity(); #endif m_Strings.Purge(); m_KeyLookupCache.Purge(); } CUtlHashtable m_Strings; CUtlHashtable m_KeyLookupCache; public: CGameStringPool() : m_Strings(256) { } ~CGameStringPool() { FreeAll(); } void Dump( void ) { CUtlVector strings( 0, m_Strings.Count() ); for (UtlHashHandle_t i = m_Strings.FirstHandle(); i != m_Strings.InvalidHandle(); i = m_Strings.NextHandle(i)) { strings.AddToTail( strings[i] ); } struct _Local { static int __cdecl F(const char * const *a, const char * const *b) { return strcmp(*a, *b); } }; strings.Sort( _Local::F ); for ( int i = 0; i < strings.Count(); ++i ) { DevMsg( " %d (0x%p) : %s\n", i, strings[i], strings[i] ); } DevMsg( "\n" ); DevMsg( "Size: %d items\n", strings.Count() ); } const char *Find(const char *string) { UtlHashHandle_t i = m_Strings.Find( string ); return i == m_Strings.InvalidHandle() ? NULL : m_Strings[ i ].Get(); } const char *Allocate(const char *string) { return m_Strings[ m_Strings.Insert( string ) ].Get(); } const char *AllocateWithKey(const char *string, const void* key) { const char * &cached = m_KeyLookupCache[ m_KeyLookupCache.Insert( key, NULL ) ]; if (cached == NULL) { cached = Allocate( string ); } return cached; } }; static CGameStringPool g_GameStringPool; #ifndef GC //----------------------------------------------------------------------------- // String system accessor //----------------------------------------------------------------------------- IGameSystem *GameStringSystem() { return &g_GameStringPool; } #endif //----------------------------------------------------------------------------- // Purpose: The public accessor for the level-global pooled strings //----------------------------------------------------------------------------- string_t AllocPooledString( const char * pszValue ) { if (pszValue && *pszValue) return MAKE_STRING( g_GameStringPool.Allocate( pszValue ) ); return NULL_STRING; } string_t AllocPooledString_StaticConstantStringPointer( const char * pszGlobalConstValue ) { Assert(pszGlobalConstValue && *pszGlobalConstValue); return MAKE_STRING( g_GameStringPool.AllocateWithKey( pszGlobalConstValue, pszGlobalConstValue ) ); } string_t FindPooledString( const char *pszValue ) { return MAKE_STRING( g_GameStringPool.Find( pszValue ) ); } #if !defined(CLIENT_DLL) && !defined( GC ) //------------------------------------------------------------------------------ // Purpose: //------------------------------------------------------------------------------ void CC_DumpGameStringTable( void ) { if ( !UTIL_IsCommandIssuedByServerAdmin() ) return; g_GameStringPool.Dump(); } static ConCommand dumpgamestringtable("dumpgamestringtable", CC_DumpGameStringTable, "Dump the contents of the game string table to the console.", FCVAR_CHEAT); #endif