2025-04-27 07:49:33 -04:00

283 lines
5.6 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996-1997 Microsoft Corporation
Module Name:
gentable.cxx
Abstract:
Implementation of the CResolverHashTable and friends.
Author:
Satish Thatte [SatishT] 02-12-96
--*/
#include<or.hxx>
// define the static members for page-based allocation
DEFINE_PAGE_ALLOCATOR(CResolverHashTable)
#if DBG
void
CResolverHashTable::IsValid()
{
ASSERT(_fInitialized == TRUE || _fInitialized == FALSE);
ASSERT(!_fInitialized || _cBuckets > 0);
ASSERT(_cBuckets > 0 || _cElements == 0);
ASSERT(_cBuckets >=0 && _cBuckets < MAX_BUCKETS);
if (_fInitialized)
{
for (USHORT i = 0; i < _cBuckets; i++)
{
_buckets[i].IsValid();
}
}
}
#endif
ORSTATUS
CResolverHashTable::PrivAdd( // never called before Init()
IN CTableElement *pElement
)
{
VALIDATE_METHOD
ORSTATUS status = OR_OK;
ISearchKey& sk = *pElement; // auto conversion to ISearchKey
DWORD hash = sk.Hash() % _cBuckets;
status = _buckets[hash].Insert(pElement);
if (status == OR_OK)
{
_cElements++;
}
return status;
}
CResolverHashTable::CResolverHashTable(UINT start_size)
{
_cBuckets = start_size;
_cElements = 0;
_buckets = NULL;
_fInitialized = FALSE;
VALIDATE_METHOD
}
ORSTATUS
CResolverHashTable::Init()
{
ORSTATUS status;
ASSERT(!_fInitialized);
VALIDATE_METHOD
_buckets = new (InSharedHeap) CTableElementList[_cBuckets];
if (NULL == _buckets)
{
status = OR_NOMEM;
}
else
{
status = OR_OK;
_fInitialized = TRUE;
}
return status;
}
CResolverHashTable::~CResolverHashTable()
{
RemoveAll();
if (_fInitialized)
{
ASSERT(_buckets != NULL);
DELETE_OR_ARRAY(CTableElementList,_buckets,_cBuckets);
}
}
CTableElement *
CResolverHashTable::Lookup(
IN ISearchKey &id
)
{
VALIDATE_METHOD
if (!_fInitialized) return NULL; // nothing to look in
DWORD hash = id.Hash();
hash %= _cBuckets;
return _buckets[hash].Find(id);
}
ORSTATUS
CResolverHashTable::Add(
IN CTableElement *pElement
)
{
VALIDATE_METHOD
ORSTATUS status = OR_OK;
if (!_fInitialized) status = Init(); // set up buckets
if (status != OR_OK) return status;
status = PrivAdd(pElement); // do the basic Add
if (status != OR_OK) return status;
if (_cElements > _cBuckets) // now see if the table is overpopulated
{
// Try to grow the table. If the allocation fails no need to worry,
// everything still works but might be a bit slower.
CTableElementList * psll;
psll = new (InSharedHeap) CTableElementList[_cBuckets * 2];
// The tricky part here is to avoid getting OR_NOMEM error while moving
// between tables. We do that by recycling the links in the old lists
if (psll)
{
UINT i, uiBucketsOld = _cBuckets;
CTableElement *pte;
CTableElementList::Link *pLink;
CTableElementList *psllOld = _buckets;
OrDbgDetailPrint(("OR: Growing table: %p\n", this));
// Change to the larger array of buckets.
_cBuckets *= 2;
_buckets = psll;
// Move every element from the old table into the large table.
for(i = 0; i < uiBucketsOld; i++)
{
while (pLink = psllOld[i].PopLink()) // uses specialized private operations
{ // to avoid both memory allocation
// and reference counting problems
ISearchKey& sk = *pLink->_pData; // auto conversion to ISearchKey
_buckets[sk.Hash() % _cBuckets].PushLink(pLink);
}
}
DELETE_OR_ARRAY(CTableElementList,psllOld,uiBucketsOld)
}
}
return status;
}
CTableElement *
CResolverHashTable::Remove(
IN ISearchKey &id
)
/*++
Routine Description:
Looks up and removes an element from the table.
Arguments:
id - The key to match the element to be removed
Return Value:
NULL - The element was not in the table
non-NULL - A pointer to the element which was removed.
--*/
{
VALIDATE_METHOD
if (!_fInitialized) return NULL; // nothing to remove
DWORD hash = id.Hash() % _cBuckets;
CTableElement *pTE = _buckets[hash].Remove(id);
if (pTE)
{
_cElements--;
}
return pTE;
}
void
CResolverHashTable::RemoveAll()
{
VALIDATE_METHOD
if (!_fInitialized) return; // nothing to remove
ASSERT(_buckets);
DWORD _currentBucketIndex = 0;
CTableElement *pTE;
while (_currentBucketIndex < _cBuckets)
{
while (pTE = _buckets[_currentBucketIndex].Pop())
{
_cElements--;
}
_currentBucketIndex++;
}
ASSERT(_cElements==0);
DELETE_OR_ARRAY(CTableElementList,_buckets,_cBuckets);
_buckets = NULL;
_fInitialized = FALSE;
}
IDataItem *
CResolverHashTableIterator::Next()
{
if (!_table._fInitialized)
{
return NULL;
}
while (
_BucketIter.Finished()
&& (_currentBucketIndex < _table._cBuckets)
)
{
_BucketIter.Init(_table._buckets[_currentBucketIndex]);
_currentBucketIndex++;
}
return _BucketIter.Next();
}