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.

452 lines
11 KiB

  1. /*
  2. * Value map
  3. */
  4. #ifndef DUI_BASE_VALUEMAP_H_INCLUDED
  5. #define DUI_BASE_VALUEMAP_H_INCLUDED
  6. #pragma once
  7. namespace DirectUI
  8. {
  9. //-------------------------------------------------------------------------
  10. //
  11. // ValueMap
  12. //
  13. // Stores Key/Value pairs
  14. //
  15. // Compile DEBUG for DUIAsserts, see public class declarations for API
  16. //
  17. // Keys and Values are stored natively and the type of each can be chosen
  18. // at compile time. For example (Key is an int, Value is a string pointer,
  19. // and the map will have 5 buckets):
  20. //
  21. // ValueMap<int,LPWSTR>* pvm;
  22. // ValueMap<int,LPWSTR>::Create(5, &pvm);
  23. // pvm->SetItem(1150, L"One thousand one hundred and fifty");
  24. // LPWSTR psz;
  25. // pvm->GetItem(1150, &psz);
  26. // DUITrace("%s\n", psz);
  27. //
  28. // The Key type must support the following operations:
  29. // Assignment (=)
  30. // Int cast for finding bucket (int)
  31. // Equality (==)
  32. //
  33. // The Value type must support the following operation:
  34. // Assignment (=)
  35. //
  36. // Given the above, a key can be created based on a string where the
  37. // correct mapping occurs even though the instance of the string is different.
  38. //
  39. // class StringKey
  40. // {
  41. // public:
  42. // StringKey(LPWSTR);
  43. // operator =(LPWSTR);
  44. // BOOL operator ==(StringKey);
  45. // operator INT_PTR();
  46. //
  47. // private:
  48. // LPWSTR pszStr;
  49. // };
  50. //
  51. // StringKey::StringKey(LPWSTR pstr)
  52. // {
  53. // pszStr = pstr;
  54. // }
  55. //
  56. // StringKey::operator =(LPWSTR pstr)
  57. // {
  58. // pszStr = pstr;
  59. // }
  60. //
  61. // BOOL StringKey::operator ==(StringKey st)
  62. // {
  63. // return wcscmp(pszStr, st.pszStr) == 0;
  64. // }
  65. //
  66. // StringKey::operator INT_PTR() // Create hash code from string
  67. // {
  68. // int dHash = 0;
  69. // LPWSTR pstr = pszStr;
  70. // WCHAR c;
  71. //
  72. // while (*pstr)
  73. // {
  74. // c = *pstr++;
  75. // dHash += (c << 1) + (c >> 1) + c;
  76. // }
  77. //
  78. // return dHash;
  79. // }
  80. //
  81. // It's usage would be:
  82. //
  83. // ValueMap<StringKey, int> v(11);
  84. //
  85. // v.SetItem(L"My favorite number", 4);
  86. // v.SetItem(L"Your favorite number", 8);
  87. //
  88. // Trace1(L"Mine : %d\n", *v.GetItem(L"My favorite number"); // 4
  89. // Trace1(L"Yours: %d\n", *v.GetItem(L"Your favorite number"); // 8
  90. //
  91. // v.SetItem(L"My favorite number", 5150);
  92. //
  93. // Trace1(L"Mine : %d\n", *v.GetItem(L"My favorite number"); // 5150
  94. //
  95. // v.Remove(L"Your favorite number";
  96. //
  97. // DUIAssert(!v.ContainsKey(L"Your favorite number"), "Error!"); // Mapping is removed
  98. //
  99. //-------------------------------------------------------------------------
  100. template <typename K, typename D> class ValueMap
  101. {
  102. typedef struct _ENTRY
  103. {
  104. bool fInUse;
  105. K tKey;
  106. D tData;
  107. struct _ENTRY* peNext;
  108. } ENTRY, *PENTRY;
  109. typedef void (*VMENUMCALLBACK)(K tKey, D tData);
  110. public: // API
  111. static HRESULT Create(UINT uBuckets, OUT ValueMap<K,D>** ppMap);
  112. virtual ~ValueMap();
  113. void Destroy() { HDelete< ValueMap<K,D> >(this); }
  114. D* GetItem(K, bool); // Pointer to Value (NULL if doesn't exist, internal copy returned)
  115. HRESULT SetItem(K, D*, bool); // Setup Key/Value map, creates new is doesn't exist (via indirection)
  116. HRESULT SetItem(K, D, bool); // Setup Key/Value map, creates new is doesn't exist
  117. void Remove(K, bool, bool); // Removes Key/Value map, ok if Key doesn't exist
  118. void Enum(VMENUMCALLBACK pfnCallback); // Callback with every item in map
  119. bool IsEmpty(); // True if no entries
  120. K* GetFirstKey(); // Returns pointer to first key found in table
  121. HRESULT GetDistribution(WCHAR**); // Returns a null terminated string describing table distribution (must HFree)
  122. ValueMap() { }
  123. HRESULT Initialize(UINT uBuckets);
  124. private:
  125. UINT _uBuckets;
  126. PENTRY* _ppBuckets;
  127. };
  128. template <typename K, typename D> HRESULT ValueMap<K,D>::Create(UINT uBuckets, OUT ValueMap<K,D>** ppMap)
  129. {
  130. DUIAssert(uBuckets > 0, "Must create at least one bucket in ValueMap");
  131. *ppMap = NULL;
  132. // Instantiate
  133. ValueMap<K,D>* pvm = HNew< ValueMap<K,D> >();
  134. if (!pvm)
  135. return E_OUTOFMEMORY;
  136. HRESULT hr = pvm->Initialize(uBuckets);
  137. if (FAILED(hr))
  138. {
  139. pvm->Destroy();
  140. return hr;
  141. }
  142. *ppMap = pvm;
  143. return S_OK;
  144. }
  145. template <typename K, typename D> HRESULT ValueMap<K,D>::Initialize(UINT uBuckets)
  146. {
  147. _uBuckets = uBuckets;
  148. _ppBuckets = (PENTRY*)HAllocAndZero(sizeof(PENTRY) * _uBuckets);
  149. if (!_ppBuckets)
  150. {
  151. // Object isn't created if buckets cannot be allocated
  152. return E_OUTOFMEMORY;
  153. }
  154. return S_OK;
  155. }
  156. template <typename K, typename D> ValueMap<K,D>::~ValueMap()
  157. {
  158. PENTRY pe;
  159. PENTRY peNext;
  160. for (UINT i = 0; i < _uBuckets; i++)
  161. {
  162. pe = _ppBuckets[i];
  163. while (pe != NULL)
  164. {
  165. peNext = pe->peNext;
  166. HFree(pe);
  167. pe = peNext;
  168. }
  169. }
  170. HFree(_ppBuckets);
  171. }
  172. template <typename K, typename D> void ValueMap<K,D>::Enum(VMENUMCALLBACK pfnCallback)
  173. {
  174. PENTRY pe;
  175. for (UINT i = 0; i < _uBuckets; i++)
  176. {
  177. pe = _ppBuckets[i];
  178. while (pe)
  179. {
  180. if (pe->fInUse)
  181. pfnCallback(pe->tKey, pe->tData);
  182. pe = pe->peNext;
  183. }
  184. }
  185. }
  186. template <typename K, typename D> K* ValueMap<K,D>::GetFirstKey()
  187. {
  188. PENTRY pe;
  189. for (UINT i = 0; i < _uBuckets; i++)
  190. {
  191. pe = _ppBuckets[i];
  192. while (pe)
  193. {
  194. if (pe->fInUse)
  195. return &pe->tKey;
  196. pe = pe->peNext;
  197. }
  198. }
  199. return NULL;
  200. }
  201. template <typename K, typename D> D* ValueMap<K,D>::GetItem(K tKey, bool fKeyIsPtr)
  202. {
  203. // Pointer based keys are shifted for better distribution
  204. // Search for items in buckets
  205. PENTRY pe = _ppBuckets[(UINT)(((fKeyIsPtr) ? (int)tKey >> 2 : (int)tKey) % _uBuckets)];
  206. while (pe && !(pe->fInUse && (pe->tKey == tKey)))
  207. {
  208. pe = pe->peNext;
  209. }
  210. return (pe) ? &pe->tData : NULL;
  211. }
  212. // Stores the value of tData (via indirection)
  213. template <typename K, typename D> HRESULT ValueMap<K,D>::SetItem(K tKey, D* pData, bool fKeyIsPtr)
  214. {
  215. // Pointer based keys are shifted for better distribution
  216. PENTRY pe;
  217. PENTRY pUnused = NULL;
  218. UINT uBucket = (UINT)(((fKeyIsPtr) ? (int)tKey >> 2 : (int)tKey) % _uBuckets);
  219. // Search for items in buckets
  220. pe = _ppBuckets[uBucket];
  221. while (pe && !(pe->fInUse && (pe->tKey == tKey)))
  222. {
  223. if (!pe->fInUse)
  224. {
  225. pUnused = pe;
  226. }
  227. pe = pe->peNext;
  228. }
  229. if (pe)
  230. {
  231. // Item found
  232. pe->tData = *pData;
  233. }
  234. else
  235. {
  236. // Reuse or create new item
  237. if (pUnused)
  238. {
  239. pUnused->fInUse = true;
  240. pUnused->tKey = tKey;
  241. pUnused->tData = *pData;
  242. }
  243. else
  244. {
  245. pe = (PENTRY)HAlloc(sizeof(ENTRY));
  246. if (!pe)
  247. return E_OUTOFMEMORY;
  248. pe->fInUse = true;
  249. pe->tKey = tKey;
  250. pe->tData = *pData;
  251. pe->peNext = _ppBuckets[uBucket];
  252. _ppBuckets[uBucket] = pe;
  253. }
  254. }
  255. return S_OK;
  256. }
  257. // Stores the value of tData
  258. template <typename K, typename D> HRESULT ValueMap<K,D>::SetItem(K tKey, D tData, bool fKeyIsPtr)
  259. {
  260. // Pointer based keys are shifted for better distribution
  261. PENTRY pe;
  262. PENTRY pUnused = NULL;
  263. UINT uBucket = (UINT)(((fKeyIsPtr) ? (UINT_PTR)tKey >> 2 : (INT_PTR)tKey) % _uBuckets);
  264. // Search for items in buckets
  265. pe = _ppBuckets[uBucket];
  266. while (pe && !(pe->fInUse && (pe->tKey == tKey)))
  267. {
  268. if (!pe->fInUse)
  269. {
  270. pUnused = pe;
  271. }
  272. pe = pe->peNext;
  273. }
  274. if (pe)
  275. {
  276. // Item found
  277. pe->tData = tData;
  278. }
  279. else
  280. {
  281. // Reuse or create new item
  282. if (pUnused)
  283. {
  284. pUnused->fInUse = true;
  285. pUnused->tKey = tKey;
  286. pUnused->tData = tData;
  287. }
  288. else
  289. {
  290. pe = (PENTRY)HAlloc(sizeof(ENTRY));
  291. if (!pe)
  292. return E_OUTOFMEMORY;
  293. pe->fInUse = true;
  294. pe->tKey = tKey;
  295. pe->tData = tData;
  296. pe->peNext = _ppBuckets[uBucket];
  297. _ppBuckets[uBucket] = pe;
  298. }
  299. }
  300. return S_OK;
  301. }
  302. template <typename K, typename D> void ValueMap<K,D>::Remove(K tKey, bool fFree, bool fKeyIsPtr)
  303. {
  304. // Pointer based keys are shifted for better distribution
  305. PENTRY pe;
  306. PENTRY pePrev = NULL;
  307. UINT uBucket = (UINT)(((fKeyIsPtr) ? (UINT_PTR)tKey >> 2 : (INT_PTR)tKey) % _uBuckets);
  308. // Search for items in buckets
  309. pe = _ppBuckets[uBucket];
  310. while (pe && !(pe->fInUse && (pe->tKey == tKey)))
  311. {
  312. pePrev = pe; // Keep the previous item
  313. pe = pe->peNext;
  314. }
  315. if (pe)
  316. {
  317. if (fFree)
  318. {
  319. if (pePrev != NULL)
  320. {
  321. pePrev->peNext = pe->peNext;
  322. }
  323. else
  324. {
  325. _ppBuckets[uBucket] = pe->peNext;
  326. }
  327. HFree(pe);
  328. }
  329. else
  330. {
  331. pe->fInUse = false;
  332. }
  333. }
  334. }
  335. template <typename K, typename D> bool ValueMap<K,D>::IsEmpty()
  336. {
  337. PENTRY pe;
  338. for (UINT i = 0; i < _uBuckets; i++)
  339. {
  340. pe = _ppBuckets[i];
  341. while (pe != NULL)
  342. {
  343. if (pe->fInUse)
  344. return false;
  345. pe = pe->peNext;
  346. }
  347. }
  348. return true;
  349. }
  350. template <typename K, typename D> HRESULT ValueMap<K,D>::GetDistribution(OUT WCHAR** ppszDist)
  351. {
  352. *ppszDist = NULL;
  353. LPWSTR pszOut = (LPWSTR)HAlloc((256 + _uBuckets * 24) * sizeof(WCHAR));
  354. if (!pszOut)
  355. return E_OUTOFMEMORY
  356. WCHAR pszBuf[151];
  357. swprintf(pszOut, L"Buckets for %x (Slots InUse/Total): %d - ", this, _uBuckets);
  358. PENTRY pe;
  359. UINT cInUse;
  360. UINT cCount;
  361. for (UINT i = 0; i < _uBuckets; i++)
  362. {
  363. pe = _ppBuckets[i];
  364. cInUse = 0;
  365. cCount = 0;
  366. while (pe)
  367. {
  368. cCount++;
  369. if (pe->fInUse)
  370. cInUse++;
  371. pe = pe->peNext;
  372. }
  373. swprintf(pszBuf, L"(B%d): %d/%d ", i, cInUse, cCount);
  374. wcscat(pszOut, pszBuf);
  375. }
  376. return pszOut;
  377. }
  378. } // namespace DirectUI
  379. #endif // DUI_BASE_VALUEMAP_H_INCLUDED