Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1314 lines
39 KiB

  1. /*****************************************************************************
  2. * DXTmpl.h *
  3. *-----------*
  4. * This is the header file contains the DX collection class templates. It
  5. * has been derived from the MFC collection templates for compatibility.
  6. *-----------------------------------------------------------------------------
  7. * Created by: Ed Connell Date: 05/17/95
  8. *
  9. *****************************************************************************/
  10. #ifndef DXTmpl_h
  11. #define DXTmpl_h
  12. #ifndef _INC_LIMITS
  13. #include <limits.h>
  14. #endif
  15. #ifndef _INC_STRING
  16. #include <string.h>
  17. #endif
  18. #ifndef _INC_STDLIB
  19. #include <stdlib.h>
  20. #endif
  21. #ifndef _INC_SEARCH
  22. #include <search.h>
  23. #endif
  24. #define DXASSERT_VALID( pObj )
  25. /////////////////////////////////////////////////////////////////////////////
  26. typedef void* DXLISTPOS;
  27. typedef DWORD DXLISTHANDLE;
  28. #define DX_BEFORE_START_POSITION ((void*)-1L)
  29. inline BOOL DXIsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite)
  30. {
  31. // simple version using Win-32 APIs for pointer validation.
  32. return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
  33. (!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
  34. }
  35. /////////////////////////////////////////////////////////////////////////////
  36. // global helpers (can be overridden)
  37. template<class TYPE>
  38. inline void DXConstructElements(TYPE* pElements, int nCount)
  39. {
  40. _ASSERT( nCount == 0 ||
  41. DXIsValidAddress( pElements, nCount * sizeof(TYPE), TRUE ) );
  42. // default is bit-wise zero initialization
  43. memset((void*)pElements, 0, nCount * sizeof(TYPE));
  44. }
  45. template<class TYPE>
  46. inline void DXDestructElements(TYPE* pElements, int nCount)
  47. {
  48. _ASSERT( ( nCount == 0 ||
  49. DXIsValidAddress( pElements, nCount * sizeof(TYPE), TRUE ) ) );
  50. pElements; // not used
  51. nCount; // not used
  52. // default does nothing
  53. }
  54. template<class TYPE>
  55. inline void DXCopyElements(TYPE* pDest, const TYPE* pSrc, int nCount)
  56. {
  57. _ASSERT( ( nCount == 0 ||
  58. DXIsValidAddress( pDest, nCount * sizeof(TYPE), TRUE )) );
  59. _ASSERT( ( nCount == 0 ||
  60. DXIsValidAddress( pSrc, nCount * sizeof(TYPE), FALSE )) );
  61. // default is bit-wise copy
  62. memcpy(pDest, pSrc, nCount * sizeof(TYPE));
  63. }
  64. template<class TYPE, class ARG_TYPE>
  65. BOOL DXCompareElements(const TYPE* pElement1, const ARG_TYPE* pElement2)
  66. {
  67. _ASSERT( DXIsValidAddress( pElement1, sizeof(TYPE), FALSE ) );
  68. _ASSERT( DXIsValidAddress( pElement2, sizeof(ARG_TYPE), FALSE ) );
  69. return *pElement1 == *pElement2;
  70. }
  71. template<class ARG_KEY>
  72. inline UINT DXHashKey(ARG_KEY key)
  73. {
  74. // default identity hash - works for most primitive values
  75. return ((UINT)(void*)(DWORD)key) >> 4;
  76. }
  77. /////////////////////////////////////////////////////////////////////////////
  78. // CDXPlex
  79. struct CDXPlex // warning variable length structure
  80. {
  81. CDXPlex* pNext;
  82. UINT nMax;
  83. UINT nCur;
  84. /* BYTE data[maxNum*elementSize]; */
  85. void* data() { return this+1; }
  86. static CDXPlex* PASCAL Create( CDXPlex*& pHead, UINT nMax, UINT cbElement )
  87. {
  88. CDXPlex* p = (CDXPlex*) new BYTE[sizeof(CDXPlex) + nMax * cbElement];
  89. p->nMax = nMax;
  90. p->nCur = 0;
  91. p->pNext = pHead;
  92. pHead = p; // change head (adds in reverse order for simplicity)
  93. return p;
  94. }
  95. void FreeDataChain()
  96. {
  97. CDXPlex* p = this;
  98. while (p != NULL)
  99. {
  100. BYTE* bytes = (BYTE*) p;
  101. CDXPlex* pNext = p->pNext;
  102. delete bytes;
  103. p = pNext;
  104. }
  105. }
  106. };
  107. /////////////////////////////////////////////////////////////////////////////
  108. // CDXArray<TYPE, ARG_TYPE>
  109. template<class TYPE, class ARG_TYPE>
  110. class CDXArray
  111. {
  112. public:
  113. // Construction
  114. CDXArray();
  115. // Attributes
  116. int GetSize() const;
  117. int GetUpperBound() const;
  118. void SetSize(int nNewSize, int nGrowBy = -1);
  119. // Operations
  120. // Clean up
  121. void FreeExtra();
  122. void RemoveAll();
  123. // Accessing elements
  124. TYPE GetAt(int nIndex) const;
  125. void SetAt(int nIndex, ARG_TYPE newElement);
  126. TYPE& ElementAt(int nIndex);
  127. // Direct Access to the element data (may return NULL)
  128. const TYPE* GetData() const;
  129. TYPE* GetData();
  130. // Potentially growing the array
  131. void SetAtGrow(int nIndex, ARG_TYPE newElement);
  132. int Add(ARG_TYPE newElement);
  133. int Append(const CDXArray& src);
  134. void Copy(const CDXArray& src);
  135. // overloaded operator helpers
  136. TYPE operator[](int nIndex) const;
  137. TYPE& operator[](int nIndex);
  138. // Operations that move elements around
  139. void InsertAt(int nIndex, ARG_TYPE newElement, int nCount = 1);
  140. void RemoveAt(int nIndex, int nCount = 1);
  141. void InsertAt(int nStartIndex, CDXArray* pNewArray);
  142. void Sort(int (__cdecl *compare )(const void *elem1, const void *elem2 ));
  143. // Implementation
  144. protected:
  145. TYPE* m_pData; // the actual array of data
  146. int m_nSize; // # of elements (upperBound - 1)
  147. int m_nMaxSize; // max allocated
  148. int m_nGrowBy; // grow amount
  149. public:
  150. ~CDXArray();
  151. #ifdef _DEBUG
  152. // void Dump(CDumpContext&) const;
  153. void AssertValid() const;
  154. #endif
  155. };
  156. /////////////////////////////////////////////////////////////////////////////
  157. // CDXArray<TYPE, ARG_TYPE> inline functions
  158. template<class TYPE, class ARG_TYPE>
  159. inline int CDXArray<TYPE, ARG_TYPE>::GetSize() const
  160. { return m_nSize; }
  161. template<class TYPE, class ARG_TYPE>
  162. inline int CDXArray<TYPE, ARG_TYPE>::GetUpperBound() const
  163. { return m_nSize-1; }
  164. template<class TYPE, class ARG_TYPE>
  165. inline void CDXArray<TYPE, ARG_TYPE>::RemoveAll()
  166. { SetSize(0, -1); }
  167. template<class TYPE, class ARG_TYPE>
  168. inline TYPE CDXArray<TYPE, ARG_TYPE>::GetAt(int nIndex) const
  169. { _ASSERT( (nIndex >= 0 && nIndex < m_nSize) );
  170. return m_pData[nIndex]; }
  171. template<class TYPE, class ARG_TYPE>
  172. inline void CDXArray<TYPE, ARG_TYPE>::SetAt(int nIndex, ARG_TYPE newElement)
  173. { _ASSERT( (nIndex >= 0 && nIndex < m_nSize) );
  174. m_pData[nIndex] = newElement; }
  175. template<class TYPE, class ARG_TYPE>
  176. inline TYPE& CDXArray<TYPE, ARG_TYPE>::ElementAt(int nIndex)
  177. { _ASSERT( (nIndex >= 0 && nIndex < m_nSize) );
  178. return m_pData[nIndex]; }
  179. template<class TYPE, class ARG_TYPE>
  180. inline const TYPE* CDXArray<TYPE, ARG_TYPE>::GetData() const
  181. { return (const TYPE*)m_pData; }
  182. template<class TYPE, class ARG_TYPE>
  183. inline TYPE* CDXArray<TYPE, ARG_TYPE>::GetData()
  184. { return (TYPE*)m_pData; }
  185. template<class TYPE, class ARG_TYPE>
  186. inline int CDXArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
  187. { int nIndex = m_nSize;
  188. SetAtGrow(nIndex, newElement);
  189. return nIndex; }
  190. template<class TYPE, class ARG_TYPE>
  191. inline TYPE CDXArray<TYPE, ARG_TYPE>::operator[](int nIndex) const
  192. { return GetAt(nIndex); }
  193. template<class TYPE, class ARG_TYPE>
  194. inline TYPE& CDXArray<TYPE, ARG_TYPE>::operator[](int nIndex)
  195. { return ElementAt(nIndex); }
  196. /////////////////////////////////////////////////////////////////////////////
  197. // CDXArray<TYPE, ARG_TYPE> out-of-line functions
  198. template<class TYPE, class ARG_TYPE>
  199. CDXArray<TYPE, ARG_TYPE>::CDXArray()
  200. {
  201. m_pData = NULL;
  202. m_nSize = m_nMaxSize = m_nGrowBy = 0;
  203. }
  204. template<class TYPE, class ARG_TYPE>
  205. CDXArray<TYPE, ARG_TYPE>::~CDXArray()
  206. {
  207. DXASSERT_VALID( this );
  208. if (m_pData != NULL)
  209. {
  210. DXDestructElements(m_pData, m_nSize);
  211. delete[] (BYTE*)m_pData;
  212. }
  213. }
  214. template<class TYPE, class ARG_TYPE>
  215. void CDXArray<TYPE, ARG_TYPE>::SetSize(int nNewSize, int nGrowBy)
  216. {
  217. DXASSERT_VALID( this );
  218. _ASSERT( nNewSize >= 0 );
  219. if (nGrowBy != -1)
  220. m_nGrowBy = nGrowBy; // set new size
  221. if (nNewSize == 0)
  222. {
  223. // shrink to nothing
  224. if (m_pData != NULL)
  225. {
  226. DXDestructElements(m_pData, m_nSize);
  227. delete[] (BYTE*)m_pData;
  228. m_pData = NULL;
  229. }
  230. m_nSize = m_nMaxSize = 0;
  231. }
  232. else if (m_pData == NULL)
  233. {
  234. // create one with exact size
  235. #ifdef SIZE_T_MAX
  236. _ASSERT( nNewSize <= SIZE_T_MAX/sizeof(TYPE) ); // no overflow
  237. #endif
  238. m_pData = (TYPE*) new BYTE[nNewSize * sizeof(TYPE)];
  239. DXConstructElements(m_pData, nNewSize);
  240. m_nSize = m_nMaxSize = nNewSize;
  241. }
  242. else if (nNewSize <= m_nMaxSize)
  243. {
  244. // it fits
  245. if (nNewSize > m_nSize)
  246. {
  247. // initialize the new elements
  248. DXConstructElements(&m_pData[m_nSize], nNewSize-m_nSize);
  249. }
  250. else if (m_nSize > nNewSize)
  251. {
  252. // destroy the old elements
  253. DXDestructElements(&m_pData[nNewSize], m_nSize-nNewSize);
  254. }
  255. m_nSize = nNewSize;
  256. }
  257. else
  258. {
  259. // otherwise, grow array
  260. int nGrowBy = m_nGrowBy;
  261. if (nGrowBy == 0)
  262. {
  263. // heuristically determe growth when nGrowBy == 0
  264. // (this avoids heap fragmentation in many situations)
  265. nGrowBy = min(1024, max(4, m_nSize / 8));
  266. }
  267. int nNewMax;
  268. if (nNewSize < m_nMaxSize + nGrowBy)
  269. nNewMax = m_nMaxSize + nGrowBy; // granularity
  270. else
  271. nNewMax = nNewSize; // no slush
  272. _ASSERT( nNewMax >= m_nMaxSize ); // no wrap around
  273. #ifdef SIZE_T_MAX
  274. _ASSERT( nNewMax <= SIZE_T_MAX/sizeof(TYPE) ); // no overflow
  275. #endif
  276. TYPE* pNewData = (TYPE*) new BYTE[nNewMax * sizeof(TYPE)];
  277. // copy new data from old
  278. memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
  279. // construct remaining elements
  280. _ASSERT( nNewSize > m_nSize );
  281. DXConstructElements(&pNewData[m_nSize], nNewSize-m_nSize);
  282. // get rid of old stuff (note: no destructors called)
  283. delete[] (BYTE*)m_pData;
  284. m_pData = pNewData;
  285. m_nSize = nNewSize;
  286. m_nMaxSize = nNewMax;
  287. }
  288. }
  289. template<class TYPE, class ARG_TYPE>
  290. int CDXArray<TYPE, ARG_TYPE>::Append(const CDXArray& src)
  291. {
  292. DXASSERT_VALID( this );
  293. _ASSERT( this != &src ); // cannot append to itself
  294. int nOldSize = m_nSize;
  295. SetSize(m_nSize + src.m_nSize);
  296. DXCopyElements(m_pData + nOldSize, src.m_pData, src.m_nSize);
  297. return nOldSize;
  298. }
  299. template<class TYPE, class ARG_TYPE>
  300. void CDXArray<TYPE, ARG_TYPE>::Copy(const CDXArray& src)
  301. {
  302. DXASSERT_VALID( this );
  303. _ASSERT( this != &src ); // cannot copy to itself
  304. SetSize(src.m_nSize);
  305. DXCopyElements(m_pData, src.m_pData, src.m_nSize);
  306. }
  307. template<class TYPE, class ARG_TYPE>
  308. void CDXArray<TYPE, ARG_TYPE>::FreeExtra()
  309. {
  310. DXASSERT_VALID( this );
  311. if (m_nSize != m_nMaxSize)
  312. {
  313. // shrink to desired size
  314. #ifdef SIZE_T_MAX
  315. _ASSERT( m_nSize <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
  316. #endif
  317. TYPE* pNewData = NULL;
  318. if (m_nSize != 0)
  319. {
  320. pNewData = (TYPE*) new BYTE[m_nSize * sizeof(TYPE)];
  321. // copy new data from old
  322. memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
  323. }
  324. // get rid of old stuff (note: no destructors called)
  325. delete[] (BYTE*)m_pData;
  326. m_pData = pNewData;
  327. m_nMaxSize = m_nSize;
  328. }
  329. }
  330. template<class TYPE, class ARG_TYPE>
  331. void CDXArray<TYPE, ARG_TYPE>::SetAtGrow(int nIndex, ARG_TYPE newElement)
  332. {
  333. DXASSERT_VALID( this );
  334. _ASSERT( nIndex >= 0 );
  335. if (nIndex >= m_nSize)
  336. SetSize(nIndex+1, -1);
  337. m_pData[nIndex] = newElement;
  338. }
  339. template<class TYPE, class ARG_TYPE>
  340. void CDXArray<TYPE, ARG_TYPE>::InsertAt(int nIndex, ARG_TYPE newElement, int nCount /*=1*/)
  341. {
  342. DXASSERT_VALID( this );
  343. _ASSERT( nIndex >= 0 ); // will expand to meet need
  344. _ASSERT( nCount > 0 ); // zero or negative size not allowed
  345. if (nIndex >= m_nSize)
  346. {
  347. // adding after the end of the array
  348. SetSize(nIndex + nCount, -1); // grow so nIndex is valid
  349. }
  350. else
  351. {
  352. // inserting in the middle of the array
  353. int nOldSize = m_nSize;
  354. SetSize(m_nSize + nCount, -1); // grow it to new size
  355. // shift old data up to fill gap
  356. memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
  357. (nOldSize-nIndex) * sizeof(TYPE));
  358. // re-init slots we copied from
  359. DXConstructElements(&m_pData[nIndex], nCount);
  360. }
  361. // insert new value in the gap
  362. _ASSERT( nIndex + nCount <= m_nSize );
  363. while (nCount--)
  364. m_pData[nIndex++] = newElement;
  365. }
  366. template<class TYPE, class ARG_TYPE>
  367. void CDXArray<TYPE, ARG_TYPE>::RemoveAt(int nIndex, int nCount)
  368. {
  369. DXASSERT_VALID( this );
  370. _ASSERT( nIndex >= 0 );
  371. _ASSERT( nCount >= 0 );
  372. _ASSERT( nIndex + nCount <= m_nSize );
  373. // just remove a range
  374. int nMoveCount = m_nSize - (nIndex + nCount);
  375. DXDestructElements(&m_pData[nIndex], nCount);
  376. if (nMoveCount)
  377. memcpy(&m_pData[nIndex], &m_pData[nIndex + nCount],
  378. nMoveCount * sizeof(TYPE));
  379. m_nSize -= nCount;
  380. }
  381. template<class TYPE, class ARG_TYPE>
  382. void CDXArray<TYPE, ARG_TYPE>::InsertAt(int nStartIndex, CDXArray* pNewArray)
  383. {
  384. DXASSERT_VALID( this );
  385. DXASSERT_VALID( pNewArray );
  386. _ASSERT( nStartIndex >= 0 );
  387. if (pNewArray->GetSize() > 0)
  388. {
  389. InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
  390. for (int i = 0; i < pNewArray->GetSize(); i++)
  391. SetAt(nStartIndex + i, pNewArray->GetAt(i));
  392. }
  393. }
  394. template<class TYPE, class ARG_TYPE>
  395. void CDXArray<TYPE, ARG_TYPE>::Sort(int (__cdecl *compare )(const void *elem1, const void *elem2 ))
  396. {
  397. DXASSERT_VALID( this );
  398. _ASSERT( m_pData != NULL );
  399. qsort( m_pData, m_nSize, sizeof(TYPE), compare );
  400. }
  401. #ifdef _DEBUG
  402. template<class TYPE, class ARG_TYPE>
  403. void CDXArray<TYPE, ARG_TYPE>::AssertValid() const
  404. {
  405. if (m_pData == NULL)
  406. {
  407. _ASSERT( m_nSize == 0 );
  408. _ASSERT( m_nMaxSize == 0 );
  409. }
  410. else
  411. {
  412. _ASSERT( m_nSize >= 0 );
  413. _ASSERT( m_nMaxSize >= 0 );
  414. _ASSERT( m_nSize <= m_nMaxSize );
  415. _ASSERT( DXIsValidAddress(m_pData, m_nMaxSize * sizeof(TYPE), TRUE ) );
  416. }
  417. }
  418. #endif //_DEBUG
  419. /////////////////////////////////////////////////////////////////////////////
  420. // CDXList<TYPE, ARG_TYPE>
  421. template<class TYPE, class ARG_TYPE>
  422. class CDXList
  423. {
  424. protected:
  425. struct CNode
  426. {
  427. CNode* pNext;
  428. CNode* pPrev;
  429. TYPE data;
  430. };
  431. public:
  432. // Construction
  433. CDXList(int nBlockSize = 10);
  434. // Attributes (head and tail)
  435. // count of elements
  436. int GetCount() const;
  437. BOOL IsEmpty() const;
  438. // peek at head or tail
  439. TYPE& GetHead();
  440. TYPE GetHead() const;
  441. TYPE& GetTail();
  442. TYPE GetTail() const;
  443. // Operations
  444. // get head or tail (and remove it) - don't call on empty list !
  445. TYPE RemoveHead();
  446. TYPE RemoveTail();
  447. // add before head or after tail
  448. DXLISTPOS AddHead(ARG_TYPE newElement);
  449. DXLISTPOS AddTail(ARG_TYPE newElement);
  450. // add another list of elements before head or after tail
  451. void AddHead(CDXList* pNewList);
  452. void AddTail(CDXList* pNewList);
  453. // remove all elements
  454. void RemoveAll();
  455. // iteration
  456. DXLISTPOS GetHeadPosition() const;
  457. DXLISTPOS GetTailPosition() const;
  458. TYPE& GetNext(DXLISTPOS& rPosition); // return *Position++
  459. TYPE GetNext(DXLISTPOS& rPosition) const; // return *Position++
  460. TYPE& GetPrev(DXLISTPOS& rPosition); // return *Position--
  461. TYPE GetPrev(DXLISTPOS& rPosition) const; // return *Position--
  462. // getting/modifying an element at a given position
  463. TYPE& GetAt(DXLISTPOS position);
  464. TYPE GetAt(DXLISTPOS position) const;
  465. void SetAt(DXLISTPOS pos, ARG_TYPE newElement);
  466. void RemoveAt(DXLISTPOS position);
  467. // inserting before or after a given position
  468. DXLISTPOS InsertBefore(DXLISTPOS position, ARG_TYPE newElement);
  469. DXLISTPOS InsertAfter(DXLISTPOS position, ARG_TYPE newElement);
  470. // helper functions (note: O(n) speed)
  471. DXLISTPOS Find(ARG_TYPE searchValue, DXLISTPOS startAfter = NULL) const;
  472. // defaults to starting at the HEAD, return NULL if not found
  473. DXLISTPOS FindIndex(int nIndex) const;
  474. // get the 'nIndex'th element (may return NULL)
  475. // Implementation
  476. protected:
  477. CNode* m_pNodeHead;
  478. CNode* m_pNodeTail;
  479. int m_nCount;
  480. CNode* m_pNodeFree;
  481. struct CDXPlex* m_pBlocks;
  482. int m_nBlockSize;
  483. CNode* NewNode(CNode*, CNode*);
  484. void FreeNode(CNode*);
  485. public:
  486. ~CDXList();
  487. #ifdef _DEBUG
  488. void AssertValid() const;
  489. #endif
  490. };
  491. /////////////////////////////////////////////////////////////////////////////
  492. // CDXList<TYPE, ARG_TYPE> inline functions
  493. template<class TYPE, class ARG_TYPE>
  494. inline int CDXList<TYPE, ARG_TYPE>::GetCount() const
  495. { return m_nCount; }
  496. template<class TYPE, class ARG_TYPE>
  497. inline BOOL CDXList<TYPE, ARG_TYPE>::IsEmpty() const
  498. { return m_nCount == 0; }
  499. template<class TYPE, class ARG_TYPE>
  500. inline TYPE& CDXList<TYPE, ARG_TYPE>::GetHead()
  501. { _ASSERT( m_pNodeHead != NULL );
  502. return m_pNodeHead->data; }
  503. template<class TYPE, class ARG_TYPE>
  504. inline TYPE CDXList<TYPE, ARG_TYPE>::GetHead() const
  505. { _ASSERT( m_pNodeHead != NULL );
  506. return m_pNodeHead->data; }
  507. template<class TYPE, class ARG_TYPE>
  508. inline TYPE& CDXList<TYPE, ARG_TYPE>::GetTail()
  509. { _ASSERT( m_pNodeTail != NULL );
  510. return m_pNodeTail->data; }
  511. template<class TYPE, class ARG_TYPE>
  512. inline TYPE CDXList<TYPE, ARG_TYPE>::GetTail() const
  513. { _ASSERT( m_pNodeTail != NULL );
  514. return m_pNodeTail->data; }
  515. template<class TYPE, class ARG_TYPE>
  516. inline DXLISTPOS CDXList<TYPE, ARG_TYPE>::GetHeadPosition() const
  517. { return (DXLISTPOS) m_pNodeHead; }
  518. template<class TYPE, class ARG_TYPE>
  519. inline DXLISTPOS CDXList<TYPE, ARG_TYPE>::GetTailPosition() const
  520. { return (DXLISTPOS) m_pNodeTail; }
  521. template<class TYPE, class ARG_TYPE>
  522. inline TYPE& CDXList<TYPE, ARG_TYPE>::GetNext(DXLISTPOS& rPosition) // return *Position++
  523. { CNode* pNode = (CNode*) rPosition;
  524. _ASSERT( DXIsValidAddress(pNode, sizeof(CNode), TRUE ) );
  525. rPosition = (DXLISTPOS) pNode->pNext;
  526. return pNode->data; }
  527. template<class TYPE, class ARG_TYPE>
  528. inline TYPE CDXList<TYPE, ARG_TYPE>::GetNext(DXLISTPOS& rPosition) const // return *Position++
  529. { CNode* pNode = (CNode*) rPosition;
  530. _ASSERT( DXIsValidAddress(pNode, sizeof(CNode), TRUE ) );
  531. rPosition = (DXLISTPOS) pNode->pNext;
  532. return pNode->data; }
  533. template<class TYPE, class ARG_TYPE>
  534. inline TYPE& CDXList<TYPE, ARG_TYPE>::GetPrev(DXLISTPOS& rPosition) // return *Position--
  535. { CNode* pNode = (CNode*) rPosition;
  536. _ASSERT( DXIsValidAddress(pNode, sizeof(CNode), TRUE ) );
  537. rPosition = (DXLISTPOS) pNode->pPrev;
  538. return pNode->data; }
  539. template<class TYPE, class ARG_TYPE>
  540. inline TYPE CDXList<TYPE, ARG_TYPE>::GetPrev(DXLISTPOS& rPosition) const // return *Position--
  541. { CNode* pNode = (CNode*) rPosition;
  542. _ASSERT( DXIsValidAddress(pNode, sizeof(CNode), TRUE ) );
  543. rPosition = (DXLISTPOS) pNode->pPrev;
  544. return pNode->data; }
  545. template<class TYPE, class ARG_TYPE>
  546. inline TYPE& CDXList<TYPE, ARG_TYPE>::GetAt(DXLISTPOS position)
  547. { CNode* pNode = (CNode*) position;
  548. _ASSERT( DXIsValidAddress(pNode, sizeof(CNode), TRUE ) );
  549. return pNode->data; }
  550. template<class TYPE, class ARG_TYPE>
  551. inline TYPE CDXList<TYPE, ARG_TYPE>::GetAt(DXLISTPOS position) const
  552. { CNode* pNode = (CNode*) position;
  553. _ASSERT( DXIsValidAddress(pNode, sizeof(CNode), TRUE ) );
  554. return pNode->data; }
  555. template<class TYPE, class ARG_TYPE>
  556. inline void CDXList<TYPE, ARG_TYPE>::SetAt(DXLISTPOS pos, ARG_TYPE newElement)
  557. { CNode* pNode = (CNode*) pos;
  558. _ASSERT( DXIsValidAddress(pNode, sizeof(CNode), TRUE ) );
  559. pNode->data = newElement; }
  560. /////////////////////////////////////////////////////////////////////////////
  561. // CDXList<TYPE, ARG_TYPE> out-of-line functions
  562. template<class TYPE, class ARG_TYPE>
  563. CDXList<TYPE, ARG_TYPE>::CDXList( int nBlockSize )
  564. {
  565. _ASSERT( nBlockSize > 0 );
  566. m_nCount = 0;
  567. m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  568. m_pBlocks = NULL;
  569. m_nBlockSize = nBlockSize;
  570. }
  571. template<class TYPE, class ARG_TYPE>
  572. void CDXList<TYPE, ARG_TYPE>::RemoveAll()
  573. {
  574. DXASSERT_VALID( this );
  575. // destroy elements
  576. CNode* pNode;
  577. for (pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
  578. DXDestructElements(&pNode->data, 1);
  579. m_nCount = 0;
  580. m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  581. m_pBlocks->FreeDataChain();
  582. m_pBlocks = NULL;
  583. }
  584. template<class TYPE, class ARG_TYPE>
  585. CDXList<TYPE, ARG_TYPE>::~CDXList()
  586. {
  587. RemoveAll();
  588. _ASSERT( m_nCount == 0 );
  589. }
  590. /////////////////////////////////////////////////////////////////////////////
  591. // Node helpers
  592. //
  593. // Implementation note: CNode's are stored in CDXPlex blocks and
  594. // chained together. Free blocks are maintained in a singly linked list
  595. // using the 'pNext' member of CNode with 'm_pNodeFree' as the head.
  596. // Used blocks are maintained in a doubly linked list using both 'pNext'
  597. // and 'pPrev' as links and 'm_pNodeHead' and 'm_pNodeTail'
  598. // as the head/tail.
  599. //
  600. // We never free a CDXPlex block unless the List is destroyed or RemoveAll()
  601. // is used - so the total number of CDXPlex blocks may grow large depending
  602. // on the maximum past size of the list.
  603. //
  604. template<class TYPE, class ARG_TYPE>
  605. typename CDXList<TYPE, ARG_TYPE>::CNode*
  606. CDXList<TYPE, ARG_TYPE>::NewNode(CNode* pPrev, CNode* pNext)
  607. {
  608. if (m_pNodeFree == NULL)
  609. {
  610. // add another block
  611. CDXPlex* pNewBlock = CDXPlex::Create(m_pBlocks, m_nBlockSize,
  612. sizeof(CNode));
  613. // chain them into free list
  614. CNode* pNode = (CNode*) pNewBlock->data();
  615. // free in reverse order to make it easier to debug
  616. pNode += m_nBlockSize - 1;
  617. for (int i = m_nBlockSize-1; i >= 0; i--, pNode--)
  618. {
  619. pNode->pNext = m_pNodeFree;
  620. m_pNodeFree = pNode;
  621. }
  622. }
  623. _ASSERT( m_pNodeFree != NULL ); // we must have something
  624. CDXList::CNode* pNode = m_pNodeFree;
  625. m_pNodeFree = m_pNodeFree->pNext;
  626. pNode->pPrev = pPrev;
  627. pNode->pNext = pNext;
  628. m_nCount++;
  629. _ASSERT( m_nCount > 0 ); // make sure we don't overflow
  630. DXConstructElements(&pNode->data, 1);
  631. return pNode;
  632. }
  633. template<class TYPE, class ARG_TYPE>
  634. void CDXList<TYPE, ARG_TYPE>::FreeNode(CNode* pNode)
  635. {
  636. DXDestructElements(&pNode->data, 1);
  637. pNode->pNext = m_pNodeFree;
  638. m_pNodeFree = pNode;
  639. m_nCount--;
  640. _ASSERT( m_nCount >= 0 ); // make sure we don't underflow
  641. }
  642. template<class TYPE, class ARG_TYPE>
  643. DXLISTPOS CDXList<TYPE, ARG_TYPE>::AddHead(ARG_TYPE newElement)
  644. {
  645. DXASSERT_VALID( this );
  646. CNode* pNewNode = NewNode(NULL, m_pNodeHead);
  647. pNewNode->data = newElement;
  648. if (m_pNodeHead != NULL)
  649. m_pNodeHead->pPrev = pNewNode;
  650. else
  651. m_pNodeTail = pNewNode;
  652. m_pNodeHead = pNewNode;
  653. return (DXLISTPOS) pNewNode;
  654. }
  655. template<class TYPE, class ARG_TYPE>
  656. DXLISTPOS CDXList<TYPE, ARG_TYPE>::AddTail(ARG_TYPE newElement)
  657. {
  658. DXASSERT_VALID( this );
  659. CNode* pNewNode = NewNode(m_pNodeTail, NULL);
  660. pNewNode->data = newElement;
  661. if (m_pNodeTail != NULL)
  662. m_pNodeTail->pNext = pNewNode;
  663. else
  664. m_pNodeHead = pNewNode;
  665. m_pNodeTail = pNewNode;
  666. return (DXLISTPOS) pNewNode;
  667. }
  668. template<class TYPE, class ARG_TYPE>
  669. void CDXList<TYPE, ARG_TYPE>::AddHead(CDXList* pNewList)
  670. {
  671. DXASSERT_VALID( this );
  672. DXASSERT_VALID( pNewList );
  673. // add a list of same elements to head (maintain order)
  674. DXLISTPOS pos = pNewList->GetTailPosition();
  675. while (pos != NULL)
  676. AddHead(pNewList->GetPrev(pos));
  677. }
  678. template<class TYPE, class ARG_TYPE>
  679. void CDXList<TYPE, ARG_TYPE>::AddTail(CDXList* pNewList)
  680. {
  681. DXASSERT_VALID( this );
  682. DXASSERT_VALID( pNewList );
  683. // add a list of same elements
  684. DXLISTPOS pos = pNewList->GetHeadPosition();
  685. while (pos != NULL)
  686. AddTail(pNewList->GetNext(pos));
  687. }
  688. template<class TYPE, class ARG_TYPE>
  689. TYPE CDXList<TYPE, ARG_TYPE>::RemoveHead()
  690. {
  691. DXASSERT_VALID( this );
  692. _ASSERT( m_pNodeHead != NULL ); // don't call on empty list !!!
  693. _ASSERT( DXIsValidAddress(m_pNodeHead, sizeof(CNode), TRUE ) );
  694. CNode* pOldNode = m_pNodeHead;
  695. TYPE returnValue = pOldNode->data;
  696. m_pNodeHead = pOldNode->pNext;
  697. if (m_pNodeHead != NULL)
  698. m_pNodeHead->pPrev = NULL;
  699. else
  700. m_pNodeTail = NULL;
  701. FreeNode(pOldNode);
  702. return returnValue;
  703. }
  704. template<class TYPE, class ARG_TYPE>
  705. TYPE CDXList<TYPE, ARG_TYPE>::RemoveTail()
  706. {
  707. DXASSERT_VALID( this );
  708. _ASSERT( m_pNodeTail != NULL ); // don't call on empty list !!!
  709. _ASSERT( DXIsValidAddress(m_pNodeTail, sizeof(CNode), TRUE ) );
  710. CNode* pOldNode = m_pNodeTail;
  711. TYPE returnValue = pOldNode->data;
  712. m_pNodeTail = pOldNode->pPrev;
  713. if (m_pNodeTail != NULL)
  714. m_pNodeTail->pNext = NULL;
  715. else
  716. m_pNodeHead = NULL;
  717. FreeNode(pOldNode);
  718. return returnValue;
  719. }
  720. template<class TYPE, class ARG_TYPE>
  721. DXLISTPOS CDXList<TYPE, ARG_TYPE>::InsertBefore(DXLISTPOS position, ARG_TYPE newElement)
  722. {
  723. DXASSERT_VALID( this );
  724. if (position == NULL)
  725. return AddHead(newElement); // insert before nothing -> head of the list
  726. // Insert it before position
  727. CNode* pOldNode = (CNode*) position;
  728. CNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode);
  729. pNewNode->data = newElement;
  730. if (pOldNode->pPrev != NULL)
  731. {
  732. _ASSERT( DXIsValidAddress(pOldNode->pPrev, sizeof(CNode), TRUE ) );
  733. pOldNode->pPrev->pNext = pNewNode;
  734. }
  735. else
  736. {
  737. _ASSERT( pOldNode == m_pNodeHead );
  738. m_pNodeHead = pNewNode;
  739. }
  740. pOldNode->pPrev = pNewNode;
  741. return (DXLISTPOS) pNewNode;
  742. }
  743. template<class TYPE, class ARG_TYPE>
  744. DXLISTPOS CDXList<TYPE, ARG_TYPE>::InsertAfter(DXLISTPOS position, ARG_TYPE newElement)
  745. {
  746. DXASSERT_VALID( this );
  747. if (position == NULL)
  748. return AddTail(newElement); // insert after nothing -> tail of the list
  749. // Insert it before position
  750. CNode* pOldNode = (CNode*) position;
  751. _ASSERT( DXIsValidAddress(pOldNode, sizeof(CNode), TRUE ));
  752. CNode* pNewNode = NewNode(pOldNode, pOldNode->pNext);
  753. pNewNode->data = newElement;
  754. if (pOldNode->pNext != NULL)
  755. {
  756. _ASSERT( DXIsValidAddress(pOldNode->pNext, sizeof(CNode), TRUE ));
  757. pOldNode->pNext->pPrev = pNewNode;
  758. }
  759. else
  760. {
  761. _ASSERT( pOldNode == m_pNodeTail );
  762. m_pNodeTail = pNewNode;
  763. }
  764. pOldNode->pNext = pNewNode;
  765. return (DXLISTPOS) pNewNode;
  766. }
  767. template<class TYPE, class ARG_TYPE>
  768. void CDXList<TYPE, ARG_TYPE>::RemoveAt(DXLISTPOS position)
  769. {
  770. DXASSERT_VALID( this );
  771. CNode* pOldNode = (CNode*) position;
  772. _ASSERT( DXIsValidAddress(pOldNode, sizeof(CNode), TRUE ) );
  773. // remove pOldNode from list
  774. if (pOldNode == m_pNodeHead)
  775. {
  776. m_pNodeHead = pOldNode->pNext;
  777. }
  778. else
  779. {
  780. _ASSERT( DXIsValidAddress(pOldNode->pPrev, sizeof(CNode), TRUE ) );
  781. pOldNode->pPrev->pNext = pOldNode->pNext;
  782. }
  783. if (pOldNode == m_pNodeTail)
  784. {
  785. m_pNodeTail = pOldNode->pPrev;
  786. }
  787. else
  788. {
  789. _ASSERT( DXIsValidAddress(pOldNode->pNext, sizeof(CNode), TRUE ) );
  790. pOldNode->pNext->pPrev = pOldNode->pPrev;
  791. }
  792. FreeNode(pOldNode);
  793. }
  794. template<class TYPE, class ARG_TYPE>
  795. DXLISTPOS CDXList<TYPE, ARG_TYPE>::FindIndex(int nIndex) const
  796. {
  797. DXASSERT_VALID( this );
  798. _ASSERT( nIndex >= 0 );
  799. if (nIndex >= m_nCount)
  800. return NULL; // went too far
  801. CNode* pNode = m_pNodeHead;
  802. while (nIndex--)
  803. {
  804. _ASSERT( DXIsValidAddress(pNode, sizeof(CNode), TRUE ));
  805. pNode = pNode->pNext;
  806. }
  807. return (DXLISTPOS) pNode;
  808. }
  809. template<class TYPE, class ARG_TYPE>
  810. DXLISTPOS CDXList<TYPE, ARG_TYPE>::Find(ARG_TYPE searchValue, DXLISTPOS startAfter) const
  811. {
  812. DXASSERT_VALID( this );
  813. CNode* pNode = (CNode*) startAfter;
  814. if (pNode == NULL)
  815. {
  816. pNode = m_pNodeHead; // start at head
  817. }
  818. else
  819. {
  820. _ASSERT( DXIsValidAddress(pNode, sizeof(CNode), TRUE ) );
  821. pNode = pNode->pNext; // start after the one specified
  822. }
  823. for (; pNode != NULL; pNode = pNode->pNext)
  824. if (DXCompareElements(&pNode->data, &searchValue))
  825. return (DXLISTPOS)pNode;
  826. return NULL;
  827. }
  828. #ifdef _DEBUG
  829. template<class TYPE, class ARG_TYPE>
  830. void CDXList<TYPE, ARG_TYPE>::AssertValid() const
  831. {
  832. if (m_nCount == 0)
  833. {
  834. // empty list
  835. _ASSERT( m_pNodeHead == NULL );
  836. _ASSERT( m_pNodeTail == NULL );
  837. }
  838. else
  839. {
  840. // non-empty list
  841. _ASSERT( DXIsValidAddress(m_pNodeHead, sizeof(CNode), TRUE ));
  842. _ASSERT( DXIsValidAddress(m_pNodeTail, sizeof(CNode), TRUE ));
  843. }
  844. }
  845. #endif //_DEBUG
  846. /////////////////////////////////////////////////////////////////////////////
  847. // CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>
  848. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  849. class CDXMap
  850. {
  851. protected:
  852. // Association
  853. struct CAssoc
  854. {
  855. CAssoc* pNext;
  856. UINT nHashValue; // needed for efficient iteration
  857. KEY key;
  858. VALUE value;
  859. };
  860. public:
  861. // Construction
  862. CDXMap( int nBlockSize = 10 );
  863. // Attributes
  864. // number of elements
  865. int GetCount() const;
  866. BOOL IsEmpty() const;
  867. // Lookup
  868. BOOL Lookup(ARG_KEY key, VALUE& rValue) const;
  869. // Operations
  870. // Lookup and add if not there
  871. VALUE& operator[](ARG_KEY key);
  872. // add a new (key, value) pair
  873. void SetAt(ARG_KEY key, ARG_VALUE newValue);
  874. // removing existing (key, ?) pair
  875. BOOL RemoveKey(ARG_KEY key);
  876. void RemoveAll();
  877. // iterating all (key, value) pairs
  878. DXLISTPOS GetStartPosition() const;
  879. void GetNextAssoc(DXLISTPOS& rNextPosition, KEY& rKey, VALUE& rValue) const;
  880. // advanced features for derived classes
  881. UINT GetHashTableSize() const;
  882. void InitHashTable(UINT hashSize, BOOL bAllocNow = TRUE);
  883. // Implementation
  884. protected:
  885. CAssoc** m_pHashTable;
  886. UINT m_nHashTableSize;
  887. int m_nCount;
  888. CAssoc* m_pFreeList;
  889. struct CDXPlex* m_pBlocks;
  890. int m_nBlockSize;
  891. CAssoc* NewAssoc();
  892. void FreeAssoc(CAssoc*);
  893. CAssoc* GetAssocAt(ARG_KEY, UINT&) const;
  894. public:
  895. ~CDXMap();
  896. #ifdef _DEBUG
  897. // void Dump(CDumpContext&) const;
  898. void AssertValid() const;
  899. #endif
  900. };
  901. /////////////////////////////////////////////////////////////////////////////
  902. // CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE> inline functions
  903. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  904. inline int CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetCount() const
  905. { return m_nCount; }
  906. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  907. inline BOOL CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::IsEmpty() const
  908. { return m_nCount == 0; }
  909. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  910. inline void CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::SetAt(ARG_KEY key, ARG_VALUE newValue)
  911. { (*this)[key] = newValue; }
  912. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  913. inline DXLISTPOS CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetStartPosition() const
  914. { return (m_nCount == 0) ? NULL : DX_BEFORE_START_POSITION; }
  915. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  916. inline UINT CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetHashTableSize() const
  917. { return m_nHashTableSize; }
  918. /////////////////////////////////////////////////////////////////////////////
  919. // CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE> out-of-line functions
  920. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  921. CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CDXMap( int nBlockSize )
  922. {
  923. _ASSERT( nBlockSize > 0 );
  924. m_pHashTable = NULL;
  925. m_nHashTableSize = 17; // default size
  926. m_nCount = 0;
  927. m_pFreeList = NULL;
  928. m_pBlocks = NULL;
  929. m_nBlockSize = nBlockSize;
  930. }
  931. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  932. void CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::InitHashTable(
  933. UINT nHashSize, BOOL bAllocNow)
  934. //
  935. // Used to force allocation of a hash table or to override the default
  936. // hash table size of (which is fairly small)
  937. {
  938. DXASSERT_VALID( this );
  939. _ASSERT( m_nCount == 0 );
  940. _ASSERT( nHashSize > 0 );
  941. if (m_pHashTable != NULL)
  942. {
  943. // free hash table
  944. delete[] m_pHashTable;
  945. m_pHashTable = NULL;
  946. }
  947. if (bAllocNow)
  948. {
  949. m_pHashTable = new CAssoc* [nHashSize];
  950. memset(m_pHashTable, 0, sizeof(CAssoc*) * nHashSize);
  951. }
  952. m_nHashTableSize = nHashSize;
  953. }
  954. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  955. void CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveAll()
  956. {
  957. DXASSERT_VALID( this );
  958. if (m_pHashTable != NULL)
  959. {
  960. // destroy elements (values and keys)
  961. for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
  962. {
  963. CAssoc* pAssoc;
  964. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
  965. pAssoc = pAssoc->pNext)
  966. {
  967. DXDestructElements(&pAssoc->value, 1);
  968. DXDestructElements(&pAssoc->key, 1);
  969. }
  970. }
  971. }
  972. // free hash table
  973. delete[] m_pHashTable;
  974. m_pHashTable = NULL;
  975. m_nCount = 0;
  976. m_pFreeList = NULL;
  977. m_pBlocks->FreeDataChain();
  978. m_pBlocks = NULL;
  979. }
  980. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  981. CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::~CDXMap()
  982. {
  983. RemoveAll();
  984. _ASSERT( m_nCount == 0 );
  985. }
  986. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  987. typename CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
  988. CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::NewAssoc()
  989. {
  990. if (m_pFreeList == NULL)
  991. {
  992. // add another block
  993. CDXPlex* newBlock = CDXPlex::Create(m_pBlocks, m_nBlockSize, sizeof(CDXMap::CAssoc));
  994. // chain them into free list
  995. CDXMap::CAssoc* pAssoc = (CDXMap::CAssoc*) newBlock->data();
  996. // free in reverse order to make it easier to debug
  997. pAssoc += m_nBlockSize - 1;
  998. for (int i = m_nBlockSize-1; i >= 0; i--, pAssoc--)
  999. {
  1000. pAssoc->pNext = m_pFreeList;
  1001. m_pFreeList = pAssoc;
  1002. }
  1003. }
  1004. _ASSERT( m_pFreeList != NULL ); // we must have something
  1005. CDXMap::CAssoc* pAssoc = m_pFreeList;
  1006. m_pFreeList = m_pFreeList->pNext;
  1007. m_nCount++;
  1008. _ASSERT( m_nCount > 0 ); // make sure we don't overflow
  1009. DXConstructElements(&pAssoc->key, 1);
  1010. DXConstructElements(&pAssoc->value, 1); // special construct values
  1011. return pAssoc;
  1012. }
  1013. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1014. void CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::FreeAssoc(CAssoc* pAssoc)
  1015. {
  1016. DXDestructElements(&pAssoc->value, 1);
  1017. DXDestructElements(&pAssoc->key, 1);
  1018. pAssoc->pNext = m_pFreeList;
  1019. m_pFreeList = pAssoc;
  1020. m_nCount--;
  1021. _ASSERT( m_nCount >= 0 ); // make sure we don't underflow
  1022. }
  1023. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1024. typename CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
  1025. CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetAssocAt(ARG_KEY key, UINT& nHash) const
  1026. // find association (or return NULL)
  1027. {
  1028. nHash = DXHashKey(key) % m_nHashTableSize;
  1029. if (m_pHashTable == NULL)
  1030. return NULL;
  1031. // see if it exists
  1032. CAssoc* pAssoc;
  1033. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
  1034. {
  1035. if (DXCompareElements(&pAssoc->key, &key))
  1036. return pAssoc;
  1037. }
  1038. return NULL;
  1039. }
  1040. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1041. BOOL CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Lookup(ARG_KEY key, VALUE& rValue) const
  1042. {
  1043. DXASSERT_VALID( this );
  1044. UINT nHash;
  1045. CAssoc* pAssoc = GetAssocAt(key, nHash);
  1046. if (pAssoc == NULL)
  1047. return FALSE; // not in map
  1048. rValue = pAssoc->value;
  1049. return TRUE;
  1050. }
  1051. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1052. VALUE& CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::operator[](ARG_KEY key)
  1053. {
  1054. DXASSERT_VALID( this );
  1055. UINT nHash;
  1056. CAssoc* pAssoc;
  1057. if ((pAssoc = GetAssocAt(key, nHash)) == NULL)
  1058. {
  1059. if (m_pHashTable == NULL)
  1060. InitHashTable(m_nHashTableSize);
  1061. // it doesn't exist, add a new Association
  1062. pAssoc = NewAssoc();
  1063. pAssoc->nHashValue = nHash;
  1064. pAssoc->key = key;
  1065. // 'pAssoc->value' is a constructed object, nothing more
  1066. // put into hash table
  1067. pAssoc->pNext = m_pHashTable[nHash];
  1068. m_pHashTable[nHash] = pAssoc;
  1069. }
  1070. return pAssoc->value; // return new reference
  1071. }
  1072. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1073. BOOL CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveKey(ARG_KEY key)
  1074. // remove key - return TRUE if removed
  1075. {
  1076. DXASSERT_VALID( this );
  1077. if (m_pHashTable == NULL)
  1078. return FALSE; // nothing in the table
  1079. CAssoc** ppAssocPrev;
  1080. ppAssocPrev = &m_pHashTable[DXHashKey(key) % m_nHashTableSize];
  1081. CAssoc* pAssoc;
  1082. for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext)
  1083. {
  1084. if (DXCompareElements(&pAssoc->key, &key))
  1085. {
  1086. // remove it
  1087. *ppAssocPrev = pAssoc->pNext; // remove from list
  1088. FreeAssoc(pAssoc);
  1089. return TRUE;
  1090. }
  1091. ppAssocPrev = &pAssoc->pNext;
  1092. }
  1093. return FALSE; // not found
  1094. }
  1095. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1096. void CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetNextAssoc(DXLISTPOS& rNextPosition,
  1097. KEY& rKey, VALUE& rValue) const
  1098. {
  1099. DXASSERT_VALID( this );
  1100. _ASSERT( m_pHashTable != NULL ); // never call on empty map
  1101. CAssoc* pAssocRet = (CAssoc*)rNextPosition;
  1102. _ASSERT( pAssocRet != NULL );
  1103. if (pAssocRet == (CAssoc*) DX_BEFORE_START_POSITION)
  1104. {
  1105. // find the first association
  1106. for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
  1107. if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
  1108. break;
  1109. _ASSERT( pAssocRet != NULL ); // must find something
  1110. }
  1111. // find next association
  1112. _ASSERT( DXIsValidAddress(pAssocRet, sizeof(CAssoc), TRUE ));
  1113. CAssoc* pAssocNext;
  1114. if ((pAssocNext = pAssocRet->pNext) == NULL)
  1115. {
  1116. // go to next bucket
  1117. for (UINT nBucket = pAssocRet->nHashValue + 1;
  1118. nBucket < m_nHashTableSize; nBucket++)
  1119. if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
  1120. break;
  1121. }
  1122. rNextPosition = (DXLISTPOS) pAssocNext;
  1123. // fill in return data
  1124. rKey = pAssocRet->key;
  1125. rValue = pAssocRet->value;
  1126. }
  1127. #ifdef _DEBUG
  1128. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1129. void CDXMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::AssertValid() const
  1130. {
  1131. _ASSERT( m_nHashTableSize > 0 );
  1132. _ASSERT( (m_nCount == 0 || m_pHashTable != NULL) );
  1133. // non-empty map should have hash table
  1134. }
  1135. #endif //_DEBUG
  1136. #endif //--- This must be the last line in the file