PageRenderTime 115ms CodeModel.GetById 8ms app.highlight 98ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/multi_index/hashed_index.hpp

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