etqw-sdk/source/idlib/containers/HashMapGeneric.h

522 lines
11 KiB
C++

// Copyright (C) 2007 Id Software, Inc.
//
#ifndef __HASHMAP_GENERIC_H__
#define __HASHMAP_GENERIC_H__
/*
============
Hash policies
============
*/
/*
============
sdHashGeneratorDefault
============
*/
struct sdHashGeneratorDefault {
template< class type >
static int Hash( const idHashIndex& hasher, const type& value ) {
return hasher.GenerateKey( value );
}
};
/*
============
sdHashGeneratorNumeric
============
*/
struct sdHashGeneratorNumeric {
template< class type >
static int Hash( const idHashIndex& hasher, const type& value ) {
return hasher.GenerateKey( value, 0 );
}
};
/*
============
sdHashGeneratorIHash
case-insensitive string hash
============
*/
struct sdHashGeneratorIHash {
template< class type >
static int Hash( const idHashIndex& hasher, const type& value ) {
return hasher.GenerateKey( value, false );
}
};
/*
============
Key comparison policies
============
*/
/*
============
sdHashCompareDefault
============
*/
struct sdHashCompareDefault {
template< class type1, class type2 >
static bool Compare( const type1& lhs, const type2& rhs ) {
return lhs == rhs;
}
};
/*
============
sdHashCompareStrCmp
============
*/
struct sdHashCompareStrCmp {
template< class type1, class type2 >
static bool Compare( const type1& lhs, const type2& rhs ) {
return idStr::Cmp( lhs, rhs ) == 0;
}
};
/*
============
sdHashCompareStrIcmp
============
*/
struct sdHashCompareStrIcmp {
template< class type1, class type2 >
static bool Compare( const type1& lhs, const type2& rhs ) {
return idStr::Icmp( lhs, rhs ) == 0;
}
};
/*
============
sdHashMapGeneric
allow for generic mapping between arbitrary data types
============
*/
template< class key,
class type,
class hashCompare = sdHashCompareDefault,
class hashGenerator = sdHashGeneratorDefault,
class hashIndexType = idHashIndex
>
class sdHashMapGeneric {
public:
typedef sdPair< key, type > Pair;
typedef const Pair ConstPair;
typedef Pair* Iterator;
typedef const Pair* ConstIterator;
typedef type Type;
typedef const type ConstType;
typedef const key ConstKey;
// < location of insertion, true if the item is new, false if the item already existed >
typedef sdPair< Iterator, bool > InsertResult;
typedef hashGenerator HashGenerator;
typedef hashCompare HashCompare;
sdHashMapGeneric( const sdHashMapGeneric& rhs );
explicit sdHashMapGeneric( int granularity = 16 );
sdHashMapGeneric& operator=( const sdHashMapGeneric& rhs );
void SetGranularity( int newGranularity );
void InitHash( const int newHashSize, const int newIndexSize );
size_t Size( void ) const;
// if the key-value mapping already exists, the value is merely reassigned
// the bool parameter of InsertResult reports the results: it is true if
// the item needed to be added, false if it already existed
InsertResult Set( const key& key_, const type& value );
// this is a convenience accessor equivalent to Set
// this is slightly more expensive than using Set directly in the case of new item insertions
type& operator[]( const key& key_ );
Iterator FindIndex( int index );
ConstIterator FindIndex( int index ) const;
void Clear();
bool Remove( const key& key_ );
// Information
int Num() const;
bool Empty() const;
// Iteration
Iterator Begin();
Iterator End();
ConstIterator Begin() const;
ConstIterator End() const;
void Remove( Iterator iter );
int Count( const key& key_ ) const;
void DeleteKeys();
void DeleteValues();
void Swap( sdHashMapGeneric& rhs );
// These various Find version are templates so that in certain cases (mainly string mappings)
// we can avoid constructing a temporary of type key
template< class OtherKey >
Iterator Find( const OtherKey& key_ ) {
int hashKey = HashGenerator::Hash( hash, key_ );
for( int i = hash.GetFirst( hashKey ); i != idHashIndex::NULL_INDEX; i = hash.GetNext( i ) ) {
if( HashCompare::Compare( pairs[ i ].first, key_ )) {
return &pairs[ i ];
}
}
return End();
}
template< class OtherKey >
ConstIterator Find( const OtherKey& key_ ) const {
int hashKey = HashGenerator::Hash( hash, key_ );
for( int i = hash.GetFirst( hashKey ); i != idHashIndex::NULL_INDEX; i = hash.GetNext( i ) ) {
if( HashCompare::Compare( pairs[ i ].first, key_ )) {
return &pairs[ i ];
}
}
return End();
}
private:
InsertResult SetNewItem( const key& key_, const type& value );
private:
typedef idList< Pair > PairList;
hashIndexType hash;
PairList pairs;
};
#define HASHMAP_TEMPLATE_HEADER template< class key, class type, class hashCompare, class hashGenerator, class hashIndexType >
#define HASHMAP_TEMPLATE_TAG sdHashMapGeneric< key, type, hashCompare, hashGenerator, hashIndexType >
/*
============
HASHMAP_TEMPLATE_TAG::sdHashMapGeneric
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
HASHMAP_TEMPLATE_TAG::sdHashMapGeneric( int granularity ) {
SetGranularity( granularity );
}
/*
============
HASHMAP_TEMPLATE_TAG::sdHashMapGeneric
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
HASHMAP_TEMPLATE_TAG::sdHashMapGeneric( const sdHashMapGeneric& rhs ) {
*this = rhs;
}
/*
============
HASHMAP_TEMPLATE_TAG::sdHashMapGeneric
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
size_t HASHMAP_TEMPLATE_TAG::Size( void ) const {
return sizeof( *this ) + hash.Size() + pairs.Size();
}
/*
============
HASHMAP_TEMPLATE_TAG::operator
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
HASHMAP_TEMPLATE_TAG& HASHMAP_TEMPLATE_TAG::operator=( const sdHashMapGeneric& rhs ) {
if( this != &rhs ) {
pairs = rhs.pairs;
hash = rhs.hash;
}
return *this;
}
/*
============
HASHMAP_TEMPLATE_TAG::Num
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
int HASHMAP_TEMPLATE_TAG::Num() const {
return pairs.Num();
}
/*
============
HASHMAP_TEMPLATE_TAG::Empty
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
bool HASHMAP_TEMPLATE_TAG::Empty() const {
return Num() == 0;
}
/*
============
HASHMAP_TEMPLATE_TAG::Begin
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
typename HASHMAP_TEMPLATE_TAG::Iterator HASHMAP_TEMPLATE_TAG::Begin() {
return pairs.Begin();
}
/*
============
HASHMAP_TEMPLATE_TAG::Begin
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
typename HASHMAP_TEMPLATE_TAG::ConstIterator HASHMAP_TEMPLATE_TAG::Begin() const {
return pairs.Begin();
}
/*
============
HASHMAP_TEMPLATE_TAG::End
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
typename HASHMAP_TEMPLATE_TAG::Iterator HASHMAP_TEMPLATE_TAG::End() {
return pairs.End();
}
/*
============
HASHMAP_TEMPLATE_TAG::End
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
typename HASHMAP_TEMPLATE_TAG::ConstIterator HASHMAP_TEMPLATE_TAG::End() const {
return pairs.End();
}
/*
============
HASHMAP_TEMPLATE_TAG::Set
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
typename HASHMAP_TEMPLATE_TAG::InsertResult HASHMAP_TEMPLATE_TAG::Set( const key& key_, const type& value ) {
Iterator result = Find( key_ );
if( result != End() ) {
result->second = value;
return InsertResult( result, false );
}
return SetNewItem( key_, value );
}
/*
============
HASHMAP_TEMPLATE_TAG::SetNewItem
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
typename HASHMAP_TEMPLATE_TAG::InsertResult HASHMAP_TEMPLATE_TAG::SetNewItem( const key& key_, const type& value ) {
assert( Find( key_ ) == End() );
int hashKey = HashGenerator::Hash( hash, key_ );
Iterator result = &pairs.Alloc();
result->first = key_;
result->second = value;
hash.Add( hashKey, pairs.Num() - 1 );
return InsertResult( result, true );
}
/*
============
HASHMAP_TEMPLATE_TAG::SetGranularity
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
void HASHMAP_TEMPLATE_TAG::SetGranularity( int newGranularity ) {
pairs.SetGranularity( newGranularity );
hash.SetGranularity( newGranularity );
}
/*
============
HASHMAP_TEMPLATE_TAG::InitHash
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
void HASHMAP_TEMPLATE_TAG::InitHash( const int newHashSize, const int newIndexSize ) {
hash.Init( newHashSize, newIndexSize );
}
/*
============
HASHMAP_TEMPLATE_TAG::FindIndex
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
typename HASHMAP_TEMPLATE_TAG::Iterator HASHMAP_TEMPLATE_TAG::FindIndex( int index ) {
return &pairs[ index ];
}
/*
============
HASHMAP_TEMPLATE_TAG::FindIndex
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
typename HASHMAP_TEMPLATE_TAG::ConstIterator HASHMAP_TEMPLATE_TAG::FindIndex( int index ) const {
return &pairs[ index ];
}
/*
============
HASHMAP_TEMPLATE_TAG::Clear
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
void HASHMAP_TEMPLATE_TAG::Clear() {
pairs.Clear();
hash.Clear();
}
/*
============
HASHMAP_TEMPLATE_TAG::Remove
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
bool HASHMAP_TEMPLATE_TAG::Remove( const key& key_ ) {
int hashKey = HashGenerator::Hash( hash, key_ );
for( int i = hash.GetFirst( hashKey ); i != idHashIndex::NULL_INDEX; i = hash.GetNext( i ) ) {
if( HashCompare::Compare( pairs[ i ].first, key_ )) {
hash.RemoveIndex( hashKey, i );
pairs.RemoveIndex( i );
return true;
}
}
return false;
}
/*
============
HASHMAP_TEMPLATE_TAG::operator[]
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
type& HASHMAP_TEMPLATE_TAG::operator[]( const key& key_ ) {
Iterator iter = Find( key_ );
if( iter != End() ) {
return iter->second;
}
InsertResult result = SetNewItem( key_, type() );
return result.first->second;
}
/*
============
HASHMAP_TEMPLATE_TAG::Remove
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
void HASHMAP_TEMPLATE_TAG::Remove( Iterator iter ) {
Remove( iter->first );
}
/*
============
HASHMAP_TEMPLATE_TAG::Count
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
int HASHMAP_TEMPLATE_TAG::Count( const key& key_ ) const {
int hashKey = HashGenerator::Hash( hash, key_ );
int count = 0;
for( int i = hash.GetFirst( hashKey ); i != idHashIndex::NULL_INDEX; i = hash.GetNext( i ) ) {
count++;
}
return count;
}
/*
============
HASHMAP_TEMPLATE_TAG::DeleteKeys
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
void HASHMAP_TEMPLATE_TAG::DeleteKeys() {
for( int i = 0; i < pairs.Num(); i++ ) {
delete pairs[ i ].first;
}
}
/*
============
HASHMAP_TEMPLATE_TAG::DeleteValues
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
void HASHMAP_TEMPLATE_TAG::DeleteValues() {
for( int i = 0; i < pairs.Num(); i++ ) {
delete pairs[ i ].second;
}
}
/*
============
HASHMAP_TEMPLATE_TAG::DeleteValues
============
*/
HASHMAP_TEMPLATE_HEADER
ID_INLINE
void HASHMAP_TEMPLATE_TAG::Swap( sdHashMapGeneric& rhs ) {
pairs.Swap( rhs.pairs );
hash.Swap( rhs.hash );
}
#undef HASHMAP_TEMPLATE_HEADER
#undef HASHMAP_TEMPLATE_TAG
#endif // !__HASHMAP_GENERIC_H__