// Copyright (C) 2007 Id Software, Inc. // #ifndef __HASHMAP_H__ #define __HASHMAP_H__ /* =============================================================================== General hash table. Slower than idHashIndex but it can also be used for linked lists and other data structures than just indexes or arrays. =============================================================================== */ template< class Type > class idHashMap { public: idHashMap(); idHashMap( const idHashMap &map ); ~idHashMap( void ); // returns total size of allocated memory size_t Allocated( void ) const; // returns total size of allocated memory including size of hash table type size_t Size( void ) const; Type & Set( const char *key, const Type &value ); bool Get( const char *key, Type **value = NULL ); bool Get( const char *key, const Type **value = NULL ) const; // the entire contents can be iterated over, but note that the // exact index for a given element may change when new elements are added int Num( void ) const; const idStr & GetKey( int index ) const; Type * GetIndex( int index ); const Type * GetIndex( int index ) const; bool Remove( const char *key ); const idList &GetKeyList( void ) const { return keyList; } const idList &GetValList( void ) const { return list; } void Clear( void ); void DeleteContents( bool clear = true ); // returns number in the range [0-100] representing the spread over the hash table int GetSpread( void ) const; void Swap( idHashMap& rhs ); private: idList list; idHashIndex hashIndex; idList keyList; }; /* ================ idHashMap::idHashMap ================ */ template< class Type > ID_INLINE idHashMap::idHashMap() { } /* ================ idHashMap::idHashMap ================ */ template< class Type > ID_INLINE idHashMap::idHashMap( const idHashMap &map ) { list = map.list; index = map.index; keyList = map.keyList; } /* ================ idHashMap::~idHashMap ================ */ template< class Type > ID_INLINE idHashMap::~idHashMap( void ) { Clear(); } /* ================ idHashMap::Allocated ================ */ template< class Type > ID_INLINE size_t idHashMap::Allocated( void ) const { return list.Allocated(); } /* ================ idHashMap::Size ================ */ template< class Type > ID_INLINE size_t idHashMap::Size( void ) const { return list.Size() + hashIndex.Size() + keyList.Size(); } /* ================ idHashMap::Set Sets a key in the table to be a certain value, adds it if it's not already there Returns a reference to the value in the table ================ */ template< class Type > ID_INLINE Type &idHashMap::Set( const char *key, const Type& value ) { Type *existingValue; if ( Get( key, &existingValue ) ) { *existingValue = value; return *existingValue; } else { int index = list.Append( value ); keyList.Append( key ); hashIndex.Add( hashIndex.GenerateKey( key ), index ); return list[index]; } } /* ================ idHashMap::Remove ================ */ template< class Type > ID_INLINE bool idHashMap::Remove( const char *key ) { int hashKey = hashIndex.GenerateKey( key ); int i; for ( i = hashIndex.GetFirst( hashKey ); i != idHashIndex::NULL_INDEX; i = hashIndex.GetNext( i ) ) { if ( keyList[ i ].Cmp( key ) == 0 ) { hashIndex.RemoveIndex( hashKey, i ); keyList.RemoveIndex( i ); list.RemoveIndex( i ); return true; } } return false; } /* =============== idHashMap::Get =============== */ template< class Type > ID_INLINE bool idHashMap::Get( const char *key, Type **value ) { int hashKey = hashIndex.GenerateKey( key ); int i; for ( i = hashIndex.GetFirst( hashKey ); i != idHashIndex::NULL_INDEX; i = hashIndex.GetNext( i ) ) { if ( keyList[i].Cmp( key ) == 0 ) { if ( value ) { *value = &list[ i ]; } return true; } } if ( value ) { *value = NULL; } return false; } /* =============== idHashMap::Get =============== */ template< class Type > ID_INLINE bool idHashMap::Get( const char *key, const Type **value ) const { return const_cast *>(this)->Get( key, const_cast( value ) ); } /* ================ idHashMap::GetIndex the entire contents can be itterated over, but note that the exact index for a given element may change when new elements are added ================ */ template< class Type > ID_INLINE Type *idHashMap::GetIndex( int index ) { if ( index >= 0 && index < list.Num() ) { return &list[index]; } return NULL; } /* ================ idHashMap::GetIndex the entire contents can be itterated over, but note that the exact index for a given element may change when new elements are added ================ */ template< class Type > ID_INLINE const Type *idHashMap::GetIndex( int index ) const { if ( index >= 0 && index < list.Num() ) { return &list[index]; } return NULL; } /* ================ idHashMap::GetKey the entire contents can be itterated over, but note that the exact index for a given element may change when new elements are added ================ */ template< class Type > ID_INLINE const idStr &idHashMap::GetKey( int index ) const { if ( index >= 0 && index < list.Num() ) { return keyList[index]; } static idStr blank; return blank; } /* ================ idHashMap::Clear ================ */ template< class Type > ID_INLINE void idHashMap::Clear( void ) { list.Clear(); hashIndex.Clear(); keyList.Clear(); } /* ================ idHashMap::DeleteContents ================ */ template< class Type > ID_INLINE void idHashMap::DeleteContents( bool clear ) { list.DeleteContents( clear ); if ( clear ) { // list already cleared hashIndex.Clear(); keyList.Clear(); } } /* ================ idHashMap::Num ================ */ template< class Type > ID_INLINE int idHashMap::Num( void ) const { return list.Num(); } /* ================ idHashMap::GetSpread ================ */ template< class Type > ID_INLINE int idHashMap::GetSpread( void ) const { return hashIndex.GetSpread(); } /* ============ idHashMap::Swap ============ */ template< class Type > ID_INLINE void idHashMap::Swap( idHashMap& rhs ) { hashIndex.Swap( rhs.hashIndex ); list.Swap( rhs.list ); keyList.Swap( rhs.keyList ); } #endif /* !__HASHMAP_H__ */