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

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