afxtempl.h 47 KB

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