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 883