Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/multi_index/hashed_index.hpp @ 44

Last change on this file since 44 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 29.3 KB
Line 
1/* Copyright 2003-2007 Joaquín M López Muñoz.
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)&&(_MSC_VER>=1200)
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/limits.hpp>
23#include <boost/mpl/push_front.hpp>
24#include <boost/multi_index/detail/access_specifier.hpp>
25#include <boost/multi_index/detail/auto_space.hpp>
26#include <boost/multi_index/detail/bucket_array.hpp>
27#include <boost/multi_index/detail/hash_index_iterator.hpp>
28#include <boost/multi_index/detail/modify_key_adaptor.hpp>
29#include <boost/multi_index/detail/safe_ctr_proxy.hpp>
30#include <boost/multi_index/detail/safe_mode.hpp>
31#include <boost/multi_index/detail/scope_guard.hpp>
32#include <boost/multi_index/hashed_index_fwd.hpp>
33#include <boost/tuple/tuple.hpp>
34#include <cstddef>
35#include <functional>
36#include <utility>
37
38#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
39#include <boost/serialization/nvp.hpp>
40#endif
41
42#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
43#define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT                       \
44  detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)=                 \
45    detail::make_obj_guard(*this,&hashed_index::check_invariant_);           \
46  BOOST_JOIN(check_invariant_,__LINE__).touch();
47#else
48#define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
49#endif
50
51namespace boost{
52
53namespace multi_index{
54
55namespace detail{
56
57/* hashed_index adds a layer of hashed indexing to a given Super */
58
59/* Most of the implementation of unique and non-unique indices is
60 * shared. We tell from one another on instantiation time by using
61 * these tags.
62 */
63
64struct hashed_unique_tag{};
65struct hashed_non_unique_tag{};
66
67template<
68  typename KeyFromValue,typename Hash,typename Pred,
69  typename SuperMeta,typename TagList,typename Category
70>
71class hashed_index:
72  BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS SuperMeta::type
73
74#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
75#if BOOST_WORKAROUND(BOOST_MSVC,<1300)
76  ,public safe_ctr_proxy_impl<
77    hashed_index_iterator<
78      hashed_index_node<typename SuperMeta::type::node_type>,
79      bucket_array<typename SuperMeta::type::final_allocator_type> >,
80    hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> >
81#else
82  ,public safe_mode::safe_container<
83    hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> >
84#endif
85#endif
86
87{ 
88#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
89    BOOST_WORKAROUND(__MWERKS__,<=0x3003)
90/* The "ISO C++ Template Parser" option in CW8.3 has a problem with the
91 * lifetime of const references bound to temporaries --precisely what
92 * scopeguards are.
93 */
94
95#pragma parse_mfunc_templ off
96#endif
97
98  typedef typename SuperMeta::type                   super;
99
100protected:
101  typedef hashed_index_node<
102    typename super::node_type>                       node_type;
103  typedef bucket_array<
104    typename super::final_allocator_type>            bucket_array_type;
105
106public:
107  /* types */
108
109  typedef typename KeyFromValue::result_type         key_type;
110  typedef typename node_type::value_type             value_type;
111  typedef KeyFromValue                               key_from_value;
112  typedef Hash                                       hasher;
113  typedef Pred                                       key_equal;
114  typedef tuple<std::size_t,
115    key_from_value,hasher,key_equal>                 ctor_args;
116  typedef typename super::final_allocator_type       allocator_type;
117  typedef typename allocator_type::pointer           pointer;
118  typedef typename allocator_type::const_pointer     const_pointer;
119  typedef typename allocator_type::reference         reference;
120  typedef typename allocator_type::const_reference   const_reference;
121  typedef std::size_t                                size_type;     
122  typedef std::ptrdiff_t                             difference_type;
123
124#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
125#if BOOST_WORKAROUND(BOOST_MSVC,<1300)
126  typedef safe_mode::safe_iterator<
127    hashed_index_iterator<
128      node_type,bucket_array_type>,
129    safe_ctr_proxy<
130      hashed_index_iterator<
131        node_type,bucket_array_type> > >             iterator;
132#else
133  typedef safe_mode::safe_iterator<
134    hashed_index_iterator<
135      node_type,bucket_array_type>,
136    hashed_index>                                    iterator;
137#endif
138#else
139  typedef hashed_index_iterator<
140    node_type,bucket_array_type>                     iterator;
141#endif
142
143  typedef iterator                                   const_iterator;
144
145  typedef iterator                                   local_iterator;
146  typedef const_iterator                             const_local_iterator;
147  typedef TagList                                    tag_list;
148
149protected:
150  typedef typename super::final_node_type     final_node_type;
151  typedef tuples::cons<
152    ctor_args, 
153    typename super::ctor_args_list>           ctor_args_list;
154  typedef typename mpl::push_front<
155    typename super::index_type_list,
156    hashed_index>::type                       index_type_list;
157  typedef typename mpl::push_front<
158    typename super::iterator_type_list,
159    iterator>::type                           iterator_type_list;
160  typedef typename mpl::push_front<
161    typename super::const_iterator_type_list,
162    const_iterator>::type                     const_iterator_type_list;
163  typedef typename super::copy_map_type       copy_map_type;
164
165#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
166  typedef typename super::index_saver_type    index_saver_type;
167  typedef typename super::index_loader_type   index_loader_type;
168#endif
169
170private:
171#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
172#if BOOST_WORKAROUND(BOOST_MSVC,<1300)
173  typedef safe_ctr_proxy_impl<
174    hashed_index_iterator<
175      node_type,
176      bucket_array_type>,
177    hashed_index>                             safe_super;
178#else
179  typedef safe_mode::safe_container<
180    hashed_index>                             safe_super;
181#endif
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
188public:
189
190  /* construct/destroy/copy
191   * Default and copy ctors are in the protected section as indices are
192   * not supposed to be created on their own. No range ctor either.
193   */
194
195  hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& operator=(
196    const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
197  {
198    this->final()=x.final();
199    return *this;
200  }
201
202  allocator_type get_allocator()const
203  {
204    return this->final().get_allocator();
205  }
206
207  /* size and capacity */
208
209  bool      empty()const{return this->final_empty_();}
210  size_type size()const{return this->final_size_();}
211  size_type max_size()const{return this->final_max_size_();}
212
213  /* iterators */
214
215  iterator begin()
216  {
217    return make_iterator(
218      node_type::from_impl(buckets.at(first_bucket)->next()));
219  }
220
221  const_iterator begin()const
222  {
223    return make_iterator(
224      node_type::from_impl(buckets.at(first_bucket)->next()));
225  }
226
227  iterator       end(){return make_iterator(header());}
228  const_iterator end()const{return make_iterator(header());}
229
230  /* modifiers */
231
232  std::pair<iterator,bool> insert(value_param_type x)
233  {
234    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
235    std::pair<final_node_type*,bool> p=this->final_insert_(x);
236    return std::pair<iterator,bool>(make_iterator(p.first),p.second);
237  }
238
239  iterator insert(iterator position,value_param_type x)
240  {
241    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
242    BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
243    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
244    std::pair<final_node_type*,bool> p=this->final_insert_(
245      x,static_cast<final_node_type*>(position.get_node()));
246    return make_iterator(p.first);
247  }
248   
249  template<typename InputIterator>
250  void insert(InputIterator first,InputIterator last)
251  {
252    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
253    iterator hint=end();
254    for(;first!=last;++first)hint=insert(hint,*first);
255  }
256
257  iterator erase(iterator position)
258  {
259    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
260    BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
261    BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
262    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
263    this->final_erase_(static_cast<final_node_type*>(position++.get_node()));
264    return position;
265  }
266
267  size_type erase(key_param_type k)
268  {
269    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
270
271    size_type               s=0;
272    std::size_t             buc=buckets.position(hash(k));
273    hashed_index_node_impl* x=buckets.at(buc);
274    hashed_index_node_impl* y=x->next();
275    while(y!=x){
276      if(eq(k,key(node_type::from_impl(y)->value()))){
277        bool b;
278        do{
279          hashed_index_node_impl* z=y->next();
280          b=z!=x&&eq(
281            key(node_type::from_impl(y)->value()),
282            key(node_type::from_impl(z)->value()));
283          this->final_erase_(
284            static_cast<final_node_type*>(node_type::from_impl(y)));
285          y=z;
286          ++s;
287        }while(b);
288        break;
289      }
290      y=y->next();
291    }
292    return s;
293  }
294
295  iterator erase(iterator first,iterator last)
296  {
297    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
298    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
299    BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,*this);
300    BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,*this);
301    BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
302    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
303    while(first!=last){
304      first=erase(first);
305    }
306    return first;
307  }
308
309  bool replace(iterator position,value_param_type x)
310  {
311    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
312    BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
313    BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
314    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
315    return this->final_replace_(
316      x,static_cast<final_node_type*>(position.get_node()));
317  }
318
319  template<typename Modifier>
320  bool modify(iterator position,Modifier mod)
321  {
322    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
323    BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
324    BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
325    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
326
327#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
328    /* MSVC++ 6.0 optimizer on safe mode code chokes if this
329     * this is not added. Left it for all compilers as it does no
330     * harm.
331     */
332
333    position.detach();
334#endif
335
336    return this->final_modify_(
337      mod,static_cast<final_node_type*>(position.get_node()));
338  }
339
340  template<typename Modifier>
341  bool modify_key(iterator position,Modifier mod)
342  {
343    BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
344    BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
345    BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
346    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
347    return modify(
348      position,modify_key_adaptor<Modifier,value_type,KeyFromValue>(mod,key));
349  }
350
351  void clear()
352  {
353    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
354    this->final_clear_();
355  }
356
357  void swap(hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
358  {
359    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
360    this->final_swap_(x.final());
361  }
362
363  /* observers */
364
365  key_from_value key_extractor()const{return key;}
366  hasher         hash_function()const{return hash;}
367  key_equal      key_eq()const{return eq;}
368 
369  /* lookup */
370
371  /* Internally, these ops rely on const_iterator being the same
372   * type as iterator.
373   */
374
375  template<typename CompatibleKey>
376  iterator find(const CompatibleKey& k)const
377  {
378    return find(k,hash,eq);
379  }
380
381  template<
382    typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
383  >
384  iterator find(
385    const CompatibleKey& k,
386    const CompatibleHash& hash,const CompatiblePred& eq)const
387  {
388    std::size_t             buc=buckets.position(hash(k));
389    hashed_index_node_impl* x=buckets.at(buc);
390    hashed_index_node_impl* y=x->next();
391    while(y!=x){
392      if(eq(k,key(node_type::from_impl(y)->value()))){
393        return make_iterator(node_type::from_impl(y));
394      }
395      y=y->next();
396    }
397    return end();
398  }
399
400  template<typename CompatibleKey>
401  size_type count(const CompatibleKey& k)const
402  {
403    return count(k,hash,eq);
404  }
405
406  template<
407    typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
408  >
409  size_type count(
410    const CompatibleKey& k,
411    const CompatibleHash& hash,const CompatiblePred& eq)const
412  {
413    size_type               res=0;
414    std::size_t             buc=buckets.position(hash(k));
415    hashed_index_node_impl* x=buckets.at(buc);
416    hashed_index_node_impl* y=x->next();
417    while(y!=x){
418      if(eq(k,key(node_type::from_impl(y)->value()))){
419        do{
420          ++res;
421          y=y->next();
422        }while(y!=x&&eq(k,key(node_type::from_impl(y)->value())));
423        break;
424      }
425      y=y->next();
426    }
427    return res;
428  }
429
430  template<typename CompatibleKey>
431  std::pair<iterator,iterator> equal_range(const CompatibleKey& k)const
432  {
433    return equal_range(k,hash,eq);
434  }
435
436  template<
437    typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
438  >
439  std::pair<iterator,iterator> equal_range(
440    const CompatibleKey& k,
441    const CompatibleHash& hash,const CompatiblePred& eq)const
442  {
443    std::size_t             buc=buckets.position(hash(k));
444    hashed_index_node_impl* x=buckets.at(buc);
445    hashed_index_node_impl* y=x->next();
446    while(y!=x){
447      if(eq(k,key(node_type::from_impl(y)->value()))){
448        hashed_index_node_impl* y0=y;
449        do{
450          y=y->next();
451        }while(y!=x&&eq(k,key(node_type::from_impl(y)->value())));
452        if(y==x){
453          do{
454            ++y;
455          }while(y==y->next());
456          y=y->next();
457        }
458        return std::pair<iterator,iterator>(
459          make_iterator(node_type::from_impl(y0)),
460          make_iterator(node_type::from_impl(y)));
461      }
462      y=y->next();
463    }
464    return std::pair<iterator,iterator>(end(),end());
465  }
466
467  /* bucket interface */
468
469  size_type bucket_count()const{return buckets.size();}
470  size_type max_bucket_count()const{return static_cast<size_type>(-1);}
471
472  size_type bucket_size(size_type n)const
473  {
474    size_type               res=0;
475    hashed_index_node_impl* x=buckets.at(n);
476    hashed_index_node_impl* y=x->next();
477    while(y!=x){
478      ++res;
479      y=y->next();
480    }
481    return res;
482  }
483
484  size_type bucket(key_param_type k)const
485  {
486    return buckets.position(hash(k));
487  }
488
489  local_iterator begin(size_type n)
490  {
491    return const_cast<const hashed_index*>(this)->begin(n);
492  }
493
494  const_local_iterator begin(size_type n)const
495  {
496    hashed_index_node_impl* x=buckets.at(n);
497    hashed_index_node_impl* y=x->next();
498    if(y==x)return end();
499    return make_iterator(node_type::from_impl(y));
500  }
501
502  local_iterator end(size_type n)
503  {
504    return const_cast<const hashed_index*>(this)->end(n);
505  }
506
507  const_local_iterator end(size_type n)const
508  {
509    hashed_index_node_impl* x=buckets.at(n);
510    if(x==x->next())return end();
511    do{
512      ++x;
513    }while(x==x->next());
514    return make_iterator(node_type::from_impl(x->next()));
515  }
516
517  /* hash policy */
518
519  float load_factor()const{return static_cast<float>(size())/bucket_count();}
520  float max_load_factor()const{return mlf;}
521  void  max_load_factor(float z){mlf=z;calculate_max_load();}
522
523  void rehash(size_type n)
524  {
525    BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
526    if(size()<max_load&&n<=bucket_count())return;
527
528    size_type bc =(std::numeric_limits<size_type>::max)();
529    float     fbc=static_cast<float>(1+size()/mlf);
530    if(bc>fbc){
531      bc=static_cast<size_type>(fbc);
532      if(bc<n)bc=n;
533    }
534    unchecked_rehash(bc);
535  }
536
537BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
538  hashed_index(const ctor_args_list& args_list,const allocator_type& al):
539    super(args_list.get_tail(),al),
540    key(tuples::get<1>(args_list.get_head())),
541    hash(tuples::get<2>(args_list.get_head())),
542    eq(tuples::get<3>(args_list.get_head())),
543    buckets(al,header()->impl(),tuples::get<0>(args_list.get_head())),
544    mlf(1.0),
545    first_bucket(buckets.size())
546  {
547    calculate_max_load();
548  }
549
550  hashed_index(
551    const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x):
552    super(x),
553
554#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
555    safe_super(),
556#endif
557
558    key(x.key),
559    hash(x.hash),
560    eq(x.eq),
561    buckets(x.get_allocator(),header()->impl(),x.buckets.size()),
562    mlf(x.mlf),
563    max_load(x.max_load),
564    first_bucket(x.first_bucket)
565  {
566    /* Copy ctor just takes the internal configuration objects from x. The rest
567     * is done in subsequent call to copy_().
568     */
569  }
570
571  ~hashed_index()
572  {
573    /* the container is guaranteed to be empty by now */
574  }
575
576#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
577  iterator make_iterator(node_type* node)
578  {
579    return iterator(node,&buckets,this);
580  }
581
582  const_iterator make_iterator(node_type* node)const
583  {
584    return const_iterator(
585      node,
586      &const_cast<bucket_array_type&>(buckets),
587      const_cast<hashed_index*>(this));
588  }
589#else
590  iterator make_iterator(node_type* node)
591  {
592    return iterator(node,&buckets);
593  }
594
595  const_iterator make_iterator(node_type* node)const
596  {
597    return const_iterator(node,&const_cast<bucket_array_type&>(buckets));
598  }
599#endif
600
601  void copy_(
602    const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
603    const copy_map_type& map)
604  {
605    for(hashed_index_node_impl* begin_org=x.buckets.begin(),
606                              * begin_cpy=buckets.begin(),
607                              * end_org=x.buckets.end();
608        begin_org!=end_org;++begin_org,++begin_cpy){
609
610      hashed_index_node_impl* next_org=begin_org->next();
611      hashed_index_node_impl* cpy=begin_cpy;
612      while(next_org!=begin_org){
613        cpy->next()=
614          static_cast<node_type*>(
615            map.find(
616              static_cast<final_node_type*>(
617                node_type::from_impl(next_org))))->impl();
618        next_org=next_org->next();
619        cpy=cpy->next();
620      }
621      cpy->next()=begin_cpy;
622    }
623
624    super::copy_(x,map);
625  }
626
627  node_type* insert_(value_param_type v,node_type* x)
628  {
629    reserve(size()+1);
630
631    std::size_t             buc=find_bucket(v);
632    hashed_index_node_impl* pos=buckets.at(buc);
633    if(!link_point(v,pos,Category()))return node_type::from_impl(pos);
634
635    node_type* res=static_cast<node_type*>(super::insert_(v,x));
636    if(res==x){
637      link(x,pos);
638      if(first_bucket>buc)first_bucket=buc;
639    }
640    return res;
641  }
642
643  node_type* insert_(value_param_type v,node_type* position,node_type* x)
644  {
645    reserve(size()+1);
646
647    std::size_t             buc=find_bucket(v);
648    hashed_index_node_impl* pos=buckets.at(buc);
649    if(!link_point(v,pos,Category()))return node_type::from_impl(pos);
650
651    node_type* res=static_cast<node_type*>(super::insert_(v,position,x));
652    if(res==x){
653      link(x,pos);
654      if(first_bucket>buc)first_bucket=buc;
655    }
656    return res;
657  }
658
659  void erase_(node_type* x)
660  {
661    unlink(x);
662    first_bucket=buckets.first_nonempty(first_bucket);
663    super::erase_(x);
664
665#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
666    detach_iterators(x);
667#endif
668  }
669
670  void delete_all_nodes_()
671  {
672    for(hashed_index_node_impl* x=buckets.begin(),*x_end=buckets.end();
673        x!=x_end;++x){
674      hashed_index_node_impl* y=x->next();
675      while(y!=x){
676        hashed_index_node_impl* z=y->next();
677        this->final_delete_node_(
678          static_cast<final_node_type*>(node_type::from_impl(y)));
679        y=z;
680      }
681    }
682  }
683
684  void clear_()
685  {
686    super::clear_();
687    buckets.clear();
688    first_bucket=buckets.size();
689
690#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
691    safe_super::detach_dereferenceable_iterators();
692#endif
693  }
694
695  void swap_(
696    hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
697  {
698    std::swap(key,x.key);
699    std::swap(hash,x.hash);
700    std::swap(eq,x.eq);
701    buckets.swap(x.buckets);
702    std::swap(mlf,x.mlf);
703    std::swap(max_load,x.max_load);
704    std::swap(first_bucket,x.first_bucket);
705
706#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
707    safe_super::swap(x);
708#endif
709
710    super::swap_(x);
711  }
712
713  bool replace_(value_param_type v,node_type* x)
714  {
715    if(eq(key(v),key(x->value()))){
716      return super::replace_(v,x);
717    }
718
719    hashed_index_node_impl* y=prev(x);
720    unlink_next(y);
721
722    BOOST_TRY{
723      std::size_t             buc=find_bucket(v);
724      hashed_index_node_impl* pos=buckets.at(buc);
725      if(link_point(v,pos,Category())&&super::replace_(v,x)){
726        link(x,pos);
727        if(first_bucket>buc){
728          first_bucket=buc;
729        }
730        else if(first_bucket<buc){
731          first_bucket=buckets.first_nonempty(first_bucket);
732        }
733        return true;
734      }
735      link(x,y);
736      return false;
737    }
738    BOOST_CATCH(...){
739      link(x,y);
740      BOOST_RETHROW;
741    }
742    BOOST_CATCH_END
743  }
744
745  bool modify_(node_type* x)
746  {
747    unlink(x);
748
749    std::size_t             buc;
750    hashed_index_node_impl* pos;
751    BOOST_TRY
752    {
753      buc=find_bucket(x->value());
754      pos=buckets.at(buc);
755      if(!link_point(x->value(),pos,Category())){
756        first_bucket=buckets.first_nonempty(first_bucket);
757        super::erase_(x);
758
759#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
760        detach_iterators(x);
761#endif
762        return false;
763      }
764
765    }
766    BOOST_CATCH(...){
767      first_bucket=buckets.first_nonempty(first_bucket);
768      super::erase_(x);
769
770#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
771      detach_iterators(x);
772#endif
773
774      BOOST_RETHROW;
775    }
776    BOOST_CATCH_END
777
778    BOOST_TRY{
779      if(super::modify_(x)){
780        link(x,pos);
781        if(first_bucket>buc){
782          first_bucket=buc;
783        }
784        else if(first_bucket<buc){
785          first_bucket=buckets.first_nonempty(first_bucket);
786        }
787        return true;
788      }
789
790      first_bucket=buckets.first_nonempty(first_bucket);
791
792#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
793      detach_iterators(x);
794#endif
795      return false;
796    }
797    BOOST_CATCH(...){
798      first_bucket=buckets.first_nonempty(first_bucket);
799
800#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
801      detach_iterators(x);
802#endif
803
804      BOOST_RETHROW;
805    }
806    BOOST_CATCH_END
807  }
808
809#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
810  /* serialization */
811
812  template<typename Archive>
813  void save_(
814    Archive& ar,const unsigned int version,const index_saver_type& sm)const
815  {
816    ar<<serialization::make_nvp("position",buckets);
817    super::save_(ar,version,sm);
818  }
819
820  template<typename Archive>
821  void load_(Archive& ar,const unsigned int version,const index_loader_type& lm)
822  {
823    ar>>serialization::make_nvp("position",buckets);
824    super::load_(ar,version,lm);
825  }
826#endif
827
828#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
829  /* invariant stuff */
830
831  bool invariant_()const
832  {
833    if(size()==0||begin()==end()){
834      if(size()!=0||begin()!=end())return false;
835    }
836    else{
837      size_type s0=0;
838      for(const_iterator it=begin(),it_end=end();it!=it_end;++it,++s0){}
839      if(s0!=size())return false;
840
841      size_type s1=0;
842      for(size_type buc=0;buc<bucket_count();++buc){
843        size_type ss1=0;
844        for(const_local_iterator it=begin(buc),it_end=end(buc);
845            it!=it_end;++it,++ss1){
846          if(find_bucket(*it)!=buc)return false;
847        }
848        if(ss1!=bucket_size(buc))return false;
849        s1+=ss1;
850      }
851      if(s1!=size())return false;
852    }
853
854    if(first_bucket!=buckets.first_nonempty(0))return false;
855
856    return super::invariant_();
857  }
858
859  /* This forwarding function eases things for the boost::mem_fn construct
860   * in BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT. Actually,
861   * final_check_invariant is already an inherited member function of index.
862   */
863  void check_invariant_()const{this->final_check_invariant_();}
864#endif
865
866private:
867  node_type* header()const{return this->final_header();}
868
869  std::size_t find_bucket(value_param_type v)const
870  {
871    return bucket(key(v));
872  }
873
874  bool link_point(
875    value_param_type v,hashed_index_node_impl*& pos,hashed_unique_tag)
876  {
877    hashed_index_node_impl* x=pos->next();
878    while(x!=pos){
879      if(eq(key(v),key(node_type::from_impl(x)->value()))){
880        pos=x;
881        return false;
882      }
883      x=x->next();
884    }
885    return true;
886  }
887
888  bool link_point(
889    value_param_type v,hashed_index_node_impl*& pos,hashed_non_unique_tag)
890  {
891    hashed_index_node_impl* prev=pos;
892    hashed_index_node_impl* x=pos->next();
893    while(x!=pos){
894      if(eq(key(v),key(node_type::from_impl(x)->value()))){
895        pos=prev;
896        return true;
897      }
898      prev=x;
899      x=x->next();
900    }
901    return true;
902  }
903 
904  void link(node_type* x,hashed_index_node_impl* pos)
905  {
906    hashed_index_node_impl::link(x->impl(),pos);
907  };
908
909  void link(hashed_index_node_impl* x,hashed_index_node_impl* pos)
910  {
911    hashed_index_node_impl::link(x,pos);
912  };
913
914  void unlink(node_type* x)
915  {
916    hashed_index_node_impl::unlink(x->impl());
917  };
918
919  static hashed_index_node_impl* prev(node_type* x)
920  {
921    return hashed_index_node_impl::prev(x->impl());
922  }
923
924  static void unlink_next(hashed_index_node_impl* x)
925  {
926    hashed_index_node_impl::unlink_next(x);
927  }
928
929  void calculate_max_load()
930  {
931    float fml=static_cast<float>(mlf*bucket_count());
932    max_load=(std::numeric_limits<size_type>::max)();
933    if(max_load>fml)max_load=static_cast<size_type>(fml);
934  }
935
936  void reserve(size_type n)
937  {
938    if(n>max_load){
939      size_type bc =(std::numeric_limits<size_type>::max)();
940      float     fbc=static_cast<float>(1+n/mlf);
941      if(bc>fbc)bc =static_cast<size_type>(fbc);
942      unchecked_rehash(bc);
943    }
944  }
945
946  void unchecked_rehash(size_type n)
947  {
948    bucket_array_type buckets1(get_allocator(),header()->impl(),n);
949    auto_space<std::size_t,allocator_type> hashes(get_allocator(),size());
950
951    std::size_t i=0;
952    hashed_index_node_impl* x=buckets.begin();
953    hashed_index_node_impl* x_end=buckets.end();
954    for(;x!=x_end;++x){
955      hashed_index_node_impl* y=x->next();
956      while(y!=x){
957        hashes.data()[i++]=hash(key(node_type::from_impl(y)->value()));
958        y=y->next();
959      }
960    }
961
962    i=0;
963    x=buckets.begin();
964    for(;x!=x_end;++x){
965      hashed_index_node_impl* y=x->next();
966      while(y!=x){
967        hashed_index_node_impl* z=y->next();
968        std::size_t             buc1=buckets1.position(hashes.data()[i++]);
969        hashed_index_node_impl* x1=buckets1.at(buc1);
970        link(y,x1);
971        y=z;
972      }
973    }
974
975    buckets.swap(buckets1);
976    calculate_max_load();
977    first_bucket=buckets.first_nonempty(0);
978  }
979
980#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
981  void detach_iterators(node_type* x)
982  {
983    iterator it=make_iterator(x);
984    safe_mode::detach_equivalent_iterators(it);
985  }
986#endif
987
988  key_from_value               key;
989  hasher                       hash;
990  key_equal                    eq;
991  bucket_array_type            buckets;
992  float                        mlf;
993  size_type                    max_load;
994  std::size_t                  first_bucket;
995     
996#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
997    BOOST_WORKAROUND(__MWERKS__,<=0x3003)
998#pragma parse_mfunc_templ reset
999#endif
1000};
1001
1002/*  specialized algorithms */
1003
1004template<
1005  typename KeyFromValue,typename Hash,typename Pred,
1006  typename SuperMeta,typename TagList,typename Category
1007>
1008void swap(
1009  hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
1010  hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
1011{
1012  x.swap(y);
1013}
1014
1015} /* namespace multi_index::detail */
1016
1017/* sequenced index specifiers */
1018
1019template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
1020struct hashed_unique
1021{
1022  typedef typename detail::hashed_index_args<
1023    Arg1,Arg2,Arg3,Arg4>                           index_args;
1024  typedef typename index_args::tag_list_type::type tag_list_type;
1025  typedef typename index_args::key_from_value_type key_from_value_type;
1026  typedef typename index_args::hash_type           hash_type;
1027  typedef typename index_args::pred_type           pred_type;
1028
1029  template<typename Super>
1030  struct node_class
1031  {
1032    typedef detail::hashed_index_node<Super> type;
1033  };
1034
1035  template<typename SuperMeta>
1036  struct index_class
1037  {
1038    typedef detail::hashed_index<
1039      key_from_value_type,hash_type,pred_type,
1040      SuperMeta,tag_list_type,detail::hashed_unique_tag> type;
1041  };
1042};
1043
1044template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
1045struct hashed_non_unique
1046{
1047  typedef typename detail::hashed_index_args<
1048    Arg1,Arg2,Arg3,Arg4>                           index_args;
1049  typedef typename index_args::tag_list_type::type tag_list_type;
1050  typedef typename index_args::key_from_value_type key_from_value_type;
1051  typedef typename index_args::hash_type           hash_type;
1052  typedef typename index_args::pred_type           pred_type;
1053
1054  template<typename Super>
1055  struct node_class
1056  {
1057    typedef detail::hashed_index_node<Super> type;
1058  };
1059
1060  template<typename SuperMeta>
1061  struct index_class
1062  {
1063    typedef detail::hashed_index<
1064      key_from_value_type,hash_type,pred_type,
1065      SuperMeta,tag_list_type,detail::hashed_non_unique_tag> type;
1066  };
1067};
1068
1069} /* namespace multi_index */
1070
1071} /* namespace boost */
1072
1073#undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
1074
1075#endif
Note: See TracBrowser for help on using the repository browser.