2025-11-27 16:46:48 +09:00

319 lines
6.7 KiB
C++

// HashTable.cpp: implementation of the COXHashTable class.
//
// Simple hash table class based on code in K&R's "The C programming
// language".
//
// Author: Chris Maunder
//
//////////////////////////////////////////////////////////////////////
// Version: 9.3
#include "stdafx.h"
#include "OXHashTable.h"
#include <malloc.h> // for free() (needed becuase of strdup())
// TODO: add API to traverse elements (FindFirst, FindNext and Count)
//////////////////////////////////////////////////////////////////////
// HashNode structure - auto initialise and cleanup
//////////////////////////////////////////////////////////////////////
HashNode::HashNode()
{
szName = NULL;
pNext = NULL;
dwData = 0;
}
HashNode::~HashNode()
{
if (szName)
free(szName);
}
//////////////////////////////////////////////////////////////////////
// COXHashTable - Construction/Destruction
//////////////////////////////////////////////////////////////////////
COXHashTable::COXHashTable(int nHashTableSize)
{
CommonConstruct(nHashTableSize);
}
COXHashTable::COXHashTable()
{
CommonConstruct(67);
}
BOOL COXHashTable::CommonConstruct(int nHashTableSize)
{
m_pHashTable = NULL;
m_nHashTableSize = 0;
m_bCaseSensitive = FALSE;
return InitHashTable(nHashTableSize);
}
COXHashTable::~COXHashTable()
{
RemoveAll();
delete [] m_pHashTable;
}
//////////////////////////////////////////////////////////////////////
// COXHashTable - Public Attributes
void COXHashTable::SetCaseSensitive(BOOL bCase)
{
m_bCaseSensitive = bCase;
}
BOOL COXHashTable::GetCaseSensitive()
{
return m_bCaseSensitive;
}
//////////////////////////////////////////////////////////////////////
// COXHashTable - Public Operations
BOOL COXHashTable::InitHashTable(UINT nHashSize)
{
if (nHashSize < 1)
return FALSE;
RemoveAll();
delete [] m_pHashTable;
m_nHashTableSize = nHashSize;
m_pHashTable = new HashNode*[m_nHashTableSize];
if (!m_pHashTable)
return FALSE;
for (UINT i = 0; i < m_nHashTableSize; i++)
m_pHashTable[i] = NULL;
return TRUE;
}
UINT COXHashTable::GetHashTableSize() const
{
return m_nHashTableSize;
}
void COXHashTable::RemoveAll()
{
if (!m_pHashTable)
return;
for (UINT i = 0; i < m_nHashTableSize; i++)
{
HashNode* pPrev = NULL;
HashNode* pNext = m_pHashTable[i];
while (pNext)
{
pPrev = pNext->pNext;
delete pNext;
pNext = pPrev;
}
m_pHashTable[i] = NULL;
}
}
BOOL COXHashTable::Add(LPCTSTR sz, DWORD dwData)
{
HashNode *pNode = Lookup(sz);
// Can't find entry - so add a new one
if (pNode == NULL)
{
// Create a new node with the given name
pNode = new HashNode;
if (pNode == NULL)
return FALSE;
// Copy over the string
pNode->szName = _tcsdup(sz);
if (pNode->szName == NULL)
{
delete pNode;
return FALSE;
}
// Find it's position in the hash table and insert it at the head of the
// list at that point
pNode->nHashValue = Hash(sz);
pNode->pNext = m_pHashTable[pNode->nHashValue];
m_pHashTable[pNode->nHashValue] = pNode;
}
// Set the data
pNode->dwData = dwData;
return TRUE;
}
BOOL COXHashTable::Lookup(LPCTSTR sz, DWORD& dwData) const
{
dwData = 0;
HashNode *pNode = Lookup(sz);
if (!pNode)
return FALSE;
dwData = pNode->dwData;
return TRUE;
}
BOOL COXHashTable::Remove(LPCTSTR sz)
{
HashNode *pNode, *pPrev = NULL;
UINT nHashVal = Hash(sz);
for (pNode = m_pHashTable[nHashVal]; pNode != NULL; pNode = pNode->pNext)
{
BOOL bFound = FALSE;
if (m_bCaseSensitive)
bFound = (_tcscmp(sz, pNode->szName) == 0);
else
bFound = (_tcsicmp(sz, pNode->szName) == 0);
if (bFound)
break;
pPrev = pNode;
}
// No entry found
if (pNode == NULL)
return FALSE;
if (pPrev == NULL) // Entry is first entry at Hash table entry site
{
m_pHashTable[nHashVal] = pNode->pNext;
delete pNode;
}
else // More than one entry with this hash val - remove entry from list
{
pPrev->pNext = pNode->pNext;
delete pNode;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// COXHashTable - protected implementation
UINT COXHashTable::Hash(LPCTSTR sz) const
{
UINT nHashVal = 0;
if (m_bCaseSensitive)
{
while (*sz)
nHashVal = (nHashVal<<5) + nHashVal + *sz++;
}
else
{
while (*sz)
{
if (_istupper(*sz))
nHashVal = (nHashVal<<5) + nHashVal + _tolower(*sz++);
else
nHashVal = (nHashVal<<5) + nHashVal + *sz++;
}
}
return nHashVal % m_nHashTableSize;
}
HashNode *COXHashTable::Lookup(LPCTSTR sz) const
{
HashNode *pNode;
UINT nHashVal = Hash(sz);
for (pNode = m_pHashTable[nHashVal]; pNode != NULL; pNode = pNode->pNext)
{
BOOL bFound = FALSE;
if (m_bCaseSensitive)
bFound = (_tcscmp(sz, pNode->szName) == 0);
else
bFound = (_tcsicmp(sz, pNode->szName) == 0);
if (bFound)
return pNode;
}
// Did not find.
return NULL;
}
HASH_POS COXHashTable::GetStartPosition() const
{
if (!m_pHashTable)
return NULL;
// Check there are elements
for (UINT nNode = 0; nNode < m_nHashTableSize; nNode++)
if (m_pHashTable[nNode])
return HASHTABLE_START_POS;
return NULL;
}
void COXHashTable::GetNextAssoc(HASH_POS& pos, LPCTSTR& sz, DWORD& dwData) const
{
if (!m_pHashTable || !pos)
{
pos = NULL;
return;
}
// If this is the first call, then find the first item
if (pos == HASHTABLE_START_POS)
{
pos = NULL;
for (UINT nNode = 0; nNode < m_nHashTableSize; nNode++)
{
if (m_pHashTable[nNode])
{
pos = m_pHashTable[nNode];
break;
}
}
}
// fill in return data
if (pos)
{
sz = pos->szName;
dwData = pos->dwData;
}
// Find the next item
if (pos)
{
HashNode* pNode = (HashNode*) pos;
if (pNode->pNext == NULL)
{
pos = NULL;
for (UINT nNode = pNode->nHashValue+1; nNode < m_nHashTableSize; nNode++)
{
if (m_pHashTable[nNode])
{
pos = m_pHashTable[nNode];
break;
}
}
}
else
pos = pNode->pNext;
}
}