windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/cmp/asp51/idhash.h
2020-09-26 16:20:57 +08:00

709 lines
14 KiB
C++

/*===================================================================
Microsoft Denali
Microsoft Confidential.
Copyright 1997 Microsoft Corporation. All Rights Reserved.
File: idhash.h
Owner: DmitryR
Header file for the new hashing stuff
===================================================================*/
#ifndef ASP_IDHASH_H
#define ASP_IDHASH_H
// forward declarations
class CPtrArray;
class CHashLock;
struct CIdHashElem;
struct CIdHashArray;
class CIdHashTable;
class CIdHashTableWithLock;
struct CObjectListElem;
class CObjectList;
class CObjectListWithLock;
// defines for the iterator callback return codes
#define IteratorCallbackCode DWORD
#define iccContinue 0x00000001 // goto next object
#define iccStop 0x00000002 // stop iterating
#define iccRemoveAndContinue 0x00000004 // remove this, goto next
#define iccRemoveAndStop 0x00000008 // remove this and stop
// typedefs for the iterator callback
typedef IteratorCallbackCode (*PFNIDHASHCB)
(void *pvObj, void *pvArg1, void *pvArg2);
/*===================================================================
C P t r A r r a y
Self-reallocating array of void pointers
===================================================================*/
class CPtrArray
{
private:
DWORD m_dwSize; // allocated size
DWORD m_dwInc; // allocation increment
void **m_rgpvPtrs; // array of void pointers
DWORD m_cPtrs; // pointers in the array
public:
CPtrArray(DWORD dwInc = 8); // 8 pointers is the default increment
~CPtrArray();
// # of elements
int Count() const;
// get pointer at position
void *Get(int i) const;
// same as operator []
void *operator[](int i) const;
// append to array
HRESULT Append(void *pv);
// prepend to array
HRESULT Prepend(void *pv);
// insert into given position
HRESULT Insert(int iPos, void *pv);
// find first position of a pointer
HRESULT Find(void *pv, int *piPos) const;
// same as operator []
int operator[](void *pv) const;
// remove by position
HRESULT Remove(int iPos);
// remove by pointer (all occurances)
HRESULT Remove(void *pv);
// remove all
HRESULT Clear();
};
// inlines
inline CPtrArray::CPtrArray(DWORD dwInc)
: m_dwSize(0), m_dwInc(dwInc), m_rgpvPtrs(NULL), m_cPtrs(0)
{
Assert(m_dwInc > 0);
}
inline CPtrArray::~CPtrArray()
{
Clear();
}
inline int CPtrArray::Count() const
{
return m_cPtrs;
}
inline void *CPtrArray::Get(int i) const
{
Assert(i >= 0 && (DWORD)i < m_cPtrs);
Assert(m_rgpvPtrs);
return m_rgpvPtrs[i];
}
inline void *CPtrArray::operator[](int i) const
{
return Get(i);
}
inline HRESULT CPtrArray::Append(void *pv)
{
return Insert(m_cPtrs, pv);
}
inline HRESULT CPtrArray::Prepend(void *pv)
{
return Insert(0, pv);
}
inline int CPtrArray::operator[](void *pv) const
{
int i;
if (Find(pv, &i) == S_OK)
return i;
return -1; // not found
}
/*===================================================================
C H a s h L o c k
A wrapper around CRITICAL_SECTION.
===================================================================*/
class CHashLock
{
private:
DWORD m_fInited : 1;
CRITICAL_SECTION m_csLock;
public:
CHashLock();
~CHashLock();
HRESULT Init();
HRESULT UnInit();
void Lock();
void UnLock();
};
// inlines
inline CHashLock::CHashLock()
: m_fInited(FALSE)
{
}
inline CHashLock::~CHashLock()
{
UnInit();
}
inline void CHashLock::Lock()
{
Assert(m_fInited);
EnterCriticalSection(&m_csLock);
}
inline void CHashLock::UnLock()
{
Assert(m_fInited);
LeaveCriticalSection( &m_csLock );
}
/*===================================================================
C I d H a s h U n i t
8-byte structure -- one element of hash array. Could be:
1) empty, 2) point to an object, 3) point to sub-array
===================================================================*/
struct CIdHashElem
{
DWORD_PTR m_dw;
void *m_pv;
BOOL FIsEmpty() const;
BOOL FIsObject() const;
BOOL FIsArray() const;
DWORD_PTR DWId() const;
void *PObject() const;
CIdHashArray *PArray() const;
void SetToEmpty();
void SetToObject(DWORD_PTR dwId, void *pvObj);
void SetToArray(CIdHashArray *pArray);
};
// inlines
inline BOOL CIdHashElem::FIsEmpty() const
{
return (m_pv == NULL);
}
inline BOOL CIdHashElem::FIsObject() const
{
return (m_dw != 0);
}
inline BOOL CIdHashElem::FIsArray() const
{
return (m_pv != NULL && m_dw == 0);
}
inline DWORD_PTR CIdHashElem::DWId() const
{
return m_dw;
}
inline void *CIdHashElem::PObject() const
{
return m_pv;
}
inline CIdHashArray *CIdHashElem::PArray() const
{
return reinterpret_cast<CIdHashArray *>(m_pv);
}
inline void CIdHashElem::SetToEmpty()
{
m_dw = 0;
m_pv = NULL;
}
inline void CIdHashElem::SetToObject
(
DWORD_PTR dwId,
void *pvObj
)
{
m_dw = dwId;
m_pv = pvObj;
}
inline void CIdHashElem::SetToArray
(
CIdHashArray *pArray
)
{
m_dw = 0;
m_pv = pArray;
}
/*===================================================================
C I d H a s h A r r a y
Structure to consisting of DWORD (# of elems) and the array of Elems
===================================================================*/
struct CIdHashArray
{
USHORT m_cElems; // total number of elements
USHORT m_cNotNulls; // number of not NULL elements
CIdHashElem m_rgElems[1]; // 1 doesn't matter
static CIdHashArray *Alloc(DWORD cElems);
static void Free(CIdHashArray *pArray);
HRESULT Find(DWORD_PTR dwId, void **ppvObj) const;
HRESULT Add(DWORD_PTR dwId, void *pvObj, USHORT *rgusSizes);
HRESULT Remove(DWORD_PTR dwId, void **ppvObj);
IteratorCallbackCode Iterate(PFNIDHASHCB pfnCB, void *pvArg1, void *pvArg2);
#ifdef DBG
void DumpStats(FILE *f, int nVerbose, DWORD iLevel,
DWORD &cElems, DWORD &cSlots, DWORD &cArrays, DWORD &cDepth) const;
#else
inline void DumpStats(FILE *, int, DWORD,
DWORD &, DWORD &, DWORD &, DWORD &) const {}
#endif
};
/*===================================================================
C I d H a s h T a b l e
Remembers sizes of arrays on all levels and has a pointer to the
first level array of CIdHashElem elements.
===================================================================*/
class CIdHashTable
{
private:
USHORT m_rgusSizes[4]; // Sizes of arrays on first 4 levels
CIdHashArray *m_pArray; // Pointer to first level array
inline BOOL FInited() const { return (m_rgusSizes[0] != 0); }
public:
CIdHashTable();
CIdHashTable(USHORT usSize1, USHORT usSize2 = 0, USHORT usSize3 = 0);
~CIdHashTable();
HRESULT Init(USHORT usSize1, USHORT usSize2 = 0, USHORT usSize3 = 0);
HRESULT UnInit();
HRESULT FindObject(DWORD_PTR dwId, void **ppvObj = NULL) const;
HRESULT AddObject(DWORD_PTR dwId, void *pvObj);
HRESULT RemoveObject(DWORD_PTR dwId, void **ppvObj = NULL);
HRESULT RemoveAllObjects();
HRESULT IterateObjects
(
PFNIDHASHCB pfnCB,
void *pvArg1 = NULL,
void *pvArg2 = NULL
);
public:
#ifdef DBG
void AssertValid() const;
void Dump(const char *szFile) const;
#else
inline void AssertValid() const {}
inline void Dump(const char *) const {}
#endif
};
// inlines
inline CIdHashTable::CIdHashTable()
{
m_rgusSizes[0] = 0; // mark as UnInited
m_pArray = NULL;
}
inline CIdHashTable::CIdHashTable
(
USHORT usSize1,
USHORT usSize2,
USHORT usSize3
)
{
m_rgusSizes[0] = 0; // mark as UnInited
m_pArray = NULL;
Init(usSize1, usSize2, usSize3); // use Init to initialize
}
inline CIdHashTable::~CIdHashTable()
{
UnInit();
}
inline HRESULT CIdHashTable::FindObject
(
DWORD_PTR dwId,
void **ppvObj
)
const
{
Assert(FInited());
Assert(dwId);
if (!m_pArray)
{
if (ppvObj)
*ppvObj = NULL;
return S_FALSE;
}
return m_pArray->Find(dwId, ppvObj);
}
inline HRESULT CIdHashTable::AddObject
(
DWORD_PTR dwId,
void *pvObj
)
{
Assert(FInited());
Assert(dwId);
Assert(pvObj);
if (!m_pArray)
{
m_pArray = CIdHashArray::Alloc(m_rgusSizes[0]);
if (!m_pArray)
return E_OUTOFMEMORY;
}
return m_pArray->Add(dwId, pvObj, m_rgusSizes);
}
inline HRESULT CIdHashTable::RemoveObject
(
DWORD_PTR dwId,
void **ppvObj
)
{
Assert(FInited());
Assert(dwId);
if (!m_pArray)
{
if (ppvObj)
*ppvObj = NULL;
return S_FALSE;
}
return m_pArray->Remove(dwId, ppvObj);
}
inline HRESULT CIdHashTable::RemoveAllObjects()
{
if (m_pArray)
{
CIdHashArray::Free(m_pArray);
m_pArray = NULL;
}
return S_OK;
}
inline HRESULT CIdHashTable::IterateObjects
(
PFNIDHASHCB pfnCB,
void *pvArg1,
void *pvArg2
)
{
Assert(FInited());
Assert(pfnCB);
if (!m_pArray)
return S_OK;
return m_pArray->Iterate(pfnCB, pvArg1, pvArg2);
}
/*===================================================================
C I d H a s h T a b l e W i t h L o c k
CIdHashTable + CRITICAL_SECTION.
===================================================================*/
class CIdHashTableWithLock : public CIdHashTable, public CHashLock
{
public:
CIdHashTableWithLock();
~CIdHashTableWithLock();
HRESULT Init(USHORT usSize1, USHORT usSize2 = 0, USHORT usSize3 = 0);
HRESULT UnInit();
};
// inlines
inline CIdHashTableWithLock::CIdHashTableWithLock()
{
}
inline CIdHashTableWithLock::~CIdHashTableWithLock()
{
UnInit();
}
inline HRESULT CIdHashTableWithLock::Init
(
USHORT usSize1,
USHORT usSize2,
USHORT usSize3
)
{
HRESULT hr = CIdHashTable::Init(usSize1, usSize2, usSize3);
if (SUCCEEDED(hr))
hr = CHashLock::Init();
return hr;
}
inline HRESULT CIdHashTableWithLock::UnInit()
{
CIdHashTable::UnInit();
CHashLock::UnInit();
return S_OK;
}
/*===================================================================
C O b j e c t L i s t E l e m
Double linked list element
===================================================================*/
struct CObjectListElem
{
CObjectListElem *m_pNext;
CObjectListElem *m_pPrev;
CObjectListElem();
void Insert(CObjectListElem *pPrevElem, CObjectListElem *pNextElem);
void Remove();
void *PObject(DWORD dwFieldOffset);
};
inline CObjectListElem::CObjectListElem()
: m_pNext(NULL), m_pPrev(NULL)
{
}
inline void CObjectListElem::Insert
(
CObjectListElem *pPrevElem,
CObjectListElem *pNextElem
)
{
Assert(!pPrevElem || (pPrevElem->m_pNext == pNextElem));
Assert(!pNextElem || (pNextElem->m_pPrev == pPrevElem));
m_pPrev = pPrevElem;
m_pNext = pNextElem;
if (pPrevElem)
pPrevElem->m_pNext = this;
if (pNextElem)
pNextElem->m_pPrev = this;
}
inline void CObjectListElem::Remove()
{
if (m_pPrev)
m_pPrev->m_pNext = m_pNext;
if (m_pNext)
m_pNext->m_pPrev = m_pPrev;
m_pPrev = m_pNext = NULL;
}
inline void *CObjectListElem::PObject(DWORD dwFieldOffset)
{
return ((BYTE *)this - dwFieldOffset);
}
// Macro to get the byte offset of a field in a class
#define OBJECT_LIST_ELEM_FIELD_OFFSET(type, field) \
(PtrToUlong(&(((type *)0)->field)))
inline CObjectListElem *PListElemField
(
void *pvObj,
DWORD dwFieldOffset
)
{
if (!pvObj)
return NULL;
return (CObjectListElem *)((BYTE *)pvObj + dwFieldOffset);
}
/*===================================================================
C O b j e c t L i s t
Double linked list of objects
===================================================================*/
class CObjectList
{
private:
CObjectListElem m_Head; // list head
DWORD m_dwFieldOffset; // offset to CObjectListElem member field
public:
CObjectList();
~CObjectList();
HRESULT Init(DWORD dwFieldOffset = 0);
HRESULT UnInit();
HRESULT AddObject(void *pvObj);
HRESULT RemoveObject(void *pvObj);
HRESULT RemoveAllObjects();
// iteration
void *PFirstObject();
void *PNextObject(void *pvObj);
};
// inlines
inline CObjectList::CObjectList()
: m_dwFieldOffset(0)
{
}
inline CObjectList::~CObjectList()
{
UnInit();
}
inline HRESULT CObjectList::Init(DWORD dwFieldOffset)
{
m_dwFieldOffset = dwFieldOffset;
m_Head.m_pPrev = m_Head.m_pNext = NULL;
return S_OK;
}
inline HRESULT CObjectList::UnInit()
{
RemoveAllObjects();
return S_OK;
}
inline HRESULT CObjectList::AddObject(void *pvObj)
{
Assert(pvObj);
// insert between head and its next
PListElemField(pvObj, m_dwFieldOffset)->Insert(&m_Head, m_Head.m_pNext);
return S_OK;
}
inline HRESULT CObjectList::RemoveObject(void *pvObj)
{
Assert(pvObj);
PListElemField(pvObj, m_dwFieldOffset)->Remove();
return S_OK;
}
inline HRESULT CObjectList::RemoveAllObjects()
{
if (m_Head.m_pNext)
m_Head.m_pNext = NULL;
return S_OK;
}
inline void *CObjectList::PFirstObject()
{
return m_Head.m_pNext ? m_Head.m_pNext->PObject(m_dwFieldOffset) : NULL;
}
inline void *CObjectList::PNextObject(void *pvObj)
{
CObjectListElem *pNextElem =
pvObj ? PListElemField(pvObj, m_dwFieldOffset)->m_pNext : NULL;
return pNextElem ? pNextElem->PObject(m_dwFieldOffset) : NULL;
}
/*===================================================================
C O b j e c t L i s t W i t h L o c k
CObjectList + CRITICAL_SECTION.
===================================================================*/
class CObjectListWithLock : public CObjectList, public CHashLock
{
public:
CObjectListWithLock();
~CObjectListWithLock();
HRESULT Init(DWORD dwFieldOffset = 0);
HRESULT UnInit();
};
// inlines
inline CObjectListWithLock::CObjectListWithLock()
{
}
inline CObjectListWithLock::~CObjectListWithLock()
{
UnInit();
}
inline HRESULT CObjectListWithLock::Init(DWORD dwFieldOffset)
{
HRESULT hr = CObjectList::Init(dwFieldOffset);
if (SUCCEEDED(hr))
hr = CHashLock::Init();
return hr;
}
inline HRESULT CObjectListWithLock::UnInit()
{
CObjectList::UnInit();
CHashLock::UnInit();
return S_OK;
}
#endif // ifndef ASP_IDHASH_H