/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program 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. ** ** This program 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 this program. If not, see . */ /*********************************************************************************************** *** Confidential - Westwood Studios *** *********************************************************************************************** * * * Project Name : Commando * * * * $Archive:: /Commando/Code/wwlib/hashtemplate.h $* * * * Author:: Greg_h * * * * $Modtime:: 11/19/01 12:16p $* * * * $Revision:: 7 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #if defined(_MSC_VER) #pragma once #endif #ifndef HASH_TEMPLATE_H #define HASH_TEMPLATE_H #include "always.h" #include "wwstring.h" // Class for providing hash values template class HashTemplateKeyClass { public: static inline unsigned int Get_Hash_Value (const Key& k); }; // Default hash function for data types that can be cast into an unsigned int template inline unsigned int HashTemplateKeyClass::Get_Hash_Value (const Key& k) { unsigned int hval = *((const unsigned int*)(&k)); hval = hval + (hval>>5) + (hval>>10) + (hval >> 20); return hval; } // Specialization for floating point hash values (as the default dword- // casting yields a very bad hash function) template <> inline unsigned int HashTemplateKeyClass::Get_Hash_Value (const float& s) { unsigned int z = *((const unsigned int*)(&s)); return ((z>>22)+(z>>12)+(z)); } // Hash class template class HashTemplateClass { struct Entry; public: enum { NIL = -1 // internal enumeration for representing a NULL link }; HashTemplateClass(void); ~HashTemplateClass(void); void Insert(const KeyType& s, const ValueType& d); void Set_Value(const KeyType& s, const ValueType& d); void Remove(const KeyType& s); void Remove(const KeyType& s, const ValueType& d); ValueType Get(const KeyType& s) const; bool Get(const KeyType& s, ValueType& d) const; bool Exists(const KeyType& s) const; bool Exists(const KeyType& s, const ValueType& d) const; void Remove_All(void); unsigned int Get_Size(void) const; int* Get_Hash() { return Hash; } Entry* Get_Table() { return Table; } private: HashTemplateClass (const HashTemplateClass&); // not allowed HashTemplateClass& operator= (const HashTemplateClass&); // not allowed static unsigned int Get_Hash_Val(const KeyType& s, const unsigned int hash_array_size); void Re_Hash(void); int Alloc_Entry(void); struct Entry { int Next; // next pointer in linked list KeyType Key; // key ValueType Value; // value }; int* Hash; // hash pointers Entry* Table; // allocation table int First; // handle of first free entry unsigned int Size; // size of hash table }; template class HashTemplateIterator { int HashIndex; // index to hash pointer table int Handle; HashTemplateClass& HashTable; public: HashTemplateIterator(HashTemplateClass& hash_table) : HashTable(hash_table) { First(); } void First() { Handle=HashTemplateClass::NIL; int size=HashTable.Get_Size(); for (HashIndex=0;HashIndex::NIL) break; } } void Next() { Handle=HashTable.Get_Table()[Handle].Next; if (Handle==HashTemplateClass::NIL) { int size=HashTable.Get_Size(); for (++HashIndex;HashIndex::NIL) break; } } } bool Is_Done() const { return HashIndex==int(HashTable.Get_Size()); } ValueType& Peek_Value() { return HashTable.Get_Table()[Handle].Value; } const KeyType& Peek_Key() { return HashTable.Get_Table()[Handle].Key; } }; //------------------------------------------------------------------------ // Implementation //------------------------------------------------------------------------ template inline void HashTemplateClass::Insert(const KeyType& s, const ValueType& d) { int h; h = Alloc_Entry(); unsigned int hval = Get_Hash_Val(s,Size); Table[h].Key = s; Table[h].Value = d; Table[h].Next = Hash[hval]; Hash[hval] = h; } template inline unsigned int HashTemplateClass::Get_Size (void) const { return Size; } template inline void HashTemplateClass::Remove_All (void) { for (unsigned int i = 0; i < Size; i++) { int f = Hash[i]; if (f!=NIL) { int h = f; while (Table[h].Next != NIL) h = Table[h].Next; Table[h].Next = First; // link to first free First = f; // link to beginning Hash[i] = NIL; // kill entry in hash } } } template inline void HashTemplateClass::Remove (const KeyType& s) { if (!Hash) return; unsigned int hval = Get_Hash_Val(s,Size); int prev = NIL; int h = Hash[hval]; while (h != NIL) { if (Table[h].Key == s) { if (prev!=NIL) Table[prev].Next = Table[h].Next; else Hash[hval] = Table[h].Next; Table[h].Next = First; First = h; return; } prev = h; h = Table[h].Next; } } template inline void HashTemplateClass::Remove (const KeyType& s, const ValueType& d) { if (!Hash) return; unsigned int hval = Get_Hash_Val(s,Size); int prev = NIL; int h = Hash[hval]; while (h != NIL) { if (Table[h].Key == s && Table[h].Value == d) { if (prev!=NIL) Table[prev].Next = Table[h].Next; else Hash[hval] = Table[h].Next; Table[h].Next = First; First = h; return; } prev = h; h = Table[h].Next; } } // Set the value at existing key, or if not found insert a new value template inline void HashTemplateClass::Set_Value (const KeyType& s, const ValueType& v) { if (Hash) { int h = Hash[Get_Hash_Val(s,Size)]; while (h!=NIL) { if (Table[h].Key == s) { Table[h].Value=v; return; } h = Table[h].Next; } } Insert(s,v); } template inline ValueType HashTemplateClass::Get (const KeyType& s) const { if (Hash) { int h = Hash[Get_Hash_Val(s,Size)]; while (h!=NIL) { if (Table[h].Key == s) return Table[h].Value; h = Table[h].Next; } } return ValueType(0); } template inline bool HashTemplateClass::Get(const KeyType& s, ValueType& d) const { if (Hash) { int h = Hash[Get_Hash_Val(s,Size)]; while (h!=NIL) { if (Table[h].Key == s) { d = Table[h].Value; return true; } h = Table[h].Next; } } return false; } template inline bool HashTemplateClass::Exists(const KeyType& s) const { if (Hash) { int h = Hash[Get_Hash_Val(s,Size)]; while (h!=NIL) { if (Table[h].Key == s) return true; h = Table[h].Next; } } return false; } template inline bool HashTemplateClass::Exists(const KeyType& s, const ValueType& d) const { if (Hash) { int h = Hash[Get_Hash_Val(s,Size)]; while (h!=NIL) { if (Table[h].Key == s && Table[h].Value == d) return true; h = Table[h].Next; } } return false; } template inline unsigned int HashTemplateClass::Get_Hash_Val(const KeyType& s, const unsigned int hash_array_size) { return HashTemplateKeyClass::Get_Hash_Value (s) & (hash_array_size-1); } template inline void HashTemplateClass::Re_Hash() { unsigned int new_size = Size*2; if (new_size < 4) new_size = 4; Entry *new_table = new Entry[new_size]; int *new_hash = new int[new_size]; int cnt = 0; int i; for (i = 0; i < (int)new_size; i++) { new_table[i].Next = NIL; new_hash[i] = NIL; } if (Size) // if we have existing data, it needs to be rehashed { for (i = 0; i < (int)Size; i++) // step through each old hash set { int h = Hash[i]; while (h != NIL) { unsigned int hVal = Get_Hash_Val(Table[h].Key, new_size); new_table[cnt].Key = Table[h].Key; new_table[cnt].Value = Table[h].Value; new_table[cnt].Next = new_hash[hVal]; new_hash[hVal] = cnt; cnt++; h = Table[h].Next; } } delete[] Hash; delete[] Table; } for (i = cnt; i < (int)new_size; i++) new_table[i].Next = i+1; new_table[new_size-1].Next = NIL; First = cnt; Hash = new_hash; Table = new_table; Size = new_size; } template inline int HashTemplateClass::Alloc_Entry() { if (First == NIL) // need to re-alloc and re-hash tables Re_Hash(); int h = First; First = Table[First].Next; return h; } template inline HashTemplateClass::HashTemplateClass() : Hash(0),Table(0),First(NIL),Size(0) { // Re_Hash(); } template inline HashTemplateClass::~HashTemplateClass() { if (Hash) delete[] Hash; if (Table) delete[] Table; } // Get_Hash_Value specialization for StringClass. This is intended to be used // for filenames, so it takes into account the four characters that come before // the file extension (.xxx - extension expected to be 4 characters). template <> inline unsigned int HashTemplateKeyClass::Get_Hash_Value(const StringClass& s) { unsigned int len=s.Get_Length(); unsigned char* buffer=(unsigned char*)s.Peek_Buffer(); if (len<8) { unsigned int hval=0; for (unsigned int a=0;a>5) + (hval>>10) + (hval >> 20); return hval; } #endif