1 /* Copyright 2003-2015 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)
5  *
6  * See http://www.boost.org/libs/multi_index for library home page.
7  */
8 
9 #ifndef BOOST_MULTI_INDEX_HASHED_INDEX_HPP
10 #define BOOST_MULTI_INDEX_HASHED_INDEX_HPP
11 
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15 
16 #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
17 #include <algorithm>
18 #include <boost/call_traits.hpp>
19 #include <boost/detail/allocator_utilities.hpp>
20 #include <boost/detail/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/mpl/bool.hpp>
26 #include <boost/mpl/if.hpp>
27 #include <boost/mpl/push_front.hpp>
28 #include <boost/multi_index/detail/access_specifier.hpp>
29 #include <boost/multi_index/detail/auto_space.hpp>
30 #include <boost/multi_index/detail/bucket_array.hpp>
31 #include <boost/multi_index/detail/do_not_copy_elements_tag.hpp>
32 #include <boost/multi_index/detail/hash_index_iterator.hpp>
33 #include <boost/multi_index/detail/index_node_base.hpp>
34 #include <boost/multi_index/detail/modify_key_adaptor.hpp>
35 #include <boost/multi_index/detail/promotes_arg.hpp>
36 #include <boost/multi_index/detail/safe_mode.hpp>
37 #include <boost/multi_index/detail/scope_guard.hpp>
38 #include <boost/multi_index/detail/vartempl_support.hpp>
39 #include <boost/multi_index/hashed_index_fwd.hpp>
40 #include <boost/tuple/tuple.hpp>
41 #include <boost/type_traits/is_same.hpp>
42 #include <cmath>
43 #include <cstddef>
44 #include <functional>
45 #include <iterator>
46 #include <utility>
47 
48 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
49 #include <initializer_list>
50 #endif
51 
52 #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
53 #include <boost/serialization/nvp.hpp>
54 #endif
55 
56 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
57 #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x)                 \
58   detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)=                 \
59     detail::make_obj_guard(x,&hashed_index::check_invariant_);               \
60   BOOST_JOIN(check_invariant_,__LINE__).touch();
61 #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT                       \
62   BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(*this)
63 #else
64 #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x)
65 #define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
66 #endif
67 
68 namespace boost{
69 
70 namespace multi_index{
71 
72 namespace detail{
73 
74 /* hashed_index adds a layer of hashed indexing to a given Super */
75 
76 /* Most of the implementation of unique and non-unique indices is
77  * shared. We tell from one another on instantiation time by using
78  * Category tags defined in hash_index_node.hpp.
79  */
80 
81 template<
82   typename KeyFromValue,typename Hash,typename Pred,
83   typename SuperMeta,typename TagList,typename Category
84 >
85 class hashed_index:
86   BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS SuperMeta::type
87 
88 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
89   ,public safe_mode::safe_container<
90     hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> >
91 #endif
92 
93 {
94 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
95     BOOST_WORKAROUND(__MWERKS__,<=0x3003)
96 /* The "ISO C++ Template Parser" option in CW8.3 has a problem with the
97  * lifetime of const references bound to temporaries --precisely what
98  * scopeguards are.
99  */
100 
101 #pragma parse_mfunc_templ off
102 #endif
103 
104   typedef typename SuperMeta::type                   super;
105 
106 protected:
107   typedef hashed_index_node<
108     typename super::node_type,Category>              node_type;
109 
110 private:
111   typedef typename node_type::node_alg               node_alg;
112   typedef typename node_type::impl_type              node_impl_type;
113   typedef typename node_impl_type::pointer           node_impl_pointer;
114   typedef typename node_impl_type::base_pointer      node_impl_base_pointer;
115   typedef bucket_array<
116     typename super::final_allocator_type>            bucket_array_type;
117 
118 public:
119   /* types */
120 
121   typedef typename KeyFromValue::result_type         key_type;
122   typedef typename node_type::value_type             value_type;
123   typedef KeyFromValue                               key_from_value;
124   typedef Hash                                       hasher;
125   typedef Pred                                       key_equal;
126   typedef tuple<std::size_t,
127     key_from_value,hasher,key_equal>                 ctor_args;
128   typedef typename super::final_allocator_type       allocator_type;
129   typedef typename allocator_type::pointer           pointer;
130   typedef typename allocator_type::const_pointer     const_pointer;
131   typedef typename allocator_type::reference         reference;
132   typedef typename allocator_type::const_reference   const_reference;
133   typedef std::size_t                                size_type;
134   typedef std::ptrdiff_t                             difference_type;
135 
136 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
137   typedef safe_mode::safe_iterator<
138     hashed_index_iterator<
139       node_type,bucket_array_type,
140       hashed_index_global_iterator_tag>,
141     hashed_index>                                    iterator;
142 #else
143   typedef hashed_index_iterator<
144     node_type,bucket_array_type,
145     hashed_index_global_iterator_tag>                iterator;
146 #endif
147 
148   typedef iterator                                   const_iterator;
149 
150   typedef hashed_index_iterator<
151     node_type,bucket_array_type,
152     hashed_index_local_iterator_tag>                 local_iterator;
153   typedef local_iterator                             const_local_iterator;
154 
155   typedef TagList                                    tag_list;
156 
157 protected:
158   typedef typename super::final_node_type     final_node_type;
159   typedef tuples::cons<
160     ctor_args,
161     typename super::ctor_args_list>           ctor_args_list;
162   typedef typename mpl::push_front<
163     typename super::index_type_list,
164     hashed_index>::type                       index_type_list;
165   typedef typename mpl::push_front<
166     typename super::iterator_type_list,
167     iterator>::type                           iterator_type_list;
168   typedef typename mpl::push_front<
169     typename super::const_iterator_type_list,
170     const_iterator>::type                     const_iterator_type_list;
171   typedef typename super::copy_map_type       copy_map_type;
172 
173 #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
174   typedef typename super::index_saver_type    index_saver_type;
175   typedef typename super::index_loader_type   index_loader_type;
176 #endif
177 
178 private:
179 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
180   typedef safe_mode::safe_container<
181     hashed_index>                             safe_super;
182 #endif
183 
184   typedef typename call_traits<value_type>::param_type value_param_type;
185   typedef typename call_traits<
186     key_type>::param_type                              key_param_type;
187 
188   /* Needed to avoid commas in BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL
189    * expansion.
190    */
191 
192   typedef std::pair<iterator,bool>                     emplace_return_type;
193 
194 public:
195 
196   /* construct/destroy/copy
197    * Default and copy ctors are in the protected section as indices are
198    * not supposed to be created on their own. No range ctor either.
199    */
200 
operator =(const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x)201   hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& operator=(
202     const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
203   {
204     this->final()=x.final();
205     return *this;
206   }
207 
208 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
operator =(std::initializer_list<value_type> list)209   hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& operator=(
210     std::initializer_list<value_type> list)
211   {
212     this->final()=list;
213     return *this;
214   }
215 #endif
216 
get_allocator() const217   allocator_type get_allocator()const BOOST_NOEXCEPT
218   {
219     return this->final().get_allocator();
220   }
221 
222   /* size and capacity */
223 
empty() const224   bool      empty()const BOOST_NOEXCEPT{return this->final_empty_();}
size() const225   size_type size()const BOOST_NOEXCEPT{return this->final_size_();}
max_size() const226   size_type max_size()const BOOST_NOEXCEPT{return this->final_max_size_();}
227 
228   /* iterators */
229 
begin()230   iterator begin()BOOST_NOEXCEPT
231     {return make_iterator(node_type::from_impl(header()->next()->prior()));}
begin() const232   const_iterator begin()const BOOST_NOEXCEPT
233     {return make_iterator(node_type::from_impl(header()->next()->prior()));}
end()234   iterator       end()BOOST_NOEXCEPT{return make_iterator(header());}
end() const235   const_iterator end()const BOOST_NOEXCEPT{return make_iterator(header());}
cbegin() const236   const_iterator cbegin()const BOOST_NOEXCEPT{return begin();}
cend() const237   const_iterator cend()const BOOST_NOEXCEPT{return end();}
238 
iterator_to(const value_type & x)239   iterator iterator_to(const value_type& x)
240   {
241     return make_iterator(node_from_value<node_type>(&x));
242   }
243 
iterator_to(const value_type & x) const244   const_iterator iterator_to(const value_type& x)const
245   {
246     return make_iterator(node_from_value<node_type>(&x));
247   }
248 
249   /* modifiers */
250 
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(emplace_return_type,emplace,emplace_impl)251   BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
252     emplace_return_type,emplace,emplace_impl)
253 
254   BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
255     iterator,emplace_hint,emplace_hint_impl,iterator,position)
256 
257   std::pair<iterator,bool> insert(const value_type& x)
258   {
259     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
260     std::pair<final_node_type*,bool> p=this->final_insert_(x);
261     return std::pair<iterator,bool>(make_iterator(p.first),p.second);
262   }
263 
insert(BOOST_RV_REF (value_type)x)264   std::pair<iterator,bool> insert(BOOST_RV_REF(value_type) x)
265   {
266     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
267     std::pair<final_node_type*,bool> p=this->final_insert_rv_(x);
268     return std::pair<iterator,bool>(make_iterator(p.first),p.second);
269   }
270 
insert(iterator position,const value_type & x)271   iterator insert(iterator position,const value_type& x)
272   {
273     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
274     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
275     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
276     std::pair<final_node_type*,bool> p=this->final_insert_(
277       x,static_cast<final_node_type*>(position.get_node()));
278     return make_iterator(p.first);
279   }
280 
insert(iterator position,BOOST_RV_REF (value_type)x)281   iterator insert(iterator position,BOOST_RV_REF(value_type) x)
282   {
283     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
284     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
285     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
286     std::pair<final_node_type*,bool> p=this->final_insert_rv_(
287       x,static_cast<final_node_type*>(position.get_node()));
288     return make_iterator(p.first);
289   }
290 
291   template<typename InputIterator>
insert(InputIterator first,InputIterator last)292   void insert(InputIterator first,InputIterator last)
293   {
294     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
295     for(;first!=last;++first)this->final_insert_ref_(*first);
296   }
297 
298 #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
insert(std::initializer_list<value_type> list)299   void insert(std::initializer_list<value_type> list)
300   {
301     insert(list.begin(),list.end());
302   }
303 #endif
304 
erase(iterator position)305   iterator erase(iterator position)
306   {
307     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
308     BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
309     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
310     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
311     this->final_erase_(static_cast<final_node_type*>(position++.get_node()));
312     return position;
313   }
314 
erase(key_param_type k)315   size_type erase(key_param_type k)
316   {
317     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
318 
319     std::size_t buc=buckets.position(hash_(k));
320     for(node_impl_pointer x=buckets.at(buc)->prior();
321         x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
322       if(eq_(k,key(node_type::from_impl(x)->value()))){
323         node_impl_pointer y=end_of_range(x);
324         size_type         s=0;
325         do{
326           node_impl_pointer z=node_alg::after(x);
327           this->final_erase_(
328             static_cast<final_node_type*>(node_type::from_impl(x)));
329           x=z;
330           ++s;
331         }while(x!=y);
332         return s;
333       }
334     }
335     return 0;
336   }
337 
erase(iterator first,iterator last)338   iterator erase(iterator first,iterator last)
339   {
340     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
341     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
342     BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,*this);
343     BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,*this);
344     BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
345     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
346     while(first!=last){
347       first=erase(first);
348     }
349     return first;
350   }
351 
replace(iterator position,const value_type & x)352   bool replace(iterator position,const value_type& x)
353   {
354     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
355     BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
356     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
357     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
358     return this->final_replace_(
359       x,static_cast<final_node_type*>(position.get_node()));
360   }
361 
replace(iterator position,BOOST_RV_REF (value_type)x)362   bool replace(iterator position,BOOST_RV_REF(value_type) x)
363   {
364     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
365     BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
366     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
367     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
368     return this->final_replace_rv_(
369       x,static_cast<final_node_type*>(position.get_node()));
370   }
371 
372   template<typename Modifier>
modify(iterator position,Modifier mod)373   bool modify(iterator position,Modifier mod)
374   {
375     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
376     BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
377     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
378     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
379 
380 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
381     /* MSVC++ 6.0 optimizer on safe mode code chokes if this
382      * this is not added. Left it for all compilers as it does no
383      * harm.
384      */
385 
386     position.detach();
387 #endif
388 
389     return this->final_modify_(
390       mod,static_cast<final_node_type*>(position.get_node()));
391   }
392 
393   template<typename Modifier,typename Rollback>
modify(iterator position,Modifier mod,Rollback back_)394   bool modify(iterator position,Modifier mod,Rollback back_)
395   {
396     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
397     BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
398     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
399     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
400 
401 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
402     /* MSVC++ 6.0 optimizer on safe mode code chokes if this
403      * this is not added. Left it for all compilers as it does no
404      * harm.
405      */
406 
407     position.detach();
408 #endif
409 
410     return this->final_modify_(
411       mod,back_,static_cast<final_node_type*>(position.get_node()));
412   }
413 
414   template<typename Modifier>
modify_key(iterator position,Modifier mod)415   bool modify_key(iterator position,Modifier mod)
416   {
417     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
418     BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
419     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
420     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
421     return modify(
422       position,modify_key_adaptor<Modifier,value_type,KeyFromValue>(mod,key));
423   }
424 
425   template<typename Modifier,typename Rollback>
modify_key(iterator position,Modifier mod,Rollback back_)426   bool modify_key(iterator position,Modifier mod,Rollback back_)
427   {
428     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
429     BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
430     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
431     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
432     return modify(
433       position,
434       modify_key_adaptor<Modifier,value_type,KeyFromValue>(mod,key),
435       modify_key_adaptor<Rollback,value_type,KeyFromValue>(back_,key));
436   }
437 
clear()438   void clear()BOOST_NOEXCEPT
439   {
440     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
441     this->final_clear_();
442   }
443 
swap(hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x)444   void swap(hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
445   {
446     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
447     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF(x);
448     this->final_swap_(x.final());
449   }
450 
451   /* observers */
452 
key_extractor() const453   key_from_value key_extractor()const{return key;}
hash_function() const454   hasher         hash_function()const{return hash_;}
key_eq() const455   key_equal      key_eq()const{return eq_;}
456 
457   /* lookup */
458 
459   /* Internally, these ops rely on const_iterator being the same
460    * type as iterator.
461    */
462 
463   /* Implementation note: When CompatibleKey is consistently promoted to
464    * KeyFromValue::result_type for equality comparison, the promotion is made
465    * once in advance to increase efficiency.
466    */
467 
468   template<typename CompatibleKey>
find(const CompatibleKey & k) const469   iterator find(const CompatibleKey& k)const
470   {
471     return find(k,hash_,eq_);
472   }
473 
474   template<
475     typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
476   >
find(const CompatibleKey & k,const CompatibleHash & hash,const CompatiblePred & eq) const477   iterator find(
478     const CompatibleKey& k,
479     const CompatibleHash& hash,const CompatiblePred& eq)const
480   {
481     return find(
482       k,hash,eq,promotes_1st_arg<CompatiblePred,CompatibleKey,key_type>());
483   }
484 
485   template<typename CompatibleKey>
count(const CompatibleKey & k) const486   size_type count(const CompatibleKey& k)const
487   {
488     return count(k,hash_,eq_);
489   }
490 
491   template<
492     typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
493   >
count(const CompatibleKey & k,const CompatibleHash & hash,const CompatiblePred & eq) const494   size_type count(
495     const CompatibleKey& k,
496     const CompatibleHash& hash,const CompatiblePred& eq)const
497   {
498     return count(
499       k,hash,eq,promotes_1st_arg<CompatiblePred,CompatibleKey,key_type>());
500   }
501 
502   template<typename CompatibleKey>
equal_range(const CompatibleKey & k) const503   std::pair<iterator,iterator> equal_range(const CompatibleKey& k)const
504   {
505     return equal_range(k,hash_,eq_);
506   }
507 
508   template<
509     typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
510   >
equal_range(const CompatibleKey & k,const CompatibleHash & hash,const CompatiblePred & eq) const511   std::pair<iterator,iterator> equal_range(
512     const CompatibleKey& k,
513     const CompatibleHash& hash,const CompatiblePred& eq)const
514   {
515     return equal_range(
516       k,hash,eq,promotes_1st_arg<CompatiblePred,CompatibleKey,key_type>());
517   }
518 
519   /* bucket interface */
520 
bucket_count() const521   size_type bucket_count()const BOOST_NOEXCEPT{return buckets.size();}
max_bucket_count() const522   size_type max_bucket_count()const BOOST_NOEXCEPT{return static_cast<size_type>(-1);}
523 
bucket_size(size_type n) const524   size_type bucket_size(size_type n)const
525   {
526     size_type res=0;
527     for(node_impl_pointer x=buckets.at(n)->prior();
528         x!=node_impl_pointer(0);x=node_alg::after_local(x)){
529       ++res;
530     }
531     return res;
532   }
533 
bucket(key_param_type k) const534   size_type bucket(key_param_type k)const
535   {
536     return buckets.position(hash_(k));
537   }
538 
begin(size_type n)539   local_iterator begin(size_type n)
540   {
541     return const_cast<const hashed_index*>(this)->begin(n);
542   }
543 
begin(size_type n) const544   const_local_iterator begin(size_type n)const
545   {
546     node_impl_pointer x=buckets.at(n)->prior();
547     if(x==node_impl_pointer(0))return end(n);
548     return make_local_iterator(node_type::from_impl(x));
549   }
550 
end(size_type n)551   local_iterator end(size_type n)
552   {
553     return const_cast<const hashed_index*>(this)->end(n);
554   }
555 
end(size_type) const556   const_local_iterator end(size_type)const
557   {
558     return make_local_iterator(0);
559   }
560 
cbegin(size_type n) const561   const_local_iterator cbegin(size_type n)const{return begin(n);}
cend(size_type n) const562   const_local_iterator cend(size_type n)const{return end(n);}
563 
local_iterator_to(const value_type & x)564   local_iterator local_iterator_to(const value_type& x)
565   {
566     return make_local_iterator(node_from_value<node_type>(&x));
567   }
568 
local_iterator_to(const value_type & x) const569   const_local_iterator local_iterator_to(const value_type& x)const
570   {
571     return make_local_iterator(node_from_value<node_type>(&x));
572   }
573 
574   /* hash policy */
575 
load_factor() const576   float load_factor()const BOOST_NOEXCEPT
577     {return static_cast<float>(size())/bucket_count();}
max_load_factor() const578   float max_load_factor()const BOOST_NOEXCEPT{return mlf;}
max_load_factor(float z)579   void  max_load_factor(float z){mlf=z;calculate_max_load();}
580 
rehash(size_type n)581   void rehash(size_type n)
582   {
583     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
584     if(size()<=max_load&&n<=bucket_count())return;
585 
586     size_type bc =(std::numeric_limits<size_type>::max)();
587     float     fbc=static_cast<float>(1+size()/mlf);
588     if(bc>fbc){
589       bc=static_cast<size_type>(fbc);
590       if(bc<n)bc=n;
591     }
592     unchecked_rehash(bc);
593   }
594 
reserve(size_type n)595   void reserve(size_type n)
596   {
597     rehash(static_cast<size_type>(std::ceil(static_cast<double>(n)/mlf)));
598   }
599 
600 BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
601   hashed_index(const ctor_args_list& args_list,const allocator_type& al):
602     super(args_list.get_tail(),al),
603     key(tuples::get<1>(args_list.get_head())),
604     hash_(tuples::get<2>(args_list.get_head())),
605     eq_(tuples::get<3>(args_list.get_head())),
606     buckets(al,header()->impl(),tuples::get<0>(args_list.get_head())),
607     mlf(1.0f)
608   {
609     calculate_max_load();
610   }
611 
hashed_index(const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x)612   hashed_index(
613     const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x):
614     super(x),
615 
616 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
617     safe_super(),
618 #endif
619 
620     key(x.key),
621     hash_(x.hash_),
622     eq_(x.eq_),
623     buckets(x.get_allocator(),header()->impl(),x.buckets.size()),
624     mlf(x.mlf),
625     max_load(x.max_load)
626   {
627     /* Copy ctor just takes the internal configuration objects from x. The rest
628      * is done in subsequent call to copy_().
629      */
630   }
631 
hashed_index(const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x,do_not_copy_elements_tag)632   hashed_index(
633     const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
634     do_not_copy_elements_tag):
635     super(x,do_not_copy_elements_tag()),
636 
637 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
638     safe_super(),
639 #endif
640 
641     key(x.key),
642     hash_(x.hash_),
643     eq_(x.eq_),
644     buckets(x.get_allocator(),header()->impl(),0),
645     mlf(1.0f)
646   {
647      calculate_max_load();
648   }
649 
~hashed_index()650   ~hashed_index()
651   {
652     /* the container is guaranteed to be empty by now */
653   }
654 
655 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
make_iterator(node_type * node)656   iterator make_iterator(node_type* node)
657   {
658     return iterator(node,this);
659   }
660 
make_iterator(node_type * node) const661   const_iterator make_iterator(node_type* node)const
662   {
663     return const_iterator(node,const_cast<hashed_index*>(this));
664   }
665 #else
make_iterator(node_type * node)666   iterator make_iterator(node_type* node)
667   {
668     return iterator(node);
669   }
670 
make_iterator(node_type * node) const671   const_iterator make_iterator(node_type* node)const
672   {
673     return const_iterator(node);
674   }
675 #endif
676 
make_local_iterator(node_type * node)677   local_iterator make_local_iterator(node_type* node)
678   {
679     return local_iterator(node);
680   }
681 
make_local_iterator(node_type * node) const682   const_local_iterator make_local_iterator(node_type* node)const
683   {
684     return const_local_iterator(node);
685   }
686 
copy_(const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x,const copy_map_type & map)687   void copy_(
688     const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
689     const copy_map_type& map)
690   {
691     copy_(x,map,Category());
692   }
693 
copy_(const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x,const copy_map_type & map,hashed_unique_tag)694   void copy_(
695     const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
696     const copy_map_type& map,hashed_unique_tag)
697   {
698     if(x.size()!=0){
699       node_impl_pointer end_org=x.header()->impl(),
700                         org=end_org,
701                         cpy=header()->impl();
702       do{
703         node_impl_pointer prev_org=org->prior(),
704                           prev_cpy=
705           static_cast<node_type*>(map.find(static_cast<final_node_type*>(
706             node_type::from_impl(prev_org))))->impl();
707         cpy->prior()=prev_cpy;
708         if(node_alg::is_first_of_bucket(org)){
709           node_impl_base_pointer buc_org=prev_org->next(),
710                                  buc_cpy=
711             buckets.begin()+(buc_org-x.buckets.begin());
712           prev_cpy->next()=buc_cpy;
713           buc_cpy->prior()=cpy;
714         }
715         else{
716           prev_cpy->next()=node_impl_type::base_pointer_from(cpy);
717         }
718         org=prev_org;
719         cpy=prev_cpy;
720       }while(org!=end_org);
721     }
722 
723     super::copy_(x,map);
724   }
725 
copy_(const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x,const copy_map_type & map,hashed_non_unique_tag)726   void copy_(
727     const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
728     const copy_map_type& map,hashed_non_unique_tag)
729   {
730     if(x.size()!=0){
731       node_impl_pointer end_org=x.header()->impl(),
732                         org=end_org,
733                         cpy=header()->impl();
734       do{
735         node_impl_pointer next_org=node_alg::after(org),
736                           next_cpy=
737           static_cast<node_type*>(map.find(static_cast<final_node_type*>(
738             node_type::from_impl(next_org))))->impl();
739         if(node_alg::is_first_of_bucket(next_org)){
740           node_impl_base_pointer buc_org=org->next(),
741                                  buc_cpy=
742             buckets.begin()+(buc_org-x.buckets.begin());
743           cpy->next()=buc_cpy;
744           buc_cpy->prior()=next_cpy;
745           next_cpy->prior()=cpy;
746         }
747         else{
748           if(org->next()==node_impl_type::base_pointer_from(next_org)){
749             cpy->next()=node_impl_type::base_pointer_from(next_cpy);
750           }
751           else{
752             cpy->next()=
753               node_impl_type::base_pointer_from(
754                 static_cast<node_type*>(map.find(static_cast<final_node_type*>(
755                   node_type::from_impl(
756                     node_impl_type::pointer_from(org->next())))))->impl());
757           }
758 
759           if(next_org->prior()!=org){
760             next_cpy->prior()=
761               static_cast<node_type*>(map.find(static_cast<final_node_type*>(
762                 node_type::from_impl(next_org->prior()))))->impl();
763           }
764           else{
765             next_cpy->prior()=cpy;
766           }
767         }
768         org=next_org;
769         cpy=next_cpy;
770       }while(org!=end_org);
771     }
772 
773     super::copy_(x,map);
774   }
775 
776   template<typename Variant>
insert_(value_param_type v,final_node_type * & x,Variant variant)777   final_node_type* insert_(
778     value_param_type v,final_node_type*& x,Variant variant)
779   {
780     reserve_for_insert(size()+1);
781 
782     std::size_t buc=find_bucket(v);
783     link_info   pos(buckets.at(buc));
784     if(!link_point(v,pos)){
785       return static_cast<final_node_type*>(
786         node_type::from_impl(node_impl_type::pointer_from(pos)));
787     }
788 
789     final_node_type* res=super::insert_(v,x,variant);
790     if(res==x)link(static_cast<node_type*>(x),pos);
791     return res;
792   }
793 
794   template<typename Variant>
insert_(value_param_type v,node_type * position,final_node_type * & x,Variant variant)795   final_node_type* insert_(
796     value_param_type v,node_type* position,final_node_type*& x,Variant variant)
797   {
798     reserve_for_insert(size()+1);
799 
800     std::size_t buc=find_bucket(v);
801     link_info   pos(buckets.at(buc));
802     if(!link_point(v,pos)){
803       return static_cast<final_node_type*>(
804         node_type::from_impl(node_impl_type::pointer_from(pos)));
805     }
806 
807     final_node_type* res=super::insert_(v,position,x,variant);
808     if(res==x)link(static_cast<node_type*>(x),pos);
809     return res;
810   }
811 
erase_(node_type * x)812   void erase_(node_type* x)
813   {
814     unlink(x);
815     super::erase_(x);
816 
817 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
818     detach_iterators(x);
819 #endif
820   }
821 
delete_all_nodes_()822   void delete_all_nodes_()
823   {
824     delete_all_nodes_(Category());
825   }
826 
delete_all_nodes_(hashed_unique_tag)827   void delete_all_nodes_(hashed_unique_tag)
828   {
829     for(node_impl_pointer x_end=header()->impl(),x=x_end->prior();x!=x_end;){
830       node_impl_pointer y=x->prior();
831       this->final_delete_node_(
832         static_cast<final_node_type*>(node_type::from_impl(x)));
833       x=y;
834     }
835   }
836 
delete_all_nodes_(hashed_non_unique_tag)837   void delete_all_nodes_(hashed_non_unique_tag)
838   {
839     for(node_impl_pointer x_end=header()->impl(),x=x_end->prior();x!=x_end;){
840       node_impl_pointer y=x->prior();
841       if(y->next()!=node_impl_type::base_pointer_from(x)&&
842          y->next()->prior()!=x){ /* n-1 of group */
843         /* Make the second node prior() pointer back-linked so that it won't
844          * refer to a deleted node when the time for its own destruction comes.
845          */
846 
847         node_impl_pointer first=node_impl_type::pointer_from(y->next());
848         first->next()->prior()=first;
849       }
850       this->final_delete_node_(
851         static_cast<final_node_type*>(node_type::from_impl(x)));
852       x=y;
853     }
854   }
855 
clear_()856   void clear_()
857   {
858     super::clear_();
859     buckets.clear(header()->impl());
860 
861 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
862     safe_super::detach_dereferenceable_iterators();
863 #endif
864   }
865 
swap_(hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x)866   void swap_(
867     hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
868   {
869     std::swap(key,x.key);
870     std::swap(hash_,x.hash_);
871     std::swap(eq_,x.eq_);
872     buckets.swap(x.buckets);
873     std::swap(mlf,x.mlf);
874     std::swap(max_load,x.max_load);
875 
876 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
877     safe_super::swap(x);
878 #endif
879 
880     super::swap_(x);
881   }
882 
swap_elements_(hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x)883   void swap_elements_(
884     hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
885   {
886     buckets.swap(x.buckets);
887     std::swap(mlf,x.mlf);
888     std::swap(max_load,x.max_load);
889 
890 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
891     safe_super::swap(x);
892 #endif
893 
894     super::swap_elements_(x);
895   }
896 
897   template<typename Variant>
replace_(value_param_type v,node_type * x,Variant variant)898   bool replace_(value_param_type v,node_type* x,Variant variant)
899   {
900     if(eq_(key(v),key(x->value()))){
901       return super::replace_(v,x,variant);
902     }
903 
904     unlink_undo undo;
905     unlink(x,undo);
906 
907     BOOST_TRY{
908       std::size_t  buc=find_bucket(v);
909       link_info    pos(buckets.at(buc));
910       if(link_point(v,pos)&&super::replace_(v,x,variant)){
911         link(x,pos);
912         return true;
913       }
914       undo();
915       return false;
916     }
917     BOOST_CATCH(...){
918       undo();
919       BOOST_RETHROW;
920     }
921     BOOST_CATCH_END
922   }
923 
modify_(node_type * x)924   bool modify_(node_type* x)
925   {
926     std::size_t buc;
927     bool        b;
928     BOOST_TRY{
929       buc=find_bucket(x->value());
930       b=in_place(x->impl(),key(x->value()),buc);
931     }
932     BOOST_CATCH(...){
933       erase_(x);
934       BOOST_RETHROW;
935     }
936     BOOST_CATCH_END
937     if(!b){
938       unlink(x);
939       BOOST_TRY{
940         link_info pos(buckets.at(buc));
941         if(!link_point(x->value(),pos)){
942           super::erase_(x);
943 
944 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
945           detach_iterators(x);
946 #endif
947           return false;
948         }
949         link(x,pos);
950       }
951       BOOST_CATCH(...){
952         super::erase_(x);
953 
954 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
955       detach_iterators(x);
956 #endif
957 
958         BOOST_RETHROW;
959       }
960       BOOST_CATCH_END
961     }
962 
963     BOOST_TRY{
964       if(!super::modify_(x)){
965         unlink(x);
966 
967 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
968         detach_iterators(x);
969 #endif
970         return false;
971       }
972       else return true;
973     }
974     BOOST_CATCH(...){
975       unlink(x);
976 
977 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
978       detach_iterators(x);
979 #endif
980 
981       BOOST_RETHROW;
982     }
983     BOOST_CATCH_END
984   }
985 
modify_rollback_(node_type * x)986   bool modify_rollback_(node_type* x)
987   {
988     std::size_t buc=find_bucket(x->value());
989     if(in_place(x->impl(),key(x->value()),buc)){
990       return super::modify_rollback_(x);
991     }
992 
993     unlink_undo undo;
994     unlink(x,undo);
995 
996     BOOST_TRY{
997       link_info pos(buckets.at(buc));
998       if(link_point(x->value(),pos)&&super::modify_rollback_(x)){
999         link(x,pos);
1000         return true;
1001       }
1002       undo();
1003       return false;
1004     }
1005     BOOST_CATCH(...){
1006       undo();
1007       BOOST_RETHROW;
1008     }
1009     BOOST_CATCH_END
1010   }
1011 
1012   /* comparison */
1013 
1014 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
1015   /* defect macro refers to class, not function, templates, but anyway */
1016 
1017   template<typename K,typename H,typename P,typename S,typename T,typename C>
1018   friend bool operator==(
1019     const hashed_index<K,H,P,S,T,C>&,const hashed_index<K,H,P,S,T,C>& y);
1020 #endif
1021 
equals(const hashed_index & x) const1022   bool equals(const hashed_index& x)const{return equals(x,Category());}
1023 
equals(const hashed_index & x,hashed_unique_tag) const1024   bool equals(const hashed_index& x,hashed_unique_tag)const
1025   {
1026     if(size()!=x.size())return false;
1027     for(const_iterator it=begin(),it_end=end(),it2_end=x.end();
1028         it!=it_end;++it){
1029       const_iterator it2=x.find(key(*it));
1030       if(it2==it2_end||!(*it==*it2))return false;
1031     }
1032     return true;
1033   }
1034 
equals(const hashed_index & x,hashed_non_unique_tag) const1035   bool equals(const hashed_index& x,hashed_non_unique_tag)const
1036   {
1037     if(size()!=x.size())return false;
1038     for(const_iterator it=begin(),it_end=end();it!=it_end;){
1039       const_iterator it2,it2_last;
1040       boost::tie(it2,it2_last)=x.equal_range(key(*it));
1041       if(it2==it2_last)return false;
1042 
1043       const_iterator it_last=make_iterator(
1044         node_type::from_impl(end_of_range(it.get_node()->impl())));
1045       if(std::distance(it,it_last)!=std::distance(it2,it2_last))return false;
1046 
1047       /* From is_permutation code in
1048        * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3068.pdf
1049        */
1050 
1051       for(;it!=it_last;++it,++it2){
1052         if(!(*it==*it2))break;
1053       }
1054       if(it!=it_last){
1055         for(const_iterator scan=it;scan!=it_last;++scan){
1056           if(std::find(it,scan,*scan)!=scan)continue;
1057           std::ptrdiff_t matches=std::count(it2,it2_last,*scan);
1058           if(matches==0||matches!=std::count(scan,it_last,*scan))return false;
1059         }
1060         it=it_last;
1061       }
1062     }
1063     return true;
1064   }
1065 
1066 #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
1067   /* serialization */
1068 
1069   template<typename Archive>
save_(Archive & ar,const unsigned int version,const index_saver_type & sm) const1070   void save_(
1071     Archive& ar,const unsigned int version,const index_saver_type& sm)const
1072   {
1073     ar<<serialization::make_nvp("position",buckets);
1074     super::save_(ar,version,sm);
1075   }
1076 
1077   template<typename Archive>
load_(Archive & ar,const unsigned int version,const index_loader_type & lm)1078   void load_(Archive& ar,const unsigned int version,const index_loader_type& lm)
1079   {
1080     ar>>serialization::make_nvp("position",buckets);
1081     super::load_(ar,version,lm);
1082   }
1083 #endif
1084 
1085 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
1086   /* invariant stuff */
1087 
invariant_() const1088   bool invariant_()const
1089   {
1090     if(size()==0||begin()==end()){
1091       if(size()!=0||begin()!=end())return false;
1092     }
1093     else{
1094       size_type s0=0;
1095       for(const_iterator it=begin(),it_end=end();it!=it_end;++it,++s0){}
1096       if(s0!=size())return false;
1097 
1098       size_type s1=0;
1099       for(size_type buc=0;buc<bucket_count();++buc){
1100         size_type ss1=0;
1101         for(const_local_iterator it=begin(buc),it_end=end(buc);
1102             it!=it_end;++it,++ss1){
1103           if(find_bucket(*it)!=buc)return false;
1104         }
1105         if(ss1!=bucket_size(buc))return false;
1106         s1+=ss1;
1107       }
1108       if(s1!=size())return false;
1109     }
1110 
1111     return super::invariant_();
1112   }
1113 
1114   /* This forwarding function eases things for the boost::mem_fn construct
1115    * in BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT. Actually,
1116    * final_check_invariant is already an inherited member function of index.
1117    */
check_invariant_() const1118   void check_invariant_()const{this->final_check_invariant_();}
1119 #endif
1120 
1121 private:
header() const1122   node_type* header()const{return this->final_header();}
1123 
find_bucket(value_param_type v) const1124   std::size_t find_bucket(value_param_type v)const
1125   {
1126     return bucket(key(v));
1127   }
1128 
1129   struct link_info_non_unique
1130   {
link_info_non_uniqueboost::multi_index::detail::hashed_index::link_info_non_unique1131     link_info_non_unique(node_impl_base_pointer pos):
1132       first(pos),last(node_impl_base_pointer(0)){}
1133 
operator const node_impl_base_pointer&boost::multi_index::detail::hashed_index::link_info_non_unique1134     operator const node_impl_base_pointer&()const{return this->first;}
1135 
1136     node_impl_base_pointer first,last;
1137   };
1138 
1139   typedef typename mpl::if_<
1140     is_same<Category,hashed_unique_tag>,
1141     node_impl_base_pointer,
1142     link_info_non_unique
1143   >::type                                link_info;
1144 
link_point(value_param_type v,link_info & pos)1145   bool link_point(value_param_type v,link_info& pos)
1146   {
1147     return link_point(v,pos,Category());
1148   }
1149 
link_point(value_param_type v,node_impl_base_pointer & pos,hashed_unique_tag)1150   bool link_point(
1151     value_param_type v,node_impl_base_pointer& pos,hashed_unique_tag)
1152   {
1153     for(node_impl_pointer x=pos->prior();x!=node_impl_pointer(0);
1154         x=node_alg::after_local(x)){
1155       if(eq_(key(v),key(node_type::from_impl(x)->value()))){
1156         pos=node_impl_type::base_pointer_from(x);
1157         return false;
1158       }
1159     }
1160     return true;
1161   }
1162 
link_point(value_param_type v,link_info_non_unique & pos,hashed_non_unique_tag)1163   bool link_point(
1164     value_param_type v,link_info_non_unique& pos,hashed_non_unique_tag)
1165   {
1166     for(node_impl_pointer x=pos.first->prior();x!=node_impl_pointer(0);
1167         x=node_alg::next_to_inspect(x)){
1168       if(eq_(key(v),key(node_type::from_impl(x)->value()))){
1169         pos.first=node_impl_type::base_pointer_from(x);
1170         pos.last=node_impl_type::base_pointer_from(last_of_range(x));
1171         return true;
1172       }
1173     }
1174     return true;
1175   }
1176 
last_of_range(node_impl_pointer x) const1177   node_impl_pointer last_of_range(node_impl_pointer x)const
1178   {
1179     return last_of_range(x,Category());
1180   }
1181 
last_of_range(node_impl_pointer x,hashed_unique_tag) const1182   node_impl_pointer last_of_range(node_impl_pointer x,hashed_unique_tag)const
1183   {
1184     return x;
1185   }
1186 
last_of_range(node_impl_pointer x,hashed_non_unique_tag) const1187   node_impl_pointer last_of_range(
1188     node_impl_pointer x,hashed_non_unique_tag)const
1189   {
1190     node_impl_base_pointer y=x->next();
1191     node_impl_pointer      z=y->prior();
1192     if(z==x){                      /* range of size 1 or 2 */
1193       node_impl_pointer yy=node_impl_type::pointer_from(y);
1194       return
1195         eq_(
1196           key(node_type::from_impl(x)->value()),
1197           key(node_type::from_impl(yy)->value()))?yy:x;
1198     }
1199     else if(z->prior()==x)               /* last of bucket */
1200       return x;
1201     else                                /* group of size>2 */
1202       return z;
1203   }
1204 
end_of_range(node_impl_pointer x) const1205   node_impl_pointer end_of_range(node_impl_pointer x)const
1206   {
1207     return end_of_range(x,Category());
1208   }
1209 
end_of_range(node_impl_pointer x,hashed_unique_tag) const1210   node_impl_pointer end_of_range(node_impl_pointer x,hashed_unique_tag)const
1211   {
1212     return node_alg::after(last_of_range(x));
1213   }
1214 
end_of_range(node_impl_pointer x,hashed_non_unique_tag) const1215   node_impl_pointer end_of_range(
1216     node_impl_pointer x,hashed_non_unique_tag)const
1217   {
1218     node_impl_base_pointer y=x->next();
1219     node_impl_pointer      z=y->prior();
1220     if(z==x){                      /* range of size 1 or 2 */
1221       node_impl_pointer yy=node_impl_type::pointer_from(y);
1222       if(!eq_(
1223            key(node_type::from_impl(x)->value()),
1224            key(node_type::from_impl(yy)->value())))yy=x;
1225       return yy->next()->prior()==yy?
1226                node_impl_type::pointer_from(yy->next()):
1227                yy->next()->prior();
1228     }
1229     else if(z->prior()==x)               /* last of bucket */
1230       return z;
1231     else                                /* group of size>2 */
1232       return z->next()->prior()==z?
1233                node_impl_type::pointer_from(z->next()):
1234                z->next()->prior();
1235   }
1236 
link(node_type * x,const link_info & pos)1237   void link(node_type* x,const link_info& pos)
1238   {
1239     link(x,pos,Category());
1240   }
1241 
link(node_type * x,node_impl_base_pointer pos,hashed_unique_tag)1242   void link(node_type* x,node_impl_base_pointer pos,hashed_unique_tag)
1243   {
1244     node_alg::link(x->impl(),pos,header()->impl());
1245   }
1246 
link(node_type * x,const link_info_non_unique & pos,hashed_non_unique_tag)1247   void link(node_type* x,const link_info_non_unique& pos,hashed_non_unique_tag)
1248   {
1249     if(pos.last==node_impl_base_pointer(0)){
1250       node_alg::link(x->impl(),pos.first,header()->impl());
1251     }
1252     else{
1253       node_alg::link(
1254         x->impl(),
1255         node_impl_type::pointer_from(pos.first),
1256         node_impl_type::pointer_from(pos.last));
1257     }
1258   }
1259 
unlink(node_type * x)1260   void unlink(node_type* x)
1261   {
1262     node_alg::unlink(x->impl());
1263   }
1264 
1265   typedef typename node_alg::unlink_undo unlink_undo;
1266 
unlink(node_type * x,unlink_undo & undo)1267   void unlink(node_type* x,unlink_undo& undo)
1268   {
1269     node_alg::unlink(x->impl(),undo);
1270   }
1271 
calculate_max_load()1272   void calculate_max_load()
1273   {
1274     float fml=static_cast<float>(mlf*static_cast<float>(bucket_count()));
1275     max_load=(std::numeric_limits<size_type>::max)();
1276     if(max_load>fml)max_load=static_cast<size_type>(fml);
1277   }
1278 
reserve_for_insert(size_type n)1279   void reserve_for_insert(size_type n)
1280   {
1281     if(n>max_load){
1282       size_type bc =(std::numeric_limits<size_type>::max)();
1283       float     fbc=static_cast<float>(1+static_cast<double>(n)/mlf);
1284       if(bc>fbc)bc =static_cast<size_type>(fbc);
1285       unchecked_rehash(bc);
1286     }
1287   }
1288 
unchecked_rehash(size_type n)1289   void unchecked_rehash(size_type n){unchecked_rehash(n,Category());}
1290 
unchecked_rehash(size_type n,hashed_unique_tag)1291   void unchecked_rehash(size_type n,hashed_unique_tag)
1292   {
1293     node_impl_type    cpy_end_node;
1294     node_impl_pointer cpy_end=node_impl_pointer(&cpy_end_node),
1295                       end_=header()->impl();
1296     bucket_array_type buckets_cpy(get_allocator(),cpy_end,n);
1297 
1298     if(size()!=0){
1299       auto_space<
1300         std::size_t,allocator_type>       hashes(get_allocator(),size());
1301       auto_space<
1302         node_impl_pointer,allocator_type> node_ptrs(get_allocator(),size());
1303       std::size_t                         i=0,size_=size();
1304       bool                                within_bucket=false;
1305       BOOST_TRY{
1306         for(;i!=size_;++i){
1307           node_impl_pointer x=end_->prior();
1308 
1309           /* only this can possibly throw */
1310           std::size_t h=hash_(key(node_type::from_impl(x)->value()));
1311 
1312           hashes.data()[i]=h;
1313           node_ptrs.data()[i]=x;
1314           within_bucket=!node_alg::unlink_last(end_);
1315           node_alg::link(x,buckets_cpy.at(buckets_cpy.position(h)),cpy_end);
1316         }
1317       }
1318       BOOST_CATCH(...){
1319         if(i!=0){
1320           std::size_t prev_buc=buckets.position(hashes.data()[i-1]);
1321           if(!within_bucket)prev_buc=~prev_buc;
1322 
1323           for(std::size_t j=i;j--;){
1324             std::size_t       buc=buckets.position(hashes.data()[j]);
1325             node_impl_pointer x=node_ptrs.data()[j];
1326             if(buc==prev_buc)node_alg::append(x,end_);
1327             else node_alg::link(x,buckets.at(buc),end_);
1328             prev_buc=buc;
1329           }
1330         }
1331         BOOST_RETHROW;
1332       }
1333       BOOST_CATCH_END
1334     }
1335 
1336     end_->prior()=cpy_end->prior()!=cpy_end?cpy_end->prior():end_;
1337     end_->next()=cpy_end->next();
1338     end_->prior()->next()->prior()=end_->next()->prior()->prior()=end_;
1339     buckets.swap(buckets_cpy);
1340     calculate_max_load();
1341   }
1342 
unchecked_rehash(size_type n,hashed_non_unique_tag)1343   void unchecked_rehash(size_type n,hashed_non_unique_tag)
1344   {
1345     node_impl_type    cpy_end_node;
1346     node_impl_pointer cpy_end=node_impl_pointer(&cpy_end_node),
1347                       end_=header()->impl();
1348     bucket_array_type buckets_cpy(get_allocator(),cpy_end,n);
1349 
1350     if(size()!=0){
1351       auto_space<
1352         std::size_t,allocator_type>       hashes(get_allocator(),size());
1353       auto_space<
1354         node_impl_pointer,allocator_type> node_ptrs(get_allocator(),size());
1355       std::size_t                         i=0;
1356       bool                                within_bucket=false;
1357       BOOST_TRY{
1358         for(;;++i){
1359           node_impl_pointer x=end_->prior();
1360           if(x==end_)break;
1361 
1362           /* only this can possibly throw */
1363           std::size_t h=hash_(key(node_type::from_impl(x)->value()));
1364 
1365           hashes.data()[i]=h;
1366           node_ptrs.data()[i]=x;
1367           std::pair<node_impl_pointer,bool> p=
1368             node_alg::unlink_last_group(end_);
1369           node_alg::link_range(
1370             p.first,x,buckets_cpy.at(buckets_cpy.position(h)),cpy_end);
1371           within_bucket=!(p.second);
1372         }
1373       }
1374       BOOST_CATCH(...){
1375         if(i!=0){
1376           std::size_t prev_buc=buckets.position(hashes.data()[i-1]);
1377           if(!within_bucket)prev_buc=~prev_buc;
1378 
1379           for(std::size_t j=i;j--;){
1380             std::size_t       buc=buckets.position(hashes.data()[j]);
1381             node_impl_pointer x=node_ptrs.data()[j],
1382                               y=
1383               x->prior()->next()!=node_impl_type::base_pointer_from(x)&&
1384               x->prior()->next()->prior()!=x?
1385                 node_impl_type::pointer_from(x->prior()->next()):x;
1386             node_alg::unlink_range(y,x);
1387             if(buc==prev_buc)node_alg::append_range(y,x,end_);
1388             else node_alg::link_range(y,x,buckets.at(buc),end_);
1389             prev_buc=buc;
1390           }
1391         }
1392         BOOST_RETHROW;
1393       }
1394       BOOST_CATCH_END
1395     }
1396 
1397     end_->prior()=cpy_end->prior()!=cpy_end?cpy_end->prior():end_;
1398     end_->next()=cpy_end->next();
1399     end_->prior()->next()->prior()=end_->next()->prior()->prior()=end_;
1400     buckets.swap(buckets_cpy);
1401     calculate_max_load();
1402   }
1403 
in_place(node_impl_pointer x,key_param_type k,std::size_t buc) const1404   bool in_place(node_impl_pointer x,key_param_type k,std::size_t buc)const
1405   {
1406     return in_place(x,k,buc,Category());
1407   }
1408 
in_place(node_impl_pointer x,key_param_type k,std::size_t buc,hashed_unique_tag) const1409   bool in_place(
1410     node_impl_pointer x,key_param_type k,std::size_t buc,
1411     hashed_unique_tag)const
1412   {
1413     bool found=false;
1414     for(node_impl_pointer y=buckets.at(buc)->prior();
1415         y!=node_impl_pointer(0);y=node_alg::after_local(y)){
1416       if(y==x)found=true;
1417       else if(eq_(k,key(node_type::from_impl(y)->value())))return false;
1418     }
1419     return found;
1420   }
1421 
in_place(node_impl_pointer x,key_param_type k,std::size_t buc,hashed_non_unique_tag) const1422   bool in_place(
1423     node_impl_pointer x,key_param_type k,std::size_t buc,
1424     hashed_non_unique_tag)const
1425   {
1426     bool found=false;
1427     int  range_size=0;
1428     for(node_impl_pointer y=buckets.at(buc)->prior();y!=node_impl_pointer(0);){
1429       if(node_alg::is_first_of_group(y)){ /* group of 3 or more */
1430         if(y==x){
1431           /* in place <-> equal to some other member of the group */
1432           return eq_(
1433             k,
1434             key(node_type::from_impl(
1435               node_impl_type::pointer_from(y->next()))->value()));
1436         }
1437         else{
1438           node_impl_pointer z=
1439             node_alg::after_local(y->next()->prior()); /* end of range */
1440           if(eq_(k,key(node_type::from_impl(y)->value()))){
1441             if(found)return false; /* x lies outside */
1442             do{
1443               if(y==x)return true;
1444               y=node_alg::after_local(y);
1445             }while(y!=z);
1446             return false; /* x not found */
1447           }
1448           else{
1449             if(range_size==1&&!found)return false;
1450             if(range_size==2)return found;
1451             range_size=0;
1452             y=z; /* skip range (and potentially x, too, which is fine) */
1453           }
1454         }
1455       }
1456       else{ /* group of 1 or 2 */
1457         if(y==x){
1458           if(range_size==1)return true;
1459           range_size=1;
1460           found=true;
1461         }
1462         else if(eq_(k,key(node_type::from_impl(y)->value()))){
1463           if(range_size==0&&found)return false;
1464           if(range_size==1&&!found)return false;
1465           if(range_size==2)return false;
1466           ++range_size;
1467         }
1468         else{
1469           if(range_size==1&&!found)return false;
1470           if(range_size==2)return found;
1471           range_size=0;
1472         }
1473         y=node_alg::after_local(y);
1474       }
1475     }
1476     return found;
1477   }
1478 
1479 #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
detach_iterators(node_type * x)1480   void detach_iterators(node_type* x)
1481   {
1482     iterator it=make_iterator(x);
1483     safe_mode::detach_equivalent_iterators(it);
1484   }
1485 #endif
1486 
1487   template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
emplace_impl(BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)1488   std::pair<iterator,bool> emplace_impl(BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
1489   {
1490     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
1491     std::pair<final_node_type*,bool>p=
1492       this->final_emplace_(BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
1493     return std::pair<iterator,bool>(make_iterator(p.first),p.second);
1494   }
1495 
1496   template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
emplace_hint_impl(iterator position,BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)1497   iterator emplace_hint_impl(
1498     iterator position,BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
1499   {
1500     BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
1501     BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
1502     BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
1503     std::pair<final_node_type*,bool>p=
1504       this->final_emplace_hint_(
1505         static_cast<final_node_type*>(position.get_node()),
1506         BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
1507     return make_iterator(p.first);
1508   }
1509 
1510   template<
1511     typename CompatibleHash,typename CompatiblePred
1512   >
find(const key_type & k,const CompatibleHash & hash,const CompatiblePred & eq,mpl::true_) const1513   iterator find(
1514     const key_type& k,
1515     const CompatibleHash& hash,const CompatiblePred& eq,mpl::true_)const
1516   {
1517     return find(k,hash,eq,mpl::false_());
1518   }
1519 
1520   template<
1521     typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
1522   >
find(const CompatibleKey & k,const CompatibleHash & hash,const CompatiblePred & eq,mpl::false_) const1523   iterator find(
1524     const CompatibleKey& k,
1525     const CompatibleHash& hash,const CompatiblePred& eq,mpl::false_)const
1526   {
1527     std::size_t buc=buckets.position(hash(k));
1528     for(node_impl_pointer x=buckets.at(buc)->prior();
1529         x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
1530       if(eq(k,key(node_type::from_impl(x)->value()))){
1531         return make_iterator(node_type::from_impl(x));
1532       }
1533     }
1534     return end();
1535   }
1536 
1537   template<
1538     typename CompatibleHash,typename CompatiblePred
1539   >
count(const key_type & k,const CompatibleHash & hash,const CompatiblePred & eq,mpl::true_) const1540   size_type count(
1541     const key_type& k,
1542     const CompatibleHash& hash,const CompatiblePred& eq,mpl::true_)const
1543   {
1544     return count(k,hash,eq,mpl::false_());
1545   }
1546 
1547   template<
1548     typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
1549   >
count(const CompatibleKey & k,const CompatibleHash & hash,const CompatiblePred & eq,mpl::false_) const1550   size_type count(
1551     const CompatibleKey& k,
1552     const CompatibleHash& hash,const CompatiblePred& eq,mpl::false_)const
1553   {
1554     std::size_t buc=buckets.position(hash(k));
1555     for(node_impl_pointer x=buckets.at(buc)->prior();
1556         x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
1557       if(eq(k,key(node_type::from_impl(x)->value()))){
1558         size_type         res=0;
1559         node_impl_pointer y=end_of_range(x);
1560         do{
1561           ++res;
1562           x=node_alg::after(x);
1563         }while(x!=y);
1564         return res;
1565       }
1566     }
1567     return 0;
1568   }
1569 
1570   template<
1571     typename CompatibleHash,typename CompatiblePred
1572   >
equal_range(const key_type & k,const CompatibleHash & hash,const CompatiblePred & eq,mpl::true_) const1573   std::pair<iterator,iterator> equal_range(
1574     const key_type& k,
1575     const CompatibleHash& hash,const CompatiblePred& eq,mpl::true_)const
1576   {
1577     return equal_range(k,hash,eq,mpl::false_());
1578   }
1579 
1580   template<
1581     typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
1582   >
equal_range(const CompatibleKey & k,const CompatibleHash & hash,const CompatiblePred & eq,mpl::false_) const1583   std::pair<iterator,iterator> equal_range(
1584     const CompatibleKey& k,
1585     const CompatibleHash& hash,const CompatiblePred& eq,mpl::false_)const
1586   {
1587     std::size_t buc=buckets.position(hash(k));
1588     for(node_impl_pointer x=buckets.at(buc)->prior();
1589         x!=node_impl_pointer(0);x=node_alg::next_to_inspect(x)){
1590       if(eq(k,key(node_type::from_impl(x)->value()))){
1591         return std::pair<iterator,iterator>(
1592           make_iterator(node_type::from_impl(x)),
1593           make_iterator(node_type::from_impl(end_of_range(x))));
1594       }
1595     }
1596     return std::pair<iterator,iterator>(end(),end());
1597   }
1598 
1599   key_from_value               key;
1600   hasher                       hash_;
1601   key_equal                    eq_;
1602   bucket_array_type            buckets;
1603   float                        mlf;
1604   size_type                    max_load;
1605 
1606 #if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
1607     BOOST_WORKAROUND(__MWERKS__,<=0x3003)
1608 #pragma parse_mfunc_templ reset
1609 #endif
1610 };
1611 
1612 /* comparison */
1613 
1614 template<
1615   typename KeyFromValue,typename Hash,typename Pred,
1616   typename SuperMeta,typename TagList,typename Category
1617 >
operator ==(const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x,const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & y)1618 bool operator==(
1619   const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
1620   const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
1621 {
1622   return x.equals(y);
1623 }
1624 
1625 template<
1626   typename KeyFromValue,typename Hash,typename Pred,
1627   typename SuperMeta,typename TagList,typename Category
1628 >
operator !=(const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x,const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & y)1629 bool operator!=(
1630   const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
1631   const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
1632 {
1633   return !(x==y);
1634 }
1635 
1636 /*  specialized algorithms */
1637 
1638 template<
1639   typename KeyFromValue,typename Hash,typename Pred,
1640   typename SuperMeta,typename TagList,typename Category
1641 >
swap(hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & x,hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> & y)1642 void swap(
1643   hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
1644   hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
1645 {
1646   x.swap(y);
1647 }
1648 
1649 } /* namespace multi_index::detail */
1650 
1651 /* hashed index specifiers */
1652 
1653 template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
1654 struct hashed_unique
1655 {
1656   typedef typename detail::hashed_index_args<
1657     Arg1,Arg2,Arg3,Arg4>                           index_args;
1658   typedef typename index_args::tag_list_type::type tag_list_type;
1659   typedef typename index_args::key_from_value_type key_from_value_type;
1660   typedef typename index_args::hash_type           hash_type;
1661   typedef typename index_args::pred_type           pred_type;
1662 
1663   template<typename Super>
1664   struct node_class
1665   {
1666     typedef detail::hashed_index_node<Super,detail::hashed_unique_tag> type;
1667   };
1668 
1669   template<typename SuperMeta>
1670   struct index_class
1671   {
1672     typedef detail::hashed_index<
1673       key_from_value_type,hash_type,pred_type,
1674       SuperMeta,tag_list_type,detail::hashed_unique_tag> type;
1675   };
1676 };
1677 
1678 template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
1679 struct hashed_non_unique
1680 {
1681   typedef typename detail::hashed_index_args<
1682     Arg1,Arg2,Arg3,Arg4>                           index_args;
1683   typedef typename index_args::tag_list_type::type tag_list_type;
1684   typedef typename index_args::key_from_value_type key_from_value_type;
1685   typedef typename index_args::hash_type           hash_type;
1686   typedef typename index_args::pred_type           pred_type;
1687 
1688   template<typename Super>
1689   struct node_class
1690   {
1691     typedef detail::hashed_index_node<
1692       Super,detail::hashed_non_unique_tag> type;
1693   };
1694 
1695   template<typename SuperMeta>
1696   struct index_class
1697   {
1698     typedef detail::hashed_index<
1699       key_from_value_type,hash_type,pred_type,
1700       SuperMeta,tag_list_type,detail::hashed_non_unique_tag> type;
1701   };
1702 };
1703 
1704 } /* namespace multi_index */
1705 
1706 } /* namespace boost */
1707 
1708 /* Boost.Foreach compatibility */
1709 
1710 template<
1711   typename KeyFromValue,typename Hash,typename Pred,
1712   typename SuperMeta,typename TagList,typename Category
1713 >
boost_foreach_is_noncopyable(boost::multi_index::detail::hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> * &,boost::foreach::tag)1714 inline boost::mpl::true_* boost_foreach_is_noncopyable(
1715   boost::multi_index::detail::hashed_index<
1716     KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>*&,
1717   boost::foreach::tag)
1718 {
1719   return 0;
1720 }
1721 
1722 #undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
1723 #undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT_OF
1724 
1725 #endif
1726