Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

536 lines
13 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 <windows.h>
  8. #include <ole2.h>
  9. #include <ole2sp.h>
  10. #include <olecoll.h>
  11. #include <memctx.hxx>
  12. #include "map_kv.h"
  13. #include "plex.h"
  14. ASSERTDATA
  15. /////////////////////////////////////////////////////////////////////////////
  16. CMapKeyToValue::CMapKeyToValue(DWORD memctx, UINT cbValue, UINT cbKey,
  17. int nBlockSize, LPFNHASHKEY lpfnHashKey, UINT nHashSize)
  18. {
  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. if (memctx == MEMCTX_SAME)
  31. memctx = CoMemctxOf(this);
  32. m_memctx = memctx;
  33. Assert(m_memctx != MEMCTX_UNKNOWN);
  34. }
  35. CMapKeyToValue::~CMapKeyToValue()
  36. {
  37. ASSERT_VALID(this);
  38. RemoveAll();
  39. Assert(m_nCount == 0);
  40. }
  41. // simple, default hash function
  42. // REVIEW: need to check the value in this for GUIDs and strings
  43. STDAPI_(UINT) MKVDefaultHashKey(LPVOID pKey, UINT cbKey)
  44. {
  45. UINT hash = 0;
  46. BYTE FAR* lpb = (BYTE FAR*)pKey;
  47. while (cbKey-- != 0)
  48. hash = 257 * hash + *lpb++;
  49. return hash;
  50. }
  51. BOOL CMapKeyToValue::InitHashTable()
  52. {
  53. ASSERT_VALID(this);
  54. Assert(m_nHashTableSize > 0);
  55. if (m_pHashTable != NULL)
  56. return TRUE;
  57. Assert(m_nCount == 0);
  58. if ((m_pHashTable = (CAssoc FAR* FAR*)CoMemAlloc(m_nHashTableSize * sizeof(CAssoc FAR*), m_memctx, NULL)) == NULL)
  59. return FALSE;
  60. _fmemset(m_pHashTable, 0, sizeof(CAssoc FAR*) * m_nHashTableSize);
  61. ASSERT_VALID(this);
  62. return TRUE;
  63. }
  64. void CMapKeyToValue::RemoveAll()
  65. {
  66. ASSERT_VALID(this);
  67. // free all key values and then hash table
  68. if (m_pHashTable != NULL)
  69. {
  70. // destroy assocs
  71. for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
  72. {
  73. register CAssoc FAR* pAssoc;
  74. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
  75. pAssoc = pAssoc->pNext)
  76. // assoc itself is freed by FreeDataChain below
  77. FreeAssocKey(pAssoc);
  78. }
  79. // free hash table
  80. CoMemFree(m_pHashTable, m_memctx);
  81. m_pHashTable = NULL;
  82. }
  83. m_nCount = 0;
  84. m_pFreeList = NULL;
  85. m_pBlocks->FreeDataChain(m_memctx);
  86. m_pBlocks = NULL;
  87. ASSERT_VALID(this);
  88. }
  89. /////////////////////////////////////////////////////////////////////////////
  90. // Assoc helpers
  91. // CAssoc's are singly linked all the time
  92. CMapKeyToValue::CAssoc FAR*
  93. CMapKeyToValue::NewAssoc(UINT hash, LPVOID pKey, UINT cbKey, LPVOID pValue)
  94. {
  95. if (m_pFreeList == NULL)
  96. {
  97. // add another block
  98. CPlex FAR* newBlock = CPlex::Create(m_pBlocks, m_memctx, m_nBlockSize, SizeAssoc());
  99. if (newBlock == NULL)
  100. return NULL;
  101. // chain them into free list
  102. register BYTE FAR* pbAssoc = (BYTE FAR*) newBlock->data();
  103. // free in reverse order to make it easier to debug
  104. pbAssoc += (m_nBlockSize - 1) * SizeAssoc();
  105. for (int i = m_nBlockSize-1; i >= 0; i--, pbAssoc -= SizeAssoc())
  106. {
  107. ((CAssoc FAR*)pbAssoc)->pNext = m_pFreeList;
  108. m_pFreeList = (CAssoc FAR*)pbAssoc;
  109. }
  110. }
  111. Assert(m_pFreeList != NULL); // we must have something
  112. CMapKeyToValue::CAssoc FAR* pAssoc = m_pFreeList;
  113. // init all fields except pNext while still on free list
  114. pAssoc->nHashValue = hash;
  115. if (!SetAssocKey(pAssoc, pKey, cbKey))
  116. return NULL;
  117. SetAssocValue(pAssoc, pValue);
  118. // remove from free list after successfully initializing it (except pNext)
  119. m_pFreeList = m_pFreeList->pNext;
  120. m_nCount++;
  121. Assert(m_nCount > 0); // make sure we don't overflow
  122. return pAssoc;
  123. }
  124. // free individual assoc by freeing key and putting on free list
  125. void CMapKeyToValue::FreeAssoc(CMapKeyToValue::CAssoc FAR* pAssoc)
  126. {
  127. pAssoc->pNext = m_pFreeList;
  128. m_pFreeList = pAssoc;
  129. m_nCount--;
  130. Assert(m_nCount >= 0); // make sure we don't underflow
  131. FreeAssocKey(pAssoc);
  132. }
  133. // find association (or return NULL)
  134. CMapKeyToValue::CAssoc FAR*
  135. CMapKeyToValue::GetAssocAt(LPVOID pKey, UINT cbKey, UINT FAR& nHash) const
  136. {
  137. if (m_lpfnHashKey)
  138. nHash = (*m_lpfnHashKey)(pKey, cbKey) % m_nHashTableSize;
  139. else {
  140. Assert(m_lpfnHashKey);
  141. return NULL;
  142. }
  143. if (m_pHashTable == NULL)
  144. return NULL;
  145. // see if it exists
  146. register CAssoc FAR* pAssoc;
  147. for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
  148. {
  149. if (CompareAssocKey(pAssoc, pKey, cbKey))
  150. return pAssoc;
  151. }
  152. return NULL;
  153. }
  154. BOOL CMapKeyToValue::CompareAssocKey(CAssoc FAR* pAssoc, LPVOID pKey2, UINT cbKey2) const
  155. {
  156. LPVOID pKey1;
  157. UINT cbKey1;
  158. GetAssocKeyPtr(pAssoc, &pKey1, &cbKey1);
  159. return cbKey1 == cbKey2 && _fmemcmp(pKey1, pKey2, cbKey1) == 0;
  160. }
  161. BOOL CMapKeyToValue::SetAssocKey(CAssoc FAR* pAssoc, LPVOID pKey, UINT cbKey) const
  162. {
  163. Assert(cbKey == m_cbKey || m_cbKey == 0);
  164. if (m_cbKey == 0)
  165. {
  166. Assert(m_cbKeyInAssoc == sizeof(CKeyWrap));
  167. // alloc, set size and pointer
  168. if ((pAssoc->key.pKey = CoMemAlloc(cbKey, m_memctx, NULL)) == NULL)
  169. return FALSE;
  170. pAssoc->key.cbKey = cbKey;
  171. }
  172. LPVOID pKeyTo;
  173. GetAssocKeyPtr(pAssoc, &pKeyTo, &cbKey);
  174. _fmemcpy(pKeyTo, pKey, cbKey);
  175. return TRUE;
  176. }
  177. // gets pointer to key and its length
  178. void CMapKeyToValue::GetAssocKeyPtr(CAssoc FAR* pAssoc, LPVOID FAR* ppKey,UINT FAR* pcbKey) const
  179. {
  180. if (m_cbKey == 0)
  181. {
  182. // variable length key; go indirect
  183. *ppKey = pAssoc->key.pKey;
  184. *pcbKey = pAssoc->key.cbKey;
  185. }
  186. else
  187. {
  188. // fixed length key; key in assoc
  189. *ppKey = (LPVOID)&pAssoc->key;
  190. *pcbKey = m_cbKey;
  191. }
  192. }
  193. void CMapKeyToValue::FreeAssocKey(CAssoc FAR* pAssoc) const
  194. {
  195. if (m_cbKey == 0)
  196. CoMemFree(pAssoc->key.pKey, m_memctx);
  197. }
  198. void CMapKeyToValue::GetAssocValuePtr(CAssoc FAR* pAssoc, LPVOID FAR* ppValue) const
  199. {
  200. *ppValue = (char FAR*)&pAssoc->key + m_cbKeyInAssoc;
  201. }
  202. void CMapKeyToValue::GetAssocValue(CAssoc FAR* pAssoc, LPVOID pValue) const
  203. {
  204. LPVOID pValueFrom;
  205. GetAssocValuePtr(pAssoc, &pValueFrom);
  206. Assert(pValue != NULL);
  207. _fmemcpy(pValue, pValueFrom, m_cbValue);
  208. }
  209. void CMapKeyToValue::SetAssocValue(CAssoc FAR* pAssoc, LPVOID pValue) const
  210. {
  211. LPVOID pValueTo;
  212. GetAssocValuePtr(pAssoc, &pValueTo);
  213. if (pValue == NULL)
  214. _fmemset(pValueTo, 0, m_cbValue);
  215. else
  216. _fmemcpy(pValueTo, pValue, m_cbValue);
  217. }
  218. /////////////////////////////////////////////////////////////////////////////
  219. // lookup value given key; return FALSE if key not found; in that
  220. // case, the value is set to all zeros
  221. BOOL CMapKeyToValue::Lookup(LPVOID pKey, UINT cbKey, LPVOID pValue) const
  222. {
  223. UINT nHash;
  224. return LookupHKey((HMAPKEY)GetAssocAt(pKey, cbKey, nHash), pValue);
  225. }
  226. // lookup value given key; return FALSE if NULL (or bad) key; in that
  227. // case, the value is set to all zeros
  228. BOOL CMapKeyToValue::LookupHKey(HMAPKEY hKey, LPVOID pValue) const
  229. {
  230. // REVIEW: would like some way to verify that hKey is valid
  231. register CAssoc FAR* pAssoc = (CAssoc FAR*)hKey;
  232. if (pAssoc == NULL)
  233. {
  234. _fmemset(pValue, 0, m_cbValue);
  235. return FALSE; // not in map
  236. }
  237. ASSERT_VALID(this);
  238. GetAssocValue(pAssoc, pValue);
  239. return TRUE;
  240. }
  241. // lookup and if not found add; returns FALSE only if OOM; if added,
  242. // value added and pointer passed are set to zeros.
  243. BOOL CMapKeyToValue::LookupAdd(LPVOID pKey, UINT cbKey, LPVOID pValue) const
  244. {
  245. if (Lookup(pKey, cbKey, pValue))
  246. return TRUE;
  247. // value set to zeros since lookup failed
  248. return ((CMapKeyToValue FAR*)this)->SetAt(pKey, cbKey, NULL);
  249. }
  250. // the only place new assocs are created; return FALSE if OOM;
  251. // never returns FALSE if keys already exists
  252. BOOL CMapKeyToValue::SetAt(LPVOID pKey, UINT cbKey, LPVOID pValue)
  253. {
  254. UINT nHash;
  255. register CAssoc FAR* pAssoc;
  256. ASSERT_VALID(this);
  257. if ((pAssoc = GetAssocAt(pKey, cbKey, nHash)) == NULL)
  258. {
  259. if (!InitHashTable())
  260. // out of memory
  261. return FALSE;
  262. // it doesn't exist, add a new Association
  263. if ((pAssoc = NewAssoc(nHash, pKey, cbKey, pValue)) == NULL)
  264. return FALSE;
  265. // put into hash table
  266. pAssoc->pNext = m_pHashTable[nHash];
  267. m_pHashTable[nHash] = pAssoc;
  268. ASSERT_VALID(this);
  269. }
  270. else
  271. {
  272. SetAssocValue(pAssoc, pValue);
  273. }
  274. return TRUE;
  275. }
  276. // set existing hkey to value; return FALSE if NULL or bad key
  277. BOOL CMapKeyToValue::SetAtHKey(HMAPKEY hKey, LPVOID pValue)
  278. {
  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. return FALSE; // not in map
  283. ASSERT_VALID(this);
  284. SetAssocValue(pAssoc, pValue);
  285. return TRUE;
  286. }
  287. // remove key - return TRUE if removed
  288. BOOL CMapKeyToValue::RemoveKey(LPVOID pKey, UINT cbKey)
  289. {
  290. ASSERT_VALID(this);
  291. if (m_pHashTable == NULL)
  292. return FALSE; // nothing in the table
  293. register CAssoc FAR* FAR* ppAssocPrev;
  294. ppAssocPrev = &m_pHashTable[(*m_lpfnHashKey)(pKey, cbKey) % m_nHashTableSize];
  295. CAssoc FAR* pAssoc;
  296. for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext)
  297. {
  298. if (CompareAssocKey(pAssoc, pKey, cbKey))
  299. {
  300. // remove it
  301. *ppAssocPrev = pAssoc->pNext; // remove from list
  302. FreeAssoc(pAssoc);
  303. ASSERT_VALID(this);
  304. return TRUE;
  305. }
  306. ppAssocPrev = &pAssoc->pNext;
  307. }
  308. return FALSE; // not found
  309. }
  310. // remove key based on pAssoc (HMAPKEY)
  311. BOOL CMapKeyToValue::RemoveHKey(HMAPKEY hKey)
  312. {
  313. ASSERT_VALID(this);
  314. if (m_pHashTable == NULL)
  315. return FALSE; // nothing in the table
  316. // REVIEW: would like some way to verify that hKey is valid
  317. CAssoc FAR* pAssoc = (CAssoc FAR*)hKey;
  318. if (pAssoc == NULL || pAssoc->nHashValue >= m_nHashTableSize)
  319. // null hkey or bad hash value
  320. return FALSE;
  321. register CAssoc FAR* FAR* ppAssocPrev;
  322. ppAssocPrev = &m_pHashTable[pAssoc->nHashValue];
  323. while (*ppAssocPrev != NULL)
  324. {
  325. if (*ppAssocPrev == pAssoc)
  326. {
  327. // remove it
  328. *ppAssocPrev = pAssoc->pNext; // remove from list
  329. FreeAssoc(pAssoc);
  330. ASSERT_VALID(this);
  331. return TRUE;
  332. }
  333. ppAssocPrev = &(*ppAssocPrev)->pNext;
  334. }
  335. return FALSE; // not found (must have a messed up list or passed
  336. // a key from another list)
  337. }
  338. HMAPKEY CMapKeyToValue::GetHKey(LPVOID pKey, UINT cbKey) const
  339. {
  340. UINT nHash;
  341. ASSERT_VALID(this);
  342. return (HMAPKEY)GetAssocAt(pKey, cbKey, nHash);
  343. }
  344. /////////////////////////////////////////////////////////////////////////////
  345. // Iterating
  346. // for fixed length keys, copies key to pKey; pcbKey can be NULL;
  347. // for variable length keys, copies pointer to key to pKey; sets pcbKey.
  348. void CMapKeyToValue::GetNextAssoc(POSITION FAR* pNextPosition,
  349. LPVOID pKey, UINT FAR* pcbKey, LPVOID pValue) const
  350. {
  351. ASSERT_VALID(this);
  352. Assert(m_pHashTable != NULL); // never call on empty map
  353. register CAssoc FAR* pAssocRet = (CAssoc FAR*)*pNextPosition;
  354. Assert(pAssocRet != NULL);
  355. if (pAssocRet == (CAssoc FAR*) BEFORE_START_POSITION)
  356. {
  357. // find the first association
  358. for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
  359. if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
  360. break;
  361. Assert(pAssocRet != NULL); // must find something
  362. }
  363. // find next association
  364. CAssoc FAR* pAssocNext;
  365. if ((pAssocNext = pAssocRet->pNext) == NULL)
  366. {
  367. // go to next bucket
  368. for (UINT nBucket = pAssocRet->nHashValue + 1;
  369. nBucket < m_nHashTableSize; nBucket++)
  370. if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
  371. break;
  372. }
  373. // fill in return data
  374. *pNextPosition = (POSITION) pAssocNext;
  375. // fill in key/pointer to key
  376. LPVOID pKeyFrom;
  377. UINT cbKey;
  378. GetAssocKeyPtr(pAssocRet, &pKeyFrom, &cbKey);
  379. if (m_cbKey == 0)
  380. // variable length key; just return pointer to key itself
  381. *(void FAR* FAR*)pKey = pKeyFrom;
  382. else
  383. _fmemcpy(pKey, pKeyFrom, cbKey);
  384. if (pcbKey != NULL)
  385. *pcbKey = cbKey;
  386. // get value
  387. GetAssocValue(pAssocRet, pValue);
  388. }
  389. /////////////////////////////////////////////////////////////////////////////
  390. void CMapKeyToValue::AssertValid() const
  391. {
  392. #ifdef _DEBUG
  393. Assert(m_cbKeyInAssoc == (m_cbKey == 0 ? sizeof(CKeyWrap) : m_cbKey));
  394. Assert(m_nHashTableSize > 0);
  395. Assert(m_nCount == 0 || m_pHashTable != NULL);
  396. if (m_pHashTable != NULL)
  397. Assert(!IsBadReadPtr(m_pHashTable, m_nHashTableSize * sizeof(CAssoc FAR*)));
  398. Assert(!IsBadCodePtr((FARPROC)m_lpfnHashKey));
  399. if (m_pFreeList != NULL)
  400. Assert(!IsBadReadPtr(m_pFreeList, SizeAssoc()));
  401. if (m_pBlocks != NULL)
  402. Assert(!IsBadReadPtr(m_pBlocks, SizeAssoc() * m_nBlockSize));
  403. // some collections live as global variables in the libraries, but
  404. // have their existance in some context. Also, we can't check shared
  405. // collections since we might be checking the etask collection
  406. // which would cause an infinite recursion.
  407. Assert(m_memctx == MEMCTX_SHARED || CoMemctxOf(this) == MEMCTX_UNKNOWN || CoMemctxOf(this) == m_memctx);
  408. #endif //_DEBUG
  409. }