Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
625 lines
14 KiB
C++
625 lines
14 KiB
C++
//===========================================================================//
|
|
// File: hash.cc //
|
|
// Project: MUNGA Brick: Connection Library //
|
|
// Contents: Implementation details of Hash class //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 12/15/94 ECH Initial coding. //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
|
// PROPRIETARY AND CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "StuffHeaders.hpp"
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ Hash ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
//
|
|
//###########################################################################
|
|
// Hash
|
|
//###########################################################################
|
|
//
|
|
Hash::Hash(
|
|
unsigned size,
|
|
void *node,
|
|
bool has_unique_entries
|
|
):
|
|
SortedSocket(NULL, has_unique_entries)
|
|
{
|
|
//
|
|
// If the size is not prime, warn and select new size
|
|
//
|
|
#if defined(_ARMOR)
|
|
if (!CheckForPrimeSize(size))
|
|
{
|
|
while (!CheckForPrimeSize(size))
|
|
size++;
|
|
PAUSE(("Non-prime hash table, correct size is %d", size));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
//---------------------
|
|
// Initialize the table
|
|
//---------------------
|
|
//
|
|
m_hashTable.SetLength(size);
|
|
for (unsigned i=0; i<size; i++)
|
|
{
|
|
m_hashTable[i] = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// ~Hash
|
|
//###########################################################################
|
|
//
|
|
Hash::~Hash()
|
|
{
|
|
Check_Object(this);
|
|
int i;
|
|
|
|
for (i=0; i<m_hashTable.GetLength(); i++)
|
|
{
|
|
if (m_hashTable[i] != NULL)
|
|
{
|
|
Check_Object(m_hashTable[i]);
|
|
delete m_hashTable[i];
|
|
}
|
|
}
|
|
m_hashTable.SetLength(0);
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// TestInstance
|
|
//###########################################################################
|
|
//
|
|
void
|
|
Hash::TestInstance()
|
|
{
|
|
SortedSocket::TestInstance();
|
|
Verify(m_hashTable.GetLength() > 0);
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// DeletePlugs
|
|
//###########################################################################
|
|
//
|
|
void
|
|
Hash::DeletePlugs()
|
|
{
|
|
Check_Object(this);
|
|
int i;
|
|
|
|
for (i=0; i<m_hashTable.GetLength(); i++)
|
|
{
|
|
if (m_hashTable[i] != NULL)
|
|
{
|
|
Check_Object(m_hashTable[i]);
|
|
m_hashTable[i]->DeletePlugs();
|
|
delete m_hashTable[i];
|
|
m_hashTable[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// GetNthItem
|
|
//###########################################################################
|
|
//
|
|
void*
|
|
Hash::GetNthItem(unsigned index)
|
|
{
|
|
STOP(("Not implemented"));
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// GetSize
|
|
//###########################################################################
|
|
//
|
|
unsigned
|
|
Hash::GetSize()
|
|
{
|
|
Check_Object(this);
|
|
HashIterator iterator(this);
|
|
unsigned i = 0;
|
|
|
|
while (iterator.ReadAndNextItem() != NULL)
|
|
i++;
|
|
return i;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// IsEmpty
|
|
//#############################################################################
|
|
//
|
|
bool
|
|
Hash::IsEmpty()
|
|
{
|
|
Check_Object(this);
|
|
|
|
for (int i = 0; i < m_hashTable.GetLength(); i++)
|
|
{
|
|
if (m_hashTable[i] != NULL)
|
|
{
|
|
if (!m_hashTable[i]->IsEmpty())
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// AddValueImplementation
|
|
//###########################################################################
|
|
//
|
|
void
|
|
Hash::AddValuePlug(
|
|
Plug *plug,
|
|
const void *value
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(plug);
|
|
Check_Pointer(value);
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// Verify that value has not been added
|
|
//-------------------------------------------------------------
|
|
//
|
|
Verify(HasUniqueEntries() ? (FindPlug(value) == NULL) : true);
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// Find hash entry
|
|
//-------------------------------------------------------------
|
|
//
|
|
unsigned index = GetHashIndex(value);
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// Get vchain for this index
|
|
//-------------------------------------------------------------
|
|
//
|
|
SortedChain *vchain;
|
|
if ((vchain = m_hashTable[index]) == NULL)
|
|
{
|
|
vchain = MakeSortedChain();
|
|
Check_Object(vchain);
|
|
m_hashTable[index] = vchain;
|
|
}
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// Add to the vchain
|
|
//-------------------------------------------------------------
|
|
//
|
|
Check_Object(vchain);
|
|
vchain->AddValuePlug(plug, value);
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// FindPlug
|
|
//###########################################################################
|
|
//
|
|
Plug*
|
|
Hash::FindPlug(
|
|
const void *value
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(value);
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// Find hash entry
|
|
//-------------------------------------------------------------
|
|
//
|
|
unsigned index;
|
|
|
|
index = GetHashIndex(value);
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// Get vchain for this index
|
|
//-------------------------------------------------------------
|
|
//
|
|
SortedChain *vchain;
|
|
if ((vchain = m_hashTable[index]) == NULL)
|
|
return NULL;
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// Find in vchain
|
|
//-------------------------------------------------------------
|
|
//
|
|
Check_Object(vchain);
|
|
return vchain->FindPlug(value);
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// CheckForPrimeSize
|
|
//###########################################################################
|
|
//
|
|
bool
|
|
Hash::CheckForPrimeSize(unsigned size)
|
|
{
|
|
Check_Signature(this);
|
|
Verify(size > 2);
|
|
|
|
unsigned upper_bound =
|
|
static_cast<unsigned>(Sqrt(static_cast<Scalar>(size)));
|
|
|
|
for (unsigned i = 2; i < upper_bound; i++)
|
|
{
|
|
if ((size % i) == 0)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ HashIterator ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
const unsigned HashIteratorNullPosition = -1;
|
|
|
|
//
|
|
//###########################################################################
|
|
// HashIterator
|
|
//###########################################################################
|
|
//
|
|
HashIterator::HashIterator(Hash *hash):
|
|
SortedIterator(hash)
|
|
{
|
|
m_currentPosition = HashIteratorNullPosition;
|
|
m_vchainIterator = NULL;
|
|
First();
|
|
}
|
|
|
|
Iterator*
|
|
HashIterator::MakeClone()
|
|
{
|
|
Check_Object(this);
|
|
return new(g_Heap) HashIterator(*this);
|
|
}
|
|
|
|
HashIterator::~HashIterator()
|
|
{
|
|
Check_Object(this);
|
|
m_currentPosition = HashIteratorNullPosition;
|
|
DeleteSortedChainIterator();
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// TestInstance
|
|
//###########################################################################
|
|
//
|
|
void
|
|
HashIterator::TestInstance()
|
|
{
|
|
SortedIterator::TestInstance();
|
|
if (m_vchainIterator != NULL)
|
|
{
|
|
Check_Object(m_vchainIterator);
|
|
}
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// First
|
|
//###########################################################################
|
|
//
|
|
Iterator&
|
|
HashIterator::First()
|
|
{
|
|
Check_Object(this);
|
|
NextSortedChainIterator(0);
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// Last
|
|
//###########################################################################
|
|
//
|
|
Iterator&
|
|
HashIterator::Last()
|
|
{
|
|
Check_Object(this);
|
|
STOP(("Shouldn't reach here"));
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// Next
|
|
//###########################################################################
|
|
//
|
|
Iterator&
|
|
HashIterator::Next()
|
|
{
|
|
Check_Object(this);
|
|
if (m_vchainIterator != NULL)
|
|
{
|
|
Check_Object(m_vchainIterator);
|
|
|
|
if (m_vchainIterator->GetCurrentPlug() != NULL)
|
|
{
|
|
//
|
|
// Try to step to the next item in this list
|
|
//
|
|
m_vchainIterator->Next();
|
|
}
|
|
if (m_vchainIterator->GetCurrentPlug() == NULL)
|
|
{
|
|
//
|
|
// At end of list, step to the next list
|
|
//
|
|
NextSortedChainIterator(m_currentPosition+1);
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// Previous
|
|
//###########################################################################
|
|
//
|
|
Iterator&
|
|
HashIterator::Previous()
|
|
{
|
|
Check_Object(this);
|
|
STOP(("Not implemented"));
|
|
return *this;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// ReadAndNextItem
|
|
//###########################################################################
|
|
//
|
|
void*
|
|
HashIterator::ReadAndNextItem()
|
|
{
|
|
Check_Object(this);
|
|
void *result = NULL;
|
|
if (m_vchainIterator != NULL)
|
|
{
|
|
Check_Object(m_vchainIterator);
|
|
if (m_vchainIterator->GetCurrentPlug() != NULL)
|
|
{
|
|
result = m_vchainIterator->GetCurrentPlug();
|
|
m_vchainIterator->Next();
|
|
}
|
|
|
|
//
|
|
// List was emptied, step to next list
|
|
//
|
|
else
|
|
{
|
|
NextSortedChainIterator(m_currentPosition+1);
|
|
if (m_vchainIterator != NULL)
|
|
{
|
|
Check_Object(m_vchainIterator);
|
|
Verify(m_vchainIterator->GetCurrentPlug() != NULL);
|
|
result = m_vchainIterator->GetCurrentPlug();
|
|
m_vchainIterator->Next();
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// Previous
|
|
//###########################################################################
|
|
//
|
|
void*
|
|
HashIterator::ReadAndPreviousItem()
|
|
{
|
|
Check_Object(this);
|
|
void *result = GetCurrentItem();
|
|
HashIterator::Previous();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// GetCurrentImplementation
|
|
//###########################################################################
|
|
//
|
|
void
|
|
*HashIterator::GetCurrentItem()
|
|
{
|
|
Check_Object(this);
|
|
if (m_vchainIterator != NULL)
|
|
{
|
|
Check_Object(m_vchainIterator);
|
|
|
|
if (m_vchainIterator->GetCurrentPlug() != NULL)
|
|
{
|
|
return m_vchainIterator->GetCurrentPlug();
|
|
}
|
|
|
|
//
|
|
// List was emptied, step to next list
|
|
//
|
|
NextSortedChainIterator(m_currentPosition+1);
|
|
|
|
if (m_vchainIterator != NULL)
|
|
{
|
|
Check_Object(m_vchainIterator);
|
|
Verify(m_vchainIterator->GetCurrentPlug() != NULL);
|
|
return m_vchainIterator->GetCurrentPlug();
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// GetNthItem
|
|
//###########################################################################
|
|
//
|
|
void*
|
|
HashIterator::GetNthItem(unsigned index)
|
|
{
|
|
unsigned i = 0;
|
|
|
|
NextSortedChainIterator(0);
|
|
while (m_vchainIterator != NULL)
|
|
{
|
|
Check_Object(m_vchainIterator);
|
|
|
|
while (m_vchainIterator->GetCurrentPlug() != NULL)
|
|
{
|
|
if (i == index)
|
|
return m_vchainIterator->GetCurrentPlug();
|
|
m_vchainIterator->Next();
|
|
i++;
|
|
}
|
|
|
|
//
|
|
// List was emptied, step to next list
|
|
//
|
|
NextSortedChainIterator(m_currentPosition+1);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// Remove
|
|
//###########################################################################
|
|
//
|
|
void
|
|
HashIterator::Remove()
|
|
{
|
|
Check_Object(this);
|
|
if (m_vchainIterator != NULL)
|
|
{
|
|
Check_Object(m_vchainIterator);
|
|
|
|
if (m_vchainIterator->GetCurrentPlug() != NULL)
|
|
{
|
|
m_vchainIterator->Remove();
|
|
return;
|
|
}
|
|
|
|
//
|
|
// List was emptied, step to next list
|
|
//
|
|
NextSortedChainIterator(m_currentPosition+1);
|
|
|
|
if (m_vchainIterator != NULL)
|
|
{
|
|
Check_Object(m_vchainIterator);
|
|
m_vchainIterator->Remove();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// FindPlug
|
|
//###########################################################################
|
|
//
|
|
Plug
|
|
*HashIterator::FindPlug(
|
|
const void*
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
STOP(("Not implemented"));
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
// GetPlugValue
|
|
//###########################################################################
|
|
//
|
|
void*
|
|
HashIterator::GetPlugValue()
|
|
{
|
|
Check_Object(this);
|
|
STOP(("Not implemented"));
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
//###########################################################################
|
|
//
|
|
void
|
|
HashIterator::DeleteSortedChainIterator()
|
|
{
|
|
if (m_vchainIterator != NULL)
|
|
{
|
|
Check_Object(m_vchainIterator);
|
|
delete m_vchainIterator;
|
|
m_vchainIterator = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
//###########################################################################
|
|
//###########################################################################
|
|
//
|
|
void
|
|
HashIterator::NextSortedChainIterator(unsigned index)
|
|
{
|
|
Check_Object(this);
|
|
int i;
|
|
|
|
DeleteSortedChainIterator();
|
|
m_currentPosition = HashIteratorNullPosition;
|
|
DynamicArrayOf<SortedChain*> &hash_table =
|
|
Cast_Object(Hash*, m_socket)->m_hashTable;
|
|
|
|
for (i = index; i < hash_table.GetLength(); i++)
|
|
{
|
|
if (hash_table[i] != NULL)
|
|
{
|
|
//
|
|
// This index contains a vchain
|
|
//
|
|
Check_Object(hash_table[i]);
|
|
|
|
//
|
|
// Create a vchain iterator
|
|
//
|
|
m_vchainIterator = new(g_Heap) SortedChainIterator(hash_table[i]);
|
|
Check_Object(m_vchainIterator);
|
|
if (m_vchainIterator->GetCurrentPlug() != NULL)
|
|
{
|
|
//
|
|
// The vchain contains items
|
|
//
|
|
m_currentPosition = i;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Destroy the vchain iterator
|
|
//
|
|
DeleteSortedChainIterator();
|
|
}
|
|
}
|
|
}
|