hashtable_node.hpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2007-2014
  4. //
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // See http://www.boost.org/libs/intrusive for documentation.
  10. //
  11. /////////////////////////////////////////////////////////////////////////////
  12. #ifndef BOOST_INTRUSIVE_HASHTABLE_NODE_HPP
  13. #define BOOST_INTRUSIVE_HASHTABLE_NODE_HPP
  14. #ifndef BOOST_CONFIG_HPP
  15. # include <boost/config.hpp>
  16. #endif
  17. #if defined(BOOST_HAS_PRAGMA_ONCE)
  18. # pragma once
  19. #endif
  20. #include <boost/intrusive/detail/workaround.hpp>
  21. #include <boost/intrusive/detail/assert.hpp>
  22. #include <boost/intrusive/pointer_traits.hpp>
  23. #include <boost/intrusive/detail/mpl.hpp>
  24. #include <boost/intrusive/trivial_value_traits.hpp>
  25. #include <boost/intrusive/slist.hpp> //make_slist
  26. #include <cstddef>
  27. #include <climits>
  28. #include <boost/move/core.hpp>
  29. namespace boost {
  30. namespace intrusive {
  31. namespace detail {
  32. template <class Slist>
  33. struct bucket_impl : public Slist
  34. {
  35. typedef Slist slist_type;
  36. BOOST_INTRUSIVE_FORCEINLINE bucket_impl()
  37. {}
  38. BOOST_INTRUSIVE_FORCEINLINE bucket_impl(const bucket_impl &)
  39. {}
  40. BOOST_INTRUSIVE_FORCEINLINE ~bucket_impl()
  41. {
  42. //This bucket is still being used!
  43. BOOST_INTRUSIVE_INVARIANT_ASSERT(Slist::empty());
  44. }
  45. BOOST_INTRUSIVE_FORCEINLINE bucket_impl &operator=(const bucket_impl&)
  46. {
  47. //This bucket is still in use!
  48. BOOST_INTRUSIVE_INVARIANT_ASSERT(Slist::empty());
  49. return *this;
  50. }
  51. };
  52. template<class Slist>
  53. struct bucket_traits_impl
  54. {
  55. private:
  56. BOOST_COPYABLE_AND_MOVABLE(bucket_traits_impl)
  57. public:
  58. /// @cond
  59. typedef typename pointer_traits
  60. <typename Slist::pointer>::template rebind_pointer
  61. < bucket_impl<Slist> >::type bucket_ptr;
  62. typedef Slist slist;
  63. typedef typename Slist::size_type size_type;
  64. /// @endcond
  65. BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl(bucket_ptr buckets, size_type len)
  66. : buckets_(buckets), buckets_len_(len)
  67. {}
  68. BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl(const bucket_traits_impl &x)
  69. : buckets_(x.buckets_), buckets_len_(x.buckets_len_)
  70. {}
  71. BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl(BOOST_RV_REF(bucket_traits_impl) x)
  72. : buckets_(x.buckets_), buckets_len_(x.buckets_len_)
  73. { x.buckets_ = bucket_ptr(); x.buckets_len_ = 0; }
  74. BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl& operator=(BOOST_RV_REF(bucket_traits_impl) x)
  75. {
  76. buckets_ = x.buckets_; buckets_len_ = x.buckets_len_;
  77. x.buckets_ = bucket_ptr(); x.buckets_len_ = 0; return *this;
  78. }
  79. BOOST_INTRUSIVE_FORCEINLINE bucket_traits_impl& operator=(BOOST_COPY_ASSIGN_REF(bucket_traits_impl) x)
  80. {
  81. buckets_ = x.buckets_; buckets_len_ = x.buckets_len_; return *this;
  82. }
  83. BOOST_INTRUSIVE_FORCEINLINE const bucket_ptr &bucket_begin() const
  84. { return buckets_; }
  85. BOOST_INTRUSIVE_FORCEINLINE size_type bucket_count() const
  86. { return buckets_len_; }
  87. private:
  88. bucket_ptr buckets_;
  89. size_type buckets_len_;
  90. };
  91. template <class NodeTraits>
  92. struct hash_reduced_slist_node_traits
  93. {
  94. template <class U> static detail::no_type test(...);
  95. template <class U> static detail::yes_type test(typename U::reduced_slist_node_traits*);
  96. static const bool value = sizeof(test<NodeTraits>(0)) == sizeof(detail::yes_type);
  97. };
  98. template <class NodeTraits>
  99. struct apply_reduced_slist_node_traits
  100. {
  101. typedef typename NodeTraits::reduced_slist_node_traits type;
  102. };
  103. template <class NodeTraits>
  104. struct reduced_slist_node_traits
  105. {
  106. typedef typename detail::eval_if_c
  107. < hash_reduced_slist_node_traits<NodeTraits>::value
  108. , apply_reduced_slist_node_traits<NodeTraits>
  109. , detail::identity<NodeTraits>
  110. >::type type;
  111. };
  112. template<class NodeTraits>
  113. struct get_slist_impl
  114. {
  115. typedef trivial_value_traits<NodeTraits, normal_link> trivial_traits;
  116. //Reducing symbol length
  117. struct type : make_slist
  118. < typename NodeTraits::node
  119. , boost::intrusive::value_traits<trivial_traits>
  120. , boost::intrusive::constant_time_size<false>
  121. , boost::intrusive::size_type<std::size_t>
  122. >::type
  123. {};
  124. };
  125. } //namespace detail {
  126. template<class BucketValueTraits, bool IsConst>
  127. class hashtable_iterator
  128. {
  129. typedef typename BucketValueTraits::value_traits value_traits;
  130. typedef typename BucketValueTraits::bucket_traits bucket_traits;
  131. typedef iiterator< value_traits, IsConst
  132. , std::forward_iterator_tag> types_t;
  133. public:
  134. typedef typename types_t::iterator_type::difference_type difference_type;
  135. typedef typename types_t::iterator_type::value_type value_type;
  136. typedef typename types_t::iterator_type::pointer pointer;
  137. typedef typename types_t::iterator_type::reference reference;
  138. typedef typename types_t::iterator_type::iterator_category iterator_category;
  139. private:
  140. typedef typename value_traits::node_traits node_traits;
  141. typedef typename node_traits::node_ptr node_ptr;
  142. typedef typename detail::get_slist_impl
  143. < typename detail::reduced_slist_node_traits
  144. <node_traits>::type >::type slist_impl;
  145. typedef typename slist_impl::iterator siterator;
  146. typedef typename slist_impl::const_iterator const_siterator;
  147. typedef detail::bucket_impl<slist_impl> bucket_type;
  148. typedef typename pointer_traits
  149. <pointer>::template rebind_pointer
  150. < const BucketValueTraits >::type const_bucketvaltraits_ptr;
  151. typedef typename slist_impl::size_type size_type;
  152. BOOST_INTRUSIVE_FORCEINLINE static node_ptr downcast_bucket(typename bucket_type::node_ptr p)
  153. {
  154. return pointer_traits<node_ptr>::
  155. pointer_to(static_cast<typename node_traits::node&>(*p));
  156. }
  157. public:
  158. BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator ()
  159. : slist_it_() //Value initialization to achieve "null iterators" (N3644)
  160. {}
  161. explicit hashtable_iterator(siterator ptr, const BucketValueTraits *cont)
  162. : slist_it_ (ptr)
  163. , traitsptr_ (cont ? pointer_traits<const_bucketvaltraits_ptr>::pointer_to(*cont) : const_bucketvaltraits_ptr() )
  164. {}
  165. BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator(const hashtable_iterator<BucketValueTraits, false> &other)
  166. : slist_it_(other.slist_it()), traitsptr_(other.get_bucket_value_traits())
  167. {}
  168. BOOST_INTRUSIVE_FORCEINLINE const siterator &slist_it() const
  169. { return slist_it_; }
  170. BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator<BucketValueTraits, false> unconst() const
  171. { return hashtable_iterator<BucketValueTraits, false>(this->slist_it(), this->get_bucket_value_traits()); }
  172. BOOST_INTRUSIVE_FORCEINLINE hashtable_iterator& operator++()
  173. { this->increment(); return *this; }
  174. hashtable_iterator operator++(int)
  175. {
  176. hashtable_iterator result (*this);
  177. this->increment();
  178. return result;
  179. }
  180. BOOST_INTRUSIVE_FORCEINLINE friend bool operator== (const hashtable_iterator& i, const hashtable_iterator& i2)
  181. { return i.slist_it_ == i2.slist_it_; }
  182. BOOST_INTRUSIVE_FORCEINLINE friend bool operator!= (const hashtable_iterator& i, const hashtable_iterator& i2)
  183. { return !(i == i2); }
  184. BOOST_INTRUSIVE_FORCEINLINE reference operator*() const
  185. { return *this->operator ->(); }
  186. BOOST_INTRUSIVE_FORCEINLINE pointer operator->() const
  187. {
  188. return this->priv_value_traits().to_value_ptr
  189. (downcast_bucket(slist_it_.pointed_node()));
  190. }
  191. BOOST_INTRUSIVE_FORCEINLINE const const_bucketvaltraits_ptr &get_bucket_value_traits() const
  192. { return traitsptr_; }
  193. BOOST_INTRUSIVE_FORCEINLINE const value_traits &priv_value_traits() const
  194. { return traitsptr_->priv_value_traits(); }
  195. BOOST_INTRUSIVE_FORCEINLINE const bucket_traits &priv_bucket_traits() const
  196. { return traitsptr_->priv_bucket_traits(); }
  197. private:
  198. void increment()
  199. {
  200. const bucket_traits &rbuck_traits = this->priv_bucket_traits();
  201. bucket_type* const buckets = boost::movelib::to_raw_pointer(rbuck_traits.bucket_begin());
  202. const size_type buckets_len = rbuck_traits.bucket_count();
  203. ++slist_it_;
  204. const typename slist_impl::node_ptr n = slist_it_.pointed_node();
  205. const siterator first_bucket_bbegin = buckets->end();
  206. if(first_bucket_bbegin.pointed_node() <= n && n <= buckets[buckets_len-1].cend().pointed_node()){
  207. //If one-past the node is inside the bucket then look for the next non-empty bucket
  208. //1. get the bucket_impl from the iterator
  209. const bucket_type &b = static_cast<const bucket_type&>
  210. (bucket_type::slist_type::container_from_end_iterator(slist_it_));
  211. //2. Now just calculate the index b has in the bucket array
  212. size_type n_bucket = static_cast<size_type>(&b - buckets);
  213. //3. Iterate until a non-empty bucket is found
  214. do{
  215. if (++n_bucket >= buckets_len){ //bucket overflow, return end() iterator
  216. slist_it_ = buckets->before_begin();
  217. return;
  218. }
  219. }
  220. while (buckets[n_bucket].empty());
  221. slist_it_ = buckets[n_bucket].begin();
  222. }
  223. else{
  224. //++slist_it_ yield to a valid object
  225. }
  226. }
  227. siterator slist_it_;
  228. const_bucketvaltraits_ptr traitsptr_;
  229. };
  230. } //namespace intrusive {
  231. } //namespace boost {
  232. #endif