bucket_hash_map.hpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. //
  2. // bucket_hash_map.hpp
  3. // bucket_hash_map
  4. //
  5. // Created by Sam Jaffe on 2/7/17.
  6. //
  7. #pragma once
  8. #include <algorithm>
  9. #include <list>
  10. #include <memory>
  11. #include <utility>
  12. #include <vector>
  13. #include "iterator/join_iterator.hpp"
  14. template <typename K, typename V, typename Hash = std::hash<K>, typename KeyEqual = std::equal_to<K> >
  15. class bucket_hash_map;
  16. template <typename K, typename V, typename Hash, typename KeyEqual>
  17. class bucket_hash_map {
  18. public: // typedefs
  19. using key_type = K;
  20. using mapped_type = V;
  21. using value_type = std::pair<key_type const, mapped_type>;
  22. using size_type = std::size_t;
  23. using difference_type = std::ptrdiff_t;
  24. using hasher = Hash;
  25. using key_equal = KeyEqual;
  26. using reference = value_type &;
  27. using const_reference = value_type const &;
  28. using pointer = value_type *;
  29. using const_pointer = value_type const *;
  30. using bucket_type = std::list<value_type>;
  31. using impl_type = std::vector<bucket_type>;
  32. using iterator = joining_iterator<typename impl_type::iterator>;
  33. using const_iterator = joining_iterator<typename impl_type::const_iterator>;
  34. using local_iterator = typename bucket_type::iterator;
  35. using local_const_iterator = typename bucket_type::const_iterator;
  36. static const constexpr size_type default_buckets = 10;
  37. static const constexpr float default_load_factor = 1.0F;
  38. static const constexpr float growth_factor = 2.0F;
  39. public:
  40. // Construction
  41. bucket_hash_map() : bucket_hash_map(default_buckets) {}
  42. bucket_hash_map(size_type num_buckets,
  43. hasher const & hash = hasher(),
  44. key_equal const & keq = key_equal()) :
  45. buckets_(num_buckets), hasher_(hash), key_equals_(keq) {}
  46. template <typename InputIt>
  47. bucket_hash_map(InputIt first, InputIt last,
  48. size_type num_buckets = default_buckets,
  49. hasher const & hash = hasher(),
  50. key_equal const & keq = key_equal())
  51. : bucket_hash_map(num_buckets, hash, keq) {
  52. insert(first, last);
  53. }
  54. bucket_hash_map(std::initializer_list<value_type> && ilist,
  55. size_type num_buckets = default_buckets,
  56. hasher const & hash = hasher(),
  57. key_equal const & keq = key_equal())
  58. : bucket_hash_map(num_buckets, hash, keq) {
  59. insert(ilist);
  60. }
  61. // Metadata
  62. bool empty() const { return size() == 0; }
  63. size_type size() const { return size_; }
  64. // Iterators
  65. iterator begin() { return { buckets_.begin(), buckets_.end() }; }
  66. const_iterator begin() const { return cbegin(); }
  67. const_iterator cbegin() const { return { buckets_.begin(), buckets_.end() }; }
  68. iterator end() { return { buckets_.end(), buckets_.end() }; }
  69. const_iterator end() const { return cend(); }
  70. const_iterator cend() const { return { buckets_.end(), buckets_.end() }; }
  71. // Create
  72. std::pair<iterator, bool> insert(value_type const & vt) {
  73. maybe_expand(1);
  74. auto lookup = lookup_impl(buckets_, vt.first);
  75. auto const end = lookup.first->end();
  76. bool const create = lookup.second == end;
  77. if ( create ) {
  78. ++size_;
  79. lookup.second = lookup.first->insert(end, vt);
  80. }
  81. return { {lookup.first, buckets_.end(), lookup.second, end}, create };
  82. }
  83. iterator insert(const_iterator, value_type const & vt) {
  84. return insert(vt).first;
  85. }
  86. template <typename InputIt>
  87. void insert(InputIt first, InputIt last) {
  88. maybe_expand(std::distance(first, last));
  89. while (first != last) { insert(*first++); }
  90. }
  91. void insert(std::initializer_list<value_type> ilist) { insert(ilist.begin(), ilist.end()); }
  92. // Access
  93. mapped_type & operator[](key_type const & key) {
  94. auto lookup = lookup_impl(buckets_, key);
  95. auto end = lookup.first->end();
  96. if (lookup.second == end) {
  97. ++size_;
  98. return lookup.first->insert(lookup.second, {key, mapped_type{}})->second;
  99. } else {
  100. return lookup.second->second;
  101. }
  102. }
  103. mapped_type & at(key_type const & key) {
  104. auto it = find(key);
  105. if (it == end()) { throw std::out_of_range{"no element at key"}; }
  106. return it->second;
  107. }
  108. mapped_type const & at(key_type const & key) const {
  109. auto it = find(key);
  110. if (it == end()) { throw std::out_of_range{"no element at key"}; }
  111. return it->second;
  112. }
  113. iterator find(key_type const & key) {
  114. return find_impl<iterator>(buckets_, key);
  115. }
  116. std::pair<iterator, iterator> equal_range(key_type const & key) {
  117. auto it = find(key);
  118. return { it, ++iterator(it) };
  119. }
  120. const_iterator find(key_type const & key) const {
  121. return find_impl<const_iterator>(buckets_, key);
  122. }
  123. std::pair<const_iterator, const_iterator> equal_range(key_type const & key) const {
  124. auto it = find(key);
  125. return { it, ++const_iterator(it) };
  126. }
  127. size_type count(key_type const & key) const { return find(key) != end(); }
  128. // Remove
  129. iterator erase(const_iterator it) {
  130. return erase_impl(unconst_iterator(it));
  131. }
  132. iterator erase(const_iterator first, const_iterator last) {
  133. iterator it = unconst_iterator(first);
  134. while (last != it) { it = erase_impl(it); }
  135. return it;
  136. }
  137. size_type erase(key_type const & key) {
  138. size_type old_size = size_;
  139. erase(find(key));
  140. return old_size - size_; // 1 or 0
  141. }
  142. void clear() { erase(begin(), end()); }
  143. // Bucket Interaction Functions
  144. local_iterator begin(size_type bkt) { return buckets_[bkt].begin(); }
  145. local_const_iterator begin(size_type bkt) const { return buckets_[bkt].cbegin(); }
  146. local_const_iterator cbegin(size_type bkt) const { return buckets_[bkt].cbegin(); }
  147. local_iterator end(size_type bkt) { return buckets_[bkt].end(); }
  148. local_const_iterator end(size_type bkt) const { return buckets_[bkt].cend(); }
  149. local_const_iterator cend(size_type bkt) const { return buckets_[bkt].cend(); }
  150. size_type bucket_count() const { return buckets_.size(); }
  151. size_type bucket_size(size_type bkt) const { return buckets_[bkt].size(); }
  152. size_type bucket(key_type const & key) const { return hasher_(key) % bucket_count(); }
  153. // Hash Policy
  154. float load_factor() const { return static_cast<float>(size()) / bucket_count(); }
  155. float max_load_factor() const { return max_load_; }
  156. void max_load_factor(float max_load) { max_load_ = max_load; }
  157. void rehash(size_type buckets) {
  158. buckets = std::max({1UL, buckets, static_cast<size_type>(size() / max_load_factor())});
  159. bucket_hash_map next{buckets, hasher_, key_equals_};
  160. next.max_load_factor(max_load_factor());
  161. next.insert(begin(), end());
  162. swap(next);
  163. }
  164. void reserve(size_type count) {
  165. rehash(static_cast<size_type>(count / max_load_factor()));
  166. }
  167. void swap( bucket_hash_map & other ) {
  168. using std::swap;
  169. swap(size_, other.size_);
  170. swap(buckets_, other.buckets_);
  171. swap(max_load_, other.max_load_);
  172. swap(hasher_, other.hasher_);
  173. swap(key_equals_, other.key_equals_);
  174. }
  175. friend void swap(bucket_hash_map & lhs, bucket_hash_map & rhs) { lhs.swap(rhs); }
  176. private:
  177. void maybe_expand(size_type add) {
  178. if ( static_cast<float>(size() + add) / bucket_count() > max_load_factor() ) {
  179. reserve(std::max(size() + add, static_cast<size_type>(size() * growth_factor)));
  180. }
  181. }
  182. template <typename Bucket>
  183. auto lookup_impl(Bucket & bkt, key_type const & key) const -> std::pair<decltype(bkt.begin()), decltype(bkt.begin()->begin())> {
  184. auto listit = bkt.begin() + bucket(key);
  185. auto it = search(listit, key);
  186. return {listit, it};
  187. }
  188. template <typename Iterator>
  189. auto search(Iterator lit, key_type const & key) const -> decltype(lit->begin()) {
  190. for ( auto it = lit->begin(); it != lit->end(); ++it ) {
  191. if ( key_equals_(key, it->first) ) { return it; }
  192. }
  193. return lit->end();
  194. }
  195. template <typename Iterator, typename Bucket>
  196. Iterator find_impl(Bucket & bkt, key_type const & key) const {
  197. auto lookup = lookup_impl(bkt, key);
  198. if (lookup.second == lookup.first->end()) {
  199. return { bkt.end(), bkt.end() };
  200. } else {
  201. return { lookup.first, bkt.end(), lookup.second, lookup.first->end() };
  202. }
  203. }
  204. iterator unconst_iterator(const_iterator it) {
  205. auto lit = it.join_iterator();
  206. auto iter = it.element_iterator();
  207. if ( lit.done() ) { return end(); }
  208. auto nit = buckets_.begin();
  209. std::advance(nit, std::distance(buckets_.cbegin(), lit.current()));
  210. return { nit, buckets_.end(), nit->erase(iter.current(), iter.current()), nit->end() };
  211. }
  212. iterator erase_impl(iterator it) {
  213. auto b = it.join_iterator();
  214. auto l = it.element_iterator();
  215. if ( b.done() || l.done() ) { return it; }
  216. --size_;
  217. return { b.current(), b.end(), b->erase(l.current()), l.end(), true };
  218. }
  219. private: // members
  220. impl_type buckets_{default_buckets};
  221. hasher hasher_;
  222. key_equal key_equals_;
  223. //allocator_type alloc_;
  224. size_type size_{0};
  225. float max_load_{default_load_factor};
  226. };