HashMap.cppm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. export module Core.HashMap;
  2. export import Core.Types;
  3. export import Core.Utility;
  4. export import Core.New;
  5. import Core.List;
  6. import Core.ToString;
  7. import Core.AlignedData;
  8. import Core.Math;
  9. import Core.Meta;
  10. export template<typename T>
  11. concept Hashable = requires(const T& t) { t.hashCode(); };
  12. export template<typename T>
  13. concept HashCast = requires(const T& t) { static_cast<size_t>(t); };
  14. export namespace Core {
  15. template<Hashable H>
  16. inline size_t hashCode(const H& key) {
  17. return key.hashCode();
  18. }
  19. template<HashCast H>
  20. inline size_t hashCode(const H& key) {
  21. return static_cast<size_t>(key);
  22. }
  23. template<Moveable K, Moveable V>
  24. struct HashMap final {
  25. template<typename Value>
  26. class Node final {
  27. friend HashMap;
  28. K key;
  29. public:
  30. Value& value;
  31. const K& getKey() const noexcept {
  32. return key;
  33. }
  34. size_t toString(StringBase& b) const noexcept {
  35. return b.addFormat("{} = {}", key, value);
  36. }
  37. private:
  38. Node(const K& key_, Value& value_) noexcept :
  39. key(key_), value(value_) {
  40. }
  41. };
  42. private:
  43. static inline K INVALID = {};
  44. template<typename Value, typename R, R (*A)(const K&, Value&)>
  45. class Iterator final {
  46. const K* currentKey;
  47. const K* endKey;
  48. Value* currentValue;
  49. public:
  50. Iterator(
  51. const K* key, const K* endKey_, Value* value,
  52. bool invalidSet) noexcept :
  53. currentKey(key), endKey(endKey_), currentValue(value) {
  54. if(!invalidSet) {
  55. skip();
  56. }
  57. }
  58. Iterator& operator++() noexcept {
  59. ++currentKey;
  60. ++currentValue;
  61. skip();
  62. return *this;
  63. }
  64. bool operator!=(const Iterator& other) const noexcept {
  65. return currentKey != other.currentKey;
  66. }
  67. R operator*() const noexcept {
  68. return A(*currentKey, *currentValue);
  69. }
  70. private:
  71. void skip() noexcept {
  72. while(currentKey != endKey && *currentKey == INVALID) {
  73. ++currentKey;
  74. ++currentValue;
  75. }
  76. }
  77. };
  78. template<typename Value>
  79. static Node<Value> access(const K& key, Value& value) noexcept {
  80. return Node<Value>(key, value);
  81. }
  82. template<typename Value>
  83. static Value& accessValue(const K&, Value& value) noexcept {
  84. return value;
  85. }
  86. static const K& accessKey(const K& key, const V&) noexcept {
  87. return key;
  88. }
  89. template<typename Value>
  90. using BaseEntryIterator = Iterator<Value, Node<Value>, access<Value>>;
  91. using EntryIterator = BaseEntryIterator<V>;
  92. using ConstEntryIterator = BaseEntryIterator<const V>;
  93. template<typename Value>
  94. using BaseValueIterator = Iterator<Value, Value&, accessValue<Value>>;
  95. using ValueIterator = BaseValueIterator<V>;
  96. using ConstValueIterator = BaseValueIterator<const V>;
  97. using ConstKeyIterator = Iterator<const V, const K&, accessKey>;
  98. template<typename M, typename I>
  99. struct IteratorAdapter final {
  100. M& map;
  101. I begin() const noexcept {
  102. return {
  103. map.keys.begin(), map.keys.end(), map.values,
  104. map.invalidSet};
  105. }
  106. I end() const noexcept {
  107. return {
  108. map.keys.end(), map.keys.end(), nullptr, map.invalidSet};
  109. }
  110. };
  111. using ValueIteratorAdapter = IteratorAdapter<HashMap, ValueIterator>;
  112. using ConstValueIteratorAdapter =
  113. IteratorAdapter<const HashMap, ConstValueIterator>;
  114. using ConstKeyIteratorAdapter =
  115. IteratorAdapter<const HashMap, ConstKeyIterator>;
  116. private:
  117. List<K> keys{};
  118. V* values = nullptr;
  119. List<i8> jumps{};
  120. size_t entries = 0;
  121. bool invalidSet = false;
  122. public:
  123. HashMap() noexcept = default;
  124. HashMap(const HashMap& other) noexcept {
  125. for(const auto& e : other) {
  126. add(e.getKey(), e.value);
  127. }
  128. }
  129. HashMap(HashMap&& other) noexcept {
  130. swap(other);
  131. }
  132. ~HashMap() noexcept {
  133. size_t length = keys.getLength();
  134. if(length > 0) {
  135. for(size_t i = 1; i < length; i++) {
  136. if(keys[i] != INVALID) {
  137. values[i].~V();
  138. }
  139. }
  140. if(invalidSet) {
  141. values[length].~V();
  142. }
  143. }
  144. deleteWithSourceN<AlignedType<V>>(
  145. reinterpret_cast<AlignedType<V>*>(values));
  146. }
  147. HashMap& operator=(HashMap other) noexcept {
  148. swap(other);
  149. return *this;
  150. }
  151. void rehash(size_t minCapacity) noexcept {
  152. if(minCapacity <= keys.getLength()) {
  153. return;
  154. }
  155. HashMap<K, V> map;
  156. size_t l = (1lu << roundUpLog2(max(minCapacity, 8lu))) + 1;
  157. map.keys.resize(l, INVALID);
  158. map.values =
  159. reinterpret_cast<V*>(newWithSourceN<AlignedType<V>>(l));
  160. map.jumps.resize(l, 0);
  161. size_t length = keys.getLength();
  162. if(length > 0) {
  163. for(size_t i = 1; i < length; i++) {
  164. if(keys[i] != INVALID) {
  165. map.add(keys[i], Core::move(values[i]));
  166. }
  167. }
  168. if(invalidSet) {
  169. map.add(INVALID, Core::move(values[length]));
  170. }
  171. }
  172. swap(map);
  173. }
  174. template<typename... Args>
  175. bool tryEmplace(V*& v, const K& key, Args&&... args) noexcept {
  176. size_t index = 0;
  177. if(key == INVALID) {
  178. if(invalidSet) {
  179. return false;
  180. }
  181. rehash(1);
  182. invalidSet = true;
  183. } else {
  184. index = searchSlot(key);
  185. if(keys[index] == key) {
  186. return false;
  187. }
  188. }
  189. keys[index] = key;
  190. static_assert(
  191. noexcept(new(values + index) V(Core::forward<Args>(args)...)));
  192. v = new(values + index) V(Core::forward<Args>(args)...);
  193. entries++;
  194. markSlot(key);
  195. return true;
  196. }
  197. template<typename VA>
  198. V& put(const K& key, VA&& value) noexcept {
  199. size_t index = 0;
  200. if(key == INVALID) {
  201. if(invalidSet) {
  202. static_assert(
  203. noexcept(values[0] = Core::forward<VA>(value)));
  204. return (values[0] = Core::forward<VA>(value));
  205. }
  206. rehash(1);
  207. invalidSet = true;
  208. } else {
  209. index = searchSlot(key);
  210. if(keys[index] == key) {
  211. static_assert(
  212. noexcept(values[index] = Core::forward<VA>(value)));
  213. return (values[index] = Core::forward<VA>(value));
  214. }
  215. }
  216. static_assert(
  217. noexcept(new(values + index) V(Core::forward<VA>(value))));
  218. new(values + index) V(Core::forward<VA>(value));
  219. entries++;
  220. keys[index] = key;
  221. markSlot(key);
  222. return values[index];
  223. }
  224. template<typename VA>
  225. HashMap& add(const K& key, VA&& value) noexcept {
  226. put(key, Core::forward<VA>(value));
  227. return *this;
  228. }
  229. bool remove(const K& key) noexcept {
  230. size_t index = 0;
  231. if(key == INVALID) {
  232. if(!invalidSet) {
  233. return false;
  234. }
  235. invalidSet = false;
  236. } else {
  237. index = searchSlot(key);
  238. if(keys[index] != key) {
  239. return false;
  240. }
  241. }
  242. values[index].~V();
  243. entries--;
  244. demarkSlot(key);
  245. keys[index] = INVALID;
  246. return true;
  247. }
  248. const V* search(const K& key) const noexcept {
  249. return searchValue<const V>(key);
  250. }
  251. V* search(const K& key) noexcept {
  252. return searchValue<V>(key);
  253. }
  254. bool contains(const K& key) const noexcept {
  255. return search(key) != nullptr;
  256. }
  257. HashMap& clear() noexcept {
  258. HashMap<K, V> map;
  259. swap(map);
  260. return *this;
  261. }
  262. ConstKeyIteratorAdapter getKeys() const noexcept {
  263. return {*this};
  264. }
  265. ValueIteratorAdapter getValues() noexcept {
  266. return {*this};
  267. }
  268. ConstValueIteratorAdapter getValues() const noexcept {
  269. return {*this};
  270. }
  271. EntryIterator begin() noexcept {
  272. return {keys.begin(), keys.end(), values, invalidSet};
  273. }
  274. EntryIterator end() noexcept {
  275. return {keys.end(), keys.end(), nullptr, invalidSet};
  276. }
  277. ConstEntryIterator begin() const noexcept {
  278. return {keys.begin(), keys.end(), values, invalidSet};
  279. }
  280. ConstEntryIterator end() const noexcept {
  281. return {keys.end(), keys.end(), nullptr, invalidSet};
  282. }
  283. void swap(HashMap& o) noexcept {
  284. Core::swap(o.keys, keys);
  285. Core::swap(o.values, values);
  286. Core::swap(o.jumps, jumps);
  287. Core::swap(o.entries, entries);
  288. Core::swap(o.invalidSet, invalidSet);
  289. }
  290. private:
  291. // clang-format off
  292. #define FOR_EACH_HASH_START() \
  293. do { \
  294. size_t baseHash = hashCode(key) * 514'685'581u; \
  295. size_t end = keys.getLength() - 2; \
  296. for(size_t i = 0; i <= 5; i++) { \
  297. size_t hash = 1 + ((baseHash + i) & end)
  298. #define FOR_EACH_HASH_STOP() \
  299. } \
  300. } while(false)
  301. // clang-format on
  302. size_t searchSlot(const K& key) noexcept {
  303. rehash(1);
  304. while(true) {
  305. // rehash on bad clustering
  306. FOR_EACH_HASH_START();
  307. if((keys[hash] == INVALID && jumps[hash] == 0) ||
  308. keys[hash] == key) {
  309. return hash;
  310. }
  311. FOR_EACH_HASH_STOP();
  312. rehash(keys.getLength() + 1);
  313. }
  314. }
  315. void markSlot(const K& key) noexcept {
  316. FOR_EACH_HASH_START();
  317. if(keys[hash] == key) {
  318. return;
  319. }
  320. jumps[hash]++;
  321. FOR_EACH_HASH_STOP();
  322. }
  323. void demarkSlot(const K& key) noexcept {
  324. FOR_EACH_HASH_START();
  325. if(keys[hash] == key) {
  326. return;
  327. }
  328. jumps[hash]--;
  329. FOR_EACH_HASH_STOP();
  330. }
  331. template<typename Value>
  332. Value* searchValue(const K& key) const noexcept {
  333. if(keys.getLength() != 0) {
  334. if(key == INVALID) {
  335. return invalidSet ? values : nullptr;
  336. }
  337. FOR_EACH_HASH_START();
  338. if(keys[hash] == key) {
  339. return values + hash;
  340. } else if(jumps[hash] == 0) {
  341. return nullptr;
  342. }
  343. FOR_EACH_HASH_STOP();
  344. }
  345. return nullptr;
  346. }
  347. };
  348. }