390 lines
9.4 KiB
C++
390 lines
9.4 KiB
C++
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// File: hashtab.cpp
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// Abstract: Implementation of Template CHashTable64<> and class CHashTable64PVOID.
|
||
|
//
|
||
|
// NOTE: The keys 0 and ~0 are both reserved for internal use.
|
||
|
//
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <winlean.h>
|
||
|
#include "hashtab.h"
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
#undef EMPTY
|
||
|
#undef DELETED
|
||
|
#define EMPTY 0
|
||
|
#define DELETED ~0u
|
||
|
|
||
|
CHashTable32PVOID::CHashTable32PVOID()
|
||
|
{
|
||
|
m_pTable = NULL;
|
||
|
m_nSize = 0;
|
||
|
m_nValid = 0;
|
||
|
}
|
||
|
|
||
|
CHashTable32PVOID::CHashTable32PVOID(INT nInitialSize)
|
||
|
{
|
||
|
m_pTable = NULL;
|
||
|
m_nSize = 0;
|
||
|
m_nValid = 0;
|
||
|
Resize(nInitialSize);
|
||
|
}
|
||
|
|
||
|
CHashTable32PVOID::~CHashTable32PVOID()
|
||
|
{
|
||
|
if (m_pTable) {
|
||
|
delete[] m_pTable;
|
||
|
m_pTable = NULL;
|
||
|
}
|
||
|
m_nSize = 0;
|
||
|
m_nValid = 0;
|
||
|
}
|
||
|
|
||
|
CHashTable32PVOID::Entry * CHashTable32PVOID::FindEntry(UINT32 key)
|
||
|
{
|
||
|
if (key == EMPTY || key == DELETED || m_nSize <= 0) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
INT offset = Offset(key);
|
||
|
INT orig_offset = offset;
|
||
|
|
||
|
for (;;) {
|
||
|
if (m_pTable[offset].key == EMPTY) {
|
||
|
break; // EMPTY, stop.
|
||
|
}
|
||
|
else if (m_pTable[offset].key == key) { // Match, return TRUE
|
||
|
if (offset != orig_offset) { // Increase locality.
|
||
|
Swap(m_pTable[offset], m_pTable[orig_offset]);
|
||
|
offset = orig_offset;
|
||
|
}
|
||
|
return &m_pTable[offset];
|
||
|
}
|
||
|
else { // Not, try next bucket.
|
||
|
offset = (offset + 1) % m_nSize;
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
PVOID CHashTable32PVOID::Find(UINT32 key)
|
||
|
{
|
||
|
Entry *pEntry = FindEntry(key);
|
||
|
return pEntry ? pEntry->value : NULL;
|
||
|
}
|
||
|
|
||
|
BOOL CHashTable32PVOID::Change(UINT32 key, PVOID value)
|
||
|
{
|
||
|
Entry *pEntry = FindEntry(key);
|
||
|
if (pEntry) {
|
||
|
pEntry->value = value;
|
||
|
return TRUE;
|
||
|
}
|
||
|
return Insert(key, value);
|
||
|
}
|
||
|
|
||
|
BOOL CHashTable32PVOID::Insert(UINT32 key, PVOID value)
|
||
|
{
|
||
|
if (key == EMPTY || key == DELETED) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ((m_nValid + 1) > (m_nSize / 2)) { // Table is never > 1/2 full!
|
||
|
if (m_nSize == 0) {
|
||
|
if (!Resize(32))
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
if (!Resize(m_nSize * 2))
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
INT offset = Offset(key);
|
||
|
|
||
|
for (;;) {
|
||
|
if (m_pTable[offset].key == EMPTY || m_pTable[offset].key == DELETED) {
|
||
|
// EMPTY, Insert
|
||
|
m_pTable[offset].key = key;
|
||
|
m_pTable[offset].value = value;
|
||
|
m_nValid++;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else { // Not, try next bucket.
|
||
|
offset = (offset + 1) % m_nSize;
|
||
|
}
|
||
|
}
|
||
|
// return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CHashTable32PVOID::Delete(UINT32 key)
|
||
|
{
|
||
|
if (key == EMPTY || key == DELETED) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (m_nSize == 0) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
INT offset = Offset(key);
|
||
|
|
||
|
// First, find the value.
|
||
|
for (;;) {
|
||
|
if (m_pTable[offset].key == EMPTY) { // EMPTY, stop.
|
||
|
return FALSE;
|
||
|
}
|
||
|
else if (m_pTable[offset].key == key) { // Match, return TRUE
|
||
|
m_pTable[offset].key = DELETED;
|
||
|
m_pTable[offset].value = 0;
|
||
|
m_nValid--;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else { // Not, try next bucket.
|
||
|
offset = (offset + 1) % m_nSize;
|
||
|
}
|
||
|
}
|
||
|
// return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CHashTable32PVOID::Resize(INT nNewSize)
|
||
|
{
|
||
|
Entry *pOldTable = m_pTable;
|
||
|
INT nOldSize = m_nSize;
|
||
|
|
||
|
m_pTable = new Entry[nNewSize];
|
||
|
if (m_pTable == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
for (INT i = 0; i < nNewSize; i++) {
|
||
|
m_pTable[i].key = EMPTY;
|
||
|
m_pTable[i].value = 0;
|
||
|
}
|
||
|
|
||
|
m_nSize = nNewSize;
|
||
|
m_nValid = 0;
|
||
|
|
||
|
if (pOldTable) {
|
||
|
for (INT i = 0; i < nOldSize; i++) {
|
||
|
if (pOldTable[i].key != EMPTY && pOldTable[i].key != DELETED) {
|
||
|
Insert(pOldTable[i].key, pOldTable[i].value);
|
||
|
}
|
||
|
}
|
||
|
delete[] pOldTable;
|
||
|
pOldTable = NULL;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
PVOID CHashTable32PVOID::Enumerate(UINT32& key, INT& nIterator)
|
||
|
{
|
||
|
for (; (INT)nIterator < m_nSize; nIterator++) {
|
||
|
if (m_pTable[nIterator].key == EMPTY ||
|
||
|
m_pTable[nIterator].key == DELETED) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
key = m_pTable[nIterator].key;
|
||
|
return m_pTable[nIterator++].value;
|
||
|
}
|
||
|
|
||
|
key = EMPTY;
|
||
|
nIterator = 0;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#undef EMPTY
|
||
|
#undef DELETED
|
||
|
#define EMPTY 0
|
||
|
#define DELETED ~0uI64
|
||
|
|
||
|
CHashTable64PVOID::CHashTable64PVOID()
|
||
|
{
|
||
|
m_pTable = NULL;
|
||
|
m_nSize = 0;
|
||
|
m_nValid = 0;
|
||
|
}
|
||
|
|
||
|
CHashTable64PVOID::CHashTable64PVOID(INT nInitialSize)
|
||
|
{
|
||
|
m_pTable = NULL;
|
||
|
m_nSize = 0;
|
||
|
m_nValid = 0;
|
||
|
Resize(nInitialSize);
|
||
|
}
|
||
|
|
||
|
CHashTable64PVOID::~CHashTable64PVOID()
|
||
|
{
|
||
|
if (m_pTable) {
|
||
|
delete[] m_pTable;
|
||
|
m_pTable = NULL;
|
||
|
}
|
||
|
m_nSize = 0;
|
||
|
m_nValid = 0;
|
||
|
}
|
||
|
|
||
|
CHashTable64PVOID::Entry * CHashTable64PVOID::FindEntry(UINT64 key)
|
||
|
{
|
||
|
if (key == EMPTY || key == DELETED || m_nSize <= 0) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
INT offset = Offset(key);
|
||
|
INT orig_offset = offset;
|
||
|
|
||
|
for (;;) {
|
||
|
if (m_pTable[offset].key == EMPTY) {
|
||
|
break; // EMPTY, stop.
|
||
|
}
|
||
|
else if (m_pTable[offset].key == key) { // Match, return TRUE
|
||
|
if (offset != orig_offset) { // Increase locality.
|
||
|
Swap(m_pTable[offset], m_pTable[orig_offset]);
|
||
|
offset = orig_offset;
|
||
|
}
|
||
|
return &m_pTable[offset];
|
||
|
}
|
||
|
else { // Not, try next bucket.
|
||
|
offset = (offset + 1) % m_nSize;
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
PVOID CHashTable64PVOID::Find(UINT64 key)
|
||
|
{
|
||
|
Entry *pEntry = FindEntry(key);
|
||
|
return pEntry ? pEntry->value : NULL;
|
||
|
}
|
||
|
|
||
|
BOOL CHashTable64PVOID::Change(UINT64 key, PVOID value)
|
||
|
{
|
||
|
Entry *pEntry = FindEntry(key);
|
||
|
if (pEntry) {
|
||
|
pEntry->value = value;
|
||
|
return TRUE;
|
||
|
}
|
||
|
return Insert(key, value);
|
||
|
}
|
||
|
|
||
|
BOOL CHashTable64PVOID::Insert(UINT64 key, PVOID value)
|
||
|
{
|
||
|
if (key == EMPTY || key == DELETED) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ((m_nValid + 1) > (m_nSize / 2)) { // Table is never > 1/2 full!
|
||
|
if (m_nSize == 0) {
|
||
|
if (!Resize(32))
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
if (!Resize(m_nSize * 2))
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
INT offset = Offset(key);
|
||
|
|
||
|
for (;;) {
|
||
|
|
||
|
if (m_pTable[offset].key == EMPTY || m_pTable[offset].key == DELETED) {
|
||
|
// EMPTY, Insert
|
||
|
m_pTable[offset].key = key;
|
||
|
m_pTable[offset].value = value;
|
||
|
m_nValid++;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else { // Not, try next bucket.
|
||
|
offset = (offset + 1) % m_nSize;
|
||
|
}
|
||
|
}
|
||
|
// return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CHashTable64PVOID::Delete(UINT64 key)
|
||
|
{
|
||
|
if (key == EMPTY || key == DELETED) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (m_nSize == 0) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
INT offset = Offset(key);
|
||
|
|
||
|
// First, find the value.
|
||
|
for (;;) {
|
||
|
if (m_pTable[offset].key == EMPTY) { // EMPTY, stop.
|
||
|
return FALSE;
|
||
|
}
|
||
|
else if (m_pTable[offset].key == key) { // Match, return TRUE
|
||
|
m_pTable[offset].key = DELETED;
|
||
|
m_pTable[offset].value = 0;
|
||
|
m_nValid--;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else { // Not, try next bucket.
|
||
|
offset = (offset + 1) % m_nSize;
|
||
|
}
|
||
|
}
|
||
|
// return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL CHashTable64PVOID::Resize(INT nNewSize)
|
||
|
{
|
||
|
Entry *pOldTable = m_pTable;
|
||
|
INT nOldSize = m_nSize;
|
||
|
|
||
|
m_pTable = new Entry[nNewSize];
|
||
|
if (m_pTable == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
for (INT i = 0; i < nNewSize; i++) {
|
||
|
m_pTable[i].key = EMPTY;
|
||
|
m_pTable[i].value = 0;
|
||
|
}
|
||
|
|
||
|
m_nSize = nNewSize;
|
||
|
m_nValid = 0;
|
||
|
|
||
|
if (pOldTable) {
|
||
|
for (INT i = 0; i < nOldSize; i++) {
|
||
|
if (pOldTable[i].key != EMPTY && pOldTable[i].key != DELETED) {
|
||
|
Insert(pOldTable[i].key, pOldTable[i].value);
|
||
|
}
|
||
|
}
|
||
|
delete[] pOldTable;
|
||
|
pOldTable = NULL;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
PVOID CHashTable64PVOID::Enumerate(UINT64& key, INT& nIterator)
|
||
|
{
|
||
|
for (; (INT)nIterator < m_nSize; nIterator++) {
|
||
|
if (m_pTable[nIterator].key == EMPTY ||
|
||
|
m_pTable[nIterator].key == DELETED) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
key = m_pTable[nIterator].key;
|
||
|
return m_pTable[nIterator++].value;
|
||
|
}
|
||
|
|
||
|
key = EMPTY;
|
||
|
nIterator = 0;
|
||
|
return NULL;
|
||
|
}
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////// End of File.
|