/** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the mingw-w64 runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifndef DXTmpl_h #define DXTmpl_h #include #include #include #include #define DXASSERT_VALID(pObj) #ifndef PASCAL_INLINE #define PASCAL_INLINE WINAPI #endif typedef void *DXLISTPOS; typedef DWORD DXLISTHANDLE; #define DX_BEFORE_START_POSITION ((void*)(INT_PTR)-1) #ifndef __CRT__NO_INLINE __CRT_INLINE WINBOOL DXIsValidAddress(const void *lp,UINT nBytes,WINBOOL bReadWrite) { return (lp!=NULL && !IsBadReadPtr(lp,nBytes) && (!bReadWrite || !IsBadWritePtr((LPVOID)lp,nBytes))); } #endif #ifdef __cplusplus template inline void DXConstructElements(TYPE *pElements,int nCount) { _ASSERT(nCount==0 || DXIsValidAddress(pElements,nCount *sizeof(TYPE),TRUE)); memset((void*)pElements,0,nCount *sizeof(TYPE)); } template inline void DXDestructElements(TYPE *pElements,int nCount) { _ASSERT((nCount==0 || DXIsValidAddress(pElements,nCount *sizeof(TYPE),TRUE))); pElements; nCount; } template inline void DXCopyElements(TYPE *pDest,const TYPE *pSrc,int nCount) { _ASSERT((nCount==0 || DXIsValidAddress(pDest,nCount *sizeof(TYPE),TRUE))); _ASSERT((nCount==0 || DXIsValidAddress(pSrc,nCount *sizeof(TYPE),FALSE))); memcpy(pDest,pSrc,nCount *sizeof(TYPE)); } template WINBOOL DXCompareElements(const TYPE *pElement1,const ARG_TYPE *pElement2) { _ASSERT(DXIsValidAddress(pElement1,sizeof(TYPE),FALSE)); _ASSERT(DXIsValidAddress(pElement2,sizeof(ARG_TYPE),FALSE)); return *pElement1==*pElement2; } template inline UINT DXHashKey(ARG_KEY key) { return ((UINT)(void*)(DWORD)key) >> 4; } struct CDXPlex { CDXPlex *pNext; UINT nMax; UINT nCur; void *data() { return this+1; } static CDXPlex *PASCAL_INLINE Create(CDXPlex *&pHead,UINT nMax,UINT cbElement) { CDXPlex *p = (CDXPlex*) new BYTE[sizeof(CDXPlex) + nMax *cbElement]; if(!p) return NULL; p->nMax = nMax; p->nCur = 0; p->pNext = pHead; pHead = p; return p; } void FreeDataChain() { CDXPlex *p = this; while(p!=NULL) { BYTE *bytes = (BYTE*) p; CDXPlex *pNext = p->pNext; delete [] bytes; p = pNext; } } }; template class CDXArray { public: CDXArray(); int GetSize() const; int GetUpperBound() const; void SetSize(int nNewSize,int nGrowBy = -1); void FreeExtra(); void RemoveAll(); TYPE GetAt(int nIndex) const; void SetAt(int nIndex,ARG_TYPE newElement); TYPE &ElementAt(int nIndex); const TYPE *GetData() const; TYPE *GetData(); void SetAtGrow(int nIndex,ARG_TYPE newElement); int Add(ARG_TYPE newElement); int Append(const CDXArray &src); void Copy(const CDXArray &src); TYPE operator[](int nIndex) const; TYPE &operator[](int nIndex); void InsertAt(int nIndex,ARG_TYPE newElement,int nCount = 1); void RemoveAt(int nIndex,int nCount = 1); void InsertAt(int nStartIndex,CDXArray *pNewArray); void Sort(int (__cdecl *compare)(const void *elem1,const void *elem2)); protected: TYPE *m_pData; int m_nSize; int m_nMaxSize; int m_nGrowBy; public: ~CDXArray(); }; template inline int CDXArray::GetSize() const { return m_nSize; } template inline int CDXArray::GetUpperBound() const { return m_nSize-1; } template inline void CDXArray::RemoveAll() { SetSize(0,-1); } template inline TYPE CDXArray::GetAt(int nIndex) const { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); return m_pData[nIndex]; } template inline void CDXArray::SetAt(int nIndex,ARG_TYPE newElement) { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); m_pData[nIndex] = newElement; } template inline TYPE &CDXArray::ElementAt(int nIndex) { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); return m_pData[nIndex]; } template inline const TYPE *CDXArray::GetData() const { return (const TYPE*)m_pData; } template inline TYPE *CDXArray::GetData() { return (TYPE*)m_pData; } template inline int CDXArray::Add(ARG_TYPE newElement) { int nIndex = m_nSize; SetAtGrow(nIndex,newElement); return nIndex; } template inline TYPE CDXArray::operator[](int nIndex) const { return GetAt(nIndex); } template inline TYPE &CDXArray::operator[](int nIndex) { return ElementAt(nIndex); } template CDXArray::CDXArray() { m_pData = NULL; m_nSize = m_nMaxSize = m_nGrowBy = 0; } emplate CDXArray::~CDXArray() { DXASSERT_VALID(this); if(m_pData!=NULL) { DXDestructElements(m_pData,m_nSize); delete[] (BYTE*)m_pData; } } template void CDXArray::SetSize(int nNewSize,int nGrowBy) { DXASSERT_VALID(this); _ASSERT(nNewSize >= 0); if(nGrowBy!=-1) m_nGrowBy = nGrowBy; if(nNewSize==0) { if(m_pData!=NULL) { DXDestructElements(m_pData,m_nSize); delete[] (BYTE*)m_pData; m_pData = NULL; } m_nSize = m_nMaxSize = 0; } else if(!m_pData) { #ifdef SIZE_T_MAX _ASSERT(nNewSize <= SIZE_T_MAX/sizeof(TYPE)); #endif m_pData = (TYPE*) new BYTE[nNewSize *sizeof(TYPE)]; DXConstructElements(m_pData,nNewSize); m_nSize = m_nMaxSize = nNewSize; } else if(nNewSize <= m_nMaxSize) { if(nNewSize > m_nSize) { DXConstructElements(&m_pData[m_nSize],nNewSize-m_nSize); } else if(m_nSize > nNewSize) { DXDestructElements(&m_pData[nNewSize],m_nSize-nNewSize); } m_nSize = nNewSize; } else { int nGrowBy = m_nGrowBy; if(!nGrowBy) nGrowBy = min(1024,max(4,m_nSize / 8)); int nNewMax; if(nNewSize < m_nMaxSize + nGrowBy) nNewMax = m_nMaxSize + nGrowBy; else nNewMax = nNewSize; _ASSERT(nNewMax >= m_nMaxSize); #ifdef SIZE_T_MAX _ASSERT(nNewMax <= SIZE_T_MAX/sizeof(TYPE)); #endif TYPE *pNewData = (TYPE*) new BYTE[nNewMax *sizeof(TYPE)]; if(!pNewData) return; memcpy(pNewData,m_pData,m_nSize *sizeof(TYPE)); _ASSERT(nNewSize > m_nSize); DXConstructElements(&pNewData[m_nSize],nNewSize-m_nSize); delete[] (BYTE*)m_pData; m_pData = pNewData; m_nSize = nNewSize; m_nMaxSize = nNewMax; } } template int CDXArray::Append(const CDXArray &src) { DXASSERT_VALID(this); _ASSERT(this!=&src); int nOldSize = m_nSize; SetSize(m_nSize + src.m_nSize); DXCopyElements(m_pData + nOldSize,src.m_pData,src.m_nSize); return nOldSize; } template void CDXArray::Copy(const CDXArray &src) { DXASSERT_VALID(this); _ASSERT(this!=&src); SetSize(src.m_nSize); DXCopyElements(m_pData,src.m_pData,src.m_nSize); } template void CDXArray::FreeExtra() { DXASSERT_VALID(this); if(m_nSize!=m_nMaxSize) { #ifdef SIZE_T_MAX _ASSERT(m_nSize <= SIZE_T_MAX/sizeof(TYPE)); #endif TYPE *pNewData = NULL; if(m_nSize!=0) { pNewData = (TYPE*) new BYTE[m_nSize *sizeof(TYPE)]; if(!pNewData) return; memcpy(pNewData,m_pData,m_nSize *sizeof(TYPE)); } delete[] (BYTE*)m_pData; m_pData = pNewData; m_nMaxSize = m_nSize; } } template void CDXArray::SetAtGrow(int nIndex,ARG_TYPE newElement) { DXASSERT_VALID(this); _ASSERT(nIndex >= 0); if(nIndex >= m_nSize) SetSize(nIndex+1,-1); m_pData[nIndex] = newElement; } template void CDXArray::InsertAt(int nIndex,ARG_TYPE newElement,int nCount) { DXASSERT_VALID(this); _ASSERT(nIndex >= 0); _ASSERT(nCount > 0); if(nIndex >= m_nSize) SetSize(nIndex + nCount,-1); else { int nOldSize = m_nSize; SetSize(m_nSize + nCount,-1); memmove(&m_pData[nIndex+nCount],&m_pData[nIndex],(nOldSize-nIndex) *sizeof(TYPE)); DXConstructElements(&m_pData[nIndex],nCount); } _ASSERT(nIndex + nCount <= m_nSize); while(nCount--) m_pData[nIndex++] = newElement; } template void CDXArray::RemoveAt(int nIndex,int nCount) { DXASSERT_VALID(this); _ASSERT(nIndex >= 0); _ASSERT(nCount >= 0); _ASSERT(nIndex + nCount <= m_nSize); int nMoveCount = m_nSize - (nIndex + nCount); DXDestructElements(&m_pData[nIndex],nCount); if(nMoveCount) memcpy(&m_pData[nIndex],&m_pData[nIndex + nCount],nMoveCount *sizeof(TYPE)); m_nSize -= nCount; } template void CDXArray::InsertAt(int nStartIndex,CDXArray *pNewArray) { DXASSERT_VALID(this); DXASSERT_VALID(pNewArray); _ASSERT(nStartIndex >= 0); if(pNewArray->GetSize() > 0) { InsertAt(nStartIndex,pNewArray->GetAt(0),pNewArray->GetSize()); for(int i = 0;i < pNewArray->GetSize();i++) SetAt(nStartIndex + i,pNewArray->GetAt(i)); } } template void CDXArray::Sort(int (__cdecl *compare)(const void *elem1,const void *elem2)) { DXASSERT_VALID(this); _ASSERT(m_pData!=NULL); qsort(m_pData,m_nSize,sizeof(TYPE),compare); } #ifdef _DEBUG template void CDXArray::AssertValid() const { if(!m_pData) { _ASSERT(m_nSize==0); _ASSERT(m_nMaxSize==0); } else { _ASSERT(m_nSize >= 0); _ASSERT(m_nMaxSize >= 0); _ASSERT(m_nSize <= m_nMaxSize); _ASSERT(DXIsValidAddress(m_pData,m_nMaxSize *sizeof(TYPE),TRUE)); } } #endif template class CDXList { protected: struct CNode { CNode *pNext; CNode *pPrev; TYPE data; }; public: CDXList(int nBlockSize = 10); int GetCount() const; WINBOOL IsEmpty() const; TYPE &GetHead(); TYPE GetHead() const; TYPE &GetTail(); TYPE GetTail() const; TYPE RemoveHead(); TYPE RemoveTail(); DXLISTPOS AddHead(ARG_TYPE newElement); DXLISTPOS AddTail(ARG_TYPE newElement); void AddHead(CDXList *pNewList); void AddTail(CDXList *pNewList); void RemoveAll(); DXLISTPOS GetHeadPosition() const; DXLISTPOS GetTailPosition() const; TYPE &GetNext(DXLISTPOS &rPosition); TYPE GetNext(DXLISTPOS &rPosition) const; TYPE &GetPrev(DXLISTPOS &rPosition); TYPE GetPrev(DXLISTPOS &rPosition) const; TYPE &GetAt(DXLISTPOS position); TYPE GetAt(DXLISTPOS position) const; void SetAt(DXLISTPOS pos,ARG_TYPE newElement); void RemoveAt(DXLISTPOS position); DXLISTPOS InsertBefore(DXLISTPOS position,ARG_TYPE newElement); DXLISTPOS InsertAfter(DXLISTPOS position,ARG_TYPE newElement); DXLISTPOS Find(ARG_TYPE searchValue,DXLISTPOS startAfter = NULL) const; DXLISTPOS FindIndex(int nIndex) const; protected: CNode *m_pNodeHead; CNode *m_pNodeTail; int m_nCount; CNode *m_pNodeFree; struct CDXPlex *m_pBlocks; int m_nBlockSize; CNode *NewNode(CNode *,CNode *); void FreeNode(CNode *); public: ~CDXList(); #ifdef _DEBUG void AssertValid() const; #endif }; template inline int CDXList::GetCount() const { return m_nCount; } template inline WINBOOL CDXList::IsEmpty() const { return m_nCount==0; } template inline TYPE &CDXList::GetHead() { _ASSERT(m_pNodeHead!=NULL); return m_pNodeHead->data; } template inline TYPE CDXList::GetHead() const { _ASSERT(m_pNodeHead!=NULL); return m_pNodeHead->data; } template inline TYPE &CDXList::GetTail() { _ASSERT(m_pNodeTail!=NULL); return m_pNodeTail->data; } template inline TYPE CDXList::GetTail() const { _ASSERT(m_pNodeTail!=NULL); return m_pNodeTail->data; } template inline DXLISTPOS CDXList::GetHeadPosition() const { return (DXLISTPOS) m_pNodeHead; } template inline DXLISTPOS CDXList::GetTailPosition() const { return (DXLISTPOS) m_pNodeTail; } template inline TYPE &CDXList::GetNext(DXLISTPOS &rPosition) { CNode *pNode = (CNode *) rPosition; _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); rPosition = (DXLISTPOS) pNode->pNext; return pNode->data; } template inline TYPE CDXList::GetNext(DXLISTPOS &rPosition) const { CNode *pNode = (CNode *) rPosition; _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); rPosition = (DXLISTPOS) pNode->pNext; return pNode->data; } template inline TYPE &CDXList::GetPrev(DXLISTPOS &rPosition) { CNode *pNode = (CNode *) rPosition; _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); rPosition = (DXLISTPOS) pNode->pPrev; return pNode->data; } template inline TYPE CDXList::GetPrev(DXLISTPOS &rPosition) const { CNode *pNode = (CNode *) rPosition; _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); rPosition = (DXLISTPOS) pNode->pPrev; return pNode->data; } template inline TYPE &CDXList::GetAt(DXLISTPOS position) { CNode *pNode = (CNode *) position; _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); return pNode->data; } template inline TYPE CDXList::GetAt(DXLISTPOS position) const { CNode *pNode = (CNode *) position; _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); return pNode->data; } template inline void CDXList::SetAt(DXLISTPOS pos,ARG_TYPE newElement) { CNode *pNode = (CNode *) pos; _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); pNode->data = newElement; } template CDXList::CDXList(int nBlockSize) { _ASSERT(nBlockSize > 0); m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_pBlocks = NULL; m_nBlockSize = nBlockSize; } template void CDXList::RemoveAll() { DXASSERT_VALID(this); CNode *pNode; for(pNode = m_pNodeHead;pNode!=NULL;pNode = pNode->pNext) DXDestructElements(&pNode->data,1); m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_pBlocks->FreeDataChain(); m_pBlocks = NULL; } template CDXList::~CDXList() { RemoveAll(); _ASSERT(m_nCount==0); } template typename CDXList::CNode * CDXList::NewNode(CNode *pPrev,CNode *pNext) { if(!m_pNodeFree) { CDXPlex *pNewBlock = CDXPlex::Create(m_pBlocks,m_nBlockSize,sizeof(CNode)); CNode *pNode = (CNode *) pNewBlock->data(); pNode += m_nBlockSize - 1; for(int i = m_nBlockSize-1;i >= 0;i--,pNode--) { pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; } } _ASSERT(m_pNodeFree!=NULL); CDXList::CNode *pNode = m_pNodeFree; m_pNodeFree = m_pNodeFree->pNext; pNode->pPrev = pPrev; pNode->pNext = pNext; m_nCount++; _ASSERT(m_nCount > 0); DXConstructElements(&pNode->data,1); return pNode; } template void CDXList::FreeNode(CNode *pNode) { DXDestructElements(&pNode->data,1); pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; m_nCount--; _ASSERT(m_nCount >= 0); } template DXLISTPOS CDXList::AddHead(ARG_TYPE newElement) { DXASSERT_VALID(this); CNode *pNewNode = NewNode(NULL,m_pNodeHead); pNewNode->data = newElement; if(m_pNodeHead!=NULL) m_pNodeHead->pPrev = pNewNode; else m_pNodeTail = pNewNode; m_pNodeHead = pNewNode; return (DXLISTPOS) pNewNode; } template DXLISTPOS CDXList::AddTail(ARG_TYPE newElement) { DXASSERT_VALID(this); CNode *pNewNode = NewNode(m_pNodeTail,NULL); pNewNode->data = newElement; if(m_pNodeTail!=NULL) m_pNodeTail->pNext = pNewNode; else m_pNodeHead = pNewNode; m_pNodeTail = pNewNode; return (DXLISTPOS) pNewNode; } template void CDXList::AddHead(CDXList *pNewList) { DXASSERT_VALID(this); DXASSERT_VALID(pNewList); DXLISTPOS pos = pNewList->GetTailPosition(); while(pos!=NULL) AddHead(pNewList->GetPrev(pos)); } template void CDXList::AddTail(CDXList *pNewList) { DXASSERT_VALID(this); DXASSERT_VALID(pNewList); DXLISTPOS pos = pNewList->GetHeadPosition(); while(pos!=NULL) AddTail(pNewList->GetNext(pos)); } template TYPE CDXList::RemoveHead() { DXASSERT_VALID(this); _ASSERT(m_pNodeHead!=NULL); _ASSERT(DXIsValidAddress(m_pNodeHead,sizeof(CNode),TRUE)); CNode *pOldNode = m_pNodeHead; TYPE returnValue = pOldNode->data; m_pNodeHead = pOldNode->pNext; if(m_pNodeHead!=NULL) m_pNodeHead->pPrev = NULL; else m_pNodeTail = NULL; FreeNode(pOldNode); return returnValue; } template TYPE CDXList::RemoveTail() { DXASSERT_VALID(this); _ASSERT(m_pNodeTail!=NULL); _ASSERT(DXIsValidAddress(m_pNodeTail,sizeof(CNode),TRUE)); CNode *pOldNode = m_pNodeTail; TYPE returnValue = pOldNode->data; m_pNodeTail = pOldNode->pPrev; if(m_pNodeTail!=NULL) m_pNodeTail->pNext = NULL; else m_pNodeHead = NULL; FreeNode(pOldNode); return returnValue; } template DXLISTPOS CDXList::InsertBefore(DXLISTPOS position,ARG_TYPE newElement) { DXASSERT_VALID(this); if(!position) return AddHead(newElement); CNode *pOldNode = (CNode *) position; CNode *pNewNode = NewNode(pOldNode->pPrev,pOldNode); pNewNode->data = newElement; if(pOldNode->pPrev!=NULL) { _ASSERT(DXIsValidAddress(pOldNode->pPrev,sizeof(CNode),TRUE)); pOldNode->pPrev->pNext = pNewNode; } else { _ASSERT(pOldNode==m_pNodeHead); m_pNodeHead = pNewNode; } pOldNode->pPrev = pNewNode; return (DXLISTPOS) pNewNode; } template DXLISTPOS CDXList::InsertAfter(DXLISTPOS position,ARG_TYPE newElement) { DXASSERT_VALID(this); if(!position) return AddTail(newElement); CNode *pOldNode = (CNode *) position; _ASSERT(DXIsValidAddress(pOldNode,sizeof(CNode),TRUE)); CNode *pNewNode = NewNode(pOldNode,pOldNode->pNext); pNewNode->data = newElement; if(pOldNode->pNext!=NULL) { _ASSERT(DXIsValidAddress(pOldNode->pNext,sizeof(CNode),TRUE)); pOldNode->pNext->pPrev = pNewNode; } else { _ASSERT(pOldNode==m_pNodeTail); m_pNodeTail = pNewNode; } pOldNode->pNext = pNewNode; return (DXLISTPOS) pNewNode; } template void CDXList::RemoveAt(DXLISTPOS position) { DXASSERT_VALID(this); CNode *pOldNode = (CNode *) position; _ASSERT(DXIsValidAddress(pOldNode,sizeof(CNode),TRUE)); if(pOldNode==m_pNodeHead) { m_pNodeHead = pOldNode->pNext; } else { _ASSERT(DXIsValidAddress(pOldNode->pPrev,sizeof(CNode),TRUE)); pOldNode->pPrev->pNext = pOldNode->pNext; } if(pOldNode==m_pNodeTail) m_pNodeTail = pOldNode->pPrev; else { _ASSERT(DXIsValidAddress(pOldNode->pNext,sizeof(CNode),TRUE)); pOldNode->pNext->pPrev = pOldNode->pPrev; } FreeNode(pOldNode); } template DXLISTPOS CDXList::FindIndex(int nIndex) const { DXASSERT_VALID(this); _ASSERT(nIndex >= 0); if(nIndex >= m_nCount) return NULL; CNode *pNode = m_pNodeHead; while(nIndex--) { _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); pNode = pNode->pNext; } return (DXLISTPOS) pNode; } template DXLISTPOS CDXList::Find(ARG_TYPE searchValue,DXLISTPOS startAfter) const { DXASSERT_VALID(this); CNode *pNode = (CNode *) startAfter; if(!pNode) pNode = m_pNodeHead; else { _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); pNode = pNode->pNext; } for(;pNode!=NULL;pNode = pNode->pNext) if(DXCompareElements(&pNode->data,&searchValue)) return (DXLISTPOS)pNode; return NULL; } #ifdef _DEBUG template void CDXList::AssertValid() const { if(!m_nCount) { _ASSERT(!m_pNodeHead); _ASSERT(!m_pNodeTail); } else { _ASSERT(DXIsValidAddress(m_pNodeHead,sizeof(CNode),TRUE)); _ASSERT(DXIsValidAddress(m_pNodeTail,sizeof(CNode),TRUE)); } } #endif template class CDXMap { protected: struct CAssoc { CAssoc *pNext; UINT nHashValue; KEY key; VALUE value; }; public: CDXMap(int nBlockSize = 10); int GetCount() const; WINBOOL IsEmpty() const; WINBOOL Lookup(ARG_KEY key,VALUE& rValue) const; VALUE& operator[](ARG_KEY key); void SetAt(ARG_KEY key,ARG_VALUE newValue); WINBOOL RemoveKey(ARG_KEY key); void RemoveAll(); DXLISTPOS GetStartPosition() const; void GetNextAssoc(DXLISTPOS &rNextPosition,KEY& rKey,VALUE& rValue) const; UINT GetHashTableSize() const; void InitHashTable(UINT hashSize,WINBOOL bAllocNow = TRUE); protected: CAssoc **m_pHashTable; UINT m_nHashTableSize; int m_nCount; CAssoc *m_pFreeList; struct CDXPlex *m_pBlocks; int m_nBlockSize; CAssoc *NewAssoc(); void FreeAssoc(CAssoc*); CAssoc *GetAssocAt(ARG_KEY,UINT&) const; public: ~CDXMap(); #ifdef _DEBUG void AssertValid() const; #endif }; template inline int CDXMap::GetCount() const { return m_nCount; } template inline WINBOOL CDXMap::IsEmpty() const { return m_nCount==0; } template inline void CDXMap::SetAt(ARG_KEY key,ARG_VALUE newValue) { (*this)[key] = newValue; } template inline DXLISTPOS CDXMap::GetStartPosition() const { return (m_nCount==0) ? NULL : DX_BEFORE_START_POSITION; } template inline UINT CDXMap::GetHashTableSize() const { return m_nHashTableSize; } template CDXMap::CDXMap(int nBlockSize) { _ASSERT(nBlockSize > 0); m_pHashTable = NULL; m_nHashTableSize = 17; m_nCount = 0; m_pFreeList = NULL; m_pBlocks = NULL; m_nBlockSize = nBlockSize; } template void CDXMap::InitHashTable(UINT nHashSize,WINBOOL bAllocNow) { DXASSERT_VALID(this); _ASSERT(m_nCount==0); _ASSERT(nHashSize > 0); if(m_pHashTable!=NULL) { delete[] m_pHashTable; m_pHashTable = NULL; } if(bAllocNow) { m_pHashTable = new CAssoc *[nHashSize]; if(!m_pHashTable) return; memset(m_pHashTable,0,sizeof(CAssoc*) *nHashSize); } m_nHashTableSize = nHashSize; } template void CDXMap::RemoveAll() { DXASSERT_VALID(this); if(m_pHashTable!=NULL) { for(UINT nHash = 0;nHash < m_nHashTableSize;nHash++) { CAssoc *pAssoc; for(pAssoc = m_pHashTable[nHash]; pAssoc!=NULL; pAssoc = pAssoc->pNext) { DXDestructElements(&pAssoc->value,1); DXDestructElements(&pAssoc->key,1); } } } delete[] m_pHashTable; m_pHashTable = NULL; m_nCount = 0; m_pFreeList = NULL; m_pBlocks->FreeDataChain(); m_pBlocks = NULL; } template CDXMap::~CDXMap() { RemoveAll(); _ASSERT(m_nCount==0); } template typename CDXMap::CAssoc* CDXMap::NewAssoc() { if(!m_pFreeList) { CDXPlex *newBlock = CDXPlex::Create(m_pBlocks,m_nBlockSize,sizeof(CDXMap::CAssoc)); CDXMap::CAssoc *pAssoc = (CDXMap::CAssoc*) newBlock->data(); pAssoc += m_nBlockSize - 1; for(int i = m_nBlockSize-1;i >= 0;i--,pAssoc--) { pAssoc->pNext = m_pFreeList; m_pFreeList = pAssoc; } } _ASSERT(m_pFreeList!=NULL); CDXMap::CAssoc *pAssoc = m_pFreeList; m_pFreeList = m_pFreeList->pNext; m_nCount++; _ASSERT(m_nCount > 0); DXConstructElements(&pAssoc->key,1); DXConstructElements(&pAssoc->value,1); return pAssoc; } template void CDXMap::FreeAssoc(CAssoc *pAssoc) { DXDestructElements(&pAssoc->value,1); DXDestructElements(&pAssoc->key,1); pAssoc->pNext = m_pFreeList; m_pFreeList = pAssoc; m_nCount--; _ASSERT(m_nCount >= 0); } template typename CDXMap::CAssoc* CDXMap::GetAssocAt(ARG_KEY key,UINT& nHash) const { nHash = DXHashKey(key) % m_nHashTableSize; if(!m_pHashTable) return NULL; CAssoc *pAssoc; for(pAssoc = m_pHashTable[nHash];pAssoc!=NULL;pAssoc = pAssoc->pNext) { if(DXCompareElements(&pAssoc->key,&key)) return pAssoc; } return NULL; } template WINBOOL CDXMap::Lookup(ARG_KEY key,VALUE& rValue) const { DXASSERT_VALID(this); UINT nHash; CAssoc *pAssoc = GetAssocAt(key,nHash); if(!pAssoc) return FALSE; rValue = pAssoc->value; return TRUE; } template VALUE& CDXMap::operator[](ARG_KEY key) { DXASSERT_VALID(this); UINT nHash; CAssoc *pAssoc; if(!(pAssoc = GetAssocAt(key,nHash))) { if(!m_pHashTable) InitHashTable(m_nHashTableSize); pAssoc = NewAssoc(); pAssoc->nHashValue = nHash; pAssoc->key = key; pAssoc->pNext = m_pHashTable[nHash]; m_pHashTable[nHash] = pAssoc; } return pAssoc->value; } template WINBOOL CDXMap::RemoveKey(ARG_KEY key) { DXASSERT_VALID(this); if(!m_pHashTable) return FALSE; CAssoc **ppAssocPrev; ppAssocPrev = &m_pHashTable[DXHashKey(key) % m_nHashTableSize]; CAssoc *pAssoc; for(pAssoc = *ppAssocPrev;pAssoc!=NULL;pAssoc = pAssoc->pNext) { if(DXCompareElements(&pAssoc->key,&key)) { *ppAssocPrev = pAssoc->pNext; FreeAssoc(pAssoc); return TRUE; } ppAssocPrev = &pAssoc->pNext; } return FALSE; } template void CDXMap::GetNextAssoc(DXLISTPOS &rNextPosition,KEY& rKey,VALUE& rValue) const { DXASSERT_VALID(this); _ASSERT(m_pHashTable!=NULL); CAssoc *pAssocRet = (CAssoc*)rNextPosition; _ASSERT(pAssocRet!=NULL); if(pAssocRet==(CAssoc*) DX_BEFORE_START_POSITION) { for(UINT nBucket = 0;nBucket < m_nHashTableSize;nBucket++) if((pAssocRet = m_pHashTable[nBucket])!=NULL) break; _ASSERT(pAssocRet!=NULL); } _ASSERT(DXIsValidAddress(pAssocRet,sizeof(CAssoc),TRUE)); CAssoc *pAssocNext; if(!(pAssocNext = pAssocRet->pNext)) { for(UINT nBucket = pAssocRet->nHashValue + 1;nBucket < m_nHashTableSize;nBucket++) if((pAssocNext = m_pHashTable[nBucket])!=NULL) break; } rNextPosition = (DXLISTPOS) pAssocNext; rKey = pAssocRet->key; rValue = pAssocRet->value; } #ifdef _DEBUG template void CDXMap::AssertValid() const { _ASSERT(m_nHashTableSize > 0); _ASSERT((m_nCount==0 || m_pHashTable!=NULL)); } #endif #endif /* __cplusplus */ #endif