Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

667 lines
14 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // class CMapKeyToValue - a mapping from 'KEY's to 'VALUE's, passed in as
  3. // pv/cb pairs. The keys can be variable length, although we optmizize the
  4. // case when they are all the same.
  5. //
  6. /////////////////////////////////////////////////////////////////////////////
  7. #include <le2int.h>
  8. #pragma SEG(map_kv)
  9. #include "map_kv.h"
  10. #include "valid.h"
  11. #include "plex.h"
  12. ASSERTDATA
  13. /////////////////////////////////////////////////////////////////////////////
  14. #pragma SEG(CMapKeyToValue_ctor)
  15. CMapKeyToValue::CMapKeyToValue(UINT cbValue, UINT cbKey,
  16. int nBlockSize, LPFNHASHKEY lpfnHashKey, UINT nHashSize)
  17. {
  18. VDATEHEAP();
  19. Assert(nBlockSize > 0);
  20. m_cbValue = cbValue;
  21. m_cbKey = cbKey;
  22. m_cbKeyInAssoc = cbKey == 0 ? sizeof(CKeyWrap) : cbKey;
  23. m_pHashTable = NULL;
  24. m_nHashTableSize = nHashSize;
  25. m_lpfnHashKey = lpfnHashKey;
  26. m_nCount = 0;
  27. m_pFreeList = NULL;
  28. m_pBlocks = NULL;
  29. m_nBlockSize = nBlockSize;
  30. }
  31. #pragma SEG(CMapKeyToValue_dtor)
  32. CMapKeyToValue::~CMapKeyToValue()
  33. {
  34. VDATEHEAP();
  35. ASSERT_VALID(this);
  36. RemoveAll();
  37. Assert(m_nCount == 0);
  38. }
  39. #define LOCKTHIS
  40. #define UNLOCKTHIS
  41. #ifdef NEVER
  42. void CMapKeyToValue::LockThis(void)
  43. {
  44. VDATEHEAP();
  45. LOCKTHIS;
  46. }
  47. void CMapKeyToValue::UnlockThis(void)
  48. {
  49. VDATEHEAP();
  50. UNLOCKTHIS;
  51. }
  52. #endif //NEVER
  53. #pragma SEG(MKVDefaultHashKey)
  54. // simple, default hash function
  55. // REVIEW: need to check the value in this for GUIDs and strings
  56. STDAPI_(UINT) MKVDefaultHashKey(LPVOID pKey, UINT cbKey)
  57. {
  58. VDATEHEAP();
  59. UINT hash = 0;
  60. BYTE FAR* lpb = (BYTE FAR*)pKey;
  61. while (cbKey-- != 0)
  62. hash = 257 * hash + *lpb++;
  63. return hash;
  64. }
  65. #pragma SEG(CMapKeyToValue_InitHashTable)
  66. BOOL CMapKeyToValue::InitHashTable()
  67. {
  68. VDATEHEAP();
  69. ASSERT_VALID(this);
  70. Assert(m_nHashTableSize > 0);
  71. if (m_pHashTable != NULL)
  72. return TRUE;
  73. Assert(m_nCount == 0);
  74. if ((m_pHashTable = (CAssoc FAR* FAR*)PrivMemAlloc(m_nHashTableSize *
  75. sizeof(CAssoc FAR*))) == NULL)
  76. return FALSE;
  77. _xmemset(m_pHashTable, 0, sizeof(CAssoc FAR*) * m_nHashTableSize);
  78. ASSERT_VALID(this);
  79. return TRUE;
  80. }
  81. #pragma SEG(CMapKeyToValue_RemoveAll)
  82. void CMapKeyToValue::RemoveAll()
  83. {
  84. VDATEHEAP();
  85. LOCKTHIS;
  86. ASSERT_VALID(this);
  87. // free all key values and then hash table
  88. if (m_pHashTable != NULL)
  89. {
  90. // destroy assocs
  91. for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
  92. {
  93. register CAssoc FAR* pAssoc;
  94. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
  95. pAssoc = pAssoc->pNext)
  96. // assoc itself is freed by FreeDataChain below
  97. FreeAssocKey(pAssoc);
  98. }
  99. // free hash table
  100. PrivMemFree(m_pHashTable);
  101. m_pHashTable = NULL;
  102. }
  103. m_nCount = 0;
  104. m_pFreeList = NULL;
  105. m_pBlocks->FreeDataChain();
  106. m_pBlocks = NULL;
  107. ASSERT_VALID(this);
  108. UNLOCKTHIS;
  109. }
  110. /////////////////////////////////////////////////////////////////////////////
  111. // Assoc helpers
  112. // CAssoc's are singly linked all the time
  113. #pragma SEG(CMapKeyToValue_NewAssoc)
  114. CMapKeyToValue::CAssoc FAR*
  115. CMapKeyToValue::NewAssoc(UINT hash, LPVOID pKey, UINT cbKey, LPVOID pValue)
  116. {
  117. VDATEHEAP();
  118. if (m_pFreeList == NULL)
  119. {
  120. // add another block
  121. CPlex FAR* newBlock = CPlex::Create(m_pBlocks, m_nBlockSize, SizeAssoc());
  122. if (newBlock == NULL)
  123. return NULL;
  124. // chain them into free list
  125. register BYTE FAR* pbAssoc = (BYTE FAR*) newBlock->data();
  126. // free in reverse order to make it easier to debug
  127. pbAssoc += (m_nBlockSize - 1) * SizeAssoc();
  128. for (int i = m_nBlockSize-1; i >= 0; i--, pbAssoc -= SizeAssoc())
  129. {
  130. ((CAssoc FAR*)pbAssoc)->pNext = m_pFreeList;
  131. m_pFreeList = (CAssoc FAR*)pbAssoc;
  132. }
  133. }
  134. Assert(m_pFreeList != NULL); // we must have something
  135. CMapKeyToValue::CAssoc FAR* pAssoc = m_pFreeList;
  136. // init all fields except pNext while still on free list
  137. pAssoc->nHashValue = hash;
  138. if (!SetAssocKey(pAssoc, pKey, cbKey))
  139. return NULL;
  140. SetAssocValue(pAssoc, pValue);
  141. // remove from free list after successfully initializing it (except pNext)
  142. m_pFreeList = m_pFreeList->pNext;
  143. m_nCount++;
  144. Assert(m_nCount > 0); // make sure we don't overflow
  145. return pAssoc;
  146. }
  147. #pragma SEG(CMapKeyToValue_FreeAssoc)
  148. // free individual assoc by freeing key and putting on free list
  149. void CMapKeyToValue::FreeAssoc(CMapKeyToValue::CAssoc FAR* pAssoc)
  150. {
  151. VDATEHEAP();
  152. pAssoc->pNext = m_pFreeList;
  153. m_pFreeList = pAssoc;
  154. m_nCount--;
  155. Assert(m_nCount >= 0); // make sure we don't underflow
  156. FreeAssocKey(pAssoc);
  157. }
  158. #pragma SEG(CMapKeyToValue_GetAssocAt)
  159. // find association (or return NULL)
  160. CMapKeyToValue::CAssoc FAR*
  161. CMapKeyToValue::GetAssocAt(LPVOID pKey, UINT cbKey, UINT FAR& nHash) const
  162. {
  163. VDATEHEAP();
  164. if (m_lpfnHashKey)
  165. nHash = (*m_lpfnHashKey)(pKey, cbKey) % m_nHashTableSize;
  166. else
  167. nHash = MKVDefaultHashKey(pKey, cbKey) % m_nHashTableSize;
  168. if (m_pHashTable == NULL)
  169. return NULL;
  170. // see if it exists
  171. register CAssoc FAR* pAssoc;
  172. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
  173. {
  174. if (CompareAssocKey(pAssoc, pKey, cbKey))
  175. return pAssoc;
  176. }
  177. return NULL;
  178. }
  179. #pragma SEG(CMapKeyToValue_CompareAssocKey)
  180. BOOL CMapKeyToValue::CompareAssocKey(CAssoc FAR* pAssoc, LPVOID pKey2, UINT cbKey2) const
  181. {
  182. VDATEHEAP();
  183. LPVOID pKey1;
  184. UINT cbKey1;
  185. GetAssocKeyPtr(pAssoc, &pKey1, &cbKey1);
  186. return cbKey1 == cbKey2 && _xmemcmp(pKey1, pKey2, cbKey1) == 0;
  187. }
  188. #pragma SEG(CMapKeyToValue_SetAssocKey)
  189. BOOL CMapKeyToValue::SetAssocKey(CAssoc FAR* pAssoc, LPVOID pKey, UINT cbKey) const
  190. {
  191. VDATEHEAP();
  192. Assert(cbKey == m_cbKey || m_cbKey == 0);
  193. if (m_cbKey == 0)
  194. {
  195. Assert(m_cbKeyInAssoc == sizeof(CKeyWrap));
  196. // alloc, set size and pointer
  197. if ((pAssoc->key.pKey = PrivMemAlloc(cbKey)) == NULL)
  198. return FALSE;
  199. pAssoc->key.cbKey = cbKey;
  200. }
  201. LPVOID pKeyTo;
  202. GetAssocKeyPtr(pAssoc, &pKeyTo, &cbKey);
  203. _xmemcpy(pKeyTo, pKey, cbKey);
  204. return TRUE;
  205. }
  206. #pragma SEG(CMapKeyToValue_GetAssocKeyPtr)
  207. // gets pointer to key and its length
  208. void CMapKeyToValue::GetAssocKeyPtr(CAssoc FAR* pAssoc, LPVOID FAR* ppKey,UINT FAR* pcbKey) const
  209. {
  210. VDATEHEAP();
  211. if (m_cbKey == 0)
  212. {
  213. // variable length key; go indirect
  214. *ppKey = pAssoc->key.pKey;
  215. *pcbKey = pAssoc->key.cbKey;
  216. }
  217. else
  218. {
  219. // fixed length key; key in assoc
  220. *ppKey = (LPVOID)&pAssoc->key;
  221. *pcbKey = m_cbKey;
  222. }
  223. }
  224. #pragma SEG(CMapKeyToValue_FreeAssocKey)
  225. void CMapKeyToValue::FreeAssocKey(CAssoc FAR* pAssoc) const
  226. {
  227. VDATEHEAP();
  228. if (m_cbKey == 0)
  229. PrivMemFree(pAssoc->key.pKey);
  230. }
  231. #pragma SEG(CMapKeyToValue_GetAssocValuePtr)
  232. void CMapKeyToValue::GetAssocValuePtr(CAssoc FAR* pAssoc, LPVOID FAR* ppValue) const
  233. {
  234. VDATEHEAP();
  235. *ppValue = (char FAR*)&pAssoc->key + m_cbKeyInAssoc;
  236. }
  237. #pragma SEG(CMapKeyToValue_GetAssocValue)
  238. void CMapKeyToValue::GetAssocValue(CAssoc FAR* pAssoc, LPVOID pValue) const
  239. {
  240. VDATEHEAP();
  241. LPVOID pValueFrom;
  242. GetAssocValuePtr(pAssoc, &pValueFrom);
  243. Assert(pValue != NULL);
  244. _xmemcpy(pValue, pValueFrom, m_cbValue);
  245. }
  246. #pragma SEG(CMapKeyToValue_SetAssocValue)
  247. void CMapKeyToValue::SetAssocValue(CAssoc FAR* pAssoc, LPVOID pValue) const
  248. {
  249. VDATEHEAP();
  250. LPVOID pValueTo;
  251. GetAssocValuePtr(pAssoc, &pValueTo);
  252. if (pValue == NULL)
  253. _xmemset(pValueTo, 0, m_cbValue);
  254. else
  255. _xmemcpy(pValueTo, pValue, m_cbValue);
  256. }
  257. /////////////////////////////////////////////////////////////////////////////
  258. #pragma SEG(CMapKeyToValue_Lookup)
  259. // lookup value given key; return FALSE if key not found; in that
  260. // case, the value is set to all zeros
  261. BOOL CMapKeyToValue::Lookup(LPVOID pKey, UINT cbKey, LPVOID pValue) const
  262. {
  263. VDATEHEAP();
  264. UINT nHash;
  265. BOOL fFound;
  266. LOCKTHIS;
  267. fFound = LookupHKey((HMAPKEY)GetAssocAt(pKey, cbKey, nHash), pValue);
  268. UNLOCKTHIS;
  269. return fFound;
  270. }
  271. #pragma SEG(CMapKeyToValue_LookupHKey)
  272. // lookup value given key; return FALSE if NULL (or bad) key; in that
  273. // case, the value is set to all zeros
  274. BOOL CMapKeyToValue::LookupHKey(HMAPKEY hKey, LPVOID pValue) const
  275. {
  276. VDATEHEAP();
  277. BOOL fFound = FALSE;
  278. LOCKTHIS;
  279. // REVIEW: would like some way to verify that hKey is valid
  280. register CAssoc FAR* pAssoc = (CAssoc FAR*)hKey;
  281. if (pAssoc == NULL)
  282. {
  283. _xmemset(pValue, 0, m_cbValue);
  284. goto Exit; // not in map
  285. }
  286. ASSERT_VALID(this);
  287. GetAssocValue(pAssoc, pValue);
  288. fFound = TRUE;
  289. Exit:
  290. UNLOCKTHIS;
  291. return fFound;
  292. }
  293. #pragma SEG(CMapKeyToValue_LookupAdd)
  294. // lookup and if not found add; returns FALSE only if OOM; if added,
  295. // value added and pointer passed are set to zeros.
  296. BOOL CMapKeyToValue::LookupAdd(LPVOID pKey, UINT cbKey, LPVOID pValue) const
  297. {
  298. VDATEHEAP();
  299. BOOL fFound;
  300. LOCKTHIS;
  301. fFound = Lookup(pKey, cbKey, pValue);
  302. if (!fFound) // value set to zeros since lookup failed
  303. fFound = ((CMapKeyToValue FAR*)this)->SetAt(pKey, cbKey, NULL);
  304. UNLOCKTHIS;
  305. return fFound;
  306. }
  307. #pragma SEG(CMapKeyToValue_SetAt)
  308. // the only place new assocs are created; return FALSE if OOM;
  309. // never returns FALSE if keys already exists
  310. BOOL CMapKeyToValue::SetAt(LPVOID pKey, UINT cbKey, LPVOID pValue)
  311. {
  312. VDATEHEAP();
  313. UINT nHash;
  314. register CAssoc FAR* pAssoc;
  315. BOOL fFound = FALSE;
  316. LOCKTHIS;
  317. ASSERT_VALID(this);
  318. if ((pAssoc = GetAssocAt(pKey, cbKey, nHash)) == NULL)
  319. {
  320. if (!InitHashTable())
  321. // out of memory
  322. goto Exit;
  323. // it doesn't exist, add a new Association
  324. if ((pAssoc = NewAssoc(nHash, pKey, cbKey, pValue)) == NULL)
  325. goto Exit;
  326. // put into hash table
  327. pAssoc->pNext = m_pHashTable[nHash];
  328. m_pHashTable[nHash] = pAssoc;
  329. ASSERT_VALID(this);
  330. }
  331. else
  332. SetAssocValue(pAssoc, pValue);
  333. fFound = TRUE;
  334. Exit:
  335. UNLOCKTHIS;
  336. return fFound;
  337. }
  338. #pragma SEG(CMapKeyToValue_SetAtHKey)
  339. // set existing hkey to value; return FALSE if NULL or bad key
  340. BOOL CMapKeyToValue::SetAtHKey(HMAPKEY hKey, LPVOID pValue)
  341. {
  342. VDATEHEAP();
  343. BOOL fDone = FALSE;
  344. LOCKTHIS;
  345. // REVIEW: would like some way to verify that hKey is valid
  346. register CAssoc FAR* pAssoc = (CAssoc FAR*)hKey;
  347. if (pAssoc == NULL)
  348. goto Exit; // not in map
  349. ASSERT_VALID(this);
  350. SetAssocValue(pAssoc, pValue);
  351. fDone = TRUE;
  352. Exit:
  353. UNLOCKTHIS;
  354. return fDone;
  355. }
  356. #pragma SEG(CMapKeyToValue_RemoveKey)
  357. // remove key - return TRUE if removed
  358. BOOL CMapKeyToValue::RemoveKey(LPVOID pKey, UINT cbKey)
  359. {
  360. VDATEHEAP();
  361. BOOL fFound = FALSE;
  362. UINT i;
  363. LOCKTHIS;
  364. ASSERT_VALID(this);
  365. if (m_pHashTable == NULL)
  366. goto Exit; // nothing in the table
  367. register CAssoc FAR* FAR* ppAssocPrev;
  368. if (m_lpfnHashKey)
  369. i = (*m_lpfnHashKey)(pKey, cbKey) % m_nHashTableSize;
  370. else
  371. i = MKVDefaultHashKey(pKey, cbKey) % m_nHashTableSize;
  372. ppAssocPrev = &m_pHashTable[i];
  373. CAssoc FAR* pAssoc;
  374. for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext)
  375. {
  376. if (CompareAssocKey(pAssoc, pKey, cbKey))
  377. {
  378. // remove it
  379. *ppAssocPrev = pAssoc->pNext; // remove from list
  380. FreeAssoc(pAssoc);
  381. ASSERT_VALID(this);
  382. fFound = TRUE;
  383. break;
  384. }
  385. ppAssocPrev = &pAssoc->pNext;
  386. }
  387. Exit:
  388. UNLOCKTHIS;
  389. return fFound;
  390. }
  391. #pragma SEG(CMapKeyToValue_RemoveHKey)
  392. // remove key based on pAssoc (HMAPKEY)
  393. BOOL CMapKeyToValue::RemoveHKey(HMAPKEY hKey)
  394. {
  395. VDATEHEAP();
  396. BOOL fFound = FALSE;
  397. // REVIEW: would like some way to verify that hKey is valid
  398. CAssoc FAR* pAssoc = (CAssoc FAR*)hKey;
  399. LOCKTHIS;
  400. ASSERT_VALID(this);
  401. if (m_pHashTable == NULL)
  402. goto Exit; // nothing in the table
  403. if (pAssoc == NULL || pAssoc->nHashValue >= m_nHashTableSize)
  404. goto Exit; // null hkey or bad hash value
  405. register CAssoc FAR* FAR* ppAssocPrev;
  406. ppAssocPrev = &m_pHashTable[pAssoc->nHashValue];
  407. while (*ppAssocPrev != NULL)
  408. {
  409. if (*ppAssocPrev == pAssoc)
  410. {
  411. // remove it
  412. *ppAssocPrev = pAssoc->pNext; // remove from list
  413. FreeAssoc(pAssoc);
  414. ASSERT_VALID(this);
  415. fFound = TRUE;
  416. break;
  417. }
  418. ppAssocPrev = &(*ppAssocPrev)->pNext;
  419. }
  420. Exit:
  421. UNLOCKTHIS;
  422. return fFound;
  423. }
  424. #pragma SEG(CMapKeyToValue_GetHKey)
  425. HMAPKEY CMapKeyToValue::GetHKey(LPVOID pKey, UINT cbKey) const
  426. {
  427. VDATEHEAP();
  428. UINT nHash;
  429. HMAPKEY hKey;
  430. LOCKTHIS;
  431. ASSERT_VALID(this);
  432. hKey = (HMAPKEY)GetAssocAt(pKey, cbKey, nHash);
  433. UNLOCKTHIS;
  434. return hKey;
  435. }
  436. /////////////////////////////////////////////////////////////////////////////
  437. // Iterating
  438. // for fixed length keys, copies key to pKey; pcbKey can be NULL;
  439. // for variable length keys, copies pointer to key to pKey; sets pcbKey.
  440. #pragma SEG(CMapKeyToValue_GetNextAssoc)
  441. void CMapKeyToValue::GetNextAssoc(POSITION FAR* pNextPosition,
  442. LPVOID pKey, UINT FAR* pcbKey, LPVOID pValue) const
  443. {
  444. VDATEHEAP();
  445. ASSERT_VALID(this);
  446. Assert(m_pHashTable != NULL); // never call on empty map
  447. register CAssoc FAR* pAssocRet = (CAssoc FAR*)*pNextPosition;
  448. Assert(pAssocRet != NULL);
  449. if (pAssocRet == (CAssoc FAR*) BEFORE_START_POSITION)
  450. {
  451. // find the first association
  452. for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
  453. if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
  454. break;
  455. Assert(pAssocRet != NULL); // must find something
  456. }
  457. // find next association
  458. CAssoc FAR* pAssocNext;
  459. if ((pAssocNext = pAssocRet->pNext) == NULL)
  460. {
  461. // go to next bucket
  462. for (UINT nBucket = pAssocRet->nHashValue + 1;
  463. nBucket < m_nHashTableSize; nBucket++)
  464. if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
  465. break;
  466. }
  467. // fill in return data
  468. *pNextPosition = (POSITION) pAssocNext;
  469. // fill in key/pointer to key
  470. LPVOID pKeyFrom;
  471. UINT cbKey;
  472. GetAssocKeyPtr(pAssocRet, &pKeyFrom, &cbKey);
  473. if (m_cbKey == 0)
  474. // variable length key; just return pointer to key itself
  475. *(void FAR* FAR*)pKey = pKeyFrom;
  476. else
  477. _xmemcpy(pKey, pKeyFrom, cbKey);
  478. if (pcbKey != NULL)
  479. *pcbKey = cbKey;
  480. // get value
  481. GetAssocValue(pAssocRet, pValue);
  482. }
  483. /////////////////////////////////////////////////////////////////////////////
  484. #pragma SEG(CMapKeyToValue_AssertValid)
  485. void CMapKeyToValue::AssertValid() const
  486. {
  487. VDATEHEAP();
  488. #ifdef _DEBUG
  489. Assert(m_cbKeyInAssoc == (m_cbKey == 0 ? sizeof(CKeyWrap) : m_cbKey));
  490. Assert(m_nHashTableSize > 0);
  491. Assert(m_nCount == 0 || m_pHashTable != NULL);
  492. if (m_pHashTable != NULL)
  493. Assert(IsValidReadPtrIn(m_pHashTable, m_nHashTableSize * sizeof(CAssoc FAR*)));
  494. if (m_lpfnHashKey)
  495. Assert(IsValidCodePtr((FARPROC)m_lpfnHashKey));
  496. if (m_pFreeList != NULL)
  497. Assert(IsValidReadPtrIn(m_pFreeList, SizeAssoc()));
  498. if (m_pBlocks != NULL)
  499. Assert(IsValidReadPtrIn(m_pBlocks, SizeAssoc() * m_nBlockSize));
  500. #endif //_DEBUG
  501. }