hash_map.hpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. #pragma once
  2. #include <assert.h>
  3. #include <bit>
  4. #include <map>
  5. #include <string>
  6. #include <type_traits>
  7. #include <utility>
  8. #include <vector>
  9. #include <stdint.h>
  10. #include <types/allocator.hpp>
  11. #include <types/cplusplus.hpp>
  12. #include <types/types.h>
  13. namespace types {
  14. // taken from linux
  15. constexpr uint32_t GOLDEN_RATIO_32 = 0x61C88647;
  16. // constexpr uint64_t GOLDEN_RATIO_64 = 0x61C8864680B583EBull;
  17. using hash_t = size_t;
  18. static inline constexpr hash_t _hash32(uint32_t val)
  19. {
  20. return val * GOLDEN_RATIO_32;
  21. }
  22. static inline constexpr hash_t hash32(uint32_t val, uint32_t bits)
  23. {
  24. // higher bits are more random
  25. return _hash32(val) >> (32 - bits);
  26. }
  27. template <typename T>
  28. constexpr bool is_c_string_v = std::is_same_v<std::decay_t<T>, char*>
  29. || std::is_same_v<std::decay_t<T>, const char*>;
  30. template <typename T,
  31. std::enable_if_t<std::is_convertible_v<T, uint32_t>, bool> = true>
  32. inline hash_t hash(T val, std::size_t bits)
  33. {
  34. return hash32(static_cast<uint32_t>(val), bits);
  35. }
  36. template <typename T,
  37. std::enable_if_t<std::is_pointer_v<T> && !is_c_string_v<T>, bool> = true>
  38. inline hash_t hash(T val, std::size_t bits)
  39. {
  40. return hash32(std::bit_cast<uint32_t>(val), bits);
  41. }
  42. inline hash_t hash(const char* str, std::size_t bits)
  43. {
  44. constexpr uint32_t seed = 131;
  45. uint32_t hash = 0;
  46. while (*str)
  47. hash = hash * seed + (*str++);
  48. return hash32(hash, bits);
  49. };
  50. template <template <typename, typename, typename> typename String,
  51. typename Char, typename Traits, typename Allocator,
  52. std::enable_if_t<
  53. std::is_same_v<
  54. std::decay_t<String<Char, Traits, Allocator>>,
  55. std::basic_string<Char, Traits, Allocator>
  56. >, bool
  57. > = true>
  58. inline hash_t hash(const String<Char, Traits, Allocator>& str, std::size_t bits)
  59. {
  60. return hash(str.c_str(), bits);
  61. }
  62. template <typename Key, typename Value,
  63. typename Allocator = std::allocator<std::pair<const Key, Value> >,
  64. std::enable_if_t<std::is_convertible_v<hash_t, decltype(
  65. hash(std::declval<Key>(), std::declval<std::size_t>())
  66. )>, bool> = true>
  67. class hash_map {
  68. public:
  69. template <bool Const>
  70. class iterator;
  71. using key_type = std::add_const_t<Key>;
  72. using value_type = Value;
  73. using size_type = size_t;
  74. using difference_type = ssize_t;
  75. using iterator_type = iterator<false>;
  76. using const_iterator_type = iterator<true>;
  77. using bucket_type = std::map<key_type,
  78. value_type,std::less<key_type>, Allocator>;
  79. using bucket_array_type = std::vector<bucket_type, typename
  80. std::allocator_traits<Allocator>:: template rebind_alloc<bucket_type>>;
  81. static constexpr size_type INITIAL_BUCKETS_ALLOCATED = 64;
  82. public:
  83. template <bool Const>
  84. class iterator {
  85. public:
  86. using bucket_iterator = std::conditional_t<Const,
  87. typename bucket_type::const_iterator,
  88. typename bucket_type::iterator>;
  89. using _Value = typename bucket_iterator::value_type;
  90. using Pointer = typename bucket_iterator::pointer;
  91. using Reference = typename bucket_iterator::reference;
  92. using hash_map_pointer = std::conditional_t<Const,
  93. const hash_map*, hash_map*>;
  94. friend class hash_map;
  95. public:
  96. constexpr iterator(const iterator& iter) noexcept
  97. : n(iter.n), iter(iter.iter), hmap(iter.hmap)
  98. {
  99. }
  100. constexpr iterator(iterator&& iter) noexcept
  101. : n(std::exchange(iter.n, 0))
  102. , iter(std::move(iter.iter))
  103. , hmap(std::exchange(iter.hmap, nullptr))
  104. {
  105. }
  106. constexpr iterator& operator=(const iterator& iter)
  107. {
  108. n = iter.n;
  109. this->iter = iter.iter;
  110. hmap = iter.hmap;
  111. return *this;
  112. }
  113. explicit constexpr iterator(std::size_t n, bucket_iterator iter,
  114. hash_map_pointer hmap) noexcept
  115. : n(n), iter(iter), hmap(hmap)
  116. {
  117. }
  118. constexpr bool operator==(const iterator& iter) const noexcept
  119. {
  120. return (!*this && !iter) || (hmap == iter.hmap && n == iter.n && this->iter == iter.iter);
  121. }
  122. constexpr bool operator!=(const iterator& iter) const noexcept
  123. {
  124. return !(*this == iter);
  125. }
  126. constexpr iterator operator++()
  127. {
  128. assert((bool)*this);
  129. ++iter;
  130. while (iter == hmap->buckets[n].end()) {
  131. ++n;
  132. if (n < hmap->buckets.size())
  133. iter = hmap->buckets[n].begin();
  134. else
  135. break;
  136. }
  137. return *this;
  138. }
  139. constexpr iterator operator++(int)
  140. {
  141. iterator ret { *this };
  142. (void)this->operator++();
  143. return ret;
  144. }
  145. constexpr operator bool(void) const
  146. {
  147. return hmap && n < hmap->buckets.size() && !!iter;
  148. }
  149. constexpr Reference operator*(void) const noexcept
  150. {
  151. return *iter;
  152. }
  153. constexpr Pointer operator->(void) const noexcept
  154. {
  155. return &*iter;
  156. }
  157. constexpr operator const_iterator_type() const noexcept
  158. {
  159. return const_iterator_type(n, iter, hmap);
  160. }
  161. protected:
  162. std::size_t n;
  163. bucket_iterator iter;
  164. hash_map_pointer hmap;
  165. };
  166. private:
  167. bucket_array_type buckets;
  168. protected:
  169. constexpr uint32_t hash_length(void) const
  170. {
  171. switch (buckets.capacity()) {
  172. case 32:
  173. return 5;
  174. case 64:
  175. return 6;
  176. case 128:
  177. return 7;
  178. case 256:
  179. return 8;
  180. // TODO
  181. default:
  182. return 9;
  183. }
  184. }
  185. public:
  186. explicit constexpr hash_map(void)
  187. : buckets(INITIAL_BUCKETS_ALLOCATED) {}
  188. constexpr hash_map(const hash_map& v)
  189. : buckets(v.buckets) {}
  190. constexpr hash_map(hash_map&& v)
  191. : buckets(std::move(v.buckets)) {}
  192. constexpr ~hash_map()
  193. {
  194. buckets.clear();
  195. }
  196. template <typename... Args>
  197. constexpr void emplace(Args&&... args)
  198. {
  199. std::pair<Key, Value> to_insert{std::forward<Args>(args)...};
  200. auto hash_value = hash(to_insert.first, hash_length());
  201. buckets.at(hash_value).emplace(to_insert);
  202. }
  203. constexpr void remove(const_iterator_type iter)
  204. {
  205. auto& bucket = buckets[iter.n];
  206. bucket.erase(iter.iter);
  207. }
  208. constexpr void remove(iterator_type iter)
  209. {
  210. return remove((const_iterator_type)iter);
  211. }
  212. constexpr void remove(const key_type& key)
  213. {
  214. const_iterator_type iter = find(key);
  215. if (!iter)
  216. return;
  217. remove(iter);
  218. }
  219. constexpr iterator_type find(const key_type& key)
  220. {
  221. auto hash_value = hash(key, hash_length());
  222. auto& bucket = buckets.at(hash_value);
  223. for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) {
  224. if (key == iter->first)
  225. return iterator_type(hash_value, iter, this);
  226. }
  227. return this->end();
  228. }
  229. constexpr const_iterator_type find(const key_type& key) const
  230. {
  231. auto hash_value = hash(key, hash_length());
  232. const auto& bucket = buckets.at(hash_value);
  233. for (auto iter = bucket.cbegin(); iter != bucket.cend(); ++iter) {
  234. if (key == iter->first)
  235. return const_iterator_type(hash_value, iter, this);
  236. }
  237. return this->cend();
  238. }
  239. constexpr void clear(void)
  240. {
  241. for (auto& bucket : buckets)
  242. bucket.clear();
  243. }
  244. constexpr const_iterator_type cend() const noexcept
  245. {
  246. return const_iterator_type(buckets.size(), buckets[0].end(), this);
  247. }
  248. constexpr const_iterator_type end() const noexcept
  249. {
  250. return cend();
  251. }
  252. constexpr iterator_type end() noexcept
  253. {
  254. return iterator_type(buckets.size(), buckets[0].end(), this);
  255. }
  256. constexpr const_iterator_type cbegin() const noexcept
  257. {
  258. for (std::size_t i = 0; i < buckets.size(); ++i) {
  259. if (buckets[i].empty())
  260. continue;
  261. return const_iterator_type(i, buckets[i].begin(), this);
  262. }
  263. return cend();
  264. }
  265. constexpr const_iterator_type begin() const noexcept
  266. {
  267. return cbegin();
  268. }
  269. constexpr iterator_type begin() noexcept
  270. {
  271. for (std::size_t i = 0; i < buckets.size(); ++i) {
  272. if (buckets[i].empty())
  273. continue;
  274. return iterator_type(i, buckets[i].begin(), this);
  275. }
  276. return end();
  277. }
  278. };
  279. } // namespace types