MAP.CTT
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:15k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////////
  2. // class CMap - a mapping from 'KEY's to 'VALUE's, passed in as
  3. // ARG_KEY and/or ARG_VALUE parameters.
  4. //
  5. // optional definitions:
  6. //  IS_SERIAL   - enable serialization through CArchive extraction & insertion
  7. //  HAS_CREATE  - call constructors and destructors
  8. //
  9. // This is a part of the Microsoft Foundation Classes C++ library.
  10. // Copyright (C) 1994-1998 Microsoft Corporation
  11. // All rights reserved.
  12. //
  13. // This source code is only intended as a supplement to the
  14. // Microsoft Foundation Classes Reference and related
  15. // electronic documentation provided with the library.
  16. // See these sources for detailed information regarding the
  17. // Microsoft Foundation Classes product.
  18. /////////////////////////////////////////////////////////////////////////////
  19. //$DECLARE_TEMPLATE
  20. /////////////////////////////////////////////////////////////////////////////
  21. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  22. class CMap : public CObject
  23. {
  24. $ifdef IS_SERIAL
  25. DECLARE_SERIAL(CMap)
  26. $else
  27. DECLARE_DYNAMIC(CMap)
  28. $endif //!IS_SERIAL
  29. protected:
  30. // Association
  31. struct CAssoc
  32. {
  33. CAssoc* pNext;
  34. $ifdef CACHE_HASH
  35. UINT nHashValue;  // needed for efficient iteration
  36. $endif
  37. KEY key;
  38. VALUE value;
  39. };
  40. public:
  41. // Construction
  42. CMap(int nBlockSize = 10);
  43. // Attributes
  44. // number of elements
  45. int GetCount() const;
  46. BOOL IsEmpty() const;
  47. // Lookup
  48. BOOL Lookup(ARG_KEY key, VALUE& rValue) const;
  49. // Operations
  50. // Lookup and add if not there
  51. VALUE& operator[](ARG_KEY key);
  52. // add a new (key, value) pair
  53. void SetAt(ARG_KEY key, ARG_VALUE newValue);
  54. // removing existing (key, ?) pair
  55. BOOL RemoveKey(ARG_KEY key);
  56. void RemoveAll();
  57. // iterating all (key, value) pairs
  58. POSITION GetStartPosition() const;
  59. void GetNextAssoc(POSITION& rNextPosition, KEY& rKey, VALUE& rValue) const;
  60. // advanced features for derived classes
  61. UINT GetHashTableSize() const;
  62. void InitHashTable(UINT hashSize, BOOL bAllocNow = TRUE);
  63. // Overridables: special non-virtual (see map implementation for details)
  64. // Routine used to user-provided hash keys
  65. UINT HashKey(ARG_KEY key) const;
  66. // Implementation
  67. protected:
  68. CAssoc** m_pHashTable;
  69. UINT m_nHashTableSize;
  70. int m_nCount;
  71. CAssoc* m_pFreeList;
  72. struct CPlex* m_pBlocks;
  73. int m_nBlockSize;
  74. CAssoc* NewAssoc();
  75. void FreeAssoc(CAssoc*);
  76. CAssoc* GetAssocAt(ARG_KEY, UINT&) const;
  77. public:
  78. ~CMap();
  79. $ifdef IS_SERIAL
  80. void Serialize(CArchive&);
  81. $endif //IS_SERIAL
  82. #ifdef _DEBUG
  83. void Dump(CDumpContext&) const;
  84. void AssertValid() const;
  85. #endif
  86. $ifdef INCLUDE_GETVALUEAT
  87. VALUE GetValueAt(ARG_KEY key) const;
  88. $endif
  89. protected:
  90. // local typedefs for CTypedPtrMap class template
  91. typedef KEY BASE_KEY;
  92. typedef ARG_KEY BASE_ARG_KEY;
  93. typedef VALUE BASE_VALUE;
  94. typedef ARG_VALUE BASE_ARG_VALUE;
  95. };
  96. //$IMPLEMENT_TEMPLATE_INLINES
  97. ////////////////////////////////////////////////////////////////////////////
  98. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  99. _AFXCOLL_INLINE int CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetCount() const
  100. { return m_nCount; }
  101. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  102. _AFXCOLL_INLINE BOOL CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::IsEmpty() const
  103. { return m_nCount == 0; }
  104. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  105. _AFXCOLL_INLINE void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::SetAt(ARG_KEY key, ARG_VALUE newValue)
  106. { (*this)[key] = newValue; }
  107. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  108. _AFXCOLL_INLINE POSITION CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetStartPosition() const
  109. { return (m_nCount == 0) ? NULL : BEFORE_START_POSITION; }
  110. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  111. _AFXCOLL_INLINE UINT CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetHashTableSize() const
  112. { return m_nHashTableSize; }
  113. //$IMPLEMENT_TEMPLATE
  114. // This is a part of the Microsoft Foundation Classes C++ library.
  115. // Copyright (C) 1992-1997 Microsoft Corporation
  116. // All rights reserved.
  117. //
  118. // This source code is only intended as a supplement to the
  119. // Microsoft Foundation Classes Reference and related
  120. // electronic documentation provided with the library.
  121. // See these sources for detailed information regarding the
  122. // Microsoft Foundation Classes product.
  123. /////////////////////////////////////////////////////////////////////////////
  124. //
  125. // Implementation of parmeterized Map
  126. //
  127. /////////////////////////////////////////////////////////////////////////////
  128. #include "stdafx.h"
  129. #ifdef AFX_COLL2_SEG
  130. #pragma code_seg(AFX_COLL2_SEG)
  131. #endif
  132. #ifdef _DEBUG
  133. #undef THIS_FILE
  134. static char THIS_FILE[] = __FILE__;
  135. #endif
  136. $ifdef HAS_CREATE
  137. #include "elements.h"  // used for special creation
  138. $endif
  139. #define new DEBUG_NEW
  140. /////////////////////////////////////////////////////////////////////////////
  141. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  142. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CMap(int nBlockSize)
  143. {
  144. ASSERT(nBlockSize > 0);
  145. m_pHashTable = NULL;
  146. m_nHashTableSize = 17;  // default size
  147. m_nCount = 0;
  148. m_pFreeList = NULL;
  149. m_pBlocks = NULL;
  150. m_nBlockSize = nBlockSize;
  151. }
  152. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  153. inline UINT CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::HashKey(ARG_KEY key) const
  154. {
  155. // default identity hash - works for most primitive values
  156. return ((UINT)(void*)(DWORD)key) >> 4;
  157. }
  158. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  159. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::InitHashTable(
  160. UINT nHashSize, BOOL bAllocNow)
  161. //
  162. // Used to force allocation of a hash table or to override the default
  163. //   hash table size of (which is fairly small)
  164. {
  165. ASSERT_VALID(this);
  166. ASSERT(m_nCount == 0);
  167. ASSERT(nHashSize > 0);
  168. if (m_pHashTable != NULL)
  169. {
  170. // free hash table
  171. delete[] m_pHashTable;
  172. m_pHashTable = NULL;
  173. }
  174. if (bAllocNow)
  175. {
  176. m_pHashTable = new CAssoc* [nHashSize];
  177. memset(m_pHashTable, 0, sizeof(CAssoc*) * nHashSize);
  178. }
  179. m_nHashTableSize = nHashSize;
  180. }
  181. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  182. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveAll()
  183. {
  184. ASSERT_VALID(this);
  185. $ifdef HAS_CREATE
  186. if (m_pHashTable != NULL)
  187. {
  188. // destroy elements (values only)
  189. for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
  190. {
  191. CAssoc* pAssoc;
  192. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
  193.   pAssoc = pAssoc->pNext)
  194. {
  195. DestructElement(&pAssoc->value);
  196. }
  197. }
  198. }
  199. $endif
  200. if (m_pHashTable != NULL)
  201. {
  202. // free hash table
  203. delete[] m_pHashTable;
  204. m_pHashTable = NULL;
  205. }
  206. m_nCount = 0;
  207. m_pFreeList = NULL;
  208. m_pBlocks->FreeDataChain();
  209. m_pBlocks = NULL;
  210. }
  211. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  212. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::~CMap()
  213. {
  214. RemoveAll();
  215. ASSERT(m_nCount == 0);
  216. }
  217. /////////////////////////////////////////////////////////////////////////////
  218. // Assoc helpers
  219. // same as CList implementation except we store CAssoc's not CNode's
  220. //    and CAssoc's are singly linked all the time
  221. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  222. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
  223. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::NewAssoc()
  224. {
  225. if (m_pFreeList == NULL)
  226. {
  227. // add another block
  228. CPlex* newBlock = CPlex::Create(m_pBlocks, m_nBlockSize, sizeof(CMap::CAssoc));
  229. // chain them into free list
  230. CMap::CAssoc* pAssoc = (CMap::CAssoc*) newBlock->data();
  231. // free in reverse order to make it easier to debug
  232. pAssoc += m_nBlockSize - 1;
  233. for (int i = m_nBlockSize-1; i >= 0; i--, pAssoc--)
  234. {
  235. pAssoc->pNext = m_pFreeList;
  236. m_pFreeList = pAssoc;
  237. }
  238. }
  239. ASSERT(m_pFreeList != NULL);  // we must have something
  240. CMap::CAssoc* pAssoc = m_pFreeList;
  241. m_pFreeList = m_pFreeList->pNext;
  242. m_nCount++;
  243. ASSERT(m_nCount > 0);  // make sure we don't overflow
  244. $ifdef USE_MEMSET_KEY
  245. memset(&pAssoc->key, 0, sizeof(KEY));
  246. $endif
  247. $ifdef USE_ASSIGN_KEY
  248. pAssoc->key = 0;
  249. $endif
  250. $ifdef HAS_CREATE
  251. ConstructElement(&pAssoc->value);   // special construct values
  252. $endif
  253. $ifdef USE_MEMSET
  254. memset(&pAssoc->value, 0, sizeof(VALUE));
  255. $endif
  256. $ifdef USE_ASSIGN
  257. pAssoc->value = 0;
  258. $endif
  259. return pAssoc;
  260. }
  261. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  262. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::FreeAssoc(CMap::CAssoc* pAssoc)
  263. {
  264. $ifdef HAS_CREATE
  265. DestructElement(&pAssoc->value);
  266. $endif
  267. pAssoc->pNext = m_pFreeList;
  268. m_pFreeList = pAssoc;
  269. m_nCount--;
  270. ASSERT(m_nCount >= 0);  // make sure we don't underflow
  271. // if no more elements, cleanup completely
  272. if (m_nCount == 0)
  273. RemoveAll();
  274. }
  275. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  276. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
  277. CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetAssocAt(ARG_KEY key, UINT& nHash) const
  278. // find association (or return NULL)
  279. {
  280. nHash = HashKey(key) % m_nHashTableSize;
  281. if (m_pHashTable == NULL)
  282. return NULL;
  283. // see if it exists
  284. CAssoc* pAssoc;
  285. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
  286. {
  287. if (pAssoc->key == key)
  288. return pAssoc;
  289. }
  290. return NULL;
  291. }
  292. $ifdef INCLUDE_GETVALUEAT
  293. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  294. VALUE CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetValueAt(ARG_KEY key) const
  295. // find value (or return NULL -- NULL values not different as a result)
  296. {
  297. if (m_pHashTable == NULL)
  298. return NULL;
  299. UINT nHash = HashKey(key) % m_nHashTableSize;
  300. // see if it exists
  301. CAssoc* pAssoc;
  302. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
  303. {
  304. if (pAssoc->key == key)
  305. return pAssoc->value;
  306. }
  307. return NULL;
  308. }
  309. $endif
  310. /////////////////////////////////////////////////////////////////////////////
  311. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  312. BOOL CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Lookup(ARG_KEY key, VALUE& rValue) const
  313. {
  314. ASSERT_VALID(this);
  315. UINT nHash;
  316. CAssoc* pAssoc = GetAssocAt(key, nHash);
  317. if (pAssoc == NULL)
  318. return FALSE;  // not in map
  319. rValue = pAssoc->value;
  320. return TRUE;
  321. }
  322. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  323. VALUE& CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::operator[](ARG_KEY key)
  324. {
  325. ASSERT_VALID(this);
  326. UINT nHash;
  327. CAssoc* pAssoc;
  328. if ((pAssoc = GetAssocAt(key, nHash)) == NULL)
  329. {
  330. if (m_pHashTable == NULL)
  331. InitHashTable(m_nHashTableSize);
  332. // it doesn't exist, add a new Association
  333. pAssoc = NewAssoc();
  334. $ifdef CACHE_HASH
  335. pAssoc->nHashValue = nHash;
  336. $endif
  337. pAssoc->key = key;
  338. // 'pAssoc->value' is a constructed object, nothing more
  339. // put into hash table
  340. pAssoc->pNext = m_pHashTable[nHash];
  341. m_pHashTable[nHash] = pAssoc;
  342. }
  343. return pAssoc->value;  // return new reference
  344. }
  345. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  346. BOOL CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::RemoveKey(ARG_KEY key)
  347. // remove key - return TRUE if removed
  348. {
  349. ASSERT_VALID(this);
  350. if (m_pHashTable == NULL)
  351. return FALSE;  // nothing in the table
  352. CAssoc** ppAssocPrev;
  353. ppAssocPrev = &m_pHashTable[HashKey(key) % m_nHashTableSize];
  354. CAssoc* pAssoc;
  355. for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext)
  356. {
  357. if (pAssoc->key == key)
  358. {
  359. // remove it
  360. *ppAssocPrev = pAssoc->pNext;  // remove from list
  361. FreeAssoc(pAssoc);
  362. return TRUE;
  363. }
  364. ppAssocPrev = &pAssoc->pNext;
  365. }
  366. return FALSE;  // not found
  367. }
  368. /////////////////////////////////////////////////////////////////////////////
  369. // Iterating
  370. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  371. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetNextAssoc(POSITION& rNextPosition,
  372. KEY& rKey, VALUE& rValue) const
  373. {
  374. ASSERT_VALID(this);
  375. ASSERT(m_pHashTable != NULL);  // never call on empty map
  376. CAssoc* pAssocRet = (CAssoc*)rNextPosition;
  377. ASSERT(pAssocRet != NULL);
  378. if (pAssocRet == (CAssoc*) BEFORE_START_POSITION)
  379. {
  380. // find the first association
  381. for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
  382. if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
  383. break;
  384. ASSERT(pAssocRet != NULL);  // must find something
  385. }
  386. // find next association
  387. ASSERT(AfxIsValidAddress(pAssocRet, sizeof(CAssoc)));
  388. CAssoc* pAssocNext;
  389. if ((pAssocNext = pAssocRet->pNext) == NULL)
  390. {
  391. // go to next bucket
  392. $ifdef CACHE_HASH
  393. for (UINT nBucket = pAssocRet->nHashValue + 1;
  394. $else
  395. for (UINT nBucket = (HashKey(pAssocRet->key) % m_nHashTableSize) + 1;
  396. $endif
  397.   nBucket < m_nHashTableSize; nBucket++)
  398. if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
  399. break;
  400. }
  401. rNextPosition = (POSITION) pAssocNext;
  402. // fill in return data
  403. rKey = pAssocRet->key;
  404. rValue = pAssocRet->value;
  405. }
  406. $ifdef IS_SERIAL
  407. /////////////////////////////////////////////////////////////////////////////
  408. // Serialization
  409. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  410. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Serialize(CArchive& ar)
  411. {
  412. ASSERT_VALID(this);
  413. CObject::Serialize(ar);
  414. if (ar.IsStoring())
  415. {
  416. ar.WriteCount(m_nCount);
  417. if (m_nCount == 0)
  418. return;  // nothing more to do
  419. ASSERT(m_pHashTable != NULL);
  420. for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
  421. {
  422. CAssoc* pAssoc;
  423. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
  424.   pAssoc = pAssoc->pNext)
  425. {
  426. ar << pAssoc->key;
  427. ar << pAssoc->value;
  428. }
  429. }
  430. }
  431. else
  432. {
  433. DWORD nNewCount = ar.ReadCount();
  434. KEY newKey;
  435. VALUE newValue;
  436. while (nNewCount--)
  437. {
  438. ar >> newKey;
  439. ar >> newValue;
  440. SetAt(newKey, newValue);
  441. }
  442. }
  443. }
  444. $endif //IS_SERIAL
  445. /////////////////////////////////////////////////////////////////////////////
  446. // Diagnostics
  447. #ifdef _DEBUG
  448. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  449. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Dump(CDumpContext& dc) const
  450. {
  451. CObject::Dump(dc);
  452. dc << "with " << m_nCount << " elements";
  453. if (dc.GetDepth() > 0)
  454. {
  455. // Dump in format "[key] -> value"
  456. KEY key;
  457. VALUE val;
  458. POSITION pos = GetStartPosition();
  459. while (pos != NULL)
  460. {
  461. GetNextAssoc(pos, key, val);
  462. dc << "nt[" << key << "] = " << val;
  463. }
  464. }
  465. dc << "n";
  466. }
  467. template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
  468. void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::AssertValid() const
  469. {
  470. CObject::AssertValid();
  471. ASSERT(m_nHashTableSize > 0);
  472. ASSERT(m_nCount == 0 || m_pHashTable != NULL);
  473. // non-empty map should have hash table
  474. }
  475. #endif //_DEBUG
  476. #ifdef AFX_INIT_SEG
  477. #pragma code_seg(AFX_INIT_SEG)
  478. #endif
  479. $ifdef IS_SERIAL
  480. IMPLEMENT_SERIAL(CMap, CObject, 0)
  481. $else
  482. IMPLEMENT_DYNAMIC(CMap, CObject)
  483. $endif //!IS_SERIAL
  484. /////////////////////////////////////////////////////////////////////////////