Source code of Windows XP (NT5)
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.

1240 lines
32 KiB

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