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.

352 lines
9.2 KiB

  1. /*
  2. * BTreeLookup
  3. */
  4. /*
  5. * Stores data and associated key and uses a binary search for quick lookup
  6. * Used if gets are much more frequent than gets
  7. *
  8. * Keys are compared as pointers. If fKeyIsWStr is true, Keys are dereferenced
  9. * as WCHAR* and compared
  10. */
  11. #ifndef DUI_BASE_BTREELOOKUP_H_INCLUDED
  12. #define DUI_BASE_BTREELOOKUP_H_INCLUDED
  13. #pragma once
  14. namespace DirectUI
  15. {
  16. template <typename D> class BTreeLookup
  17. {
  18. typedef struct
  19. {
  20. void* pKey;
  21. D tData;
  22. } ENTRY, *PENTRY;
  23. typedef void (*PBTENUMCALLBACK)(void* pKey, D tData);
  24. public:
  25. static HRESULT Create(bool fKeyIsWStr, OUT BTreeLookup<D>** ppBTree);
  26. virtual ~BTreeLookup();
  27. void Destroy() { HDelete< BTreeLookup<D> >(this); }
  28. D* GetItem(void* pKey); // Pointer to Value (NULL if doesn't exist, internal copy returned)
  29. HRESULT SetItem(void* pKey, D* ptData); // Setup Key/Value map, creates new is doesn't exist (via indirection)
  30. HRESULT SetItem(void* pKey, D tData); // Setup Key/Value map, creates new is doesn't exist
  31. void Remove(void* pKey); // Removes Key/Value map, ok if Key doesn't exist
  32. void Enum(PBTENUMCALLBACK pfnCallback); // Callback with every item in map
  33. static int __cdecl ENTRYCompare(const void* pA, const void* pB);
  34. static int __cdecl WStrENTRYCompare(const void* pA, const void* pB);
  35. BTreeLookup() { }
  36. void Initialize(bool fKeyIsWStr);
  37. private:
  38. UINT _uListSize;
  39. PENTRY _pList;
  40. bool _fKeyIsWStr;
  41. };
  42. template <typename D> HRESULT BTreeLookup<D>::Create(bool fKeyIsWStr, OUT BTreeLookup<D>** ppBTree)
  43. {
  44. *ppBTree = NULL;
  45. // Instantiate
  46. BTreeLookup<D>* pbt = HNew< BTreeLookup<D> >();
  47. if (!pbt)
  48. return E_OUTOFMEMORY;
  49. pbt->Initialize(fKeyIsWStr);
  50. *ppBTree = pbt;
  51. return S_OK;
  52. }
  53. template <typename D> void BTreeLookup<D>::Initialize(bool fKeyIsWStr)
  54. {
  55. _uListSize = 0;
  56. _pList = NULL;
  57. _fKeyIsWStr = fKeyIsWStr;
  58. }
  59. template <typename D> BTreeLookup<D>::~BTreeLookup()
  60. {
  61. if (_pList)
  62. HFree(_pList);
  63. }
  64. template <typename D> D* BTreeLookup<D>::GetItem(void* pKey)
  65. {
  66. DUIAssert(_fKeyIsWStr ? pKey != NULL : true, "pKey may not be NULL");
  67. //PENTRY pEntry = NULL;
  68. if (_pList)
  69. {
  70. //ENTRY eKey = { pKey }; // Create ENTRY key, populate key field
  71. //pEntry = (PENTRY)bsearch(&eKey, _pList, _uListSize, sizeof(ENTRY), ENTRYCompare);
  72. PENTRY pEntry;
  73. int uPv;
  74. int uLo = 0;
  75. int uHi = _uListSize - 1;
  76. while (uLo <= uHi)
  77. {
  78. uPv = (uHi + uLo) / 2;
  79. pEntry = _pList + uPv;
  80. // Locate
  81. if (!_fKeyIsWStr)
  82. {
  83. // Key is numeric
  84. if ((UINT_PTR)pKey == (UINT_PTR)pEntry->pKey)
  85. return &(pEntry->tData);
  86. if ((UINT_PTR)pKey < (UINT_PTR)pEntry->pKey)
  87. uHi = uPv - 1;
  88. else
  89. uLo = uPv + 1;
  90. }
  91. else
  92. {
  93. // Key is pointer to a wide string
  94. int cmp = _wcsicmp((LPCWSTR)pKey, (LPCWSTR)pEntry->pKey);
  95. if (!cmp)
  96. return &(pEntry->tData);
  97. if (cmp < 0)
  98. uHi = uPv - 1;
  99. else
  100. uLo = uPv + 1;
  101. }
  102. }
  103. }
  104. //return pEntry ? &(pEntry->tData) : NULL;
  105. return NULL;
  106. }
  107. template <typename D> HRESULT BTreeLookup<D>::SetItem(void* pKey, D tData)
  108. {
  109. D* pData = GetItem(pKey); // Find current entry (if exits)
  110. if (pData)
  111. {
  112. // Entry found and have pointer to data of entry
  113. *pData = tData;
  114. }
  115. else
  116. {
  117. // Entry not found, allocate room for new entry, store, and sort
  118. // New size
  119. UINT uNewSize = _uListSize + 1;
  120. if (_pList)
  121. {
  122. DUIAssert(uNewSize > 1, "Tracked list size and actual size differ");
  123. PENTRY pNewList = (PENTRY)HReAlloc(_pList, sizeof(ENTRY) * uNewSize);
  124. if (!pNewList)
  125. return E_OUTOFMEMORY;
  126. _pList = pNewList;
  127. }
  128. else
  129. {
  130. DUIAssert(uNewSize == 1, "Tracked list size and actual list size differ");
  131. _pList = (PENTRY)HAlloc(sizeof(ENTRY));
  132. if (!_pList)
  133. return E_OUTOFMEMORY;
  134. }
  135. // Update size
  136. _uListSize = uNewSize;
  137. // Store
  138. _pList[_uListSize - 1].pKey = pKey;
  139. _pList[_uListSize - 1].tData = tData;
  140. // Sort
  141. qsort(_pList, _uListSize, sizeof(ENTRY), !_fKeyIsWStr ? ENTRYCompare : WStrENTRYCompare);
  142. }
  143. return S_OK;
  144. }
  145. template <typename D> HRESULT BTreeLookup<D>::SetItem(void* pKey, D* ptData)
  146. {
  147. D* pData = GetItem(pKey); // Find current entry (if exits)
  148. if (pData)
  149. {
  150. // Entry found and have pointer to data of entry
  151. *pData = *ptData;
  152. }
  153. else
  154. {
  155. // Entry not found, allocate room for new entry, store, and sort
  156. // New size
  157. UINT uNewSize = _uListSize + 1;
  158. if (_pList)
  159. {
  160. DUIAssert(uNewSize > 1, "Tracked list size and actual list size differ");
  161. PENTRY pNewList = (PENTRY)HReAlloc(_pList, sizeof(ENTRY) * uNewSize);
  162. if (!pNewList)
  163. return E_OUTOFMEMORY;
  164. _pList = pNewList;
  165. }
  166. else
  167. {
  168. DUIAssert(uNewSize == 1, "Tracked list size and actual list size differ");
  169. _pList = (PENTRY)HAlloc(sizeof(ENTRY));
  170. if (!_pList)
  171. return E_OUTOFMEMORY;
  172. }
  173. // Update size
  174. _uListSize = uNewSize;
  175. // Store
  176. _pList[_uListSize - 1].pKey = pKey;
  177. _pList[_uListSize - 1].tData = *ptData;
  178. // Sort
  179. qsort(_pList, _uListSize, sizeof(ENTRY), !_fKeyIsWStr ? ENTRYCompare : WStrENTRYCompare);
  180. }
  181. return S_OK;
  182. }
  183. // Returns success even if key isn't found
  184. template <typename D> void BTreeLookup<D>::Remove(void* pKey)
  185. {
  186. // Validate parameters
  187. DUIAssert(_fKeyIsWStr ? pKey != NULL : true, "Invalid parameter: pKey == NULL");
  188. if (_pList)
  189. {
  190. // Search for ENTRY with key
  191. //ENTRY eKey = { pKey };
  192. //PENTRY pEntry = (PENTRY)bsearch(&eKey, _pList, _uListSize, sizeof(ENTRY), ENTRYCompare);
  193. PENTRY pEntry = NULL;
  194. int uPv;
  195. int uLo = 0;
  196. int uHi = _uListSize - 1;
  197. while (uLo <= uHi)
  198. {
  199. uPv = (uHi + uLo) / 2;
  200. pEntry = _pList + uPv;
  201. // Locate
  202. if (!_fKeyIsWStr)
  203. {
  204. // Key is numeric
  205. if ((UINT_PTR)pKey == (UINT_PTR)pEntry->pKey)
  206. break;
  207. if ((UINT_PTR)pKey < (UINT_PTR)pEntry->pKey)
  208. uHi = uPv - 1;
  209. else
  210. uLo = uPv + 1;
  211. }
  212. else
  213. {
  214. // Key is pointer to a wide string
  215. int cmp = _wcsicmp((LPCWSTR)pKey, (LPCWSTR)pEntry->pKey);
  216. if (!cmp)
  217. break;
  218. if (cmp < 0)
  219. uHi = uPv - 1;
  220. else
  221. uLo = uPv + 1;
  222. }
  223. pEntry = NULL;
  224. }
  225. if (pEntry)
  226. {
  227. UINT uIndex = (UINT)(((UINT_PTR)pEntry - (UINT_PTR)_pList) / sizeof(ENTRY));
  228. DUIAssert(uIndex < _uListSize, "Index out of bounds");
  229. // ENTRY found, move all entries after this entry down
  230. MoveMemory(pEntry, pEntry + 1, (_uListSize - uIndex - 1) * sizeof(ENTRY));
  231. // One less entry
  232. UINT uNewSize = _uListSize - 1;
  233. // Trim allocation
  234. if (uNewSize == 0)
  235. {
  236. HFree(_pList);
  237. _pList = NULL;
  238. }
  239. else
  240. {
  241. PENTRY pNewList = (PENTRY)HReAlloc(_pList, uNewSize * sizeof(ENTRY));
  242. // List is becoming smaller, if re-allocation failed, keep previous and continue
  243. if (pNewList)
  244. _pList = pNewList;
  245. }
  246. // Update size
  247. _uListSize = uNewSize;
  248. }
  249. }
  250. }
  251. template <typename D> void BTreeLookup<D>::Enum(PBTENUMCALLBACK pfnCallback)
  252. {
  253. if (_pList)
  254. {
  255. for (UINT i = 0; i < _uListSize; i++)
  256. pfnCallback(_pList[i].pKey, _pList[i].tData);
  257. }
  258. }
  259. template <typename D> int __cdecl BTreeLookup<D>::ENTRYCompare(const void* pA, const void* pB)
  260. {
  261. PENTRY pEA = (PENTRY)pA;
  262. PENTRY pEB = (PENTRY)pB;
  263. if ((UINT_PTR)pEA->pKey == (UINT_PTR)pEB->pKey)
  264. return 0;
  265. else if ((UINT_PTR)pEA->pKey < (UINT_PTR)pEB->pKey)
  266. return -1;
  267. else
  268. return 1;
  269. }
  270. template <typename D> int __cdecl BTreeLookup<D>::WStrENTRYCompare(const void* pA, const void* pB)
  271. {
  272. PENTRY pEA = (PENTRY)pA;
  273. PENTRY pEB = (PENTRY)pB;
  274. // Ignore case
  275. return _wcsicmp((LPCWSTR)pEA->pKey, (LPCWSTR)pEB->pKey);
  276. }
  277. } // namespace DirectUI
  278. #endif // DUI_BASE_BTREELOOKUP_H_INCLUDED