|
|
/*===================================================================
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
|