1626 lines
56 KiB
C++
1626 lines
56 KiB
C++
#if !defined(_FUSION_INC_FUSIONHASH_H_INCLUDED_)
|
|
#define _FUSION_INC_FUSIONHASH_H_INCLUDED_
|
|
|
|
#pragma once
|
|
|
|
#include "fusionheap.h"
|
|
#include "fusionbuffer.h"
|
|
#include "fusionchartraits.h"
|
|
#include "fusiondeque.h"
|
|
|
|
#define T2P(x, y) < x , y >
|
|
|
|
#pragma warning(disable:4327) // indirection alignment of LHS (16) is greater than RHS (8)
|
|
#pragma warning(disable:4328) // indirection alignment of formal parameter 2 (16) is greater than the actual argument alignment (8)
|
|
|
|
enum InsertOrUpdateIfDisposition
|
|
{
|
|
eUpdateValue,
|
|
eLeaveValueAlone,
|
|
};
|
|
|
|
template <typename TPassed, class TStored> inline BOOL HashTableCompareKey(TPassed tpassed, const TStored &rtstored, bool &rfMatch)
|
|
{
|
|
return rtstored.Compare(tpassed, rfMatch);
|
|
}
|
|
|
|
template<> inline BOOL HashTableCompareKey<REFGUID, GUID>(REFGUID rguid, const GUID &rguidstored, bool &rfMatch)
|
|
{
|
|
rfMatch = ((rguid == rguidstored) != 0);
|
|
return TRUE;
|
|
}
|
|
|
|
template <typename TPassed> inline BOOL HashTableHashKey(TPassed tpassed, ULONG &rulPseudoKey);
|
|
|
|
// common override for GUID-indexed tables
|
|
template<> inline BOOL HashTableHashKey<REFGUID>(REFGUID rguid, ULONG &rulPseudoKey)
|
|
{
|
|
rulPseudoKey = rguid.Data1;
|
|
return TRUE;
|
|
}
|
|
|
|
template <typename TPassed, class TStored> inline BOOL HashTableInitializeKey(TPassed tpassed, TStored &rtstored)
|
|
{
|
|
return rtstored.Initialize(tpassed);
|
|
}
|
|
|
|
// common override for GUID-indexed tables
|
|
template<> inline BOOL HashTableInitializeKey<REFGUID, GUID>(REFGUID rguidIn, GUID &rguidOut)
|
|
{
|
|
rguidOut = rguidIn;
|
|
return TRUE;
|
|
}
|
|
|
|
template <typename TPassed, class TStored> inline BOOL HashTableInitializeValue(TPassed tpassed, TStored &rtstored)
|
|
{
|
|
return rtstored.Initialize(tpassed);
|
|
}
|
|
|
|
template <typename TPassed, class TStored> inline BOOL HashTableUpdateValue(TPassed tpassed, TStored &rtstored)
|
|
{
|
|
return rtstored.Assign(tpassed);
|
|
}
|
|
|
|
template <typename TStored> inline VOID HashTablePreInitializeKey(TStored &rtstored) { }
|
|
|
|
template <typename TStored> inline VOID HashTablePreInitializeValue(TStored &rtstored) { }
|
|
|
|
template <typename TStored> inline VOID HashTableFinalizeKey(TStored &rtstored) { }
|
|
|
|
template <typename TStored> inline VOID HashTableFinalizeValue(TStored &rtstored) { }
|
|
|
|
template <typename TCharTraits>
|
|
class CCountedStringHolder
|
|
{
|
|
public:
|
|
CCountedStringHolder() : m_psz(NULL), m_cch(0) { }
|
|
CCountedStringHolder(TCharTraits::TConstantString sz) : m_psz(sz), m_cch(TCharTraits::Cch(sz)) { }
|
|
CCountedStringHolder(const CGenericBaseStringBuffer<TCharTraits> &rBuffer) : m_psz(rBuffer), m_cch(TCharTraits::Cch(rBuffer)) { }
|
|
~CCountedStringHolder() { }
|
|
|
|
TCharTraits::TConstantString m_psz;
|
|
SIZE_T m_cch;
|
|
};
|
|
|
|
//
|
|
// You want to create a class derived from CHashTableHelper, and
|
|
// use it as THashHelper for CHashTable.
|
|
//
|
|
|
|
template <typename TKPassed, class TKStored, typename TVPassed, typename TVStored> class CHashTableHelper
|
|
{
|
|
public:
|
|
static BOOL HashKey(TKPassed keyin, ULONG &rulPseudoKey) { return ::HashTableHashKey<TKPassed>(keyin, rulPseudoKey); }
|
|
static BOOL CompareKey(TKPassed keyin, const TKStored &rtkeystored, bool &rfMatch) { return ::HashTableCompareKey<TKPassed, TKStored>(keyin, rtkeystored, rfMatch); }
|
|
static VOID PreInitializeKey(TKStored &rtkeystored) { return ::HashTablePreInitializeKey<TKStored>(rtkeystored); }
|
|
static VOID PreInitializeValue(TVStored &rtvaluestored) { return ::HashTablePreInitializeValue<TVStored>(rtvaluestored); }
|
|
static BOOL InitializeKey(TKPassed keyin, TKStored &rtkeystored) { return ::HashTableInitializeKey<TKPassed>(keyin, rtkeystored); }
|
|
static BOOL InitializeValue(TVPassed vin, TVStored &rvstored) { return ::HashTableInitializeValue<TVPassed, TVStored>(vin, rvstored); }
|
|
static BOOL UpdateValue(TVPassed vin, TVStored &rvstored) { return ::HashTableUpdateValue<TVPassed, TVStored>(vin, rvstored); }
|
|
static VOID FinalizeKey(TKStored &rtkeystored) { return ::HashTableFinalizeKey<TKStored>(rtkeystored); }
|
|
static VOID FinalizeValue(TVStored &rtvstored) { return ::HashTableFinalizeValue<TVStored>(rtvstored); }
|
|
};
|
|
|
|
template <typename TKPassed, typename TKStored, typename TVPassed, typename TVStored, class THashHelper = CHashTableHelper<TKPassed, TKStored, TVPassed, TVStored>, ULONG nInlineBucketChains = 7, bool fAllowDups = false> class CHashTableIter;
|
|
|
|
template <typename TKPassed, typename TKStored, typename TVPassed, typename TVStored, class THashHelper = CHashTableHelper<TKPassed, TKStored, TVPassed, TVStored>, ULONG nInlineBucketChains = 7, bool fAllowDups = false> class CHashTable
|
|
{
|
|
friend CHashTableIter<TKPassed, TKStored, TVPassed, TVStored, THashHelper, nInlineBucketChains, fAllowDups>;
|
|
|
|
typedef CHashTable<TKPassed, TKStored, TVPassed, TVStored, THashHelper, nInlineBucketChains, fAllowDups> TThisHashTable;
|
|
public:
|
|
CHashTable() :
|
|
m_cBucketChains(nInlineBucketChains),
|
|
m_prgBucketChains(m_rgInlineBucketChains),
|
|
m_ulLockCount(0),
|
|
m_cEntries(0)
|
|
{
|
|
}
|
|
|
|
~CHashTable()
|
|
{
|
|
// This denotes a programming error.
|
|
ASSERT_NTC(m_ulLockCount == 0);
|
|
ULONG i;
|
|
SIZE_T cFound = 0;
|
|
|
|
for (i=0; i<m_cBucketChains; i++)
|
|
{
|
|
SIZE_T cThisBucket = 0;
|
|
m_prgBucketChains[i].ClearNoCallback(this, cThisBucket);
|
|
FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "Destroying hash table %p; found %Id buckets at index %d\n", this, cThisBucket, i);
|
|
cFound += cThisBucket;
|
|
}
|
|
|
|
FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "After loop, destroying hash table %p; found total of %Id buckets; m_cEntries == %Id\n", this, cFound, m_cEntries);
|
|
|
|
ASSERT_NTC(cFound == m_cEntries);
|
|
|
|
if ((m_prgBucketChains != m_rgInlineBucketChains) &&
|
|
(m_prgBucketChains != NULL))
|
|
{
|
|
ASSERT_NTC(m_cBucketChains != 0);
|
|
|
|
FUSION_DELETE_ARRAY(m_prgBucketChains);
|
|
m_cBucketChains = 0;
|
|
m_prgBucketChains = NULL;
|
|
}
|
|
else
|
|
{
|
|
// Better safe than sorry
|
|
ASSERT_NTC((m_prgBucketChains == m_rgInlineBucketChains) || (m_cBucketChains == 0));
|
|
m_cBucketChains = 0;
|
|
}
|
|
|
|
m_prgBucketChains = NULL;
|
|
}
|
|
|
|
BOOL Initialize(ULONG cBucketChains = nInlineBucketChains)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
PARAMETER_CHECK(cBucketChains != 0);
|
|
|
|
// If you hit this assertion, it either means that you're calling Initialize
|
|
// twice on the same hash table, the hash table has been corrupted since it was
|
|
// constructed, or someone messed up the constructor.
|
|
INTERNAL_ERROR_CHECK(m_prgBucketChains == m_rgInlineBucketChains);
|
|
|
|
// Since we already have nInlineBucketChains allocated, there's no point
|
|
// in going lower. However, do perform the dynamic allocation if necessary.
|
|
if (cBucketChains > nInlineBucketChains)
|
|
{
|
|
IFALLOCFAILED_EXIT(m_prgBucketChains = FUSION_NEW_ARRAY(CBucketChain, cBucketChains));
|
|
m_cBucketChains = cBucketChains;
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
void Lock(bool fAllowInsertions)
|
|
{
|
|
FN_TRACE();
|
|
|
|
if (m_ulLockCount++ == 0)
|
|
{
|
|
m_fInsertionsPermitted = fAllowInsertions;
|
|
m_fRemovalsPermitted = false;
|
|
}
|
|
}
|
|
|
|
void Unlock()
|
|
{
|
|
FN_TRACE();
|
|
|
|
m_ulLockCount--;
|
|
}
|
|
|
|
BOOL Insert(TKPassed keyin, TVPassed valuein, DWORD DuplicateKeyErrorCode)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
ULONG ulPseudoKey = 0;
|
|
ULONG iBucket = 0;
|
|
|
|
PARAMETER_CHECK(DuplicateKeyErrorCode != ERROR_SUCCESS);
|
|
|
|
INTERNAL_ERROR_CHECK((m_ulLockCount == 0) || (m_fInsertionsPermitted));
|
|
IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
|
|
|
|
iBucket = ulPseudoKey % m_cBucketChains;
|
|
|
|
IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Insert(this, keyin, valuein, ulPseudoKey, DuplicateKeyErrorCode));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL Insert(TKPassed keyin, TVPassed valuein)
|
|
{
|
|
return this->Insert(keyin, valuein, ERROR_ALREADY_EXISTS);
|
|
}
|
|
|
|
BOOL FindOrInsertIfNotPresent(TKPassed keyin, TVPassed valuein, TVStored **ppvaluestored = NULL, BOOL *pfFound = NULL)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
ULONG ulPseudoKey = 0;
|
|
ULONG iBucket = 0;
|
|
|
|
if (ppvaluestored != NULL)
|
|
*ppvaluestored = NULL;
|
|
|
|
if (pfFound != NULL)
|
|
*pfFound = FALSE;
|
|
|
|
INTERNAL_ERROR_CHECK((m_ulLockCount == 0) || (m_fInsertionsPermitted));
|
|
IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
|
|
|
|
iBucket = ulPseudoKey % m_cBucketChains;
|
|
|
|
IFW32FALSE_EXIT(m_prgBucketChains[iBucket].FindOrInsertIfNotPresent(this, keyin, valuein, ulPseudoKey, ppvaluestored, pfFound));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
// U is always as indicated, but the compiler would rather
|
|
// deduce that seperately than deduce types dependent on each other
|
|
template <typename T>
|
|
BOOL InsertOrUpdateIf(
|
|
TKPassed keyin,
|
|
TVPassed valuein,
|
|
T *pt,
|
|
BOOL (T::*pmfn)(
|
|
TVPassed,
|
|
const TVStored &,
|
|
InsertOrUpdateIfDisposition &)
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
ULONG ulPseudoKey = 0;
|
|
ULONG iBucket = 0;
|
|
|
|
INTERNAL_ERROR_CHECK((m_ulLockCount == 0) || (m_fInsertionsPermitted));
|
|
|
|
IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
|
|
|
|
iBucket = ulPseudoKey % m_cBucketChains;
|
|
|
|
IFW32FALSE_EXIT(m_prgBucketChains[iBucket].InsertOrUpdateIf T2P(TThisHashTable, T)(this, keyin, valuein, ulPseudoKey, pt, pmfn));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
inline VOID ClearNoCallback()
|
|
{
|
|
FN_TRACE();
|
|
|
|
ULONG i;
|
|
SIZE_T cFound = 0;
|
|
|
|
for (i=0; i<m_cBucketChains; i++)
|
|
{
|
|
SIZE_T cThisBucket = 0;
|
|
m_prgBucketChains[i].ClearNoCallback(this, cThisBucket);
|
|
cFound += cThisBucket;
|
|
}
|
|
|
|
if (m_prgBucketChains != m_rgInlineBucketChains)
|
|
{
|
|
FUSION_DELETE_ARRAY(m_prgBucketChains);
|
|
m_prgBucketChains = m_rgInlineBucketChains;
|
|
m_cBucketChains = nInlineBucketChains;
|
|
}
|
|
|
|
m_cEntries = 0;
|
|
FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Cleared hash table %p entries to 0\n", __FILE__, __LINE__, this);
|
|
}
|
|
|
|
template <typename T> inline VOID Clear(T *pt = NULL, VOID (T::*pmfn)(TKStored &, TVStored &) = NULL)
|
|
{
|
|
FN_TRACE();
|
|
ULONG i;
|
|
|
|
// Either both have to be NULL or neither.
|
|
ASSERT((pt == NULL) == (pmfn == NULL));
|
|
|
|
if ((pt != NULL) && (pmfn != NULL))
|
|
{
|
|
for (i=0; i<m_cBucketChains; i++)
|
|
m_prgBucketChains[i].Clear(this, pt, pmfn);
|
|
}
|
|
|
|
if (m_prgBucketChains != m_rgInlineBucketChains)
|
|
{
|
|
FUSION_DELETE_ARRAY(m_prgBucketChains);
|
|
m_prgBucketChains = m_rgInlineBucketChains;
|
|
m_cBucketChains = nInlineBucketChains;
|
|
}
|
|
|
|
m_cEntries = 0;
|
|
FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Cleared hash table %p entries to 0\n", __FILE__, __LINE__, this);
|
|
}
|
|
|
|
BOOL Remove(TKPassed keyin, bool fRemoveFirstFoundOnly = false)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
ULONG ulPseudoKey = 0;
|
|
ULONG iBucket = 0;
|
|
|
|
INTERNAL_ERROR_CHECK((m_ulLockCount == 0) || (m_fRemovalsPermitted));
|
|
|
|
IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
|
|
|
|
iBucket = ulPseudoKey % m_cBucketChains;
|
|
|
|
IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Remove(this, keyin, ulPseudoKey, fRemoveFirstFoundOnly));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL Find(TKPassed keyin, TVStored const *&rpvaluestored) const
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
ULONG ulPseudoKey = 0;
|
|
ULONG iBucket = 0;
|
|
|
|
rpvaluestored = NULL;
|
|
IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
|
|
iBucket = ulPseudoKey % m_cBucketChains;
|
|
IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, rpvaluestored));
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL Find(TKPassed keyin, TVStored *&rpvaluestored)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
ULONG ulPseudoKey = 0;
|
|
ULONG iBucket = 0;
|
|
|
|
rpvaluestored = NULL;
|
|
|
|
IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
|
|
|
|
iBucket = ulPseudoKey % m_cBucketChains;
|
|
|
|
IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, rpvaluestored));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL Assign(CHashTable &TableToCopy) { return FALSE; }
|
|
|
|
VOID TakeValue(CHashTable &That)
|
|
{
|
|
FN_TRACE();
|
|
|
|
ULONG i;
|
|
|
|
// Nothing can fail in this function, so we're theoretically safe to preemptively clean up our own storage.
|
|
if (m_prgBucketChains != m_rgInlineBucketChains)
|
|
{
|
|
FUSION_DELETE_ARRAY(m_prgBucketChains);
|
|
m_prgBucketChains = m_rgInlineBucketChains;
|
|
m_cBucketChains = nInlineBucketChains;
|
|
}
|
|
|
|
// Just steal any storage from the other table.
|
|
if (That.m_prgBucketChains != That.m_rgInlineBucketChains)
|
|
{
|
|
// It's a dynamically allocated array in the source; just move the pointer over
|
|
// and clean up its state to be somewhat consistent.
|
|
m_prgBucketChains = That.m_prgBucketChains;
|
|
m_cBucketChains = That.m_cBucketChains;
|
|
|
|
That.m_prgBucketChains = That.m_rgInlineBucketChains;
|
|
That.m_cBucketChains = nInlineBucketChains;
|
|
}
|
|
else
|
|
{
|
|
// The inline chain of the other table is being used; we have to copy the
|
|
// chains over one by one.
|
|
for (i=0; i<nInlineBucketChains; i++)
|
|
m_rgInlineBucketChains[i].TakeValue(this, That.m_rgInlineBucketChains[i]);
|
|
}
|
|
|
|
m_cEntries = That.m_cEntries;
|
|
That.m_cEntries = 0;
|
|
FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Hash table %p took over hash table %p's %Id entries\n", __FILE__, __LINE__, this, &That, m_cEntries);
|
|
}
|
|
|
|
SIZE_T GetEntryCount() const { return m_cEntries; }
|
|
|
|
//protected:
|
|
|
|
class CBucketChain;
|
|
|
|
class CBucket
|
|
{
|
|
public:
|
|
CBucket(ULONG ulPseudoKey) : m_ulPseudoKey(ulPseudoKey) { THashHelper::PreInitializeKey(m_tkey); THashHelper::PreInitializeValue(m_tvalue); }
|
|
|
|
~CBucket() { THashHelper::FinalizeKey(m_tkey); THashHelper::FinalizeValue(m_tvalue); }
|
|
|
|
BOOL Initialize(CHashTable const * pTable, TKPassed keyin, TVPassed valuein)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
IFW32FALSE_EXIT(THashHelper::InitializeKey(keyin, m_tkey));
|
|
IFW32FALSE_EXIT(THashHelper::InitializeValue(valuein, m_tvalue));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL Matches(TKPassed keyin, ULONG ulPseudoKey, bool &rfMatches) const
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
bool fMatches = false;
|
|
|
|
if (m_ulPseudoKey == ulPseudoKey)
|
|
IFW32FALSE_EXIT(THashHelper::CompareKey(keyin, m_tkey, fMatches));
|
|
|
|
rfMatches = fMatches;
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
template <typename T> VOID Clear(TThisHashTable const * pTable, T *pt, VOID (T::*pmfn)(TKStored &keystored, TVStored &rvaluestored))
|
|
{
|
|
FN_TRACE();
|
|
(pt->*pmfn)(m_tkey, m_tvalue);
|
|
}
|
|
|
|
template <typename T> VOID Clear(TThisHashTable const * pTable, T *pt, VOID (T::*pmfn)(TKStored &keystored, TVStored &rvaluestored) const)
|
|
{
|
|
FN_TRACE();
|
|
(pt->*pmfn)(m_tkey, m_tvalue);
|
|
}
|
|
|
|
VOID Remove()
|
|
{
|
|
FN_TRACE();
|
|
m_Linkage.Remove();
|
|
}
|
|
|
|
BOOL Update(TVPassed valuein)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
IFW32FALSE_EXIT(THashHelper::UpdateValue(m_tvalue, valuein));
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
TKStored m_tkey;
|
|
TVStored m_tvalue;
|
|
ULONG m_ulPseudoKey;
|
|
CDequeLinkage m_Linkage;
|
|
|
|
private:
|
|
CBucket(const CBucket &);
|
|
void operator =(const CBucket &);
|
|
};
|
|
|
|
typedef CDequeIterator<CBucket, FIELD_OFFSET(CBucket, m_Linkage)> CBucketIterator;
|
|
typedef CConstDequeIterator<CBucket, FIELD_OFFSET(CBucket, m_Linkage)> CConstBucketIterator;
|
|
|
|
class CBucketChain
|
|
{
|
|
public:
|
|
CBucketChain() { }
|
|
~CBucketChain() { }
|
|
|
|
inline void DeallocateBuckets(CHashTable const *pTable, SIZE_T &rcFound)
|
|
{
|
|
rcFound = m_Buckets.GetEntryCount();
|
|
m_Buckets.Clear(pTable, &CHashTable::DeallocateBucket);
|
|
}
|
|
|
|
BOOL Insert(
|
|
CHashTable *pTable,
|
|
TKPassed keyin,
|
|
TVPassed valuein,
|
|
ULONG ulPseudoKey,
|
|
DWORD DuplicateKeyErrorCode)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
bool fMatches = false;
|
|
CBucket *pCBucket = NULL;
|
|
|
|
if (!fAllowDups)
|
|
{
|
|
CBucketIterator Iter(&m_Buckets);
|
|
|
|
for (Iter.Reset(); Iter.More(); Iter.Next())
|
|
{
|
|
IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
|
|
|
|
if (fMatches)
|
|
ORIGINATE_WIN32_FAILURE_AND_EXIT(DuplicateKey, DuplicateKeyErrorCode);
|
|
}
|
|
}
|
|
|
|
IFW32FALSE_EXIT(pTable->AllocateAndInitializeBucket(ulPseudoKey, keyin, valuein, pCBucket));
|
|
|
|
m_Buckets.AddToTail(pCBucket);
|
|
pTable->m_cEntries++;
|
|
FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Incremented hash table %p entries to %Id\n", __FILE__, __LINE__, pTable, pTable->m_cEntries);
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL FindOrInsertIfNotPresent(
|
|
CHashTable *pTable,
|
|
TKPassed keyin,
|
|
TVPassed valuein,
|
|
ULONG ulPseudoKey,
|
|
TVStored **ppvaluestored,
|
|
BOOL *pfFound
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
bool fMatches = false;
|
|
CBucketIterator Iter(&m_Buckets);
|
|
|
|
for (Iter.Reset(); Iter.More(); Iter.Next())
|
|
{
|
|
IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
|
|
|
|
if (fMatches)
|
|
{
|
|
*ppvaluestored = &Iter->m_tvalue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fMatches)
|
|
{
|
|
CBucket *pCBucket = NULL;
|
|
|
|
IFW32FALSE_EXIT(pTable->AllocateAndInitializeBucket(ulPseudoKey, keyin, valuein, pCBucket));
|
|
|
|
m_Buckets.AddToTail(pCBucket);
|
|
|
|
pTable->m_cEntries++;
|
|
FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Incremented hash table %p entries to %Id\n", __FILE__, __LINE__, pTable, pTable->m_cEntries);
|
|
|
|
if (ppvaluestored != NULL)
|
|
*ppvaluestored = &pCBucket->m_tvalue;
|
|
}
|
|
|
|
if (pfFound != NULL)
|
|
*pfFound = fMatches;
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
template <typename THashTable, typename T>
|
|
BOOL InsertOrUpdateIf(
|
|
THashTable *pTable,
|
|
TKPassed keyin,
|
|
TVPassed valuein,
|
|
ULONG ulPseudoKey,
|
|
T *pt,
|
|
BOOL (T::*pmfn)(
|
|
TVPassed,
|
|
const TVStored &,
|
|
InsertOrUpdateIfDisposition &)
|
|
)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
bool fMatches = false;
|
|
CBucketIterator Iter(&m_Buckets);
|
|
|
|
for (Iter.Reset(); Iter.More(); Iter.Next())
|
|
{
|
|
IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
|
|
|
|
if (fMatches)
|
|
{
|
|
InsertOrUpdateIfDisposition Disposition;
|
|
|
|
IFW32FALSE_EXIT((pt->*pmfn)(valuein, Iter->m_tvalue, Disposition));
|
|
|
|
if (Disposition == eUpdateValue)
|
|
{
|
|
FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Updating value in hash table %p\n", __FILE__, __LINE__, pTable);
|
|
IFW32FALSE_EXIT(THashHelper::UpdateValue(valuein, Iter->m_tvalue));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we didn't find one, we want to insert.
|
|
if (!fMatches)
|
|
{
|
|
CBucket *pCBucket = NULL;
|
|
|
|
IFW32FALSE_EXIT(pTable->AllocateAndInitializeBucket(ulPseudoKey, keyin, valuein, pCBucket));
|
|
|
|
m_Buckets.AddToTail(pCBucket);
|
|
pTable->m_cEntries++;
|
|
FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Incremented hash table %p entries to %Id\n", __FILE__, __LINE__, pTable, pTable->m_cEntries);
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
inline VOID ClearNoCallback(TThisHashTable const *pTable, SIZE_T &rcFound)
|
|
{
|
|
FN_TRACE();
|
|
this->DeallocateBuckets(pTable, rcFound);
|
|
}
|
|
|
|
template <typename T> class CLEAR_CALLBACK_BLOCK
|
|
{
|
|
public:
|
|
VOID DoClear(CBucket *pCBucket) { pCBucket->Clear(pTable, pt, pmfn); pTable->DeallocateBucket(pCBucket); }
|
|
|
|
TThisHashTable const *pTable;
|
|
T *pt;
|
|
VOID (T::*pmfn)(TKStored &, TVStored &);
|
|
};
|
|
|
|
template <typename T> VOID Clear(TThisHashTable const *pTable, T *pt, VOID (T::*pmfn)(TKStored &keystored, TVStored &valuestored))
|
|
{
|
|
FN_TRACE();
|
|
SIZE_T cFound = 0;
|
|
ASSERT((pt != NULL) && (pmfn != NULL));
|
|
|
|
CLEAR_CALLBACK_BLOCK<T> CallbackBlock;
|
|
|
|
CallbackBlock.pTable = pTable;
|
|
CallbackBlock.pt = pt;
|
|
CallbackBlock.pmfn = pmfn;
|
|
|
|
m_Buckets.Clear<CLEAR_CALLBACK_BLOCK<T> >(&CallbackBlock, &CLEAR_CALLBACK_BLOCK<T>::DoClear);
|
|
|
|
this->DeallocateBuckets(pTable, cFound);
|
|
}
|
|
|
|
// BOOL Remove(CHashTable const *pTable, TKPassed keyin, ULONG ulPseudoKey, bool fFirstOnly = false)
|
|
BOOL Remove(CHashTable *pTable, TKPassed keyin, ULONG ulPseudoKey, bool fFirstOnly = false)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
bool fFoundOne = false;
|
|
bool fMatches = false;
|
|
|
|
CBucketIterator Iter(&m_Buckets);
|
|
|
|
Iter.Reset();
|
|
|
|
while (Iter.More())
|
|
{
|
|
IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
|
|
|
|
if (fMatches)
|
|
{
|
|
CBucket *pCBucket = Iter.RemoveCurrent(eDequeIteratorMoveForward);
|
|
pTable->DeallocateBucket(pCBucket);
|
|
fFoundOne = true;
|
|
|
|
pTable->m_cEntries--;
|
|
FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Decremented hash table %p entries to %Id\n", __FILE__, __LINE__, pTable, pTable->m_cEntries);
|
|
|
|
// If we don't allow duplicates, our job is done and there's no point
|
|
// in searching the remainder of the list. Also, if we're only interested
|
|
// in removing the first match we find (and not necessarily all of them),
|
|
// then also bail out.
|
|
if ((!fAllowDups) || (fFirstOnly))
|
|
break;
|
|
}
|
|
else
|
|
Iter.Next();
|
|
}
|
|
|
|
// If we didn't at least find one, then tell the caller.
|
|
if (!fFoundOne)
|
|
ORIGINATE_WIN32_FAILURE_AND_EXIT(HashTableEntryNotFound, ERROR_FILE_NOT_FOUND);
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL Find(TKPassed keyin, ULONG ulPseudoKey, TVStored const *&rpvaluestored) const
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
bool fMatches = false;
|
|
CConstBucketIterator Iter(&m_Buckets);
|
|
|
|
rpvaluestored = NULL;
|
|
|
|
for (Iter.Reset(); Iter.More(); Iter.Next())
|
|
{
|
|
IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
|
|
|
|
if (fMatches)
|
|
{
|
|
rpvaluestored = &Iter->m_tvalue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL Find(TKPassed keyin, ULONG ulPseudoKey, TVStored *&rpvaluestored)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
bool fMatches = false;
|
|
CBucketIterator Iter(&m_Buckets);
|
|
|
|
rpvaluestored = NULL;
|
|
|
|
for (Iter.Reset(); Iter.More(); Iter.Next())
|
|
{
|
|
IFW32FALSE_EXIT(Iter->Matches(keyin, ulPseudoKey, fMatches));
|
|
|
|
if (fMatches)
|
|
{
|
|
rpvaluestored = &Iter->m_tvalue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
VOID TakeValue(CHashTable *pTable, CBucketChain &That)
|
|
{
|
|
SIZE_T cFound = 0;
|
|
this->DeallocateBuckets(pTable, cFound);
|
|
m_Buckets.TakeValue(That.m_Buckets);
|
|
}
|
|
|
|
CDeque<CBucket, FIELD_OFFSET(CBucket, m_Linkage)> m_Buckets;
|
|
private:
|
|
CBucketChain(const CBucketChain &);
|
|
void operator =(const CBucketChain &);
|
|
};
|
|
|
|
inline BOOL AllocateAndInitializeBucket(
|
|
ULONG ulPseudoKey,
|
|
TKPassed keyin,
|
|
TVPassed valuein,
|
|
CBucket *&rpBucket
|
|
) const
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
rpBucket = NULL;
|
|
CBucket *pBucket = NULL;
|
|
|
|
IFALLOCFAILED_EXIT(pBucket = new CBucket(ulPseudoKey));
|
|
IFW32FALSE_EXIT(pBucket->Initialize(this, keyin, valuein));
|
|
|
|
rpBucket = pBucket;
|
|
pBucket = NULL;
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
if (pBucket != NULL)
|
|
this->DeallocateBucket(pBucket);
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
inline void DeallocateBucket(CBucket *pCBucket) const { FUSION_DELETE_SINGLETON(pCBucket); }
|
|
|
|
friend CBucket;
|
|
friend CBucketChain;
|
|
|
|
ULONG m_cBucketChains;
|
|
CBucketChain *m_prgBucketChains;
|
|
CBucketChain m_rgInlineBucketChains[nInlineBucketChains];
|
|
SIZE_T m_ulLockCount;
|
|
SIZE_T m_cEntries;
|
|
bool m_fInsertionsPermitted;
|
|
bool m_fRemovalsPermitted;
|
|
private:
|
|
CHashTable(const CHashTable &r); // intentionally not implmented
|
|
void operator =(const CHashTable &r); // intentionally not implemented
|
|
|
|
};
|
|
|
|
template <typename TKPassed, typename TKStored, typename TVPassed, typename TVStored, class THashHelper = CHashTableHelper<TKPassed, TKStored, TVPassed, TVStored>, ULONG nInlineBucketChains = 7, bool fAllowDups = false> class CHashTableIter
|
|
{
|
|
typedef CHashTable<TKPassed, TKStored, TVPassed, TVStored, THashHelper, nInlineBucketChains, fAllowDups> THashTable;
|
|
|
|
public:
|
|
inline CHashTableIter(CHashTable<TKPassed, TKStored, TVPassed, TVStored, THashHelper, nInlineBucketChains, fAllowDups> &r) : m_rTable(r), m_iBucketChain(0),
|
|
m_fAlreadyAdvanced(false) { }
|
|
|
|
inline ~CHashTableIter() { }
|
|
|
|
inline void Reset()
|
|
{
|
|
FN_TRACE();
|
|
|
|
m_iBucketChain = 0;
|
|
m_fAlreadyAdvanced = false;
|
|
|
|
// Move the bucket iterator across the bucket chains looking for one with some
|
|
// buckets
|
|
for (m_iBucketChain = 0; m_iBucketChain < m_rTable.m_cBucketChains; m_iBucketChain++)
|
|
{
|
|
m_Iter.Rebind(&m_rTable.m_prgBucketChains[m_iBucketChain].m_Buckets);
|
|
m_Iter.Reset();
|
|
if (m_Iter.More())
|
|
break;
|
|
}
|
|
|
|
if (m_iBucketChain == m_rTable.m_cBucketChains)
|
|
{
|
|
// There wasn't anything. Unbind the iterator to signal that we're
|
|
// totally done.
|
|
m_Iter.Unbind();
|
|
}
|
|
}
|
|
|
|
inline void Delete()
|
|
{
|
|
FN_TRACE();
|
|
|
|
CSxsPreserveLastError ple;
|
|
|
|
ASSERT(m_Iter.IsBound());
|
|
if (m_Iter.IsBound())
|
|
{
|
|
THashTable::CBucket *pCBucket = m_Iter.RemoveCurrent(eDequeIteratorMoveForward);
|
|
FUSION_DELETE_SINGLETON(pCBucket);
|
|
m_fAlreadyAdvanced = true;
|
|
m_rTable.m_cEntries--;
|
|
::FusionpDbgPrintEx(FUSION_DBG_LEVEL_HASHTABLE, "%s(%d): Decremented hash table %p entries to %Id\n", __FILE__, __LINE__, &m_rTable, m_rTable.m_cEntries);
|
|
}
|
|
|
|
ple.Restore();
|
|
}
|
|
|
|
inline BOOL Update(TVPassed valuein) const
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
INTERNAL_ERROR_CHECK(m_Iter.IsBound());
|
|
INTERNAL_ERROR_CHECK(!m_fAlreadyAdvanced);
|
|
|
|
IFW32FALSE_EXIT(m_Iter->Update(valuein));
|
|
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
inline bool More() const { return m_Iter.IsBound(); }
|
|
|
|
inline void Next()
|
|
{
|
|
FN_TRACE();
|
|
|
|
if (m_Iter.IsBound())
|
|
{
|
|
// If someone deleted the current element, the iterator has already been
|
|
// advanced. Otherwise, move on.
|
|
if (!m_fAlreadyAdvanced)
|
|
m_Iter.Next();
|
|
|
|
// We've taken it into account, now forget about it.
|
|
m_fAlreadyAdvanced = false;
|
|
|
|
// If there aren't any more elements in this deque, try the next bucket chain
|
|
if (!m_Iter.More())
|
|
{
|
|
m_iBucketChain++;
|
|
|
|
while (m_iBucketChain < m_rTable.m_cBucketChains)
|
|
{
|
|
m_Iter.Rebind(&m_rTable.m_prgBucketChains[m_iBucketChain].m_Buckets);
|
|
m_Iter.Reset();
|
|
if (m_Iter.More())
|
|
break;
|
|
m_iBucketChain++;
|
|
}
|
|
|
|
if (m_iBucketChain == m_rTable.m_cBucketChains)
|
|
m_Iter.Unbind();
|
|
}
|
|
}
|
|
}
|
|
|
|
inline const TKStored &GetKey() const
|
|
{
|
|
FN_TRACE();
|
|
|
|
// Should not call this if More() returns false
|
|
ASSERT(m_Iter.IsBound());
|
|
|
|
if (m_Iter.IsBound() && m_Iter.More())
|
|
{
|
|
return m_Iter->m_tkey;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
inline TVStored &GetValue() const
|
|
{
|
|
FN_TRACE();
|
|
|
|
// Should not call this function if More() returns false
|
|
ASSERT(m_Iter.IsBound());
|
|
return m_Iter->m_tvalue;
|
|
}
|
|
|
|
inline TVStored &operator ->() const
|
|
{
|
|
FN_TRACE();
|
|
|
|
// Should not call this function if More() returns false
|
|
ASSERT(m_Iter.IsBound());
|
|
return m_Iter->m_tvalue;
|
|
}
|
|
|
|
protected:
|
|
THashTable &m_rTable;
|
|
THashTable::CBucketIterator m_Iter;
|
|
ULONG m_iBucketChain;
|
|
bool m_fAlreadyAdvanced;
|
|
|
|
private:
|
|
CHashTableIter(const CHashTableIter &);
|
|
void operator =(const CHashTableIter &);
|
|
};
|
|
|
|
//
|
|
// Helper class for hash tables of filenames:
|
|
//
|
|
|
|
template <typename TVPassed, typename TVStored> class CFusionFilenameHashTableHelper : public CHashTableHelper<LPCWSTR, CUnicodeStringBuffer, TVPassed, TVStored>
|
|
{
|
|
public:
|
|
inline static BOOL HashKey(LPCWSTR sz, ULONG &rulPseudoKey)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
ULONG ulPK = 0;
|
|
LPCWSTR pszTemp;
|
|
WCHAR wch;
|
|
|
|
if (sz != NULL)
|
|
{
|
|
SIZE_T cch = ::wcslen(sz);
|
|
IFW32FALSE_EXIT(::FusionpHashUnicodeString(sz, cch, &ulPK, true));
|
|
}
|
|
|
|
rulPseudoKey = ulPK;
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
static BOOL CompareKey(LPCWSTR szKey, CUnicodeBaseStringBuffer *pbuff, bool &rfMatch)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
int iResult;
|
|
|
|
rfMatch = false;
|
|
|
|
PARAMETER_CHECK(pbuff != NULL);
|
|
|
|
iResult = ::FusionpCompareStrings(
|
|
szKey, (szKey == NULL) ? 0 : ::wcslen(szKey),
|
|
static_cast<LPCWSTR>(*pbuff), pbuff->Cch(),
|
|
true);
|
|
|
|
rfMatch = (iResult == 2); // In SDK DOCS, 2 == CSTR_EQUAL; there is no constant defined. -mgrier 12/6/1999
|
|
fSuccess = TRUE;
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
};
|
|
|
|
//
|
|
// CSimpleKeyedTable
|
|
//
|
|
// A simplification of the CHashTable class template which assumes that
|
|
// keys are passed as const references.
|
|
//
|
|
|
|
template <typename TKey, typename TVPassed, typename TVStored, typename THashHelper> class CSimpleKeyedTable : public CHashTable<const TKey &, TKey, TVPassed, TVStored, THashHelper>
|
|
{
|
|
public:
|
|
CSimpleKeyedTable() : CHashTable<const TKey &, TKey, TVPassed, TVStored, THashHelper>() { }
|
|
};
|
|
|
|
template <typename TKey, typename TVPassed, typename TVStored, typename THashHelper> class CSimpleKeyedTableIter : public CHashTableIter<const TKey &, TKey, TVPassed, TVStored, THashHelper>
|
|
{
|
|
typedef CHashTableIter<const TKey &, TKey, TVPassed, TVStored, THashHelper> Base;
|
|
public:
|
|
CSimpleKeyedTableIter(CSimpleKeyedTable<TKey, TVPassed, TVStored, THashHelper> &Table) : Base(Table) { }
|
|
};
|
|
|
|
template <typename TKPassed, typename TKStored, typename TValue> class CPtrTableHelper : public CHashTableHelper<TKPassed, TKStored, TValue *, TValue *>
|
|
{
|
|
typedef TValue *TValuePtr;
|
|
|
|
public:
|
|
static VOID PreInitializeValue(TValue *&rvstored) { rvstored = NULL; }
|
|
static BOOL InitializeValue(const TValuePtr &vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
|
|
static BOOL UpdateValue(const TValuePtr &vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
|
|
static VOID FinalizeValue(TValuePtr &rvstored) { if (rvstored != NULL) { FUSION_DELETE_SINGLETON(rvstored); rvstored = NULL; } }
|
|
};
|
|
|
|
template <typename TKPassed, typename TKStored, typename TValue, typename THashHelper = CPtrTableHelper<TKPassed, TKStored, TValue> > class CPtrTable : public CHashTable<TKPassed, TKStored, TValue *, TValue *, THashHelper>
|
|
{
|
|
public:
|
|
CPtrTable() : CHashTable<TKPassed, TKStored, TValue *, TValue *, THashHelper>() { }
|
|
|
|
BOOL Find(TKPassed keyin, TValue *&rpvaluestored)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
ULONG ulPseudoKey = 0;
|
|
ULONG iBucket = 0;
|
|
TValue **ppValue = NULL;
|
|
|
|
rpvaluestored = NULL;
|
|
|
|
IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
|
|
|
|
iBucket = ulPseudoKey % m_cBucketChains;
|
|
|
|
IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, ppValue));
|
|
|
|
if (ppValue != NULL)
|
|
rpvaluestored = *ppValue;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
private:
|
|
CPtrTable(const CPtrTable &);
|
|
void operator =(const CPtrTable &);
|
|
};
|
|
|
|
template <typename TKPassed, typename TKStored, typename TValue, typename THashHelper = CPtrTableHelper<TKPassed, TKStored, TValue> > class CPtrTableIter : public CHashTableIter<TKPassed, TKStored, TValue *, TValue *, THashHelper>
|
|
{
|
|
public:
|
|
CPtrTableIter(CPtrTable<TKPassed, TKStored, TValue, THashHelper> &Table) : CHashTableIter<TKPassed, TKStored, TValue *, TValue *, THashHelper>(Table) { }
|
|
|
|
private:
|
|
CPtrTableIter(const CPtrTableIter &);
|
|
void operator =(const CPtrTableIter &);
|
|
};
|
|
|
|
template <typename TKey, typename TValue> class CSimplePtrTableHelper : public CPtrTableHelper<const TKey &, TKey, TValue>
|
|
{
|
|
public:
|
|
};
|
|
|
|
//
|
|
// CSimplePtrTable
|
|
//
|
|
// A simplification of CHashTable class template which assumes
|
|
// that keys are passed as const references and values are pointers.
|
|
//
|
|
// Note that the table does NOT own allocating or deallocating the storage
|
|
// to which the pointers refer. If the table is destroyed, the
|
|
// storage is not released.
|
|
//
|
|
|
|
template <typename TKey, typename TValue, typename THashHelper = CSimplePtrTableHelper<TKey, TValue> > class CSimplePtrTable : public CSimpleKeyedTable<TKey, TValue *, TValue *, THashHelper>
|
|
{
|
|
public:
|
|
CSimplePtrTable() : CSimpleKeyedTable<TKey, TValue *, TValue *, THashHelper>(hHeap) { }
|
|
|
|
BOOL Find(const TKey &keyin, TValue *&rpvaluestored)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
|
|
ULONG ulPseudoKey = 0;
|
|
ULONG iBucket = 0;
|
|
TValue **ppValue = NULL;
|
|
|
|
rpvaluestored = NULL;
|
|
|
|
IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
|
|
|
|
iBucket = ulPseudoKey % m_cBucketChains;
|
|
|
|
IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, ppValue));
|
|
|
|
if (ppValue != NULL)
|
|
rpvaluestored = *ppValue;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
private:
|
|
CSimplePtrTable(const CSimplePtrTable &);
|
|
void operator =(const CSimplePtrTable &);
|
|
};
|
|
|
|
template <typename TKey, typename TValue, typename THashHelper = CSimplePtrTableHelper<TKey, TValue> > class CSimplePtrTableIter : public CSimpleKeyedTableIter<TKey, TValue *, TValue *, THashHelper>
|
|
{
|
|
typedef CSimpleKeyedTableIter<TKey, TValue *, TValue *, THashHelper> Base;
|
|
public:
|
|
CSimplePtrTableIter(CSimplePtrTable<TKey, TValue, THashHelper> &Table)
|
|
: Base(Table) { }
|
|
private:
|
|
CSimplePtrTableIter(const CSimplePtrTableIter &);
|
|
void operator =(const CSimplePtrTableIter &);
|
|
};
|
|
|
|
template <typename TVPassed, typename TVStored> class CGuidTableHelper : public CHashTableHelper<GUID, GUID, TVPassed, TVStored>
|
|
{
|
|
typedef CHashTableHelper<REFGUID, GUID, TVPassed, TVStored> Base;
|
|
public:
|
|
static BOOL InitializeKey(REFGUID keyin, GUID &rtkeystored) { rtkeystored = keyin; return TRUE; }
|
|
};
|
|
|
|
template <typename TVPassed, typename TVStored, typename THashHelper = CGuidTableHelper<TVPassed, TVStored> > class CGuidTable : public CHashTable<REFGUID, GUID, TVPassed, TVStored, THashHelper >
|
|
{
|
|
public:
|
|
CGuidTable() : CHashTable<REFGUID, GUID, TVPassed, TVStored, THashHelper >() { }
|
|
private:
|
|
CGuidTable(const CGuidTable &);
|
|
void operator =(const CGuidTable &);
|
|
};
|
|
|
|
template <typename TVPassed, typename TVStored, typename THashHelper = CGuidTableHelper<TVPassed, TVStored> > class CGuidTableIter : public CHashTableIter<REFGUID, GUID, TVPassed, TVStored, THashHelper >
|
|
{
|
|
typedef CHashTableIter<REFGUID, GUID, TVPassed, TVStored, THashHelper > Base;
|
|
public:
|
|
CGuidTableIter(CGuidTable<TVPassed, TVStored, THashHelper> &Table) : Base(Table) { }
|
|
private:
|
|
CGuidTableIter(const CGuidTableIter &);
|
|
void operator =(const CGuidTableIter &);
|
|
};
|
|
|
|
template <typename TValue> class CGuidPtrTableHelper : public CHashTableHelper<REFGUID, GUID, TValue *, TValue *>
|
|
{
|
|
public:
|
|
static BOOL InitializeKey(REFGUID keyin, GUID &rtkeystored) { rtkeystored = keyin; return TRUE; }
|
|
static BOOL InitializeValue(TValue *vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
|
|
static BOOL UpdateValue(TValue *vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
|
|
};
|
|
|
|
template <typename TValue, typename THashHelper = CGuidPtrTableHelper<TValue> > class CGuidPtrTable : public CGuidTable<TValue *, TValue *, THashHelper>
|
|
{
|
|
public:
|
|
CGuidPtrTable() : CGuidTable<TValue *, TValue *, THashHelper>() { }
|
|
private:
|
|
CGuidPtrTable(const CGuidPtrTable &);
|
|
void operator =(const CGuidPtrTable &);
|
|
};
|
|
|
|
template <typename TValue, typename THashHelper = CGuidPtrTableHelper<TValue> > class CGuidPtrTableIter : public CGuidTableIter<TValue *, TValue *, THashHelper>
|
|
{
|
|
typedef CGuidTableIter<TValue *, TValue *, THashHelper> Base;
|
|
public:
|
|
CGuidPtrTableIter(CGuidPtrTable<TValue, THashHelper> &Table) : Base(Table) { }
|
|
private:
|
|
CGuidPtrTableIter(const CGuidPtrTableIter &);
|
|
void operator =(const CGuidPtrTableIter &);
|
|
};
|
|
|
|
template <typename TVPassed, typename TVStored, typename TCharTraits, bool fCaseInsensitive = false> class CStringTableHelper : public CHashTableHelper<const CCountedStringHolder<TCharTraits> &, CStringBuffer, TVPassed, TVStored>
|
|
{
|
|
public:
|
|
typedef CCountedStringHolder<TCharTraits> TCountedStringHolder;
|
|
|
|
static BOOL HashKey(const TCountedStringHolder &keyin, ULONG &rulPseudoKey) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); IFW32FALSE_EXIT(TCharTraits::Win32HashString(keyin.m_psz, keyin.m_cch, rulPseudoKey, fCaseInsensitive)); fSuccess = TRUE; Exit: return fSuccess; }
|
|
static BOOL InitializeKey(const TCountedStringHolder &keyin, CBaseStringBuffer &rtkeystored) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); IFW32FALSE_EXIT(rtkeystored.Win32Assign(keyin.m_psz, keyin.m_cch)); fSuccess = TRUE; Exit: return fSuccess; }
|
|
static BOOL CompareKey(const TCountedStringHolder &keyin, const CBaseStringBuffer &rtkeystored, bool &rfMatch) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); IFW32FALSE_EXIT(rtkeystored.Win32Equals(keyin.m_psz, keyin.m_cch, rfMatch, fCaseInsensitive)); fSuccess = TRUE; Exit: return fSuccess; }
|
|
};
|
|
|
|
class STRING_TABLE_CLEAR_CALLBACK_BLOCK_BASE
|
|
{
|
|
public:
|
|
virtual VOID DoClear(PVOID) = 0;
|
|
};
|
|
|
|
template <typename TVPassed, typename TVStored, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CStringTableHelper<TVPassed, TVStored, TCharTraits, dwCmpFlags> > class CStringTable : public CHashTable<const CCountedStringHolder<TCharTraits> &, CStringBuffer, TVPassed, TVStored, THashHelper>
|
|
{
|
|
typedef CHashTable<const CCountedStringHolder<TCharTraits> &, CStringBuffer, TVPassed, TVStored, THashHelper> Base;
|
|
|
|
public:
|
|
typedef CCountedStringHolder<TCharTraits> TCountedStringHolder;
|
|
|
|
protected:
|
|
VOID ClearCallbackWrapper(CStringBuffer &key, TVStored &valuestored)
|
|
{
|
|
FN_TRACE();
|
|
|
|
key.Clear();
|
|
m_pActiveClearCallbackBlock->DoClear(valuestored);
|
|
}
|
|
|
|
STRING_TABLE_CLEAR_CALLBACK_BLOCK_BASE *m_pActiveClearCallbackBlock;
|
|
|
|
template <typename T> class STRING_TABLE_CLEAR_CALLBACK_BLOCK : public STRING_TABLE_CLEAR_CALLBACK_BLOCK_BASE
|
|
{
|
|
public:
|
|
T *pt;
|
|
VOID (T::*pmfn)(TVStored &valuestored);
|
|
|
|
VOID DoClear(PVOID pv) { TVStored *pvstored = (TVStored *) pv; (pt->*pmfn)(*pvstored); }
|
|
};
|
|
|
|
// Introduce name that derived classes will not override to work around compiler bugs
|
|
inline VOID ClearStringTable(STRING_TABLE_CLEAR_CALLBACK_BLOCK_BASE *pCallbackBlock)
|
|
{
|
|
FN_TRACE();
|
|
|
|
ASSERT(m_pActiveClearCallbackBlock == NULL);
|
|
|
|
m_pActiveClearCallbackBlock = pCallbackBlock;
|
|
|
|
ULONG i;
|
|
|
|
for (i=0; i<m_cBucketChains; i++)
|
|
m_prgBucketChains[i].Clear<CStringTable>(this, this, &CStringTable::ClearCallbackWrapper);
|
|
|
|
this->ClearNoCallback();
|
|
|
|
m_pActiveClearCallbackBlock = NULL;
|
|
}
|
|
|
|
public:
|
|
typedef CCountedStringHolder<TCharTraits> TCountedStringHolder;
|
|
|
|
CStringTable() : CHashTable<const TCountedStringHolder &, CStringBuffer, TVPassed, TVStored, THashHelper>(), m_pActiveClearCallbackBlock(NULL) { }
|
|
|
|
template <typename T> inline VOID Clear(T *pt, VOID (T::*pmfn)(TVStored &valuestored))
|
|
{
|
|
FN_TRACE();
|
|
|
|
STRING_TABLE_CLEAR_CALLBACK_BLOCK<T> CallbackBlock;
|
|
CallbackBlock.pt = pt;
|
|
CallbackBlock.pmfn = pmfn;
|
|
this->ClearStringTable(&CallbackBlock);
|
|
}
|
|
|
|
private:
|
|
CStringTable(const CStringTable &);
|
|
void operator =(const CStringTable &);
|
|
};
|
|
|
|
template <typename TVPassed, typename TVStored, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CStringTableHelper<TVPassed, TVStored, TCharTraits, dwCmpFlags> > class CStringTableIter : public CHashTableIter<const CCountedStringHolder<TCharTraits> &, CStringBuffer, TVPassed, TVStored, THashHelper>
|
|
{
|
|
public:
|
|
typedef CCountedStringHolder<TCharTraits> TCountedStringHolder;
|
|
|
|
protected:
|
|
typedef CHashTableIter<const TCountedStringHolder &, CStringBuffer, TVPassed, TVStored, THashHelper> Base;
|
|
|
|
public:
|
|
CStringTableIter(CStringTable<TVPassed, TVStored, TCharTraits, dwCmpFlags, THashHelper> &rTable) : Base(rTable) { }
|
|
|
|
inline TCharTraits::TConstantString GetKey() const
|
|
{
|
|
FN_TRACE();
|
|
|
|
// Should not call this if More() returns false
|
|
ASSERT(m_Iter != NULL);
|
|
|
|
//
|
|
// m_ulLockCount doesn't exist. I'm wondering if perhaps this entire function
|
|
// could be axed in favor of using the default one, which does something
|
|
// very similar. (jonwis 8/24/00)
|
|
//
|
|
// ASSERT(m_ulLockCount != 0);
|
|
|
|
if (m_Iter != NULL)
|
|
return m_Iter->m_tkey;
|
|
|
|
return NULL;
|
|
}
|
|
private:
|
|
CStringTableIter(const CStringTableIter &);
|
|
void operator =(const CStringTableIter &);
|
|
};
|
|
|
|
template <typename TValue, typename TCharTraits, bool fCaseInsensitive = false> class CStringPtrTableHelper : public CStringTableHelper<TValue *, TValue *, TCharTraits, fCaseInsensitive>
|
|
{
|
|
public:
|
|
static VOID PreInitializeValue(TValue *&rvstored) { rvstored = NULL; }
|
|
static BOOL InitializeValue(TValue *vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
|
|
static BOOL UpdateValue(TValue *vin, TValue *&rvstored) { rvstored = vin; return TRUE; }
|
|
static VOID FinalizeValue(TValue *&rvstored) { if (rvstored != NULL) { FUSION_DELETE_SINGLETON(rvstored); rvstored = NULL; } }
|
|
};
|
|
|
|
template <typename TValue, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CStringPtrTableHelper<TValue, TCharTraits, dwCmpFlags> > class CStringPtrTable : public CStringTable<TValue *, TValue *, TCharTraits, dwCmpFlags, THashHelper>
|
|
{
|
|
typedef CStringTable<TValue *, TValue *, TCharTraits, dwCmpFlags, THashHelper> Base;
|
|
|
|
protected:
|
|
template <typename T> class STRING_PTR_TABLE_CLEAR_CALLBACK_BLOCK : public STRING_TABLE_CLEAR_CALLBACK_BLOCK_BASE
|
|
{
|
|
public:
|
|
T *pt;
|
|
VOID (T::*pmfn)(TValue *pvaluestored);
|
|
|
|
VOID DoClear(PVOID pv) { /* TValue **ppvstored = (TValue **) pv; */ (pt->*pmfn)((TValue *) pv); }
|
|
};
|
|
|
|
public:
|
|
CStringPtrTable() : CStringTable<TValue *, TValue *, TCharTraits, dwCmpFlags, THashHelper>() { }
|
|
|
|
template <typename T> VOID Clear(T *pt, VOID (T::*pmfn)(TValue *valuestored))
|
|
{
|
|
FN_TRACE();
|
|
|
|
STRING_PTR_TABLE_CLEAR_CALLBACK_BLOCK<T> CallbackBlock;
|
|
CallbackBlock.pt = pt;
|
|
CallbackBlock.pmfn = pmfn;
|
|
this->ClearStringTable(&CallbackBlock);
|
|
}
|
|
|
|
BOOL Find(const TCountedStringHolder &keyin, TValue const *&rpvaluestored) const
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
ULONG ulPseudoKey = 0;
|
|
ULONG iBucket = 0;
|
|
|
|
rpvaluestored = NULL;
|
|
|
|
IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
|
|
|
|
iBucket = ulPseudoKey % m_cBucketChains;
|
|
|
|
IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, rpvaluestored));
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL Find(const TCountedStringHolder &keyin, TValue *&rpvaluestored)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
FN_TRACE_WIN32(fSuccess);
|
|
ULONG ulPseudoKey = 0;
|
|
ULONG iBucket = 0;
|
|
TValue **ppvaluestored = NULL;
|
|
|
|
rpvaluestored = NULL;
|
|
|
|
IFW32FALSE_EXIT(THashHelper::HashKey(keyin, ulPseudoKey));
|
|
|
|
iBucket = ulPseudoKey % m_cBucketChains;
|
|
|
|
IFW32FALSE_EXIT(m_prgBucketChains[iBucket].Find(keyin, ulPseudoKey, ppvaluestored));
|
|
|
|
if (ppvaluestored != NULL)
|
|
rpvaluestored = *ppvaluestored;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
Exit:
|
|
return fSuccess;
|
|
}
|
|
|
|
private:
|
|
CStringPtrTable(const CStringPtrTable &);
|
|
void operator =(const CStringPtrTable &);
|
|
};
|
|
|
|
template <typename TValue, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CStringPtrTableHelper<TValue, TCharTraits, dwCmpFlags> > class CStringPtrTableIter : public CStringTableIter<TValue *, TValue *, TCharTraits, dwCmpFlags, THashHelper>
|
|
{
|
|
typedef CStringTableIter<TValue *, TValue *, TCharTraits, dwCmpFlags, THashHelper> Base;
|
|
public:
|
|
CStringPtrTableIter(CStringPtrTable<TValue, TCharTraits, dwCmpFlags, THashHelper> &rTable) : Base(rTable) { }
|
|
|
|
operator TValue *() const { return this->GetValue(); }
|
|
TValue *operator ->() const { return this->GetValue(); }
|
|
|
|
private:
|
|
CStringPtrTableIter(const CStringPtrTableIter &);
|
|
void operator =(const CStringPtrTableIter &);
|
|
};
|
|
|
|
template <typename TValue, typename TCharTraits, DWORD dwCmpFlags = 0> class CSimpleStringTableHelper : public CStringTableHelper<const TValue &, TValue, TCharTraits, dwCmpFlags>
|
|
{
|
|
public:
|
|
static BOOL InitializeValue(const TValue &vin, TValue &rvstored) { rvstored = vin; return TRUE; }
|
|
static BOOL UpdateValue(const TValue &vin, TValue &rvstored) { rvstored = vin; return TRUE; }
|
|
};
|
|
|
|
template <typename TValue, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CSimpleStringTableHelper<TValue, TCharTraits, dwCmpFlags> > class CSimpleStringTable : public CStringTable<const TValue &, TValue, TCharTraits, dwCmpFlags, THashHelper>
|
|
{
|
|
public:
|
|
CSimpleStringTable() : CStringTable<const TValue &, TValue, TCharTraits, dwCmpFlags, THashHelper>() { }
|
|
private:
|
|
CSimpleStringTable(const CSimpleStringTable &);
|
|
void operator =(const CSimpleStringTable &);
|
|
};
|
|
|
|
template <typename TValue, typename TCharTraits, DWORD dwCmpFlags = 0, typename THashHelper = CSimpleStringTableHelper<TValue, TCharTraits, dwCmpFlags> > class CSimpleStringTableIter : public CStringTableIter<const TValue &, TValue, TCharTraits, dwCmpFlags, THashHelper>
|
|
{
|
|
typedef CStringTableIter<const TValue &, TValue, TCharTraits, dwCmpFlags, THashHelper> Base;
|
|
public:
|
|
CSimpleStringTableIter(CSimpleStringTable<TValue, TCharTraits, dwCmpFlags, THashHelper> &rTable) : Base(rTable) { }
|
|
|
|
private:
|
|
CSimpleStringTableIter(const CSimpleStringTableIter &);
|
|
void operator =(const CSimpleStringTableIter &);
|
|
};
|
|
|
|
// CSimpleUnicodeStringTable et al:
|
|
|
|
template <typename TValue, DWORD dwCmpFlags = 0> class CSimpleUnicodeStringTableHelper : public CSimpleStringTableHelper<TValue, CUnicodeCharTraits, dwCmpFlags>
|
|
{
|
|
};
|
|
|
|
template <typename TValue, DWORD dwCmpFlags = 0, typename THashHelper = CSimpleUnicodeStringTableHelper<TValue, dwCmpFlags> > class CSimpleUnicodeStringTable : public CSimpleStringTable<TValue, CUnicodeCharTraits, dwCmpFlags, THashHelper>
|
|
{
|
|
typedef CSimpleStringTable<TValue, CUnicodeCharTraits, dwCmpFlags, THashHelper> Base;
|
|
public:
|
|
CSimpleUnicodeStringTable() : Base() { }
|
|
private:
|
|
CSimpleUnicodeStringTable(const CSimpleUnicodeStringTable &);
|
|
void operator =(const CSimpleUnicodeStringTable &);
|
|
};
|
|
|
|
template <typename TValue, DWORD dwCmpFlags = 0, typename THashHelper = CSimpleUnicodeStringTableHelper<TValue, dwCmpFlags> > class CSimpleUnicodeStringTableIter : public CSimpleStringTableIter<TValue, CUnicodeCharTraits, dwCmpFlags, THashHelper>
|
|
{
|
|
typedef CSimpleStringTableIter<TValue, CUnicodeCharTraits, dwCmpFlags, THashHelper> Base;
|
|
typedef CSimpleUnicodeStringTable<TValue, dwCmpFlags, THashHelper> TTable;
|
|
|
|
public:
|
|
CSimpleUnicodeStringTableIter(TTable &rTable) : Base(rTable) { }
|
|
private:
|
|
CSimpleUnicodeStringTableIter(const CSimpleUnicodeStringTableIter &);
|
|
void operator =(const CSimpleUnicodeStringTableIter &);
|
|
};
|
|
|
|
// CCaseInsensitiveSimpleStringTable et al:
|
|
|
|
template <typename TValue, typename TCharTraits> class CCaseInsensitiveSimpleStringTableHelper : public CSimpleStringTableHelper<TValue, TCharTraits, true>
|
|
{
|
|
};
|
|
|
|
template <typename TValue, typename TCharTraits, typename THashHelper = CCaseInsensitiveSimpleStringTableHelper<TValue, TCharTraits> > class CCaseInsensitiveSimpleStringTable : public CSimpleStringTable<TValue, TCharTraits, true, THashHelper>
|
|
{
|
|
typedef CSimpleStringTable<TValue, TCharTraits, true, THashHelper> Base;
|
|
public:
|
|
CCaseInsensitiveSimpleStringTable() : Base() { }
|
|
};
|
|
|
|
template <typename TValue, typename TCharTraits, typename THashHelper = CCaseInsensitiveSimpleStringTableHelper<TValue, TCharTraits> > class CCaseInsensitiveSimpleStringTableIter : public CSimpleStringTableIter<TValue, TCharTraits, true, THashHelper>
|
|
{
|
|
typedef CSimpleStringTableIter<TValue, TCharTraits, true, THashHelper> Base;
|
|
public:
|
|
CCaseInsensitiveSimpleStringTableIter(CCaseInsensitiveSimpleStringTable<TValue, TCharTraits, THashHelper> &rTable) : Base(rTable) { }
|
|
};
|
|
|
|
// CCaseInsensitiveSimpleUnicodeStringTable et al:
|
|
|
|
template <typename TValue> class CCaseInsensitiveSimpleUnicodeStringTableHelper : public CSimpleUnicodeStringTableHelper<TValue, true>
|
|
{
|
|
};
|
|
|
|
template <typename TValue, typename THashHelper = CCaseInsensitiveSimpleUnicodeStringTableHelper<TValue> > class CCaseInsensitiveSimpleUnicodeStringTable : public CSimpleUnicodeStringTable<TValue, true, THashHelper>
|
|
{
|
|
typedef CSimpleUnicodeStringTable<TValue, true, THashHelper> Base;
|
|
public:
|
|
CCaseInsensitiveSimpleUnicodeStringTable() : Base() { }
|
|
|
|
private:
|
|
CCaseInsensitiveSimpleUnicodeStringTable(const CCaseInsensitiveSimpleUnicodeStringTable &);
|
|
void operator =(const CCaseInsensitiveSimpleUnicodeStringTable &);
|
|
};
|
|
|
|
template <typename TValue, typename THashHelper = CCaseInsensitiveSimpleUnicodeStringTableHelper<TValue> > class CCaseInsensitiveSimpleUnicodeStringTableIter : public CSimpleUnicodeStringTableIter<TValue, true, THashHelper>
|
|
{
|
|
typedef CSimpleUnicodeStringTableIter<TValue, true, THashHelper> Base;
|
|
public:
|
|
CCaseInsensitiveSimpleUnicodeStringTableIter(CCaseInsensitiveSimpleUnicodeStringTable<TValue, THashHelper> &rTable) : Base(rTable) { }
|
|
|
|
private:
|
|
CCaseInsensitiveSimpleUnicodeStringTableIter(const CCaseInsensitiveSimpleUnicodeStringTableIter &);
|
|
void operator =(const CCaseInsensitiveSimpleUnicodeStringTableIter &);
|
|
};
|
|
|
|
// CCaseInsensitiveStringPtrTable et al:
|
|
|
|
template <typename TValue, typename TCharTraits> class CCaseInsensitiveStringPtrTableHelper : public CStringPtrTableHelper<TValue, TCharTraits, true>
|
|
{
|
|
};
|
|
|
|
template <typename TValue, typename TCharTraits, typename THashHelper = CCaseInsensitiveStringPtrTableHelper<TValue, TCharTraits> > class CCaseInsensitiveStringPtrTable : public CStringPtrTable<TValue, TCharTraits, true, THashHelper>
|
|
{
|
|
typedef CStringPtrTable<TValue, TCharTraits, true, THashHelper> Base;
|
|
public:
|
|
CCaseInsensitiveStringPtrTable() : Base() { }
|
|
};
|
|
|
|
template <typename TValue, typename TCharTraits, typename THashHelper = CCaseInsensitiveStringPtrTableHelper<TValue, TCharTraits> > class CCaseInsensitiveStringPtrTableIter : public CStringPtrTableIter<TValue, TCharTraits, true, THashHelper>
|
|
{
|
|
typedef CStringPtrTableIter<TValue, TCharTraits, true, THashHelper> Base;
|
|
|
|
public:
|
|
CCaseInsensitiveStringPtrTableIter(CCaseInsensitiveStringPtrTable<TValue, TCharTraits, THashHelper> &rTable) : Base(rTable) { }
|
|
};
|
|
|
|
// CCaseInsensitiveUnicodeStringPtrTable et al:
|
|
|
|
template <typename TValue> class CCaseInsensitiveUnicodeStringPtrTableHelper : public CStringPtrTableHelper<TValue, CUnicodeCharTraits, true>
|
|
{
|
|
};
|
|
|
|
template <typename TValue, typename THashHelper = CCaseInsensitiveUnicodeStringPtrTableHelper<TValue> > class CCaseInsensitiveUnicodeStringPtrTable : public CStringPtrTable<TValue, CUnicodeCharTraits, true, THashHelper>
|
|
{
|
|
typedef CStringPtrTable<TValue, CUnicodeCharTraits, true, THashHelper> Base;
|
|
public:
|
|
CCaseInsensitiveUnicodeStringPtrTable() { }
|
|
|
|
private:
|
|
CCaseInsensitiveUnicodeStringPtrTable(const CCaseInsensitiveUnicodeStringPtrTable &r);
|
|
void operator =(const CCaseInsensitiveUnicodeStringPtrTable &r);
|
|
};
|
|
|
|
template <typename TValue, typename THashHelper = CCaseInsensitiveUnicodeStringPtrTableHelper<TValue> > class CCaseInsensitiveUnicodeStringPtrTableIter : public CStringPtrTableIter<TValue, CUnicodeCharTraits, true, THashHelper>
|
|
{
|
|
typedef CStringPtrTableIter<TValue, CUnicodeCharTraits, true, THashHelper> Base;
|
|
|
|
public:
|
|
CCaseInsensitiveUnicodeStringPtrTableIter(CCaseInsensitiveUnicodeStringPtrTable<TValue, THashHelper> &rTable) : Base(rTable) { }
|
|
|
|
private:
|
|
CCaseInsensitiveUnicodeStringPtrTableIter(const CCaseInsensitiveUnicodeStringPtrTableIter &);
|
|
void operator =(const CCaseInsensitiveUnicodeStringPtrTableIter &);
|
|
};
|
|
|
|
#endif
|