source-engine/public/tier1/utlsymbol.h

382 lines
11 KiB
C++

//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: Defines a symbol table
//
// $Header: $
// $NoKeywords: $
//===========================================================================//
#ifndef UTLSYMBOL_H
#define UTLSYMBOL_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/platform.h"
#include "tier0/threadtools.h"
#include "tier1/utlrbtree.h"
#include "tier1/utlvector.h"
#include "tier1/utlbuffer.h"
#include "tier1/utllinkedlist.h"
#include "tier1/stringpool.h"
//-----------------------------------------------------------------------------
// forward declarations
//-----------------------------------------------------------------------------
class CUtlSymbolTable;
class CUtlSymbolTableMT;
#define FILENAMEHANDLE_INVALID 0
//-----------------------------------------------------------------------------
// This is a symbol, which is a easier way of dealing with strings.
//-----------------------------------------------------------------------------
typedef unsigned short UtlSymId_t;
#define UTL_INVAL_SYMBOL ((UtlSymId_t)~0)
class CUtlSymbol
{
public:
// constructor, destructor
CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) {}
CUtlSymbol( UtlSymId_t id ) : m_Id(id) {}
CUtlSymbol( const char* pStr );
CUtlSymbol( CUtlSymbol const& sym ) : m_Id(sym.m_Id) {}
// operator=
CUtlSymbol& operator=( CUtlSymbol const& src ) { m_Id = src.m_Id; return *this; }
// operator==
bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; }
bool operator==( const char* pStr ) const;
// Is valid?
bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; }
// Gets at the symbol
operator UtlSymId_t () const { return m_Id; }
// Gets the string associated with the symbol
const char* String( ) const;
// Modules can choose to disable the static symbol table so to prevent accidental use of them.
static void DisableStaticSymbolTable();
// Methods with explicit locking mechanism. Only use for optimization reasons.
static void LockTableForRead();
static void UnlockTableForRead();
const char * StringNoLock() const;
protected:
UtlSymId_t m_Id;
// Initializes the symbol table
static void Initialize();
// returns the current symbol table
static CUtlSymbolTableMT* CurrTable();
// The standard global symbol table
static CUtlSymbolTableMT* s_pSymbolTable;
static bool s_bAllowStaticSymbolTable;
friend class CCleanupUtlSymbolTable;
};
//-----------------------------------------------------------------------------
// CUtlSymbolTable:
// description:
// This class defines a symbol table, which allows us to perform mappings
// of strings to symbols and back. The symbol class itself contains
// a static version of this class for creating global strings, but this
// class can also be instanced to create local symbol tables.
//
// This class stores the strings in a series of string pools. The first
// two bytes of each string are decorated with a hash to speed up
// comparisons.
//-----------------------------------------------------------------------------
class CUtlSymbolTable
{
public:
// constructor, destructor
CUtlSymbolTable( int growSize = 0, int initSize = 16, bool caseInsensitive = false );
~CUtlSymbolTable();
// Finds and/or creates a symbol based on the string
CUtlSymbol AddString( const char* pString );
// Finds the symbol for pString
CUtlSymbol Find( const char* pString ) const;
// Look up the string associated with a particular symbol
const char* String( CUtlSymbol id ) const;
inline bool HasElement(const char* pStr) const
{
return Find(pStr) != UTL_INVAL_SYMBOL;
}
// Remove all symbols in the table.
void RemoveAll();
int GetNumStrings( void ) const
{
return m_Lookup.Count();
}
// We store one of these at the beginning of every string to speed
// up comparisons.
typedef unsigned short hashDecoration_t;
protected:
class CStringPoolIndex
{
public:
inline CStringPoolIndex()
{
}
inline CStringPoolIndex( unsigned short iPool, unsigned short iOffset )
: m_iPool(iPool), m_iOffset(iOffset)
{}
inline bool operator==( const CStringPoolIndex &other ) const
{
return m_iPool == other.m_iPool && m_iOffset == other.m_iOffset;
}
unsigned short m_iPool; // Index into m_StringPools.
unsigned short m_iOffset; // Index into the string pool.
};
class CLess
{
public:
CLess( int ignored = 0 ) {} // permits default initialization to NULL in CUtlRBTree
bool operator!() const { return false; }
bool operator()( const CStringPoolIndex &left, const CStringPoolIndex &right ) const;
};
// Stores the symbol lookup
class CTree : public CUtlRBTree<CStringPoolIndex, unsigned short, CLess>
{
public:
CTree( int growSize, int initSize ) : CUtlRBTree<CStringPoolIndex, unsigned short, CLess>( growSize, initSize ) {}
friend class CUtlSymbolTable::CLess; // Needed to allow CLess to calculate pointer to symbol table
};
struct StringPool_t
{
int m_TotalLen; // How large is
int m_SpaceUsed;
char m_Data[1];
};
CTree m_Lookup;
bool m_bInsensitive;
mutable unsigned short m_nUserSearchStringHash;
mutable const char* m_pUserSearchString;
// stores the string data
CUtlVector<StringPool_t*> m_StringPools;
private:
int FindPoolWithSpace( int len ) const;
const char* StringFromIndex( const CStringPoolIndex &index ) const;
const char* DecoratedStringFromIndex( const CStringPoolIndex &index ) const;
friend class CLess;
friend class CSymbolHash;
};
class CUtlSymbolTableMT : public CUtlSymbolTable
{
public:
CUtlSymbolTableMT( int growSize = 0, int initSize = 32, bool caseInsensitive = false )
: CUtlSymbolTable( growSize, initSize, caseInsensitive )
{
}
CUtlSymbol AddString( const char* pString )
{
m_lock.LockForWrite();
CUtlSymbol result = CUtlSymbolTable::AddString( pString );
m_lock.UnlockWrite();
return result;
}
CUtlSymbol Find( const char* pString ) const
{
m_lock.LockForWrite();
CUtlSymbol result = CUtlSymbolTable::Find( pString );
m_lock.UnlockWrite();
return result;
}
const char* String( CUtlSymbol id ) const
{
m_lock.LockForRead();
const char *pszResult = CUtlSymbolTable::String( id );
m_lock.UnlockRead();
return pszResult;
}
const char * StringNoLock( CUtlSymbol id ) const
{
return CUtlSymbolTable::String( id );
}
void LockForRead()
{
m_lock.LockForRead();
}
void UnlockForRead()
{
m_lock.UnlockRead();
}
private:
#ifdef WIN32
mutable CThreadSpinRWLock m_lock;
#else
mutable CThreadRWLock m_lock;
#endif
};
//-----------------------------------------------------------------------------
// CUtlFilenameSymbolTable:
// description:
// This class defines a symbol table of individual filenames, stored more
// efficiently than a standard symbol table. Internally filenames are broken
// up into file and path entries, and a file handle class allows convenient
// access to these.
//-----------------------------------------------------------------------------
// The handle is a CUtlSymbol for the dirname and the same for the filename, the accessor
// copies them into a static char buffer for return.
typedef void* FileNameHandle_t;
// Symbol table for more efficiently storing filenames by breaking paths and filenames apart.
// Refactored from BaseFileSystem.h
class CUtlFilenameSymbolTable
{
// Internal representation of a FileHandle_t
// If we get more than 64K filenames, we'll have to revisit...
// Right now CUtlSymbol is a short, so this packs into an int/void * pointer size...
struct FileNameHandleInternal_t
{
FileNameHandleInternal_t()
{
COMPILE_TIME_ASSERT( sizeof( *this ) == sizeof( FileNameHandle_t ) );
COMPILE_TIME_ASSERT( sizeof( value ) == 4 );
value = 0;
#ifdef PLATFORM_64BITS
pad = 0;
#endif
}
// We pack the path and file values into a single 32 bit value. We were running
// out of space with the two 16 bit values (more than 64k files) so instead of increasing
// the total size we split the underlying pool into two (paths and files) and
// use a smaller path string pool and a larger file string pool.
unsigned int value;
#ifdef PLATFORM_64BITS
// some padding to make sure we are the same size as FileNameHandle_t on 64 bit.
unsigned int pad;
#endif
static const unsigned int cNumBitsInPath = 12;
static const unsigned int cNumBitsInFile = 32 - cNumBitsInPath;
static const unsigned int cMaxPathValue = 1 << cNumBitsInPath;
static const unsigned int cMaxFileValue = 1 << cNumBitsInFile;
static const unsigned int cPathBitMask = cMaxPathValue - 1;
static const unsigned int cFileBitMask = cMaxFileValue - 1;
// Part before the final '/' character
unsigned int GetPath() const { return ((value >> cNumBitsInFile) & cPathBitMask); }
void SetPath( unsigned int path ) { Assert( path < cMaxPathValue ); value = ((value & cFileBitMask) | ((path & cPathBitMask) << cNumBitsInFile)); }
// Part after the final '/', including extension
unsigned int GetFile() const { return (value & cFileBitMask); }
void SetFile( unsigned int file ) { Assert( file < cMaxFileValue ); value = ((value & (cPathBitMask << cNumBitsInFile)) | (file & cFileBitMask)); }
};
public:
FileNameHandle_t FindOrAddFileName( const char *pFileName );
FileNameHandle_t FindFileName( const char *pFileName );
int PathIndex( const FileNameHandle_t &handle ) { return (( const FileNameHandleInternal_t * )&handle)->GetPath(); }
bool String( const FileNameHandle_t& handle, char *buf, int buflen );
void RemoveAll();
void SpewStrings();
bool SaveToBuffer( CUtlBuffer &buffer );
bool RestoreFromBuffer( CUtlBuffer &buffer );
private:
CCountedStringPoolBase<unsigned short> m_PathStringPool;
CCountedStringPoolBase<unsigned int> m_FileStringPool;
mutable CThreadSpinRWLock m_lock;
};
// This creates a simple class that includes the underlying CUtlSymbol
// as a private member and then instances a private symbol table to
// manage those symbols. Avoids the possibility of the code polluting the
// 'global'/default symbol table, while letting the code look like
// it's just using = and .String() to look at CUtlSymbol type objects
//
// NOTE: You can't pass these objects between .dlls in an interface (also true of CUtlSymbol of course)
//
#define DECLARE_PRIVATE_SYMBOLTYPE( typename ) \
class typename \
{ \
public: \
typename(); \
typename( const char* pStr ); \
typename& operator=( typename const& src ); \
bool operator==( typename const& src ) const; \
const char* String( ) const; \
private: \
CUtlSymbol m_SymbolId; \
};
// Put this in the .cpp file that uses the above typename
#define IMPLEMENT_PRIVATE_SYMBOLTYPE( typename ) \
static CUtlSymbolTable g_##typename##SymbolTable; \
typename::typename() \
{ \
m_SymbolId = UTL_INVAL_SYMBOL; \
} \
typename::typename( const char* pStr ) \
{ \
m_SymbolId = g_##typename##SymbolTable.AddString( pStr ); \
} \
typename& typename::operator=( typename const& src ) \
{ \
m_SymbolId = src.m_SymbolId; \
return *this; \
} \
bool typename::operator==( typename const& src ) const \
{ \
return ( m_SymbolId == src.m_SymbolId ); \
} \
const char* typename::String( ) const \
{ \
return g_##typename##SymbolTable.String( m_SymbolId ); \
}
#endif // UTLSYMBOL_H