| 1 |
/** |
| 2 |
* This file has no copyright assigned and is placed in the Public Domain. |
| 3 |
* This file is part of the mingw-w64 runtime package. |
| 4 |
* No warranty is given; refer to the file DISCLAIMER.PD within this package. |
| 5 |
*/ |
| 6 |
#ifndef DXTmpl_h |
| 7 |
#define DXTmpl_h |
| 8 |
|
| 9 |
#include <limits.h> |
| 10 |
#include <string.h> |
| 11 |
#include <stdlib.h> |
| 12 |
#include <search.h> |
| 13 |
|
| 14 |
#define DXASSERT_VALID(pObj) |
| 15 |
|
| 16 |
#ifndef PASCAL_INLINE |
| 17 |
#define PASCAL_INLINE WINAPI |
| 18 |
#endif |
| 19 |
|
| 20 |
typedef void *DXLISTPOS; |
| 21 |
typedef DWORD DXLISTHANDLE; |
| 22 |
|
| 23 |
#define DX_BEFORE_START_POSITION ((void*)(INT_PTR)-1) |
| 24 |
|
| 25 |
#ifndef __CRT__NO_INLINE |
| 26 |
__CRT_INLINE WINBOOL DXIsValidAddress(const void *lp,UINT nBytes,WINBOOL bReadWrite) { return (lp!=NULL && !IsBadReadPtr(lp,nBytes) && (!bReadWrite || !IsBadWritePtr((LPVOID)lp,nBytes))); } |
| 27 |
#endif |
| 28 |
|
| 29 |
#ifdef __cplusplus |
| 30 |
|
| 31 |
template<class TYPE> |
| 32 |
inline void DXConstructElements(TYPE *pElements,int nCount) { |
| 33 |
_ASSERT(nCount==0 || DXIsValidAddress(pElements,nCount *sizeof(TYPE),TRUE)); |
| 34 |
memset((void*)pElements,0,nCount *sizeof(TYPE)); |
| 35 |
} |
| 36 |
|
| 37 |
template<class TYPE> |
| 38 |
inline void DXDestructElements(TYPE *pElements,int nCount) { |
| 39 |
_ASSERT((nCount==0 || DXIsValidAddress(pElements,nCount *sizeof(TYPE),TRUE))); |
| 40 |
pElements; |
| 41 |
nCount; |
| 42 |
} |
| 43 |
|
| 44 |
template<class TYPE> |
| 45 |
inline void DXCopyElements(TYPE *pDest,const TYPE *pSrc,int nCount) { |
| 46 |
_ASSERT((nCount==0 || DXIsValidAddress(pDest,nCount *sizeof(TYPE),TRUE))); |
| 47 |
_ASSERT((nCount==0 || DXIsValidAddress(pSrc,nCount *sizeof(TYPE),FALSE))); |
| 48 |
memcpy(pDest,pSrc,nCount *sizeof(TYPE)); |
| 49 |
} |
| 50 |
|
| 51 |
template<class TYPE,class ARG_TYPE> |
| 52 |
WINBOOL DXCompareElements(const TYPE *pElement1,const ARG_TYPE *pElement2) { |
| 53 |
_ASSERT(DXIsValidAddress(pElement1,sizeof(TYPE),FALSE)); |
| 54 |
_ASSERT(DXIsValidAddress(pElement2,sizeof(ARG_TYPE),FALSE)); |
| 55 |
return *pElement1==*pElement2; |
| 56 |
} |
| 57 |
|
| 58 |
template<class ARG_KEY> |
| 59 |
inline UINT DXHashKey(ARG_KEY key) { return ((UINT)(void*)(DWORD)key) >> 4; } |
| 60 |
|
| 61 |
struct CDXPlex { |
| 62 |
CDXPlex *pNext; |
| 63 |
UINT nMax; |
| 64 |
UINT nCur; |
| 65 |
void *data() { return this+1; } |
| 66 |
static CDXPlex *PASCAL_INLINE Create(CDXPlex *&pHead,UINT nMax,UINT cbElement) { |
| 67 |
CDXPlex *p = (CDXPlex*) new BYTE[sizeof(CDXPlex) + nMax *cbElement]; |
| 68 |
if(!p) return NULL; |
| 69 |
p->nMax = nMax; |
| 70 |
p->nCur = 0; |
| 71 |
p->pNext = pHead; |
| 72 |
pHead = p; |
| 73 |
return p; |
| 74 |
} |
| 75 |
void FreeDataChain() { |
| 76 |
CDXPlex *p = this; |
| 77 |
while(p!=NULL) { |
| 78 |
BYTE *bytes = (BYTE*) p; |
| 79 |
CDXPlex *pNext = p->pNext; |
| 80 |
delete [] bytes; |
| 81 |
p = pNext; |
| 82 |
} |
| 83 |
} |
| 84 |
}; |
| 85 |
|
| 86 |
template<class TYPE,class ARG_TYPE> |
| 87 |
class CDXArray { |
| 88 |
public: |
| 89 |
CDXArray(); |
| 90 |
int GetSize() const; |
| 91 |
int GetUpperBound() const; |
| 92 |
void SetSize(int nNewSize,int nGrowBy = -1); |
| 93 |
void FreeExtra(); |
| 94 |
void RemoveAll(); |
| 95 |
TYPE GetAt(int nIndex) const; |
| 96 |
void SetAt(int nIndex,ARG_TYPE newElement); |
| 97 |
TYPE &ElementAt(int nIndex); |
| 98 |
const TYPE *GetData() const; |
| 99 |
TYPE *GetData(); |
| 100 |
void SetAtGrow(int nIndex,ARG_TYPE newElement); |
| 101 |
int Add(ARG_TYPE newElement); |
| 102 |
int Append(const CDXArray &src); |
| 103 |
void Copy(const CDXArray &src); |
| 104 |
TYPE operator[](int nIndex) const; |
| 105 |
TYPE &operator[](int nIndex); |
| 106 |
void InsertAt(int nIndex,ARG_TYPE newElement,int nCount = 1); |
| 107 |
void RemoveAt(int nIndex,int nCount = 1); |
| 108 |
void InsertAt(int nStartIndex,CDXArray *pNewArray); |
| 109 |
void Sort(int (__cdecl *compare)(const void *elem1,const void *elem2)); |
| 110 |
protected: |
| 111 |
TYPE *m_pData; |
| 112 |
int m_nSize; |
| 113 |
int m_nMaxSize; |
| 114 |
int m_nGrowBy; |
| 115 |
public: |
| 116 |
~CDXArray(); |
| 117 |
}; |
| 118 |
|
| 119 |
template<class TYPE,class ARG_TYPE> |
| 120 |
inline int CDXArray<TYPE,ARG_TYPE>::GetSize() const { return m_nSize; } |
| 121 |
template<class TYPE,class ARG_TYPE> |
| 122 |
inline int CDXArray<TYPE,ARG_TYPE>::GetUpperBound() const { return m_nSize-1; } |
| 123 |
template<class TYPE,class ARG_TYPE> |
| 124 |
inline void CDXArray<TYPE,ARG_TYPE>::RemoveAll() { SetSize(0,-1); } |
| 125 |
template<class TYPE,class ARG_TYPE> |
| 126 |
inline TYPE CDXArray<TYPE,ARG_TYPE>::GetAt(int nIndex) const { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); return m_pData[nIndex]; } |
| 127 |
template<class TYPE,class ARG_TYPE> |
| 128 |
inline void CDXArray<TYPE,ARG_TYPE>::SetAt(int nIndex,ARG_TYPE newElement) { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); m_pData[nIndex] = newElement; } |
| 129 |
template<class TYPE,class ARG_TYPE> |
| 130 |
inline TYPE &CDXArray<TYPE,ARG_TYPE>::ElementAt(int nIndex) { _ASSERT((nIndex >= 0 && nIndex < m_nSize)); return m_pData[nIndex]; } |
| 131 |
template<class TYPE,class ARG_TYPE> |
| 132 |
inline const TYPE *CDXArray<TYPE,ARG_TYPE>::GetData() const { return (const TYPE*)m_pData; } |
| 133 |
template<class TYPE,class ARG_TYPE> |
| 134 |
inline TYPE *CDXArray<TYPE,ARG_TYPE>::GetData() { return (TYPE*)m_pData; } |
| 135 |
template<class TYPE,class ARG_TYPE> |
| 136 |
inline int CDXArray<TYPE,ARG_TYPE>::Add(ARG_TYPE newElement) { |
| 137 |
int nIndex = m_nSize; |
| 138 |
SetAtGrow(nIndex,newElement); |
| 139 |
return nIndex; |
| 140 |
} |
| 141 |
template<class TYPE,class ARG_TYPE> |
| 142 |
inline TYPE CDXArray<TYPE,ARG_TYPE>::operator[](int nIndex) const { return GetAt(nIndex); } |
| 143 |
template<class TYPE,class ARG_TYPE> |
| 144 |
inline TYPE &CDXArray<TYPE,ARG_TYPE>::operator[](int nIndex) { return ElementAt(nIndex); } |
| 145 |
template<class TYPE,class ARG_TYPE> |
| 146 |
CDXArray<TYPE,ARG_TYPE>::CDXArray() { m_pData = NULL; m_nSize = m_nMaxSize = m_nGrowBy = 0; } |
| 147 |
emplate<class TYPE,class ARG_TYPE> |
| 148 |
CDXArray<TYPE,ARG_TYPE>::~CDXArray() { |
| 149 |
DXASSERT_VALID(this); |
| 150 |
if(m_pData!=NULL) { |
| 151 |
DXDestructElements(m_pData,m_nSize); |
| 152 |
delete[] (BYTE*)m_pData; |
| 153 |
} |
| 154 |
} |
| 155 |
|
| 156 |
template<class TYPE,class ARG_TYPE> |
| 157 |
void CDXArray<TYPE,ARG_TYPE>::SetSize(int nNewSize,int nGrowBy) { |
| 158 |
DXASSERT_VALID(this); |
| 159 |
_ASSERT(nNewSize >= 0); |
| 160 |
if(nGrowBy!=-1) m_nGrowBy = nGrowBy; |
| 161 |
if(nNewSize==0) { |
| 162 |
if(m_pData!=NULL) { |
| 163 |
DXDestructElements(m_pData,m_nSize); |
| 164 |
delete[] (BYTE*)m_pData; |
| 165 |
m_pData = NULL; |
| 166 |
} |
| 167 |
m_nSize = m_nMaxSize = 0; |
| 168 |
} else if(!m_pData) { |
| 169 |
#ifdef SIZE_T_MAX |
| 170 |
_ASSERT(nNewSize <= SIZE_T_MAX/sizeof(TYPE)); |
| 171 |
#endif |
| 172 |
m_pData = (TYPE*) new BYTE[nNewSize *sizeof(TYPE)]; |
| 173 |
DXConstructElements(m_pData,nNewSize); |
| 174 |
m_nSize = m_nMaxSize = nNewSize; |
| 175 |
} else if(nNewSize <= m_nMaxSize) { |
| 176 |
if(nNewSize > m_nSize) { |
| 177 |
DXConstructElements(&m_pData[m_nSize],nNewSize-m_nSize); |
| 178 |
} else if(m_nSize > nNewSize) { |
| 179 |
DXDestructElements(&m_pData[nNewSize],m_nSize-nNewSize); |
| 180 |
} |
| 181 |
m_nSize = nNewSize; |
| 182 |
} else { |
| 183 |
int nGrowBy = m_nGrowBy; |
| 184 |
if(!nGrowBy) nGrowBy = min(1024,max(4,m_nSize / 8)); |
| 185 |
int nNewMax; |
| 186 |
if(nNewSize < m_nMaxSize + nGrowBy) nNewMax = m_nMaxSize + nGrowBy; |
| 187 |
else nNewMax = nNewSize; |
| 188 |
_ASSERT(nNewMax >= m_nMaxSize); |
| 189 |
#ifdef SIZE_T_MAX |
| 190 |
_ASSERT(nNewMax <= SIZE_T_MAX/sizeof(TYPE)); |
| 191 |
#endif |
| 192 |
TYPE *pNewData = (TYPE*) new BYTE[nNewMax *sizeof(TYPE)]; |
| 193 |
|
| 194 |
if(!pNewData) return; |
| 195 |
memcpy(pNewData,m_pData,m_nSize *sizeof(TYPE)); |
| 196 |
_ASSERT(nNewSize > m_nSize); |
| 197 |
DXConstructElements(&pNewData[m_nSize],nNewSize-m_nSize); |
| 198 |
delete[] (BYTE*)m_pData; |
| 199 |
m_pData = pNewData; |
| 200 |
m_nSize = nNewSize; |
| 201 |
m_nMaxSize = nNewMax; |
| 202 |
} |
| 203 |
} |
| 204 |
|
| 205 |
template<class TYPE,class ARG_TYPE> |
| 206 |
int CDXArray<TYPE,ARG_TYPE>::Append(const CDXArray &src) { |
| 207 |
DXASSERT_VALID(this); |
| 208 |
_ASSERT(this!=&src); |
| 209 |
int nOldSize = m_nSize; |
| 210 |
SetSize(m_nSize + src.m_nSize); |
| 211 |
DXCopyElements(m_pData + nOldSize,src.m_pData,src.m_nSize); |
| 212 |
return nOldSize; |
| 213 |
} |
| 214 |
|
| 215 |
template<class TYPE,class ARG_TYPE> |
| 216 |
void CDXArray<TYPE,ARG_TYPE>::Copy(const CDXArray &src) { |
| 217 |
DXASSERT_VALID(this); |
| 218 |
_ASSERT(this!=&src); |
| 219 |
SetSize(src.m_nSize); |
| 220 |
DXCopyElements(m_pData,src.m_pData,src.m_nSize); |
| 221 |
} |
| 222 |
|
| 223 |
template<class TYPE,class ARG_TYPE> |
| 224 |
void CDXArray<TYPE,ARG_TYPE>::FreeExtra() { |
| 225 |
DXASSERT_VALID(this); |
| 226 |
if(m_nSize!=m_nMaxSize) { |
| 227 |
#ifdef SIZE_T_MAX |
| 228 |
_ASSERT(m_nSize <= SIZE_T_MAX/sizeof(TYPE)); |
| 229 |
#endif |
| 230 |
TYPE *pNewData = NULL; |
| 231 |
if(m_nSize!=0) { |
| 232 |
pNewData = (TYPE*) new BYTE[m_nSize *sizeof(TYPE)]; |
| 233 |
if(!pNewData) return; |
| 234 |
memcpy(pNewData,m_pData,m_nSize *sizeof(TYPE)); |
| 235 |
} |
| 236 |
delete[] (BYTE*)m_pData; |
| 237 |
m_pData = pNewData; |
| 238 |
m_nMaxSize = m_nSize; |
| 239 |
} |
| 240 |
} |
| 241 |
|
| 242 |
template<class TYPE,class ARG_TYPE> |
| 243 |
void CDXArray<TYPE,ARG_TYPE>::SetAtGrow(int nIndex,ARG_TYPE newElement) { |
| 244 |
DXASSERT_VALID(this); |
| 245 |
_ASSERT(nIndex >= 0); |
| 246 |
if(nIndex >= m_nSize) SetSize(nIndex+1,-1); |
| 247 |
m_pData[nIndex] = newElement; |
| 248 |
} |
| 249 |
|
| 250 |
template<class TYPE,class ARG_TYPE> |
| 251 |
void CDXArray<TYPE,ARG_TYPE>::InsertAt(int nIndex,ARG_TYPE newElement,int nCount) { |
| 252 |
DXASSERT_VALID(this); |
| 253 |
_ASSERT(nIndex >= 0); |
| 254 |
_ASSERT(nCount > 0); |
| 255 |
if(nIndex >= m_nSize) SetSize(nIndex + nCount,-1); |
| 256 |
else { |
| 257 |
int nOldSize = m_nSize; |
| 258 |
SetSize(m_nSize + nCount,-1); |
| 259 |
memmove(&m_pData[nIndex+nCount],&m_pData[nIndex],(nOldSize-nIndex) *sizeof(TYPE)); |
| 260 |
DXConstructElements(&m_pData[nIndex],nCount); |
| 261 |
} |
| 262 |
_ASSERT(nIndex + nCount <= m_nSize); |
| 263 |
while(nCount--) |
| 264 |
m_pData[nIndex++] = newElement; |
| 265 |
} |
| 266 |
|
| 267 |
template<class TYPE,class ARG_TYPE> |
| 268 |
void CDXArray<TYPE,ARG_TYPE>::RemoveAt(int nIndex,int nCount) { |
| 269 |
DXASSERT_VALID(this); |
| 270 |
_ASSERT(nIndex >= 0); |
| 271 |
_ASSERT(nCount >= 0); |
| 272 |
_ASSERT(nIndex + nCount <= m_nSize); |
| 273 |
int nMoveCount = m_nSize - (nIndex + nCount); |
| 274 |
DXDestructElements(&m_pData[nIndex],nCount); |
| 275 |
if(nMoveCount) |
| 276 |
memcpy(&m_pData[nIndex],&m_pData[nIndex + nCount],nMoveCount *sizeof(TYPE)); |
| 277 |
m_nSize -= nCount; |
| 278 |
} |
| 279 |
|
| 280 |
template<class TYPE,class ARG_TYPE> |
| 281 |
void CDXArray<TYPE,ARG_TYPE>::InsertAt(int nStartIndex,CDXArray *pNewArray) { |
| 282 |
DXASSERT_VALID(this); |
| 283 |
DXASSERT_VALID(pNewArray); |
| 284 |
_ASSERT(nStartIndex >= 0); |
| 285 |
if(pNewArray->GetSize() > 0) { |
| 286 |
InsertAt(nStartIndex,pNewArray->GetAt(0),pNewArray->GetSize()); |
| 287 |
for(int i = 0;i < pNewArray->GetSize();i++) |
| 288 |
SetAt(nStartIndex + i,pNewArray->GetAt(i)); |
| 289 |
} |
| 290 |
} |
| 291 |
|
| 292 |
template<class TYPE,class ARG_TYPE> |
| 293 |
void CDXArray<TYPE,ARG_TYPE>::Sort(int (__cdecl *compare)(const void *elem1,const void *elem2)) { |
| 294 |
DXASSERT_VALID(this); |
| 295 |
_ASSERT(m_pData!=NULL); |
| 296 |
qsort(m_pData,m_nSize,sizeof(TYPE),compare); |
| 297 |
} |
| 298 |
|
| 299 |
#ifdef _DEBUG |
| 300 |
template<class TYPE,class ARG_TYPE> |
| 301 |
void CDXArray<TYPE,ARG_TYPE>::AssertValid() const { |
| 302 |
if(!m_pData) { |
| 303 |
_ASSERT(m_nSize==0); |
| 304 |
_ASSERT(m_nMaxSize==0); |
| 305 |
} else { |
| 306 |
_ASSERT(m_nSize >= 0); |
| 307 |
_ASSERT(m_nMaxSize >= 0); |
| 308 |
_ASSERT(m_nSize <= m_nMaxSize); |
| 309 |
_ASSERT(DXIsValidAddress(m_pData,m_nMaxSize *sizeof(TYPE),TRUE)); |
| 310 |
} |
| 311 |
} |
| 312 |
#endif |
| 313 |
|
| 314 |
template<class TYPE,class ARG_TYPE> |
| 315 |
class CDXList { |
| 316 |
protected: |
| 317 |
struct CNode { |
| 318 |
CNode *pNext; |
| 319 |
CNode *pPrev; |
| 320 |
TYPE data; |
| 321 |
}; |
| 322 |
public: |
| 323 |
CDXList(int nBlockSize = 10); |
| 324 |
int GetCount() const; |
| 325 |
WINBOOL IsEmpty() const; |
| 326 |
TYPE &GetHead(); |
| 327 |
TYPE GetHead() const; |
| 328 |
TYPE &GetTail(); |
| 329 |
TYPE GetTail() const; |
| 330 |
|
| 331 |
TYPE RemoveHead(); |
| 332 |
TYPE RemoveTail(); |
| 333 |
DXLISTPOS AddHead(ARG_TYPE newElement); |
| 334 |
DXLISTPOS AddTail(ARG_TYPE newElement); |
| 335 |
void AddHead(CDXList *pNewList); |
| 336 |
void AddTail(CDXList *pNewList); |
| 337 |
void RemoveAll(); |
| 338 |
DXLISTPOS GetHeadPosition() const; |
| 339 |
DXLISTPOS GetTailPosition() const; |
| 340 |
TYPE &GetNext(DXLISTPOS &rPosition); |
| 341 |
TYPE GetNext(DXLISTPOS &rPosition) const; |
| 342 |
TYPE &GetPrev(DXLISTPOS &rPosition); |
| 343 |
TYPE GetPrev(DXLISTPOS &rPosition) const; |
| 344 |
TYPE &GetAt(DXLISTPOS position); |
| 345 |
TYPE GetAt(DXLISTPOS position) const; |
| 346 |
void SetAt(DXLISTPOS pos,ARG_TYPE newElement); |
| 347 |
void RemoveAt(DXLISTPOS position); |
| 348 |
DXLISTPOS InsertBefore(DXLISTPOS position,ARG_TYPE newElement); |
| 349 |
DXLISTPOS InsertAfter(DXLISTPOS position,ARG_TYPE newElement); |
| 350 |
DXLISTPOS Find(ARG_TYPE searchValue,DXLISTPOS startAfter = NULL) const; |
| 351 |
DXLISTPOS FindIndex(int nIndex) const; |
| 352 |
protected: |
| 353 |
CNode *m_pNodeHead; |
| 354 |
CNode *m_pNodeTail; |
| 355 |
int m_nCount; |
| 356 |
CNode *m_pNodeFree; |
| 357 |
struct CDXPlex *m_pBlocks; |
| 358 |
int m_nBlockSize; |
| 359 |
CNode *NewNode(CNode *,CNode *); |
| 360 |
void FreeNode(CNode *); |
| 361 |
public: |
| 362 |
~CDXList(); |
| 363 |
#ifdef _DEBUG |
| 364 |
void AssertValid() const; |
| 365 |
#endif |
| 366 |
}; |
| 367 |
|
| 368 |
template<class TYPE,class ARG_TYPE> |
| 369 |
inline int CDXList<TYPE,ARG_TYPE>::GetCount() const { return m_nCount; } |
| 370 |
template<class TYPE,class ARG_TYPE> |
| 371 |
inline WINBOOL CDXList<TYPE,ARG_TYPE>::IsEmpty() const { return m_nCount==0; } |
| 372 |
template<class TYPE,class ARG_TYPE> |
| 373 |
inline TYPE &CDXList<TYPE,ARG_TYPE>::GetHead() { _ASSERT(m_pNodeHead!=NULL); return m_pNodeHead->data; } |
| 374 |
template<class TYPE,class ARG_TYPE> |
| 375 |
inline TYPE CDXList<TYPE,ARG_TYPE>::GetHead() const { _ASSERT(m_pNodeHead!=NULL); return m_pNodeHead->data; } |
| 376 |
template<class TYPE,class ARG_TYPE> |
| 377 |
inline TYPE &CDXList<TYPE,ARG_TYPE>::GetTail() { _ASSERT(m_pNodeTail!=NULL); return m_pNodeTail->data; } |
| 378 |
template<class TYPE,class ARG_TYPE> |
| 379 |
inline TYPE CDXList<TYPE,ARG_TYPE>::GetTail() const { _ASSERT(m_pNodeTail!=NULL); return m_pNodeTail->data; } |
| 380 |
template<class TYPE,class ARG_TYPE> |
| 381 |
inline DXLISTPOS CDXList<TYPE,ARG_TYPE>::GetHeadPosition() const { return (DXLISTPOS) m_pNodeHead; } |
| 382 |
template<class TYPE,class ARG_TYPE> |
| 383 |
inline DXLISTPOS CDXList<TYPE,ARG_TYPE>::GetTailPosition() const { return (DXLISTPOS) m_pNodeTail; } |
| 384 |
template<class TYPE,class ARG_TYPE> |
| 385 |
inline TYPE &CDXList<TYPE,ARG_TYPE>::GetNext(DXLISTPOS &rPosition) { |
| 386 |
CNode *pNode = (CNode *) rPosition; |
| 387 |
_ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); |
| 388 |
rPosition = (DXLISTPOS) pNode->pNext; |
| 389 |
return pNode->data; |
| 390 |
} |
| 391 |
template<class TYPE,class ARG_TYPE> |
| 392 |
inline TYPE CDXList<TYPE,ARG_TYPE>::GetNext(DXLISTPOS &rPosition) const { |
| 393 |
CNode *pNode = (CNode *) rPosition; |
| 394 |
_ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); |
| 395 |
rPosition = (DXLISTPOS) pNode->pNext; |
| 396 |
return pNode->data; |
| 397 |
} |
| 398 |
template<class TYPE,class ARG_TYPE> |
| 399 |
inline TYPE &CDXList<TYPE,ARG_TYPE>::GetPrev(DXLISTPOS &rPosition) { |
| 400 |
CNode *pNode = (CNode *) rPosition; |
| 401 |
_ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); |
| 402 |
rPosition = (DXLISTPOS) pNode->pPrev; |
| 403 |
return pNode->data; |
| 404 |
} |
| 405 |
template<class TYPE,class ARG_TYPE> |
| 406 |
inline TYPE CDXList<TYPE,ARG_TYPE>::GetPrev(DXLISTPOS &rPosition) const { |
| 407 |
CNode *pNode = (CNode *) rPosition; |
| 408 |
_ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); |
| 409 |
rPosition = (DXLISTPOS) pNode->pPrev; |
| 410 |
return pNode->data; |
| 411 |
} |
| 412 |
template<class TYPE,class ARG_TYPE> |
| 413 |
inline TYPE &CDXList<TYPE,ARG_TYPE>::GetAt(DXLISTPOS position) { |
| 414 |
CNode *pNode = (CNode *) position; |
| 415 |
_ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); |
| 416 |
return pNode->data; |
| 417 |
} |
| 418 |
template<class TYPE,class ARG_TYPE> |
| 419 |
inline TYPE CDXList<TYPE,ARG_TYPE>::GetAt(DXLISTPOS position) const { |
| 420 |
CNode *pNode = (CNode *) position; |
| 421 |
_ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); |
| 422 |
return pNode->data; |
| 423 |
} |
| 424 |
template<class TYPE,class ARG_TYPE> |
| 425 |
inline void CDXList<TYPE,ARG_TYPE>::SetAt(DXLISTPOS pos,ARG_TYPE newElement) { |
| 426 |
CNode *pNode = (CNode *) pos; |
| 427 |
_ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); |
| 428 |
pNode->data = newElement; |
| 429 |
} |
| 430 |
|
| 431 |
template<class TYPE,class ARG_TYPE> |
| 432 |
CDXList<TYPE,ARG_TYPE>::CDXList(int nBlockSize) { |
| 433 |
_ASSERT(nBlockSize > 0); |
| 434 |
m_nCount = 0; |
| 435 |
m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; |
| 436 |
m_pBlocks = NULL; |
| 437 |
m_nBlockSize = nBlockSize; |
| 438 |
} |
| 439 |
|
| 440 |
template<class TYPE,class ARG_TYPE> |
| 441 |
void CDXList<TYPE,ARG_TYPE>::RemoveAll() { |
| 442 |
DXASSERT_VALID(this); |
| 443 |
CNode *pNode; |
| 444 |
for(pNode = m_pNodeHead;pNode!=NULL;pNode = pNode->pNext) |
| 445 |
DXDestructElements(&pNode->data,1); |
| 446 |
m_nCount = 0; |
| 447 |
m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; |
| 448 |
m_pBlocks->FreeDataChain(); |
| 449 |
m_pBlocks = NULL; |
| 450 |
} |
| 451 |
|
| 452 |
template<class TYPE,class ARG_TYPE> |
| 453 |
CDXList<TYPE,ARG_TYPE>::~CDXList() { |
| 454 |
RemoveAll(); |
| 455 |
_ASSERT(m_nCount==0); |
| 456 |
} |
| 457 |
|
| 458 |
template<class TYPE,class ARG_TYPE> |
| 459 |
typename CDXList<TYPE,ARG_TYPE>::CNode * |
| 460 |
CDXList<TYPE,ARG_TYPE>::NewNode(CNode *pPrev,CNode *pNext) { |
| 461 |
if(!m_pNodeFree) { |
| 462 |
CDXPlex *pNewBlock = CDXPlex::Create(m_pBlocks,m_nBlockSize,sizeof(CNode)); |
| 463 |
CNode *pNode = (CNode *) pNewBlock->data(); |
| 464 |
pNode += m_nBlockSize - 1; |
| 465 |
for(int i = m_nBlockSize-1;i >= 0;i--,pNode--) { |
| 466 |
pNode->pNext = m_pNodeFree; |
| 467 |
m_pNodeFree = pNode; |
| 468 |
} |
| 469 |
} |
| 470 |
_ASSERT(m_pNodeFree!=NULL); |
| 471 |
CDXList::CNode *pNode = m_pNodeFree; |
| 472 |
m_pNodeFree = m_pNodeFree->pNext; |
| 473 |
pNode->pPrev = pPrev; |
| 474 |
pNode->pNext = pNext; |
| 475 |
m_nCount++; |
| 476 |
_ASSERT(m_nCount > 0); |
| 477 |
DXConstructElements(&pNode->data,1); |
| 478 |
return pNode; |
| 479 |
} |
| 480 |
|
| 481 |
template<class TYPE,class ARG_TYPE> |
| 482 |
void CDXList<TYPE,ARG_TYPE>::FreeNode(CNode *pNode) { |
| 483 |
DXDestructElements(&pNode->data,1); |
| 484 |
pNode->pNext = m_pNodeFree; |
| 485 |
m_pNodeFree = pNode; |
| 486 |
m_nCount--; |
| 487 |
_ASSERT(m_nCount >= 0); |
| 488 |
} |
| 489 |
|
| 490 |
template<class TYPE,class ARG_TYPE> |
| 491 |
DXLISTPOS CDXList<TYPE,ARG_TYPE>::AddHead(ARG_TYPE newElement) { |
| 492 |
DXASSERT_VALID(this); |
| 493 |
CNode *pNewNode = NewNode(NULL,m_pNodeHead); |
| 494 |
pNewNode->data = newElement; |
| 495 |
if(m_pNodeHead!=NULL) m_pNodeHead->pPrev = pNewNode; |
| 496 |
else m_pNodeTail = pNewNode; |
| 497 |
m_pNodeHead = pNewNode; |
| 498 |
return (DXLISTPOS) pNewNode; |
| 499 |
} |
| 500 |
|
| 501 |
template<class TYPE,class ARG_TYPE> |
| 502 |
DXLISTPOS CDXList<TYPE,ARG_TYPE>::AddTail(ARG_TYPE newElement) { |
| 503 |
DXASSERT_VALID(this); |
| 504 |
CNode *pNewNode = NewNode(m_pNodeTail,NULL); |
| 505 |
pNewNode->data = newElement; |
| 506 |
if(m_pNodeTail!=NULL) m_pNodeTail->pNext = pNewNode; |
| 507 |
else m_pNodeHead = pNewNode; |
| 508 |
m_pNodeTail = pNewNode; |
| 509 |
return (DXLISTPOS) pNewNode; |
| 510 |
} |
| 511 |
|
| 512 |
template<class TYPE,class ARG_TYPE> |
| 513 |
void CDXList<TYPE,ARG_TYPE>::AddHead(CDXList *pNewList) { |
| 514 |
DXASSERT_VALID(this); |
| 515 |
DXASSERT_VALID(pNewList); |
| 516 |
DXLISTPOS pos = pNewList->GetTailPosition(); |
| 517 |
while(pos!=NULL) |
| 518 |
AddHead(pNewList->GetPrev(pos)); |
| 519 |
} |
| 520 |
|
| 521 |
template<class TYPE,class ARG_TYPE> |
| 522 |
void CDXList<TYPE,ARG_TYPE>::AddTail(CDXList *pNewList) { |
| 523 |
DXASSERT_VALID(this); |
| 524 |
DXASSERT_VALID(pNewList); |
| 525 |
DXLISTPOS pos = pNewList->GetHeadPosition(); |
| 526 |
while(pos!=NULL) |
| 527 |
AddTail(pNewList->GetNext(pos)); |
| 528 |
} |
| 529 |
|
| 530 |
template<class TYPE,class ARG_TYPE> |
| 531 |
TYPE CDXList<TYPE,ARG_TYPE>::RemoveHead() { |
| 532 |
DXASSERT_VALID(this); |
| 533 |
_ASSERT(m_pNodeHead!=NULL); |
| 534 |
_ASSERT(DXIsValidAddress(m_pNodeHead,sizeof(CNode),TRUE)); |
| 535 |
CNode *pOldNode = m_pNodeHead; |
| 536 |
TYPE returnValue = pOldNode->data; |
| 537 |
m_pNodeHead = pOldNode->pNext; |
| 538 |
if(m_pNodeHead!=NULL) m_pNodeHead->pPrev = NULL; |
| 539 |
else m_pNodeTail = NULL; |
| 540 |
FreeNode(pOldNode); |
| 541 |
return returnValue; |
| 542 |
} |
| 543 |
|
| 544 |
template<class TYPE,class ARG_TYPE> |
| 545 |
TYPE CDXList<TYPE,ARG_TYPE>::RemoveTail() { |
| 546 |
DXASSERT_VALID(this); |
| 547 |
_ASSERT(m_pNodeTail!=NULL); |
| 548 |
_ASSERT(DXIsValidAddress(m_pNodeTail,sizeof(CNode),TRUE)); |
| 549 |
CNode *pOldNode = m_pNodeTail; |
| 550 |
TYPE returnValue = pOldNode->data; |
| 551 |
m_pNodeTail = pOldNode->pPrev; |
| 552 |
if(m_pNodeTail!=NULL) m_pNodeTail->pNext = NULL; |
| 553 |
else m_pNodeHead = NULL; |
| 554 |
FreeNode(pOldNode); |
| 555 |
return returnValue; |
| 556 |
} |
| 557 |
|
| 558 |
template<class TYPE,class ARG_TYPE> |
| 559 |
DXLISTPOS CDXList<TYPE,ARG_TYPE>::InsertBefore(DXLISTPOS position,ARG_TYPE newElement) { |
| 560 |
DXASSERT_VALID(this); |
| 561 |
if(!position) return AddHead(newElement); |
| 562 |
CNode *pOldNode = (CNode *) position; |
| 563 |
CNode *pNewNode = NewNode(pOldNode->pPrev,pOldNode); |
| 564 |
pNewNode->data = newElement; |
| 565 |
if(pOldNode->pPrev!=NULL) { |
| 566 |
_ASSERT(DXIsValidAddress(pOldNode->pPrev,sizeof(CNode),TRUE)); |
| 567 |
pOldNode->pPrev->pNext = pNewNode; |
| 568 |
} else { |
| 569 |
_ASSERT(pOldNode==m_pNodeHead); |
| 570 |
m_pNodeHead = pNewNode; |
| 571 |
} |
| 572 |
pOldNode->pPrev = pNewNode; |
| 573 |
return (DXLISTPOS) pNewNode; |
| 574 |
} |
| 575 |
|
| 576 |
template<class TYPE,class ARG_TYPE> |
| 577 |
DXLISTPOS CDXList<TYPE,ARG_TYPE>::InsertAfter(DXLISTPOS position,ARG_TYPE newElement) { |
| 578 |
DXASSERT_VALID(this); |
| 579 |
if(!position) return AddTail(newElement); |
| 580 |
CNode *pOldNode = (CNode *) position; |
| 581 |
_ASSERT(DXIsValidAddress(pOldNode,sizeof(CNode),TRUE)); |
| 582 |
CNode *pNewNode = NewNode(pOldNode,pOldNode->pNext); |
| 583 |
pNewNode->data = newElement; |
| 584 |
if(pOldNode->pNext!=NULL) { |
| 585 |
_ASSERT(DXIsValidAddress(pOldNode->pNext,sizeof(CNode),TRUE)); |
| 586 |
pOldNode->pNext->pPrev = pNewNode; |
| 587 |
} else { |
| 588 |
_ASSERT(pOldNode==m_pNodeTail); |
| 589 |
m_pNodeTail = pNewNode; |
| 590 |
} |
| 591 |
pOldNode->pNext = pNewNode; |
| 592 |
return (DXLISTPOS) pNewNode; |
| 593 |
} |
| 594 |
|
| 595 |
template<class TYPE,class ARG_TYPE> |
| 596 |
void CDXList<TYPE,ARG_TYPE>::RemoveAt(DXLISTPOS position) { |
| 597 |
DXASSERT_VALID(this); |
| 598 |
CNode *pOldNode = (CNode *) position; |
| 599 |
_ASSERT(DXIsValidAddress(pOldNode,sizeof(CNode),TRUE)); |
| 600 |
if(pOldNode==m_pNodeHead) { |
| 601 |
m_pNodeHead = pOldNode->pNext; |
| 602 |
} else { |
| 603 |
_ASSERT(DXIsValidAddress(pOldNode->pPrev,sizeof(CNode),TRUE)); |
| 604 |
pOldNode->pPrev->pNext = pOldNode->pNext; |
| 605 |
} |
| 606 |
if(pOldNode==m_pNodeTail) m_pNodeTail = pOldNode->pPrev; |
| 607 |
else { |
| 608 |
_ASSERT(DXIsValidAddress(pOldNode->pNext,sizeof(CNode),TRUE)); |
| 609 |
pOldNode->pNext->pPrev = pOldNode->pPrev; |
| 610 |
} |
| 611 |
FreeNode(pOldNode); |
| 612 |
} |
| 613 |
|
| 614 |
template<class TYPE,class ARG_TYPE> |
| 615 |
DXLISTPOS CDXList<TYPE,ARG_TYPE>::FindIndex(int nIndex) const { |
| 616 |
DXASSERT_VALID(this); |
| 617 |
_ASSERT(nIndex >= 0); |
| 618 |
if(nIndex >= m_nCount) return NULL; |
| 619 |
CNode *pNode = m_pNodeHead; |
| 620 |
while(nIndex--) { |
| 621 |
_ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); |
| 622 |
pNode = pNode->pNext; |
| 623 |
} |
| 624 |
return (DXLISTPOS) pNode; |
| 625 |
} |
| 626 |
|
| 627 |
template<class TYPE,class ARG_TYPE> |
| 628 |
DXLISTPOS CDXList<TYPE,ARG_TYPE>::Find(ARG_TYPE searchValue,DXLISTPOS startAfter) const { |
| 629 |
DXASSERT_VALID(this); |
| 630 |
CNode *pNode = (CNode *) startAfter; |
| 631 |
if(!pNode) pNode = m_pNodeHead; |
| 632 |
else { |
| 633 |
_ASSERT(DXIsValidAddress(pNode,sizeof(CNode),TRUE)); |
| 634 |
pNode = pNode->pNext; |
| 635 |
} |
| 636 |
for(;pNode!=NULL;pNode = pNode->pNext) |
| 637 |
if(DXCompareElements(&pNode->data,&searchValue)) return (DXLISTPOS)pNode; |
| 638 |
return NULL; |
| 639 |
} |
| 640 |
|
| 641 |
#ifdef _DEBUG |
| 642 |
template<class TYPE,class ARG_TYPE> |
| 643 |
void CDXList<TYPE,ARG_TYPE>::AssertValid() const { |
| 644 |
if(!m_nCount) { |
| 645 |
_ASSERT(!m_pNodeHead); |
| 646 |
_ASSERT(!m_pNodeTail); |
| 647 |
} else { |
| 648 |
_ASSERT(DXIsValidAddress(m_pNodeHead,sizeof(CNode),TRUE)); |
| 649 |
_ASSERT(DXIsValidAddress(m_pNodeTail,sizeof(CNode),TRUE)); |
| 650 |
} |
| 651 |
} |
| 652 |
#endif |
| 653 |
|
| 654 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 655 |
class CDXMap { |
| 656 |
protected: |
| 657 |
struct CAssoc { |
| 658 |
CAssoc *pNext; |
| 659 |
UINT nHashValue; |
| 660 |
KEY key; |
| 661 |
VALUE value; |
| 662 |
}; |
| 663 |
public: |
| 664 |
CDXMap(int nBlockSize = 10); |
| 665 |
int GetCount() const; |
| 666 |
WINBOOL IsEmpty() const; |
| 667 |
WINBOOL Lookup(ARG_KEY key,VALUE& rValue) const; |
| 668 |
VALUE& operator[](ARG_KEY key); |
| 669 |
void SetAt(ARG_KEY key,ARG_VALUE newValue); |
| 670 |
WINBOOL RemoveKey(ARG_KEY key); |
| 671 |
void RemoveAll(); |
| 672 |
DXLISTPOS GetStartPosition() const; |
| 673 |
void GetNextAssoc(DXLISTPOS &rNextPosition,KEY& rKey,VALUE& rValue) const; |
| 674 |
UINT GetHashTableSize() const; |
| 675 |
void InitHashTable(UINT hashSize,WINBOOL bAllocNow = TRUE); |
| 676 |
protected: |
| 677 |
CAssoc **m_pHashTable; |
| 678 |
UINT m_nHashTableSize; |
| 679 |
int m_nCount; |
| 680 |
CAssoc *m_pFreeList; |
| 681 |
struct CDXPlex *m_pBlocks; |
| 682 |
int m_nBlockSize; |
| 683 |
CAssoc *NewAssoc(); |
| 684 |
void FreeAssoc(CAssoc*); |
| 685 |
CAssoc *GetAssocAt(ARG_KEY,UINT&) const; |
| 686 |
public: |
| 687 |
~CDXMap(); |
| 688 |
#ifdef _DEBUG |
| 689 |
void AssertValid() const; |
| 690 |
#endif |
| 691 |
}; |
| 692 |
|
| 693 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 694 |
inline int CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetCount() const { return m_nCount; } |
| 695 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 696 |
inline WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::IsEmpty() const { return m_nCount==0; } |
| 697 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 698 |
inline void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::SetAt(ARG_KEY key,ARG_VALUE newValue) { (*this)[key] = newValue; } |
| 699 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 700 |
inline DXLISTPOS CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetStartPosition() const { return (m_nCount==0) ? NULL : DX_BEFORE_START_POSITION; } |
| 701 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 702 |
inline UINT CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetHashTableSize() const { return m_nHashTableSize; } |
| 703 |
|
| 704 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 705 |
CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CDXMap(int nBlockSize) { |
| 706 |
_ASSERT(nBlockSize > 0); |
| 707 |
m_pHashTable = NULL; |
| 708 |
m_nHashTableSize = 17; |
| 709 |
m_nCount = 0; |
| 710 |
m_pFreeList = NULL; |
| 711 |
m_pBlocks = NULL; |
| 712 |
m_nBlockSize = nBlockSize; |
| 713 |
} |
| 714 |
|
| 715 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 716 |
void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::InitHashTable(UINT nHashSize,WINBOOL bAllocNow) { |
| 717 |
DXASSERT_VALID(this); |
| 718 |
_ASSERT(m_nCount==0); |
| 719 |
_ASSERT(nHashSize > 0); |
| 720 |
if(m_pHashTable!=NULL) { |
| 721 |
delete[] m_pHashTable; |
| 722 |
m_pHashTable = NULL; |
| 723 |
} |
| 724 |
if(bAllocNow) { |
| 725 |
m_pHashTable = new CAssoc *[nHashSize]; |
| 726 |
if(!m_pHashTable) return; |
| 727 |
memset(m_pHashTable,0,sizeof(CAssoc*) *nHashSize); |
| 728 |
} |
| 729 |
m_nHashTableSize = nHashSize; |
| 730 |
} |
| 731 |
|
| 732 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 733 |
void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::RemoveAll() { |
| 734 |
DXASSERT_VALID(this); |
| 735 |
if(m_pHashTable!=NULL) { |
| 736 |
for(UINT nHash = 0;nHash < m_nHashTableSize;nHash++) { |
| 737 |
CAssoc *pAssoc; |
| 738 |
for(pAssoc = m_pHashTable[nHash]; pAssoc!=NULL; |
| 739 |
pAssoc = pAssoc->pNext) |
| 740 |
{ |
| 741 |
DXDestructElements(&pAssoc->value,1); |
| 742 |
DXDestructElements(&pAssoc->key,1); |
| 743 |
} |
| 744 |
} |
| 745 |
} |
| 746 |
delete[] m_pHashTable; |
| 747 |
m_pHashTable = NULL; |
| 748 |
m_nCount = 0; |
| 749 |
m_pFreeList = NULL; |
| 750 |
m_pBlocks->FreeDataChain(); |
| 751 |
m_pBlocks = NULL; |
| 752 |
} |
| 753 |
|
| 754 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 755 |
CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::~CDXMap() { |
| 756 |
RemoveAll(); |
| 757 |
_ASSERT(m_nCount==0); |
| 758 |
} |
| 759 |
|
| 760 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 761 |
typename CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CAssoc* |
| 762 |
CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::NewAssoc() { |
| 763 |
if(!m_pFreeList) { |
| 764 |
CDXPlex *newBlock = CDXPlex::Create(m_pBlocks,m_nBlockSize,sizeof(CDXMap::CAssoc)); |
| 765 |
CDXMap::CAssoc *pAssoc = (CDXMap::CAssoc*) newBlock->data(); |
| 766 |
pAssoc += m_nBlockSize - 1; |
| 767 |
for(int i = m_nBlockSize-1;i >= 0;i--,pAssoc--) { |
| 768 |
pAssoc->pNext = m_pFreeList; |
| 769 |
m_pFreeList = pAssoc; |
| 770 |
} |
| 771 |
} |
| 772 |
_ASSERT(m_pFreeList!=NULL); |
| 773 |
CDXMap::CAssoc *pAssoc = m_pFreeList; |
| 774 |
m_pFreeList = m_pFreeList->pNext; |
| 775 |
m_nCount++; |
| 776 |
_ASSERT(m_nCount > 0); |
| 777 |
DXConstructElements(&pAssoc->key,1); |
| 778 |
DXConstructElements(&pAssoc->value,1); |
| 779 |
return pAssoc; |
| 780 |
} |
| 781 |
|
| 782 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 783 |
void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::FreeAssoc(CAssoc *pAssoc) { |
| 784 |
DXDestructElements(&pAssoc->value,1); |
| 785 |
DXDestructElements(&pAssoc->key,1); |
| 786 |
pAssoc->pNext = m_pFreeList; |
| 787 |
m_pFreeList = pAssoc; |
| 788 |
m_nCount--; |
| 789 |
_ASSERT(m_nCount >= 0); |
| 790 |
} |
| 791 |
|
| 792 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 793 |
typename CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::CAssoc* |
| 794 |
CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetAssocAt(ARG_KEY key,UINT& nHash) const { |
| 795 |
nHash = DXHashKey(key) % m_nHashTableSize; |
| 796 |
if(!m_pHashTable) return NULL; |
| 797 |
CAssoc *pAssoc; |
| 798 |
for(pAssoc = m_pHashTable[nHash];pAssoc!=NULL;pAssoc = pAssoc->pNext) { |
| 799 |
if(DXCompareElements(&pAssoc->key,&key)) return pAssoc; |
| 800 |
} |
| 801 |
return NULL; |
| 802 |
} |
| 803 |
|
| 804 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 805 |
WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::Lookup(ARG_KEY key,VALUE& rValue) const { |
| 806 |
DXASSERT_VALID(this); |
| 807 |
UINT nHash; |
| 808 |
CAssoc *pAssoc = GetAssocAt(key,nHash); |
| 809 |
if(!pAssoc) return FALSE; |
| 810 |
rValue = pAssoc->value; |
| 811 |
return TRUE; |
| 812 |
} |
| 813 |
|
| 814 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 815 |
VALUE& CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::operator[](ARG_KEY key) { |
| 816 |
DXASSERT_VALID(this); |
| 817 |
UINT nHash; |
| 818 |
CAssoc *pAssoc; |
| 819 |
if(!(pAssoc = GetAssocAt(key,nHash))) { |
| 820 |
if(!m_pHashTable) InitHashTable(m_nHashTableSize); |
| 821 |
pAssoc = NewAssoc(); |
| 822 |
pAssoc->nHashValue = nHash; |
| 823 |
pAssoc->key = key; |
| 824 |
pAssoc->pNext = m_pHashTable[nHash]; |
| 825 |
m_pHashTable[nHash] = pAssoc; |
| 826 |
} |
| 827 |
return pAssoc->value; |
| 828 |
} |
| 829 |
|
| 830 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 831 |
WINBOOL CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::RemoveKey(ARG_KEY key) { |
| 832 |
DXASSERT_VALID(this); |
| 833 |
if(!m_pHashTable) return FALSE; |
| 834 |
CAssoc **ppAssocPrev; |
| 835 |
ppAssocPrev = &m_pHashTable[DXHashKey(key) % m_nHashTableSize]; |
| 836 |
CAssoc *pAssoc; |
| 837 |
for(pAssoc = *ppAssocPrev;pAssoc!=NULL;pAssoc = pAssoc->pNext) { |
| 838 |
if(DXCompareElements(&pAssoc->key,&key)) { |
| 839 |
*ppAssocPrev = pAssoc->pNext; |
| 840 |
FreeAssoc(pAssoc); |
| 841 |
return TRUE; |
| 842 |
} |
| 843 |
ppAssocPrev = &pAssoc->pNext; |
| 844 |
} |
| 845 |
return FALSE; |
| 846 |
} |
| 847 |
|
| 848 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 849 |
void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::GetNextAssoc(DXLISTPOS &rNextPosition,KEY& rKey,VALUE& rValue) const { |
| 850 |
DXASSERT_VALID(this); |
| 851 |
_ASSERT(m_pHashTable!=NULL); |
| 852 |
CAssoc *pAssocRet = (CAssoc*)rNextPosition; |
| 853 |
_ASSERT(pAssocRet!=NULL); |
| 854 |
if(pAssocRet==(CAssoc*) DX_BEFORE_START_POSITION) { |
| 855 |
for(UINT nBucket = 0;nBucket < m_nHashTableSize;nBucket++) |
| 856 |
if((pAssocRet = m_pHashTable[nBucket])!=NULL) |
| 857 |
break; |
| 858 |
_ASSERT(pAssocRet!=NULL); |
| 859 |
} |
| 860 |
_ASSERT(DXIsValidAddress(pAssocRet,sizeof(CAssoc),TRUE)); |
| 861 |
CAssoc *pAssocNext; |
| 862 |
if(!(pAssocNext = pAssocRet->pNext)) { |
| 863 |
for(UINT nBucket = pAssocRet->nHashValue + 1;nBucket < m_nHashTableSize;nBucket++) |
| 864 |
if((pAssocNext = m_pHashTable[nBucket])!=NULL) |
| 865 |
break; |
| 866 |
} |
| 867 |
rNextPosition = (DXLISTPOS) pAssocNext; |
| 868 |
rKey = pAssocRet->key; |
| 869 |
rValue = pAssocRet->value; |
| 870 |
} |
| 871 |
|
| 872 |
#ifdef _DEBUG |
| 873 |
template<class KEY,class ARG_KEY,class VALUE,class ARG_VALUE> |
| 874 |
void CDXMap<KEY,ARG_KEY,VALUE,ARG_VALUE>::AssertValid() const { |
| 875 |
_ASSERT(m_nHashTableSize > 0); |
| 876 |
_ASSERT((m_nCount==0 || m_pHashTable!=NULL)); |
| 877 |
} |
| 878 |
#endif |
| 879 |
|
| 880 |
#endif /* __cplusplus */ |
| 881 |
|
| 882 |
#endif |