1 /* Copyright 2003-2021 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
6 * See http://www.boost.org/libs/multi_index for library home page.
9 #ifndef BOOST_MULTI_INDEX_HASHED_INDEX_HPP
10 #define BOOST_MULTI_INDEX_HASHED_INDEX_HPP
16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
18 #include <boost/call_traits.hpp>
19 #include <boost/core/addressof.hpp>
20 #include <boost/core/no_exceptions_support.hpp>
21 #include <boost/detail/workaround.hpp>
22 #include <boost/foreach_fwd.hpp>
23 #include <boost/limits.hpp>
24 #include <boost/move/core.hpp>
25 #include <boost/move/utility_core.hpp>
26 #include <boost/mpl/bool.hpp>
27 #include <boost/mpl/if.hpp>
28 #include <boost/mpl/push_front.hpp>
29 #include <boost/multi_index/detail/access_specifier.hpp>
30 #include <boost/multi_index/detail/adl_swap.hpp>
31 #include <boost/multi_index/detail/allocator_traits.hpp>
32 #include <boost/multi_index/detail/auto_space.hpp>
33 #include <boost/multi_index/detail/bucket_array.hpp>
34 #include <boost/multi_index/detail/do_not_copy_elements_tag.hpp>
35 #include <boost/multi_index/detail/hash_index_iterator.hpp>
36 #include <boost/multi_index/detail/index_node_base.hpp>
37 #include <boost/multi_index/detail/invalidate_iterators.hpp>
38 #include <boost/multi_index/detail/modify_key_adaptor.hpp>
39 #include <boost/multi_index/detail/node_handle.hpp>
40 #include <boost/multi_index/detail/promotes_arg.hpp>
41 #include <boost/multi_index/detail/safe_mode.hpp>
42 #include <boost/multi_index/detail/scope_guard.hpp>
43 #include <boost/multi_index/detail/vartempl_support.hpp>
44 #include <boost/multi_index/hashed_index_fwd.hpp>
45 #include <boost/tuple/tuple.hpp>
46 #include <boost/type_traits/is_same.hpp>
53 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
54 #include <initializer_list>
57 #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
58 #include <boost/serialization/nvp.hpp>
61 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
62 #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x) \
63 detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)= \
64 detail::make_obj_guard(x,&hashed_index::check_invariant_); \
65 BOOST_JOIN(check_invariant_,__LINE__).touch();
66 #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT \
67 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(*this)
69 #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x)
70 #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
75 namespace multi_index{
79 /* hashed_index adds a layer of hashed indexing to a given Super */
81 /* Most of the implementation of unique and non-unique indices is
82 * shared. We tell from one another on instantiation time by using
83 * Category tags defined in hash_index_node.hpp.
86 #if defined(BOOST_MSVC)
88 #pragma warning(disable:4355) /* this used in base member initializer list */
92 typename KeyFromValue,typename Hash,typename Pred,
93 typename SuperMeta,typename TagList,typename Category
96 BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS SuperMeta::type
98 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
99 BOOST_WORKAROUND(__MWERKS__,<=0x3003)
100 /* The "ISO C++ Template Parser" option in CW8.3 has a problem with the
101 * lifetime of const references bound to temporaries --precisely what
105 #pragma parse_mfunc_templ off
108 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
109 /* cross-index access */
111 template <typename,typename,typename> friend class index_base;
114 typedef typename SuperMeta::type super;
117 typedef hashed_index_node<
118 typename super::index_node_type> index_node_type;
121 typedef typename index_node_type::
122 template node_alg<Category>::type node_alg;
123 typedef typename index_node_type::impl_type node_impl_type;
124 typedef typename node_impl_type::pointer node_impl_pointer;
125 typedef typename node_impl_type::base_pointer node_impl_base_pointer;
126 typedef bucket_array<
127 typename super::final_allocator_type> bucket_array_type;
132 typedef typename KeyFromValue::result_type key_type;
133 typedef typename index_node_type::value_type value_type;
134 typedef KeyFromValue key_from_value;
136 typedef Pred key_equal;
137 typedef typename super::final_allocator_type allocator_type;
140 typedef allocator_traits<allocator_type> alloc_traits;
143 typedef typename alloc_traits::pointer pointer;
144 typedef typename alloc_traits::const_pointer const_pointer;
145 typedef value_type& reference;
146 typedef const value_type& const_reference;
147 typedef typename alloc_traits::size_type size_type;
148 typedef typename alloc_traits::difference_type difference_type;
149 typedef tuple<size_type,
150 key_from_value,hasher,key_equal> ctor_args;
152 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
153 typedef safe_mode::safe_iterator<
154 hashed_index_iterator<
155 index_node_type,bucket_array_type,
157 hashed_index_global_iterator_tag> > iterator;
159 typedef hashed_index_iterator<
160 index_node_type,bucket_array_type,
161 Category,hashed_index_global_iterator_tag> iterator;
164 typedef iterator const_iterator;
166 typedef hashed_index_iterator<
167 index_node_type,bucket_array_type,
168 Category,hashed_index_local_iterator_tag> local_iterator;
169 typedef local_iterator const_local_iterator;
171 typedef typename super::final_node_handle_type node_type;
172 typedef detail::insert_return_type<
173 iterator,node_type> insert_return_type;
174 typedef TagList tag_list;
177 typedef typename super::final_node_type final_node_type;
178 typedef tuples::cons<
180 typename super::ctor_args_list> ctor_args_list;
181 typedef typename mpl::push_front<
182 typename super::index_type_list,
183 hashed_index>::type index_type_list;
184 typedef typename mpl::push_front<
185 typename super::iterator_type_list,
186 iterator>::type iterator_type_list;
187 typedef typename mpl::push_front<
188 typename super::const_iterator_type_list,
189 const_iterator>::type const_iterator_type_list;
190 typedef typename super::copy_map_type copy_map_type;
192 #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
193 typedef typename super::index_saver_type index_saver_type;
194 typedef typename super::index_loader_type index_loader_type;
198 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
199 typedef safe_mode::safe_container<iterator> safe_container;
202 typedef typename call_traits<value_type>::param_type value_param_type;
203 typedef typename call_traits<
204 key_type>::param_type key_param_type;
206 /* needed to avoid commas in some macros */
208 typedef std::pair<iterator,bool> pair_return_type;
212 /* construct/destroy/copy
213 * Default and copy ctors are in the protected section as indices are
214 * not supposed to be created on their own. No range ctor either.
217 hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& operator=(
218 const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
220 this->final()=x.final();
224 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
225 hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& operator=(
226 std::initializer_list<value_type> list)
233 allocator_type get_allocator()const BOOST_NOEXCEPT
235 return this->final().get_allocator();
238 /* size and capacity */
240 bool empty()const BOOST_NOEXCEPT{return this->final_empty_();}
241 size_type size()const BOOST_NOEXCEPT{return this->final_size_();}
242 size_type max_size()const BOOST_NOEXCEPT{return this->final_max_size_();}
246 iterator begin()BOOST_NOEXCEPT
248 return make_iterator(
249 index_node_type::from_impl(header()->next()->prior()));
252 const_iterator begin()const BOOST_NOEXCEPT
254 return make_iterator(
255 index_node_type::from_impl(header()->next()->prior()));
258 iterator end()BOOST_NOEXCEPT{return make_iterator(header());}
259 const_iterator end()const BOOST_NOEXCEPT{return make_iterator(header());}
260 const_iterator cbegin()const BOOST_NOEXCEPT{return begin();}
261 const_iterator cend()const BOOST_NOEXCEPT{return end();}
263 iterator iterator_to(const value_type& x)
265 return make_iterator(
266 node_from_value<index_node_type>(boost::addressof(x)));
269 const_iterator iterator_to(const value_type& x)const
271 return make_iterator(
272 node_from_value<index_node_type>(boost::addressof(x)));
277 BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
278 pair_return_type,emplace,emplace_impl)
280 BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
281 iterator,emplace_hint,emplace_hint_impl,iterator,position)
283 std::pair<iterator,bool> insert(const value_type& x)
285 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
286 std::pair<final_node_type*,bool> p=this->final_insert_(x);
287 return std::pair<iterator,bool>(make_iterator(p.first),p.second);
290 std::pair<iterator,bool> insert(BOOST_RV_REF(value_type) x)
292 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
293 std::pair<final_node_type*,bool> p=this->final_insert_rv_(x);
294 return std::pair<iterator,bool>(make_iterator(p.first),p.second);
297 iterator insert(iterator position,const value_type& x)
299 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
300 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
301 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
302 std::pair<final_node_type*,bool> p=this->final_insert_(
303 x,static_cast<final_node_type*>(position.get_node()));
304 return make_iterator(p.first);
307 iterator insert(iterator position,BOOST_RV_REF(value_type) x)
309 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
310 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
311 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
312 std::pair<final_node_type*,bool> p=this->final_insert_rv_(
313 x,static_cast<final_node_type*>(position.get_node()));
314 return make_iterator(p.first);
317 template<typename InputIterator>
318 void insert(InputIterator first,InputIterator last)
320 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
321 for(;first!=last;++first)this->final_insert_ref_(*first);
324 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
325 void insert(std::initializer_list<value_type> list)
327 insert(list.begin(),list.end());
331 insert_return_type insert(BOOST_RV_REF(node_type) nh)
333 if(nh)BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,nh);
334 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
335 std::pair<final_node_type*,bool> p=this->final_insert_nh_(nh);
336 return insert_return_type(make_iterator(p.first),p.second,boost::move(nh));
339 iterator insert(const_iterator position,BOOST_RV_REF(node_type) nh)
341 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
342 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
343 if(nh)BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,nh);
344 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
345 std::pair<final_node_type*,bool> p=this->final_insert_nh_(
346 nh,static_cast<final_node_type*>(position.get_node()));
347 return make_iterator(p.first);
350 node_type extract(const_iterator position)
352 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
353 BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
354 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
355 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
356 return this->final_extract_(
357 static_cast<final_node_type*>(position.get_node()));
360 node_type extract(key_param_type x)
362 iterator position=find(x);
363 if(position==end())return node_type();
364 else return extract(position);
367 iterator erase(iterator position)
369 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
370 BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
371 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
372 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
373 this->final_erase_(static_cast<final_node_type*>(position++.get_node()));
377 size_type erase(key_param_type k)
379 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
381 std::size_t buc=buckets.position(hash_(k));
382 for(node_impl_pointer x=buckets.at(buc)->prior();
383 x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
384 if(eq_(k,key(index_node_type::from_impl(x)->value()))){
385 node_impl_pointer y=end_of_range(x);
388 node_impl_pointer z=node_alg::after(x);
390 static_cast<final_node_type*>(index_node_type::from_impl(x)));
400 iterator erase(iterator first,iterator last)
402 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
403 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
404 BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,*this);
405 BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,*this);
406 BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
407 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
414 bool replace(iterator position,const value_type& x)
416 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
417 BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
418 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
419 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
420 return this->final_replace_(
421 x,static_cast<final_node_type*>(position.get_node()));
424 bool replace(iterator position,BOOST_RV_REF(value_type) x)
426 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
427 BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
428 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
429 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
430 return this->final_replace_rv_(
431 x,static_cast<final_node_type*>(position.get_node()));
434 template<typename Modifier>
435 bool modify(iterator position,Modifier mod)
437 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
438 BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
439 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
440 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
442 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
443 /* MSVC++ 6.0 optimizer on safe mode code chokes if this
444 * this is not added. Left it for all compilers as it does no
451 return this->final_modify_(
452 mod,static_cast<final_node_type*>(position.get_node()));
455 template<typename Modifier,typename Rollback>
456 bool modify(iterator position,Modifier mod,Rollback back_)
458 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
459 BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
460 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
461 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
463 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
464 /* MSVC++ 6.0 optimizer on safe mode code chokes if this
465 * this is not added. Left it for all compilers as it does no
472 return this->final_modify_(
473 mod,back_,static_cast<final_node_type*>(position.get_node()));
476 template<typename Modifier>
477 bool modify_key(iterator position,Modifier mod)
479 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
480 BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
481 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
482 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
484 position,modify_key_adaptor<Modifier,value_type,KeyFromValue>(mod,key));
487 template<typename Modifier,typename Rollback>
488 bool modify_key(iterator position,Modifier mod,Rollback back_)
490 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
491 BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
492 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
493 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
496 modify_key_adaptor<Modifier,value_type,KeyFromValue>(mod,key),
497 modify_key_adaptor<Rollback,value_type,KeyFromValue>(back_,key));
500 void clear()BOOST_NOEXCEPT
502 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
503 this->final_clear_();
506 void swap(hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
508 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
509 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x);
510 this->final_swap_(x.final());
513 template<typename Index>
514 BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
517 merge(x,x.begin(),x.end());
520 template<typename Index>
521 BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
522 merge(BOOST_RV_REF(Index) x){merge(static_cast<Index&>(x));}
524 template<typename Index>
525 BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,pair_return_type)
526 merge(Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i)
528 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(i);
529 BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(i);
530 BOOST_MULTI_INDEX_CHECK_IS_OWNER(i,x);
531 BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
532 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
533 if(x.end().get_node()==this->header()){ /* same container */
534 return std::pair<iterator,bool>(
535 make_iterator(static_cast<final_node_type*>(i.get_node())),true);
538 std::pair<final_node_type*,bool> p=this->final_transfer_(
539 x,static_cast<final_node_type*>(i.get_node()));
540 return std::pair<iterator,bool>(make_iterator(p.first),p.second);
544 template<typename Index>
545 BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,pair_return_type)
546 merge(BOOST_RV_REF(Index) x,BOOST_DEDUCED_TYPENAME Index::iterator i)
548 return merge(static_cast<Index&>(x),i);
551 template<typename Index>
552 BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
555 BOOST_DEDUCED_TYPENAME Index::iterator first,
556 BOOST_DEDUCED_TYPENAME Index::iterator last)
558 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
559 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
560 BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,x);
561 BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,x);
562 BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
563 BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
564 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
565 if(x.end().get_node()!=this->header()){ /* different containers */
566 this->final_transfer_range_(x,first,last);
570 template<typename Index>
571 BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
573 BOOST_RV_REF(Index) x,
574 BOOST_DEDUCED_TYPENAME Index::iterator first,
575 BOOST_DEDUCED_TYPENAME Index::iterator last)
577 merge(static_cast<Index&>(x),first,last);
582 key_from_value key_extractor()const{return key;}
583 hasher hash_function()const{return hash_;}
584 key_equal key_eq()const{return eq_;}
588 /* Internally, these ops rely on const_iterator being the same
592 /* Implementation note: When CompatibleKey is consistently promoted to
593 * KeyFromValue::result_type for equality comparison, the promotion is made
594 * once in advance to increase efficiency.
597 template<typename CompatibleKey>
598 iterator find(const CompatibleKey& k)const
600 return find(k,hash_,eq_);
604 typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
607 const CompatibleKey& k,
608 const CompatibleHash& hash,const CompatiblePred& eq)const
611 k,hash,eq,promotes_1st_arg<CompatiblePred,CompatibleKey,key_type>());
614 template<typename CompatibleKey>
615 size_type count(const CompatibleKey& k)const
617 return count(k,hash_,eq_);
621 typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
624 const CompatibleKey& k,
625 const CompatibleHash& hash,const CompatiblePred& eq)const
628 k,hash,eq,promotes_1st_arg<CompatiblePred,CompatibleKey,key_type>());
631 template<typename CompatibleKey>
632 bool contains(const CompatibleKey& k)const
634 return contains(k,hash_,eq_);
638 typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
641 const CompatibleKey& k,
642 const CompatibleHash& hash,const CompatiblePred& eq)const
644 return find(k,hash,eq)!=end();
647 template<typename CompatibleKey>
648 std::pair<iterator,iterator> equal_range(const CompatibleKey& k)const
650 return equal_range(k,hash_,eq_);
654 typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
656 std::pair<iterator,iterator> equal_range(
657 const CompatibleKey& k,
658 const CompatibleHash& hash,const CompatiblePred& eq)const
661 k,hash,eq,promotes_1st_arg<CompatiblePred,CompatibleKey,key_type>());
664 /* bucket interface */
666 size_type bucket_count()const BOOST_NOEXCEPT
668 return static_cast<size_type>(buckets.size());
671 size_type max_bucket_count()const BOOST_NOEXCEPT{return static_cast<size_type>(-1);}
673 size_type bucket_size(size_type n)const
676 for(node_impl_pointer x=buckets.at(n)->prior();
677 x!=node_impl_pointer(0);x=node_alg::after_local(x)){
683 size_type bucket(key_param_type k)const
685 return static_cast<size_type>(buckets.position(hash_(k)));
688 local_iterator begin(size_type n)
690 return const_cast<const hashed_index*>(this)->begin(n);
693 const_local_iterator begin(size_type n)const
695 node_impl_pointer x=buckets.at(n)->prior();
696 if(x==node_impl_pointer(0))return end(n);
697 return make_local_iterator(index_node_type::from_impl(x));
700 local_iterator end(size_type n)
702 return const_cast<const hashed_index*>(this)->end(n);
705 const_local_iterator end(size_type)const
707 return make_local_iterator(0);
710 const_local_iterator cbegin(size_type n)const{return begin(n);}
711 const_local_iterator cend(size_type n)const{return end(n);}
713 local_iterator local_iterator_to(const value_type& x)
715 return make_local_iterator(
716 node_from_value<index_node_type>(boost::addressof(x)));
719 const_local_iterator local_iterator_to(const value_type& x)const
721 return make_local_iterator(
722 node_from_value<index_node_type>(boost::addressof(x)));
727 float load_factor()const BOOST_NOEXCEPT
728 {return static_cast<float>(size())/bucket_count();}
729 float max_load_factor()const BOOST_NOEXCEPT{return mlf;}
730 void max_load_factor(float z){mlf=z;calculate_max_load();}
732 void rehash(size_type n)
734 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
735 if(size()<=max_load&&n<=bucket_count())return;
737 size_type bc =(std::numeric_limits<size_type>::max)();
738 float fbc=1.0f+static_cast<float>(size())/mlf;
740 bc=static_cast<size_type>(fbc);
743 unchecked_rehash(bc);
746 void reserve(size_type n)
748 rehash(static_cast<size_type>(std::ceil(static_cast<float>(n)/mlf)));
751 BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
752 hashed_index(const ctor_args_list& args_list,const allocator_type& al):
753 super(args_list.get_tail(),al),
754 key(tuples::get<1>(args_list.get_head())),
755 hash_(tuples::get<2>(args_list.get_head())),
756 eq_(tuples::get<3>(args_list.get_head())),
757 buckets(al,header()->impl(),tuples::get<0>(args_list.get_head())),
760 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
765 calculate_max_load();
769 const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x):
774 buckets(x.get_allocator(),header()->impl(),x.buckets.size()),
778 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
783 /* Copy ctor just takes the internal configuration objects from x. The rest
784 * is done in subsequent call to copy_().
789 const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
790 do_not_copy_elements_tag):
791 super(x,do_not_copy_elements_tag()),
795 buckets(x.get_allocator(),header()->impl(),0),
798 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
803 calculate_max_load();
808 /* the container is guaranteed to be empty by now */
811 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
812 iterator make_iterator(index_node_type* node)
814 return iterator(node,&safe);
817 const_iterator make_iterator(index_node_type* node)const
819 return const_iterator(node,const_cast<safe_container*>(&safe));
822 iterator make_iterator(index_node_type* node)
824 return iterator(node);
827 const_iterator make_iterator(index_node_type* node)const
829 return const_iterator(node);
833 local_iterator make_local_iterator(index_node_type* node)
835 return local_iterator(node);
838 const_local_iterator make_local_iterator(index_node_type* node)const
840 return const_local_iterator(node);
844 const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
845 const copy_map_type& map)
847 copy_(x,map,Category());
851 const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
852 const copy_map_type& map,hashed_unique_tag)
855 node_impl_pointer end_org=x.header()->impl(),
857 cpy=header()->impl();
859 node_impl_pointer prev_org=org->prior(),
861 static_cast<index_node_type*>(map.find(static_cast<final_node_type*>(
862 index_node_type::from_impl(prev_org))))->impl();
863 cpy->prior()=prev_cpy;
864 if(node_alg::is_first_of_bucket(org)){
865 node_impl_base_pointer buc_org=prev_org->next(),
867 buckets.begin()+(buc_org-x.buckets.begin());
868 prev_cpy->next()=buc_cpy;
869 buc_cpy->prior()=cpy;
872 prev_cpy->next()=node_impl_type::base_pointer_from(cpy);
876 }while(org!=end_org);
883 const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
884 const copy_map_type& map,hashed_non_unique_tag)
887 node_impl_pointer end_org=x.header()->impl(),
889 cpy=header()->impl();
891 node_impl_pointer next_org=node_alg::after(org),
893 static_cast<index_node_type*>(map.find(static_cast<final_node_type*>(
894 index_node_type::from_impl(next_org))))->impl();
895 if(node_alg::is_first_of_bucket(next_org)){
896 node_impl_base_pointer buc_org=org->next(),
898 buckets.begin()+(buc_org-x.buckets.begin());
900 buc_cpy->prior()=next_cpy;
901 next_cpy->prior()=cpy;
904 if(org->next()==node_impl_type::base_pointer_from(next_org)){
905 cpy->next()=node_impl_type::base_pointer_from(next_cpy);
909 node_impl_type::base_pointer_from(
910 static_cast<index_node_type*>(
911 map.find(static_cast<final_node_type*>(
912 index_node_type::from_impl(
913 node_impl_type::pointer_from(org->next())))))->impl());
916 if(next_org->prior()!=org){
918 static_cast<index_node_type*>(
919 map.find(static_cast<final_node_type*>(
920 index_node_type::from_impl(next_org->prior()))))->impl();
923 next_cpy->prior()=cpy;
928 }while(org!=end_org);
934 template<typename Variant>
935 final_node_type* insert_(
936 value_param_type v,final_node_type*& x,Variant variant)
938 reserve_for_insert(size()+1);
940 std::size_t buc=find_bucket(v);
941 link_info pos(buckets.at(buc));
942 if(!link_point(v,pos)){
943 return static_cast<final_node_type*>(
944 index_node_type::from_impl(node_impl_type::pointer_from(pos)));
947 final_node_type* res=super::insert_(v,x,variant);
948 if(res==x)link(static_cast<index_node_type*>(x),pos);
952 template<typename Variant>
953 final_node_type* insert_(
954 value_param_type v,index_node_type* position,
955 final_node_type*& x,Variant variant)
957 reserve_for_insert(size()+1);
959 std::size_t buc=find_bucket(v);
960 link_info pos(buckets.at(buc));
961 if(!link_point(v,pos)){
962 return static_cast<final_node_type*>(
963 index_node_type::from_impl(node_impl_type::pointer_from(pos)));
966 final_node_type* res=super::insert_(v,position,x,variant);
967 if(res==x)link(static_cast<index_node_type*>(x),pos);
971 template<typename Dst>
972 void extract_(index_node_type* x,Dst dst)
975 super::extract_(x,dst.next());
977 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
978 transfer_iterators(dst.get(),x);
982 void delete_all_nodes_()
984 delete_all_nodes_(Category());
987 void delete_all_nodes_(hashed_unique_tag)
989 for(node_impl_pointer x_end=header()->impl(),x=x_end->prior();x!=x_end;){
990 node_impl_pointer y=x->prior();
991 this->final_delete_node_(
992 static_cast<final_node_type*>(index_node_type::from_impl(x)));
997 void delete_all_nodes_(hashed_non_unique_tag)
999 for(node_impl_pointer x_end=header()->impl(),x=x_end->prior();x!=x_end;){
1000 node_impl_pointer y=x->prior();
1001 if(y->next()!=node_impl_type::base_pointer_from(x)&&
1002 y->next()->prior()!=x){ /* n-1 of group */
1003 /* Make the second node prior() pointer back-linked so that it won't
1004 * refer to a deleted node when the time for its own destruction comes.
1007 node_impl_pointer first=node_impl_type::pointer_from(y->next());
1008 first->next()->prior()=first;
1010 this->final_delete_node_(
1011 static_cast<final_node_type*>(index_node_type::from_impl(x)));
1019 buckets.clear(header()->impl());
1021 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1022 safe.detach_dereferenceable_iterators();
1026 template<typename BoolConstant>
1028 hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
1029 BoolConstant swap_allocators)
1031 adl_swap(key,x.key);
1032 adl_swap(hash_,x.hash_);
1033 adl_swap(eq_,x.eq_);
1034 buckets.swap(x.buckets,swap_allocators);
1035 std::swap(mlf,x.mlf);
1036 std::swap(max_load,x.max_load);
1038 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1042 super::swap_(x,swap_allocators);
1045 void swap_elements_(
1046 hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
1048 buckets.swap(x.buckets);
1049 std::swap(mlf,x.mlf);
1050 std::swap(max_load,x.max_load);
1052 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1056 super::swap_elements_(x);
1059 template<typename Variant>
1060 bool replace_(value_param_type v,index_node_type* x,Variant variant)
1062 if(eq_(key(v),key(x->value()))){
1063 return super::replace_(v,x,variant);
1070 std::size_t buc=find_bucket(v);
1071 link_info pos(buckets.at(buc));
1072 if(link_point(v,pos)&&super::replace_(v,x,variant)){
1086 bool modify_(index_node_type* x)
1091 buc=find_bucket(x->value());
1092 b=in_place(x->impl(),key(x->value()),buc);
1095 extract_(x,invalidate_iterators());
1102 link_info pos(buckets.at(buc));
1103 if(!link_point(x->value(),pos)){
1104 super::extract_(x,invalidate_iterators());
1106 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1107 detach_iterators(x);
1114 super::extract_(x,invalidate_iterators());
1116 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1117 detach_iterators(x);
1126 if(!super::modify_(x)){
1129 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1130 detach_iterators(x);
1139 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1140 detach_iterators(x);
1148 bool modify_rollback_(index_node_type* x)
1150 std::size_t buc=find_bucket(x->value());
1151 if(in_place(x->impl(),key(x->value()),buc)){
1152 return super::modify_rollback_(x);
1159 link_info pos(buckets.at(buc));
1160 if(link_point(x->value(),pos)&&super::modify_rollback_(x)){
1174 bool check_rollback_(index_node_type* x)const
1176 std::size_t buc=find_bucket(x->value());
1177 return in_place(x->impl(),key(x->value()),buc)&&super::check_rollback_(x);
1182 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
1183 /* defect macro refers to class, not function, templates, but anyway */
1185 template<typename K,typename H,typename P,typename S,typename T,typename C>
1186 friend bool operator==(
1187 const hashed_index<K,H,P,S,T,C>&,const hashed_index<K,H,P,S,T,C>& y);
1190 bool equals(const hashed_index& x)const{return equals(x,Category());}
1192 bool equals(const hashed_index& x,hashed_unique_tag)const
1194 if(size()!=x.size())return false;
1195 for(const_iterator it=begin(),it_end=end(),it2_end=x.end();
1197 const_iterator it2=x.find(key(*it));
1198 if(it2==it2_end||!(*it==*it2))return false;
1203 bool equals(const hashed_index& x,hashed_non_unique_tag)const
1205 if(size()!=x.size())return false;
1206 for(const_iterator it=begin(),it_end=end();it!=it_end;){
1207 const_iterator it2,it2_last;
1208 boost::tie(it2,it2_last)=x.equal_range(key(*it));
1209 if(it2==it2_last)return false;
1211 const_iterator it_last=make_iterator(
1212 index_node_type::from_impl(end_of_range(it.get_node()->impl())));
1213 if(std::distance(it,it_last)!=std::distance(it2,it2_last))return false;
1215 /* From is_permutation code in
1216 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3068.pdf
1219 for(;it!=it_last;++it,++it2){
1220 if(!(*it==*it2))break;
1223 for(const_iterator scan=it;scan!=it_last;++scan){
1224 if(std::find(it,scan,*scan)!=scan)continue;
1225 difference_type matches=std::count(it2,it2_last,*scan);
1226 if(matches==0||matches!=std::count(scan,it_last,*scan))return false;
1234 #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
1237 template<typename Archive>
1239 Archive& ar,const unsigned int version,const index_saver_type& sm)const
1241 ar<<serialization::make_nvp("position",buckets);
1242 super::save_(ar,version,sm);
1245 template<typename Archive>
1246 void load_(Archive& ar,const unsigned int version,const index_loader_type& lm)
1248 ar>>serialization::make_nvp("position",buckets);
1249 super::load_(ar,version,lm);
1253 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
1254 /* invariant stuff */
1256 bool invariant_()const
1258 if(size()==0||begin()==end()){
1259 if(size()!=0||begin()!=end())return false;
1263 for(const_iterator it=begin(),it_end=end();it!=it_end;++it,++s0){}
1264 if(s0!=size())return false;
1267 for(size_type buc=0;buc<bucket_count();++buc){
1269 for(const_local_iterator it=begin(buc),it_end=end(buc);
1270 it!=it_end;++it,++ss1){
1271 if(find_bucket(*it)!=buc)return false;
1273 if(ss1!=bucket_size(buc))return false;
1276 if(s1!=size())return false;
1279 return super::invariant_();
1282 /* This forwarding function eases things for the boost::mem_fn construct
1283 * in BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT. Actually,
1284 * final_check_invariant is already an inherited member function of index.
1286 void check_invariant_()const{this->final_check_invariant_();}
1290 index_node_type* header()const{return this->final_header();}
1292 std::size_t find_bucket(value_param_type v)const
1294 return bucket(key(v));
1297 struct link_info_non_unique
1299 link_info_non_unique(node_impl_base_pointer pos):
1300 first(pos),last(node_impl_base_pointer(0)){}
1302 operator const node_impl_base_pointer&()const{return this->first;}
1304 node_impl_base_pointer first,last;
1307 typedef typename mpl::if_<
1308 is_same<Category,hashed_unique_tag>,
1309 node_impl_base_pointer,
1310 link_info_non_unique
1313 bool link_point(value_param_type v,link_info& pos)
1315 return link_point(v,pos,Category());
1319 value_param_type v,node_impl_base_pointer& pos,hashed_unique_tag)
1321 for(node_impl_pointer x=pos->prior();x!=node_impl_pointer(0);
1322 x=node_alg::after_local(x)){
1323 if(eq_(key(v),key(index_node_type::from_impl(x)->value()))){
1324 pos=node_impl_type::base_pointer_from(x);
1332 value_param_type v,link_info_non_unique& pos,hashed_non_unique_tag)
1334 for(node_impl_pointer x=pos.first->prior();x!=node_impl_pointer(0);
1335 x=node_alg::next_to_inspect(x)){
1336 if(eq_(key(v),key(index_node_type::from_impl(x)->value()))){
1337 pos.first=node_impl_type::base_pointer_from(x);
1338 pos.last=node_impl_type::base_pointer_from(last_of_range(x));
1345 node_impl_pointer last_of_range(node_impl_pointer x)const
1347 return last_of_range(x,Category());
1350 node_impl_pointer last_of_range(node_impl_pointer x,hashed_unique_tag)const
1355 node_impl_pointer last_of_range(
1356 node_impl_pointer x,hashed_non_unique_tag)const
1358 node_impl_base_pointer y=x->next();
1359 node_impl_pointer z=y->prior();
1360 if(z==x){ /* range of size 1 or 2 */
1361 node_impl_pointer yy=node_impl_type::pointer_from(y);
1364 key(index_node_type::from_impl(x)->value()),
1365 key(index_node_type::from_impl(yy)->value()))?yy:x;
1367 else if(z->prior()==x) /* last of bucket */
1369 else /* group of size>2 */
1373 node_impl_pointer end_of_range(node_impl_pointer x)const
1375 return end_of_range(x,Category());
1378 node_impl_pointer end_of_range(node_impl_pointer x,hashed_unique_tag)const
1380 return node_alg::after(last_of_range(x));
1383 node_impl_pointer end_of_range(
1384 node_impl_pointer x,hashed_non_unique_tag)const
1386 node_impl_base_pointer y=x->next();
1387 node_impl_pointer z=y->prior();
1388 if(z==x){ /* range of size 1 or 2 */
1389 node_impl_pointer yy=node_impl_type::pointer_from(y);
1391 key(index_node_type::from_impl(x)->value()),
1392 key(index_node_type::from_impl(yy)->value())))yy=x;
1393 return yy->next()->prior()==yy?
1394 node_impl_type::pointer_from(yy->next()):
1395 yy->next()->prior();
1397 else if(z->prior()==x) /* last of bucket */
1399 else /* group of size>2 */
1400 return z->next()->prior()==z?
1401 node_impl_type::pointer_from(z->next()):
1405 void link(index_node_type* x,const link_info& pos)
1407 link(x,pos,Category());
1410 void link(index_node_type* x,node_impl_base_pointer pos,hashed_unique_tag)
1412 node_alg::link(x->impl(),pos,header()->impl());
1416 index_node_type* x,const link_info_non_unique& pos,hashed_non_unique_tag)
1418 if(pos.last==node_impl_base_pointer(0)){
1419 node_alg::link(x->impl(),pos.first,header()->impl());
1424 node_impl_type::pointer_from(pos.first),
1425 node_impl_type::pointer_from(pos.last));
1429 void unlink(index_node_type* x)
1431 node_alg::unlink(x->impl());
1434 typedef typename node_alg::unlink_undo unlink_undo;
1436 void unlink(index_node_type* x,unlink_undo& undo)
1438 node_alg::unlink(x->impl(),undo);
1441 void calculate_max_load()
1443 float fml=mlf*static_cast<float>(bucket_count());
1444 max_load=(std::numeric_limits<size_type>::max)();
1445 if(max_load>fml)max_load=static_cast<size_type>(fml);
1448 void reserve_for_insert(size_type n)
1451 size_type bc =(std::numeric_limits<size_type>::max)();
1452 float fbc=1.0f+static_cast<float>(n)/mlf;
1453 if(bc>fbc)bc =static_cast<size_type>(fbc);
1454 unchecked_rehash(bc);
1458 void unchecked_rehash(size_type n){unchecked_rehash(n,Category());}
1460 void unchecked_rehash(size_type n,hashed_unique_tag)
1462 node_impl_type cpy_end_node;
1463 node_impl_pointer cpy_end=node_impl_pointer(&cpy_end_node),
1464 end_=header()->impl();
1465 bucket_array_type buckets_cpy(get_allocator(),cpy_end,n);
1469 std::size_t,allocator_type> hashes(get_allocator(),size());
1471 node_impl_pointer,allocator_type> node_ptrs(get_allocator(),size());
1472 std::size_t i=0,size_=size();
1473 bool within_bucket=false;
1476 node_impl_pointer x=end_->prior();
1478 /* only this can possibly throw */
1479 std::size_t h=hash_(key(index_node_type::from_impl(x)->value()));
1482 node_ptrs.data()[i]=x;
1483 within_bucket=!node_alg::unlink_last(end_);
1484 node_alg::link(x,buckets_cpy.at(buckets_cpy.position(h)),cpy_end);
1489 std::size_t prev_buc=buckets.position(hashes.data()[i-1]);
1490 if(!within_bucket)prev_buc=~prev_buc;
1492 for(std::size_t j=i;j--;){
1493 std::size_t buc=buckets.position(hashes.data()[j]);
1494 node_impl_pointer x=node_ptrs.data()[j];
1495 if(buc==prev_buc)node_alg::append(x,end_);
1496 else node_alg::link(x,buckets.at(buc),end_);
1505 end_->prior()=cpy_end->prior()!=cpy_end?cpy_end->prior():end_;
1506 end_->next()=cpy_end->next();
1507 end_->prior()->next()->prior()=end_->next()->prior()->prior()=end_;
1508 buckets.swap(buckets_cpy);
1509 calculate_max_load();
1512 void unchecked_rehash(size_type n,hashed_non_unique_tag)
1514 node_impl_type cpy_end_node;
1515 node_impl_pointer cpy_end=node_impl_pointer(&cpy_end_node),
1516 end_=header()->impl();
1517 bucket_array_type buckets_cpy(get_allocator(),cpy_end,n);
1521 std::size_t,allocator_type> hashes(get_allocator(),size());
1523 node_impl_pointer,allocator_type> node_ptrs(get_allocator(),size());
1525 bool within_bucket=false;
1528 node_impl_pointer x=end_->prior();
1531 /* only this can possibly throw */
1532 std::size_t h=hash_(key(index_node_type::from_impl(x)->value()));
1535 node_ptrs.data()[i]=x;
1536 std::pair<node_impl_pointer,bool> p=
1537 node_alg::unlink_last_group(end_);
1538 node_alg::link_range(
1539 p.first,x,buckets_cpy.at(buckets_cpy.position(h)),cpy_end);
1540 within_bucket=!(p.second);
1545 std::size_t prev_buc=buckets.position(hashes.data()[i-1]);
1546 if(!within_bucket)prev_buc=~prev_buc;
1548 for(std::size_t j=i;j--;){
1549 std::size_t buc=buckets.position(hashes.data()[j]);
1550 node_impl_pointer x=node_ptrs.data()[j],
1552 x->prior()->next()!=node_impl_type::base_pointer_from(x)&&
1553 x->prior()->next()->prior()!=x?
1554 node_impl_type::pointer_from(x->prior()->next()):x;
1555 node_alg::unlink_range(y,x);
1556 if(buc==prev_buc)node_alg::append_range(y,x,end_);
1557 else node_alg::link_range(y,x,buckets.at(buc),end_);
1566 end_->prior()=cpy_end->prior()!=cpy_end?cpy_end->prior():end_;
1567 end_->next()=cpy_end->next();
1568 end_->prior()->next()->prior()=end_->next()->prior()->prior()=end_;
1569 buckets.swap(buckets_cpy);
1570 calculate_max_load();
1573 bool in_place(node_impl_pointer x,key_param_type k,std::size_t buc)const
1575 return in_place(x,k,buc,Category());
1579 node_impl_pointer x,key_param_type k,std::size_t buc,
1580 hashed_unique_tag)const
1583 for(node_impl_pointer y=buckets.at(buc)->prior();
1584 y!=node_impl_pointer(0);y=node_alg::after_local(y)){
1586 else if(eq_(k,key(index_node_type::from_impl(y)->value())))return false;
1592 node_impl_pointer x,key_param_type k,std::size_t buc,
1593 hashed_non_unique_tag)const
1597 for(node_impl_pointer y=buckets.at(buc)->prior();y!=node_impl_pointer(0);){
1598 if(node_alg::is_first_of_group(y)){ /* group of 3 or more */
1600 /* in place <-> equal to some other member of the group */
1603 key(index_node_type::from_impl(
1604 node_impl_type::pointer_from(y->next()))->value()));
1607 node_impl_pointer z=
1608 node_alg::after_local(y->next()->prior()); /* end of range */
1609 if(eq_(k,key(index_node_type::from_impl(y)->value()))){
1610 if(found)return false; /* x lies outside */
1612 if(y==x)return true;
1613 y=node_alg::after_local(y);
1615 return false; /* x not found */
1618 if(range_size==1&&!found)return false;
1619 if(range_size==2)return found;
1621 y=z; /* skip range (and potentially x, too, which is fine) */
1625 else{ /* group of 1 or 2 */
1627 if(range_size==1)return true;
1631 else if(eq_(k,key(index_node_type::from_impl(y)->value()))){
1632 if(range_size==0&&found)return false;
1633 if(range_size==1&&!found)return false;
1634 if(range_size==2)return false;
1638 if(range_size==1&&!found)return false;
1639 if(range_size==2)return found;
1642 y=node_alg::after_local(y);
1648 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1649 void detach_iterators(index_node_type* x)
1651 iterator it=make_iterator(x);
1652 safe_mode::detach_equivalent_iterators(it);
1655 template<typename Dst>
1656 void transfer_iterators(Dst& dst,index_node_type* x)
1658 iterator it=make_iterator(x);
1659 safe_mode::transfer_equivalent_iterators(dst,it);
1663 template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
1664 std::pair<iterator,bool> emplace_impl(BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
1666 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
1667 std::pair<final_node_type*,bool>p=
1668 this->final_emplace_(BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
1669 return std::pair<iterator,bool>(make_iterator(p.first),p.second);
1672 template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
1673 iterator emplace_hint_impl(
1674 iterator position,BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
1676 BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
1677 BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
1678 BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
1679 std::pair<final_node_type*,bool>p=
1680 this->final_emplace_hint_(
1681 static_cast<final_node_type*>(position.get_node()),
1682 BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
1683 return make_iterator(p.first);
1687 typename CompatibleHash,typename CompatiblePred
1691 const CompatibleHash& hash,const CompatiblePred& eq,mpl::true_)const
1693 return find(k,hash,eq,mpl::false_());
1697 typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
1700 const CompatibleKey& k,
1701 const CompatibleHash& hash,const CompatiblePred& eq,mpl::false_)const
1703 std::size_t buc=buckets.position(hash(k));
1704 for(node_impl_pointer x=buckets.at(buc)->prior();
1705 x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
1706 if(eq(k,key(index_node_type::from_impl(x)->value()))){
1707 return make_iterator(index_node_type::from_impl(x));
1714 typename CompatibleHash,typename CompatiblePred
1718 const CompatibleHash& hash,const CompatiblePred& eq,mpl::true_)const
1720 return count(k,hash,eq,mpl::false_());
1724 typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
1727 const CompatibleKey& k,
1728 const CompatibleHash& hash,const CompatiblePred& eq,mpl::false_)const
1730 std::size_t buc=buckets.position(hash(k));
1731 for(node_impl_pointer x=buckets.at(buc)->prior();
1732 x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
1733 if(eq(k,key(index_node_type::from_impl(x)->value()))){
1735 node_impl_pointer y=end_of_range(x);
1738 x=node_alg::after(x);
1747 typename CompatibleHash,typename CompatiblePred
1749 std::pair<iterator,iterator> equal_range(
1751 const CompatibleHash& hash,const CompatiblePred& eq,mpl::true_)const
1753 return equal_range(k,hash,eq,mpl::false_());
1757 typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
1759 std::pair<iterator,iterator> equal_range(
1760 const CompatibleKey& k,
1761 const CompatibleHash& hash,const CompatiblePred& eq,mpl::false_)const
1763 std::size_t buc=buckets.position(hash(k));
1764 for(node_impl_pointer x=buckets.at(buc)->prior();
1765 x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
1766 if(eq(k,key(index_node_type::from_impl(x)->value()))){
1767 return std::pair<iterator,iterator>(
1768 make_iterator(index_node_type::from_impl(x)),
1769 make_iterator(index_node_type::from_impl(end_of_range(x))));
1772 return std::pair<iterator,iterator>(end(),end());
1778 bucket_array_type buckets;
1782 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
1783 safe_container safe;
1786 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
1787 BOOST_WORKAROUND(__MWERKS__,<=0x3003)
1788 #pragma parse_mfunc_templ reset
1792 #if defined(BOOST_MSVC)
1793 #pragma warning(pop) /* C4355 */
1799 typename KeyFromValue,typename Hash,typename Pred,
1800 typename SuperMeta,typename TagList,typename Category
1803 const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
1804 const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
1810 typename KeyFromValue,typename Hash,typename Pred,
1811 typename SuperMeta,typename TagList,typename Category
1814 const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
1815 const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
1820 /* specialized algorithms */
1823 typename KeyFromValue,typename Hash,typename Pred,
1824 typename SuperMeta,typename TagList,typename Category
1827 hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
1828 hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
1833 } /* namespace multi_index::detail */
1835 /* hashed index specifiers */
1837 template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
1838 struct hashed_unique
1840 typedef typename detail::hashed_index_args<
1841 Arg1,Arg2,Arg3,Arg4> index_args;
1842 typedef typename index_args::tag_list_type::type tag_list_type;
1843 typedef typename index_args::key_from_value_type key_from_value_type;
1844 typedef typename index_args::hash_type hash_type;
1845 typedef typename index_args::pred_type pred_type;
1847 template<typename Super>
1850 typedef detail::hashed_index_node<Super> type;
1853 template<typename SuperMeta>
1856 typedef detail::hashed_index<
1857 key_from_value_type,hash_type,pred_type,
1858 SuperMeta,tag_list_type,detail::hashed_unique_tag> type;
1862 template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
1863 struct hashed_non_unique
1865 typedef typename detail::hashed_index_args<
1866 Arg1,Arg2,Arg3,Arg4> index_args;
1867 typedef typename index_args::tag_list_type::type tag_list_type;
1868 typedef typename index_args::key_from_value_type key_from_value_type;
1869 typedef typename index_args::hash_type hash_type;
1870 typedef typename index_args::pred_type pred_type;
1872 template<typename Super>
1875 typedef detail::hashed_index_node<Super> type;
1878 template<typename SuperMeta>
1881 typedef detail::hashed_index<
1882 key_from_value_type,hash_type,pred_type,
1883 SuperMeta,tag_list_type,detail::hashed_non_unique_tag> type;
1887 } /* namespace multi_index */
1889 } /* namespace boost */
1891 /* Boost.Foreach compatibility */
1894 typename KeyFromValue,typename Hash,typename Pred,
1895 typename SuperMeta,typename TagList,typename Category
1897 inline boost::mpl::true_* boost_foreach_is_noncopyable(
1898 boost::multi_index::detail::hashed_index<
1899 KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>*&,
1900 boost_foreach_argument_dependent_lookup_hack)
1905 #undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
1906 #undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF