Move boost/intrusive to senf/boost_intrusive
[senf.git] / senf / boost_intrusive / detail / ihashtable.hpp
diff --git a/senf/boost_intrusive/detail/ihashtable.hpp b/senf/boost_intrusive/detail/ihashtable.hpp
new file mode 100644 (file)
index 0000000..19e6d6f
--- /dev/null
@@ -0,0 +1,1017 @@
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// (C) Copyright Ion Gazta�aga  2006-2007\r
+//\r
+// Distributed under the Boost Software License, Version 1.0.\r
+//    (See accompanying file LICENSE_1_0.txt or copy at\r
+//          http://www.boost.org/LICENSE_1_0.txt)\r
+//\r
+// See http://www.boost.org/libs/intrusive for documentation.\r
+//\r
+/////////////////////////////////////////////////////////////////////////////\r
+#ifndef BOOST_INTRUSIVE_IHASHTABLE_HPP\r
+#define BOOST_INTRUSIVE_IHASHTABLE_HPP\r
+\r
+#include "config_begin.hpp"\r
+//std C++\r
+#include <functional>\r
+#include <iterator>\r
+#include <utility>\r
+#include <algorithm>\r
+//boost\r
+#include <boost/utility.hpp>\r
+#include <boost/compressed_pair.hpp>\r
+#include <boost/assert.hpp>\r
+#include <boost/static_assert.hpp>\r
+#include <boost/functional/hash.hpp>\r
+//General intrusive utilities\r
+#include "pointer_type.hpp"\r
+#include "pointer_to_other.hpp"\r
+#include "../linking_policy.hpp"\r
+//Implementation utilities\r
+#include "../iunordered_set_hook.hpp"\r
+#include "../islist.hpp"\r
+#include <cstddef>\r
+#include <iterator>\r
+\r
+namespace boost {\r
+namespace intrusive {\r
+namespace detail {\r
+\r
+template<int Dummy = 0>\r
+struct prime_list_holder\r
+{\r
+   static const std::size_t prime_list[];\r
+   static const std::size_t prime_list_size;\r
+};\r
+\r
+template<int Dummy>\r
+const std::size_t prime_list_holder<Dummy>::prime_list[] = {\r
+   53ul, 97ul, 193ul, 389ul, 769ul,\r
+   1543ul, 3079ul, 6151ul, 12289ul, 24593ul,\r
+   49157ul, 98317ul, 196613ul, 393241ul, 786433ul,\r
+   1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,\r
+   50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,\r
+   1610612741ul, 3221225473ul, 4294967291ul };\r
+\r
+template<int Dummy>\r
+const std::size_t prime_list_holder<Dummy>::prime_list_size\r
+   = sizeof(prime_list)/sizeof(std::size_t);\r
+\r
+//! The class template ihashtable is an intrusive hash table container, that\r
+//! is used to construct intrusive unordered_set and unordered_multiset containers. The\r
+//! no-throw guarantee holds only, if the Equal object and Hasher don't throw.\r
+template< class ValueTraits\r
+        , class Hash             = boost::hash<typename ValueTraits::value_type>\r
+        , class Equal            = std::equal_to<typename ValueTraits::value_type>\r
+        , bool  ConstantTimeSize = true\r
+        , class SizeType         = std::size_t\r
+        >\r
+class ihashtable\r
+   :  private detail::size_holder<ConstantTimeSize, SizeType>\r
+{\r
+   private:\r
+   template<class T, class Self, class NodeTraits>\r
+   class hashtable_iterator;\r
+\r
+   typedef islist<ValueTraits, false, SizeType> islist_impl;\r
+\r
+   struct bucket_type_impl\r
+      :  private islist_impl\r
+   {\r
+      friend class ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>;\r
+\r
+      bucket_type_impl()\r
+      {}\r
+\r
+      bucket_type_impl(const bucket_type_impl &)\r
+      {}\r
+\r
+      bucket_type_impl &operator=(const bucket_type_impl&)\r
+      {  islist_impl::clear();   }\r
+   };\r
+\r
+   static islist_impl &islist_from_bucket(bucket_type_impl &b)\r
+   {  return static_cast<islist_impl&>(b);   }\r
+\r
+   static const islist_impl &islist_from_bucket(const bucket_type_impl &b)\r
+   {  return static_cast<const islist_impl&>(b);   }\r
+\r
+   typedef ihashtable<ValueTraits, Hash, Equal\r
+                     ,ConstantTimeSize, SizeType>           this_type; \r
+   typedef typename ValueTraits::node_traits                node_traits;\r
+   typedef detail::size_holder<ConstantTimeSize, SizeType>  size_traits;\r
+\r
+   //noncopyable\r
+   ihashtable (const ihashtable&);\r
+   ihashtable operator =(const ihashtable&);\r
+\r
+   public:\r
+   typedef typename ValueTraits::value_type        value_type;\r
+   typedef typename ValueTraits::pointer           pointer;\r
+   typedef typename ValueTraits::const_pointer     const_pointer;\r
+   typedef value_type&                             reference;\r
+   typedef const value_type&                       const_reference;\r
+   typedef SizeType                                size_type;\r
+   typedef typename std::iterator_traits\r
+      <pointer>::difference_type                   difference_type;\r
+   typedef value_type                              key_type;\r
+   typedef Hash                                    hasher;\r
+   typedef Equal                                   key_equal;\r
+   typedef bucket_type_impl                        bucket_type;\r
+   typedef typename boost::pointer_to_other\r
+      <pointer, bucket_type>::type                 bucket_ptr;\r
+   typedef typename islist_impl::iterator          local_iterator;\r
+   typedef typename islist_impl::const_iterator    const_local_iterator;\r
+\r
+   class const_iterator;\r
+   class iterator;\r
+\r
+   private:\r
+   typedef typename node_traits::node              node;\r
+   typedef typename boost::pointer_to_other\r
+      <pointer, node>::type                        node_ptr;\r
+   typedef typename boost::pointer_to_other\r
+      <node_ptr, const node>::type                 const_node_ptr;\r
+   //typedef hashtable_algorithms<node_traits>       node_algorithms;\r
+   typedef slist_algorithms<node_traits>           node_algorithms;\r
+   enum { safemode_or_autounlink  = \r
+            (int)ValueTraits::linking_policy == (int)auto_unlink   ||\r
+            (int)ValueTraits::linking_policy == (int)safe_mode_link     };\r
+\r
+   //Constant-time size is incompatible with auto-unlink hooks!\r
+   BOOST_STATIC_ASSERT(!(ConstantTimeSize && ((int)ValueTraits::linking_policy == (int)auto_unlink)));\r
+\r
+   struct bucket_info_t\r
+   {\r
+      bucket_ptr  buckets_;\r
+      size_type   buckets_len_;\r
+   } ;\r
+\r
+   typedef typename boost::pointer_to_other\r
+      <pointer, bucket_info_t>::type               bucket_info_ptr;\r
+\r
+   typedef typename boost::pointer_to_other\r
+      <pointer, const bucket_info_t>::type         const_bucket_info_ptr;\r
+\r
+   //User scattered boost::compressed pair to get EBO all compilers\r
+   boost::compressed_pair\r
+      <boost::compressed_pair<bucket_info_t, Hash>\r
+      ,Equal> members_;\r
+\r
+   const Equal &priv_equal() const\r
+   {  return members_.second();  }\r
+\r
+   Equal &priv_equal()\r
+   {  return members_.second();  }\r
+\r
+   const_bucket_info_ptr priv_bucket_info() const\r
+   {  return &members_.first().first();  }\r
+\r
+   bucket_info_ptr priv_bucket_info()\r
+   {  return &members_.first().first();  }\r
+\r
+   const Hash &priv_hasher() const\r
+   {  return members_.first().second();  }\r
+\r
+   Hash &priv_hasher()\r
+   {  return members_.first().second();  }\r
+\r
+   const bucket_ptr &priv_buckets() const\r
+   {  return members_.first().first().buckets_;  }\r
+\r
+   bucket_ptr &priv_buckets()\r
+   {  return members_.first().first().buckets_;  }\r
+\r
+   const size_type &priv_buckets_len() const\r
+   {  return members_.first().first().buckets_len_;  }\r
+\r
+   size_type &priv_buckets_len()\r
+   {  return members_.first().first().buckets_len_;  }\r
+\r
+   static node_ptr uncast(const_node_ptr ptr)\r
+   {\r
+      using boost::get_pointer;\r
+      return node_ptr(const_cast<node*>(get_pointer(ptr)));\r
+   }\r
+\r
+   static bucket_info_ptr uncast(const_bucket_info_ptr ptr)\r
+   {\r
+      using boost::get_pointer;\r
+      return bucket_info_ptr(const_cast<bucket_info_t*>(get_pointer(ptr)));\r
+   }\r
+\r
+   template<class T, class Self, class NodeTraits>\r
+   class hashtable_iterator\r
+      :  public std::iterator<std::forward_iterator_tag, T>\r
+   {\r
+      protected:\r
+      explicit hashtable_iterator\r
+         (local_iterator ptr, bucket_info_ptr bucket_info, size_type n_bucket)\r
+         :  local_it_ (ptr),   bucket_info_ (bucket_info),   n_bucket_ (n_bucket)\r
+      {}\r
+\r
+      public:\r
+      hashtable_iterator ()\r
+      {}\r
+\r
+      Self& operator++()\r
+      {\r
+         using boost::get_pointer;\r
+         ++local_it_;\r
+         size_type   buckets_len = bucket_info_->buckets_len_;\r
+         bucket_ptr  buckets     = bucket_info_->buckets_;\r
+         while (local_it_ == islist_from_bucket(buckets[n_bucket_]).end()){\r
+             if (++n_bucket_ == buckets_len) {\r
+                 local_it_ = invalid_local_it(*bucket_info_);\r
+                 break;\r
+             }\r
+             local_it_ = islist_from_bucket(buckets[n_bucket_]).begin();\r
+         }\r
+         return static_cast<Self&> (*this);\r
+      }\r
+\r
+      Self operator++(int)\r
+      {\r
+         Self result(local_it_, bucket_info_, n_bucket_);\r
+         ++(*this);\r
+         return result;\r
+      }\r
+\r
+      bool operator== (const Self& i) const\r
+      { return local_it_ == i.local(); }\r
+\r
+      bool operator!= (const Self& i) const\r
+      { return !operator== (i); }\r
+\r
+      Self &set_internals\r
+         (local_iterator ptr, bucket_info_ptr bucket_info, size_type n_bucket)\r
+      {\r
+         local_it_ = ptr;  bucket_info_ = bucket_info;  n_bucket_ = n_bucket;\r
+         return static_cast<Self&>(*this);\r
+      }\r
+\r
+      local_iterator local() const\r
+      { return local_it_; }\r
+\r
+      bucket_info_ptr priv_bucket_info() const\r
+      { return bucket_info_; }\r
+\r
+      size_type bucket_num() const\r
+      { return n_bucket_; }\r
+\r
+      private:\r
+      local_iterator    local_it_;\r
+      bucket_info_ptr   bucket_info_;\r
+      size_type         n_bucket_;\r
+   };\r
+\r
+   public:\r
+\r
+   class iterator\r
+      :  public hashtable_iterator <value_type, iterator, node_traits>\r
+    {\r
+      private:\r
+      typedef typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::value_type   private_vt;\r
+      typedef typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::pointer      private_pointer;\r
+      typedef typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::reference    private_reference;\r
+      typedef hashtable_iterator<private_vt, iterator, node_traits>   inherited;\r
+\r
+      public:\r
+      iterator()\r
+      {}\r
+\r
+      private_pointer operator->() const\r
+      { return &*this->local(); }\r
+\r
+      private_reference operator*() const\r
+      { return *this->local(); }\r
+\r
+      private:\r
+      explicit iterator\r
+         (local_iterator local_it, bucket_info_ptr bucket_info, size_type n_bucket)\r
+         :  inherited(local_it, bucket_info, n_bucket)\r
+      {}\r
+\r
+      friend class ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>; \r
+      friend class hashtable_iterator<private_vt, iterator, node_traits>;\r
+      friend class const_iterator;\r
+   };\r
+\r
+   class const_iterator\r
+      :  public hashtable_iterator<const value_type, const_iterator, node_traits>\r
+   {\r
+      private:\r
+      typedef const typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::value_type private_vt;\r
+      typedef typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::const_pointer    private_pointer;\r
+      typedef typename ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>::const_reference  private_reference;\r
+      typedef hashtable_iterator<private_vt, const_iterator, node_traits>   inherited;\r
+\r
+      public:\r
+      const_iterator()\r
+      {}\r
+\r
+      const_iterator(const typename ihashtable::iterator& it)\r
+         :  inherited (it.local(), it.priv_bucket_info(), it.bucket_num())\r
+      {}\r
+\r
+      const_iterator & operator=(const typename ihashtable::iterator& it)\r
+      {  return inherited::set_internals(it.local(), it.priv_bucket_info(), it.bucket_num());  }\r
+\r
+      private_pointer operator->() const\r
+      { return &*this->local(); }\r
+\r
+      private_reference operator*() const\r
+      { return *this->local(); }\r
+\r
+      private:\r
+      explicit const_iterator\r
+         (local_iterator ptr, bucket_info_ptr bucket_info, size_type n_bucket)\r
+         :  inherited(ptr, bucket_info, n_bucket)\r
+      {}\r
+\r
+      friend class ihashtable<ValueTraits, Hash, Equal, ConstantTimeSize, SizeType>; \r
+      friend class hashtable_iterator<private_vt, const_iterator, node_traits>;\r
+   };\r
+\r
+   //typedef typename node_algorithms::insert_commit_data insert_commit_data;\r
+   struct insert_commit_data\r
+   {\r
+      local_iterator prev_pos;\r
+      size_type   bucket_num;\r
+   };\r
+\r
+   ihashtable( bucket_ptr buckets\r
+             , size_type buckets_len\r
+             , const Hash & hasher = Hash()\r
+             , const Equal &equal = Equal()) \r
+      :  members_(boost::compressed_pair<bucket_info_t, Hash>(hasher)/*hasher*/, equal)\r
+   {\r
+      \r
+      BOOST_ASSERT(buckets_len != 0);\r
+      priv_buckets()       = buckets;\r
+      priv_buckets_len()   = buckets_len;\r
+      priv_clear_buckets();\r
+      size_traits::set_size(size_type(0));\r
+   }\r
+\r
+   ~ihashtable() \r
+   {  this->clear(); }\r
+\r
+   iterator begin()\r
+   {\r
+      size_type bucket_num;\r
+      local_iterator local_it = priv_begin(bucket_num);\r
+      return iterator( local_it\r
+                     , this->priv_bucket_info()\r
+                     , bucket_num);\r
+   }\r
+\r
+   const_iterator begin() const\r
+   {\r
+      size_type bucket_num;\r
+      local_iterator local_it = priv_begin(bucket_num);\r
+      return const_iterator( local_it\r
+                           , uncast(this->priv_bucket_info())\r
+                           , bucket_num);\r
+   }\r
+\r
+   iterator end()\r
+   {\r
+      using boost::get_pointer;\r
+      bucket_info_t *info = get_pointer(this->priv_bucket_info());\r
+      return iterator(invalid_local_it(*info), 0, info->buckets_len_);\r
+   }\r
+\r
+   const_iterator end() const\r
+   {\r
+      using boost::get_pointer;\r
+      const bucket_info_t *info = get_pointer(this->priv_bucket_info());\r
+      return const_iterator(invalid_local_it(*info), 0, info->buckets_len_);\r
+   }\r
+\r
+   hasher hash_function() const\r
+   {  return this->priv_hasher();  }\r
+\r
+   key_equal key_eq() const\r
+   {  return this->priv_equal();   }\r
+\r
+   bool empty() const\r
+   {\r
+      if(ConstantTimeSize){\r
+         return !size();\r
+      }\r
+      else{\r
+         using boost::get_pointer;\r
+         size_type buckets_len = this->priv_buckets_len();\r
+         const bucket_type *b = get_pointer(this->priv_buckets());\r
+         for (size_type n = 0; n < buckets_len; ++n, ++b){\r
+            if(!b->empty()){\r
+               return false;\r
+            }\r
+         }\r
+         return true;\r
+      }\r
+   }\r
+\r
+   size_type size() const\r
+   {\r
+      if(ConstantTimeSize)\r
+         return size_traits::get_size();\r
+      else{\r
+         size_type len = 0;\r
+         using boost::get_pointer;\r
+         size_type buckets_len = this->priv_buckets_len();\r
+         const bucket_type *b = get_pointer(this->priv_buckets());\r
+         for (size_type n = 0; n < buckets_len; ++n, ++b){\r
+            len += b->size();\r
+         }\r
+         return len;\r
+      }\r
+   }\r
+\r
+   void swap(ihashtable& other)\r
+   {\r
+      using std::swap;\r
+      //These can throw\r
+      swap(this->priv_equal(), other.priv_equal());\r
+      swap(this->priv_hasher(), other.priv_hasher());\r
+      //These can't throw\r
+      swap(this->priv_buckets(), other.priv_buckets());\r
+      swap(this->priv_buckets_len(), other.priv_buckets_len());\r
+      if(ConstantTimeSize){\r
+         size_type backup = size_traits::get_size();\r
+         size_traits::set_size(other.get_size());\r
+         other.set_size(backup);\r
+      }\r
+   }\r
+\r
+   template <class Cloner, class Destroyer>\r
+   void clone_from(const ihashtable &src, Cloner cloner, Destroyer destroyer)\r
+   {\r
+      this->clear_and_destroy(destroyer);\r
+      if(!ConstantTimeSize || !src.empty()){\r
+         const size_type src_bucket_count = src.bucket_count();\r
+         const size_type dst_bucket_count = this->bucket_count();\r
+\r
+         //If src bucket count is bigger or equal, structural copy is possible\r
+         if(src_bucket_count >= dst_bucket_count){\r
+            //First clone the first ones\r
+            const bucket_ptr src_buckets = src.priv_buckets();\r
+            const bucket_ptr dst_buckets = this->priv_buckets();\r
+            size_type constructed;\r
+            try{\r
+               for( constructed = 0\r
+                  ; constructed < dst_bucket_count\r
+                  ; ++constructed){\r
+                  dst_buckets[constructed].clone_and_reverse_from(src_buckets[constructed], cloner, destroyer);\r
+               }\r
+               if(src_bucket_count != dst_bucket_count){\r
+                  //Now insert the remaining ones using the modulo trick\r
+                  for(//"constructed" comes from the previous loop\r
+                     ; constructed < src_bucket_count\r
+                     ; ++constructed){\r
+                     bucket_type &dst_b = dst_buckets[constructed % dst_bucket_count];\r
+                     bucket_type &src_b = src_buckets[constructed];\r
+                     for( local_iterator b(src_b.begin()), e(src_b.end())\r
+                        ; b != e\r
+                        ; ++b){\r
+                        dst_b.push_front(*cloner(*b));\r
+                     }\r
+                  }\r
+               }\r
+            }\r
+            catch(...){\r
+               while(constructed--){\r
+                  dst_buckets[constructed].clear_and_destroy(destroyer);\r
+               }\r
+               throw;\r
+            }\r
+            size_traits::set_size(src.get_size());\r
+         }\r
+         else{\r
+            //Unlike previous cloning algorithm, this can throw\r
+            //if cloner, the hasher or comparison functor throw\r
+            const_iterator b(src.begin()), e(src.end());\r
+            try{\r
+               for(; b != e; ++b){\r
+                  this->insert_equal(*cloner(*b));\r
+               }\r
+            }\r
+            catch(...){\r
+               this->clear_and_destroy(destroyer);\r
+               throw;\r
+            }\r
+         }\r
+      }\r
+   }\r
+\r
+   iterator insert_equal(value_type &value)\r
+   {\r
+      size_type bucket_num;\r
+      local_iterator it = priv_find(value, this->priv_hasher(), this->priv_equal(), bucket_num);\r
+      bucket_type &b = this->priv_buckets()[bucket_num];\r
+      if(it == invalid_local_it(*this->priv_bucket_info())){\r
+         it = b.before_begin();\r
+      }\r
+      size_traits::increment();\r
+      return iterator(b.insert_after(it, value), this->priv_bucket_info(), bucket_num);\r
+   }\r
+\r
+   template<class Iterator>\r
+   void insert_equal(Iterator b, Iterator e)\r
+   {\r
+      for (; b != e; ++b)\r
+         this->insert_equal(*b);\r
+   }\r
+\r
+   std::pair<iterator, bool> insert_unique(value_type &value)\r
+   {\r
+      insert_commit_data commit_data;\r
+      std::pair<iterator, bool> ret = insert_unique_check(value, commit_data);\r
+      if(!ret.second)\r
+         return ret;\r
+      return std::pair<iterator, bool> (insert_unique_commit(value, commit_data), true);\r
+   }\r
+\r
+   template<class Iterator>\r
+   void insert_unique(Iterator b, Iterator e)\r
+   {\r
+      for (; b != e; ++b)\r
+         this->insert_unique(*b);\r
+   }\r
+\r
+   std::pair<iterator, bool> insert_unique_check\r
+      (const value_type &value, insert_commit_data &commit_data)\r
+   {  return insert_unique_check(value, this->priv_hasher(), this->priv_equal(), commit_data); }\r
+\r
+   template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+   std::pair<iterator, bool> insert_unique_check\r
+      ( const KeyType &key\r
+      , KeyHasher hasher\r
+      , KeyValueEqual key_value_eq\r
+      , insert_commit_data &commit_data)\r
+   {\r
+      commit_data.prev_pos = \r
+         priv_find(key, hasher, key_value_eq, commit_data.bucket_num);\r
+      bool success = commit_data.prev_pos == invalid_local_it(*this->priv_bucket_info());\r
+      if(success){\r
+         commit_data.prev_pos = this->priv_buckets()[commit_data.bucket_num].before_begin();\r
+      }\r
+      return std::pair<iterator, bool>\r
+         (iterator(commit_data.prev_pos, this->priv_bucket_info(), commit_data.bucket_num)\r
+         ,success);\r
+   }\r
+\r
+   iterator insert_unique_commit(value_type &value, const insert_commit_data &commit_data)\r
+   {\r
+      bucket_type &b = this->priv_buckets()[commit_data.bucket_num];\r
+      size_traits::increment();\r
+      return iterator( b.insert_after(commit_data.prev_pos, value)\r
+                     , this->priv_bucket_info()\r
+                     , commit_data.bucket_num);\r
+   }\r
+\r
+   void erase(const_iterator i)\r
+   {  erase_and_destroy(i, detail::null_destroyer());  }\r
+\r
+   void erase(const_iterator b, const_iterator e)\r
+   {  erase_and_destroy(b, e, detail::null_destroyer());  }\r
+\r
+   size_type erase(const value_type &value)\r
+   {  return this->erase(value, this->priv_hasher(), this->priv_equal());  }\r
+\r
+   template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+   size_type erase(const KeyType& key, KeyHasher hasher, KeyValueEqual equal)\r
+   {  return erase_and_destroy(key, hasher, equal, detail::null_destroyer()); }\r
+\r
+   template<class Destroyer>\r
+   void erase_and_destroy(const_iterator i, Destroyer destroyer)\r
+   {\r
+      local_iterator to_erase(i.local());\r
+      size_type n_bucket = i.bucket_num();\r
+      bucket_type &b = this->priv_buckets()[n_bucket];\r
+      b.erase_after_and_destroy(b.previous(to_erase), destroyer);\r
+      size_traits::decrement();\r
+   }\r
+\r
+   template<class Destroyer>\r
+   void erase_and_destroy(const_iterator b, const_iterator e, Destroyer destroyer)\r
+   {\r
+      if(b == e)  return;\r
+\r
+      //Get the bucket number and local iterator for both iterators\r
+      size_type first_bucket_num\r
+         = b.bucket_num();\r
+      local_iterator before_first_local_it\r
+         = priv_buckets()[first_bucket_num].previous(b.local());\r
+      size_type last_bucket_num;\r
+      local_iterator last_local_it;\r
+\r
+      //For the end iterator, we will assign the end iterator\r
+      //of the last bucket\r
+      if(e == end()){\r
+         last_bucket_num   = this->bucket_count() - 1;\r
+         last_local_it     = priv_buckets()[last_bucket_num].end();\r
+      }\r
+      else{\r
+         last_bucket_num   = e.bucket_num();\r
+         last_local_it     = e.local();\r
+      }\r
+\r
+      const bucket_ptr buckets = priv_buckets();\r
+      //First erase the nodes of the first bucket\r
+      {\r
+         bucket_type &first_b = buckets[first_bucket_num];\r
+         local_iterator nxt(before_first_local_it); ++nxt;\r
+         local_iterator end = first_b.end();\r
+         while(nxt != end){\r
+            nxt = first_b.erase_after_and_destroy(before_first_local_it, destroyer);\r
+            size_traits::decrement();\r
+         }\r
+      }\r
+\r
+      //Now fully clear the intermediate buckets\r
+      for(size_type i = first_bucket_num+1; i < last_bucket_num; ++i){\r
+         bucket_type &b = buckets[i];\r
+         if(b.empty())\r
+            continue;\r
+         local_iterator b_begin(b.before_begin());\r
+         local_iterator nxt(b_begin); ++nxt;\r
+         local_iterator end = b.end();\r
+         while(nxt != end){\r
+            nxt = b.erase_after_and_destroy(b_begin, destroyer);\r
+            size_traits::decrement();\r
+         }\r
+      }\r
+\r
+      //Now erase nodes from the last bucket\r
+      {\r
+         bucket_type &last_b = buckets[last_bucket_num];\r
+         local_iterator b_begin(last_b.before_begin());\r
+         local_iterator nxt(b_begin); ++nxt;\r
+         while(nxt != last_local_it){\r
+            nxt = last_b.erase_after_and_destroy(b_begin, destroyer);\r
+            size_traits::decrement();\r
+         }\r
+      }\r
+   }\r
+\r
+   template<class Destroyer>\r
+   size_type erase_and_destroy(const value_type &value, Destroyer destroyer)\r
+   {  return erase_and_destroy(value, priv_hasher(), priv_equal(), destroyer);   }\r
+\r
+   template<class KeyType, class KeyHasher, class KeyValueEqual, class Destroyer>\r
+   size_type erase_and_destroy(const KeyType& key, KeyHasher hasher\r
+                  ,KeyValueEqual equal, Destroyer destroyer)\r
+   {\r
+      size_type count(0);\r
+\r
+      if(ConstantTimeSize && this->empty()){\r
+         return 0;\r
+      }\r
+\r
+      bucket_type &b = this->priv_buckets()[hasher(key) % this->priv_buckets_len()];\r
+      local_iterator it    = b.begin();\r
+      local_iterator prev  = b.before_begin();\r
+\r
+      bool found = false;\r
+      //Find equal value\r
+      while(it != b.end()){\r
+         if(equal(key, *it)){\r
+            found = true;\r
+            break;\r
+         }\r
+         ++prev;\r
+         ++it;\r
+      }\r
+   \r
+      if(!found)\r
+         return 0;\r
+\r
+      //If found erase all equal values\r
+      for(local_iterator end = b.end(); it != end && equal(key, *it); ++count){\r
+         it = b.erase_after_and_destroy(prev, destroyer);\r
+         size_traits::decrement();\r
+      }\r
+      return count;\r
+   }\r
+\r
+   void clear()\r
+   {\r
+      if(safemode_or_autounlink){\r
+         priv_clear_buckets();\r
+      }\r
+      size_traits::set_size(size_type(0));\r
+   }\r
+\r
+   template<class Destroyer>\r
+   void clear_and_destroy(Destroyer destroyer)\r
+   {\r
+      if(!ConstantTimeSize || !this->empty()){\r
+         size_type num_buckets = this->bucket_count();\r
+         bucket_ptr b = this->priv_buckets();\r
+         for(; num_buckets--; ++b){\r
+            b->clear_and_destroy(destroyer);\r
+         }\r
+         size_traits::set_size(size_type(0));\r
+      }\r
+   }\r
+\r
+   size_type count(const value_type &value) const\r
+   {  return this->count(value, this->priv_hasher(), this->priv_equal());  }\r
+\r
+   template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+   size_type count(const KeyType &key, const KeyHasher &hasher, const KeyValueEqual &equal) const\r
+   {\r
+      size_type bucket_n1, bucket_n2, count;\r
+      priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count);\r
+      return count;\r
+   }\r
+\r
+   iterator find(const value_type &value)\r
+   {  return find(value, this->priv_hasher(), this->priv_equal());   }\r
+\r
+   template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+   iterator find(const KeyType &key, KeyHasher hasher, KeyValueEqual equal)\r
+   {\r
+      size_type bucket_n;\r
+      local_iterator local_it = priv_find(key, hasher, equal, bucket_n);\r
+      return iterator( local_it\r
+                      , this->priv_bucket_info()\r
+                      , bucket_n);\r
+   }\r
+\r
+   const_iterator find(const value_type &value) const\r
+   {  return find(value, this->priv_hasher(), this->priv_equal());   }\r
+\r
+   template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+   const_iterator find\r
+      (const KeyType &key, KeyHasher hasher, KeyValueEqual equal) const\r
+   {\r
+      size_type bucket_n;\r
+      local_iterator local_it = priv_find(key, hasher, equal, bucket_n);\r
+      return const_iterator( local_it\r
+                           , uncast(this->priv_bucket_info())\r
+                           , bucket_n);\r
+   }\r
+\r
+   std::pair<iterator,iterator> equal_range(const value_type &value)\r
+   {  return this->equal_range(value, this->priv_hasher(), this->priv_equal());  }\r
+\r
+   template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+   std::pair<iterator,iterator> equal_range\r
+      (const KeyType &key, KeyHasher hasher, KeyValueEqual equal)\r
+   {\r
+      size_type bucket_n1, bucket_n2, count;\r
+      std::pair<local_iterator, local_iterator> ret\r
+         = priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count);\r
+      return std::pair<iterator, iterator>\r
+         (  iterator( ret.first, this->priv_bucket_info(), bucket_n1)\r
+         ,  iterator( ret.second, this->priv_bucket_info(), bucket_n2) );\r
+   }\r
+\r
+   std::pair<const_iterator, const_iterator>\r
+      equal_range(const value_type &value) const\r
+   {  return this->equal_range(value, this->priv_hasher(), this->priv_equal());  }\r
+\r
+   template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+   std::pair<const_iterator,const_iterator> equal_range\r
+      (const KeyType &key, KeyHasher hasher, KeyValueEqual equal) const\r
+   {\r
+      size_type bucket_n1, bucket_n2, count;\r
+      std::pair<local_iterator, local_iterator> ret\r
+         = priv_equal_range(key, hasher, equal, bucket_n1, bucket_n2, count);\r
+      return std::pair<const_iterator, const_iterator>\r
+         (  const_iterator( ret.first, uncast(this->priv_bucket_info()), bucket_n1)\r
+         ,  const_iterator( ret.second, uncast(this->priv_bucket_info()), bucket_n2)  );\r
+   }\r
+\r
+   size_type bucket_count() const\r
+   {  return this->priv_buckets_len();   }\r
+\r
+   size_type bucket_size(size_type n)\r
+   {  return this->priv_buckets()[n].size();   }\r
+\r
+   size_type bucket(const key_type& k)\r
+   {  return this->bucket(k, this->priv_hasher());   }\r
+\r
+   template<class KeyType, class KeyHasher>\r
+   size_type bucket(const KeyType& k, const KeyHasher &hasher)\r
+   {  return hasher(k) % this->priv_buckets_len();   }\r
+\r
+   bucket_ptr bucket_pointer() const\r
+   {  return this->priv_buckets();   }\r
+\r
+   local_iterator begin(size_type n)\r
+   {  return this->priv_buckets()[n].begin();  }\r
+\r
+   const_local_iterator begin(size_type n) const\r
+   {  return const_cast<const bucket_type&>(this->priv_buckets()[n]).begin();  }\r
+\r
+   local_iterator end(size_type n)\r
+   {  return this->priv_buckets()[n].end();  }\r
+\r
+   const_local_iterator end(size_type n) const\r
+   {  return const_cast<const bucket_type&>(this->priv_buckets()[n]).end();  }\r
+\r
+   void rehash(bucket_ptr new_buckets, size_type new_buckets_len)\r
+   {\r
+      bucket_ptr old_buckets     = this->priv_buckets();\r
+      size_type  old_buckets_len = this->priv_buckets_len();\r
+\r
+      try{\r
+         size_type n = 0;\r
+         bool same_buffer = old_buckets == new_buckets;\r
+         //If we are shrinking the bucket array, just rehash the last nodes\r
+         if(same_buffer && (old_buckets_len > new_buckets_len)){\r
+            n = new_buckets_len;\r
+         }\r
+\r
+         //Iterate through nodes\r
+         for(; n < old_buckets_len; ++n){\r
+            bucket_type &old_bucket = old_buckets[n];\r
+            local_iterator before_i(old_bucket.before_begin());\r
+            local_iterator end(old_bucket.end());\r
+            local_iterator i(old_bucket.begin());\r
+            for(;i != end; ++i){\r
+               size_type new_n = this->priv_hasher()(*i) % new_buckets_len;\r
+               //If this is a buffer expansion don't move if it's not necessary\r
+               if(same_buffer && new_n == n){\r
+                  ++before_i;\r
+               }\r
+               else{\r
+                  bucket_type &new_b = new_buckets[new_n];\r
+                  new_b.splice_after(new_b.before_begin(), old_bucket, before_i);\r
+                  i = before_i;\r
+               }\r
+            }\r
+         }\r
+\r
+         this->priv_buckets()      = new_buckets;\r
+         this->priv_buckets_len()  = new_buckets_len;\r
+      }\r
+      catch(...){\r
+         for(size_type n = 0; n < new_buckets_len; ++n){\r
+            new_buckets[n].clear();\r
+            old_buckets[n].clear();\r
+         }\r
+         size_traits::set_size(size_type(0));\r
+         throw;\r
+      }\r
+   }\r
+\r
+   iterator current(value_type &value)\r
+   {\r
+      return iterator( bucket_type::current(value)\r
+                     , this->priv_bucket_info()\r
+                     , this->priv_hasher()(value) % this->priv_buckets_len());\r
+   }\r
+\r
+   const_iterator current(const value_type &value) const\r
+   {\r
+      return const_iterator( bucket_type::current(const_cast<value_type&>(value))\r
+                     , uncast(this->priv_bucket_info())\r
+                     , this->priv_hasher()(value) % this->priv_buckets_len());\r
+   }\r
+\r
+   static local_iterator current_local(value_type &value)\r
+   {  return bucket_type::current(value);  }\r
+\r
+   static const_local_iterator current_local(const value_type &value)\r
+   {  return bucket_type::current(value);  }\r
+\r
+   // no throw\r
+   static size_type suggested_upper_bucket_count(size_type n)\r
+   {\r
+      const std::size_t *primes     = &prime_list_holder<0>::prime_list[0];\r
+      const std::size_t *primes_end = primes + prime_list_holder<0>::prime_list_size;\r
+      size_type const* bound =\r
+            std::lower_bound(primes, primes_end, n);\r
+      if(bound == primes_end)\r
+            bound--;\r
+      return size_type(*bound);\r
+   }\r
+\r
+   // no throw\r
+   static size_type suggested_lower_bucket_count(size_type n)\r
+   {\r
+      const std::size_t *primes     = &prime_list_holder<0>::prime_list[0];\r
+      const std::size_t *primes_end = primes + prime_list_holder<0>::prime_list_size;\r
+      size_type const* bound =\r
+            std::upper_bound(primes, primes_end, n);\r
+      if(bound != primes_end)\r
+            bound--;\r
+      return size_type(*bound);\r
+   }\r
+\r
+   private:\r
+\r
+   static local_iterator invalid_local_it(const bucket_info_t &b)\r
+   {  return b.buckets_->end();  }\r
+\r
+   local_iterator priv_begin(size_type &bucket_num) const\r
+   {\r
+      size_type buckets_len = this->priv_buckets_len();\r
+      for (bucket_num = 0; bucket_num < buckets_len; ++bucket_num){\r
+         bucket_type &b = this->priv_buckets()[bucket_num];\r
+         if(!b.empty())\r
+            return b.begin();\r
+      }\r
+      return invalid_local_it(*this->priv_bucket_info());\r
+   }\r
+\r
+   void priv_clear_buckets()\r
+   {  priv_clear_buckets(this->priv_buckets(), this->priv_buckets_len());  }\r
+\r
+   static void priv_clear_buckets(bucket_ptr buckets_ptr, size_type buckets_len)\r
+   {\r
+      for(; buckets_len--; ++buckets_ptr){\r
+         buckets_ptr->clear();\r
+      }\r
+   }\r
+\r
+   template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+   local_iterator priv_find\r
+      ( const KeyType &key,  KeyHasher hasher\r
+      , KeyValueEqual equal, size_type &bucket_number) const\r
+   {\r
+      size_type b_len(this->priv_buckets_len());\r
+      bucket_number = hasher(key) % b_len;\r
+\r
+      if(ConstantTimeSize && this->empty()){\r
+         return invalid_local_it(*this->priv_bucket_info());\r
+      }\r
+      \r
+      bucket_type &b = this->priv_buckets()[bucket_number];\r
+      local_iterator it = b.begin();\r
+\r
+      while(it != b.end()){\r
+         if(equal(key, *it)){\r
+            return it;\r
+         }\r
+         ++it;\r
+      }\r
+\r
+      return invalid_local_it(*this->priv_bucket_info());\r
+   }\r
+\r
+   template<class KeyType, class KeyHasher, class KeyValueEqual>\r
+   std::pair<local_iterator, local_iterator> priv_equal_range\r
+      ( const KeyType &key\r
+      , KeyHasher hasher\r
+      , KeyValueEqual equal\r
+      , size_type &bucket_number_first\r
+      , size_type &bucket_number_second\r
+      , size_type &count) const\r
+   {\r
+      count = 0;\r
+      //Let's see if the element is present\r
+      std::pair<local_iterator, local_iterator> to_return\r
+         ( priv_find(key, hasher, equal, bucket_number_first)\r
+         , invalid_local_it(*this->priv_bucket_info()));\r
+      if(to_return.first == to_return.second){\r
+         bucket_number_second = bucket_number_first;\r
+         return to_return;\r
+      }\r
+      ++count;\r
+      //If it's present, find the first that it's not equal in\r
+      //the same bucket\r
+      bucket_type &b = this->priv_buckets()[bucket_number_first];\r
+      local_iterator it = to_return.first;\r
+      ++it;\r
+\r
+      while(it != b.end()){\r
+         if(!equal(key, *it)){\r
+            to_return.second = it;\r
+            bucket_number_second = bucket_number_first;\r
+            return to_return;\r
+         }\r
+         ++it;\r
+         ++count;\r
+      }\r
+   \r
+      //If we reached the end, find the first, non-empty bucket\r
+      for(bucket_number_second = bucket_number_first+1\r
+         ; bucket_number_second != this->priv_buckets_len()\r
+         ; ++bucket_number_second){\r
+         bucket_type &b = this->priv_buckets()[bucket_number_second];\r
+         if(!b.empty()){\r
+            to_return.second = b.begin();\r
+            return to_return;\r
+         }\r
+      }\r
+\r
+      //Otherwise, return the end node\r
+      to_return.second = invalid_local_it(*this->priv_bucket_info());\r
+      return to_return;\r
+   }\r
+};\r
+\r
+} //namespace detail\r
+} //namespace intrusive \r
+} //namespace boost \r
+\r
+#include "config_end.hpp"\r
+\r
+#endif //BOOST_INTRUSIVE_IHASHTABLE_HPP\r