hash_map.hpp 9.3 KB

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