dhewm3/neo/idlib/containers/HashIndex.h
dhewg 736ec20d4d Untangle the epic precompiled.h mess
Don't include the lazy precompiled.h everywhere, only what's
required for the compilation unit.
platform.h needs to be included instead to provide all essential
defines and types.
All includes use the relative path to the neo or the game
specific root.
Move all idlib related includes from idlib/Lib.h to precompiled.h.
precompiled.h still exists for the MFC stuff in tools/.
Add some missing header guards.
2011-12-19 23:21:47 +01:00

408 lines
10 KiB
C++

/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef __HASHINDEX_H__
#define __HASHINDEX_H__
#include "idlib/math/Vector.h"
#include "idlib/Str.h"
/*
===============================================================================
Fast hash table for indexes and arrays.
Does not allocate memory until the first key/index pair is added.
===============================================================================
*/
#define DEFAULT_HASH_SIZE 1024
#define DEFAULT_HASH_GRANULARITY 1024
class idHashIndex {
public:
idHashIndex( void );
idHashIndex( const int initialHashSize, const int initialIndexSize );
~idHashIndex( void );
// returns total size of allocated memory
size_t Allocated( void ) const;
// returns total size of allocated memory including size of hash index type
size_t Size( void ) const;
idHashIndex & operator=( const idHashIndex &other );
// add an index to the hash, assumes the index has not yet been added to the hash
void Add( const int key, const int index );
// remove an index from the hash
void Remove( const int key, const int index );
// get the first index from the hash, returns -1 if empty hash entry
int First( const int key ) const;
// get the next index from the hash, returns -1 if at the end of the hash chain
int Next( const int index ) const;
// insert an entry into the index and add it to the hash, increasing all indexes >= index
void InsertIndex( const int key, const int index );
// remove an entry from the index and remove it from the hash, decreasing all indexes >= index
void RemoveIndex( const int key, const int index );
// clear the hash
void Clear( void );
// clear and resize
void Clear( const int newHashSize, const int newIndexSize );
// free allocated memory
void Free( void );
// get size of hash table
int GetHashSize( void ) const;
// get size of the index
int GetIndexSize( void ) const;
// set granularity
void SetGranularity( const int newGranularity );
// force resizing the index, current hash table stays intact
void ResizeIndex( const int newIndexSize );
// returns number in the range [0-100] representing the spread over the hash table
int GetSpread( void ) const;
// returns a key for a string
int GenerateKey( const char *string, bool caseSensitive = true ) const;
// returns a key for a vector
int GenerateKey( const idVec3 &v ) const;
// returns a key for two integers
int GenerateKey( const int n1, const int n2 ) const;
private:
int hashSize;
int * hash;
int indexSize;
int * indexChain;
int granularity;
int hashMask;
int lookupMask;
static int INVALID_INDEX[1];
void Init( const int initialHashSize, const int initialIndexSize );
void Allocate( const int newHashSize, const int newIndexSize );
};
/*
================
idHashIndex::idHashIndex
================
*/
ID_INLINE idHashIndex::idHashIndex( void ) {
Init( DEFAULT_HASH_SIZE, DEFAULT_HASH_SIZE );
}
/*
================
idHashIndex::idHashIndex
================
*/
ID_INLINE idHashIndex::idHashIndex( const int initialHashSize, const int initialIndexSize ) {
Init( initialHashSize, initialIndexSize );
}
/*
================
idHashIndex::~idHashIndex
================
*/
ID_INLINE idHashIndex::~idHashIndex( void ) {
Free();
}
/*
================
idHashIndex::Allocated
================
*/
ID_INLINE size_t idHashIndex::Allocated( void ) const {
return hashSize * sizeof( int ) + indexSize * sizeof( int );
}
/*
================
idHashIndex::Size
================
*/
ID_INLINE size_t idHashIndex::Size( void ) const {
return sizeof( *this ) + Allocated();
}
/*
================
idHashIndex::operator=
================
*/
ID_INLINE idHashIndex &idHashIndex::operator=( const idHashIndex &other ) {
granularity = other.granularity;
hashMask = other.hashMask;
lookupMask = other.lookupMask;
if ( other.lookupMask == 0 ) {
hashSize = other.hashSize;
indexSize = other.indexSize;
Free();
}
else {
if ( other.hashSize != hashSize || hash == INVALID_INDEX ) {
if ( hash != INVALID_INDEX ) {
delete[] hash;
}
hashSize = other.hashSize;
hash = new int[hashSize];
}
if ( other.indexSize != indexSize || indexChain == INVALID_INDEX ) {
if ( indexChain != INVALID_INDEX ) {
delete[] indexChain;
}
indexSize = other.indexSize;
indexChain = new int[indexSize];
}
memcpy( hash, other.hash, hashSize * sizeof( hash[0] ) );
memcpy( indexChain, other.indexChain, indexSize * sizeof( indexChain[0] ) );
}
return *this;
}
/*
================
idHashIndex::Add
================
*/
ID_INLINE void idHashIndex::Add( const int key, const int index ) {
int h;
assert( index >= 0 );
if ( hash == INVALID_INDEX ) {
Allocate( hashSize, index >= indexSize ? index + 1 : indexSize );
}
else if ( index >= indexSize ) {
ResizeIndex( index + 1 );
}
h = key & hashMask;
indexChain[index] = hash[h];
hash[h] = index;
}
/*
================
idHashIndex::Remove
================
*/
ID_INLINE void idHashIndex::Remove( const int key, const int index ) {
int k = key & hashMask;
if ( hash == INVALID_INDEX ) {
return;
}
if ( hash[k] == index ) {
hash[k] = indexChain[index];
}
else {
for ( int i = hash[k]; i != -1; i = indexChain[i] ) {
if ( indexChain[i] == index ) {
indexChain[i] = indexChain[index];
break;
}
}
}
indexChain[index] = -1;
}
/*
================
idHashIndex::First
================
*/
ID_INLINE int idHashIndex::First( const int key ) const {
return hash[key & hashMask & lookupMask];
}
/*
================
idHashIndex::Next
================
*/
ID_INLINE int idHashIndex::Next( const int index ) const {
assert( index >= 0 && index < indexSize );
return indexChain[index & lookupMask];
}
/*
================
idHashIndex::InsertIndex
================
*/
ID_INLINE void idHashIndex::InsertIndex( const int key, const int index ) {
int i, max;
if ( hash != INVALID_INDEX ) {
max = index;
for ( i = 0; i < hashSize; i++ ) {
if ( hash[i] >= index ) {
hash[i]++;
if ( hash[i] > max ) {
max = hash[i];
}
}
}
for ( i = 0; i < indexSize; i++ ) {
if ( indexChain[i] >= index ) {
indexChain[i]++;
if ( indexChain[i] > max ) {
max = indexChain[i];
}
}
}
if ( max >= indexSize ) {
ResizeIndex( max + 1 );
}
for ( i = max; i > index; i-- ) {
indexChain[i] = indexChain[i-1];
}
indexChain[index] = -1;
}
Add( key, index );
}
/*
================
idHashIndex::RemoveIndex
================
*/
ID_INLINE void idHashIndex::RemoveIndex( const int key, const int index ) {
int i, max;
Remove( key, index );
if ( hash != INVALID_INDEX ) {
max = index;
for ( i = 0; i < hashSize; i++ ) {
if ( hash[i] >= index ) {
if ( hash[i] > max ) {
max = hash[i];
}
hash[i]--;
}
}
for ( i = 0; i < indexSize; i++ ) {
if ( indexChain[i] >= index ) {
if ( indexChain[i] > max ) {
max = indexChain[i];
}
indexChain[i]--;
}
}
for ( i = index; i < max; i++ ) {
indexChain[i] = indexChain[i+1];
}
indexChain[max] = -1;
}
}
/*
================
idHashIndex::Clear
================
*/
ID_INLINE void idHashIndex::Clear( void ) {
// only clear the hash table because clearing the indexChain is not really needed
if ( hash != INVALID_INDEX ) {
memset( hash, 0xff, hashSize * sizeof( hash[0] ) );
}
}
/*
================
idHashIndex::Clear
================
*/
ID_INLINE void idHashIndex::Clear( const int newHashSize, const int newIndexSize ) {
Free();
hashSize = newHashSize;
indexSize = newIndexSize;
}
/*
================
idHashIndex::GetHashSize
================
*/
ID_INLINE int idHashIndex::GetHashSize( void ) const {
return hashSize;
}
/*
================
idHashIndex::GetIndexSize
================
*/
ID_INLINE int idHashIndex::GetIndexSize( void ) const {
return indexSize;
}
/*
================
idHashIndex::SetGranularity
================
*/
ID_INLINE void idHashIndex::SetGranularity( const int newGranularity ) {
assert( newGranularity > 0 );
granularity = newGranularity;
}
/*
================
idHashIndex::GenerateKey
================
*/
ID_INLINE int idHashIndex::GenerateKey( const char *string, bool caseSensitive ) const {
if ( caseSensitive ) {
return ( idStr::Hash( string ) & hashMask );
} else {
return ( idStr::IHash( string ) & hashMask );
}
}
/*
================
idHashIndex::GenerateKey
================
*/
ID_INLINE int idHashIndex::GenerateKey( const idVec3 &v ) const {
return ( (((int) v[0]) + ((int) v[1]) + ((int) v[2])) & hashMask );
}
/*
================
idHashIndex::GenerateKey
================
*/
ID_INLINE int idHashIndex::GenerateKey( const int n1, const int n2 ) const {
return ( ( n1 + n2 ) & hashMask );
}
#endif /* !__HASHINDEX_H__ */