WindowsXP/inetsrv/iis/lkrhash/src/lkr-stl-iter.cpp
2025-04-27 07:49:33 -04:00

697 lines
21 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) 2000 Microsoft Corporation
Module Name :
LKR-stl-iter.cpp
Abstract:
Implements STL-style iterators for LKRhash
Author:
George V. Reilly (GeorgeRe) March 2000
Environment:
Win32 - User Mode
Project:
Internet Information Server RunTime Library
Revision History:
March 2000
--*/
#include "precomp.hxx"
#define DLL_IMPLEMENTATION
#define IMPLEMENTATION_EXPORT
#include <lkrhash.h>
#include "i-lkrhash.h"
#ifndef __LKRHASH_NO_NAMESPACE__
#define LKRHASH_NS LKRhash
#else // __LKRHASH_NO_NAMESPACE__
#define LKRHASH_NS
#endif // __LKRHASH_NO_NAMESPACE__
#ifndef __LKRHASH_NO_NAMESPACE__
namespace LKRhash {
#endif // !__LKRHASH_NO_NAMESPACE__
#ifdef LKR_STL_ITERATORS
//------------------------------------------------------------------------
// Function: CLKRLinearHashTable::Begin
// Synopsis: Make the iterator point to the first record in the hash table.
//------------------------------------------------------------------------
CLKRLinearHashTable::Iterator
CLKRLinearHashTable::Begin()
{
Iterator iter(this, &_Bucket(0)->m_ncFirst, 0, NODE_BEGIN - NODE_STEP);
LKR_ITER_TRACE(_TEXT(" LKLH:Begin(it=%p, plht=%p)\n"), &iter, this);
// Let Increment do the hard work of finding the first slot in use.
iter._Increment(false);
IRTLASSERT(iter.m_iNode != NODE_BEGIN - NODE_STEP);
IRTLASSERT(iter == End() || _IsValidIterator(iter));
return iter;
} // CLKRLinearHashTable::Begin
//------------------------------------------------------------------------
// Function: CLKRLinearHashTable_Iterator::Increment()
// Synopsis: move iterator to next valid record in table
//------------------------------------------------------------------------
bool
CLKRLinearHashTable_Iterator::_Increment(
bool fDecrementOldValue)
{
IRTLASSERT(m_plht != NULL);
IRTLASSERT(m_dwBucketAddr < m_plht->m_cActiveBuckets);
IRTLASSERT(m_pnc != NULL);
IRTLASSERT((0 <= m_iNode && m_iNode < NODES_PER_CLUMP)
|| (NODE_BEGIN - NODE_STEP == m_iNode));
// Release the reference acquired in the previous call to _Increment
if (fDecrementOldValue)
_AddRef(LKAR_ITER_RELEASE);
do
{
do
{
// find the next slot in the nodeclump that's in use
while ((m_iNode += NODE_STEP) != NODE_END)
{
const void* pvRecord = m_pnc->m_pvNode[m_iNode];
if (pvRecord != NULL)
{
IRTLASSERT(!m_pnc->InvalidSignature(m_iNode));
// Add a new reference
_AddRef(LKAR_ITER_ACQUIRE);
LKR_ITER_TRACE(_TEXT(" LKLH:++(this=%p, plht=%p, NC=%p, ")
_TEXT("BA=%u, IN=%d, Rec=%p)\n"),
this, m_plht, m_pnc,
m_dwBucketAddr, m_iNode, pvRecord);
return true;
}
else // pvRecord == NULL
{
#if 0 //// #ifdef IRTLDEBUG
// Check that all the remaining nodes are empty
IRTLASSERT(m_pnc->IsLastClump());
for (int i = m_iNode; i != NODE_END; i += NODE_STEP)
{
IRTLASSERT(m_pnc->IsEmptyAndInvalid(i));
}
#endif // IRTLDEBUG
break; // rest of nodeclump is empty
}
}
// try the next nodeclump in the bucket chain
m_iNode = NODE_BEGIN - NODE_STEP;
m_pnc = m_pnc->m_pncNext;
} while (m_pnc != NULL);
// Try the next bucket, if there is one
if (++m_dwBucketAddr < m_plht->m_cActiveBuckets)
{
CBucket* pbkt = m_plht->_Bucket(m_dwBucketAddr);
IRTLASSERT(pbkt != NULL);
m_pnc = &pbkt->m_ncFirst;
}
} while (m_dwBucketAddr < m_plht->m_cActiveBuckets);
// We have fallen off the end of the hashtable. Set iterator equal
// to end(), the empty iterator.
LKR_ITER_TRACE(_TEXT(" LKLH:End(this=%p, plht=%p)\n"), this, m_plht);
m_plht = NULL;
m_pnc = NULL;
m_dwBucketAddr = 0;
m_iNode = 0;
//// IRTLASSERT(this->operator==(Iterator())); // == end()
return false;
} // CLKRLinearHashTable_Iterator::_Increment()
//------------------------------------------------------------------------
// Function: CLKRLinearHashTable::Insert
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRLinearHashTable::Insert(
const void* pvRecord,
Iterator& riterResult,
bool fOverwrite /* = false */)
{
riterResult = End();
if (!IsUsable() || pvRecord == NULL)
return false;
bool fSuccess = (_InsertRecord(pvRecord,
_CalcKeyHash(_ExtractKey(pvRecord)),
fOverwrite,
&riterResult)
== LK_SUCCESS);
IRTLASSERT(riterResult.m_iNode != NODE_BEGIN - NODE_STEP);
IRTLASSERT(fSuccess
? _IsValidIterator(riterResult)
: riterResult == End());
return fSuccess;
} // CLKRLinearHashTable::Insert()
//------------------------------------------------------------------------
// Function: CLKRLinearHashTable::_Erase
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRLinearHashTable::_Erase(
Iterator& riter,
DWORD dwSignature)
{
CNodeClump* pncCurr, *pncPrev;
CBucket* const pbkt = riter.m_plht->_Bucket(riter.m_dwBucketAddr);
LKR_ITER_TRACE(_TEXT(" LKLH:_Erase:pre(iter=%p, plht=%p, NC=%p, ")
_TEXT("BA=%u, IN=%d, Sig=%x, Rec=%p)\n"),
&riter, riter.m_plht, riter.m_pnc,
riter.m_dwBucketAddr, riter.m_iNode, dwSignature,
riter.m_pnc ? riter.m_pnc->m_pvNode[riter.m_iNode] : NULL);
pbkt->WriteLock();
for (pncCurr = &pbkt->m_ncFirst, pncPrev = NULL;
pncCurr != NULL;
pncPrev = pncCurr, pncCurr = pncCurr->m_pncNext)
{
if (pncCurr == riter.m_pnc)
break;
}
IRTLASSERT(pncCurr != NULL);
// Release the iterator's reference on the record
const void* pvRecord = riter.m_pnc->m_pvNode[riter.m_iNode];
IRTLASSERT(pvRecord != NULL);
_AddRefRecord(pvRecord, LKAR_ITER_ERASE);
// _DeleteNode will leave iterator members pointing to the
// preceding record
int iNode = riter.m_iNode;
IRTLVERIFY(_DeleteNode(pbkt, riter.m_pnc, pncPrev, iNode,
LKAR_ITER_ERASE_TABLE));
if (iNode == NODE_END)
LKR_ITER_TRACE(_TEXT("\t_Erase(Bkt=%p, pnc=%p, Prev=%p, iNode=%d)\n"),
pbkt, riter.m_pnc, pncPrev, iNode);
riter.m_iNode = (iNode == NODE_END) ? NODE_END-NODE_STEP : (short) iNode;
pbkt->WriteUnlock();
// Don't contract the table. Likely to invalidate the iterator,
// if iterator is being used in a loop
return true;
} // CLKRLinearHashTable::_Erase()
//------------------------------------------------------------------------
// Function: CLKRLinearHashTable::Erase
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRLinearHashTable::Erase(
Iterator& riter)
{
if (!IsUsable() || !_IsValidIterator(riter))
return false;
DWORD dwSignature = _CalcKeyHash(_ExtractKey(riter.Record()));
LKR_ITER_TRACE(_TEXT(" LKLH:Erase:pre(iter=%p, plht=%p, NC=%p, BA=%u, ")
_TEXT("IN=%d, Sig=%x, Rec=%p)\n"),
&riter, riter.m_plht, riter.m_pnc, riter.m_dwBucketAddr,
riter.m_iNode, dwSignature,
riter.m_pnc ? riter.m_pnc->m_pvNode[riter.m_iNode] : NULL);
bool fSuccess = _Erase(riter, dwSignature);
bool fIncrement = false;
LKR_ITER_TRACE(_TEXT(" LKLH:Erase:post(iter=%p, plht=%p, NC=%p, BA=%u, ")
_TEXT("IN=%d, Sig=%x, Rec=%p, Success=%s)\n"),
&riter, riter.m_plht, riter.m_pnc, riter.m_dwBucketAddr,
riter.m_iNode, dwSignature,
riter.m_pnc ? riter.m_pnc->m_pvNode[riter.m_iNode] : NULL,
(fSuccess ? "true" : "false"));
// _Erase left riter pointing to the preceding record.
// Move to next record.
if (fSuccess)
fIncrement = riter._Increment(false);
IRTLASSERT(riter.m_iNode != NODE_BEGIN - NODE_STEP);
IRTLASSERT(fIncrement ? _IsValidIterator(riter) : riter == End());
LKR_ITER_TRACE(_TEXT(" LKLH:Erase:post++(iter=%p, plht=%p, NC=%p, ")
_TEXT("BA=%u, IN=%d, Sig=%x, Rec=%p)\n"),
&riter, riter.m_plht, riter.m_pnc,
riter.m_dwBucketAddr, riter.m_iNode, dwSignature,
riter.m_pnc ? riter.m_pnc->m_pvNode[riter.m_iNode] : NULL);
return fSuccess;
} // CLKRLinearHashTable::Erase
//------------------------------------------------------------------------
// Function: CLKRLinearHashTable::Erase
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRLinearHashTable::Erase(
Iterator& riterFirst,
Iterator& riterLast)
{
LKR_ITER_TRACE(_TEXT(" LKHT:Erase2(%p, %p)\n"), &riterFirst, &riterLast);
bool fSuccess;
int cRecords = 0;
do
{
LKR_ITER_TRACE(_TEXT("\n LKLH:Erase2(%d, %p)\n"),
++cRecords, &riterFirst);
fSuccess = Erase(riterFirst);
} while (fSuccess && riterFirst != End() && riterFirst != riterLast);
LKR_ITER_TRACE(_TEXT(" LKLH:Erase2: fSuccess = %s\n"),
(fSuccess ? "true" : "false"));
return fSuccess;
} // CLKRLinearHashTable::Erase
//------------------------------------------------------------------------
// Function: CLKRLinearHashTable::Find
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRLinearHashTable::Find(
DWORD_PTR pnKey,
Iterator& riterResult)
{
riterResult = End();
if (!IsUsable())
return false;
const void* pvRecord = NULL;
DWORD hash_val = _CalcKeyHash(pnKey);
bool fFound = (_FindKey(pnKey, hash_val, &pvRecord, &riterResult)
== LK_SUCCESS);
IRTLASSERT(fFound
? _IsValidIterator(riterResult) && riterResult.Key() == pnKey
: riterResult == End());
IRTLASSERT(riterResult.m_iNode != NODE_BEGIN - NODE_STEP);
return fFound;
} // CLKRLinearHashTable::Find
//------------------------------------------------------------------------
// Function: CLKRLinearHashTable::EqualRange
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRLinearHashTable::EqualRange(
DWORD_PTR pnKey,
Iterator& riterFirst,
Iterator& riterLast)
{
LKR_ITER_TRACE(_TEXT(" LKLH:EqualRange: Key=%p)\n"), (void*) pnKey);
riterLast = End();
bool fFound = Find(pnKey, riterFirst);
if (fFound)
{
riterLast = riterFirst;
IRTLASSERT(riterLast != End());
do
{
riterLast._Increment();
} while (riterLast != End() && riterLast.Key() == pnKey);
}
IRTLASSERT(riterFirst.m_iNode != NODE_BEGIN - NODE_STEP);
IRTLASSERT(fFound ? _IsValidIterator(riterFirst) : riterFirst == End());
IRTLASSERT(riterLast.m_iNode != NODE_BEGIN - NODE_STEP);
IRTLASSERT(fFound || riterLast == End());
return fFound;
} // CLKRLinearHashTable::EqualRange
//------------------------------------------------------------------------
// Function: CLKRHashTable::Begin
// Synopsis: Make the iterator point to the first record in the hash table.
//------------------------------------------------------------------------
CLKRHashTable::Iterator
CLKRHashTable::Begin()
{
Iterator iter(this, -1);
LKR_ITER_TRACE(_TEXT(" LKHT:Begin(it=%p, pht=%p)\n"), &iter, this);
// Let Increment do the hard work of finding the first slot in use.
iter._Increment(false);
IRTLASSERT(iter.m_ist != -1);
IRTLASSERT(iter == End() || _IsValidIterator(iter));
return iter;
} // CLKRHashTable::Begin
//------------------------------------------------------------------------
// Function: CLKRHashTable_Iterator::_Increment()
// Synopsis: move iterator to next valid record in table
//------------------------------------------------------------------------
bool
CLKRHashTable_Iterator::_Increment(
bool fDecrementOldValue)
{
IRTLASSERT(m_pht != NULL);
IRTLASSERT(-1 <= m_ist
&& m_ist < static_cast<int>(m_pht->m_cSubTables));
for (;;)
{
// Do we have a valid iterator into a subtable? If not, get one.
while (m_subiter.m_plht == NULL)
{
while (++m_ist < static_cast<int>(m_pht->m_cSubTables))
{
LKR_ITER_TRACE(_TEXT(" LKHT:++IST=%d\n"), m_ist);
m_subiter = m_pht->m_palhtDir[m_ist]->Begin();
if (m_subiter.m_plht != NULL)
{
LKR_ITER_TRACE(_TEXT(" LKHT:++(this=%p, pht=%p, IST=%d, ")
_TEXT("LHT=%p, NC=%p, ")
_TEXT("BA=%u, IN=%d, Rec=%p)\n"),
this, m_pht, m_ist,
m_subiter.m_plht, m_subiter.m_pnc,
m_subiter.m_dwBucketAddr, m_subiter.m_iNode,
m_subiter.m_pnc->m_pvNode[m_subiter.m_iNode]
);
return true;
}
}
// There are no more subtables left.
LKR_ITER_TRACE(_TEXT(" LKHT:End(this=%p, pht=%p)\n"), this, m_pht);
m_pht = NULL;
m_ist = 0;
//// IRTLASSERT(this->operator==(Iterator())); // == end()
return false;
}
// We already have a valid iterator into a subtable. Increment it.
m_subiter._Increment(fDecrementOldValue);
if (m_subiter.m_plht != NULL)
{
LKR_ITER_TRACE(_TEXT(" LKHT:++(this=%p, pht=%p, IST=%d, ")
_TEXT("LHT=%p, NC=%p, BA=%u, IN=%d, Rec=%p)\n"),
this, m_pht, m_ist,
m_subiter.m_plht, m_subiter.m_pnc,
m_subiter.m_dwBucketAddr, m_subiter.m_iNode,
m_subiter.m_pnc->m_pvNode[m_subiter.m_iNode]);
return true;
}
}
} // CLKRHashTable_Iterator::_Increment()
//------------------------------------------------------------------------
// Function: CLKRHashTable::Insert
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRHashTable::Insert(
const void* pvRecord,
Iterator& riterResult,
bool fOverwrite)
{
riterResult = End();
if (!IsUsable() || pvRecord == NULL)
return false;
DWORD hash_val = _CalcKeyHash(_ExtractKey(pvRecord));
SubTable* const pst = _SubTable(hash_val);
bool f = (pst->_InsertRecord(pvRecord, hash_val, fOverwrite,
&riterResult.m_subiter)
== LK_SUCCESS);
if (f)
{
riterResult.m_pht = this;
riterResult.m_ist = (short) _SubTableIndex(pst);
}
IRTLASSERT(riterResult.m_ist != -1);
IRTLASSERT(f ? _IsValidIterator(riterResult) : riterResult == End());
return f;
} // CLKRHashTable::Insert
//------------------------------------------------------------------------
// Function: CLKRHashTable::Erase
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRHashTable::Erase(
Iterator& riter)
{
if (!IsUsable() || !_IsValidIterator(riter))
return false;
DWORD dwSignature = _CalcKeyHash(_ExtractKey(riter.Record()));
SubTable* const pst = _SubTable(dwSignature);
IRTLASSERT(pst == riter.m_subiter.m_plht);
if (pst != riter.m_subiter.m_plht)
return false;
LKR_ITER_TRACE(_TEXT(" LKHT:Erase:pre(iter=%p, pht=%p, ist=%d, plht=%p, ")
_TEXT("NC=%p, BA=%u, IN=%d, Sig=%x, Rec=%p)\n"),
&riter, riter.m_pht, riter.m_ist,
riter.m_subiter.m_plht, riter.m_subiter.m_pnc,
riter.m_subiter.m_dwBucketAddr, riter.m_subiter.m_iNode,
dwSignature,
(riter.m_subiter.m_pnc ? riter.Record() : NULL));
// _Erase left riter pointing to the preceding record. Move to
// next record.
bool fSuccess = pst->_Erase(riter.m_subiter, dwSignature);
bool fIncrement = false;
LKR_ITER_TRACE(_TEXT(" LKHT:Erase:post(iter=%p, pht=%p, ist=%d, plht=%p, ")
_TEXT("NC=%p, BA=%u, IN=%d, Sig=%x, Rec=%p, Success=%s)\n"),
&riter, riter.m_pht, riter.m_ist,
riter.m_subiter.m_plht, riter.m_subiter.m_pnc,
riter.m_subiter.m_dwBucketAddr, riter.m_subiter.m_iNode,
dwSignature,
((riter.m_subiter.m_pnc && riter.m_subiter.m_iNode >= 0)
? riter.Record() : NULL),
(fSuccess ? "true" : "false"));
if (fSuccess)
fIncrement = riter._Increment(false);
IRTLASSERT(riter.m_ist != -1);
IRTLASSERT(fIncrement ? _IsValidIterator(riter) : riter == End());
LKR_ITER_TRACE(_TEXT(" LKHT:Erase:post++(iter=%p, pht=%p, ist=%d, ")
_TEXT("plht=%p, NC=%p, ")
_TEXT("BA=%u, IN=%d, Sig=%x, Rec=%p)\n"),
&riter, riter.m_pht, riter.m_ist,
riter.m_subiter.m_plht, riter.m_subiter.m_pnc,
riter.m_subiter.m_dwBucketAddr, riter.m_subiter.m_iNode,
dwSignature,
(riter.m_subiter.m_pnc ? riter.Record() : NULL));
return fSuccess;
} // CLKRHashTable::Erase
//------------------------------------------------------------------------
// Function: CLKRHashTable::Erase
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRHashTable::Erase(
Iterator& riterFirst,
Iterator& riterLast)
{
LKR_ITER_TRACE(_TEXT(" LKHT:Erase2(%p, %p)\n"), &riterFirst, &riterLast);
bool fSuccess;
int cRecords = 0;
do
{
LKR_ITER_TRACE(_TEXT("\n LKHT:Erase2(%d, %p)\n"),
++cRecords, &riterFirst);
fSuccess = Erase(riterFirst);
} while (fSuccess && riterFirst != End() && riterFirst != riterLast);
LKR_ITER_TRACE(_TEXT(" LKHT:Erase2: fSuccess = %s\n"),
(fSuccess ? "true" : "false"));
return fSuccess;
} // CLKRHashTable::Erase
//------------------------------------------------------------------------
// Function: CLKRHashTable::Find
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRHashTable::Find(
DWORD_PTR pnKey,
Iterator& riterResult)
{
riterResult = End();
if (!IsUsable())
return false;
const void* pvRecord = NULL;
DWORD hash_val = _CalcKeyHash(pnKey);
SubTable* const pst = _SubTable(hash_val);
bool fFound = (pst->_FindKey(pnKey, hash_val, &pvRecord,
&riterResult.m_subiter)
== LK_SUCCESS);
if (fFound)
{
riterResult.m_pht = this;
riterResult.m_ist = (short) _SubTableIndex(pst);
}
IRTLASSERT(riterResult.m_ist != -1);
IRTLASSERT(fFound
? _IsValidIterator(riterResult) && riterResult.Key() == pnKey
: riterResult == End());
return fFound;
} // CLKRHashTable::Find
//------------------------------------------------------------------------
// Function: CLKRHashTable::EqualRange
// Synopsis:
//------------------------------------------------------------------------
bool
CLKRHashTable::EqualRange(
DWORD_PTR pnKey,
Iterator& riterFirst,
Iterator& riterLast)
{
LKR_ITER_TRACE(_TEXT(" LKHT:EqualRange: Key=%p)\n"), (void*) pnKey);
riterLast = End();
bool fFound = Find(pnKey, riterFirst);
if (fFound)
{
riterLast = riterFirst;
IRTLASSERT(riterLast != End());
do
{
riterLast._Increment();
} while (riterLast != End() && riterLast.Key() == pnKey);
}
IRTLASSERT(riterFirst.m_ist != -1);
IRTLASSERT(fFound ? _IsValidIterator(riterFirst) : riterFirst == End());
IRTLASSERT(riterLast.m_ist != -1);
IRTLASSERT(fFound || riterLast == End());
return fFound;
} // CLKRHashTable::EqualRange
#endif // LKR_STL_ITERATORS
#ifndef __LKRHASH_NO_NAMESPACE__
};
#endif // !__LKRHASH_NO_NAMESPACE__