Chris@101: /* Copyright 2003-2015 Joaquin M Lopez Munoz. Chris@16: * Distributed under the Boost Software License, Version 1.0. Chris@16: * (See accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: * Chris@16: * See http://www.boost.org/libs/multi_index for library home page. Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_MULTI_INDEX_HASHED_INDEX_HPP Chris@16: #define BOOST_MULTI_INDEX_HASHED_INDEX_HPP Chris@16: Chris@101: #if defined(_MSC_VER) Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: #include /* keep it first to prevent nasty warns in MSVC */ Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: Chris@16: #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) Chris@16: #include Chris@16: #endif Chris@16: Chris@16: #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION) Chris@16: #include Chris@16: #endif Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) Chris@16: #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x) \ Chris@16: detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)= \ Chris@16: detail::make_obj_guard(x,&hashed_index::check_invariant_); \ Chris@16: BOOST_JOIN(check_invariant_,__LINE__).touch(); Chris@16: #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT \ Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(*this) Chris@16: #else Chris@16: #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x) Chris@16: #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT Chris@16: #endif Chris@16: Chris@16: namespace boost{ Chris@16: Chris@16: namespace multi_index{ Chris@16: Chris@16: namespace detail{ Chris@16: Chris@16: /* hashed_index adds a layer of hashed indexing to a given Super */ Chris@16: Chris@16: /* Most of the implementation of unique and non-unique indices is Chris@16: * shared. We tell from one another on instantiation time by using Chris@101: * Category tags defined in hash_index_node.hpp. Chris@16: */ Chris@16: Chris@16: template< Chris@16: typename KeyFromValue,typename Hash,typename Pred, Chris@16: typename SuperMeta,typename TagList,typename Category Chris@16: > Chris@16: class hashed_index: Chris@16: BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS SuperMeta::type Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: ,public safe_mode::safe_container< Chris@16: hashed_index > Chris@16: #endif Chris@16: Chris@16: { Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\ Chris@16: BOOST_WORKAROUND(__MWERKS__,<=0x3003) Chris@16: /* The "ISO C++ Template Parser" option in CW8.3 has a problem with the Chris@16: * lifetime of const references bound to temporaries --precisely what Chris@16: * scopeguards are. Chris@16: */ Chris@16: Chris@16: #pragma parse_mfunc_templ off Chris@16: #endif Chris@16: Chris@16: typedef typename SuperMeta::type super; Chris@16: Chris@16: protected: Chris@16: typedef hashed_index_node< Chris@101: typename super::node_type,Category> node_type; Chris@16: Chris@16: private: Chris@101: typedef typename node_type::node_alg node_alg; Chris@16: typedef typename node_type::impl_type node_impl_type; Chris@16: typedef typename node_impl_type::pointer node_impl_pointer; Chris@101: typedef typename node_impl_type::base_pointer node_impl_base_pointer; Chris@16: typedef bucket_array< Chris@16: typename super::final_allocator_type> bucket_array_type; Chris@16: Chris@16: public: Chris@16: /* types */ Chris@16: Chris@16: typedef typename KeyFromValue::result_type key_type; Chris@16: typedef typename node_type::value_type value_type; Chris@16: typedef KeyFromValue key_from_value; Chris@16: typedef Hash hasher; Chris@16: typedef Pred key_equal; Chris@16: typedef tuple ctor_args; Chris@16: typedef typename super::final_allocator_type allocator_type; Chris@16: typedef typename allocator_type::pointer pointer; Chris@16: typedef typename allocator_type::const_pointer const_pointer; Chris@16: typedef typename allocator_type::reference reference; Chris@16: typedef typename allocator_type::const_reference const_reference; Chris@16: typedef std::size_t size_type; Chris@16: typedef std::ptrdiff_t difference_type; Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: typedef safe_mode::safe_iterator< Chris@16: hashed_index_iterator< Chris@101: node_type,bucket_array_type, Chris@101: hashed_index_global_iterator_tag>, Chris@16: hashed_index> iterator; Chris@16: #else Chris@16: typedef hashed_index_iterator< Chris@101: node_type,bucket_array_type, Chris@101: hashed_index_global_iterator_tag> iterator; Chris@16: #endif Chris@16: Chris@16: typedef iterator const_iterator; Chris@16: Chris@101: typedef hashed_index_iterator< Chris@101: node_type,bucket_array_type, Chris@101: hashed_index_local_iterator_tag> local_iterator; Chris@101: typedef local_iterator const_local_iterator; Chris@101: Chris@16: typedef TagList tag_list; Chris@16: Chris@16: protected: Chris@16: typedef typename super::final_node_type final_node_type; Chris@16: typedef tuples::cons< Chris@16: ctor_args, Chris@16: typename super::ctor_args_list> ctor_args_list; Chris@16: typedef typename mpl::push_front< Chris@16: typename super::index_type_list, Chris@16: hashed_index>::type index_type_list; Chris@16: typedef typename mpl::push_front< Chris@16: typename super::iterator_type_list, Chris@16: iterator>::type iterator_type_list; Chris@16: typedef typename mpl::push_front< Chris@16: typename super::const_iterator_type_list, Chris@16: const_iterator>::type const_iterator_type_list; Chris@16: typedef typename super::copy_map_type copy_map_type; Chris@16: Chris@16: #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION) Chris@16: typedef typename super::index_saver_type index_saver_type; Chris@16: typedef typename super::index_loader_type index_loader_type; Chris@16: #endif Chris@16: Chris@16: private: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: typedef safe_mode::safe_container< Chris@16: hashed_index> safe_super; Chris@16: #endif Chris@16: Chris@16: typedef typename call_traits::param_type value_param_type; Chris@16: typedef typename call_traits< Chris@16: key_type>::param_type key_param_type; Chris@16: Chris@16: /* Needed to avoid commas in BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL Chris@16: * expansion. Chris@16: */ Chris@16: Chris@16: typedef std::pair emplace_return_type; Chris@16: Chris@16: public: Chris@16: Chris@16: /* construct/destroy/copy Chris@16: * Default and copy ctors are in the protected section as indices are Chris@16: * not supposed to be created on their own. No range ctor either. Chris@16: */ Chris@16: Chris@16: hashed_index& operator=( Chris@16: const hashed_index& x) Chris@16: { Chris@16: this->final()=x.final(); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) Chris@16: hashed_index& operator=( Chris@16: std::initializer_list list) Chris@16: { Chris@16: this->final()=list; Chris@16: return *this; Chris@16: } Chris@16: #endif Chris@16: Chris@101: allocator_type get_allocator()const BOOST_NOEXCEPT Chris@16: { Chris@16: return this->final().get_allocator(); Chris@16: } Chris@16: Chris@16: /* size and capacity */ Chris@16: Chris@101: bool empty()const BOOST_NOEXCEPT{return this->final_empty_();} Chris@101: size_type size()const BOOST_NOEXCEPT{return this->final_size_();} Chris@101: size_type max_size()const BOOST_NOEXCEPT{return this->final_max_size_();} Chris@16: Chris@16: /* iterators */ Chris@16: Chris@101: iterator begin()BOOST_NOEXCEPT Chris@101: {return make_iterator(node_type::from_impl(header()->next()->prior()));} Chris@101: const_iterator begin()const BOOST_NOEXCEPT Chris@101: {return make_iterator(node_type::from_impl(header()->next()->prior()));} Chris@101: iterator end()BOOST_NOEXCEPT{return make_iterator(header());} Chris@101: const_iterator end()const BOOST_NOEXCEPT{return make_iterator(header());} Chris@101: const_iterator cbegin()const BOOST_NOEXCEPT{return begin();} Chris@101: const_iterator cend()const BOOST_NOEXCEPT{return end();} Chris@16: Chris@16: iterator iterator_to(const value_type& x) Chris@16: { Chris@16: return make_iterator(node_from_value(&x)); Chris@16: } Chris@16: Chris@16: const_iterator iterator_to(const value_type& x)const Chris@16: { Chris@16: return make_iterator(node_from_value(&x)); Chris@16: } Chris@16: Chris@16: /* modifiers */ Chris@16: Chris@16: BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL( Chris@16: emplace_return_type,emplace,emplace_impl) Chris@16: Chris@16: BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG( Chris@16: iterator,emplace_hint,emplace_hint_impl,iterator,position) Chris@16: Chris@16: std::pair insert(const value_type& x) Chris@16: { Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: std::pair p=this->final_insert_(x); Chris@16: return std::pair(make_iterator(p.first),p.second); Chris@16: } Chris@16: Chris@16: std::pair insert(BOOST_RV_REF(value_type) x) Chris@16: { Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: std::pair p=this->final_insert_rv_(x); Chris@16: return std::pair(make_iterator(p.first),p.second); Chris@16: } Chris@16: Chris@16: iterator insert(iterator position,const value_type& x) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: std::pair p=this->final_insert_( Chris@16: x,static_cast(position.get_node())); Chris@16: return make_iterator(p.first); Chris@16: } Chris@16: Chris@16: iterator insert(iterator position,BOOST_RV_REF(value_type) x) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: std::pair p=this->final_insert_rv_( Chris@16: x,static_cast(position.get_node())); Chris@16: return make_iterator(p.first); Chris@16: } Chris@16: Chris@16: template Chris@16: void insert(InputIterator first,InputIterator last) Chris@16: { Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: for(;first!=last;++first)this->final_insert_ref_(*first); Chris@16: } Chris@16: Chris@16: #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) Chris@16: void insert(std::initializer_list list) Chris@16: { Chris@16: insert(list.begin(),list.end()); Chris@16: } Chris@16: #endif Chris@16: Chris@16: iterator erase(iterator position) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: this->final_erase_(static_cast(position++.get_node())); Chris@16: return position; Chris@16: } Chris@16: Chris@16: size_type erase(key_param_type k) Chris@16: { Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: Chris@101: std::size_t buc=buckets.position(hash_(k)); Chris@101: for(node_impl_pointer x=buckets.at(buc)->prior(); Chris@101: x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){ Chris@101: if(eq_(k,key(node_type::from_impl(x)->value()))){ Chris@101: node_impl_pointer y=end_of_range(x); Chris@101: size_type s=0; Chris@16: do{ Chris@101: node_impl_pointer z=node_alg::after(x); Chris@16: this->final_erase_( Chris@101: static_cast(node_type::from_impl(x))); Chris@101: x=z; Chris@16: ++s; Chris@101: }while(x!=y); Chris@101: return s; Chris@16: } Chris@16: } Chris@101: return 0; Chris@16: } Chris@16: Chris@16: iterator erase(iterator first,iterator last) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first); Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,*this); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,*this); Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: while(first!=last){ Chris@16: first=erase(first); Chris@16: } Chris@16: return first; Chris@16: } Chris@16: Chris@16: bool replace(iterator position,const value_type& x) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: return this->final_replace_( Chris@16: x,static_cast(position.get_node())); Chris@16: } Chris@16: Chris@16: bool replace(iterator position,BOOST_RV_REF(value_type) x) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: return this->final_replace_rv_( Chris@16: x,static_cast(position.get_node())); Chris@16: } Chris@16: Chris@16: template Chris@16: bool modify(iterator position,Modifier mod) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: /* MSVC++ 6.0 optimizer on safe mode code chokes if this Chris@16: * this is not added. Left it for all compilers as it does no Chris@16: * harm. Chris@16: */ Chris@16: Chris@16: position.detach(); Chris@16: #endif Chris@16: Chris@16: return this->final_modify_( Chris@16: mod,static_cast(position.get_node())); Chris@16: } Chris@16: Chris@16: template Chris@101: bool modify(iterator position,Modifier mod,Rollback back_) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: /* MSVC++ 6.0 optimizer on safe mode code chokes if this Chris@16: * this is not added. Left it for all compilers as it does no Chris@16: * harm. Chris@16: */ Chris@16: Chris@16: position.detach(); Chris@16: #endif Chris@16: Chris@16: return this->final_modify_( Chris@101: mod,back_,static_cast(position.get_node())); Chris@16: } Chris@16: Chris@16: template Chris@16: bool modify_key(iterator position,Modifier mod) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: return modify( Chris@16: position,modify_key_adaptor(mod,key)); Chris@16: } Chris@16: Chris@16: template Chris@101: bool modify_key(iterator position,Modifier mod,Rollback back_) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: return modify( Chris@16: position, Chris@16: modify_key_adaptor(mod,key), Chris@101: modify_key_adaptor(back_,key)); Chris@16: } Chris@16: Chris@101: void clear()BOOST_NOEXCEPT Chris@16: { Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: this->final_clear_(); Chris@16: } Chris@16: Chris@16: void swap(hashed_index& x) Chris@16: { Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x); Chris@16: this->final_swap_(x.final()); Chris@16: } Chris@16: Chris@16: /* observers */ Chris@16: Chris@16: key_from_value key_extractor()const{return key;} Chris@16: hasher hash_function()const{return hash_;} Chris@16: key_equal key_eq()const{return eq_;} Chris@16: Chris@16: /* lookup */ Chris@16: Chris@16: /* Internally, these ops rely on const_iterator being the same Chris@16: * type as iterator. Chris@16: */ Chris@16: Chris@101: /* Implementation note: When CompatibleKey is consistently promoted to Chris@101: * KeyFromValue::result_type for equality comparison, the promotion is made Chris@101: * once in advance to increase efficiency. Chris@101: */ Chris@101: Chris@16: template Chris@16: iterator find(const CompatibleKey& k)const Chris@16: { Chris@16: return find(k,hash_,eq_); Chris@16: } Chris@16: Chris@16: template< Chris@16: typename CompatibleKey,typename CompatibleHash,typename CompatiblePred Chris@16: > Chris@16: iterator find( Chris@16: const CompatibleKey& k, Chris@16: const CompatibleHash& hash,const CompatiblePred& eq)const Chris@16: { Chris@101: return find( Chris@101: k,hash,eq,promotes_1st_arg()); Chris@16: } Chris@16: Chris@16: template Chris@16: size_type count(const CompatibleKey& k)const Chris@16: { Chris@16: return count(k,hash_,eq_); Chris@16: } Chris@16: Chris@16: template< Chris@16: typename CompatibleKey,typename CompatibleHash,typename CompatiblePred Chris@16: > Chris@16: size_type count( Chris@16: const CompatibleKey& k, Chris@16: const CompatibleHash& hash,const CompatiblePred& eq)const Chris@16: { Chris@101: return count( Chris@101: k,hash,eq,promotes_1st_arg()); Chris@16: } Chris@16: Chris@16: template Chris@16: std::pair equal_range(const CompatibleKey& k)const Chris@16: { Chris@16: return equal_range(k,hash_,eq_); Chris@16: } Chris@16: Chris@16: template< Chris@16: typename CompatibleKey,typename CompatibleHash,typename CompatiblePred Chris@16: > Chris@16: std::pair equal_range( Chris@16: const CompatibleKey& k, Chris@16: const CompatibleHash& hash,const CompatiblePred& eq)const Chris@16: { Chris@101: return equal_range( Chris@101: k,hash,eq,promotes_1st_arg()); Chris@16: } Chris@16: Chris@16: /* bucket interface */ Chris@16: Chris@101: size_type bucket_count()const BOOST_NOEXCEPT{return buckets.size();} Chris@101: size_type max_bucket_count()const BOOST_NOEXCEPT{return static_cast(-1);} Chris@16: Chris@16: size_type bucket_size(size_type n)const Chris@16: { Chris@101: size_type res=0; Chris@101: for(node_impl_pointer x=buckets.at(n)->prior(); Chris@101: x!=node_impl_pointer(0);x=node_alg::after_local(x)){ Chris@16: ++res; Chris@16: } Chris@16: return res; Chris@16: } Chris@16: Chris@16: size_type bucket(key_param_type k)const Chris@16: { Chris@16: return buckets.position(hash_(k)); Chris@16: } Chris@16: Chris@16: local_iterator begin(size_type n) Chris@16: { Chris@16: return const_cast(this)->begin(n); Chris@16: } Chris@16: Chris@16: const_local_iterator begin(size_type n)const Chris@16: { Chris@101: node_impl_pointer x=buckets.at(n)->prior(); Chris@101: if(x==node_impl_pointer(0))return end(n); Chris@101: return make_local_iterator(node_type::from_impl(x)); Chris@16: } Chris@16: Chris@16: local_iterator end(size_type n) Chris@16: { Chris@16: return const_cast(this)->end(n); Chris@16: } Chris@16: Chris@101: const_local_iterator end(size_type)const Chris@16: { Chris@101: return make_local_iterator(0); Chris@16: } Chris@16: Chris@16: const_local_iterator cbegin(size_type n)const{return begin(n);} Chris@16: const_local_iterator cend(size_type n)const{return end(n);} Chris@16: Chris@16: local_iterator local_iterator_to(const value_type& x) Chris@16: { Chris@101: return make_local_iterator(node_from_value(&x)); Chris@16: } Chris@16: Chris@16: const_local_iterator local_iterator_to(const value_type& x)const Chris@16: { Chris@101: return make_local_iterator(node_from_value(&x)); Chris@16: } Chris@16: Chris@16: /* hash policy */ Chris@16: Chris@101: float load_factor()const BOOST_NOEXCEPT Chris@101: {return static_cast(size())/bucket_count();} Chris@101: float max_load_factor()const BOOST_NOEXCEPT{return mlf;} Chris@16: void max_load_factor(float z){mlf=z;calculate_max_load();} Chris@16: Chris@16: void rehash(size_type n) Chris@16: { Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@101: if(size()<=max_load&&n<=bucket_count())return; Chris@16: Chris@16: size_type bc =(std::numeric_limits::max)(); Chris@16: float fbc=static_cast(1+size()/mlf); Chris@16: if(bc>fbc){ Chris@16: bc=static_cast(fbc); Chris@16: if(bc(std::ceil(static_cast(n)/mlf))); Chris@101: } Chris@101: Chris@16: BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS: Chris@16: hashed_index(const ctor_args_list& args_list,const allocator_type& al): Chris@16: super(args_list.get_tail(),al), Chris@16: key(tuples::get<1>(args_list.get_head())), Chris@16: hash_(tuples::get<2>(args_list.get_head())), Chris@16: eq_(tuples::get<3>(args_list.get_head())), Chris@16: buckets(al,header()->impl(),tuples::get<0>(args_list.get_head())), Chris@101: mlf(1.0f) Chris@16: { Chris@16: calculate_max_load(); Chris@16: } Chris@16: Chris@16: hashed_index( Chris@16: const hashed_index& x): Chris@16: super(x), Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: safe_super(), Chris@16: #endif Chris@16: Chris@16: key(x.key), Chris@16: hash_(x.hash_), Chris@16: eq_(x.eq_), Chris@16: buckets(x.get_allocator(),header()->impl(),x.buckets.size()), Chris@16: mlf(x.mlf), Chris@101: max_load(x.max_load) Chris@16: { Chris@16: /* Copy ctor just takes the internal configuration objects from x. The rest Chris@16: * is done in subsequent call to copy_(). Chris@16: */ Chris@16: } Chris@16: Chris@16: hashed_index( Chris@16: const hashed_index& x, Chris@16: do_not_copy_elements_tag): Chris@16: super(x,do_not_copy_elements_tag()), Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: safe_super(), Chris@16: #endif Chris@16: Chris@16: key(x.key), Chris@16: hash_(x.hash_), Chris@16: eq_(x.eq_), Chris@16: buckets(x.get_allocator(),header()->impl(),0), Chris@101: mlf(1.0f) Chris@16: { Chris@16: calculate_max_load(); Chris@16: } Chris@16: Chris@16: ~hashed_index() Chris@16: { Chris@16: /* the container is guaranteed to be empty by now */ Chris@16: } Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: iterator make_iterator(node_type* node) Chris@16: { Chris@101: return iterator(node,this); Chris@16: } Chris@16: Chris@16: const_iterator make_iterator(node_type* node)const Chris@16: { Chris@101: return const_iterator(node,const_cast(this)); Chris@16: } Chris@16: #else Chris@16: iterator make_iterator(node_type* node) Chris@16: { Chris@101: return iterator(node); Chris@16: } Chris@16: Chris@16: const_iterator make_iterator(node_type* node)const Chris@16: { Chris@101: return const_iterator(node); Chris@16: } Chris@16: #endif Chris@16: Chris@101: local_iterator make_local_iterator(node_type* node) Chris@101: { Chris@101: return local_iterator(node); Chris@101: } Chris@101: Chris@101: const_local_iterator make_local_iterator(node_type* node)const Chris@101: { Chris@101: return const_local_iterator(node); Chris@101: } Chris@101: Chris@16: void copy_( Chris@16: const hashed_index& x, Chris@16: const copy_map_type& map) Chris@16: { Chris@101: copy_(x,map,Category()); Chris@101: } Chris@16: Chris@101: void copy_( Chris@101: const hashed_index& x, Chris@101: const copy_map_type& map,hashed_unique_tag) Chris@101: { Chris@101: if(x.size()!=0){ Chris@101: node_impl_pointer end_org=x.header()->impl(), Chris@101: org=end_org, Chris@101: cpy=header()->impl(); Chris@101: do{ Chris@101: node_impl_pointer prev_org=org->prior(), Chris@101: prev_cpy= Chris@101: static_cast(map.find(static_cast( Chris@101: node_type::from_impl(prev_org))))->impl(); Chris@101: cpy->prior()=prev_cpy; Chris@101: if(node_alg::is_first_of_bucket(org)){ Chris@101: node_impl_base_pointer buc_org=prev_org->next(), Chris@101: buc_cpy= Chris@101: buckets.begin()+(buc_org-x.buckets.begin()); Chris@101: prev_cpy->next()=buc_cpy; Chris@101: buc_cpy->prior()=cpy; Chris@101: } Chris@101: else{ Chris@101: prev_cpy->next()=node_impl_type::base_pointer_from(cpy); Chris@101: } Chris@101: org=prev_org; Chris@101: cpy=prev_cpy; Chris@101: }while(org!=end_org); Chris@16: } Chris@16: Chris@16: super::copy_(x,map); Chris@16: } Chris@16: Chris@101: void copy_( Chris@101: const hashed_index& x, Chris@101: const copy_map_type& map,hashed_non_unique_tag) Chris@101: { Chris@101: if(x.size()!=0){ Chris@101: node_impl_pointer end_org=x.header()->impl(), Chris@101: org=end_org, Chris@101: cpy=header()->impl(); Chris@101: do{ Chris@101: node_impl_pointer next_org=node_alg::after(org), Chris@101: next_cpy= Chris@101: static_cast(map.find(static_cast( Chris@101: node_type::from_impl(next_org))))->impl(); Chris@101: if(node_alg::is_first_of_bucket(next_org)){ Chris@101: node_impl_base_pointer buc_org=org->next(), Chris@101: buc_cpy= Chris@101: buckets.begin()+(buc_org-x.buckets.begin()); Chris@101: cpy->next()=buc_cpy; Chris@101: buc_cpy->prior()=next_cpy; Chris@101: next_cpy->prior()=cpy; Chris@101: } Chris@101: else{ Chris@101: if(org->next()==node_impl_type::base_pointer_from(next_org)){ Chris@101: cpy->next()=node_impl_type::base_pointer_from(next_cpy); Chris@101: } Chris@101: else{ Chris@101: cpy->next()= Chris@101: node_impl_type::base_pointer_from( Chris@101: static_cast(map.find(static_cast( Chris@101: node_type::from_impl( Chris@101: node_impl_type::pointer_from(org->next())))))->impl()); Chris@101: } Chris@101: Chris@101: if(next_org->prior()!=org){ Chris@101: next_cpy->prior()= Chris@101: static_cast(map.find(static_cast( Chris@101: node_type::from_impl(next_org->prior()))))->impl(); Chris@101: } Chris@101: else{ Chris@101: next_cpy->prior()=cpy; Chris@101: } Chris@101: } Chris@101: org=next_org; Chris@101: cpy=next_cpy; Chris@101: }while(org!=end_org); Chris@101: } Chris@101: Chris@101: super::copy_(x,map); Chris@101: } Chris@101: Chris@16: template Chris@101: final_node_type* insert_( Chris@101: value_param_type v,final_node_type*& x,Variant variant) Chris@16: { Chris@101: reserve_for_insert(size()+1); Chris@16: Chris@101: std::size_t buc=find_bucket(v); Chris@101: link_info pos(buckets.at(buc)); Chris@101: if(!link_point(v,pos)){ Chris@101: return static_cast( Chris@101: node_type::from_impl(node_impl_type::pointer_from(pos))); Chris@101: } Chris@16: Chris@101: final_node_type* res=super::insert_(v,x,variant); Chris@101: if(res==x)link(static_cast(x),pos); Chris@16: return res; Chris@16: } Chris@16: Chris@16: template Chris@101: final_node_type* insert_( Chris@101: value_param_type v,node_type* position,final_node_type*& x,Variant variant) Chris@16: { Chris@101: reserve_for_insert(size()+1); Chris@16: Chris@101: std::size_t buc=find_bucket(v); Chris@101: link_info pos(buckets.at(buc)); Chris@101: if(!link_point(v,pos)){ Chris@101: return static_cast( Chris@101: node_type::from_impl(node_impl_type::pointer_from(pos))); Chris@101: } Chris@16: Chris@101: final_node_type* res=super::insert_(v,position,x,variant); Chris@101: if(res==x)link(static_cast(x),pos); Chris@16: return res; Chris@16: } Chris@16: Chris@16: void erase_(node_type* x) Chris@16: { Chris@16: unlink(x); Chris@16: super::erase_(x); Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: detach_iterators(x); Chris@16: #endif Chris@16: } Chris@16: Chris@16: void delete_all_nodes_() Chris@16: { Chris@101: delete_all_nodes_(Category()); Chris@101: } Chris@101: Chris@101: void delete_all_nodes_(hashed_unique_tag) Chris@101: { Chris@101: for(node_impl_pointer x_end=header()->impl(),x=x_end->prior();x!=x_end;){ Chris@101: node_impl_pointer y=x->prior(); Chris@101: this->final_delete_node_( Chris@101: static_cast(node_type::from_impl(x))); Chris@101: x=y; Chris@101: } Chris@101: } Chris@101: Chris@101: void delete_all_nodes_(hashed_non_unique_tag) Chris@101: { Chris@101: for(node_impl_pointer x_end=header()->impl(),x=x_end->prior();x!=x_end;){ Chris@101: node_impl_pointer y=x->prior(); Chris@101: if(y->next()!=node_impl_type::base_pointer_from(x)&& Chris@101: y->next()->prior()!=x){ /* n-1 of group */ Chris@101: /* Make the second node prior() pointer back-linked so that it won't Chris@101: * refer to a deleted node when the time for its own destruction comes. Chris@101: */ Chris@101: Chris@101: node_impl_pointer first=node_impl_type::pointer_from(y->next()); Chris@101: first->next()->prior()=first; Chris@16: } Chris@101: this->final_delete_node_( Chris@101: static_cast(node_type::from_impl(x))); Chris@101: x=y; Chris@16: } Chris@16: } Chris@16: Chris@16: void clear_() Chris@16: { Chris@16: super::clear_(); Chris@101: buckets.clear(header()->impl()); Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: safe_super::detach_dereferenceable_iterators(); Chris@16: #endif Chris@16: } Chris@16: Chris@16: void swap_( Chris@16: hashed_index& x) Chris@16: { Chris@16: std::swap(key,x.key); Chris@16: std::swap(hash_,x.hash_); Chris@16: std::swap(eq_,x.eq_); Chris@16: buckets.swap(x.buckets); Chris@16: std::swap(mlf,x.mlf); Chris@16: std::swap(max_load,x.max_load); Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: safe_super::swap(x); Chris@16: #endif Chris@16: Chris@16: super::swap_(x); Chris@16: } Chris@16: Chris@16: void swap_elements_( Chris@16: hashed_index& x) Chris@16: { Chris@16: buckets.swap(x.buckets); Chris@16: std::swap(mlf,x.mlf); Chris@16: std::swap(max_load,x.max_load); Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: safe_super::swap(x); Chris@16: #endif Chris@16: Chris@16: super::swap_elements_(x); Chris@16: } Chris@16: Chris@16: template Chris@16: bool replace_(value_param_type v,node_type* x,Variant variant) Chris@16: { Chris@16: if(eq_(key(v),key(x->value()))){ Chris@16: return super::replace_(v,x,variant); Chris@16: } Chris@101: Chris@101: unlink_undo undo; Chris@101: unlink(x,undo); Chris@16: Chris@16: BOOST_TRY{ Chris@101: std::size_t buc=find_bucket(v); Chris@101: link_info pos(buckets.at(buc)); Chris@101: if(link_point(v,pos)&&super::replace_(v,x,variant)){ Chris@16: link(x,pos); Chris@16: return true; Chris@16: } Chris@101: undo(); Chris@16: return false; Chris@16: } Chris@16: BOOST_CATCH(...){ Chris@101: undo(); Chris@16: BOOST_RETHROW; Chris@16: } Chris@16: BOOST_CATCH_END Chris@16: } Chris@16: Chris@16: bool modify_(node_type* x) Chris@16: { Chris@16: std::size_t buc; Chris@16: bool b; Chris@16: BOOST_TRY{ Chris@16: buc=find_bucket(x->value()); Chris@101: b=in_place(x->impl(),key(x->value()),buc); Chris@16: } Chris@16: BOOST_CATCH(...){ Chris@16: erase_(x); Chris@16: BOOST_RETHROW; Chris@16: } Chris@16: BOOST_CATCH_END Chris@16: if(!b){ Chris@16: unlink(x); Chris@16: BOOST_TRY{ Chris@101: link_info pos(buckets.at(buc)); Chris@101: if(!link_point(x->value(),pos)){ Chris@16: super::erase_(x); Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: detach_iterators(x); Chris@16: #endif Chris@16: return false; Chris@16: } Chris@16: link(x,pos); Chris@16: } Chris@16: BOOST_CATCH(...){ Chris@16: super::erase_(x); Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: detach_iterators(x); Chris@16: #endif Chris@16: Chris@16: BOOST_RETHROW; Chris@16: } Chris@16: BOOST_CATCH_END Chris@16: } Chris@16: Chris@16: BOOST_TRY{ Chris@16: if(!super::modify_(x)){ Chris@16: unlink(x); Chris@101: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: detach_iterators(x); Chris@16: #endif Chris@16: return false; Chris@16: } Chris@16: else return true; Chris@16: } Chris@16: BOOST_CATCH(...){ Chris@16: unlink(x); Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: detach_iterators(x); Chris@16: #endif Chris@16: Chris@16: BOOST_RETHROW; Chris@16: } Chris@16: BOOST_CATCH_END Chris@16: } Chris@16: Chris@16: bool modify_rollback_(node_type* x) Chris@16: { Chris@16: std::size_t buc=find_bucket(x->value()); Chris@101: if(in_place(x->impl(),key(x->value()),buc)){ Chris@16: return super::modify_rollback_(x); Chris@16: } Chris@16: Chris@101: unlink_undo undo; Chris@101: unlink(x,undo); Chris@16: Chris@16: BOOST_TRY{ Chris@101: link_info pos(buckets.at(buc)); Chris@101: if(link_point(x->value(),pos)&&super::modify_rollback_(x)){ Chris@16: link(x,pos); Chris@16: return true; Chris@16: } Chris@101: undo(); Chris@16: return false; Chris@16: } Chris@16: BOOST_CATCH(...){ Chris@101: undo(); Chris@16: BOOST_RETHROW; Chris@16: } Chris@16: BOOST_CATCH_END Chris@16: } Chris@16: Chris@101: /* comparison */ Chris@101: Chris@101: #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) Chris@101: /* defect macro refers to class, not function, templates, but anyway */ Chris@101: Chris@101: template Chris@101: friend bool operator==( Chris@101: const hashed_index&,const hashed_index& y); Chris@101: #endif Chris@101: Chris@101: bool equals(const hashed_index& x)const{return equals(x,Category());} Chris@101: Chris@101: bool equals(const hashed_index& x,hashed_unique_tag)const Chris@101: { Chris@101: if(size()!=x.size())return false; Chris@101: for(const_iterator it=begin(),it_end=end(),it2_end=x.end(); Chris@101: it!=it_end;++it){ Chris@101: const_iterator it2=x.find(key(*it)); Chris@101: if(it2==it2_end||!(*it==*it2))return false; Chris@101: } Chris@101: return true; Chris@101: } Chris@101: Chris@101: bool equals(const hashed_index& x,hashed_non_unique_tag)const Chris@101: { Chris@101: if(size()!=x.size())return false; Chris@101: for(const_iterator it=begin(),it_end=end();it!=it_end;){ Chris@101: const_iterator it2,it2_last; Chris@101: boost::tie(it2,it2_last)=x.equal_range(key(*it)); Chris@101: if(it2==it2_last)return false; Chris@101: Chris@101: const_iterator it_last=make_iterator( Chris@101: node_type::from_impl(end_of_range(it.get_node()->impl()))); Chris@101: if(std::distance(it,it_last)!=std::distance(it2,it2_last))return false; Chris@101: Chris@101: /* From is_permutation code in Chris@101: * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3068.pdf Chris@101: */ Chris@101: Chris@101: for(;it!=it_last;++it,++it2){ Chris@101: if(!(*it==*it2))break; Chris@101: } Chris@101: if(it!=it_last){ Chris@101: for(const_iterator scan=it;scan!=it_last;++scan){ Chris@101: if(std::find(it,scan,*scan)!=scan)continue; Chris@101: std::ptrdiff_t matches=std::count(it2,it2_last,*scan); Chris@101: if(matches==0||matches!=std::count(scan,it_last,*scan))return false; Chris@101: } Chris@101: it=it_last; Chris@101: } Chris@101: } Chris@101: return true; Chris@101: } Chris@101: Chris@16: #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION) Chris@16: /* serialization */ Chris@16: Chris@16: template Chris@16: void save_( Chris@16: Archive& ar,const unsigned int version,const index_saver_type& sm)const Chris@16: { Chris@16: ar< Chris@16: void load_(Archive& ar,const unsigned int version,const index_loader_type& lm) Chris@16: { Chris@16: ar>>serialization::make_nvp("position",buckets); Chris@16: super::load_(ar,version,lm); Chris@16: } Chris@16: #endif Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING) Chris@16: /* invariant stuff */ Chris@16: Chris@16: bool invariant_()const Chris@16: { Chris@16: if(size()==0||begin()==end()){ Chris@16: if(size()!=0||begin()!=end())return false; Chris@16: } Chris@16: else{ Chris@16: size_type s0=0; Chris@16: for(const_iterator it=begin(),it_end=end();it!=it_end;++it,++s0){} Chris@16: if(s0!=size())return false; Chris@16: Chris@16: size_type s1=0; Chris@16: for(size_type buc=0;bucfinal_check_invariant_();} Chris@16: #endif Chris@16: Chris@16: private: Chris@16: node_type* header()const{return this->final_header();} Chris@16: Chris@16: std::size_t find_bucket(value_param_type v)const Chris@16: { Chris@16: return bucket(key(v)); Chris@16: } Chris@16: Chris@101: struct link_info_non_unique Chris@101: { Chris@101: link_info_non_unique(node_impl_base_pointer pos): Chris@101: first(pos),last(node_impl_base_pointer(0)){} Chris@101: Chris@101: operator const node_impl_base_pointer&()const{return this->first;} Chris@101: Chris@101: node_impl_base_pointer first,last; Chris@101: }; Chris@101: Chris@101: typedef typename mpl::if_< Chris@101: is_same, Chris@101: node_impl_base_pointer, Chris@101: link_info_non_unique Chris@101: >::type link_info; Chris@101: Chris@101: bool link_point(value_param_type v,link_info& pos) Chris@101: { Chris@101: return link_point(v,pos,Category()); Chris@101: } Chris@101: Chris@16: bool link_point( Chris@101: value_param_type v,node_impl_base_pointer& pos,hashed_unique_tag) Chris@16: { Chris@101: for(node_impl_pointer x=pos->prior();x!=node_impl_pointer(0); Chris@101: x=node_alg::after_local(x)){ Chris@16: if(eq_(key(v),key(node_type::from_impl(x)->value()))){ Chris@101: pos=node_impl_type::base_pointer_from(x); Chris@16: return false; Chris@16: } Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: bool link_point( Chris@101: value_param_type v,link_info_non_unique& pos,hashed_non_unique_tag) Chris@16: { Chris@101: for(node_impl_pointer x=pos.first->prior();x!=node_impl_pointer(0); Chris@101: x=node_alg::next_to_inspect(x)){ Chris@16: if(eq_(key(v),key(node_type::from_impl(x)->value()))){ Chris@101: pos.first=node_impl_type::base_pointer_from(x); Chris@101: pos.last=node_impl_type::base_pointer_from(last_of_range(x)); Chris@16: return true; Chris@16: } Chris@16: } Chris@16: return true; Chris@16: } Chris@101: Chris@101: node_impl_pointer last_of_range(node_impl_pointer x)const Chris@16: { Chris@101: return last_of_range(x,Category()); Chris@16: } Chris@16: Chris@101: node_impl_pointer last_of_range(node_impl_pointer x,hashed_unique_tag)const Chris@16: { Chris@101: return x; Chris@16: } Chris@16: Chris@101: node_impl_pointer last_of_range( Chris@101: node_impl_pointer x,hashed_non_unique_tag)const Chris@16: { Chris@101: node_impl_base_pointer y=x->next(); Chris@101: node_impl_pointer z=y->prior(); Chris@101: if(z==x){ /* range of size 1 or 2 */ Chris@101: node_impl_pointer yy=node_impl_type::pointer_from(y); Chris@101: return Chris@101: eq_( Chris@101: key(node_type::from_impl(x)->value()), Chris@101: key(node_type::from_impl(yy)->value()))?yy:x; Chris@101: } Chris@101: else if(z->prior()==x) /* last of bucket */ Chris@101: return x; Chris@101: else /* group of size>2 */ Chris@101: return z; Chris@101: } Chris@101: Chris@101: node_impl_pointer end_of_range(node_impl_pointer x)const Chris@101: { Chris@101: return end_of_range(x,Category()); Chris@101: } Chris@101: Chris@101: node_impl_pointer end_of_range(node_impl_pointer x,hashed_unique_tag)const Chris@101: { Chris@101: return node_alg::after(last_of_range(x)); Chris@101: } Chris@101: Chris@101: node_impl_pointer end_of_range( Chris@101: node_impl_pointer x,hashed_non_unique_tag)const Chris@101: { Chris@101: node_impl_base_pointer y=x->next(); Chris@101: node_impl_pointer z=y->prior(); Chris@101: if(z==x){ /* range of size 1 or 2 */ Chris@101: node_impl_pointer yy=node_impl_type::pointer_from(y); Chris@101: if(!eq_( Chris@101: key(node_type::from_impl(x)->value()), Chris@101: key(node_type::from_impl(yy)->value())))yy=x; Chris@101: return yy->next()->prior()==yy? Chris@101: node_impl_type::pointer_from(yy->next()): Chris@101: yy->next()->prior(); Chris@101: } Chris@101: else if(z->prior()==x) /* last of bucket */ Chris@101: return z; Chris@101: else /* group of size>2 */ Chris@101: return z->next()->prior()==z? Chris@101: node_impl_type::pointer_from(z->next()): Chris@101: z->next()->prior(); Chris@101: } Chris@101: Chris@101: void link(node_type* x,const link_info& pos) Chris@101: { Chris@101: link(x,pos,Category()); Chris@101: } Chris@101: Chris@101: void link(node_type* x,node_impl_base_pointer pos,hashed_unique_tag) Chris@101: { Chris@101: node_alg::link(x->impl(),pos,header()->impl()); Chris@101: } Chris@101: Chris@101: void link(node_type* x,const link_info_non_unique& pos,hashed_non_unique_tag) Chris@101: { Chris@101: if(pos.last==node_impl_base_pointer(0)){ Chris@101: node_alg::link(x->impl(),pos.first,header()->impl()); Chris@101: } Chris@101: else{ Chris@101: node_alg::link( Chris@101: x->impl(), Chris@101: node_impl_type::pointer_from(pos.first), Chris@101: node_impl_type::pointer_from(pos.last)); Chris@101: } Chris@101: } Chris@101: Chris@101: void unlink(node_type* x) Chris@101: { Chris@101: node_alg::unlink(x->impl()); Chris@101: } Chris@101: Chris@101: typedef typename node_alg::unlink_undo unlink_undo; Chris@101: Chris@101: void unlink(node_type* x,unlink_undo& undo) Chris@101: { Chris@101: node_alg::unlink(x->impl(),undo); Chris@16: } Chris@16: Chris@16: void calculate_max_load() Chris@16: { Chris@101: float fml=static_cast(mlf*static_cast(bucket_count())); Chris@16: max_load=(std::numeric_limits::max)(); Chris@16: if(max_load>fml)max_load=static_cast(fml); Chris@16: } Chris@16: Chris@101: void reserve_for_insert(size_type n) Chris@16: { Chris@16: if(n>max_load){ Chris@16: size_type bc =(std::numeric_limits::max)(); Chris@16: float fbc=static_cast(1+static_cast(n)/mlf); Chris@16: if(bc>fbc)bc =static_cast(fbc); Chris@16: unchecked_rehash(bc); Chris@16: } Chris@16: } Chris@16: Chris@101: void unchecked_rehash(size_type n){unchecked_rehash(n,Category());} Chris@101: Chris@101: void unchecked_rehash(size_type n,hashed_unique_tag) Chris@16: { Chris@101: node_impl_type cpy_end_node; Chris@101: node_impl_pointer cpy_end=node_impl_pointer(&cpy_end_node), Chris@101: end_=header()->impl(); Chris@101: bucket_array_type buckets_cpy(get_allocator(),cpy_end,n); Chris@16: Chris@101: if(size()!=0){ Chris@101: auto_space< Chris@101: std::size_t,allocator_type> hashes(get_allocator(),size()); Chris@101: auto_space< Chris@101: node_impl_pointer,allocator_type> node_ptrs(get_allocator(),size()); Chris@101: std::size_t i=0,size_=size(); Chris@101: bool within_bucket=false; Chris@101: BOOST_TRY{ Chris@101: for(;i!=size_;++i){ Chris@101: node_impl_pointer x=end_->prior(); Chris@101: Chris@101: /* only this can possibly throw */ Chris@101: std::size_t h=hash_(key(node_type::from_impl(x)->value())); Chris@101: Chris@101: hashes.data()[i]=h; Chris@101: node_ptrs.data()[i]=x; Chris@101: within_bucket=!node_alg::unlink_last(end_); Chris@101: node_alg::link(x,buckets_cpy.at(buckets_cpy.position(h)),cpy_end); Chris@101: } Chris@16: } Chris@101: BOOST_CATCH(...){ Chris@101: if(i!=0){ Chris@101: std::size_t prev_buc=buckets.position(hashes.data()[i-1]); Chris@101: if(!within_bucket)prev_buc=~prev_buc; Chris@101: Chris@101: for(std::size_t j=i;j--;){ Chris@101: std::size_t buc=buckets.position(hashes.data()[j]); Chris@101: node_impl_pointer x=node_ptrs.data()[j]; Chris@101: if(buc==prev_buc)node_alg::append(x,end_); Chris@101: else node_alg::link(x,buckets.at(buc),end_); Chris@101: prev_buc=buc; Chris@101: } Chris@101: } Chris@101: BOOST_RETHROW; Chris@101: } Chris@101: BOOST_CATCH_END Chris@16: } Chris@16: Chris@101: end_->prior()=cpy_end->prior()!=cpy_end?cpy_end->prior():end_; Chris@101: end_->next()=cpy_end->next(); Chris@101: end_->prior()->next()->prior()=end_->next()->prior()->prior()=end_; Chris@101: buckets.swap(buckets_cpy); Chris@101: calculate_max_load(); Chris@101: } Chris@101: Chris@101: void unchecked_rehash(size_type n,hashed_non_unique_tag) Chris@101: { Chris@101: node_impl_type cpy_end_node; Chris@101: node_impl_pointer cpy_end=node_impl_pointer(&cpy_end_node), Chris@101: end_=header()->impl(); Chris@101: bucket_array_type buckets_cpy(get_allocator(),cpy_end,n); Chris@101: Chris@101: if(size()!=0){ Chris@101: auto_space< Chris@101: std::size_t,allocator_type> hashes(get_allocator(),size()); Chris@101: auto_space< Chris@101: node_impl_pointer,allocator_type> node_ptrs(get_allocator(),size()); Chris@101: std::size_t i=0; Chris@101: bool within_bucket=false; Chris@101: BOOST_TRY{ Chris@101: for(;;++i){ Chris@101: node_impl_pointer x=end_->prior(); Chris@101: if(x==end_)break; Chris@101: Chris@101: /* only this can possibly throw */ Chris@101: std::size_t h=hash_(key(node_type::from_impl(x)->value())); Chris@101: Chris@101: hashes.data()[i]=h; Chris@101: node_ptrs.data()[i]=x; Chris@101: std::pair p= Chris@101: node_alg::unlink_last_group(end_); Chris@101: node_alg::link_range( Chris@101: p.first,x,buckets_cpy.at(buckets_cpy.position(h)),cpy_end); Chris@101: within_bucket=!(p.second); Chris@101: } Chris@16: } Chris@101: BOOST_CATCH(...){ Chris@101: if(i!=0){ Chris@101: std::size_t prev_buc=buckets.position(hashes.data()[i-1]); Chris@101: if(!within_bucket)prev_buc=~prev_buc; Chris@101: Chris@101: for(std::size_t j=i;j--;){ Chris@101: std::size_t buc=buckets.position(hashes.data()[j]); Chris@101: node_impl_pointer x=node_ptrs.data()[j], Chris@101: y= Chris@101: x->prior()->next()!=node_impl_type::base_pointer_from(x)&& Chris@101: x->prior()->next()->prior()!=x? Chris@101: node_impl_type::pointer_from(x->prior()->next()):x; Chris@101: node_alg::unlink_range(y,x); Chris@101: if(buc==prev_buc)node_alg::append_range(y,x,end_); Chris@101: else node_alg::link_range(y,x,buckets.at(buc),end_); Chris@101: prev_buc=buc; Chris@101: } Chris@101: } Chris@101: BOOST_RETHROW; Chris@101: } Chris@101: BOOST_CATCH_END Chris@16: } Chris@16: Chris@101: end_->prior()=cpy_end->prior()!=cpy_end?cpy_end->prior():end_; Chris@101: end_->next()=cpy_end->next(); Chris@101: end_->prior()->next()->prior()=end_->next()->prior()->prior()=end_; Chris@101: buckets.swap(buckets_cpy); Chris@16: calculate_max_load(); Chris@101: } Chris@101: Chris@101: bool in_place(node_impl_pointer x,key_param_type k,std::size_t buc)const Chris@101: { Chris@101: return in_place(x,k,buc,Category()); Chris@16: } Chris@16: Chris@16: bool in_place( Chris@16: node_impl_pointer x,key_param_type k,std::size_t buc, Chris@16: hashed_unique_tag)const Chris@16: { Chris@101: bool found=false; Chris@101: for(node_impl_pointer y=buckets.at(buc)->prior(); Chris@101: y!=node_impl_pointer(0);y=node_alg::after_local(y)){ Chris@101: if(y==x)found=true; Chris@101: else if(eq_(k,key(node_type::from_impl(y)->value())))return false; Chris@16: } Chris@101: return found; Chris@16: } Chris@16: Chris@16: bool in_place( Chris@16: node_impl_pointer x,key_param_type k,std::size_t buc, Chris@16: hashed_non_unique_tag)const Chris@16: { Chris@101: bool found=false; Chris@101: int range_size=0; Chris@101: for(node_impl_pointer y=buckets.at(buc)->prior();y!=node_impl_pointer(0);){ Chris@101: if(node_alg::is_first_of_group(y)){ /* group of 3 or more */ Chris@101: if(y==x){ Chris@101: /* in place <-> equal to some other member of the group */ Chris@101: return eq_( Chris@101: k, Chris@101: key(node_type::from_impl( Chris@101: node_impl_type::pointer_from(y->next()))->value())); Chris@101: } Chris@101: else{ Chris@101: node_impl_pointer z= Chris@101: node_alg::after_local(y->next()->prior()); /* end of range */ Chris@101: if(eq_(k,key(node_type::from_impl(y)->value()))){ Chris@101: if(found)return false; /* x lies outside */ Chris@101: do{ Chris@101: if(y==x)return true; Chris@101: y=node_alg::after_local(y); Chris@101: }while(y!=z); Chris@101: return false; /* x not found */ Chris@101: } Chris@101: else{ Chris@101: if(range_size==1&&!found)return false; Chris@101: if(range_size==2)return found; Chris@101: range_size=0; Chris@101: y=z; /* skip range (and potentially x, too, which is fine) */ Chris@101: } Chris@16: } Chris@16: } Chris@101: else{ /* group of 1 or 2 */ Chris@101: if(y==x){ Chris@101: if(range_size==1)return true; Chris@101: range_size=1; Chris@101: found=true; Chris@16: } Chris@101: else if(eq_(k,key(node_type::from_impl(y)->value()))){ Chris@101: if(range_size==0&&found)return false; Chris@101: if(range_size==1&&!found)return false; Chris@101: if(range_size==2)return false; Chris@101: ++range_size; Chris@101: } Chris@101: else{ Chris@101: if(range_size==1&&!found)return false; Chris@101: if(range_size==2)return found; Chris@101: range_size=0; Chris@101: } Chris@101: y=node_alg::after_local(y); Chris@16: } Chris@16: } Chris@101: return found; Chris@16: } Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE) Chris@16: void detach_iterators(node_type* x) Chris@16: { Chris@16: iterator it=make_iterator(x); Chris@16: safe_mode::detach_equivalent_iterators(it); Chris@16: } Chris@16: #endif Chris@16: Chris@16: template Chris@16: std::pair emplace_impl(BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK) Chris@16: { Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: std::pairp= Chris@16: this->final_emplace_(BOOST_MULTI_INDEX_FORWARD_PARAM_PACK); Chris@16: return std::pair(make_iterator(p.first),p.second); Chris@16: } Chris@16: Chris@16: template Chris@16: iterator emplace_hint_impl( Chris@16: iterator position,BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK) Chris@16: { Chris@16: BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position); Chris@16: BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this); Chris@16: BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT; Chris@16: std::pairp= Chris@16: this->final_emplace_hint_( Chris@16: static_cast(position.get_node()), Chris@16: BOOST_MULTI_INDEX_FORWARD_PARAM_PACK); Chris@16: return make_iterator(p.first); Chris@16: } Chris@16: Chris@101: template< Chris@101: typename CompatibleHash,typename CompatiblePred Chris@101: > Chris@101: iterator find( Chris@101: const key_type& k, Chris@101: const CompatibleHash& hash,const CompatiblePred& eq,mpl::true_)const Chris@101: { Chris@101: return find(k,hash,eq,mpl::false_()); Chris@101: } Chris@101: Chris@101: template< Chris@101: typename CompatibleKey,typename CompatibleHash,typename CompatiblePred Chris@101: > Chris@101: iterator find( Chris@101: const CompatibleKey& k, Chris@101: const CompatibleHash& hash,const CompatiblePred& eq,mpl::false_)const Chris@101: { Chris@101: std::size_t buc=buckets.position(hash(k)); Chris@101: for(node_impl_pointer x=buckets.at(buc)->prior(); Chris@101: x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){ Chris@101: if(eq(k,key(node_type::from_impl(x)->value()))){ Chris@101: return make_iterator(node_type::from_impl(x)); Chris@101: } Chris@101: } Chris@101: return end(); Chris@101: } Chris@101: Chris@101: template< Chris@101: typename CompatibleHash,typename CompatiblePred Chris@101: > Chris@101: size_type count( Chris@101: const key_type& k, Chris@101: const CompatibleHash& hash,const CompatiblePred& eq,mpl::true_)const Chris@101: { Chris@101: return count(k,hash,eq,mpl::false_()); Chris@101: } Chris@101: Chris@101: template< Chris@101: typename CompatibleKey,typename CompatibleHash,typename CompatiblePred Chris@101: > Chris@101: size_type count( Chris@101: const CompatibleKey& k, Chris@101: const CompatibleHash& hash,const CompatiblePred& eq,mpl::false_)const Chris@101: { Chris@101: std::size_t buc=buckets.position(hash(k)); Chris@101: for(node_impl_pointer x=buckets.at(buc)->prior(); Chris@101: x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){ Chris@101: if(eq(k,key(node_type::from_impl(x)->value()))){ Chris@101: size_type res=0; Chris@101: node_impl_pointer y=end_of_range(x); Chris@101: do{ Chris@101: ++res; Chris@101: x=node_alg::after(x); Chris@101: }while(x!=y); Chris@101: return res; Chris@101: } Chris@101: } Chris@101: return 0; Chris@101: } Chris@101: Chris@101: template< Chris@101: typename CompatibleHash,typename CompatiblePred Chris@101: > Chris@101: std::pair equal_range( Chris@101: const key_type& k, Chris@101: const CompatibleHash& hash,const CompatiblePred& eq,mpl::true_)const Chris@101: { Chris@101: return equal_range(k,hash,eq,mpl::false_()); Chris@101: } Chris@101: Chris@101: template< Chris@101: typename CompatibleKey,typename CompatibleHash,typename CompatiblePred Chris@101: > Chris@101: std::pair equal_range( Chris@101: const CompatibleKey& k, Chris@101: const CompatibleHash& hash,const CompatiblePred& eq,mpl::false_)const Chris@101: { Chris@101: std::size_t buc=buckets.position(hash(k)); Chris@101: for(node_impl_pointer x=buckets.at(buc)->prior(); Chris@101: x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){ Chris@101: if(eq(k,key(node_type::from_impl(x)->value()))){ Chris@101: return std::pair( Chris@101: make_iterator(node_type::from_impl(x)), Chris@101: make_iterator(node_type::from_impl(end_of_range(x)))); Chris@101: } Chris@101: } Chris@101: return std::pair(end(),end()); Chris@101: } Chris@101: Chris@16: key_from_value key; Chris@16: hasher hash_; Chris@16: key_equal eq_; Chris@16: bucket_array_type buckets; Chris@16: float mlf; Chris@16: size_type max_load; Chris@16: Chris@16: #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\ Chris@16: BOOST_WORKAROUND(__MWERKS__,<=0x3003) Chris@16: #pragma parse_mfunc_templ reset Chris@16: #endif Chris@16: }; Chris@16: Chris@101: /* comparison */ Chris@101: Chris@101: template< Chris@101: typename KeyFromValue,typename Hash,typename Pred, Chris@101: typename SuperMeta,typename TagList,typename Category Chris@101: > Chris@101: bool operator==( Chris@101: const hashed_index& x, Chris@101: const hashed_index& y) Chris@101: { Chris@101: return x.equals(y); Chris@101: } Chris@101: Chris@101: template< Chris@101: typename KeyFromValue,typename Hash,typename Pred, Chris@101: typename SuperMeta,typename TagList,typename Category Chris@101: > Chris@101: bool operator!=( Chris@101: const hashed_index& x, Chris@101: const hashed_index& y) Chris@101: { Chris@101: return !(x==y); Chris@101: } Chris@101: Chris@16: /* specialized algorithms */ Chris@16: Chris@16: template< Chris@16: typename KeyFromValue,typename Hash,typename Pred, Chris@16: typename SuperMeta,typename TagList,typename Category Chris@16: > Chris@16: void swap( Chris@16: hashed_index& x, Chris@16: hashed_index& y) Chris@16: { Chris@16: x.swap(y); Chris@16: } Chris@16: Chris@16: } /* namespace multi_index::detail */ Chris@16: Chris@16: /* hashed index specifiers */ Chris@16: Chris@16: template Chris@16: struct hashed_unique Chris@16: { Chris@16: typedef typename detail::hashed_index_args< Chris@16: Arg1,Arg2,Arg3,Arg4> index_args; Chris@16: typedef typename index_args::tag_list_type::type tag_list_type; Chris@16: typedef typename index_args::key_from_value_type key_from_value_type; Chris@16: typedef typename index_args::hash_type hash_type; Chris@16: typedef typename index_args::pred_type pred_type; Chris@16: Chris@16: template Chris@16: struct node_class Chris@16: { Chris@101: typedef detail::hashed_index_node type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct index_class Chris@16: { Chris@16: typedef detail::hashed_index< Chris@16: key_from_value_type,hash_type,pred_type, Chris@16: SuperMeta,tag_list_type,detail::hashed_unique_tag> type; Chris@16: }; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct hashed_non_unique Chris@16: { Chris@16: typedef typename detail::hashed_index_args< Chris@16: Arg1,Arg2,Arg3,Arg4> index_args; Chris@16: typedef typename index_args::tag_list_type::type tag_list_type; Chris@16: typedef typename index_args::key_from_value_type key_from_value_type; Chris@16: typedef typename index_args::hash_type hash_type; Chris@16: typedef typename index_args::pred_type pred_type; Chris@16: Chris@16: template Chris@16: struct node_class Chris@16: { Chris@101: typedef detail::hashed_index_node< Chris@101: Super,detail::hashed_non_unique_tag> type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct index_class Chris@16: { Chris@16: typedef detail::hashed_index< Chris@16: key_from_value_type,hash_type,pred_type, Chris@16: SuperMeta,tag_list_type,detail::hashed_non_unique_tag> type; Chris@16: }; Chris@16: }; Chris@16: Chris@16: } /* namespace multi_index */ Chris@16: Chris@16: } /* namespace boost */ Chris@16: Chris@16: /* Boost.Foreach compatibility */ Chris@16: Chris@16: template< Chris@16: typename KeyFromValue,typename Hash,typename Pred, Chris@16: typename SuperMeta,typename TagList,typename Category Chris@16: > Chris@16: inline boost::mpl::true_* boost_foreach_is_noncopyable( Chris@16: boost::multi_index::detail::hashed_index< Chris@16: KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>*&, Chris@16: boost::foreach::tag) Chris@16: { Chris@16: return 0; Chris@16: } Chris@16: Chris@16: #undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT Chris@16: #undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF Chris@16: Chris@16: #endif