|  | /** | 
|  | * 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 <limits.h> | 
|  | #include <string.h> | 
|  | #include <stdlib.h> | 
|  | #include <search.h> | 
|  |  | 
|  | #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<class TYPE> | 
|  | inline void DXConstructElements(TYPE *pElements,int nCount) { | 
|  | _ASSERT(nCount==0 || DXIsValidAddress(pElements,nCount *sizeof(TYPE),TRUE)); | 
|  | memset((void*)pElements,0,nCount *sizeof(TYPE)); | 
|  | } | 
|  |  | 
|  | template<class TYPE> | 
|  | inline void DXDestructElements(TYPE *pElements,int nCount) { | 
|  | _ASSERT((nCount==0 || DXIsValidAddress(pElements,nCount *sizeof(TYPE),TRUE))); | 
|  | pElements; | 
|  | nCount; | 
|  | } | 
|  |  | 
|  | template<class TYPE> | 
|  | 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<class TYPE,class ARG_TYPE> | 
|  | 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<class ARG_KEY> | 
|  | 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 TYPE,class ARG_TYPE> | 
|  | 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<class TYPE,class ARG_TYPE> | 
|  | inline int CDXArray<TYPE,ARG_TYPE>::GetSize() const { return m_nSize; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline int CDXArray<TYPE,ARG_TYPE>::GetUpperBound() const { return m_nSize-1; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline void CDXArray<TYPE,ARG_TYPE>::RemoveAll() { SetSize(0,-1); } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE CDXArray<TYPE,ARG_TYPE>::GetAt(int nIndex) const { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); return m_pData[nIndex]; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline void CDXArray<TYPE,ARG_TYPE>::SetAt(int nIndex,ARG_TYPE newElement) { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); m_pData[nIndex] = newElement; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE &CDXArray<TYPE,ARG_TYPE>::ElementAt(int nIndex) { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); return m_pData[nIndex]; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline const TYPE *CDXArray<TYPE,ARG_TYPE>::GetData() const { return (const TYPE*)m_pData; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE *CDXArray<TYPE,ARG_TYPE>::GetData() { return (TYPE*)m_pData; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline int CDXArray<TYPE,ARG_TYPE>::Add(ARG_TYPE newElement) { | 
|  | int nIndex = m_nSize; | 
|  | SetAtGrow(nIndex,newElement); | 
|  | return nIndex; | 
|  | } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE CDXArray<TYPE,ARG_TYPE>::operator[](int nIndex) const { return GetAt(nIndex); } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE &CDXArray<TYPE,ARG_TYPE>::operator[](int nIndex) { return ElementAt(nIndex); } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | CDXArray<TYPE,ARG_TYPE>::CDXArray() { m_pData = NULL; m_nSize = m_nMaxSize = m_nGrowBy = 0; } | 
|  | emplate<class TYPE,class ARG_TYPE> | 
|  | CDXArray<TYPE,ARG_TYPE>::~CDXArray() { | 
|  | DXASSERT_VALID(this); | 
|  | if(m_pData!=NULL) { | 
|  | DXDestructElements(m_pData,m_nSize); | 
|  | delete[] (BYTE*)m_pData; | 
|  | } | 
|  | } | 
|  |  | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | void CDXArray<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | int CDXArray<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXArray<TYPE,ARG_TYPE>::Copy(const CDXArray &src) { | 
|  | DXASSERT_VALID(this); | 
|  | _ASSERT(this!=&src); | 
|  | SetSize(src.m_nSize); | 
|  | DXCopyElements(m_pData,src.m_pData,src.m_nSize); | 
|  | } | 
|  |  | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | void CDXArray<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXArray<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXArray<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXArray<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXArray<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXArray<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXArray<TYPE,ARG_TYPE>::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 TYPE,class ARG_TYPE> | 
|  | 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<class TYPE,class ARG_TYPE> | 
|  | inline int CDXList<TYPE,ARG_TYPE>::GetCount() const { return m_nCount; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline WINBOOL CDXList<TYPE,ARG_TYPE>::IsEmpty() const { return m_nCount==0; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE &CDXList<TYPE,ARG_TYPE>::GetHead() { _ASSERT(m_pNodeHead!=NULL); return m_pNodeHead->data; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE CDXList<TYPE,ARG_TYPE>::GetHead() const { _ASSERT(m_pNodeHead!=NULL); return m_pNodeHead->data; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE &CDXList<TYPE,ARG_TYPE>::GetTail() { _ASSERT(m_pNodeTail!=NULL); return m_pNodeTail->data; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE CDXList<TYPE,ARG_TYPE>::GetTail() const { _ASSERT(m_pNodeTail!=NULL); return m_pNodeTail->data; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline DXLISTPOS CDXList<TYPE,ARG_TYPE>::GetHeadPosition() const { return (DXLISTPOS) m_pNodeHead; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline DXLISTPOS CDXList<TYPE,ARG_TYPE>::GetTailPosition() const { return (DXLISTPOS) m_pNodeTail; } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE &CDXList<TYPE,ARG_TYPE>::GetNext(DXLISTPOS &rPosition) { | 
|  | CNode *pNode = (CNode *) rPosition; | 
|  | _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); | 
|  | rPosition = (DXLISTPOS) pNode->pNext; | 
|  | return pNode->data; | 
|  | } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE CDXList<TYPE,ARG_TYPE>::GetNext(DXLISTPOS &rPosition) const { | 
|  | CNode *pNode = (CNode *) rPosition; | 
|  | _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); | 
|  | rPosition = (DXLISTPOS) pNode->pNext; | 
|  | return pNode->data; | 
|  | } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE &CDXList<TYPE,ARG_TYPE>::GetPrev(DXLISTPOS &rPosition) { | 
|  | CNode *pNode = (CNode *) rPosition; | 
|  | _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); | 
|  | rPosition = (DXLISTPOS) pNode->pPrev; | 
|  | return pNode->data; | 
|  | } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE CDXList<TYPE,ARG_TYPE>::GetPrev(DXLISTPOS &rPosition) const { | 
|  | CNode *pNode = (CNode *) rPosition; | 
|  | _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); | 
|  | rPosition = (DXLISTPOS) pNode->pPrev; | 
|  | return pNode->data; | 
|  | } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE &CDXList<TYPE,ARG_TYPE>::GetAt(DXLISTPOS position) { | 
|  | CNode *pNode = (CNode *) position; | 
|  | _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); | 
|  | return pNode->data; | 
|  | } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline TYPE CDXList<TYPE,ARG_TYPE>::GetAt(DXLISTPOS position) const { | 
|  | CNode *pNode = (CNode *) position; | 
|  | _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); | 
|  | return pNode->data; | 
|  | } | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | inline void CDXList<TYPE,ARG_TYPE>::SetAt(DXLISTPOS pos,ARG_TYPE newElement) { | 
|  | CNode *pNode = (CNode *) pos; | 
|  | _ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); | 
|  | pNode->data = newElement; | 
|  | } | 
|  |  | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | CDXList<TYPE,ARG_TYPE>::CDXList(int nBlockSize) { | 
|  | _ASSERT(nBlockSize > 0); | 
|  | m_nCount = 0; | 
|  | m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; | 
|  | m_pBlocks = NULL; | 
|  | m_nBlockSize = nBlockSize; | 
|  | } | 
|  |  | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | void CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | CDXList<TYPE,ARG_TYPE>::~CDXList() { | 
|  | RemoveAll(); | 
|  | _ASSERT(m_nCount==0); | 
|  | } | 
|  |  | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | typename CDXList<TYPE,ARG_TYPE>::CNode * | 
|  | CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXList<TYPE,ARG_TYPE>::FreeNode(CNode *pNode) { | 
|  | DXDestructElements(&pNode->data,1); | 
|  | pNode->pNext = m_pNodeFree; | 
|  | m_pNodeFree = pNode; | 
|  | m_nCount--; | 
|  | _ASSERT(m_nCount >= 0); | 
|  | } | 
|  |  | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | DXLISTPOS CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | DXLISTPOS CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXList<TYPE,ARG_TYPE>::AddHead(CDXList *pNewList) { | 
|  | DXASSERT_VALID(this); | 
|  | DXASSERT_VALID(pNewList); | 
|  | DXLISTPOS pos = pNewList->GetTailPosition(); | 
|  | while(pos!=NULL) | 
|  | AddHead(pNewList->GetPrev(pos)); | 
|  | } | 
|  |  | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | void CDXList<TYPE,ARG_TYPE>::AddTail(CDXList *pNewList) { | 
|  | DXASSERT_VALID(this); | 
|  | DXASSERT_VALID(pNewList); | 
|  | DXLISTPOS pos = pNewList->GetHeadPosition(); | 
|  | while(pos!=NULL) | 
|  | AddTail(pNewList->GetNext(pos)); | 
|  | } | 
|  |  | 
|  | template<class TYPE,class ARG_TYPE> | 
|  | TYPE CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | TYPE CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | DXLISTPOS CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | DXLISTPOS CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | DXLISTPOS CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | DXLISTPOS CDXList<TYPE,ARG_TYPE>::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<class TYPE,class ARG_TYPE> | 
|  | void CDXList<TYPE,ARG_TYPE>::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 KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | 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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | inline int CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetCount() const { return m_nCount; } | 
|  | template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | inline WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::IsEmpty() const { return m_nCount==0; } | 
|  | template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | inline void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::SetAt(ARG_KEY key,ARG_VALUE newValue) { (*this)[key] = newValue; } | 
|  | template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | inline DXLISTPOS CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetStartPosition() const { return (m_nCount==0) ? NULL : DX_BEFORE_START_POSITION; } | 
|  | template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | inline UINT CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetHashTableSize() const { return m_nHashTableSize; } | 
|  |  | 
|  | template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::~CDXMap() { | 
|  | RemoveAll(); | 
|  | _ASSERT(m_nCount==0); | 
|  | } | 
|  |  | 
|  | template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | typename CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CAssoc* | 
|  | CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | typename CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CAssoc* | 
|  | CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | VALUE& CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::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<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> | 
|  | void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::AssertValid() const { | 
|  | _ASSERT(m_nHashTableSize > 0); | 
|  | _ASSERT((m_nCount==0 || m_pHashTable!=NULL)); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #endif /* __cplusplus */ | 
|  |  | 
|  | #endif |