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.

1260 lines
35 KiB

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