mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-30 16:11:11 +00:00
736ec20d4d
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.
408 lines
10 KiB
C++
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__ */
|