bucket_hash_set.hpp 8.4 KB

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