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.

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