270 lines
5.3 KiB
C++
270 lines
5.3 KiB
C++
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Table.cxx
|
||
|
||
Abstract:
|
||
|
||
Implementation of the CResolverHashTable and CTableElement.
|
||
|
||
Author:
|
||
|
||
Mario Goertzel [MarioGo]
|
||
|
||
Revision History:
|
||
|
||
MarioGo 02-15-95 Bits 'n pieces
|
||
MarioGo 12-18-95 Changed from UUID to generic object keys
|
||
SatishT 02-12-96 Modified for use with shared memory
|
||
|
||
--*/
|
||
|
||
#include<or.hxx>
|
||
|
||
#if DBG
|
||
|
||
void
|
||
CResolverHashTable::IsValid()
|
||
{
|
||
IsGoodBasedPtr(_buckets);
|
||
|
||
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;
|
||
|
||
ComDebOut((DEB_ITRACE, "Adding %x at hash = %d\n",
|
||
OR_OFFSET(pElement),hash));
|
||
|
||
_buckets[hash].Insert(status,pElement);
|
||
|
||
_cElements++;
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
CResolverHashTable::CResolverHashTable(UINT start_size)
|
||
{
|
||
ComDebOut((DEB_ITRACE, "Constructing CResolverHashTable Size = %d\n",start_size));
|
||
|
||
_cBuckets = start_size;
|
||
_cElements = 0;
|
||
_buckets = NULL;
|
||
_fInitialized = FALSE;
|
||
|
||
VALIDATE_METHOD
|
||
}
|
||
|
||
|
||
ORSTATUS
|
||
CResolverHashTable::Init()
|
||
{
|
||
ORSTATUS status;
|
||
|
||
ASSERT(!_fInitialized);
|
||
|
||
VALIDATE_METHOD
|
||
|
||
NEW_OR_BASED_ARRAY(_buckets,CTableElementList,_cBuckets);
|
||
|
||
if (NULL == _buckets)
|
||
{
|
||
status = OR_NOMEM;
|
||
}
|
||
else
|
||
{
|
||
status = OR_OK;
|
||
_fInitialized = TRUE;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
CResolverHashTable::~CResolverHashTable()
|
||
{
|
||
RemoveAll();
|
||
}
|
||
|
||
|
||
CTableElement *
|
||
CResolverHashTable::Lookup(
|
||
IN ISearchKey &id
|
||
)
|
||
{
|
||
ComDebOut((DEB_ITRACE, "Entering Lookup\n"));
|
||
|
||
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
|
||
)
|
||
{
|
||
ComDebOut((DEB_ITRACE, "Entering Add for %x in %x\n",
|
||
OR_OFFSET(pElement),OR_OFFSET(this)));
|
||
|
||
|
||
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 OR_BASED * psll;
|
||
NEW_OR_BASED_ARRAY(psll,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 OR_BASED *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);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
ComDebOut((DEB_ITRACE, "Leaving Add\n"));
|
||
|
||
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_BASED_ARRAY(CTableElementList,_buckets,_cBuckets);
|
||
_buckets = NULL;
|
||
_fInitialized = FALSE;
|
||
}
|
||
|