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.

1780 lines
49 KiB

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 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 __AFXTEMPL_H__
  11. #define __AFXTEMPL_H__
  12. #ifndef __AFXPLEX_H__
  13. #include <afxplex_.h>
  14. #endif
  15. #ifdef _AFX_MINREBUILD
  16. #pragma component(minrebuild, off)
  17. #endif
  18. #ifndef _AFX_FULLTYPEINFO
  19. #pragma component(mintypeinfo, on)
  20. #endif
  21. #ifdef _AFX_PACKING
  22. #pragma pack(push, _AFX_PACKING)
  23. #endif
  24. #ifdef _DEBUG
  25. static char _szAfxTempl[] = "afxtempl.h";
  26. #undef THIS_FILE
  27. #define THIS_FILE _szAfxTempl
  28. #endif
  29. #ifndef ALL_WARNINGS
  30. #pragma warning(disable: 4114)
  31. #endif
  32. /////////////////////////////////////////////////////////////////////////////
  33. // global helpers (can be overridden)
  34. #ifdef new
  35. #undef new
  36. #define _REDEF_NEW
  37. #endif
  38. #ifndef _INC_NEW
  39. #include <new.h>
  40. #endif
  41. template<class TYPE>
  42. AFX_INLINE void AFXAPI ConstructElements(TYPE* pElements, INT_PTR nCount)
  43. {
  44. ASSERT(nCount == 0 ||
  45. AfxIsValidAddress(pElements, (size_t)nCount * sizeof(TYPE)));
  46. // first do bit-wise zero initialization
  47. memset((void*)pElements, 0, (size_t)nCount * sizeof(TYPE));
  48. // then call the constructor(s)
  49. for (; nCount--; pElements++)
  50. ::new((void*)pElements) TYPE;
  51. }
  52. template<class TYPE>
  53. AFX_INLINE void AFXAPI DestructElements(TYPE* pElements, INT_PTR nCount)
  54. {
  55. ASSERT(nCount == 0 ||
  56. AfxIsValidAddress(pElements, (size_t)nCount * sizeof(TYPE)));
  57. // call the destructor(s)
  58. for (; nCount--; pElements++)
  59. pElements->~TYPE();
  60. }
  61. template<class TYPE>
  62. AFX_INLINE void AFXAPI CopyElements(TYPE* pDest, const TYPE* pSrc, INT_PTR nCount)
  63. {
  64. ASSERT(nCount == 0 ||
  65. AfxIsValidAddress(pDest, (size_t)nCount * sizeof(TYPE)));
  66. ASSERT(nCount == 0 ||
  67. AfxIsValidAddress(pSrc, (size_t)nCount * sizeof(TYPE)));
  68. // default is element-copy using assignment
  69. while (nCount--)
  70. *pDest++ = *pSrc++;
  71. }
  72. template<class TYPE>
  73. void AFXAPI SerializeElements(CArchive& ar, TYPE* pElements, INT_PTR nCount)
  74. {
  75. ASSERT(nCount == 0 ||
  76. AfxIsValidAddress(pElements, (size_t)nCount * sizeof(TYPE)));
  77. // default is bit-wise read/write
  78. if (ar.IsStoring())
  79. {
  80. TYPE* pData;
  81. UINT_PTR nElementsLeft;
  82. nElementsLeft = nCount;
  83. pData = pElements;
  84. while( nElementsLeft > 0 )
  85. {
  86. UINT nElementsToWrite;
  87. nElementsToWrite = UINT(min(nElementsLeft, INT_MAX/sizeof(TYPE)));
  88. ar.Write(pData, nElementsToWrite*sizeof(TYPE));
  89. nElementsLeft -= nElementsToWrite;
  90. pData += nElementsToWrite;
  91. }
  92. }
  93. else
  94. {
  95. TYPE* pData;
  96. UINT_PTR nElementsLeft;
  97. nElementsLeft = nCount;
  98. pData = pElements;
  99. while( nElementsLeft > 0 )
  100. {
  101. UINT nElementsToRead;
  102. nElementsToRead = UINT(min(nElementsLeft, INT_MAX/sizeof(TYPE)));
  103. ar.Read(pData, nElementsToRead*sizeof(TYPE));
  104. nElementsLeft -= nElementsToRead;
  105. pData += nElementsToRead;
  106. }
  107. }
  108. }
  109. #ifdef _DEBUG
  110. template<class TYPE>
  111. void AFXAPI DumpElements(CDumpContext& dc, const TYPE* pElements, INT_PTR nCount)
  112. {
  113. ASSERT(nCount == 0 ||
  114. AfxIsValidAddress(pElements, (size_t)nCount * sizeof(TYPE), FALSE));
  115. &dc; // not used
  116. pElements; // not used
  117. nCount; // not used
  118. // default does nothing
  119. }
  120. #endif
  121. template<class TYPE, class ARG_TYPE>
  122. BOOL AFXAPI CompareElements(const TYPE* pElement1, const ARG_TYPE* pElement2)
  123. {
  124. ASSERT(AfxIsValidAddress(pElement1, sizeof(TYPE), FALSE));
  125. ASSERT(AfxIsValidAddress(pElement2, sizeof(ARG_TYPE), FALSE));
  126. return *pElement1 == *pElement2;
  127. }
  128. template<class ARG_KEY>
  129. AFX_INLINE UINT AFXAPI HashKey(ARG_KEY key)
  130. {
  131. // default identity hash - works for most primitive values
  132. return ((UINT)(ULONG_PTR)key) >> 4;
  133. }
  134. // special versions for CString
  135. #if _MSC_VER >= 1100
  136. template<> void AFXAPI ConstructElements<CString> (CString* pElements, INT_PTR nCount);
  137. template<> void AFXAPI DestructElements<CString> (CString* pElements, INT_PTR nCount);
  138. template<> void AFXAPI CopyElements<CString> (CString* pDest, const CString* pSrc, INT_PTR nCount);
  139. template<> void AFXAPI SerializeElements<CString> (CArchive& ar, CString* pElements, INT_PTR nCount);
  140. #ifndef OLE2ANSI
  141. template<> UINT AFXAPI HashKey<LPCWSTR> (LPCWSTR key);
  142. #endif
  143. template<> UINT AFXAPI HashKey<LPCSTR> (LPCSTR key);
  144. #else // _MSC_VER >= 1100
  145. void AFXAPI ConstructElements(CString* pElements, INT_PTR nCount);
  146. void AFXAPI DestructElements(CString* pElements, INT_PTR nCount);
  147. void AFXAPI CopyElements(CString* pDest, const CString* pSrc, INT_PTR nCount);
  148. void AFXAPI SerializeElements(CArchive& ar, CString* pElements, INT_PTR nCount);
  149. #ifndef OLE2ANSI
  150. UINT AFXAPI HashKey(LPCWSTR key);
  151. #endif
  152. UINT AFXAPI HashKey(LPCSTR key);
  153. #endif // _MSC_VER >= 1100
  154. // forward declarations
  155. class COleVariant;
  156. struct tagVARIANT;
  157. // special versions for COleVariant
  158. #if _MSC_VER >= 1100
  159. template<> void AFXAPI ConstructElements<COleVariant> (COleVariant* pElements, INT_PTR nCount);
  160. template<> void AFXAPI DestructElements<COleVariant> (COleVariant* pElements, INT_PTR nCount);
  161. template<> void AFXAPI CopyElements<COleVariant> (COleVariant* pDest, const COleVariant* pSrc, INT_PTR nCount);
  162. template<> void AFXAPI SerializeElements<COleVariant> (CArchive& ar, COleVariant* pElements, INT_PTR nCount);
  163. #ifdef _DEBUG
  164. template<> void AFXAPI DumpElements<COleVariant> (CDumpContext& dc, const COleVariant* pElements, INT_PTR nCount);
  165. #endif
  166. template<> UINT AFXAPI HashKey<const struct tagVARIANT&> (const struct tagVARIANT& var);
  167. #else // _MSC_VER >= 1100
  168. void AFXAPI ConstructElements(COleVariant* pElements, INT_PTR nCount);
  169. void AFXAPI DestructElements(COleVariant* pElements, INT_PTR nCount);
  170. void AFXAPI CopyElements(COleVariant* pDest, const COleVariant* pSrc, INT_PTR nCount);
  171. void AFXAPI SerializeElements(CArchive& ar, COleVariant* pElements, INT_PTR nCount);
  172. #ifdef _DEBUG
  173. void AFXAPI DumpElements(CDumpContext& dc, const COleVariant* pElements, INT_PTR nCount);
  174. #endif
  175. UINT AFXAPI HashKey(const struct tagVARIANT& var);
  176. #endif // _MSC_VER >= 1100
  177. #define new DEBUG_NEW
  178. /////////////////////////////////////////////////////////////////////////////
  179. // CArray<TYPE, ARG_TYPE>
  180. template<class TYPE, class ARG_TYPE>
  181. class CArray : public CObject
  182. {
  183. public:
  184. // Construction
  185. CArray();
  186. // Attributes
  187. INT_PTR GetSize() const;
  188. INT_PTR GetUpperBound() const;
  189. void SetSize(INT_PTR nNewSize, INT_PTR nGrowBy = -1);
  190. // Operations
  191. // Clean up
  192. void FreeExtra();
  193. void RemoveAll();
  194. // Accessing elements
  195. TYPE GetAt(INT_PTR nIndex) const;
  196. void SetAt(INT_PTR nIndex, ARG_TYPE newElement);
  197. TYPE& ElementAt(INT_PTR nIndex);
  198. // Direct Access to the element data (may return NULL)
  199. const TYPE* GetData() const;
  200. TYPE* GetData();
  201. // Potentially growing the array
  202. void SetAtGrow(INT_PTR nIndex, ARG_TYPE newElement);
  203. INT_PTR Add(ARG_TYPE newElement);
  204. INT_PTR Append(const CArray& src);
  205. void Copy(const CArray& src);
  206. // overloaded operator helpers
  207. TYPE operator[](INT_PTR nIndex) const;
  208. TYPE& operator[](INT_PTR nIndex);
  209. // Operations that move elements around
  210. void InsertAt(INT_PTR nIndex, ARG_TYPE newElement, INT_PTR nCount = 1);
  211. void RemoveAt(INT_PTR nIndex, INT_PTR nCount = 1);
  212. void InsertAt(INT_PTR nStartIndex, CArray* pNewArray);
  213. // Implementation
  214. protected:
  215. TYPE* m_pData; // the actual array of data
  216. INT_PTR m_nSize; // # of elements (upperBound - 1)
  217. INT_PTR m_nMaxSize; // max allocated
  218. INT_PTR m_nGrowBy; // grow amount
  219. public:
  220. ~CArray();
  221. void Serialize(CArchive&);
  222. #ifdef _DEBUG
  223. void Dump(CDumpContext&) const;
  224. void AssertValid() const;
  225. #endif
  226. };
  227. /////////////////////////////////////////////////////////////////////////////
  228. // CArray<TYPE, ARG_TYPE> inline functions
  229. template<class TYPE, class ARG_TYPE>
  230. AFX_INLINE INT_PTR CArray<TYPE, ARG_TYPE>::GetSize() const
  231. { return m_nSize; }
  232. template<class TYPE, class ARG_TYPE>
  233. AFX_INLINE INT_PTR CArray<TYPE, ARG_TYPE>::GetUpperBound() const
  234. { return m_nSize-1; }
  235. template<class TYPE, class ARG_TYPE>
  236. AFX_INLINE void CArray<TYPE, ARG_TYPE>::RemoveAll()
  237. { SetSize(0, -1); }
  238. template<class TYPE, class ARG_TYPE>
  239. AFX_INLINE TYPE CArray<TYPE, ARG_TYPE>::GetAt(INT_PTR nIndex) const
  240. { ASSERT(nIndex >= 0 && nIndex < m_nSize);
  241. return m_pData[nIndex]; }
  242. template<class TYPE, class ARG_TYPE>
  243. AFX_INLINE void CArray<TYPE, ARG_TYPE>::SetAt(INT_PTR nIndex, ARG_TYPE newElement)
  244. { ASSERT(nIndex >= 0 && nIndex < m_nSize);
  245. m_pData[nIndex] = newElement; }
  246. template<class TYPE, class ARG_TYPE>
  247. AFX_INLINE TYPE& CArray<TYPE, ARG_TYPE>::ElementAt(INT_PTR nIndex)
  248. { ASSERT(nIndex >= 0 && nIndex < m_nSize);
  249. return m_pData[nIndex]; }
  250. template<class TYPE, class ARG_TYPE>
  251. AFX_INLINE const TYPE* CArray<TYPE, ARG_TYPE>::GetData() const
  252. { return (const TYPE*)m_pData; }
  253. template<class TYPE, class ARG_TYPE>
  254. AFX_INLINE TYPE* CArray<TYPE, ARG_TYPE>::GetData()
  255. { return (TYPE*)m_pData; }
  256. template<class TYPE, class ARG_TYPE>
  257. AFX_INLINE INT_PTR CArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
  258. { INT_PTR nIndex = m_nSize;
  259. SetAtGrow(nIndex, newElement);
  260. return nIndex; }
  261. template<class TYPE, class ARG_TYPE>
  262. AFX_INLINE TYPE CArray<TYPE, ARG_TYPE>::operator[](INT_PTR nIndex) const
  263. { return GetAt(nIndex); }
  264. template<class TYPE, class ARG_TYPE>
  265. AFX_INLINE TYPE& CArray<TYPE, ARG_TYPE>::operator[](INT_PTR nIndex)
  266. { return ElementAt(nIndex); }
  267. /////////////////////////////////////////////////////////////////////////////
  268. // CArray<TYPE, ARG_TYPE> out-of-line functions
  269. template<class TYPE, class ARG_TYPE>
  270. CArray<TYPE, ARG_TYPE>::CArray()
  271. {
  272. m_pData = NULL;
  273. m_nSize = m_nMaxSize = m_nGrowBy = 0;
  274. }
  275. template<class TYPE, class ARG_TYPE>
  276. CArray<TYPE, ARG_TYPE>::~CArray()
  277. {
  278. ASSERT_VALID(this);
  279. if (m_pData != NULL)
  280. {
  281. DestructElements<TYPE>(m_pData, m_nSize);
  282. delete[] (BYTE*)m_pData;
  283. }
  284. }
  285. template<class TYPE, class ARG_TYPE>
  286. void CArray<TYPE, ARG_TYPE>::SetSize(INT_PTR nNewSize, INT_PTR nGrowBy)
  287. {
  288. ASSERT_VALID(this);
  289. ASSERT(nNewSize >= 0);
  290. if (nGrowBy != -1)
  291. m_nGrowBy = nGrowBy; // set new size
  292. if (nNewSize == 0)
  293. {
  294. // shrink to nothing
  295. if (m_pData != NULL)
  296. {
  297. DestructElements<TYPE>(m_pData, m_nSize);
  298. delete[] (BYTE*)m_pData;
  299. m_pData = NULL;
  300. }
  301. m_nSize = m_nMaxSize = 0;
  302. }
  303. else if (m_pData == NULL)
  304. {
  305. // create one with exact size
  306. #ifdef SIZE_T_MAX
  307. ASSERT(nNewSize <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
  308. #endif
  309. m_pData = (TYPE*) new BYTE[(size_t)nNewSize * sizeof(TYPE)];
  310. ConstructElements<TYPE>(m_pData, nNewSize);
  311. m_nSize = m_nMaxSize = nNewSize;
  312. }
  313. else if (nNewSize <= m_nMaxSize)
  314. {
  315. // it fits
  316. if (nNewSize > m_nSize)
  317. {
  318. // initialize the new elements
  319. ConstructElements<TYPE>(&m_pData[m_nSize], nNewSize-m_nSize);
  320. }
  321. else if (m_nSize > nNewSize)
  322. {
  323. // destroy the old elements
  324. DestructElements<TYPE>(&m_pData[nNewSize], m_nSize-nNewSize);
  325. }
  326. m_nSize = nNewSize;
  327. }
  328. else
  329. {
  330. // otherwise, grow array
  331. INT_PTR nGrowBy = m_nGrowBy;
  332. if (nGrowBy == 0)
  333. {
  334. // heuristically determine growth when nGrowBy == 0
  335. // (this avoids heap fragmentation in many situations)
  336. nGrowBy = m_nSize / 8;
  337. nGrowBy = (nGrowBy < 4) ? 4 : ((nGrowBy > 1024) ? 1024 : nGrowBy);
  338. }
  339. INT_PTR nNewMax;
  340. if (nNewSize < m_nMaxSize + nGrowBy)
  341. nNewMax = m_nMaxSize + nGrowBy; // granularity
  342. else
  343. nNewMax = nNewSize; // no slush
  344. ASSERT(nNewMax >= m_nMaxSize); // no wrap around
  345. #ifdef SIZE_T_MAX
  346. ASSERT(nNewMax <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
  347. #endif
  348. TYPE* pNewData = (TYPE*) new BYTE[(size_t)nNewMax * sizeof(TYPE)];
  349. // copy new data from old
  350. memcpy(pNewData, m_pData, (size_t)m_nSize * sizeof(TYPE));
  351. // construct remaining elements
  352. ASSERT(nNewSize > m_nSize);
  353. ConstructElements<TYPE>(&pNewData[m_nSize], nNewSize-m_nSize);
  354. // get rid of old stuff (note: no destructors called)
  355. delete[] (BYTE*)m_pData;
  356. m_pData = pNewData;
  357. m_nSize = nNewSize;
  358. m_nMaxSize = nNewMax;
  359. }
  360. }
  361. template<class TYPE, class ARG_TYPE>
  362. INT_PTR CArray<TYPE, ARG_TYPE>::Append(const CArray& src)
  363. {
  364. ASSERT_VALID(this);
  365. ASSERT(this != &src); // cannot append to itself
  366. INT_PTR nOldSize = m_nSize;
  367. SetSize(m_nSize + src.m_nSize);
  368. CopyElements<TYPE>(m_pData + nOldSize, src.m_pData, src.m_nSize);
  369. return nOldSize;
  370. }
  371. template<class TYPE, class ARG_TYPE>
  372. void CArray<TYPE, ARG_TYPE>::Copy(const CArray& src)
  373. {
  374. ASSERT_VALID(this);
  375. ASSERT(this != &src); // cannot append to itself
  376. SetSize(src.m_nSize);
  377. CopyElements<TYPE>(m_pData, src.m_pData, src.m_nSize);
  378. }
  379. template<class TYPE, class ARG_TYPE>
  380. void CArray<TYPE, ARG_TYPE>::FreeExtra()
  381. {
  382. ASSERT_VALID(this);
  383. if (m_nSize != m_nMaxSize)
  384. {
  385. // shrink to desired size
  386. #ifdef SIZE_T_MAX
  387. ASSERT(m_nSize <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
  388. #endif
  389. TYPE* pNewData = NULL;
  390. if (m_nSize != 0)
  391. {
  392. pNewData = (TYPE*) new BYTE[m_nSize * sizeof(TYPE)];
  393. // copy new data from old
  394. memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
  395. }
  396. // get rid of old stuff (note: no destructors called)
  397. delete[] (BYTE*)m_pData;
  398. m_pData = pNewData;
  399. m_nMaxSize = m_nSize;
  400. }
  401. }
  402. template<class TYPE, class ARG_TYPE>
  403. void CArray<TYPE, ARG_TYPE>::SetAtGrow(INT_PTR nIndex, ARG_TYPE newElement)
  404. {
  405. ASSERT_VALID(this);
  406. ASSERT(nIndex >= 0);
  407. if (nIndex >= m_nSize)
  408. SetSize(nIndex+1, -1);
  409. m_pData[nIndex] = newElement;
  410. }
  411. template<class TYPE, class ARG_TYPE>
  412. void CArray<TYPE, ARG_TYPE>::InsertAt(INT_PTR nIndex, ARG_TYPE newElement, INT_PTR nCount /*=1*/)
  413. {
  414. ASSERT_VALID(this);
  415. ASSERT(nIndex >= 0); // will expand to meet need
  416. ASSERT(nCount > 0); // zero or negative size not allowed
  417. if (nIndex >= m_nSize)
  418. {
  419. // adding after the end of the array
  420. SetSize(nIndex + nCount, -1); // grow so nIndex is valid
  421. }
  422. else
  423. {
  424. // inserting in the middle of the array
  425. INT_PTR nOldSize = m_nSize;
  426. SetSize(m_nSize + nCount, -1); // grow it to new size
  427. // destroy intial data before copying over it
  428. DestructElements<TYPE>(&m_pData[nOldSize], nCount);
  429. // shift old data up to fill gap
  430. memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
  431. (size_t)(nOldSize-nIndex) * sizeof(TYPE));
  432. // re-init slots we copied from
  433. ConstructElements<TYPE>(&m_pData[nIndex], nCount);
  434. }
  435. // insert new value in the gap
  436. ASSERT(nIndex + nCount <= m_nSize);
  437. while (nCount--)
  438. m_pData[nIndex++] = newElement;
  439. }
  440. template<class TYPE, class ARG_TYPE>
  441. void CArray<TYPE, ARG_TYPE>::RemoveAt(INT_PTR nIndex, INT_PTR nCount)
  442. {
  443. ASSERT_VALID(this);
  444. ASSERT(nIndex >= 0);
  445. ASSERT(nCount >= 0);
  446. ASSERT(nIndex + nCount <= m_nSize);
  447. // just remove a range
  448. INT_PTR nMoveCount = m_nSize - (nIndex + nCount);
  449. DestructElements<TYPE>(&m_pData[nIndex], nCount);
  450. if (nMoveCount)
  451. memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],
  452. (size_t)nMoveCount * sizeof(TYPE));
  453. m_nSize -= nCount;
  454. }
  455. template<class TYPE, class ARG_TYPE>
  456. void CArray<TYPE, ARG_TYPE>::InsertAt(INT_PTR nStartIndex, CArray* pNewArray)
  457. {
  458. ASSERT_VALID(this);
  459. ASSERT(pNewArray != NULL);
  460. ASSERT_VALID(pNewArray);
  461. ASSERT(nStartIndex >= 0);
  462. if (pNewArray->GetSize() > 0)
  463. {
  464. InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
  465. for (INT_PTR i = 0; i < pNewArray->GetSize(); i++)
  466. SetAt(nStartIndex + i, pNewArray->GetAt(i));
  467. }
  468. }
  469. template<class TYPE, class ARG_TYPE>
  470. void CArray<TYPE, ARG_TYPE>::Serialize(CArchive& ar)
  471. {
  472. ASSERT_VALID(this);
  473. CObject::Serialize(ar);
  474. if (ar.IsStoring())
  475. {
  476. ar.WriteCount(m_nSize);
  477. }
  478. else
  479. {
  480. DWORD_PTR nOldSize = ar.ReadCount();
  481. SetSize(nOldSize, -1);
  482. }
  483. SerializeElements<TYPE>(ar, m_pData, m_nSize);
  484. }
  485. #ifdef _DEBUG
  486. template<class TYPE, class ARG_TYPE>
  487. void CArray<TYPE, ARG_TYPE>::Dump(CDumpContext& dc) const
  488. {
  489. CObject::Dump(dc);
  490. dc << "with " << m_nSize << " elements";
  491. if (dc.GetDepth() > 0)
  492. {
  493. dc << "\n";
  494. DumpElements<TYPE>(dc, m_pData, m_nSize);
  495. }
  496. dc << "\n";
  497. }
  498. template<class TYPE, class ARG_TYPE>
  499. void CArray<TYPE, ARG_TYPE>::AssertValid() const
  500. {
  501. CObject::AssertValid();
  502. if (m_pData == NULL)
  503. {
  504. ASSERT(m_nSize == 0);
  505. ASSERT(m_nMaxSize == 0);
  506. }
  507. else
  508. {
  509. ASSERT(m_nSize >= 0);
  510. ASSERT(m_nMaxSize >= 0);
  511. ASSERT(m_nSize <= m_nMaxSize);
  512. ASSERT(AfxIsValidAddress(m_pData, m_nMaxSize * sizeof(TYPE)));
  513. }
  514. }
  515. #endif //_DEBUG
  516. /////////////////////////////////////////////////////////////////////////////
  517. // CList<TYPE, ARG_TYPE>
  518. template<class TYPE, class ARG_TYPE>
  519. class CList : public CObject
  520. {
  521. protected:
  522. struct CNode
  523. {
  524. CNode* pNext;
  525. CNode* pPrev;
  526. TYPE data;
  527. };
  528. public:
  529. // Construction
  530. CList(int nBlockSize = 10);
  531. // Attributes (head and tail)
  532. // count of elements
  533. INT_PTR GetCount() const;
  534. BOOL IsEmpty() const;
  535. // peek at head or tail
  536. TYPE& GetHead();
  537. TYPE GetHead() const;
  538. TYPE& GetTail();
  539. TYPE GetTail() const;
  540. // Operations
  541. // get head or tail (and remove it) - don't call on empty list !
  542. TYPE RemoveHead();
  543. TYPE RemoveTail();
  544. // add before head or after tail
  545. POSITION AddHead(ARG_TYPE newElement);
  546. POSITION AddTail(ARG_TYPE newElement);
  547. // add another list of elements before head or after tail
  548. void AddHead(CList* pNewList);
  549. void AddTail(CList* pNewList);
  550. // remove all elements
  551. void RemoveAll();
  552. // iteration
  553. POSITION GetHeadPosition() const;
  554. POSITION GetTailPosition() const;
  555. TYPE& GetNext(POSITION& rPosition); // return *Position++
  556. TYPE GetNext(POSITION& rPosition) const; // return *Position++
  557. TYPE& GetPrev(POSITION& rPosition); // return *Position--
  558. TYPE GetPrev(POSITION& rPosition) const; // return *Position--
  559. // getting/modifying an element at a given position
  560. TYPE& GetAt(POSITION position);
  561. TYPE GetAt(POSITION position) const;
  562. void SetAt(POSITION pos, ARG_TYPE newElement);
  563. void RemoveAt(POSITION position);
  564. // inserting before or after a given position
  565. POSITION InsertBefore(POSITION position, ARG_TYPE newElement);
  566. POSITION InsertAfter(POSITION position, ARG_TYPE newElement);
  567. // helper functions (note: O(n) speed)
  568. POSITION Find(ARG_TYPE searchValue, POSITION startAfter = NULL) const;
  569. // defaults to starting at the HEAD, return NULL if not found
  570. POSITION FindIndex(INT_PTR nIndex) const;
  571. // get the 'nIndex'th element (may return NULL)
  572. // Implementation
  573. protected:
  574. CNode* m_pNodeHead;
  575. CNode* m_pNodeTail;
  576. INT_PTR m_nCount;
  577. CNode* m_pNodeFree;
  578. struct CPlex* m_pBlocks;
  579. int m_nBlockSize;
  580. CNode* NewNode(CNode*, CNode*);
  581. void FreeNode(CNode*);
  582. public:
  583. ~CList();
  584. void Serialize(CArchive&);
  585. #ifdef _DEBUG
  586. void Dump(CDumpContext&) const;
  587. void AssertValid() const;
  588. #endif
  589. };
  590. /////////////////////////////////////////////////////////////////////////////
  591. // CList<TYPE, ARG_TYPE> inline functions
  592. template<class TYPE, class ARG_TYPE>
  593. AFX_INLINE INT_PTR CList<TYPE, ARG_TYPE>::GetCount() const
  594. { return m_nCount; }
  595. template<class TYPE, class ARG_TYPE>
  596. AFX_INLINE BOOL CList<TYPE, ARG_TYPE>::IsEmpty() const
  597. { return m_nCount == 0; }
  598. template<class TYPE, class ARG_TYPE>
  599. AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetHead()
  600. { ASSERT(m_pNodeHead != NULL);
  601. return m_pNodeHead->data; }
  602. template<class TYPE, class ARG_TYPE>
  603. AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetHead() const
  604. { ASSERT(m_pNodeHead != NULL);
  605. return m_pNodeHead->data; }
  606. template<class TYPE, class ARG_TYPE>
  607. AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetTail()
  608. { ASSERT(m_pNodeTail != NULL);
  609. return m_pNodeTail->data; }
  610. template<class TYPE, class ARG_TYPE>
  611. AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetTail() const
  612. { ASSERT(m_pNodeTail != NULL);
  613. return m_pNodeTail->data; }
  614. template<class TYPE, class ARG_TYPE>
  615. AFX_INLINE POSITION CList<TYPE, ARG_TYPE>::GetHeadPosition() const
  616. { return (POSITION) m_pNodeHead; }
  617. template<class TYPE, class ARG_TYPE>
  618. AFX_INLINE POSITION CList<TYPE, ARG_TYPE>::GetTailPosition() const
  619. { return (POSITION) m_pNodeTail; }
  620. template<class TYPE, class ARG_TYPE>
  621. AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPosition) // return *Position++
  622. { CNode* pNode = (CNode*) rPosition;
  623. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  624. rPosition = (POSITION) pNode->pNext;
  625. return pNode->data; }
  626. template<class TYPE, class ARG_TYPE>
  627. AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPosition) const // return *Position++
  628. { CNode* pNode = (CNode*) rPosition;
  629. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  630. rPosition = (POSITION) pNode->pNext;
  631. return pNode->data; }
  632. template<class TYPE, class ARG_TYPE>
  633. AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetPrev(POSITION& rPosition) // return *Position--
  634. { CNode* pNode = (CNode*) rPosition;
  635. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  636. rPosition = (POSITION) pNode->pPrev;
  637. return pNode->data; }
  638. template<class TYPE, class ARG_TYPE>
  639. AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetPrev(POSITION& rPosition) const // return *Position--
  640. { CNode* pNode = (CNode*) rPosition;
  641. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  642. rPosition = (POSITION) pNode->pPrev;
  643. return pNode->data; }
  644. template<class TYPE, class ARG_TYPE>
  645. AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetAt(POSITION position)
  646. { CNode* pNode = (CNode*) position;
  647. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  648. return pNode->data; }
  649. template<class TYPE, class ARG_TYPE>
  650. AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetAt(POSITION position) const
  651. { CNode* pNode = (CNode*) position;
  652. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  653. return pNode->data; }
  654. template<class TYPE, class ARG_TYPE>
  655. AFX_INLINE void CList<TYPE, ARG_TYPE>::SetAt(POSITION pos, ARG_TYPE newElement)
  656. { CNode* pNode = (CNode*) pos;
  657. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  658. pNode->data = newElement; }
  659. template<class TYPE, class ARG_TYPE>
  660. CList<TYPE, ARG_TYPE>::CList(int nBlockSize)
  661. {
  662. ASSERT(nBlockSize > 0);
  663. m_nCount = 0;
  664. m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  665. m_pBlocks = NULL;
  666. m_nBlockSize = nBlockSize;
  667. }
  668. template<class TYPE, class ARG_TYPE>
  669. void CList<TYPE, ARG_TYPE>::RemoveAll()
  670. {
  671. ASSERT_VALID(this);
  672. // destroy elements
  673. CNode* pNode;
  674. for (pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
  675. DestructElements<TYPE>(&pNode->data, 1);
  676. m_nCount = 0;
  677. m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
  678. m_pBlocks->FreeDataChain();
  679. m_pBlocks = NULL;
  680. }
  681. template<class TYPE, class ARG_TYPE>
  682. CList<TYPE, ARG_TYPE>::~CList()
  683. {
  684. RemoveAll();
  685. ASSERT(m_nCount == 0);
  686. }
  687. /////////////////////////////////////////////////////////////////////////////
  688. // Node helpers
  689. //
  690. // Implementation note: CNode's are stored in CPlex blocks and
  691. // chained together. Free blocks are maintained in a singly linked list
  692. // using the 'pNext' member of CNode with 'm_pNodeFree' as the head.
  693. // Used blocks are maintained in a doubly linked list using both 'pNext'
  694. // and 'pPrev' as links and 'm_pNodeHead' and 'm_pNodeTail'
  695. // as the head/tail.
  696. //
  697. // We never free a CPlex block unless the List is destroyed or RemoveAll()
  698. // is used - so the total number of CPlex blocks may grow large depending
  699. // on the maximum past size of the list.
  700. //
  701. template<class TYPE, class ARG_TYPE>
  702. typename CList<TYPE, ARG_TYPE>::CNode*
  703. CList<TYPE, ARG_TYPE>::NewNode(CNode* pPrev, CNode* pNext)
  704. {
  705. if (m_pNodeFree == NULL)
  706. {
  707. // add another block
  708. CPlex* pNewBlock = CPlex::Create(m_pBlocks, m_nBlockSize,
  709. sizeof(CNode));
  710. // chain them into free list
  711. CNode* pNode = (CNode*) pNewBlock->data();
  712. // free in reverse order to make it easier to debug
  713. pNode += m_nBlockSize - 1;
  714. for (int i = m_nBlockSize-1; i >= 0; i--, pNode--)
  715. {
  716. pNode->pNext = m_pNodeFree;
  717. m_pNodeFree = pNode;
  718. }
  719. }
  720. ASSERT(m_pNodeFree != NULL); // we must have something
  721. CList::CNode* pNode = m_pNodeFree;
  722. m_pNodeFree = m_pNodeFree->pNext;
  723. pNode->pPrev = pPrev;
  724. pNode->pNext = pNext;
  725. m_nCount++;
  726. ASSERT(m_nCount > 0); // make sure we don't overflow
  727. ConstructElements<TYPE>(&pNode->data, 1);
  728. return pNode;
  729. }
  730. template<class TYPE, class ARG_TYPE>
  731. void CList<TYPE, ARG_TYPE>::FreeNode(CNode* pNode)
  732. {
  733. DestructElements<TYPE>(&pNode->data, 1);
  734. pNode->pNext = m_pNodeFree;
  735. m_pNodeFree = pNode;
  736. m_nCount--;
  737. ASSERT(m_nCount >= 0); // make sure we don't underflow
  738. // if no more elements, cleanup completely
  739. if (m_nCount == 0)
  740. RemoveAll();
  741. }
  742. template<class TYPE, class ARG_TYPE>
  743. POSITION CList<TYPE, ARG_TYPE>::AddHead(ARG_TYPE newElement)
  744. {
  745. ASSERT_VALID(this);
  746. CNode* pNewNode = NewNode(NULL, m_pNodeHead);
  747. pNewNode->data = newElement;
  748. if (m_pNodeHead != NULL)
  749. m_pNodeHead->pPrev = pNewNode;
  750. else
  751. m_pNodeTail = pNewNode;
  752. m_pNodeHead = pNewNode;
  753. return (POSITION) pNewNode;
  754. }
  755. template<class TYPE, class ARG_TYPE>
  756. POSITION CList<TYPE, ARG_TYPE>::AddTail(ARG_TYPE newElement)
  757. {
  758. ASSERT_VALID(this);
  759. CNode* pNewNode = NewNode(m_pNodeTail, NULL);
  760. pNewNode->data = newElement;
  761. if (m_pNodeTail != NULL)
  762. m_pNodeTail->pNext = pNewNode;
  763. else
  764. m_pNodeHead = pNewNode;
  765. m_pNodeTail = pNewNode;
  766. return (POSITION) pNewNode;
  767. }
  768. template<class TYPE, class ARG_TYPE>
  769. void CList<TYPE, ARG_TYPE>::AddHead(CList* pNewList)
  770. {
  771. ASSERT_VALID(this);
  772. ASSERT(pNewList != NULL);
  773. ASSERT_VALID(pNewList);
  774. // add a list of same elements to head (maintain order)
  775. POSITION pos = pNewList->GetTailPosition();
  776. while (pos != NULL)
  777. AddHead(pNewList->GetPrev(pos));
  778. }
  779. template<class TYPE, class ARG_TYPE>
  780. void CList<TYPE, ARG_TYPE>::AddTail(CList* pNewList)
  781. {
  782. ASSERT_VALID(this);
  783. ASSERT(pNewList != NULL);
  784. ASSERT_VALID(pNewList);
  785. // add a list of same elements
  786. POSITION pos = pNewList->GetHeadPosition();
  787. while (pos != NULL)
  788. AddTail(pNewList->GetNext(pos));
  789. }
  790. template<class TYPE, class ARG_TYPE>
  791. TYPE CList<TYPE, ARG_TYPE>::RemoveHead()
  792. {
  793. ASSERT_VALID(this);
  794. ASSERT(m_pNodeHead != NULL); // don't call on empty list !!!
  795. ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode)));
  796. CNode* pOldNode = m_pNodeHead;
  797. TYPE returnValue = pOldNode->data;
  798. m_pNodeHead = pOldNode->pNext;
  799. if (m_pNodeHead != NULL)
  800. m_pNodeHead->pPrev = NULL;
  801. else
  802. m_pNodeTail = NULL;
  803. FreeNode(pOldNode);
  804. return returnValue;
  805. }
  806. template<class TYPE, class ARG_TYPE>
  807. TYPE CList<TYPE, ARG_TYPE>::RemoveTail()
  808. {
  809. ASSERT_VALID(this);
  810. ASSERT(m_pNodeTail != NULL); // don't call on empty list !!!
  811. ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode)));
  812. CNode* pOldNode = m_pNodeTail;
  813. TYPE returnValue = pOldNode->data;
  814. m_pNodeTail = pOldNode->pPrev;
  815. if (m_pNodeTail != NULL)
  816. m_pNodeTail->pNext = NULL;
  817. else
  818. m_pNodeHead = NULL;
  819. FreeNode(pOldNode);
  820. return returnValue;
  821. }
  822. template<class TYPE, class ARG_TYPE>
  823. POSITION CList<TYPE, ARG_TYPE>::InsertBefore(POSITION position, ARG_TYPE newElement)
  824. {
  825. ASSERT_VALID(this);
  826. if (position == NULL)
  827. return AddHead(newElement); // insert before nothing -> head of the list
  828. // Insert it before position
  829. CNode* pOldNode = (CNode*) position;
  830. CNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode);
  831. pNewNode->data = newElement;
  832. if (pOldNode->pPrev != NULL)
  833. {
  834. ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  835. pOldNode->pPrev->pNext = pNewNode;
  836. }
  837. else
  838. {
  839. ASSERT(pOldNode == m_pNodeHead);
  840. m_pNodeHead = pNewNode;
  841. }
  842. pOldNode->pPrev = pNewNode;
  843. return (POSITION) pNewNode;
  844. }
  845. template<class TYPE, class ARG_TYPE>
  846. POSITION CList<TYPE, ARG_TYPE>::InsertAfter(POSITION position, ARG_TYPE newElement)
  847. {
  848. ASSERT_VALID(this);
  849. if (position == NULL)
  850. return AddTail(newElement); // insert after nothing -> tail of the list
  851. // Insert it before position
  852. CNode* pOldNode = (CNode*) position;
  853. ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode)));
  854. CNode* pNewNode = NewNode(pOldNode, pOldNode->pNext);
  855. pNewNode->data = newElement;
  856. if (pOldNode->pNext != NULL)
  857. {
  858. ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode)));
  859. pOldNode->pNext->pPrev = pNewNode;
  860. }
  861. else
  862. {
  863. ASSERT(pOldNode == m_pNodeTail);
  864. m_pNodeTail = pNewNode;
  865. }
  866. pOldNode->pNext = pNewNode;
  867. return (POSITION) pNewNode;
  868. }
  869. template<class TYPE, class ARG_TYPE>
  870. void CList<TYPE, ARG_TYPE>::RemoveAt(POSITION position)
  871. {
  872. ASSERT_VALID(this);
  873. CNode* pOldNode = (CNode*) position;
  874. ASSERT(AfxIsValidAddress(pOldNode, sizeof(CNode)));
  875. // remove pOldNode from list
  876. if (pOldNode == m_pNodeHead)
  877. {
  878. m_pNodeHead = pOldNode->pNext;
  879. }
  880. else
  881. {
  882. ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(CNode)));
  883. pOldNode->pPrev->pNext = pOldNode->pNext;
  884. }
  885. if (pOldNode == m_pNodeTail)
  886. {
  887. m_pNodeTail = pOldNode->pPrev;
  888. }
  889. else
  890. {
  891. ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(CNode)));
  892. pOldNode->pNext->pPrev = pOldNode->pPrev;
  893. }
  894. FreeNode(pOldNode);
  895. }
  896. template<class TYPE, class ARG_TYPE>
  897. POSITION CList<TYPE, ARG_TYPE>::FindIndex(INT_PTR nIndex) const
  898. {
  899. ASSERT_VALID(this);
  900. if (nIndex >= m_nCount || nIndex < 0)
  901. return NULL; // went too far
  902. CNode* pNode = m_pNodeHead;
  903. while (nIndex--)
  904. {
  905. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  906. pNode = pNode->pNext;
  907. }
  908. return (POSITION) pNode;
  909. }
  910. template<class TYPE, class ARG_TYPE>
  911. POSITION CList<TYPE, ARG_TYPE>::Find(ARG_TYPE searchValue, POSITION startAfter) const
  912. {
  913. ASSERT_VALID(this);
  914. CNode* pNode = (CNode*) startAfter;
  915. if (pNode == NULL)
  916. {
  917. pNode = m_pNodeHead; // start at head
  918. }
  919. else
  920. {
  921. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  922. pNode = pNode->pNext; // start after the one specified
  923. }
  924. for (; pNode != NULL; pNode = pNode->pNext)
  925. if (CompareElements<TYPE>(&pNode->data, &searchValue))
  926. return (POSITION)pNode;
  927. return NULL;
  928. }
  929. template<class TYPE, class ARG_TYPE>
  930. void CList<TYPE, ARG_TYPE>::Serialize(CArchive& ar)
  931. {
  932. ASSERT_VALID(this);
  933. CObject::Serialize(ar);
  934. if (ar.IsStoring())
  935. {
  936. ar.WriteCount(m_nCount);
  937. for (CNode* pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
  938. {
  939. ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
  940. SerializeElements<TYPE>(ar, &pNode->data, 1);
  941. }
  942. }
  943. else
  944. {
  945. DWORD_PTR nNewCount = ar.ReadCount();
  946. while (nNewCount--)
  947. {
  948. TYPE newData;
  949. SerializeElements<TYPE>(ar, &newData, 1);
  950. AddTail(newData);
  951. }
  952. }
  953. }
  954. #ifdef _DEBUG
  955. template<class TYPE, class ARG_TYPE>
  956. void CList<TYPE, ARG_TYPE>::Dump(CDumpContext& dc) const
  957. {
  958. CObject::Dump(dc);
  959. dc << "with " << m_nCount << " elements";
  960. if (dc.GetDepth() > 0)
  961. {
  962. POSITION pos = GetHeadPosition();
  963. while (pos != NULL)
  964. {
  965. dc << "\n";
  966. DumpElements<TYPE>(dc, &((CList*)this)->GetNext(pos), 1);
  967. }
  968. }
  969. dc << "\n";
  970. }
  971. template<class TYPE, class ARG_TYPE>
  972. void CList<TYPE, ARG_TYPE>::AssertValid() const
  973. {
  974. CObject::AssertValid();
  975. if (m_nCount == 0)
  976. {
  977. // empty list
  978. ASSERT(m_pNodeHead == NULL);
  979. ASSERT(m_pNodeTail == NULL);
  980. }
  981. else
  982. {
  983. // non-empty list
  984. ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(CNode)));
  985. ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(CNode)));
  986. }
  987. }
  988. #endif //_DEBUG
  989. /////////////////////////////////////////////////////////////////////////////
  990. // CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>
  991. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  992. class CMap : public CObject
  993. {
  994. protected:
  995. // Association
  996. struct CAssoc
  997. {
  998. CAssoc* pNext;
  999. UINT nHashValue; // needed for efficient iteration
  1000. KEY key;
  1001. VALUE value;
  1002. };
  1003. public:
  1004. // Construction
  1005. CMap(int nBlockSize = 10);
  1006. // Attributes
  1007. // number of elements
  1008. INT_PTR GetCount() const;
  1009. BOOL IsEmpty() const;
  1010. // Lookup
  1011. BOOL Lookup(ARG_KEY key, VALUE& rValue) const;
  1012. // Operations
  1013. // Lookup and add if not there
  1014. VALUE& operator[](ARG_KEY key);
  1015. // add a new (key, value) pair
  1016. void SetAt(ARG_KEY key, ARG_VALUE newValue);
  1017. // removing existing (key, ?) pair
  1018. BOOL RemoveKey(ARG_KEY key);
  1019. void RemoveAll();
  1020. // iterating all (key, value) pairs
  1021. POSITION GetStartPosition() const;
  1022. void GetNextAssoc(POSITION& rNextPosition, KEY& rKey, VALUE& rValue) const;
  1023. // advanced features for derived classes
  1024. UINT GetHashTableSize() const;
  1025. void InitHashTable(UINT hashSize, BOOL bAllocNow = TRUE);
  1026. // Implementation
  1027. protected:
  1028. CAssoc** m_pHashTable;
  1029. UINT m_nHashTableSize;
  1030. INT_PTR m_nCount;
  1031. CAssoc* m_pFreeList;
  1032. struct CPlex* m_pBlocks;
  1033. int m_nBlockSize;
  1034. CAssoc* NewAssoc();
  1035. void FreeAssoc(CAssoc*);
  1036. CAssoc* GetAssocAt(ARG_KEY, UINT&) const;
  1037. public:
  1038. ~CMap();
  1039. void Serialize(CArchive&);
  1040. #ifdef _DEBUG
  1041. void Dump(CDumpContext&) const;
  1042. void AssertValid() const;
  1043. #endif
  1044. };
  1045. /////////////////////////////////////////////////////////////////////////////
  1046. // CMap<KEY, ARG_KEY, VALUE, ARG_VALUE> inline functions
  1047. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1048. AFX_INLINE INT_PTR CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetCount() const
  1049. { return m_nCount; }
  1050. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1051. AFX_INLINE BOOL CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::IsEmpty() const
  1052. { return m_nCount == 0; }
  1053. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1054. AFX_INLINE void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::SetAt(ARG_KEY key, ARG_VALUE newValue)
  1055. { (*this)[key] = newValue; }
  1056. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1057. AFX_INLINE POSITION CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetStartPosition() const
  1058. { return (m_nCount == 0) ? NULL : BEFORE_START_POSITION; }
  1059. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1060. AFX_INLINE UINT CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetHashTableSize() const
  1061. { return m_nHashTableSize; }
  1062. /////////////////////////////////////////////////////////////////////////////
  1063. // CMap<KEY, ARG_KEY, VALUE, ARG_VALUE> out-of-line functions
  1064. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1065. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CMap(int nBlockSize)
  1066. {
  1067. ASSERT(nBlockSize > 0);
  1068. m_pHashTable = NULL;
  1069. m_nHashTableSize = 17; // default size
  1070. m_nCount = 0;
  1071. m_pFreeList = NULL;
  1072. m_pBlocks = NULL;
  1073. m_nBlockSize = nBlockSize;
  1074. }
  1075. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1076. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::InitHashTable(
  1077. UINT nHashSize, BOOL bAllocNow)
  1078. //
  1079. // Used to force allocation of a hash table or to override the default
  1080. // hash table size of (which is fairly small)
  1081. {
  1082. ASSERT_VALID(this);
  1083. ASSERT(m_nCount == 0);
  1084. ASSERT(nHashSize > 0);
  1085. if (m_pHashTable != NULL)
  1086. {
  1087. // free hash table
  1088. delete[] m_pHashTable;
  1089. m_pHashTable = NULL;
  1090. }
  1091. if (bAllocNow)
  1092. {
  1093. m_pHashTable = new CAssoc* [nHashSize];
  1094. memset(m_pHashTable, 0, sizeof(CAssoc*) * nHashSize);
  1095. }
  1096. m_nHashTableSize = nHashSize;
  1097. }
  1098. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1099. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveAll()
  1100. {
  1101. ASSERT_VALID(this);
  1102. if (m_pHashTable != NULL)
  1103. {
  1104. // destroy elements (values and keys)
  1105. for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
  1106. {
  1107. CAssoc* pAssoc;
  1108. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
  1109. pAssoc = pAssoc->pNext)
  1110. {
  1111. DestructElements<VALUE>(&pAssoc->value, 1);
  1112. DestructElements<KEY>(&pAssoc->key, 1);
  1113. }
  1114. }
  1115. }
  1116. // free hash table
  1117. delete[] m_pHashTable;
  1118. m_pHashTable = NULL;
  1119. m_nCount = 0;
  1120. m_pFreeList = NULL;
  1121. m_pBlocks->FreeDataChain();
  1122. m_pBlocks = NULL;
  1123. }
  1124. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1125. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::~CMap()
  1126. {
  1127. RemoveAll();
  1128. ASSERT(m_nCount == 0);
  1129. }
  1130. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1131. typename CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
  1132. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::NewAssoc()
  1133. {
  1134. if (m_pFreeList == NULL)
  1135. {
  1136. // add another block
  1137. CPlex* newBlock = CPlex::Create(m_pBlocks, m_nBlockSize, sizeof(CMap::CAssoc));
  1138. // chain them into free list
  1139. CMap::CAssoc* pAssoc = (CMap::CAssoc*) newBlock->data();
  1140. // free in reverse order to make it easier to debug
  1141. pAssoc += m_nBlockSize - 1;
  1142. for (int i = m_nBlockSize-1; i >= 0; i--, pAssoc--)
  1143. {
  1144. pAssoc->pNext = m_pFreeList;
  1145. m_pFreeList = pAssoc;
  1146. }
  1147. }
  1148. ASSERT(m_pFreeList != NULL); // we must have something
  1149. CMap::CAssoc* pAssoc = m_pFreeList;
  1150. m_pFreeList = m_pFreeList->pNext;
  1151. m_nCount++;
  1152. ASSERT(m_nCount > 0); // make sure we don't overflow
  1153. ConstructElements<KEY>(&pAssoc->key, 1);
  1154. ConstructElements<VALUE>(&pAssoc->value, 1); // special construct values
  1155. return pAssoc;
  1156. }
  1157. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1158. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::FreeAssoc(CAssoc* pAssoc)
  1159. {
  1160. DestructElements<VALUE>(&pAssoc->value, 1);
  1161. DestructElements<KEY>(&pAssoc->key, 1);
  1162. pAssoc->pNext = m_pFreeList;
  1163. m_pFreeList = pAssoc;
  1164. m_nCount--;
  1165. ASSERT(m_nCount >= 0); // make sure we don't underflow
  1166. // if no more elements, cleanup completely
  1167. if (m_nCount == 0)
  1168. RemoveAll();
  1169. }
  1170. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1171. typename CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
  1172. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetAssocAt(ARG_KEY key, UINT& nHash) const
  1173. // find association (or return NULL)
  1174. {
  1175. nHash = HashKey<ARG_KEY>(key) % m_nHashTableSize;
  1176. if (m_pHashTable == NULL)
  1177. return NULL;
  1178. // see if it exists
  1179. CAssoc* pAssoc;
  1180. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
  1181. {
  1182. if (CompareElements(&pAssoc->key, &key))
  1183. return pAssoc;
  1184. }
  1185. return NULL;
  1186. }
  1187. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1188. BOOL CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Lookup(ARG_KEY key, VALUE& rValue) const
  1189. {
  1190. ASSERT_VALID(this);
  1191. UINT nHash;
  1192. CAssoc* pAssoc = GetAssocAt(key, nHash);
  1193. if (pAssoc == NULL)
  1194. return FALSE; // not in map
  1195. rValue = pAssoc->value;
  1196. return TRUE;
  1197. }
  1198. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1199. VALUE& CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::operator[](ARG_KEY key)
  1200. {
  1201. ASSERT_VALID(this);
  1202. UINT nHash;
  1203. CAssoc* pAssoc;
  1204. if ((pAssoc = GetAssocAt(key, nHash)) == NULL)
  1205. {
  1206. if (m_pHashTable == NULL)
  1207. InitHashTable(m_nHashTableSize);
  1208. // it doesn't exist, add a new Association
  1209. pAssoc = NewAssoc();
  1210. pAssoc->nHashValue = nHash;
  1211. pAssoc->key = key;
  1212. // 'pAssoc->value' is a constructed object, nothing more
  1213. // put into hash table
  1214. pAssoc->pNext = m_pHashTable[nHash];
  1215. m_pHashTable[nHash] = pAssoc;
  1216. }
  1217. return pAssoc->value; // return new reference
  1218. }
  1219. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1220. BOOL CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveKey(ARG_KEY key)
  1221. // remove key - return TRUE if removed
  1222. {
  1223. ASSERT_VALID(this);
  1224. if (m_pHashTable == NULL)
  1225. return FALSE; // nothing in the table
  1226. CAssoc** ppAssocPrev;
  1227. ppAssocPrev = &m_pHashTable[HashKey<ARG_KEY>(key) % m_nHashTableSize];
  1228. CAssoc* pAssoc;
  1229. for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext)
  1230. {
  1231. if (CompareElements(&pAssoc->key, &key))
  1232. {
  1233. // remove it
  1234. *ppAssocPrev = pAssoc->pNext; // remove from list
  1235. FreeAssoc(pAssoc);
  1236. return TRUE;
  1237. }
  1238. ppAssocPrev = &pAssoc->pNext;
  1239. }
  1240. return FALSE; // not found
  1241. }
  1242. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1243. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetNextAssoc(POSITION& rNextPosition,
  1244. KEY& rKey, VALUE& rValue) const
  1245. {
  1246. ASSERT_VALID(this);
  1247. ASSERT(m_pHashTable != NULL); // never call on empty map
  1248. CAssoc* pAssocRet = (CAssoc*)rNextPosition;
  1249. ASSERT(pAssocRet != NULL);
  1250. if (pAssocRet == (CAssoc*) BEFORE_START_POSITION)
  1251. {
  1252. // find the first association
  1253. for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
  1254. if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
  1255. break;
  1256. ASSERT(pAssocRet != NULL); // must find something
  1257. }
  1258. // find next association
  1259. ASSERT(AfxIsValidAddress(pAssocRet, sizeof(CAssoc)));
  1260. CAssoc* pAssocNext;
  1261. if ((pAssocNext = pAssocRet->pNext) == NULL)
  1262. {
  1263. // go to next bucket
  1264. for (UINT nBucket = pAssocRet->nHashValue + 1;
  1265. nBucket < m_nHashTableSize; nBucket++)
  1266. if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
  1267. break;
  1268. }
  1269. rNextPosition = (POSITION) pAssocNext;
  1270. // fill in return data
  1271. rKey = pAssocRet->key;
  1272. rValue = pAssocRet->value;
  1273. }
  1274. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1275. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Serialize(CArchive& ar)
  1276. {
  1277. ASSERT_VALID(this);
  1278. CObject::Serialize(ar);
  1279. if (ar.IsStoring())
  1280. {
  1281. ar.WriteCount(m_nCount);
  1282. if (m_nCount == 0)
  1283. return; // nothing more to do
  1284. ASSERT(m_pHashTable != NULL);
  1285. for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
  1286. {
  1287. CAssoc* pAssoc;
  1288. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
  1289. pAssoc = pAssoc->pNext)
  1290. {
  1291. SerializeElements<KEY>(ar, &pAssoc->key, 1);
  1292. SerializeElements<VALUE>(ar, &pAssoc->value, 1);
  1293. }
  1294. }
  1295. }
  1296. else
  1297. {
  1298. DWORD_PTR nNewCount = ar.ReadCount();
  1299. while (nNewCount--)
  1300. {
  1301. KEY newKey;
  1302. VALUE newValue;
  1303. SerializeElements<KEY>(ar, &newKey, 1);
  1304. SerializeElements<VALUE>(ar, &newValue, 1);
  1305. SetAt(newKey, newValue);
  1306. }
  1307. }
  1308. }
  1309. #ifdef _DEBUG
  1310. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1311. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Dump(CDumpContext& dc) const
  1312. {
  1313. CObject::Dump(dc);
  1314. dc << "with " << m_nCount << " elements";
  1315. if (dc.GetDepth() > 0)
  1316. {
  1317. // Dump in format "[key] -> value"
  1318. KEY key;
  1319. VALUE val;
  1320. POSITION pos = GetStartPosition();
  1321. while (pos != NULL)
  1322. {
  1323. GetNextAssoc(pos, key, val);
  1324. dc << "\n\t[";
  1325. DumpElements<KEY>(dc, &key, 1);
  1326. dc << "] = ";
  1327. DumpElements<VALUE>(dc, &val, 1);
  1328. }
  1329. }
  1330. dc << "\n";
  1331. }
  1332. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  1333. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::AssertValid() const
  1334. {
  1335. CObject::AssertValid();
  1336. ASSERT(m_nHashTableSize > 0);
  1337. ASSERT(m_nCount == 0 || m_pHashTable != NULL);
  1338. // non-empty map should have hash table
  1339. }
  1340. #endif //_DEBUG
  1341. /////////////////////////////////////////////////////////////////////////////
  1342. // CTypedPtrArray<BASE_CLASS, TYPE>
  1343. template<class BASE_CLASS, class TYPE>
  1344. class CTypedPtrArray : public BASE_CLASS
  1345. {
  1346. public:
  1347. // Accessing elements
  1348. TYPE GetAt(INT_PTR nIndex) const
  1349. { return (TYPE)BASE_CLASS::GetAt(nIndex); }
  1350. TYPE& ElementAt(INT_PTR nIndex)
  1351. { return (TYPE&)BASE_CLASS::ElementAt(nIndex); }
  1352. void SetAt(INT_PTR nIndex, TYPE ptr)
  1353. { BASE_CLASS::SetAt(nIndex, ptr); }
  1354. // Potentially growing the array
  1355. void SetAtGrow(INT_PTR nIndex, TYPE newElement)
  1356. { BASE_CLASS::SetAtGrow(nIndex, newElement); }
  1357. INT_PTR Add(TYPE newElement)
  1358. { return BASE_CLASS::Add(newElement); }
  1359. INT_PTR Append(const CTypedPtrArray<BASE_CLASS, TYPE>& src)
  1360. { return BASE_CLASS::Append(src); }
  1361. void Copy(const CTypedPtrArray<BASE_CLASS, TYPE>& src)
  1362. { BASE_CLASS::Copy(src); }
  1363. // Operations that move elements around
  1364. void InsertAt(INT_PTR nIndex, TYPE newElement, INT_PTR nCount = 1)
  1365. { BASE_CLASS::InsertAt(nIndex, newElement, nCount); }
  1366. void InsertAt(INT_PTR nStartIndex, CTypedPtrArray<BASE_CLASS, TYPE>* pNewArray)
  1367. { BASE_CLASS::InsertAt(nStartIndex, pNewArray); }
  1368. // overloaded operator helpers
  1369. TYPE operator[](INT_PTR nIndex) const
  1370. { return (TYPE)BASE_CLASS::operator[](nIndex); }
  1371. TYPE& operator[](INT_PTR nIndex)
  1372. { return (TYPE&)BASE_CLASS::operator[](nIndex); }
  1373. };
  1374. /////////////////////////////////////////////////////////////////////////////
  1375. // CTypedPtrList<BASE_CLASS, TYPE>
  1376. template<class BASE_CLASS, class TYPE>
  1377. #if _MFC_VER >= 0x600
  1378. class _CTypedPtrList : public BASE_CLASS
  1379. #else
  1380. class CTypedPtrList : public BASE_CLASS
  1381. #endif
  1382. {
  1383. public:
  1384. // Construction
  1385. #if _MFC_VER >= 0x0600
  1386. _CTypedPtrList(int nBlockSize = 10)
  1387. #else
  1388. CTypedPtrList(int nBlockSize = 10)
  1389. #endif
  1390. : BASE_CLASS(nBlockSize) { }
  1391. // peek at head or tail
  1392. TYPE& GetHead()
  1393. { return (TYPE&)BASE_CLASS::GetHead(); }
  1394. TYPE GetHead() const
  1395. { return (TYPE)BASE_CLASS::GetHead(); }
  1396. TYPE& GetTail()
  1397. { return (TYPE&)BASE_CLASS::GetTail(); }
  1398. TYPE GetTail() const
  1399. { return (TYPE)BASE_CLASS::GetTail(); }
  1400. // get head or tail (and remove it) - don't call on empty list!
  1401. TYPE RemoveHead()
  1402. { return (TYPE)BASE_CLASS::RemoveHead(); }
  1403. TYPE RemoveTail()
  1404. { return (TYPE)BASE_CLASS::RemoveTail(); }
  1405. #if _MFC_VER < 0x0600
  1406. // add before head or after tail
  1407. POSITION AddHead(TYPE newElement)
  1408. { return BASE_CLASS::AddHead(newElement); }
  1409. POSITION AddTail(TYPE newElement)
  1410. { return BASE_CLASS::AddTail(newElement); }
  1411. // add another list of elements before head or after tail
  1412. void AddHead(CTypedPtrList<BASE_CLASS, TYPE>* pNewList)
  1413. { BASE_CLASS::AddHead(pNewList); }
  1414. void AddTail(CTypedPtrList<BASE_CLASS, TYPE>* pNewList)
  1415. { BASE_CLASS::AddTail(pNewList); }
  1416. #endif
  1417. // iteration
  1418. TYPE& GetNext(POSITION& rPosition)
  1419. { return (TYPE&)BASE_CLASS::GetNext(rPosition); }
  1420. TYPE GetNext(POSITION& rPosition) const
  1421. { return (TYPE)BASE_CLASS::GetNext(rPosition); }
  1422. TYPE& GetPrev(POSITION& rPosition)
  1423. { return (TYPE&)BASE_CLASS::GetPrev(rPosition); }
  1424. TYPE GetPrev(POSITION& rPosition) const
  1425. { return (TYPE)BASE_CLASS::GetPrev(rPosition); }
  1426. // getting/modifying an element at a given position
  1427. TYPE& GetAt(POSITION position)
  1428. { return (TYPE&)BASE_CLASS::GetAt(position); }
  1429. TYPE GetAt(POSITION position) const
  1430. { return (TYPE)BASE_CLASS::GetAt(position); }
  1431. void SetAt(POSITION pos, TYPE newElement)
  1432. { BASE_CLASS::SetAt(pos, newElement); }
  1433. };
  1434. #if _MFC_VER >= 0x0600
  1435. template<class BASE_CLASS, class TYPE>
  1436. class CTypedPtrList : public _CTypedPtrList<BASE_CLASS, TYPE>
  1437. {
  1438. public:
  1439. // Construction
  1440. CTypedPtrList(int nBlockSize = 10)
  1441. : _CTypedPtrList<BASE_CLASS, TYPE>(nBlockSize) { }
  1442. // add before head or after tail
  1443. POSITION AddHead(TYPE newElement)
  1444. { return BASE_CLASS::AddHead(newElement); }
  1445. POSITION AddTail(TYPE newElement)
  1446. { return BASE_CLASS::AddTail(newElement); }
  1447. // add another list of elements before head or after tail
  1448. void AddHead(CTypedPtrList<BASE_CLASS, TYPE>* pNewList)
  1449. { BASE_CLASS::AddHead(pNewList); }
  1450. void AddTail(CTypedPtrList<BASE_CLASS, TYPE>* pNewList)
  1451. { BASE_CLASS::AddTail(pNewList); }
  1452. };
  1453. // need specialized version for CObList because of AddHead/Tail ambiguity
  1454. template<> class CTypedPtrList<CObList, CObList*>
  1455. : public _CTypedPtrList<CObList, CObList*>
  1456. {
  1457. public:
  1458. // Construction
  1459. CTypedPtrList(int nBlockSize = 10)
  1460. : _CTypedPtrList<CObList, CObList*>(nBlockSize) { }
  1461. // add before head or after tail
  1462. POSITION AddHead(CObList* newElement)
  1463. { return _CTypedPtrList<CObList, CObList*>::AddHead((CObject*)newElement); }
  1464. POSITION AddTail(CObList* newElement)
  1465. { return _CTypedPtrList<CObList, CObList*>::AddTail((CObject*)newElement); }
  1466. // add another list of elements before head or after tail
  1467. void AddHead(CTypedPtrList<CObList, CObList*>* pNewList)
  1468. { _CTypedPtrList<CObList, CObList*>::AddHead(pNewList); }
  1469. void AddTail(CTypedPtrList<CObList, CObList*>* pNewList)
  1470. { _CTypedPtrList<CObList, CObList*>::AddTail(pNewList); }
  1471. };
  1472. // need specialized version for CPtrList because of AddHead/Tail ambiguity
  1473. template<> class CTypedPtrList<CPtrList, CPtrList*>
  1474. : public _CTypedPtrList<CPtrList, CPtrList*>
  1475. {
  1476. public:
  1477. // Construction
  1478. CTypedPtrList(int nBlockSize = 10)
  1479. : _CTypedPtrList<CPtrList, CPtrList*>(nBlockSize) { }
  1480. // add before head or after tail
  1481. POSITION AddHead(CPtrList* newElement)
  1482. { return _CTypedPtrList<CPtrList, CPtrList*>::AddHead((void*)newElement); }
  1483. POSITION AddTail(CPtrList* newElement)
  1484. { return _CTypedPtrList<CPtrList, CPtrList*>::AddTail((void*)newElement); }
  1485. // add another list of elements before head or after tail
  1486. void AddHead(CTypedPtrList<CPtrList, CPtrList*>* pNewList)
  1487. { _CTypedPtrList<CPtrList, CPtrList*>::AddHead(pNewList); }
  1488. void AddTail(CTypedPtrList<CPtrList, CPtrList*>* pNewList)
  1489. { _CTypedPtrList<CPtrList, CPtrList*>::AddTail(pNewList); }
  1490. };
  1491. #endif
  1492. /////////////////////////////////////////////////////////////////////////////
  1493. // CTypedPtrMap<BASE_CLASS, KEY, VALUE>
  1494. template<class BASE_CLASS, class KEY, class VALUE>
  1495. class CTypedPtrMap : public BASE_CLASS
  1496. {
  1497. public:
  1498. // Construction
  1499. CTypedPtrMap(int nBlockSize = 10)
  1500. : BASE_CLASS(nBlockSize) { }
  1501. // Lookup
  1502. BOOL Lookup(typename BASE_CLASS::BASE_ARG_KEY key, VALUE& rValue) const
  1503. { return BASE_CLASS::Lookup(key, (BASE_CLASS::BASE_VALUE&)rValue); }
  1504. // Lookup and add if not there
  1505. VALUE& operator[](typename BASE_CLASS::BASE_ARG_KEY key)
  1506. { return (VALUE&)BASE_CLASS::operator[](key); }
  1507. // add a new key (key, value) pair
  1508. void SetAt(KEY key, VALUE newValue)
  1509. { BASE_CLASS::SetAt(key, newValue); }
  1510. // removing existing (key, ?) pair
  1511. BOOL RemoveKey(KEY key)
  1512. { return BASE_CLASS::RemoveKey(key); }
  1513. // iteration
  1514. void GetNextAssoc(POSITION& rPosition, KEY& rKey, VALUE& rValue) const
  1515. { BASE_CLASS::GetNextAssoc(rPosition, (BASE_CLASS::BASE_KEY&)rKey,
  1516. (BASE_CLASS::BASE_VALUE&)rValue); }
  1517. };
  1518. /////////////////////////////////////////////////////////////////////////////
  1519. #undef THIS_FILE
  1520. #define THIS_FILE __FILE__
  1521. #undef new
  1522. #ifdef _REDEF_NEW
  1523. #define new DEBUG_NEW
  1524. #undef _REDEF_NEW
  1525. #endif
  1526. #ifdef _AFX_PACKING
  1527. #pragma pack(pop)
  1528. #endif
  1529. #ifdef _AFX_MINREBUILD
  1530. #pragma component(minrebuild, on)
  1531. #endif
  1532. #ifndef _AFX_FULLTYPEINFO
  1533. #pragma component(mintypeinfo, off)
  1534. #endif
  1535. #endif //__AFXTEMPL_H__
  1536. /////////////////////////////////////////////////////////////////////////////