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.

1372 lines
36 KiB

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