212 lines
6.6 KiB
C++
212 lines
6.6 KiB
C++
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
|
//
|
|
// Purpose: Special case hash table for console commands
|
|
//
|
|
// $NoKeywords: $
|
|
//
|
|
//===========================================================================//
|
|
|
|
#if !defined( CONCOMMANDHASH_H )
|
|
#define CONCOMMANDHASH_H
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "utllinkedlist.h"
|
|
#include "generichash.h"
|
|
|
|
// This is a hash table class very similar to the CUtlHashFast, but
|
|
// modified specifically so that we can look up ConCommandBases
|
|
// by string names without having to actually store those strings in
|
|
// the dictionary, and also iterate over all of them.
|
|
// It uses separate chaining: each key hashes to a bucket, each
|
|
// bucket is a linked list of hashed commands. We store the hash of
|
|
// the command's string name as well as its pointer, so we can do
|
|
// the linked list march part of the Find() operation more quickly.
|
|
class CConCommandHash
|
|
{
|
|
public:
|
|
typedef intp CCommandHashHandle_t;
|
|
typedef unsigned int HashKey_t;
|
|
|
|
// Constructor/Deconstructor.
|
|
CConCommandHash();
|
|
~CConCommandHash();
|
|
|
|
// Memory.
|
|
void Purge( bool bReinitialize );
|
|
|
|
// Invalid handle.
|
|
static CCommandHashHandle_t InvalidHandle( void ) { return ( CCommandHashHandle_t )~0; }
|
|
inline bool IsValidHandle( CCommandHashHandle_t hHash ) const;
|
|
|
|
/// Initialize.
|
|
void Init( void ); // bucket count is hardcoded in enum below.
|
|
|
|
/// Get hash value for a concommand
|
|
static inline HashKey_t Hash( const ConCommandBase *cmd );
|
|
|
|
// Size not available; count is meaningless for multilists.
|
|
// int Count( void ) const;
|
|
|
|
// Insertion.
|
|
CCommandHashHandle_t Insert( ConCommandBase *cmd );
|
|
CCommandHashHandle_t FastInsert( ConCommandBase *cmd );
|
|
|
|
// Removal.
|
|
void Remove( CCommandHashHandle_t hHash ) RESTRICT;
|
|
void RemoveAll( void );
|
|
|
|
// Retrieval.
|
|
inline CCommandHashHandle_t Find( const char *name ) const;
|
|
CCommandHashHandle_t Find( const ConCommandBase *cmd ) const RESTRICT;
|
|
// A convenience version of Find that skips the handle part
|
|
// and returns a pointer to a concommand, or NULL if none was found.
|
|
inline ConCommandBase * FindPtr( const char *name ) const;
|
|
|
|
inline ConCommandBase * &operator[]( CCommandHashHandle_t hHash );
|
|
inline ConCommandBase *const &operator[]( CCommandHashHandle_t hHash ) const;
|
|
|
|
#ifdef _DEBUG
|
|
// Dump a report to MSG
|
|
void Report( void );
|
|
#endif
|
|
|
|
// Iteration
|
|
struct CCommandHashIterator_t
|
|
{
|
|
int bucket;
|
|
CCommandHashHandle_t handle;
|
|
|
|
CCommandHashIterator_t(int _bucket, const CCommandHashHandle_t &_handle)
|
|
: bucket(_bucket), handle(_handle) {};
|
|
// inline operator UtlHashFastHandle_t() const { return handle; };
|
|
};
|
|
inline CCommandHashIterator_t First() const;
|
|
inline CCommandHashIterator_t Next( const CCommandHashIterator_t &hHash ) const;
|
|
inline bool IsValidIterator( const CCommandHashIterator_t &iter ) const;
|
|
inline ConCommandBase * &operator[]( const CCommandHashIterator_t &iter ) { return (*this)[iter.handle]; }
|
|
inline ConCommandBase * const &operator[]( const CCommandHashIterator_t &iter ) const { return (*this)[iter.handle]; }
|
|
private:
|
|
// a find func where we've already computed the hash for the string.
|
|
// (hidden private in case we decide to invent a custom string hash func
|
|
// for this class)
|
|
CCommandHashHandle_t Find( const char *name, HashKey_t hash) const RESTRICT;
|
|
|
|
protected:
|
|
enum
|
|
{
|
|
kNUM_BUCKETS = 256,
|
|
kBUCKETMASK = kNUM_BUCKETS - 1,
|
|
};
|
|
|
|
struct HashEntry_t
|
|
{
|
|
HashKey_t m_uiKey;
|
|
ConCommandBase *m_Data;
|
|
|
|
HashEntry_t(unsigned int _hash, ConCommandBase * _cmd)
|
|
: m_uiKey(_hash), m_Data(_cmd) {};
|
|
|
|
HashEntry_t(){};
|
|
};
|
|
|
|
typedef CUtlFixedLinkedList<HashEntry_t> datapool_t;
|
|
|
|
CUtlVector<CCommandHashHandle_t> m_aBuckets;
|
|
datapool_t m_aDataPool;
|
|
};
|
|
|
|
inline bool CConCommandHash::IsValidHandle( CCommandHashHandle_t hHash ) const
|
|
{
|
|
return m_aDataPool.IsValidIndex(hHash);
|
|
}
|
|
|
|
|
|
inline CConCommandHash::CCommandHashHandle_t CConCommandHash::Find( const char *name ) const
|
|
{
|
|
return Find( name, HashStringCaseless(name) );
|
|
}
|
|
|
|
inline ConCommandBase * &CConCommandHash::operator[]( CCommandHashHandle_t hHash )
|
|
{
|
|
return ( m_aDataPool[hHash].m_Data );
|
|
}
|
|
|
|
inline ConCommandBase *const &CConCommandHash::operator[]( CCommandHashHandle_t hHash ) const
|
|
{
|
|
return ( m_aDataPool[hHash].m_Data );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: For iterating over the whole hash, return the index of the first element
|
|
//-----------------------------------------------------------------------------
|
|
CConCommandHash::CCommandHashIterator_t CConCommandHash::First() const
|
|
{
|
|
// walk through the buckets to find the first one that has some data
|
|
int bucketCount = m_aBuckets.Count();
|
|
const CCommandHashHandle_t invalidIndex = m_aDataPool.InvalidIndex();
|
|
for ( int bucket = 0 ; bucket < bucketCount ; ++bucket )
|
|
{
|
|
CCommandHashHandle_t iElement = m_aBuckets[bucket]; // get the head of the bucket
|
|
if ( iElement != invalidIndex )
|
|
return CCommandHashIterator_t( bucket, iElement );
|
|
}
|
|
|
|
// if we are down here, the list is empty
|
|
return CCommandHashIterator_t( -1, invalidIndex );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: For iterating over the whole hash, return the next element after
|
|
// the param one. Or an invalid iterator.
|
|
//-----------------------------------------------------------------------------
|
|
CConCommandHash::CCommandHashIterator_t
|
|
CConCommandHash::Next( const CConCommandHash::CCommandHashIterator_t &iter ) const
|
|
{
|
|
// look for the next entry in the current bucket
|
|
CCommandHashHandle_t next = m_aDataPool.Next(iter.handle);
|
|
const CCommandHashHandle_t invalidIndex = m_aDataPool.InvalidIndex();
|
|
if ( next != invalidIndex )
|
|
{
|
|
// this bucket still has more elements in it
|
|
return CCommandHashIterator_t(iter.bucket, next);
|
|
}
|
|
|
|
// otherwise look for the next bucket with data
|
|
int bucketCount = m_aBuckets.Count();
|
|
for ( int bucket = iter.bucket+1 ; bucket < bucketCount ; ++bucket )
|
|
{
|
|
CCommandHashHandle_t next = m_aBuckets[bucket]; // get the head of the bucket
|
|
if (next != invalidIndex)
|
|
return CCommandHashIterator_t( bucket, next );
|
|
}
|
|
|
|
// if we're here, there's no more data to be had
|
|
return CCommandHashIterator_t(-1, invalidIndex);
|
|
}
|
|
|
|
bool CConCommandHash::IsValidIterator( const CCommandHashIterator_t &iter ) const
|
|
{
|
|
return ( (iter.bucket >= 0) && (m_aDataPool.IsValidIndex(iter.handle)) );
|
|
}
|
|
|
|
inline CConCommandHash::HashKey_t CConCommandHash::Hash( const ConCommandBase *cmd )
|
|
{
|
|
return HashStringCaseless( cmd->GetName() );
|
|
}
|
|
|
|
inline ConCommandBase * CConCommandHash::FindPtr( const char *name ) const
|
|
{
|
|
CCommandHashHandle_t handle = Find(name);
|
|
if (handle == InvalidHandle())
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return (*this)[handle];
|
|
}
|
|
}
|
|
|
|
#endif |