HashTable.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  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 T>
  10. class Bucket
  11. {
  12. public:
  13. T element;
  14. int value;
  15. public:
  16. Bucket() : element(), value(0) {}
  17. static void Copy(Bucket<T> const& bucket, Bucket<T>& newBucket)
  18. {
  19. bucket.element.Copy(&(newBucket.element));
  20. newBucket.value = bucket.value;
  21. }
  22. };
  23. template<typename T, typename TAllocator = ArenaAllocator>
  24. class HashTable
  25. {
  26. public:
  27. TAllocator * alloc;
  28. uint tableSize;
  29. SListBase<Bucket<T>> * table;
  30. public:
  31. static HashTable<T, TAllocator> * New(TAllocator *allocator, DECLSPEC_GUARD_OVERFLOW uint tableSize)
  32. {
  33. return AllocatorNewPlus(TAllocator, allocator, (tableSize*sizeof(SListBase<Bucket<T>>)), HashTable, allocator, tableSize);
  34. }
  35. void Delete()
  36. {
  37. AllocatorDeletePlus(TAllocator, alloc, (tableSize*sizeof(SListBase<Bucket<T>>)), this);
  38. }
  39. ~HashTable()
  40. {
  41. for (uint i = 0; i< tableSize; i++)
  42. {
  43. table[i].Clear(alloc);
  44. }
  45. }
  46. SListBase<Bucket<T>> * SwapBucket(SListBase<Bucket<T>> * newTable)
  47. {
  48. SListBase<Bucket<T>> * retTable = table;
  49. table = newTable;
  50. return retTable;
  51. }
  52. T * FindOrInsertNew(int value)
  53. {
  54. uint hash = this->Hash(value);
  55. #if PROFILE_DICTIONARY
  56. uint depth = 1;
  57. #endif
  58. // Keep sorted
  59. FOREACH_SLISTBASE_ENTRY_EDITING(Bucket<T>, bucket, &this->table[hash], iter)
  60. {
  61. if (bucket.value <= value)
  62. {
  63. if (bucket.value == value)
  64. {
  65. return &(bucket.element);
  66. }
  67. break;
  68. }
  69. #if PROFILE_DICTIONARY
  70. ++depth;
  71. #endif
  72. } NEXT_SLISTBASE_ENTRY_EDITING;
  73. Bucket<T> * newBucket = iter.InsertNodeBefore(this->alloc);
  74. newBucket->value = value;
  75. #if PROFILE_DICTIONARY
  76. if (stats)
  77. stats->Insert(depth);
  78. #endif
  79. return &newBucket->element;
  80. }
  81. T * FindOrInsertNewNoThrow(int value)
  82. {
  83. uint hash = this->Hash(value);
  84. #if PROFILE_DICTIONARY
  85. uint depth = 1;
  86. #endif
  87. // Keep sorted
  88. FOREACH_SLISTBASE_ENTRY_EDITING(Bucket<T>, bucket, &this->table[hash], iter)
  89. {
  90. if (bucket.value <= value)
  91. {
  92. if (bucket.value == value)
  93. {
  94. return &(bucket.element);
  95. }
  96. break;
  97. }
  98. #if PROFILE_DICTIONARY
  99. ++depth;
  100. #endif
  101. } NEXT_SLISTBASE_ENTRY_EDITING;
  102. Bucket<T> * newBucket = iter.InsertNodeBeforeNoThrow(this->alloc);
  103. if (newBucket == nullptr)
  104. {
  105. return nullptr;
  106. }
  107. newBucket->value = value;
  108. #if PROFILE_DICTIONARY
  109. if (stats)
  110. stats->Insert(depth);
  111. #endif
  112. return &newBucket->element;
  113. }
  114. T * FindOrInsert(T element, int value)
  115. {
  116. uint hash = this->Hash(value);
  117. #if PROFILE_DICTIONARY
  118. uint depth = 1;
  119. #endif
  120. // Keep sorted
  121. FOREACH_SLISTBASE_ENTRY_EDITING(Bucket<T>, bucket, &this->table[hash], iter)
  122. {
  123. if (bucket.value <= value)
  124. {
  125. if (bucket.value == value)
  126. {
  127. return &(bucket.element);
  128. }
  129. break;
  130. }
  131. #if PROFILE_DICTIONARY
  132. ++depth;
  133. #endif
  134. } NEXT_SLISTBASE_ENTRY_EDITING;
  135. Bucket<T> * newBucket = iter.InsertNodeBefore(this->alloc);
  136. Assert(newBucket != nullptr);
  137. newBucket->value = value;
  138. newBucket->element = element;
  139. #if PROFILE_DICTIONARY
  140. if (stats)
  141. stats->Insert(depth);
  142. #endif
  143. return nullptr;
  144. }
  145. T * Get(int value)
  146. {
  147. // Assumes sorted lists
  148. FOREACH_SLISTBASE_ENTRY(Bucket<T>, bucket, &this->table[this->Hash(value)])
  149. {
  150. if (bucket.value <= value)
  151. {
  152. if (bucket.value == value)
  153. {
  154. return &(bucket.element);
  155. }
  156. break;
  157. }
  158. } NEXT_SLISTBASE_ENTRY;
  159. return nullptr;
  160. }
  161. T GetAndClear(int value)
  162. {
  163. SListBase<Bucket<T>> * list = &this->table[this->Hash(value)];
  164. #if PROFILE_DICTIONARY
  165. bool first = true;
  166. #endif
  167. // Assumes sorted lists
  168. FOREACH_SLISTBASE_ENTRY_EDITING(Bucket<T>, bucket, list, iter)
  169. {
  170. if (bucket.value <= value)
  171. {
  172. if (bucket.value == value)
  173. {
  174. T retVal = bucket.element;
  175. iter.RemoveCurrent(this->alloc);
  176. #if PROFILE_DICTIONARY
  177. if (stats)
  178. stats->Remove(first && !(iter.Next()));
  179. #endif
  180. return retVal;
  181. }
  182. break;
  183. }
  184. #if PROFILE_DICTIONARY
  185. first = false;
  186. #endif
  187. } NEXT_SLISTBASE_ENTRY_EDITING;
  188. return T();
  189. }
  190. void Clear(int value)
  191. {
  192. SListBase<Bucket<T>> * list = &this->table[this->Hash(value)];
  193. // Assumes sorted lists
  194. #if PROFILE_DICTIONARY
  195. bool first = true;
  196. #endif
  197. FOREACH_SLISTBASE_ENTRY_EDITING(Bucket<T>, bucket, list, iter)
  198. {
  199. if (bucket.value <= value)
  200. {
  201. if (bucket.value == value)
  202. {
  203. iter.RemoveCurrent(this->alloc);
  204. #if PROFILE_DICTIONARY
  205. if (stats)
  206. stats->Remove(first && !(iter.Next()));
  207. #endif
  208. }
  209. return;
  210. }
  211. #if PROFILE_DICTIONARY
  212. first = false;
  213. #endif
  214. } NEXT_SLISTBASE_ENTRY_EDITING;
  215. }
  216. void And(HashTable<T> *this2)
  217. {
  218. for (uint i = 0; i < this->tableSize; i++)
  219. {
  220. _TYPENAME SListBase<Bucket<T>>::Iterator iter2(&this2->table[i]);
  221. iter2.Next();
  222. FOREACH_SLISTBASE_ENTRY_EDITING(Bucket<T>, bucket, &this->table[i], iter)
  223. {
  224. while (iter2.IsValid() && bucket.value < iter2.Data().value)
  225. {
  226. iter2.Next();
  227. }
  228. if (!iter2.IsValid() || bucket.value != iter2.Data().value || bucket.element != iter2.Data().element)
  229. {
  230. iter.RemoveCurrent(this->alloc);
  231. #if PROFILE_DICTIONARY
  232. if (stats)
  233. stats->Remove(false);
  234. #endif
  235. continue;
  236. }
  237. else
  238. {
  239. AssertMsg(bucket.value == iter2.Data().value && bucket.element == iter2.Data().element, "Huh??");
  240. }
  241. iter2.Next();
  242. } NEXT_SLISTBASE_ENTRY_EDITING;
  243. }
  244. }
  245. // "And" with fixup actions to take when data don't make it to the result.
  246. template <class FnFrom, class FnTo>
  247. void AndWithFixup(HashTable<T> *this2, FnFrom fnFixupFrom, FnTo fnFixupTo)
  248. {
  249. for (uint i = 0; i < this->tableSize; i++)
  250. {
  251. _TYPENAME SListBase<Bucket<T>>::Iterator iter2(&this2->table[i]);
  252. iter2.Next();
  253. FOREACH_SLISTBASE_ENTRY_EDITING(Bucket<T>, bucket, &this->table[i], iter)
  254. {
  255. while (iter2.IsValid() && bucket.value < iter2.Data().value)
  256. {
  257. // Skipping a this2 value.
  258. fnFixupTo(iter2.Data());
  259. iter2.Next();
  260. }
  261. if (!iter2.IsValid() || bucket.value != iter2.Data().value || bucket.element != iter2.Data().element)
  262. {
  263. // Skipping a this value.
  264. fnFixupFrom(bucket);
  265. iter.RemoveCurrent(this->alloc);
  266. #if PROFILE_DICTIONARY
  267. if (stats)
  268. stats->Remove(false);
  269. #endif
  270. continue;
  271. }
  272. else
  273. {
  274. AssertMsg(bucket.value == iter2.Data().value && bucket.element == iter2.Data().element, "Huh??");
  275. }
  276. iter2.Next();
  277. } NEXT_SLISTBASE_ENTRY_EDITING;
  278. while (iter2.IsValid())
  279. {
  280. // Skipping a this2 value.
  281. fnFixupTo(iter2.Data());
  282. iter2.Next();
  283. }
  284. }
  285. }
  286. template <class Fn>
  287. void Or(HashTable<T> * this2, Fn fn)
  288. {
  289. for (uint i = 0; i < this->tableSize; i++)
  290. {
  291. _TYPENAME SListBase<Bucket<T>>::Iterator iter2(&this2->table[i]);
  292. iter2.Next();
  293. FOREACH_SLISTBASE_ENTRY_EDITING(Bucket<T>, bucket, &this->table[i], iter)
  294. {
  295. while (iter2.IsValid() && bucket.value < iter2.Data().value)
  296. {
  297. Bucket<T> * newBucket = iter.InsertNodeBefore(this->alloc);
  298. newBucket->value = iter2.Data().value;
  299. newBucket->element = fn(nullptr, iter2.Data().element);
  300. iter2.Next();
  301. }
  302. if (!iter2.IsValid())
  303. {
  304. break;
  305. }
  306. if (bucket.value == iter2.Data().value)
  307. {
  308. bucket.element = fn(bucket.element, iter2.Data().element);
  309. iter2.Next();
  310. }
  311. } NEXT_SLISTBASE_ENTRY_EDITING;
  312. while (iter2.IsValid())
  313. {
  314. Bucket<T> * newBucket = iter.InsertNodeBefore(this->alloc);
  315. newBucket->value = iter2.Data().value;
  316. newBucket->element = fn(nullptr, iter2.Data().element);
  317. iter2.Next();
  318. }
  319. }
  320. }
  321. HashTable<T> *Copy()
  322. {
  323. HashTable<T> *newTable = HashTable<T>::New(this->alloc, this->tableSize);
  324. for (uint i = 0; i < this->tableSize; i++)
  325. {
  326. this->table[i].template CopyTo<Bucket<T>::Copy>(this->alloc, newTable->table[i]);
  327. }
  328. #if PROFILE_DICTIONARY
  329. if (stats)
  330. newTable->stats = stats->Clone();
  331. #endif
  332. return newTable;
  333. }
  334. void ClearAll()
  335. {
  336. for (uint i = 0; i < this->tableSize; i++)
  337. {
  338. this->table[i].Clear(this->alloc);
  339. }
  340. #if PROFILE_DICTIONARY
  341. // To not lose previously collected data, we will treat cleared dictionary as a separate instance for stats tracking purpose
  342. stats = DictionaryStats::Create(typeid(this).name(), tableSize);
  343. #endif
  344. }
  345. #if DBG_DUMP
  346. void Dump(uint newLinePerEntry = 2);
  347. void Dump(void (*valueDump)(int));
  348. #endif
  349. protected:
  350. HashTable(TAllocator * allocator, DECLSPEC_GUARD_OVERFLOW uint tableSize) : alloc(allocator), tableSize(tableSize)
  351. {
  352. Init();
  353. #if PROFILE_DICTIONARY
  354. stats = DictionaryStats::Create(typeid(this).name(), tableSize);
  355. #endif
  356. }
  357. void Init()
  358. {
  359. table = (SListBase<Bucket<T>> *)(((char *)this) + sizeof(HashTable<T>));
  360. for (uint i = 0; i < tableSize; i++)
  361. {
  362. // placement new
  363. ::new (&table[i]) SListBase<Bucket<T>>();
  364. }
  365. }
  366. private:
  367. uint Hash(int value) { return (value % this->tableSize); }
  368. #if PROFILE_DICTIONARY
  369. DictionaryStats *stats;
  370. #endif
  371. };
  372. template <typename T, uint size, typename TAllocator = ArenaAllocator>
  373. class HashTableS : public HashTable<T, TAllocator>
  374. {
  375. public:
  376. HashTableS(TAllocator * allocator) : HashTable(allocator, size) {}
  377. void Reset()
  378. {
  379. __super::Init();
  380. }
  381. private:
  382. char tableSpace[size * sizeof(SListBase<Bucket<T>>)];
  383. };
  384. #define FOREACH_HASHTABLE_ENTRY(T, bucket, hashTable) \
  385. for (uint _iterHash = 0; _iterHash < (hashTable)->tableSize; _iterHash++) \
  386. { \
  387. FOREACH_SLISTBASE_ENTRY(Bucket<T>, bucket, &(hashTable)->table[_iterHash]) \
  388. {
  389. #define NEXT_HASHTABLE_ENTRY \
  390. } \
  391. NEXT_SLISTBASE_ENTRY; \
  392. }
  393. #if DBG_DUMP
  394. template <typename T, typename TAllocator>
  395. inline void
  396. HashTable<T, TAllocator>::Dump(uint newLinePerEntry)
  397. {
  398. FOREACH_HASHTABLE_ENTRY(T, bucket, this)
  399. {
  400. Output::Print(_u("%4d => "), bucket.value);
  401. ::Dump<T>(bucket.element);
  402. for (uint i = 0; i < newLinePerEntry; i++)
  403. {
  404. Output::Print(_u("\n"));
  405. }
  406. }
  407. NEXT_HASHTABLE_ENTRY;
  408. }
  409. template <typename T, typename TAllocator>
  410. inline void
  411. HashTable<T, TAllocator>::Dump(void (*valueDump)(int))
  412. {
  413. FOREACH_HASHTABLE_ENTRY(T, bucket, this)
  414. {
  415. valueDump(bucket.value);
  416. Output::Print(_u(" => "), bucket.value);
  417. ::Dump<T>(bucket.element);
  418. Output::Print(_u("\n"));
  419. }
  420. NEXT_HASHTABLE_ENTRY;
  421. }
  422. template <typename T>
  423. inline void Dump(T const& t)
  424. {
  425. t.Dump();
  426. }
  427. #endif