mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2026-04-29 12:26:59 +02:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
** 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
*** 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 Key> 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 <class Key> inline unsigned int HashTemplateKeyClass<Key>::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<float>::Get_Hash_Value (const float& s)
|
||||
{
|
||||
unsigned int z = *((const unsigned int*)(&s));
|
||||
return ((z>>22)+(z>>12)+(z));
|
||||
}
|
||||
|
||||
// Hash class
|
||||
template <class KeyType, class ValueType>
|
||||
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 KeyType, class ValueType>
|
||||
class HashTemplateIterator
|
||||
{
|
||||
int HashIndex; // index to hash pointer table
|
||||
int Handle;
|
||||
HashTemplateClass<KeyType,ValueType>& HashTable;
|
||||
|
||||
public:
|
||||
HashTemplateIterator(HashTemplateClass<KeyType,ValueType>& hash_table)
|
||||
:
|
||||
HashTable(hash_table)
|
||||
{
|
||||
First();
|
||||
}
|
||||
|
||||
void First()
|
||||
{
|
||||
Handle=HashTemplateClass<KeyType,ValueType>::NIL;
|
||||
int size=HashTable.Get_Size();
|
||||
for (HashIndex=0;HashIndex<size;++HashIndex) {
|
||||
Handle = HashTable.Get_Hash()[HashIndex];
|
||||
if (Handle!=HashTemplateClass<KeyType,ValueType>::NIL) break;
|
||||
}
|
||||
}
|
||||
|
||||
void Next()
|
||||
{
|
||||
Handle=HashTable.Get_Table()[Handle].Next;
|
||||
if (Handle==HashTemplateClass<KeyType,ValueType>::NIL) {
|
||||
int size=HashTable.Get_Size();
|
||||
for (++HashIndex;HashIndex<size;++HashIndex) {
|
||||
Handle = HashTable.Get_Hash()[HashIndex];
|
||||
if (Handle!=HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline void HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline unsigned int HashTemplateClass<KeyType,ValueType>::Get_Size (void) const
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
template <class KeyType, class ValueType> inline void HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline void HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline void HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline void HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline ValueType HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline bool HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline bool HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline bool HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline unsigned int HashTemplateClass<KeyType,ValueType>::Get_Hash_Val(const KeyType& s, const unsigned int hash_array_size)
|
||||
{
|
||||
return HashTemplateKeyClass<KeyType>::Get_Hash_Value (s) & (hash_array_size-1);
|
||||
}
|
||||
|
||||
template <class KeyType, class ValueType> inline void HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline int HashTemplateClass<KeyType,ValueType>::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 <class KeyType, class ValueType> inline HashTemplateClass<KeyType,ValueType>::HashTemplateClass() : Hash(0),Table(0),First(NIL),Size(0)
|
||||
{
|
||||
// Re_Hash();
|
||||
}
|
||||
|
||||
template <class KeyType, class ValueType> inline HashTemplateClass<KeyType,ValueType>::~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<StringClass>::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<len;++a) {
|
||||
hval+=37*hval+buffer[a];
|
||||
}
|
||||
return hval;
|
||||
}
|
||||
unsigned int hval = *((const unsigned int*)(buffer+len-8));
|
||||
hval = hval + (hval>>5) + (hval>>10) + (hval >> 20);
|
||||
return hval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user