319 lines
6.7 KiB
C++
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;
|
|
}
|
|
}
|