Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / multi_index / hashed_index.hpp
index 0ee4aeb..ebf55c9 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright 2003-2011 Joaquin M Lopez Munoz.
+/* Copyright 2003-2014 Joaquin M Lopez Munoz.
  * Distributed under the Boost Software License, Version 1.0.
  * (See accompanying file LICENSE_1_0.txt or copy at
  * http://www.boost.org/LICENSE_1_0.txt)
@@ -9,7 +9,7 @@
 #ifndef BOOST_MULTI_INDEX_HASHED_INDEX_HPP
 #define BOOST_MULTI_INDEX_HASHED_INDEX_HPP
 
-#if defined(_MSC_VER)&&(_MSC_VER>=1200)
+#if defined(_MSC_VER)
 #pragma once
 #endif
 
 #include <boost/detail/workaround.hpp>
 #include <boost/foreach_fwd.hpp>
 #include <boost/limits.hpp>
+#include <boost/move/core.hpp>
 #include <boost/mpl/bool.hpp>
+#include <boost/mpl/if.hpp>
 #include <boost/mpl/push_front.hpp>
 #include <boost/multi_index/detail/access_specifier.hpp>
 #include <boost/multi_index/detail/auto_space.hpp>
 #include <boost/multi_index/detail/bucket_array.hpp>
+#include <boost/multi_index/detail/do_not_copy_elements_tag.hpp>
 #include <boost/multi_index/detail/hash_index_iterator.hpp>
 #include <boost/multi_index/detail/index_node_base.hpp>
 #include <boost/multi_index/detail/modify_key_adaptor.hpp>
-#include <boost/multi_index/detail/safe_ctr_proxy.hpp>
 #include <boost/multi_index/detail/safe_mode.hpp>
 #include <boost/multi_index/detail/scope_guard.hpp>
+#include <boost/multi_index/detail/vartempl_support.hpp>
 #include <boost/multi_index/hashed_index_fwd.hpp>
 #include <boost/tuple/tuple.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <cmath>
 #include <cstddef>
 #include <functional>
+#include <iterator>
 #include <utility>
 
+#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
+#include <initializer_list>
+#endif
+
 #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
 #include <boost/serialization/nvp.hpp>
 #endif
 
 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
-#define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT                       \
+#define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x)                 \
   detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)=                 \
-    detail::make_obj_guard(*this,&hashed_index::check_invariant_);           \
+    detail::make_obj_guard(x,&hashed_index::check_invariant_);               \
   BOOST_JOIN(check_invariant_,__LINE__).touch();
+#define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT                       \
+  BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(*this)
 #else
+#define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x)
 #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
 #endif
 
@@ -61,12 +74,9 @@ namespace detail{
 
 /* Most of the implementation of unique and non-unique indices is
  * shared. We tell from one another on instantiation time by using
- * these tags.
+ * Category tags defined in hash_index_node.hpp.
  */
 
-struct hashed_unique_tag{};
-struct hashed_non_unique_tag{};
-
 template<
   typename KeyFromValue,typename Hash,typename Pred,
   typename SuperMeta,typename TagList,typename Category
@@ -75,17 +85,9 @@ class hashed_index:
   BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS SuperMeta::type
 
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
-#if BOOST_WORKAROUND(BOOST_MSVC,<1300)
-  ,public safe_ctr_proxy_impl<
-    hashed_index_iterator<
-      hashed_index_node<typename SuperMeta::type::node_type>,
-      bucket_array<typename SuperMeta::type::final_allocator_type> >,
-    hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> >
-#else
   ,public safe_mode::safe_container<
     hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> >
 #endif
-#endif
 
 { 
 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
@@ -102,11 +104,13 @@ class hashed_index:
 
 protected:
   typedef hashed_index_node<
-    typename super::node_type>                       node_type;
+    typename super::node_type,Category>              node_type;
 
 private:
+  typedef typename node_type::node_alg               node_alg;
   typedef typename node_type::impl_type              node_impl_type;
   typedef typename node_impl_type::pointer           node_impl_pointer;
+  typedef typename node_impl_type::base_pointer      node_impl_base_pointer;
   typedef bucket_array<
     typename super::final_allocator_type>            bucket_array_type;
 
@@ -129,28 +133,24 @@ public:
   typedef std::ptrdiff_t                             difference_type;
 
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
-#if BOOST_WORKAROUND(BOOST_MSVC,<1300)
   typedef safe_mode::safe_iterator<
     hashed_index_iterator<
-      node_type,bucket_array_type>,
-    safe_ctr_proxy<
-      hashed_index_iterator<
-        node_type,bucket_array_type> > >             iterator;
-#else
-  typedef safe_mode::safe_iterator<
-    hashed_index_iterator<
-      node_type,bucket_array_type>,
+      node_type,bucket_array_type,
+      hashed_index_global_iterator_tag>,
     hashed_index>                                    iterator;
-#endif
 #else
   typedef hashed_index_iterator<
-    node_type,bucket_array_type>                     iterator;
+    node_type,bucket_array_type,
+    hashed_index_global_iterator_tag>                iterator;
 #endif
 
   typedef iterator                                   const_iterator;
 
-  typedef iterator                                   local_iterator;
-  typedef const_iterator                             const_local_iterator;
+  typedef hashed_index_iterator<
+    node_type,bucket_array_type,
+    hashed_index_local_iterator_tag>                 local_iterator;
+  typedef local_iterator                             const_local_iterator;
+
   typedef TagList                                    tag_list;
 
 protected:
@@ -176,21 +176,20 @@ protected:
 
 private:
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
-#if BOOST_WORKAROUND(BOOST_MSVC,<1300)
-  typedef safe_ctr_proxy_impl<
-    hashed_index_iterator<
-      node_type,bucket_array_type>,
-    hashed_index>                             safe_super;
-#else
   typedef safe_mode::safe_container<
     hashed_index>                             safe_super;
 #endif
-#endif
 
   typedef typename call_traits<value_type>::param_type value_param_type;
   typedef typename call_traits<
     key_type>::param_type                              key_param_type;
 
+  /* Needed to avoid commas in BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL
+   * expansion.
+   */
+
+  typedef std::pair<iterator,bool>                     emplace_return_type;
+
 public:
 
   /* construct/destroy/copy
@@ -205,36 +204,36 @@ public:
     return *this;
   }
 
-  allocator_type get_allocator()const
+#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
+  hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& operator=(
+    std::initializer_list<value_type> list)
+  {
+    this->final()=list;
+    return *this;
+  }
+#endif
+
+  allocator_type get_allocator()const BOOST_NOEXCEPT
   {
     return this->final().get_allocator();
   }
 
   /* size and capacity */
 
-  bool      empty()const{return this->final_empty_();}
-  size_type size()const{return this->final_size_();}
-  size_type max_size()const{return this->final_max_size_();}
+  bool      empty()const BOOST_NOEXCEPT{return this->final_empty_();}
+  size_type size()const BOOST_NOEXCEPT{return this->final_size_();}
+  size_type max_size()const BOOST_NOEXCEPT{return this->final_max_size_();}
 
   /* iterators */
 
-  iterator begin()
-  {
-    return make_iterator(
-      node_type::from_impl(buckets.at(first_bucket)->next()));
-  }
-
-  const_iterator begin()const
-  {
-    return make_iterator(
-      node_type::from_impl(buckets.at(first_bucket)->next()));
-  }
-
-  iterator       end(){return make_iterator(header());}
-  const_iterator end()const{return make_iterator(header());}
-
-  const_iterator cbegin()const{return begin();}
-  const_iterator cend()const{return end();}
+  iterator begin()BOOST_NOEXCEPT
+    {return make_iterator(node_type::from_impl(header()->next()->prior()));}
+  const_iterator begin()const BOOST_NOEXCEPT
+    {return make_iterator(node_type::from_impl(header()->next()->prior()));}
+  iterator       end()BOOST_NOEXCEPT{return make_iterator(header());}
+  const_iterator end()const BOOST_NOEXCEPT{return make_iterator(header());}
+  const_iterator cbegin()const BOOST_NOEXCEPT{return begin();}
+  const_iterator cend()const BOOST_NOEXCEPT{return end();}
 
   iterator iterator_to(const value_type& x)
   {
@@ -248,14 +247,27 @@ public:
 
   /* modifiers */
 
-  std::pair<iterator,bool> insert(value_param_type x)
+  BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
+    emplace_return_type,emplace,emplace_impl)
+
+  BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
+    iterator,emplace_hint,emplace_hint_impl,iterator,position)
+
+  std::pair<iterator,bool> insert(const value_type& x)
   {
     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
     std::pair<final_node_type*,bool> p=this->final_insert_(x);
     return std::pair<iterator,bool>(make_iterator(p.first),p.second);
   }
 
-  iterator insert(iterator position,value_param_type x)
+  std::pair<iterator,bool> insert(BOOST_RV_REF(value_type) x)
+  {
+    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
+    std::pair<final_node_type*,bool> p=this->final_insert_rv_(x);
+    return std::pair<iterator,bool>(make_iterator(p.first),p.second);
+  }
+
+  iterator insert(iterator position,const value_type& x)
   {
     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
@@ -265,14 +277,30 @@ public:
     return make_iterator(p.first);
   }
     
+  iterator insert(iterator position,BOOST_RV_REF(value_type) x)
+  {
+    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
+    BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
+    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
+    std::pair<final_node_type*,bool> p=this->final_insert_rv_(
+      x,static_cast<final_node_type*>(position.get_node()));
+    return make_iterator(p.first);
+  }
+
   template<typename InputIterator>
   void insert(InputIterator first,InputIterator last)
   {
     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
-    iterator hint=end();
-    for(;first!=last;++first)hint=insert(hint,*first);
+    for(;first!=last;++first)this->final_insert_ref_(*first);
   }
 
+#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
+  void insert(std::initializer_list<value_type> list)
+  {
+    insert(list.begin(),list.end());
+  }
+#endif
+
   iterator erase(iterator position)
   {
     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
@@ -287,28 +315,23 @@ public:
   {
     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
 
-    size_type         s=0;
-    std::size_t       buc=buckets.position(hash(k));
-    node_impl_pointer x=buckets.at(buc);
-    node_impl_pointer y=x->next();
-    while(y!=x){
-      if(eq(k,key(node_type::from_impl(y)->value()))){
-        bool b;
+    std::size_t buc=buckets.position(hash_(k));
+    for(node_impl_pointer x=buckets.at(buc)->prior();
+        x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
+      if(eq_(k,key(node_type::from_impl(x)->value()))){
+        node_impl_pointer y=end_of_range(x);
+        size_type         s=0;
         do{
-          node_impl_pointer z=y->next();
-          b=z!=x&&eq(
-            key(node_type::from_impl(y)->value()),
-            key(node_type::from_impl(z)->value()));
+          node_impl_pointer z=node_alg::after(x);
           this->final_erase_(
-            static_cast<final_node_type*>(node_type::from_impl(y)));
-          y=z;
+            static_cast<final_node_type*>(node_type::from_impl(x)));
+          x=z;
           ++s;
-        }while(b);
-        break;
+        }while(x!=y);
+        return s;
       }
-      y=y->next();
     }
-    return s;
+    return 0;
   }
 
   iterator erase(iterator first,iterator last)
@@ -325,7 +348,7 @@ public:
     return first;
   }
 
-  bool replace(iterator position,value_param_type x)
+  bool replace(iterator position,const value_type& x)
   {
     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
     BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
@@ -335,6 +358,16 @@ public:
       x,static_cast<final_node_type*>(position.get_node()));
   }
 
+  bool replace(iterator position,BOOST_RV_REF(value_type) x)
+  {
+    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
+    BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
+    BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
+    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
+    return this->final_replace_rv_(
+      x,static_cast<final_node_type*>(position.get_node()));
+  }
+
   template<typename Modifier>
   bool modify(iterator position,Modifier mod)
   {
@@ -357,7 +390,7 @@ public:
   }
 
   template<typename Modifier,typename Rollback>
-  bool modify(iterator position,Modifier mod,Rollback back)
+  bool modify(iterator position,Modifier mod,Rollback back_)
   {
     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
     BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
@@ -374,7 +407,7 @@ public:
 #endif
 
     return this->final_modify_(
-      mod,back,static_cast<final_node_type*>(position.get_node()));
+      mod,back_,static_cast<final_node_type*>(position.get_node()));
   }
 
   template<typename Modifier>
@@ -389,7 +422,7 @@ public:
   }
 
   template<typename Modifier,typename Rollback>
-  bool modify_key(iterator position,Modifier mod,Rollback back)
+  bool modify_key(iterator position,Modifier mod,Rollback back_)
   {
     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
     BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
@@ -398,10 +431,10 @@ public:
     return modify(
       position,
       modify_key_adaptor<Modifier,value_type,KeyFromValue>(mod,key),
-      modify_key_adaptor<Rollback,value_type,KeyFromValue>(back,key));
+      modify_key_adaptor<Rollback,value_type,KeyFromValue>(back_,key));
   }
 
-  void clear()
+  void clear()BOOST_NOEXCEPT
   {
     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
     this->final_clear_();
@@ -410,14 +443,15 @@ public:
   void swap(hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
   {
     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
+    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x);
     this->final_swap_(x.final());
   }
 
   /* observers */
 
   key_from_value key_extractor()const{return key;}
-  hasher         hash_function()const{return hash;}
-  key_equal      key_eq()const{return eq;}
+  hasher         hash_function()const{return hash_;}
+  key_equal      key_eq()const{return eq_;}
   
   /* lookup */
 
@@ -428,7 +462,7 @@ public:
   template<typename CompatibleKey>
   iterator find(const CompatibleKey& k)const
   {
-    return find(k,hash,eq);
+    return find(k,hash_,eq_);
   }
 
   template<
@@ -438,14 +472,12 @@ public:
     const CompatibleKey& k,
     const CompatibleHash& hash,const CompatiblePred& eq)const
   {
-    std::size_t       buc=buckets.position(hash(k));
-    node_impl_pointer x=buckets.at(buc);
-    node_impl_pointer y=x->next();
-    while(y!=x){
-      if(eq(k,key(node_type::from_impl(y)->value()))){
-        return make_iterator(node_type::from_impl(y));
+    std::size_t buc=buckets.position(hash(k));
+    for(node_impl_pointer x=buckets.at(buc)->prior();
+        x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
+      if(eq(k,key(node_type::from_impl(x)->value()))){
+        return make_iterator(node_type::from_impl(x));
       }
-      y=y->next();
     }
     return end();
   }
@@ -453,7 +485,7 @@ public:
   template<typename CompatibleKey>
   size_type count(const CompatibleKey& k)const
   {
-    return count(k,hash,eq);
+    return count(k,hash_,eq_);
   }
 
   template<
@@ -463,27 +495,26 @@ public:
     const CompatibleKey& k,
     const CompatibleHash& hash,const CompatiblePred& eq)const
   {
-    size_type         res=0;
-    std::size_t       buc=buckets.position(hash(k));
-    node_impl_pointer x=buckets.at(buc);
-    node_impl_pointer y=x->next();
-    while(y!=x){
-      if(eq(k,key(node_type::from_impl(y)->value()))){
+    std::size_t buc=buckets.position(hash(k));
+    for(node_impl_pointer x=buckets.at(buc)->prior();
+        x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
+      if(eq(k,key(node_type::from_impl(x)->value()))){
+        size_type         res=0;
+        node_impl_pointer y=end_of_range(x);
         do{
           ++res;
-          y=y->next();
-        }while(y!=x&&eq(k,key(node_type::from_impl(y)->value())));
-        break;
+          x=node_alg::after(x);
+        }while(x!=y);
+        return res;
       }
-      y=y->next();
     }
-    return res;
+    return 0;
   }
 
   template<typename CompatibleKey>
   std::pair<iterator,iterator> equal_range(const CompatibleKey& k)const
   {
-    return equal_range(k,hash,eq);
+    return equal_range(k,hash_,eq_);
   }
 
   template<
@@ -493,50 +524,36 @@ public:
     const CompatibleKey& k,
     const CompatibleHash& hash,const CompatiblePred& eq)const
   {
-    std::size_t       buc=buckets.position(hash(k));
-    node_impl_pointer x=buckets.at(buc);
-    node_impl_pointer y=x->next();
-    while(y!=x){
-      if(eq(k,key(node_type::from_impl(y)->value()))){
-        node_impl_pointer y0=y;
-        do{
-          y=y->next();
-        }while(y!=x&&eq(k,key(node_type::from_impl(y)->value())));
-        if(y==x){
-          do{
-            ++y;
-          }while(y==y->next());
-          y=y->next();
-        }
+    std::size_t buc=buckets.position(hash(k));
+    for(node_impl_pointer x=buckets.at(buc)->prior();
+        x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
+      if(eq(k,key(node_type::from_impl(x)->value()))){
         return std::pair<iterator,iterator>(
-          make_iterator(node_type::from_impl(y0)),
-          make_iterator(node_type::from_impl(y)));
+          make_iterator(node_type::from_impl(x)),
+          make_iterator(node_type::from_impl(end_of_range(x))));
       }
-      y=y->next();
     }
     return std::pair<iterator,iterator>(end(),end());
   }
 
   /* bucket interface */
 
-  size_type bucket_count()const{return buckets.size();}
-  size_type max_bucket_count()const{return static_cast<size_type>(-1);}
+  size_type bucket_count()const BOOST_NOEXCEPT{return buckets.size();}
+  size_type max_bucket_count()const BOOST_NOEXCEPT{return static_cast<size_type>(-1);}
 
   size_type bucket_size(size_type n)const
   {
-    size_type         res=0;
-    node_impl_pointer x=buckets.at(n);
-    node_impl_pointer y=x->next();
-    while(y!=x){
+    size_type res=0;
+    for(node_impl_pointer x=buckets.at(n)->prior();
+        x!=node_impl_pointer(0);x=node_alg::after_local(x)){
       ++res;
-      y=y->next();
     }
     return res;
   }
 
   size_type bucket(key_param_type k)const
   {
-    return buckets.position(hash(k));
+    return buckets.position(hash_(k));
   }
 
   local_iterator begin(size_type n)
@@ -546,10 +563,9 @@ public:
 
   const_local_iterator begin(size_type n)const
   {
-    node_impl_pointer x=buckets.at(n);
-    node_impl_pointer y=x->next();
-    if(y==x)return end();
-    return make_iterator(node_type::from_impl(y));
+    node_impl_pointer x=buckets.at(n)->prior();
+    if(x==node_impl_pointer(0))return end(n);
+    return make_local_iterator(node_type::from_impl(x));
   }
 
   local_iterator end(size_type n)
@@ -557,14 +573,9 @@ public:
     return const_cast<const hashed_index*>(this)->end(n);
   }
 
-  const_local_iterator end(size_type n)const
+  const_local_iterator end(size_type)const
   {
-    node_impl_pointer x=buckets.at(n);
-    if(x==x->next())return end();
-    do{
-      ++x;
-    }while(x==x->next());
-    return make_iterator(node_type::from_impl(x->next()));
+    return make_local_iterator(0);
   }
 
   const_local_iterator cbegin(size_type n)const{return begin(n);}
@@ -572,24 +583,25 @@ public:
 
   local_iterator local_iterator_to(const value_type& x)
   {
-    return make_iterator(node_from_value<node_type>(&x));
+    return make_local_iterator(node_from_value<node_type>(&x));
   }
 
   const_local_iterator local_iterator_to(const value_type& x)const
   {
-    return make_iterator(node_from_value<node_type>(&x));
+    return make_local_iterator(node_from_value<node_type>(&x));
   }
 
   /* hash policy */
 
-  float load_factor()const{return static_cast<float>(size())/bucket_count();}
-  float max_load_factor()const{return mlf;}
+  float load_factor()const BOOST_NOEXCEPT
+    {return static_cast<float>(size())/bucket_count();}
+  float max_load_factor()const BOOST_NOEXCEPT{return mlf;}
   void  max_load_factor(float z){mlf=z;calculate_max_load();}
 
   void rehash(size_type n)
   {
     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
-    if(size()<max_load&&n<=bucket_count())return;
+    if(size()<=max_load&&n<=bucket_count())return;
 
     size_type bc =(std::numeric_limits<size_type>::max)();
     float     fbc=static_cast<float>(1+size()/mlf);
@@ -600,15 +612,19 @@ public:
     unchecked_rehash(bc);
   }
 
+  void reserve(size_type n)
+  {
+    rehash(static_cast<size_type>(std::ceil(static_cast<double>(n)/mlf)));
+  }
+
 BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
   hashed_index(const ctor_args_list& args_list,const allocator_type& al):
     super(args_list.get_tail(),al),
     key(tuples::get<1>(args_list.get_head())),
-    hash(tuples::get<2>(args_list.get_head())),
-    eq(tuples::get<3>(args_list.get_head())),
+    hash_(tuples::get<2>(args_list.get_head())),
+    eq_(tuples::get<3>(args_list.get_head())),
     buckets(al,header()->impl(),tuples::get<0>(args_list.get_head())),
-    mlf(1.0f),
-    first_bucket(buckets.size())
+    mlf(1.0f)
   {
     calculate_max_load();
   }
@@ -622,18 +638,35 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
 #endif
 
     key(x.key),
-    hash(x.hash),
-    eq(x.eq),
+    hash_(x.hash_),
+    eq_(x.eq_),
     buckets(x.get_allocator(),header()->impl(),x.buckets.size()),
     mlf(x.mlf),
-    max_load(x.max_load),
-    first_bucket(x.first_bucket)
+    max_load(x.max_load)
   {
     /* Copy ctor just takes the internal configuration objects from x. The rest
      * is done in subsequent call to copy_().
      */
   }
 
+  hashed_index(
+    const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
+    do_not_copy_elements_tag):
+    super(x,do_not_copy_elements_tag()),
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+    safe_super(),
+#endif
+
+    key(x.key),
+    hash_(x.hash_),
+    eq_(x.eq_),
+    buckets(x.get_allocator(),header()->impl(),0),
+    mlf(1.0f)
+  {
+     calculate_max_load();
+  }
+
   ~hashed_index()
   {
     /* the container is guaranteed to be empty by now */
@@ -642,90 +675,163 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
   iterator make_iterator(node_type* node)
   {
-    return iterator(node,&buckets,this);
+    return iterator(node,this);
   }
 
   const_iterator make_iterator(node_type* node)const
   {
-    return const_iterator(
-      node,
-      &const_cast<bucket_array_type&>(buckets),
-      const_cast<hashed_index*>(this));
+    return const_iterator(node,const_cast<hashed_index*>(this));
   }
 #else
   iterator make_iterator(node_type* node)
   {
-    return iterator(node,&buckets);
+    return iterator(node);
   }
 
   const_iterator make_iterator(node_type* node)const
   {
-    return const_iterator(node,&const_cast<bucket_array_type&>(buckets));
+    return const_iterator(node);
   }
 #endif
 
+  local_iterator make_local_iterator(node_type* node)
+  {
+    return local_iterator(node);
+  }
+
+  const_local_iterator make_local_iterator(node_type* node)const
+  {
+    return const_local_iterator(node);
+  }
+
   void copy_(
     const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
     const copy_map_type& map)
   {
-    for(node_impl_pointer begin_org=x.buckets.begin(),
-                          begin_cpy=buckets.begin(),
-                          end_org=x.buckets.end();
-        begin_org!=end_org;++begin_org,++begin_cpy){
-
-      node_impl_pointer next_org=begin_org->next();
-      node_impl_pointer cpy=begin_cpy;
-      while(next_org!=begin_org){
-        cpy->next()=
-          static_cast<node_type*>(
-            map.find(
-              static_cast<final_node_type*>(
-                node_type::from_impl(next_org))))->impl();
-        next_org=next_org->next();
-        cpy=cpy->next();
-      }
-      cpy->next()=begin_cpy;
+    copy_(x,map,Category());
+  }
+
+  void copy_(
+    const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
+    const copy_map_type& map,hashed_unique_tag)
+  {
+    if(x.size()!=0){
+      node_impl_pointer end_org=x.header()->impl(),
+                        org=end_org,
+                        cpy=header()->impl();
+      do{
+        node_impl_pointer prev_org=org->prior(),
+                          prev_cpy=
+          static_cast<node_type*>(map.find(static_cast<final_node_type*>(
+            node_type::from_impl(prev_org))))->impl();
+        cpy->prior()=prev_cpy;
+        if(node_alg::is_first_of_bucket(org)){
+          node_impl_base_pointer buc_org=prev_org->next(),
+                                 buc_cpy=
+            buckets.begin()+(buc_org-x.buckets.begin());
+          prev_cpy->next()=buc_cpy;
+          buc_cpy->prior()=cpy;
+        }
+        else{
+          prev_cpy->next()=node_impl_type::base_pointer_from(cpy);
+        }
+        org=prev_org;
+        cpy=prev_cpy;
+      }while(org!=end_org);
     }
 
     super::copy_(x,map);
   }
+  
+  void copy_(
+    const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
+    const copy_map_type& map,hashed_non_unique_tag)
+  {
+    if(x.size()!=0){
+      node_impl_pointer end_org=x.header()->impl(),
+                        org=end_org,
+                        cpy=header()->impl();
+      do{
+        node_impl_pointer next_org=node_alg::after(org),
+                          next_cpy=
+          static_cast<node_type*>(map.find(static_cast<final_node_type*>(
+            node_type::from_impl(next_org))))->impl();
+        if(node_alg::is_first_of_bucket(next_org)){
+          node_impl_base_pointer buc_org=org->next(),
+                                 buc_cpy=
+            buckets.begin()+(buc_org-x.buckets.begin());
+          cpy->next()=buc_cpy;
+          buc_cpy->prior()=next_cpy;
+          next_cpy->prior()=cpy;
+        }
+        else{
+          if(org->next()==node_impl_type::base_pointer_from(next_org)){
+            cpy->next()=node_impl_type::base_pointer_from(next_cpy);
+          }
+          else{
+            cpy->next()=
+              node_impl_type::base_pointer_from(
+                static_cast<node_type*>(map.find(static_cast<final_node_type*>(
+                  node_type::from_impl(
+                    node_impl_type::pointer_from(org->next())))))->impl());
+          }
+
+          if(next_org->prior()!=org){
+            next_cpy->prior()=
+              static_cast<node_type*>(map.find(static_cast<final_node_type*>(
+                node_type::from_impl(next_org->prior()))))->impl();
+          }
+          else{
+            next_cpy->prior()=cpy;
+          }
+        }
+        org=next_org;
+        cpy=next_cpy;
+      }while(org!=end_org);
+    }
 
-  node_type* insert_(value_param_type v,node_type* x)
-  {
-    reserve(size()+1);
+    super::copy_(x,map);
+  }
 
-    std::size_t       buc=find_bucket(v);
-    node_impl_pointer pos=buckets.at(buc);
-    if(!link_point(v,pos,Category()))return node_type::from_impl(pos);
+  template<typename Variant>
+  final_node_type* insert_(
+    value_param_type v,final_node_type*& x,Variant variant)
+  {
+    reserve_for_insert(size()+1);
 
-    node_type* res=static_cast<node_type*>(super::insert_(v,x));
-    if(res==x){
-      link(x,pos);
-      if(first_bucket>buc)first_bucket=buc;
+    std::size_t buc=find_bucket(v);
+    link_info   pos(buckets.at(buc));
+    if(!link_point(v,pos)){
+      return static_cast<final_node_type*>(
+        node_type::from_impl(node_impl_type::pointer_from(pos)));
     }
+
+    final_node_type* res=super::insert_(v,x,variant);
+    if(res==x)link(static_cast<node_type*>(x),pos);
     return res;
   }
 
-  node_type* insert_(value_param_type v,node_type* position,node_type* x)
+  template<typename Variant>
+  final_node_type* insert_(
+    value_param_type v,node_type* position,final_node_type*& x,Variant variant)
   {
-    reserve(size()+1);
-
-    std::size_t       buc=find_bucket(v);
-    node_impl_pointer pos=buckets.at(buc);
-    if(!link_point(v,pos,Category()))return node_type::from_impl(pos);
+    reserve_for_insert(size()+1);
 
-    node_type* res=static_cast<node_type*>(super::insert_(v,position,x));
-    if(res==x){
-      link(x,pos);
-      if(first_bucket>buc)first_bucket=buc;
+    std::size_t buc=find_bucket(v);
+    link_info   pos(buckets.at(buc));
+    if(!link_point(v,pos)){
+      return static_cast<final_node_type*>(
+        node_type::from_impl(node_impl_type::pointer_from(pos)));
     }
+
+    final_node_type* res=super::insert_(v,position,x,variant);
+    if(res==x)link(static_cast<node_type*>(x),pos);
     return res;
   }
 
   void erase_(node_type* x)
   {
     unlink(x);
-    first_bucket=buckets.first_nonempty(first_bucket);
     super::erase_(x);
 
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
@@ -735,23 +841,42 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
 
   void delete_all_nodes_()
   {
-    for(node_impl_pointer x=buckets.begin(),x_end=buckets.end();
-        x!=x_end;++x){
-      node_impl_pointer y=x->next();
-      while(y!=x){
-        node_impl_pointer z=y->next();
-        this->final_delete_node_(
-          static_cast<final_node_type*>(node_type::from_impl(y)));
-        y=z;
+    delete_all_nodes_(Category());
+  }
+
+  void delete_all_nodes_(hashed_unique_tag)
+  {
+    for(node_impl_pointer x_end=header()->impl(),x=x_end->prior();x!=x_end;){
+      node_impl_pointer y=x->prior();
+      this->final_delete_node_(
+        static_cast<final_node_type*>(node_type::from_impl(x)));
+      x=y;
+    }
+  }
+
+  void delete_all_nodes_(hashed_non_unique_tag)
+  {
+    for(node_impl_pointer x_end=header()->impl(),x=x_end->prior();x!=x_end;){
+      node_impl_pointer y=x->prior();
+      if(y->next()!=node_impl_type::base_pointer_from(x)&&
+         y->next()->prior()!=x){ /* n-1 of group */
+        /* Make the second node prior() pointer back-linked so that it won't
+         * refer to a deleted node when the time for its own destruction comes.
+         */
+
+        node_impl_pointer first=node_impl_type::pointer_from(y->next());
+        first->next()->prior()=first;
       }
+      this->final_delete_node_(
+        static_cast<final_node_type*>(node_type::from_impl(x)));
+      x=y;
     }
   }
 
   void clear_()
   {
     super::clear_();
-    buckets.clear();
-    first_bucket=buckets.size();
+    buckets.clear(header()->impl());
 
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
     safe_super::detach_dereferenceable_iterators();
@@ -762,12 +887,11 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
     hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
   {
     std::swap(key,x.key);
-    std::swap(hash,x.hash);
-    std::swap(eq,x.eq);
+    std::swap(hash_,x.hash_);
+    std::swap(eq_,x.eq_);
     buckets.swap(x.buckets);
     std::swap(mlf,x.mlf);
     std::swap(max_load,x.max_load);
-    std::swap(first_bucket,x.first_bucket);
 
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
     safe_super::swap(x);
@@ -776,33 +900,42 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
     super::swap_(x);
   }
 
-  bool replace_(value_param_type v,node_type* x)
+  void swap_elements_(
+    hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
   {
-    if(eq(key(v),key(x->value()))){
-      return super::replace_(v,x);
-    }
+    buckets.swap(x.buckets);
+    std::swap(mlf,x.mlf);
+    std::swap(max_load,x.max_load);
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+    safe_super::swap(x);
+#endif
 
-    node_impl_pointer y=prev(x);
-    unlink_next(y);
+    super::swap_elements_(x);
+  }
+
+  template<typename Variant>
+  bool replace_(value_param_type v,node_type* x,Variant variant)
+  {
+    if(eq_(key(v),key(x->value()))){
+      return super::replace_(v,x,variant);
+    }
+      
+    unlink_undo undo;
+    unlink(x,undo);
 
     BOOST_TRY{
-      std::size_t       buc=find_bucket(v);
-      node_impl_pointer pos=buckets.at(buc);
-      if(link_point(v,pos,Category())&&super::replace_(v,x)){
+      std::size_t  buc=find_bucket(v);
+      link_info    pos(buckets.at(buc));
+      if(link_point(v,pos)&&super::replace_(v,x,variant)){
         link(x,pos);
-        if(first_bucket>buc){
-          first_bucket=buc;
-        }
-        else if(first_bucket<buc){
-          first_bucket=buckets.first_nonempty(first_bucket);
-        }
         return true;
       }
-      link(x,y);
+      undo();
       return false;
     }
     BOOST_CATCH(...){
-      link(x,y);
+      undo();
       BOOST_RETHROW;
     }
     BOOST_CATCH_END
@@ -814,7 +947,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
     bool        b; 
     BOOST_TRY{
       buc=find_bucket(x->value());
-      b=in_place(x->impl(),key(x->value()),buc,Category());
+      b=in_place(x->impl(),key(x->value()),buc);
     }
     BOOST_CATCH(...){
       erase_(x);
@@ -824,9 +957,8 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
     if(!b){
       unlink(x);
       BOOST_TRY{
-        node_impl_pointer pos=buckets.at(buc);
-        if(!link_point(x->value(),pos,Category())){
-          first_bucket=buckets.first_nonempty(first_bucket);
+        link_info pos(buckets.at(buc));
+        if(!link_point(x->value(),pos)){
           super::erase_(x);
 
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
@@ -835,15 +967,8 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
           return false;
         }
         link(x,pos);
-        if(first_bucket>buc){
-          first_bucket=buc;
-        }
-        else if(first_bucket<buc){
-          first_bucket=buckets.first_nonempty(first_bucket);
-        }
       }
       BOOST_CATCH(...){
-        first_bucket=buckets.first_nonempty(first_bucket);
         super::erase_(x);
 
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
@@ -858,7 +983,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
     BOOST_TRY{
       if(!super::modify_(x)){
         unlink(x);
-        first_bucket=buckets.first_nonempty(first_bucket);
+
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
         detach_iterators(x);
 #endif
@@ -868,7 +993,6 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
     }
     BOOST_CATCH(...){
       unlink(x);
-      first_bucket=buckets.first_nonempty(first_bucket);
 
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
       detach_iterators(x);
@@ -882,35 +1006,83 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
   bool modify_rollback_(node_type* x)
   {
     std::size_t buc=find_bucket(x->value());
-    if(in_place(x->impl(),key(x->value()),buc,Category())){
+    if(in_place(x->impl(),key(x->value()),buc)){
       return super::modify_rollback_(x);
     }
 
-    node_impl_pointer y=prev(x);
-    unlink_next(y);
+    unlink_undo undo;
+    unlink(x,undo);
 
     BOOST_TRY{
-      node_impl_pointer pos=buckets.at(buc);
-      if(link_point(x->value(),pos,Category())&&super::modify_rollback_(x)){
+      link_info pos(buckets.at(buc));
+      if(link_point(x->value(),pos)&&super::modify_rollback_(x)){
         link(x,pos);
-        if(first_bucket>buc){
-          first_bucket=buc;
-        }
-        else if(first_bucket<buc){
-          first_bucket=buckets.first_nonempty(first_bucket);
-        }
         return true;
       }
-      link(x,y);
+      undo();
       return false;
     }
     BOOST_CATCH(...){
-      link(x,y);
+      undo();
       BOOST_RETHROW;
     }
     BOOST_CATCH_END
   }
 
+  /* comparison */
+
+#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
+  /* defect macro refers to class, not function, templates, but anyway */
+
+  template<typename K,typename H,typename P,typename S,typename T,typename C>
+  friend bool operator==(
+    const hashed_index<K,H,P,S,T,C>&,const hashed_index<K,H,P,S,T,C>& y);
+#endif
+
+  bool equals(const hashed_index& x)const{return equals(x,Category());}
+
+  bool equals(const hashed_index& x,hashed_unique_tag)const
+  {
+    if(size()!=x.size())return false;
+    for(const_iterator it=begin(),it_end=end(),it2_end=x.end();
+        it!=it_end;++it){
+      const_iterator it2=x.find(key(*it));
+      if(it2==it2_end||!(*it==*it2))return false;
+    }
+    return true;
+  }
+
+  bool equals(const hashed_index& x,hashed_non_unique_tag)const
+  {
+    if(size()!=x.size())return false;
+    for(const_iterator it=begin(),it_end=end();it!=it_end;){
+      const_iterator it2,it2_last;
+      boost::tie(it2,it2_last)=x.equal_range(key(*it));
+      if(it2==it2_last)return false;
+
+      const_iterator it_last=make_iterator(
+        node_type::from_impl(end_of_range(it.get_node()->impl())));
+      if(std::distance(it,it_last)!=std::distance(it2,it2_last))return false;
+
+      /* From is_permutation code in
+       * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3068.pdf
+       */
+
+      for(;it!=it_last;++it,++it2){
+        if(!(*it==*it2))break;
+      }
+      if(it!=it_last){
+        for(const_iterator scan=it;scan!=it_last;++scan){
+          if(std::find(it,scan,*scan)!=scan)continue;
+          std::ptrdiff_t matches=std::count(it2,it2_last,*scan);
+          if(matches==0||matches!=std::count(scan,it_last,*scan))return false;
+        }
+        it=it_last;
+      }
+    }
+    return true;
+  }
+
 #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
   /* serialization */
 
@@ -956,8 +1128,6 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
       if(s1!=size())return false;
     }
 
-    if(first_bucket!=buckets.first_nonempty(0))return false;
-
     return super::invariant_();
   }
 
@@ -976,64 +1146,147 @@ private:
     return bucket(key(v));
   }
 
+  struct link_info_non_unique
+  {
+    link_info_non_unique(node_impl_base_pointer pos):
+      first(pos),last(node_impl_base_pointer(0)){}
+
+    operator const node_impl_base_pointer&()const{return this->first;}
+
+    node_impl_base_pointer first,last;
+  };
+
+  typedef typename mpl::if_<
+    is_same<Category,hashed_unique_tag>,
+    node_impl_base_pointer,
+    link_info_non_unique
+  >::type                                link_info;
+
+  bool link_point(value_param_type v,link_info& pos)
+  {
+    return link_point(v,pos,Category());
+  }
+
   bool link_point(
-    value_param_type v,node_impl_pointer& pos,hashed_unique_tag)
+    value_param_type v,node_impl_base_pointer& pos,hashed_unique_tag)
   {
-    node_impl_pointer x=pos->next();
-    while(x!=pos){
-      if(eq(key(v),key(node_type::from_impl(x)->value()))){
-        pos=x;
+    for(node_impl_pointer x=pos->prior();x!=node_impl_pointer(0);
+        x=node_alg::after_local(x)){
+      if(eq_(key(v),key(node_type::from_impl(x)->value()))){
+        pos=node_impl_type::base_pointer_from(x);
         return false;
       }
-      x=x->next();
     }
     return true;
   }
 
   bool link_point(
-    value_param_type v,node_impl_pointer& pos,hashed_non_unique_tag)
+    value_param_type v,link_info_non_unique& pos,hashed_non_unique_tag)
   {
-    node_impl_pointer prev=pos;
-    node_impl_pointer x=pos->next();
-    while(x!=pos){
-      if(eq(key(v),key(node_type::from_impl(x)->value()))){
-        pos=prev;
+    for(node_impl_pointer x=pos.first->prior();x!=node_impl_pointer(0);
+        x=node_alg::next_to_inspect(x)){
+      if(eq_(key(v),key(node_type::from_impl(x)->value()))){
+        pos.first=node_impl_type::base_pointer_from(x);
+        pos.last=node_impl_type::base_pointer_from(last_of_range(x));
         return true;
       }
-      prev=x;
-      x=x->next();
     }
     return true;
   }
-  
-  static void link(node_type* x,node_impl_pointer pos)
+
+  node_impl_pointer last_of_range(node_impl_pointer x)const
   {
-    node_impl_type::link(x->impl(),pos);
-  };
+    return last_of_range(x,Category());
+  }
 
-  static void link(node_impl_pointer x,node_impl_pointer pos)
+  node_impl_pointer last_of_range(node_impl_pointer x,hashed_unique_tag)const
   {
-    node_impl_type::link(x,pos);
-  };
+    return x;
+  }
 
-  static void unlink(node_type* x)
+  node_impl_pointer last_of_range(
+    node_impl_pointer x,hashed_non_unique_tag)const
   {
-    node_impl_type::unlink(x->impl());
-  };
+    node_impl_base_pointer y=x->next();
+    node_impl_pointer      z=y->prior();
+    if(z==x){                      /* range of size 1 or 2 */
+      node_impl_pointer yy=node_impl_type::pointer_from(y);
+      return
+        eq_(
+          key(node_type::from_impl(x)->value()),
+          key(node_type::from_impl(yy)->value()))?yy:x;
+    }
+    else if(z->prior()==x)               /* last of bucket */
+      return x;
+    else                                /* group of size>2 */        
+      return z;
+  }
+
+  node_impl_pointer end_of_range(node_impl_pointer x)const
+  {
+    return end_of_range(x,Category());
+  }
 
-  static node_impl_pointer prev(node_type* x)
+  node_impl_pointer end_of_range(node_impl_pointer x,hashed_unique_tag)const
   {
-    return node_impl_type::prev(x->impl());
+    return node_alg::after(last_of_range(x));
+  }
+
+  node_impl_pointer end_of_range(
+    node_impl_pointer x,hashed_non_unique_tag)const
+  {
+    node_impl_base_pointer y=x->next();
+    node_impl_pointer      z=y->prior();
+    if(z==x){                      /* range of size 1 or 2 */
+      node_impl_pointer yy=node_impl_type::pointer_from(y);
+      if(!eq_(
+           key(node_type::from_impl(x)->value()),
+           key(node_type::from_impl(yy)->value())))yy=x;
+      return yy->next()->prior()==yy?
+               node_impl_type::pointer_from(yy->next()):
+               yy->next()->prior();
+    }
+    else if(z->prior()==x)               /* last of bucket */
+      return z;
+    else                                /* group of size>2 */        
+      return z->next()->prior()==z?
+               node_impl_type::pointer_from(z->next()):
+               z->next()->prior();
   }
 
-  static node_impl_pointer prev_from(node_type* x,node_impl_pointer y)
+  void link(node_type* x,const link_info& pos)
   {
-    return node_impl_type::prev_from(x->impl(),y);
+    link(x,pos,Category());
   }
 
-  static void unlink_next(node_impl_pointer x)
+  void link(node_type* x,node_impl_base_pointer pos,hashed_unique_tag)
   {
-    node_impl_type::unlink_next(x);
+    node_alg::link(x->impl(),pos,header()->impl());
+  }
+
+  void link(node_type* x,const link_info_non_unique& pos,hashed_non_unique_tag)
+  {
+    if(pos.last==node_impl_base_pointer(0)){
+      node_alg::link(x->impl(),pos.first,header()->impl());
+    }
+    else{
+      node_alg::link(
+        x->impl(),
+        node_impl_type::pointer_from(pos.first),
+        node_impl_type::pointer_from(pos.last));
+    }
+  }
+
+  void unlink(node_type* x)
+  {
+    node_alg::unlink(x->impl());
+  }
+
+  typedef typename node_alg::unlink_undo unlink_undo;
+
+  void unlink(node_type* x,unlink_undo& undo)
+  {
+    node_alg::unlink(x->impl(),undo);
   }
 
   void calculate_max_load()
@@ -1043,112 +1296,206 @@ private:
     if(max_load>fml)max_load=static_cast<size_type>(fml);
   }
 
-  void reserve(size_type n)
+  void reserve_for_insert(size_type n)
   {
     if(n>max_load){
       size_type bc =(std::numeric_limits<size_type>::max)();
-      float     fbc=static_cast<float>(1+n/mlf);
+      float     fbc=static_cast<float>(1+static_cast<double>(n)/mlf);
       if(bc>fbc)bc =static_cast<size_type>(fbc);
       unchecked_rehash(bc);
     }
   }
 
-  void unchecked_rehash(size_type n)
+  void unchecked_rehash(size_type n){unchecked_rehash(n,Category());}
+
+  void unchecked_rehash(size_type n,hashed_unique_tag)
   {
-    bucket_array_type buckets1(get_allocator(),header()->impl(),n);
-    auto_space<std::size_t,allocator_type> hashes(get_allocator(),size());
+    node_impl_type    cpy_end_node;
+    node_impl_pointer cpy_end=node_impl_pointer(&cpy_end_node),
+                      end_=header()->impl();
+    bucket_array_type buckets_cpy(get_allocator(),cpy_end,n);
 
-    std::size_t i=0;
-    node_impl_pointer x=buckets.begin();
-    node_impl_pointer x_end=buckets.end();
-    for(;x!=x_end;++x){
-      node_impl_pointer y=x->next();
-      while(y!=x){
-        hashes.data()[i++]=hash(key(node_type::from_impl(y)->value()));
-        y=y->next();
+    if(size()!=0){
+      auto_space<
+        std::size_t,allocator_type>       hashes(get_allocator(),size());
+      auto_space<
+        node_impl_pointer,allocator_type> node_ptrs(get_allocator(),size());
+      std::size_t                         i=0,size_=size();
+      bool                                within_bucket=false;
+      BOOST_TRY{
+        for(;i!=size_;++i){
+          node_impl_pointer x=end_->prior();
+
+          /* only this can possibly throw */
+          std::size_t h=hash_(key(node_type::from_impl(x)->value()));
+
+          hashes.data()[i]=h;
+          node_ptrs.data()[i]=x;
+          within_bucket=!node_alg::unlink_last(end_);
+          node_alg::link(x,buckets_cpy.at(buckets_cpy.position(h)),cpy_end);
+        }
       }
+      BOOST_CATCH(...){
+        if(i!=0){
+          std::size_t prev_buc=buckets.position(hashes.data()[i-1]);
+          if(!within_bucket)prev_buc=~prev_buc;
+
+          for(std::size_t j=i;j--;){
+            std::size_t       buc=buckets.position(hashes.data()[j]);
+            node_impl_pointer x=node_ptrs.data()[j];
+            if(buc==prev_buc)node_alg::append(x,end_);
+            else node_alg::link(x,buckets.at(buc),end_);
+            prev_buc=buc;
+          }
+        }
+        BOOST_RETHROW;
+      }
+      BOOST_CATCH_END
     }
 
-    i=0;
-    x=buckets.begin();
-    for(;x!=x_end;++x){
-      node_impl_pointer y=x->next();
-      while(y!=x){
-        node_impl_pointer z=y->next();
-        std::size_t       buc1=buckets1.position(hashes.data()[i++]);
-        node_impl_pointer x1=buckets1.at(buc1);
-        link(y,x1);
-        y=z;
+    end_->prior()=cpy_end->prior()!=cpy_end?cpy_end->prior():end_;
+    end_->next()=cpy_end->next();
+    end_->prior()->next()->prior()=end_->next()->prior()->prior()=end_;
+    buckets.swap(buckets_cpy);
+    calculate_max_load();
+  }
+
+  void unchecked_rehash(size_type n,hashed_non_unique_tag)
+  {
+    node_impl_type    cpy_end_node;
+    node_impl_pointer cpy_end=node_impl_pointer(&cpy_end_node),
+                      end_=header()->impl();
+    bucket_array_type buckets_cpy(get_allocator(),cpy_end,n);
+
+    if(size()!=0){
+      auto_space<
+        std::size_t,allocator_type>       hashes(get_allocator(),size());
+      auto_space<
+        node_impl_pointer,allocator_type> node_ptrs(get_allocator(),size());
+      std::size_t                         i=0;
+      bool                                within_bucket=false;
+      BOOST_TRY{
+        for(;;++i){
+          node_impl_pointer x=end_->prior();
+          if(x==end_)break;
+
+          /* only this can possibly throw */
+          std::size_t h=hash_(key(node_type::from_impl(x)->value()));
+
+          hashes.data()[i]=h;
+          node_ptrs.data()[i]=x;
+          std::pair<node_impl_pointer,bool> p=
+            node_alg::unlink_last_group(end_);
+          node_alg::link_range(
+            p.first,x,buckets_cpy.at(buckets_cpy.position(h)),cpy_end);
+          within_bucket=!(p.second);
+        }
       }
+      BOOST_CATCH(...){
+        if(i!=0){
+          std::size_t prev_buc=buckets.position(hashes.data()[i-1]);
+          if(!within_bucket)prev_buc=~prev_buc;
+
+          for(std::size_t j=i;j--;){
+            std::size_t       buc=buckets.position(hashes.data()[j]);
+            node_impl_pointer x=node_ptrs.data()[j],
+                              y=
+              x->prior()->next()!=node_impl_type::base_pointer_from(x)&&
+              x->prior()->next()->prior()!=x?
+                node_impl_type::pointer_from(x->prior()->next()):x;
+            node_alg::unlink_range(y,x);
+            if(buc==prev_buc)node_alg::append_range(y,x,end_);
+            else node_alg::link_range(y,x,buckets.at(buc),end_);
+            prev_buc=buc;
+          }
+        }
+        BOOST_RETHROW;
+      }
+      BOOST_CATCH_END
     }
 
-    buckets.swap(buckets1);
+    end_->prior()=cpy_end->prior()!=cpy_end?cpy_end->prior():end_;
+    end_->next()=cpy_end->next();
+    end_->prior()->next()->prior()=end_->next()->prior()->prior()=end_;
+    buckets.swap(buckets_cpy);
     calculate_max_load();
-    first_bucket=buckets.first_nonempty(0);
+  }
+
+  bool in_place(node_impl_pointer x,key_param_type k,std::size_t buc)const
+  {
+    return in_place(x,k,buc,Category());
   }
 
   bool in_place(
     node_impl_pointer x,key_param_type k,std::size_t buc,
     hashed_unique_tag)const
   {
-    std::less_equal<node_impl_pointer> leq;
-    node_impl_pointer                  bbegin=buckets.begin();
-    node_impl_pointer                  bend=buckets.end();
-    node_impl_pointer                  pbuc=x->next();
-
-    while(!leq(bbegin,pbuc)||!leq(pbuc,bend))pbuc=pbuc->next();
-    if(buc!=static_cast<std::size_t>(pbuc-bbegin))return false;
-
-    node_impl_pointer y=x;
-    while(y->next()!=x){
-      y=y->next();
-      if(y==pbuc)continue;
-      if(eq(k,key(node_type::from_impl(y)->value())))return false;
+    bool found=false;
+    for(node_impl_pointer y=buckets.at(buc)->prior();
+        y!=node_impl_pointer(0);y=node_alg::after_local(y)){
+      if(y==x)found=true;
+      else if(eq_(k,key(node_type::from_impl(y)->value())))return false;
     }
-    return true;
+    return found;
   }
 
   bool in_place(
     node_impl_pointer x,key_param_type k,std::size_t buc,
     hashed_non_unique_tag)const
   {
-    std::less_equal<node_impl_pointer> leq;
-    node_impl_pointer                  bbegin=buckets.begin();
-    node_impl_pointer                  bend=buckets.end();
-    node_impl_pointer                  pbuc=x->next();
-
-    while(!leq(bbegin,pbuc)||!leq(pbuc,bend))pbuc=pbuc->next();
-    if(buc!=static_cast<std::size_t>(pbuc-bbegin))return false;
-
-    node_impl_pointer y=x->next();
-    if(y!=pbuc){
-      if(eq(k,key(node_type::from_impl(y)->value()))){
-        /* adjacent to equivalent element -> in place */
-        return true;
-      }
-      else{
-        y=y->next();
-        while(y!=pbuc){
-          if(eq(k,key(node_type::from_impl(y)->value())))return false;
-          y=y->next();
+    bool found=false;
+    int  range_size=0;
+    for(node_impl_pointer y=buckets.at(buc)->prior();y!=node_impl_pointer(0);){
+      if(node_alg::is_first_of_group(y)){ /* group of 3 or more */
+        if(y==x){
+          /* in place <-> equal to some other member of the group */
+          return eq_(
+            k,
+            key(node_type::from_impl(
+              node_impl_type::pointer_from(y->next()))->value()));
+        }
+        else{
+          node_impl_pointer z=
+            node_alg::after_local(y->next()->prior()); /* end of range */
+          if(eq_(k,key(node_type::from_impl(y)->value()))){
+            if(found)return false; /* x lies outside */
+            do{
+              if(y==x)return true;
+              y=node_alg::after_local(y);
+            }while(y!=z);
+            return false; /* x not found */
+          }
+          else{
+            if(range_size==1&&!found)return false;
+            if(range_size==2)return found;
+            range_size=0;
+            y=z; /* skip range (and potentially x, too, which is fine) */
+          }
         }
       }
-    }
-    while(y->next()!=x){
-      y=y->next();
-      if(eq(k,key(node_type::from_impl(y)->value()))){
-        while(y->next()!=x){
-          y=y->next();
-          if(!eq(k,key(node_type::from_impl(y)->value())))return false;
+      else{ /* group of 1 or 2 */
+        if(y==x){
+          if(range_size==1)return true;
+          range_size=1;
+          found=true;
         }
-        /* after a group of equivalent elements --> in place */
-        return true;
+        else if(eq_(k,key(node_type::from_impl(y)->value()))){
+          if(range_size==0&&found)return false;
+          if(range_size==1&&!found)return false;
+          if(range_size==2)return false;
+          ++range_size;
+        }
+        else{
+          if(range_size==1&&!found)return false;
+          if(range_size==2)return found;
+          range_size=0;
+        }
+        y=node_alg::after_local(y);
       }
     }
-    return true;
+    return found;
   }
 
-
 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
   void detach_iterators(node_type* x)
   {
@@ -1157,13 +1504,35 @@ private:
   }
 #endif
 
+  template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
+  std::pair<iterator,bool> emplace_impl(BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
+  {
+    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
+    std::pair<final_node_type*,bool>p=
+      this->final_emplace_(BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
+    return std::pair<iterator,bool>(make_iterator(p.first),p.second);
+  }
+
+  template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
+  iterator emplace_hint_impl(
+    iterator position,BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
+  {
+    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
+    BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
+    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
+    std::pair<final_node_type*,bool>p=
+      this->final_emplace_hint_(
+        static_cast<final_node_type*>(position.get_node()),
+        BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
+    return make_iterator(p.first);
+  }
+
   key_from_value               key;
-  hasher                       hash;
-  key_equal                    eq;
+  hasher                       hash_;
+  key_equal                    eq_;
   bucket_array_type            buckets;
   float                        mlf;
   size_type                    max_load;
-  std::size_t                  first_bucket;
       
 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
     BOOST_WORKAROUND(__MWERKS__,<=0x3003)
@@ -1171,6 +1540,30 @@ private:
 #endif
 };
 
+/* comparison */
+
+template<
+  typename KeyFromValue,typename Hash,typename Pred,
+  typename SuperMeta,typename TagList,typename Category
+>
+bool operator==(
+  const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
+  const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
+{
+  return x.equals(y);
+}
+
+template<
+  typename KeyFromValue,typename Hash,typename Pred,
+  typename SuperMeta,typename TagList,typename Category
+>
+bool operator!=(
+  const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
+  const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
+{
+  return !(x==y);
+}
+
 /*  specialized algorithms */
 
 template<
@@ -1201,7 +1594,7 @@ struct hashed_unique
   template<typename Super>
   struct node_class
   {
-    typedef detail::hashed_index_node<Super> type;
+    typedef detail::hashed_index_node<Super,detail::hashed_unique_tag> type;
   };
 
   template<typename SuperMeta>
@@ -1226,7 +1619,8 @@ struct hashed_non_unique
   template<typename Super>
   struct node_class
   {
-    typedef detail::hashed_index_node<Super> type;
+    typedef detail::hashed_index_node<
+      Super,detail::hashed_non_unique_tag> type;
   };
 
   template<typename SuperMeta>
@@ -1257,5 +1651,6 @@ inline boost::mpl::true_* boost_foreach_is_noncopyable(
 }
 
 #undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
+#undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF
 
 #endif