--- /dev/null
+/* Copyright 2003-2007 Joaquín M López Muñoz.
+ * 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)
+ *
+ * See http://www.boost.org/libs/multi_index for library home page.
+ */
+
+#ifndef BOOST_MULTI_INDEX_HASHED_INDEX_HPP
+#define BOOST_MULTI_INDEX_HASHED_INDEX_HPP
+
+#if defined(_MSC_VER)&&(_MSC_VER>=1200)
+#pragma once
+#endif
+
+#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
+#include <algorithm>
+#include <boost/call_traits.hpp>
+#include <boost/detail/allocator_utilities.hpp>
+#include <boost/detail/no_exceptions_support.hpp>
+#include <boost/detail/workaround.hpp>
+#include <boost/limits.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/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/hashed_index_fwd.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <cstddef>
+#include <functional>
+#include <utility>
+
+#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 \
+ detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)= \
+ detail::make_obj_guard(*this,&hashed_index::check_invariant_); \
+ BOOST_JOIN(check_invariant_,__LINE__).touch();
+#else
+#define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
+#endif
+
+namespace boost{
+
+namespace multi_index{
+
+namespace detail{
+
+/* hashed_index adds a layer of hashed indexing to a given Super */
+
+/* Most of the implementation of unique and non-unique indices is
+ * shared. We tell from one another on instantiation time by using
+ * these tags.
+ */
+
+struct hashed_unique_tag{};
+struct hashed_non_unique_tag{};
+
+template<
+ typename KeyFromValue,typename Hash,typename Pred,
+ typename SuperMeta,typename TagList,typename Category
+>
+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)&&\
+ BOOST_WORKAROUND(__MWERKS__,<=0x3003)
+/* The "ISO C++ Template Parser" option in CW8.3 has a problem with the
+ * lifetime of const references bound to temporaries --precisely what
+ * scopeguards are.
+ */
+
+#pragma parse_mfunc_templ off
+#endif
+
+ typedef typename SuperMeta::type super;
+
+protected:
+ typedef hashed_index_node<
+ typename super::node_type> node_type;
+
+private:
+ typedef typename node_type::impl_type node_impl_type;
+ typedef typename node_impl_type::pointer node_impl_pointer;
+ typedef bucket_array<
+ typename super::final_allocator_type> bucket_array_type;
+
+public:
+ /* types */
+
+ typedef typename KeyFromValue::result_type key_type;
+ typedef typename node_type::value_type value_type;
+ typedef KeyFromValue key_from_value;
+ typedef Hash hasher;
+ typedef Pred key_equal;
+ typedef tuple<std::size_t,
+ key_from_value,hasher,key_equal> ctor_args;
+ typedef typename super::final_allocator_type allocator_type;
+ typedef typename allocator_type::pointer pointer;
+ typedef typename allocator_type::const_pointer const_pointer;
+ typedef typename allocator_type::reference reference;
+ typedef typename allocator_type::const_reference const_reference;
+ typedef std::size_t size_type;
+ 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>,
+ hashed_index> iterator;
+#endif
+#else
+ typedef hashed_index_iterator<
+ node_type,bucket_array_type> iterator;
+#endif
+
+ typedef iterator const_iterator;
+
+ typedef iterator local_iterator;
+ typedef const_iterator const_local_iterator;
+ typedef TagList tag_list;
+
+protected:
+ typedef typename super::final_node_type final_node_type;
+ typedef tuples::cons<
+ ctor_args,
+ typename super::ctor_args_list> ctor_args_list;
+ typedef typename mpl::push_front<
+ typename super::index_type_list,
+ hashed_index>::type index_type_list;
+ typedef typename mpl::push_front<
+ typename super::iterator_type_list,
+ iterator>::type iterator_type_list;
+ typedef typename mpl::push_front<
+ typename super::const_iterator_type_list,
+ const_iterator>::type const_iterator_type_list;
+ typedef typename super::copy_map_type copy_map_type;
+
+#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
+ typedef typename super::index_saver_type index_saver_type;
+ typedef typename super::index_loader_type index_loader_type;
+#endif
+
+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;
+
+public:
+
+ /* construct/destroy/copy
+ * Default and copy ctors are in the protected section as indices are
+ * not supposed to be created on their own. No range ctor either.
+ */
+
+ hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& operator=(
+ const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
+ {
+ this->final()=x.final();
+ return *this;
+ }
+
+ allocator_type get_allocator()const
+ {
+ 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_();}
+
+ /* 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 iterator_to(const value_type& x)
+ {
+ return make_iterator(node_from_value<node_type>(&x));
+ }
+
+ const_iterator iterator_to(const value_type& x)const
+ {
+ return make_iterator(node_from_value<node_type>(&x));
+ }
+
+ /* modifiers */
+
+ std::pair<iterator,bool> insert(value_param_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)
+ {
+ 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_(
+ 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);
+ }
+
+ iterator erase(iterator position)
+ {
+ 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;
+ this->final_erase_(static_cast<final_node_type*>(position++.get_node()));
+ return position;
+ }
+
+ size_type erase(key_param_type k)
+ {
+ 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;
+ 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()));
+ this->final_erase_(
+ static_cast<final_node_type*>(node_type::from_impl(y)));
+ y=z;
+ ++s;
+ }while(b);
+ break;
+ }
+ y=y->next();
+ }
+ return s;
+ }
+
+ iterator erase(iterator first,iterator last)
+ {
+ BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
+ BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
+ BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,*this);
+ BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,*this);
+ BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
+ BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
+ while(first!=last){
+ first=erase(first);
+ }
+ return first;
+ }
+
+ bool replace(iterator position,value_param_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_(
+ x,static_cast<final_node_type*>(position.get_node()));
+ }
+
+ template<typename Modifier>
+ bool modify(iterator position,Modifier mod)
+ {
+ 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;
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+ /* MSVC++ 6.0 optimizer on safe mode code chokes if this
+ * this is not added. Left it for all compilers as it does no
+ * harm.
+ */
+
+ position.detach();
+#endif
+
+ return this->final_modify_(
+ mod,static_cast<final_node_type*>(position.get_node()));
+ }
+
+ template<typename Modifier,typename Rollback>
+ bool modify(iterator position,Modifier mod,Rollback back)
+ {
+ 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;
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+ /* MSVC++ 6.0 optimizer on safe mode code chokes if this
+ * this is not added. Left it for all compilers as it does no
+ * harm.
+ */
+
+ position.detach();
+#endif
+
+ return this->final_modify_(
+ mod,back,static_cast<final_node_type*>(position.get_node()));
+ }
+
+ template<typename Modifier>
+ bool modify_key(iterator position,Modifier mod)
+ {
+ 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 modify(
+ position,modify_key_adaptor<Modifier,value_type,KeyFromValue>(mod,key));
+ }
+
+ template<typename Modifier,typename Rollback>
+ bool modify_key(iterator position,Modifier mod,Rollback back)
+ {
+ 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 modify(
+ position,
+ modify_key_adaptor<Modifier,value_type,KeyFromValue>(mod,key),
+ modify_key_adaptor<Modifier,value_type,KeyFromValue>(back,key));
+ }
+
+ void clear()
+ {
+ BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
+ this->final_clear_();
+ }
+
+ void swap(hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
+ {
+ BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
+ 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;}
+
+ /* lookup */
+
+ /* Internally, these ops rely on const_iterator being the same
+ * type as iterator.
+ */
+
+ template<typename CompatibleKey>
+ iterator find(const CompatibleKey& k)const
+ {
+ return find(k,hash,eq);
+ }
+
+ template<
+ typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
+ >
+ iterator find(
+ 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));
+ }
+ y=y->next();
+ }
+ return end();
+ }
+
+ template<typename CompatibleKey>
+ size_type count(const CompatibleKey& k)const
+ {
+ return count(k,hash,eq);
+ }
+
+ template<
+ typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
+ >
+ size_type count(
+ 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()))){
+ do{
+ ++res;
+ y=y->next();
+ }while(y!=x&&eq(k,key(node_type::from_impl(y)->value())));
+ break;
+ }
+ y=y->next();
+ }
+ return res;
+ }
+
+ template<typename CompatibleKey>
+ std::pair<iterator,iterator> equal_range(const CompatibleKey& k)const
+ {
+ return equal_range(k,hash,eq);
+ }
+
+ template<
+ typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
+ >
+ std::pair<iterator,iterator> equal_range(
+ 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();
+ }
+ return std::pair<iterator,iterator>(
+ make_iterator(node_type::from_impl(y0)),
+ make_iterator(node_type::from_impl(y)));
+ }
+ 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_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){
+ ++res;
+ y=y->next();
+ }
+ return res;
+ }
+
+ size_type bucket(key_param_type k)const
+ {
+ return buckets.position(hash(k));
+ }
+
+ local_iterator begin(size_type n)
+ {
+ return const_cast<const hashed_index*>(this)->begin(n);
+ }
+
+ 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));
+ }
+
+ local_iterator end(size_type n)
+ {
+ return const_cast<const hashed_index*>(this)->end(n);
+ }
+
+ const_local_iterator end(size_type n)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()));
+ }
+
+ const_local_iterator cbegin(size_type n)const{return begin(n);}
+ const_local_iterator cend(size_type n)const{return end(n);}
+
+ local_iterator local_iterator_to(const value_type& x)
+ {
+ return make_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));
+ }
+
+ /* hash policy */
+
+ float load_factor()const{return static_cast<float>(size())/bucket_count();}
+ float max_load_factor()const{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;
+
+ size_type bc =(std::numeric_limits<size_type>::max)();
+ float fbc=static_cast<float>(1+size()/mlf);
+ if(bc>fbc){
+ bc=static_cast<size_type>(fbc);
+ if(bc<n)bc=n;
+ }
+ unchecked_rehash(bc);
+ }
+
+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())),
+ buckets(al,header()->impl(),tuples::get<0>(args_list.get_head())),
+ mlf(1.0),
+ first_bucket(buckets.size())
+ {
+ calculate_max_load();
+ }
+
+ hashed_index(
+ const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x):
+ super(x),
+
+#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(),x.buckets.size()),
+ mlf(x.mlf),
+ max_load(x.max_load),
+ first_bucket(x.first_bucket)
+ {
+ /* Copy ctor just takes the internal configuration objects from x. The rest
+ * is done in subsequent call to copy_().
+ */
+ }
+
+ ~hashed_index()
+ {
+ /* the container is guaranteed to be empty by now */
+ }
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+ iterator make_iterator(node_type* node)
+ {
+ return iterator(node,&buckets,this);
+ }
+
+ const_iterator make_iterator(node_type* node)const
+ {
+ return const_iterator(
+ node,
+ &const_cast<bucket_array_type&>(buckets),
+ const_cast<hashed_index*>(this));
+ }
+#else
+ iterator make_iterator(node_type* node)
+ {
+ return iterator(node,&buckets);
+ }
+
+ const_iterator make_iterator(node_type* node)const
+ {
+ return const_iterator(node,&const_cast<bucket_array_type&>(buckets));
+ }
+#endif
+
+ 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;
+ }
+
+ super::copy_(x,map);
+ }
+
+ node_type* insert_(value_param_type v,node_type* x)
+ {
+ 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);
+
+ node_type* res=static_cast<node_type*>(super::insert_(v,x));
+ if(res==x){
+ link(x,pos);
+ if(first_bucket>buc)first_bucket=buc;
+ }
+ return res;
+ }
+
+ node_type* insert_(value_param_type v,node_type* position,node_type* x)
+ {
+ 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);
+
+ 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;
+ }
+ 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)
+ detach_iterators(x);
+#endif
+ }
+
+ 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;
+ }
+ }
+ }
+
+ void clear_()
+ {
+ super::clear_();
+ buckets.clear();
+ first_bucket=buckets.size();
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+ safe_super::detach_dereferenceable_iterators();
+#endif
+ }
+
+ void swap_(
+ hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
+ {
+ std::swap(key,x.key);
+ 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);
+#endif
+
+ super::swap_(x);
+ }
+
+ bool replace_(value_param_type v,node_type* x)
+ {
+ if(eq(key(v),key(x->value()))){
+ return super::replace_(v,x);
+ }
+
+ node_impl_pointer y=prev(x);
+ unlink_next(y);
+
+ 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)){
+ 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);
+ return false;
+ }
+ BOOST_CATCH(...){
+ link(x,y);
+ BOOST_RETHROW;
+ }
+ BOOST_CATCH_END
+ }
+
+ bool modify_(node_type* x)
+ {
+ unlink(x);
+
+ std::size_t buc;
+ node_impl_pointer pos;
+ BOOST_TRY
+ {
+ buc=find_bucket(x->value());
+ pos=buckets.at(buc);
+ if(!link_point(x->value(),pos,Category())){
+ first_bucket=buckets.first_nonempty(first_bucket);
+ super::erase_(x);
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+ detach_iterators(x);
+#endif
+ return false;
+ }
+
+ }
+ BOOST_CATCH(...){
+ first_bucket=buckets.first_nonempty(first_bucket);
+ super::erase_(x);
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+ detach_iterators(x);
+#endif
+
+ BOOST_RETHROW;
+ }
+ BOOST_CATCH_END
+
+ BOOST_TRY{
+ if(super::modify_(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;
+ }
+
+ first_bucket=buckets.first_nonempty(first_bucket);
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+ detach_iterators(x);
+#endif
+ return false;
+ }
+ BOOST_CATCH(...){
+ first_bucket=buckets.first_nonempty(first_bucket);
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+ detach_iterators(x);
+#endif
+
+ BOOST_RETHROW;
+ }
+ BOOST_CATCH_END
+ }
+
+ bool modify_rollback_(node_type* x)
+ {
+ node_impl_pointer y=prev(x);
+ unlink_next(y);
+
+ BOOST_TRY{
+ std::size_t buc=find_bucket(x->value());
+ node_impl_pointer pos=buckets.at(buc);
+ if(link_point(x->value(),pos,Category())&&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);
+ return false;
+ }
+ BOOST_CATCH(...){
+ link(x,y);
+ BOOST_RETHROW;
+ }
+ BOOST_CATCH_END
+ }
+
+#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
+ /* serialization */
+
+ template<typename Archive>
+ void save_(
+ Archive& ar,const unsigned int version,const index_saver_type& sm)const
+ {
+ ar<<serialization::make_nvp("position",buckets);
+ super::save_(ar,version,sm);
+ }
+
+ template<typename Archive>
+ void load_(Archive& ar,const unsigned int version,const index_loader_type& lm)
+ {
+ ar>>serialization::make_nvp("position",buckets);
+ super::load_(ar,version,lm);
+ }
+#endif
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
+ /* invariant stuff */
+
+ bool invariant_()const
+ {
+ if(size()==0||begin()==end()){
+ if(size()!=0||begin()!=end())return false;
+ }
+ else{
+ size_type s0=0;
+ for(const_iterator it=begin(),it_end=end();it!=it_end;++it,++s0){}
+ if(s0!=size())return false;
+
+ size_type s1=0;
+ for(size_type buc=0;buc<bucket_count();++buc){
+ size_type ss1=0;
+ for(const_local_iterator it=begin(buc),it_end=end(buc);
+ it!=it_end;++it,++ss1){
+ if(find_bucket(*it)!=buc)return false;
+ }
+ if(ss1!=bucket_size(buc))return false;
+ s1+=ss1;
+ }
+ if(s1!=size())return false;
+ }
+
+ if(first_bucket!=buckets.first_nonempty(0))return false;
+
+ return super::invariant_();
+ }
+
+ /* This forwarding function eases things for the boost::mem_fn construct
+ * in BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT. Actually,
+ * final_check_invariant is already an inherited member function of index.
+ */
+ void check_invariant_()const{this->final_check_invariant_();}
+#endif
+
+private:
+ node_type* header()const{return this->final_header();}
+
+ std::size_t find_bucket(value_param_type v)const
+ {
+ return bucket(key(v));
+ }
+
+ bool link_point(
+ value_param_type v,node_impl_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;
+ return false;
+ }
+ x=x->next();
+ }
+ return true;
+ }
+
+ bool link_point(
+ value_param_type v,node_impl_pointer& 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;
+ return true;
+ }
+ prev=x;
+ x=x->next();
+ }
+ return true;
+ }
+
+ void link(node_type* x,node_impl_pointer pos)
+ {
+ node_impl_type::link(x->impl(),pos);
+ };
+
+ void link(node_impl_pointer x,node_impl_pointer pos)
+ {
+ node_impl_type::link(x,pos);
+ };
+
+ void unlink(node_type* x)
+ {
+ node_impl_type::unlink(x->impl());
+ };
+
+ static node_impl_pointer prev(node_type* x)
+ {
+ return node_impl_type::prev(x->impl());
+ }
+
+ static void unlink_next(node_impl_pointer x)
+ {
+ node_impl_type::unlink_next(x);
+ }
+
+ void calculate_max_load()
+ {
+ float fml=static_cast<float>(mlf*bucket_count());
+ max_load=(std::numeric_limits<size_type>::max)();
+ if(max_load>fml)max_load=static_cast<size_type>(fml);
+ }
+
+ void reserve(size_type n)
+ {
+ if(n>max_load){
+ size_type bc =(std::numeric_limits<size_type>::max)();
+ float fbc=static_cast<float>(1+n/mlf);
+ if(bc>fbc)bc =static_cast<size_type>(fbc);
+ unchecked_rehash(bc);
+ }
+ }
+
+ void unchecked_rehash(size_type n)
+ {
+ bucket_array_type buckets1(get_allocator(),header()->impl(),n);
+ auto_space<std::size_t,allocator_type> hashes(get_allocator(),size());
+
+ 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();
+ }
+ }
+
+ 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;
+ }
+ }
+
+ buckets.swap(buckets1);
+ calculate_max_load();
+ first_bucket=buckets.first_nonempty(0);
+ }
+
+#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
+ void detach_iterators(node_type* x)
+ {
+ iterator it=make_iterator(x);
+ safe_mode::detach_equivalent_iterators(it);
+ }
+#endif
+
+ key_from_value key;
+ 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)
+#pragma parse_mfunc_templ reset
+#endif
+};
+
+/* specialized algorithms */
+
+template<
+ typename KeyFromValue,typename Hash,typename Pred,
+ typename SuperMeta,typename TagList,typename Category
+>
+void swap(
+ hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
+ hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
+{
+ x.swap(y);
+}
+
+} /* namespace multi_index::detail */
+
+/* hashed index specifiers */
+
+template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
+struct hashed_unique
+{
+ typedef typename detail::hashed_index_args<
+ Arg1,Arg2,Arg3,Arg4> index_args;
+ typedef typename index_args::tag_list_type::type tag_list_type;
+ typedef typename index_args::key_from_value_type key_from_value_type;
+ typedef typename index_args::hash_type hash_type;
+ typedef typename index_args::pred_type pred_type;
+
+ template<typename Super>
+ struct node_class
+ {
+ typedef detail::hashed_index_node<Super> type;
+ };
+
+ template<typename SuperMeta>
+ struct index_class
+ {
+ typedef detail::hashed_index<
+ key_from_value_type,hash_type,pred_type,
+ SuperMeta,tag_list_type,detail::hashed_unique_tag> type;
+ };
+};
+
+template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
+struct hashed_non_unique
+{
+ typedef typename detail::hashed_index_args<
+ Arg1,Arg2,Arg3,Arg4> index_args;
+ typedef typename index_args::tag_list_type::type tag_list_type;
+ typedef typename index_args::key_from_value_type key_from_value_type;
+ typedef typename index_args::hash_type hash_type;
+ typedef typename index_args::pred_type pred_type;
+
+ template<typename Super>
+ struct node_class
+ {
+ typedef detail::hashed_index_node<Super> type;
+ };
+
+ template<typename SuperMeta>
+ struct index_class
+ {
+ typedef detail::hashed_index<
+ key_from_value_type,hash_type,pred_type,
+ SuperMeta,tag_list_type,detail::hashed_non_unique_tag> type;
+ };
+};
+
+} /* namespace multi_index */
+
+} /* namespace boost */
+
+#undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
+
+#endif