GlobHashTable.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. #if PROFILE_DICTIONARY
  7. #include "DictionaryStats.h"
  8. #endif
  9. template <typename TData, typename TElement>
  10. class HashBucket
  11. {
  12. public:
  13. TElement element;
  14. TData value;
  15. public:
  16. HashBucket() : element(NULL), value(NULL) {}
  17. static void Copy(HashBucket const& bucket, HashBucket& newBucket)
  18. {
  19. newBucket.element = bucket.element;
  20. newBucket.value = bucket.value;
  21. }
  22. };
  23. class Key
  24. {
  25. public:
  26. static uint Get(Sym *sym) { return static_cast<uint>(sym->m_id); }
  27. static uint Get(ExprHash hash) { return static_cast<uint>(hash); }
  28. };
  29. #define FOREACH_GLOBHASHTABLE_ENTRY(bucket, hashTable) \
  30. for (uint _iterHash = 0; _iterHash < (hashTable)->tableSize; _iterHash++) \
  31. { \
  32. FOREACH_SLISTBASE_ENTRY(GlobHashBucket, bucket, &(hashTable)->table[_iterHash]) \
  33. {
  34. #define NEXT_GLOBHASHTABLE_ENTRY \
  35. } \
  36. NEXT_SLISTBASE_ENTRY; \
  37. }
  38. template<typename TData, typename TElement>
  39. class ValueHashTable
  40. {
  41. private:
  42. typedef HashBucket<TData, TElement> HashBucket;
  43. public:
  44. JitArenaAllocator * alloc;
  45. uint tableSize;
  46. SListBase<HashBucket> * table;
  47. public:
  48. static ValueHashTable * New(JitArenaAllocator *allocator, uint tableSize)
  49. {
  50. return AllocatorNewPlus(JitArenaAllocator, allocator, (tableSize*sizeof(SListBase<HashBucket>)), ValueHashTable, allocator, tableSize);
  51. }
  52. void Delete()
  53. {
  54. AllocatorDeletePlus(JitArenaAllocator, alloc, (tableSize*sizeof(SListBase<HashBucket>)), this);
  55. }
  56. ~ValueHashTable()
  57. {
  58. for (uint i = 0; i< tableSize; i++)
  59. {
  60. table[i].Clear(alloc);
  61. }
  62. }
  63. SListBase<HashBucket> * SwapBucket(SListBase<HashBucket> * newTable)
  64. {
  65. SListBase<HashBucket> * retTable = table;
  66. table = newTable;
  67. return retTable;
  68. }
  69. TElement * FindOrInsertNew(TData value)
  70. {
  71. uint key = Key::Get(value);
  72. uint hash = this->Hash(key);
  73. #if PROFILE_DICTIONARY
  74. uint depth = 1;
  75. #endif
  76. // Keep sorted
  77. FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, &this->table[hash], iter)
  78. {
  79. if (Key::Get(bucket.value) <= key)
  80. {
  81. if (Key::Get(bucket.value) == key)
  82. {
  83. return &(bucket.element);
  84. }
  85. break;
  86. }
  87. #if PROFILE_DICTIONARY
  88. ++depth;
  89. #endif
  90. } NEXT_SLISTBASE_ENTRY_EDITING;
  91. HashBucket * newBucket = iter.InsertNodeBefore(this->alloc);
  92. newBucket->value = value;
  93. #if PROFILE_DICTIONARY
  94. if (stats)
  95. stats->Insert(depth);
  96. #endif
  97. return &newBucket->element;
  98. }
  99. TElement * FindOrInsertNewNoThrow(TData * value)
  100. {
  101. uint key = Key::Get(value);
  102. uint hash = this->Hash(key);
  103. #if PROFILE_DICTIONARY
  104. uint depth = 1;
  105. #endif
  106. // Keep sorted
  107. FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, &this->table[hash], iter)
  108. {
  109. if (Key::Get(bucket.value) <= key)
  110. {
  111. if (Key::Get(bucket.value) == key)
  112. {
  113. return &(bucket.element);
  114. }
  115. break;
  116. }
  117. #if PROFILE_DICTIONARY
  118. ++depth;
  119. #endif
  120. } NEXT_SLISTBASE_ENTRY_EDITING;
  121. HashBucket * newBucket = iter.InsertNodeBeforeNoThrow(this->alloc);
  122. if (newBucket == nullptr)
  123. {
  124. return nullptr;
  125. }
  126. newBucket->value = value;
  127. #if PROFILE_DICTIONARY
  128. if (stats)
  129. stats->Insert(depth);
  130. #endif
  131. return &newBucket->element;
  132. }
  133. TElement * FindOrInsert(TElement element, TData value)
  134. {
  135. uint key = Key::Get(value);
  136. uint hash = this->Hash(key);
  137. #if PROFILE_DICTIONARY
  138. uint depth = 1;
  139. #endif
  140. // Keep sorted
  141. FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, &this->table[hash], iter)
  142. {
  143. if (Key::Get(bucket.value) <= key)
  144. {
  145. if (Key::Get(bucket.value) == key)
  146. {
  147. return &(bucket.element);
  148. }
  149. break;
  150. }
  151. #if PROFILE_DICTIONARY
  152. ++depth;
  153. #endif
  154. } NEXT_SLISTBASE_ENTRY_EDITING;
  155. HashBucket * newBucket = iter.InsertNodeBefore(this->alloc);
  156. Assert(newBucket != nullptr);
  157. newBucket->value = value;
  158. newBucket->element = element;
  159. #if PROFILE_DICTIONARY
  160. if (stats)
  161. stats->Insert(depth);
  162. #endif
  163. return NULL;
  164. }
  165. TElement * Get(TData value)
  166. {
  167. uint key = Key::Get(value);
  168. return Get(key);
  169. }
  170. TElement * Get(uint key)
  171. {
  172. uint hash = this->Hash(key);
  173. // Assumes sorted lists
  174. FOREACH_SLISTBASE_ENTRY(HashBucket, bucket, &this->table[hash])
  175. {
  176. if (Key::Get(bucket.value) <= key)
  177. {
  178. if (Key::Get(bucket.value) == key)
  179. {
  180. return &(bucket.element);
  181. }
  182. break;
  183. }
  184. } NEXT_SLISTBASE_ENTRY;
  185. return NULL;
  186. }
  187. TElement GetAndClear(TData * value)
  188. {
  189. uint key = Key::Get(value);
  190. uint hash = this->Hash(key);
  191. SListBase<HashBucket> * list = &this->table[hash];
  192. #if PROFILE_DICTIONARY
  193. bool first = true;
  194. #endif
  195. // Assumes sorted lists
  196. FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, list, iter)
  197. {
  198. if (Key::Get(bucket.value) <= key)
  199. {
  200. if (Key::Get(bucket.value) == key)
  201. {
  202. TElement retVal = bucket.element;
  203. iter.RemoveCurrent(this->alloc);
  204. #if PROFILE_DICTIONARY
  205. if (stats)
  206. stats->Remove(first && !(iter.Next()));
  207. #endif
  208. return retVal;
  209. }
  210. break;
  211. }
  212. #if PROFILE_DICTIONARY
  213. first = false;
  214. #endif
  215. } NEXT_SLISTBASE_ENTRY_EDITING;
  216. return nullptr;
  217. }
  218. void Clear(uint key)
  219. {
  220. uint hash = this->Hash(key);
  221. SListBase<HashBucket> * list = &this->table[hash];
  222. // Assumes sorted lists
  223. #if PROFILE_DICTIONARY
  224. bool first = true;
  225. #endif
  226. FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, list, iter)
  227. {
  228. if (Key::Get(bucket.value) <= key)
  229. {
  230. if (Key::Get(bucket.value) == key)
  231. {
  232. iter.RemoveCurrent(this->alloc);
  233. #if PROFILE_DICTIONARY
  234. if (stats)
  235. stats->Remove(first && !(iter.Next()));
  236. #endif
  237. }
  238. return;
  239. }
  240. #if PROFILE_DICTIONARY
  241. first = false;
  242. #endif
  243. } NEXT_SLISTBASE_ENTRY_EDITING;
  244. }
  245. void And(ValueHashTable *this2)
  246. {
  247. for (uint i = 0; i < this->tableSize; i++)
  248. {
  249. SListBase<HashBucket>::Iterator iter2(&this2->table[i]);
  250. iter2.Next();
  251. FOREACH_SLISTBASE_ENTRY_EDITING(HashBucket, bucket, &this->table[i], iter)
  252. {
  253. while (iter2.IsValid() && bucket.value < iter2.Data().value)
  254. {
  255. iter2.Next();
  256. }
  257. if (!iter2.IsValid() || bucket.value != iter2.Data().value || bucket.element != iter2.Data().element)
  258. {
  259. iter.RemoveCurrent(this->alloc);
  260. #if PROFILE_DICTIONARY
  261. if (stats)
  262. stats->Remove(false);
  263. #endif
  264. continue;
  265. }
  266. else
  267. {
  268. AssertMsg(bucket.value == iter2.Data().value && bucket.element == iter2.Data().element, "Huh??");
  269. }
  270. iter2.Next();
  271. } NEXT_SLISTBASE_ENTRY_EDITING;
  272. }
  273. }
  274. template <class Fn>
  275. void Or(ValueHashTable * this2, Fn fn)
  276. {
  277. for (uint i = 0; i < this->tableSize; i++)
  278. {
  279. SListBase<HashBucket>::Iterator iter2(&this2->table[i]);
  280. iter2.Next();
  281. FOREACH_SLISTBASE_ENTRY_EDITING((HashBucket), bucket, &this->table[i], iter)
  282. {
  283. while (iter2.IsValid() && bucket.value < iter2.Data().value)
  284. {
  285. HashBucket * newBucket = iter.InsertNodeBefore(this->alloc);
  286. newBucket->value = iter2.Data().value;
  287. newBucket->element = fn(null, iter2.Data().element);
  288. iter2.Next();
  289. }
  290. if (!iter2.IsValid())
  291. {
  292. break;
  293. }
  294. if (bucket.value == iter2.Data().value)
  295. {
  296. bucket.element = fn(bucket.element, iter2.Data().element);
  297. iter2.Next();
  298. }
  299. } NEXT_SLISTBASE_ENTRY_EDITING;
  300. while (iter2.IsValid())
  301. {
  302. HashBucket * newBucket = iter.InsertNodeBefore(this->alloc);
  303. newBucket->value = iter2.Data().value;
  304. newBucket->element = fn(null, iter2.Data().element);
  305. iter2.Next();
  306. }
  307. }
  308. }
  309. ValueHashTable *Copy()
  310. {
  311. ValueHashTable *newTable = ValueHashTable::New(this->alloc, this->tableSize);
  312. for (uint i = 0; i < this->tableSize; i++)
  313. {
  314. this->table[i].CopyTo<HashBucket::Copy>(this->alloc, newTable->table[i]);
  315. }
  316. #if PROFILE_DICTIONARY
  317. if (stats)
  318. newTable->stats = stats->Clone();
  319. #endif
  320. return newTable;
  321. }
  322. void ClearAll()
  323. {
  324. for (uint i = 0; i < this->tableSize; i++)
  325. {
  326. this->table[i].Clear(this->alloc);
  327. }
  328. #if PROFILE_DICTIONARY
  329. // To not lose previously collected data, we will treat cleared dictionary as a separate instance for stats tracking purpose
  330. stats = DictionaryStats::Create(typeid(this).name(), tableSize);
  331. #endif
  332. }
  333. #if DBG_DUMP
  334. void Dump()
  335. {
  336. FOREACH_GLOBHASHTABLE_ENTRY(bucket, this)
  337. {
  338. Output::Print(L"%4d => ", bucket.value);
  339. bucket.element->Dump();
  340. Output::Print(L"\n");
  341. Output::Print(L"\n");
  342. }
  343. NEXT_GLOBHASHTABLE_ENTRY;
  344. }
  345. void Dump(void (*valueDump)(TData))
  346. {
  347. Output::Print(L"\n-------------------------------------------------------------------------------------------------\n");
  348. FOREACH_GLOBHASHTABLE_ENTRY(bucket, this)
  349. {
  350. valueDump(bucket.value);
  351. Output::Print(L" => ", bucket.value);
  352. bucket.element->Dump();
  353. Output::Print(L"\n");
  354. }
  355. NEXT_GLOBHASHTABLE_ENTRY;
  356. }
  357. #endif
  358. protected:
  359. ValueHashTable(JitArenaAllocator * allocator, uint tableSize) : alloc(allocator), tableSize(tableSize)
  360. {
  361. Init();
  362. #if PROFILE_DICTIONARY
  363. stats = DictionaryStats::Create(typeid(this).name(), tableSize);
  364. #endif
  365. }
  366. void Init()
  367. {
  368. table = (SListBase<HashBucket> *)(((char *)this) + sizeof(ValueHashTable));
  369. for (uint i = 0; i < tableSize; i++)
  370. {
  371. // placement new
  372. ::new (&table[i]) SListBase<HashBucket>();
  373. }
  374. }
  375. private:
  376. uint Hash(uint key) { return (key % this->tableSize); }
  377. #if PROFILE_DICTIONARY
  378. DictionaryStats *stats;
  379. #endif
  380. };