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.

1391 lines
41 KiB

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