]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/intrusive/hashtable.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / intrusive / hashtable.hpp
1 /////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2006-2015
4 //
5 // Distributed under the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // See http://www.boost.org/libs/intrusive for documentation.
10 //
11 /////////////////////////////////////////////////////////////////////////////
12 #ifndef BOOST_INTRUSIVE_HASHTABLE_HPP
13 #define BOOST_INTRUSIVE_HASHTABLE_HPP
14
15 #include <boost/intrusive/detail/config_begin.hpp>
16 #include <boost/intrusive/intrusive_fwd.hpp>
17
18 //General intrusive utilities
19 #include <boost/intrusive/detail/hashtable_node.hpp>
20 #include <boost/intrusive/detail/transform_iterator.hpp>
21 #include <boost/intrusive/link_mode.hpp>
22 #include <boost/intrusive/detail/ebo_functor_holder.hpp>
23 #include <boost/intrusive/detail/is_stateful_value_traits.hpp>
24 #include <boost/intrusive/detail/node_to_value.hpp>
25 #include <boost/intrusive/detail/exception_disposer.hpp>
26 #include <boost/intrusive/detail/node_cloner_disposer.hpp>
27 #include <boost/intrusive/detail/simple_disposers.hpp>
28 #include <boost/intrusive/detail/size_holder.hpp>
29 #include <boost/intrusive/detail/iterator.hpp>
30
31 //Implementation utilities
32 #include <boost/intrusive/unordered_set_hook.hpp>
33 #include <boost/intrusive/slist.hpp>
34 #include <boost/intrusive/pointer_traits.hpp>
35 #include <boost/intrusive/detail/mpl.hpp>
36
37 //boost
38 #include <boost/functional/hash.hpp>
39 #include <boost/intrusive/detail/assert.hpp>
40 #include <boost/static_assert.hpp>
41 #include <boost/move/utility_core.hpp>
42 #include <boost/move/adl_move_swap.hpp>
43
44 //std C++
45 #include <boost/intrusive/detail/minimal_less_equal_header.hpp> //std::equal_to
46 #include <boost/intrusive/detail/minimal_pair_header.hpp> //std::pair
47 #include <algorithm> //std::lower_bound, std::upper_bound
48 #include <cstddef> //std::size_t
49
50 #if defined(BOOST_HAS_PRAGMA_ONCE)
51 # pragma once
52 #endif
53
54 namespace boost {
55 namespace intrusive {
56
57 /// @cond
58
59 template<class InputIt, class T>
60 InputIt priv_algo_find(InputIt first, InputIt last, const T& value)
61 {
62 for (; first != last; ++first) {
63 if (*first == value) {
64 return first;
65 }
66 }
67 return last;
68 }
69
70 template<class InputIt, class T>
71 typename boost::intrusive::iterator_traits<InputIt>::difference_type
72 priv_algo_count(InputIt first, InputIt last, const T& value)
73 {
74 typename boost::intrusive::iterator_traits<InputIt>::difference_type ret = 0;
75 for (; first != last; ++first) {
76 if (*first == value) {
77 ret++;
78 }
79 }
80 return ret;
81 }
82
83 template <class ForwardIterator1, class ForwardIterator2>
84 bool priv_algo_is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2)
85 {
86 typedef typename
87 boost::intrusive::iterator_traits<ForwardIterator2>::difference_type
88 distance_type;
89 //Efficiently compare identical prefixes: O(N) if sequences
90 //have the same elements in the same order.
91 for ( ; first1 != last1; ++first1, ++first2){
92 if (! (*first1 == *first2))
93 break;
94 }
95 if (first1 == last1){
96 return true;
97 }
98
99 //Establish last2 assuming equal ranges by iterating over the
100 //rest of the list.
101 ForwardIterator2 last2 = first2;
102 boost::intrusive::iterator_advance(last2, boost::intrusive::iterator_distance(first1, last1));
103 for(ForwardIterator1 scan = first1; scan != last1; ++scan){
104 if (scan != (priv_algo_find)(first1, scan, *scan)){
105 continue; //We've seen this one before.
106 }
107 distance_type matches = (priv_algo_count)(first2, last2, *scan);
108 if (0 == matches || (priv_algo_count)(scan, last1, *scan != matches)){
109 return false;
110 }
111 }
112 return true;
113 }
114
115 template<int Dummy = 0>
116 struct prime_list_holder
117 {
118 static const std::size_t prime_list[];
119 static const std::size_t prime_list_size;
120
121 static std::size_t suggested_upper_bucket_count(std::size_t n)
122 {
123 const std::size_t *primes = &prime_list_holder<0>::prime_list[0];
124 const std::size_t *primes_end = primes + prime_list_holder<0>::prime_list_size;
125 std::size_t const* bound = std::lower_bound(primes, primes_end, n);
126 bound -= (bound == primes_end);
127 return *bound;
128 }
129
130 static std::size_t suggested_lower_bucket_count(std::size_t n)
131 {
132 const std::size_t *primes = &prime_list_holder<0>::prime_list[0];
133 const std::size_t *primes_end = primes + prime_list_holder<0>::prime_list_size;
134 std::size_t const* bound = std::upper_bound(primes, primes_end, n);
135 bound -= (bound != primes);
136 return *bound;
137 }
138 };
139
140 #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
141
142 //We only support LLP64(Win64) or LP64(most Unix) data models
143 #ifdef _WIN64 //In 64 bit windows sizeof(size_t) == sizeof(unsigned long long)
144 #define BOOST_INTRUSIVE_PRIME_C(NUMBER) NUMBER##ULL
145 #define BOOST_INTRUSIVE_64_BIT_SIZE_T 1
146 #else //In 32 bit windows and 32/64 bit unixes sizeof(size_t) == sizeof(unsigned long)
147 #define BOOST_INTRUSIVE_PRIME_C(NUMBER) NUMBER##UL
148 #define BOOST_INTRUSIVE_64_BIT_SIZE_T (((((ULONG_MAX>>16)>>16)>>16)>>15) != 0)
149 #endif
150
151 template<int Dummy>
152 const std::size_t prime_list_holder<Dummy>::prime_list[] = {
153 BOOST_INTRUSIVE_PRIME_C(3), BOOST_INTRUSIVE_PRIME_C(7),
154 BOOST_INTRUSIVE_PRIME_C(11), BOOST_INTRUSIVE_PRIME_C(17),
155 BOOST_INTRUSIVE_PRIME_C(29), BOOST_INTRUSIVE_PRIME_C(53),
156 BOOST_INTRUSIVE_PRIME_C(97), BOOST_INTRUSIVE_PRIME_C(193),
157 BOOST_INTRUSIVE_PRIME_C(389), BOOST_INTRUSIVE_PRIME_C(769),
158 BOOST_INTRUSIVE_PRIME_C(1543), BOOST_INTRUSIVE_PRIME_C(3079),
159 BOOST_INTRUSIVE_PRIME_C(6151), BOOST_INTRUSIVE_PRIME_C(12289),
160 BOOST_INTRUSIVE_PRIME_C(24593), BOOST_INTRUSIVE_PRIME_C(49157),
161 BOOST_INTRUSIVE_PRIME_C(98317), BOOST_INTRUSIVE_PRIME_C(196613),
162 BOOST_INTRUSIVE_PRIME_C(393241), BOOST_INTRUSIVE_PRIME_C(786433),
163 BOOST_INTRUSIVE_PRIME_C(1572869), BOOST_INTRUSIVE_PRIME_C(3145739),
164 BOOST_INTRUSIVE_PRIME_C(6291469), BOOST_INTRUSIVE_PRIME_C(12582917),
165 BOOST_INTRUSIVE_PRIME_C(25165843), BOOST_INTRUSIVE_PRIME_C(50331653),
166 BOOST_INTRUSIVE_PRIME_C(100663319), BOOST_INTRUSIVE_PRIME_C(201326611),
167 BOOST_INTRUSIVE_PRIME_C(402653189), BOOST_INTRUSIVE_PRIME_C(805306457),
168 BOOST_INTRUSIVE_PRIME_C(1610612741), BOOST_INTRUSIVE_PRIME_C(3221225473),
169 #if BOOST_INTRUSIVE_64_BIT_SIZE_T
170 //Taken from Boost.MultiIndex code, thanks to Joaquin M Lopez Munoz.
171 BOOST_INTRUSIVE_PRIME_C(6442450939), BOOST_INTRUSIVE_PRIME_C(12884901893),
172 BOOST_INTRUSIVE_PRIME_C(25769803751), BOOST_INTRUSIVE_PRIME_C(51539607551),
173 BOOST_INTRUSIVE_PRIME_C(103079215111), BOOST_INTRUSIVE_PRIME_C(206158430209),
174 BOOST_INTRUSIVE_PRIME_C(412316860441), BOOST_INTRUSIVE_PRIME_C(824633720831),
175 BOOST_INTRUSIVE_PRIME_C(1649267441651), BOOST_INTRUSIVE_PRIME_C(3298534883309),
176 BOOST_INTRUSIVE_PRIME_C(6597069766657), BOOST_INTRUSIVE_PRIME_C(13194139533299),
177 BOOST_INTRUSIVE_PRIME_C(26388279066623), BOOST_INTRUSIVE_PRIME_C(52776558133303),
178 BOOST_INTRUSIVE_PRIME_C(105553116266489), BOOST_INTRUSIVE_PRIME_C(211106232532969),
179 BOOST_INTRUSIVE_PRIME_C(422212465066001), BOOST_INTRUSIVE_PRIME_C(844424930131963),
180 BOOST_INTRUSIVE_PRIME_C(1688849860263953), BOOST_INTRUSIVE_PRIME_C(3377699720527861),
181 BOOST_INTRUSIVE_PRIME_C(6755399441055731), BOOST_INTRUSIVE_PRIME_C(13510798882111483),
182 BOOST_INTRUSIVE_PRIME_C(27021597764222939), BOOST_INTRUSIVE_PRIME_C(54043195528445957),
183 BOOST_INTRUSIVE_PRIME_C(108086391056891903), BOOST_INTRUSIVE_PRIME_C(216172782113783843),
184 BOOST_INTRUSIVE_PRIME_C(432345564227567621), BOOST_INTRUSIVE_PRIME_C(864691128455135207),
185 BOOST_INTRUSIVE_PRIME_C(1729382256910270481), BOOST_INTRUSIVE_PRIME_C(3458764513820540933),
186 BOOST_INTRUSIVE_PRIME_C(6917529027641081903), BOOST_INTRUSIVE_PRIME_C(13835058055282163729),
187 BOOST_INTRUSIVE_PRIME_C(18446744073709551557)
188 #else
189 BOOST_INTRUSIVE_PRIME_C(4294967291)
190 #endif
191 };
192
193 #undef BOOST_INTRUSIVE_PRIME_C
194 #undef BOOST_INTRUSIVE_64_BIT_SIZE_T
195
196 #endif //#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
197
198 template<int Dummy>
199 const std::size_t prime_list_holder<Dummy>::prime_list_size
200 = sizeof(prime_list)/sizeof(std::size_t);
201
202 struct hash_bool_flags
203 {
204 static const std::size_t unique_keys_pos = 1u;
205 static const std::size_t constant_time_size_pos = 2u;
206 static const std::size_t power_2_buckets_pos = 4u;
207 static const std::size_t cache_begin_pos = 8u;
208 static const std::size_t compare_hash_pos = 16u;
209 static const std::size_t incremental_pos = 32u;
210 };
211
212 namespace detail {
213
214 template<class SupposedValueTraits>
215 struct get_slist_impl_from_supposed_value_traits
216 {
217 typedef SupposedValueTraits value_traits;
218 typedef typename detail::get_node_traits
219 <value_traits>::type node_traits;
220 typedef typename get_slist_impl
221 <typename reduced_slist_node_traits
222 <node_traits>::type
223 >::type type;
224 };
225
226 template<class SupposedValueTraits>
227 struct unordered_bucket_impl
228 {
229 typedef typename
230 get_slist_impl_from_supposed_value_traits
231 <SupposedValueTraits>::type slist_impl;
232 typedef detail::bucket_impl<slist_impl> implementation_defined;
233 typedef implementation_defined type;
234 };
235
236 template<class SupposedValueTraits>
237 struct unordered_bucket_ptr_impl
238 {
239 typedef typename detail::get_node_traits
240 <SupposedValueTraits>::type::node_ptr node_ptr;
241 typedef typename unordered_bucket_impl
242 <SupposedValueTraits>::type bucket_type;
243
244 typedef typename pointer_traits
245 <node_ptr>::template rebind_pointer
246 < bucket_type >::type implementation_defined;
247 typedef implementation_defined type;
248 };
249
250 template <class T>
251 struct store_hash_is_true
252 {
253 template<bool Add>
254 struct two_or_three {yes_type _[2 + Add];};
255 template <class U> static yes_type test(...);
256 template <class U> static two_or_three<U::store_hash> test (int);
257 static const bool value = sizeof(test<T>(0)) > sizeof(yes_type)*2;
258 };
259
260 template <class T>
261 struct optimize_multikey_is_true
262 {
263 template<bool Add>
264 struct two_or_three {yes_type _[2 + Add];};
265 template <class U> static yes_type test(...);
266 template <class U> static two_or_three<U::optimize_multikey> test (int);
267 static const bool value = sizeof(test<T>(0)) > sizeof(yes_type)*2;
268 };
269
270 struct insert_commit_data_impl
271 {
272 std::size_t hash;
273 };
274
275 template<class Node, class SlistNodePtr>
276 BOOST_INTRUSIVE_FORCEINLINE typename pointer_traits<SlistNodePtr>::template rebind_pointer<Node>::type
277 dcast_bucket_ptr(const SlistNodePtr &p)
278 {
279 typedef typename pointer_traits<SlistNodePtr>::template rebind_pointer<Node>::type node_ptr;
280 return pointer_traits<node_ptr>::pointer_to(static_cast<Node&>(*p));
281 }
282
283 template<class NodeTraits>
284 struct group_functions
285 {
286 // A group is reverse-linked
287 //
288 // A is "first in group"
289 // C is "last in group"
290 // __________________
291 // | _____ _____ |
292 // | | | | | | <- Group links
293 // ^ V ^ V ^ V
294 // _ _ _ _
295 // A|_| B|_| C|_| D|_|
296 //
297 // ^ | ^ | ^ | ^ V <- Bucket links
298 // _ _____| |_____| |______| |____| |
299 // |B| |
300 // ^________________________________|
301 //
302
303 typedef NodeTraits node_traits;
304 typedef unordered_group_adapter<node_traits> group_traits;
305 typedef typename node_traits::node_ptr node_ptr;
306 typedef typename node_traits::node node;
307 typedef typename reduced_slist_node_traits
308 <node_traits>::type reduced_node_traits;
309 typedef typename reduced_node_traits::node_ptr slist_node_ptr;
310 typedef typename reduced_node_traits::node slist_node;
311 typedef circular_slist_algorithms<group_traits> group_algorithms;
312 typedef circular_slist_algorithms<node_traits> node_algorithms;
313
314 static slist_node_ptr get_bucket_before_begin
315 (const slist_node_ptr &bucket_beg, const slist_node_ptr &bucket_end, const node_ptr &p)
316 {
317 //First find the last node of p's group.
318 //This requires checking the first node of the next group or
319 //the bucket node.
320 node_ptr prev_node = p;
321 node_ptr nxt(node_traits::get_next(p));
322 while(!(bucket_beg <= nxt && nxt <= bucket_end) &&
323 (group_traits::get_next(nxt) == prev_node)){
324 prev_node = nxt;
325 nxt = node_traits::get_next(nxt);
326 }
327
328 //If we've reached the bucket node just return it.
329 if(bucket_beg <= nxt && nxt <= bucket_end){
330 return nxt;
331 }
332
333 //Otherwise, iterate using group links until the bucket node
334 node_ptr first_node_of_group = nxt;
335 node_ptr last_node_group = group_traits::get_next(first_node_of_group);
336 slist_node_ptr possible_end = node_traits::get_next(last_node_group);
337
338 while(!(bucket_beg <= possible_end && possible_end <= bucket_end)){
339 first_node_of_group = detail::dcast_bucket_ptr<node>(possible_end);
340 last_node_group = group_traits::get_next(first_node_of_group);
341 possible_end = node_traits::get_next(last_node_group);
342 }
343 return possible_end;
344 }
345
346 static node_ptr get_prev_to_first_in_group(const slist_node_ptr &bucket_node, const node_ptr &first_in_group)
347 {
348 node_ptr nb = detail::dcast_bucket_ptr<node>(bucket_node);
349 node_ptr n;
350 while((n = node_traits::get_next(nb)) != first_in_group){
351 nb = group_traits::get_next(n); //go to last in group
352 }
353 return nb;
354 }
355
356 static void erase_from_group(const slist_node_ptr &end_ptr, const node_ptr &to_erase_ptr, detail::true_)
357 {
358 node_ptr const nxt_ptr(node_traits::get_next(to_erase_ptr));
359 //Check if the next node is in the group (not end node) and reverse linked to
360 //'to_erase_ptr'. Erase if that's the case.
361 if(nxt_ptr != end_ptr && to_erase_ptr == group_traits::get_next(nxt_ptr)){
362 group_algorithms::unlink_after(nxt_ptr);
363 }
364 }
365
366 BOOST_INTRUSIVE_FORCEINLINE static void erase_from_group(const slist_node_ptr&, const node_ptr&, detail::false_)
367 {}
368
369 BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_last_in_group(const node_ptr &first_in_group, detail::true_)
370 { return group_traits::get_next(first_in_group); }
371
372 BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_last_in_group(node_ptr n, detail::false_)
373 { return n; }
374
375 static node_ptr get_first_in_group(node_ptr n, detail::true_)
376 {
377 node_ptr ng;
378 while(n == node_traits::get_next((ng = group_traits::get_next(n)))){
379 n = ng;
380 }
381 return n;
382 }
383
384 BOOST_INTRUSIVE_FORCEINLINE static node_ptr next_group_if_first_in_group(node_ptr ptr)
385 {
386 return node_traits::get_next(group_traits::get_next(ptr));
387 }
388
389 BOOST_INTRUSIVE_FORCEINLINE static node_ptr get_first_in_group(const node_ptr &n, detail::false_)
390 { return n; }
391
392 BOOST_INTRUSIVE_FORCEINLINE static void insert_in_group(const node_ptr &first_in_group, const node_ptr &n, true_)
393 { group_algorithms::link_after(first_in_group, n); }
394
395 static void insert_in_group(const node_ptr&, const node_ptr&, false_)
396 {}
397
398 BOOST_INTRUSIVE_FORCEINLINE static node_ptr split_group(node_ptr const new_first_in_group)
399 {
400 node_ptr const first((get_first_in_group)(new_first_in_group, detail::true_()));
401 if(first != new_first_in_group){
402 node_ptr const last = group_traits::get_next(first);
403 group_traits::set_next(first, group_traits::get_next(new_first_in_group));
404 group_traits::set_next(new_first_in_group, last);
405 }
406 return first;
407 }
408 };
409
410 template<class BucketType, class SplitTraits>
411 class incremental_rehash_rollback
412 {
413 private:
414 typedef BucketType bucket_type;
415 typedef SplitTraits split_traits;
416
417 incremental_rehash_rollback();
418 incremental_rehash_rollback & operator=(const incremental_rehash_rollback &);
419 incremental_rehash_rollback (const incremental_rehash_rollback &);
420
421 public:
422 incremental_rehash_rollback
423 (bucket_type &source_bucket, bucket_type &destiny_bucket, split_traits &split_traits)
424 : source_bucket_(source_bucket), destiny_bucket_(destiny_bucket)
425 , split_traits_(split_traits), released_(false)
426 {}
427
428 BOOST_INTRUSIVE_FORCEINLINE void release()
429 { released_ = true; }
430
431 ~incremental_rehash_rollback()
432 {
433 if(!released_){
434 //If an exception is thrown, just put all moved nodes back in the old bucket
435 //and move back the split mark.
436 destiny_bucket_.splice_after(destiny_bucket_.before_begin(), source_bucket_);
437 split_traits_.decrement();
438 }
439 }
440
441 private:
442 bucket_type &source_bucket_;
443 bucket_type &destiny_bucket_;
444 split_traits &split_traits_;
445 bool released_;
446 };
447
448 template<class NodeTraits>
449 struct node_functions
450 {
451 BOOST_INTRUSIVE_FORCEINLINE static void store_hash(typename NodeTraits::node_ptr p, std::size_t h, true_)
452 { return NodeTraits::set_hash(p, h); }
453
454 BOOST_INTRUSIVE_FORCEINLINE static void store_hash(typename NodeTraits::node_ptr, std::size_t, false_)
455 {}
456 };
457
458 BOOST_INTRUSIVE_FORCEINLINE std::size_t hash_to_bucket(std::size_t hash_value, std::size_t bucket_cnt, detail::false_)
459 { return hash_value % bucket_cnt; }
460
461 BOOST_INTRUSIVE_FORCEINLINE std::size_t hash_to_bucket(std::size_t hash_value, std::size_t bucket_cnt, detail::true_)
462 { return hash_value & (bucket_cnt - 1); }
463
464 template<bool Power2Buckets, bool Incremental>
465 BOOST_INTRUSIVE_FORCEINLINE std::size_t hash_to_bucket_split(std::size_t hash_value, std::size_t bucket_cnt, std::size_t split)
466 {
467 std::size_t bucket_number = detail::hash_to_bucket(hash_value, bucket_cnt, detail::bool_<Power2Buckets>());
468 if(Incremental)
469 bucket_number -= static_cast<std::size_t>(bucket_number >= split)*(bucket_cnt/2);
470 return bucket_number;
471 }
472
473 } //namespace detail {
474
475 //!This metafunction will obtain the type of a bucket
476 //!from the value_traits or hook option to be used with
477 //!a hash container.
478 template<class ValueTraitsOrHookOption>
479 struct unordered_bucket
480 : public detail::unordered_bucket_impl
481 <typename ValueTraitsOrHookOption::
482 template pack<empty>::proto_value_traits
483 >
484 {};
485
486 //!This metafunction will obtain the type of a bucket pointer
487 //!from the value_traits or hook option to be used with
488 //!a hash container.
489 template<class ValueTraitsOrHookOption>
490 struct unordered_bucket_ptr
491 : public detail::unordered_bucket_ptr_impl
492 <typename ValueTraitsOrHookOption::
493 template pack<empty>::proto_value_traits
494 >
495 {};
496
497 //!This metafunction will obtain the type of the default bucket traits
498 //!(when the user does not specify the bucket_traits<> option) from the
499 //!value_traits or hook option to be used with
500 //!a hash container.
501 template<class ValueTraitsOrHookOption>
502 struct unordered_default_bucket_traits
503 {
504 typedef typename ValueTraitsOrHookOption::
505 template pack<empty>::proto_value_traits supposed_value_traits;
506 typedef typename detail::
507 get_slist_impl_from_supposed_value_traits
508 <supposed_value_traits>::type slist_impl;
509 typedef detail::bucket_traits_impl
510 <slist_impl> implementation_defined;
511 typedef implementation_defined type;
512 };
513
514 struct default_bucket_traits;
515
516 //hashtable default hook traits
517 struct default_hashtable_hook_applier
518 { template <class T> struct apply{ typedef typename T::default_hashtable_hook type; }; };
519
520 template<>
521 struct is_default_hook_tag<default_hashtable_hook_applier>
522 { static const bool value = true; };
523
524 struct hashtable_defaults
525 {
526 typedef default_hashtable_hook_applier proto_value_traits;
527 typedef std::size_t size_type;
528 typedef void key_of_value;
529 typedef void equal;
530 typedef void hash;
531 typedef default_bucket_traits bucket_traits;
532 static const bool constant_time_size = true;
533 static const bool power_2_buckets = false;
534 static const bool cache_begin = false;
535 static const bool compare_hash = false;
536 static const bool incremental = false;
537 };
538
539 template<class ValueTraits, bool IsConst>
540 struct downcast_node_to_value_t
541 : public detail::node_to_value<ValueTraits, IsConst>
542 {
543 typedef detail::node_to_value<ValueTraits, IsConst> base_t;
544 typedef typename base_t::result_type result_type;
545 typedef ValueTraits value_traits;
546 typedef typename detail::get_slist_impl
547 <typename detail::reduced_slist_node_traits
548 <typename value_traits::node_traits>::type
549 >::type slist_impl;
550 typedef typename detail::add_const_if_c
551 <typename slist_impl::node, IsConst>::type & first_argument_type;
552 typedef typename detail::add_const_if_c
553 < typename ValueTraits::node_traits::node
554 , IsConst>::type & intermediate_argument_type;
555 typedef typename pointer_traits
556 <typename ValueTraits::pointer>::
557 template rebind_pointer
558 <const ValueTraits>::type const_value_traits_ptr;
559
560 BOOST_INTRUSIVE_FORCEINLINE downcast_node_to_value_t(const const_value_traits_ptr &ptr)
561 : base_t(ptr)
562 {}
563
564 BOOST_INTRUSIVE_FORCEINLINE result_type operator()(first_argument_type arg) const
565 { return this->base_t::operator()(static_cast<intermediate_argument_type>(arg)); }
566 };
567
568 template<class F, class SlistNodePtr, class NodePtr>
569 struct node_cast_adaptor
570 //Use public inheritance to avoid MSVC bugs with closures
571 : public detail::ebo_functor_holder<F>
572 {
573 typedef detail::ebo_functor_holder<F> base_t;
574
575 typedef typename pointer_traits<SlistNodePtr>::element_type slist_node;
576 typedef typename pointer_traits<NodePtr>::element_type node;
577
578 template<class ConvertibleToF, class RealValuTraits>
579 BOOST_INTRUSIVE_FORCEINLINE node_cast_adaptor(const ConvertibleToF &c2f, const RealValuTraits *traits)
580 : base_t(base_t(c2f, traits))
581 {}
582
583 BOOST_INTRUSIVE_FORCEINLINE typename base_t::node_ptr operator()(const slist_node &to_clone)
584 { return base_t::operator()(static_cast<const node &>(to_clone)); }
585
586 BOOST_INTRUSIVE_FORCEINLINE void operator()(SlistNodePtr to_clone)
587 {
588 base_t::operator()(pointer_traits<NodePtr>::pointer_to(static_cast<node &>(*to_clone)));
589 }
590 };
591
592 //bucket_plus_vtraits stores ValueTraits + BucketTraits
593 //this data is needed by iterators to obtain the
594 //value from the iterator and detect the bucket
595 template<class ValueTraits, class BucketTraits>
596 struct bucket_plus_vtraits
597 {
598 typedef BucketTraits bucket_traits;
599 typedef ValueTraits value_traits;
600
601 static const bool safemode_or_autounlink = is_safe_autounlink<value_traits::link_mode>::value;
602
603 typedef typename
604 detail::get_slist_impl_from_supposed_value_traits
605 <value_traits>::type slist_impl;
606 typedef typename value_traits::node_traits node_traits;
607 typedef unordered_group_adapter<node_traits> group_traits;
608 typedef typename slist_impl::iterator siterator;
609 typedef detail::bucket_impl<slist_impl> bucket_type;
610 typedef detail::group_functions<node_traits> group_functions_t;
611 typedef typename slist_impl::node_algorithms node_algorithms;
612 typedef typename slist_impl::node_ptr slist_node_ptr;
613 typedef typename node_traits::node_ptr node_ptr;
614 typedef typename node_traits::node node;
615 typedef typename value_traits::value_type value_type;
616 typedef typename value_traits::pointer pointer;
617 typedef typename value_traits::const_pointer const_pointer;
618 typedef typename pointer_traits<pointer>::reference reference;
619 typedef typename pointer_traits
620 <const_pointer>::reference const_reference;
621 typedef circular_slist_algorithms<group_traits> group_algorithms;
622 typedef typename pointer_traits
623 <typename value_traits::pointer>::
624 template rebind_pointer
625 <const value_traits>::type const_value_traits_ptr;
626 typedef typename pointer_traits
627 <typename value_traits::pointer>::
628 template rebind_pointer
629 <const bucket_plus_vtraits>::type const_bucket_value_traits_ptr;
630 typedef typename detail::unordered_bucket_ptr_impl
631 <value_traits>::type bucket_ptr;
632
633 template<class BucketTraitsType>
634 BOOST_INTRUSIVE_FORCEINLINE bucket_plus_vtraits(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits)
635 : data(val_traits, ::boost::forward<BucketTraitsType>(b_traits))
636 {}
637
638 BOOST_INTRUSIVE_FORCEINLINE bucket_plus_vtraits & operator =(const bucket_plus_vtraits &x)
639 { data.bucket_traits_ = x.data.bucket_traits_; return *this; }
640
641 BOOST_INTRUSIVE_FORCEINLINE const_value_traits_ptr priv_value_traits_ptr() const
642 { return pointer_traits<const_value_traits_ptr>::pointer_to(this->priv_value_traits()); }
643
644 //bucket_value_traits
645 //
646 BOOST_INTRUSIVE_FORCEINLINE const bucket_plus_vtraits &get_bucket_value_traits() const
647 { return *this; }
648
649 BOOST_INTRUSIVE_FORCEINLINE bucket_plus_vtraits &get_bucket_value_traits()
650 { return *this; }
651
652 BOOST_INTRUSIVE_FORCEINLINE const_bucket_value_traits_ptr bucket_value_traits_ptr() const
653 { return pointer_traits<const_bucket_value_traits_ptr>::pointer_to(this->get_bucket_value_traits()); }
654
655 //value traits
656 //
657 BOOST_INTRUSIVE_FORCEINLINE const value_traits &priv_value_traits() const
658 { return this->data; }
659
660 BOOST_INTRUSIVE_FORCEINLINE value_traits &priv_value_traits()
661 { return this->data; }
662
663 //bucket_traits
664 //
665 BOOST_INTRUSIVE_FORCEINLINE const bucket_traits &priv_bucket_traits() const
666 { return this->data.bucket_traits_; }
667
668 BOOST_INTRUSIVE_FORCEINLINE bucket_traits &priv_bucket_traits()
669 { return this->data.bucket_traits_; }
670
671 //bucket operations
672 BOOST_INTRUSIVE_FORCEINLINE bucket_ptr priv_bucket_pointer() const
673 { return this->priv_bucket_traits().bucket_begin(); }
674
675 std::size_t priv_bucket_count() const
676 { return this->priv_bucket_traits().bucket_count(); }
677
678 BOOST_INTRUSIVE_FORCEINLINE bucket_ptr priv_invalid_bucket() const
679 {
680 const bucket_traits &rbt = this->priv_bucket_traits();
681 return rbt.bucket_begin() + rbt.bucket_count();
682 }
683
684 BOOST_INTRUSIVE_FORCEINLINE siterator priv_invalid_local_it() const
685 { return this->priv_bucket_traits().bucket_begin()->before_begin(); }
686
687 template<class NodeDisposer>
688 static std::size_t priv_erase_from_single_bucket(bucket_type &b, siterator sbefore_first, siterator slast, NodeDisposer node_disposer, detail::true_) //optimize multikey
689 {
690 std::size_t n = 0;
691 siterator const sfirst(++siterator(sbefore_first));
692 if(sfirst != slast){
693 node_ptr const nf = detail::dcast_bucket_ptr<node>(sfirst.pointed_node());
694 node_ptr const nl = detail::dcast_bucket_ptr<node>(slast.pointed_node());
695 node_ptr const ne = detail::dcast_bucket_ptr<node>(b.end().pointed_node());
696
697 if(group_functions_t::next_group_if_first_in_group(nf) != nf) {
698 // The node is at the beginning of a group.
699 if(nl != ne){
700 group_functions_t::split_group(nl);
701 }
702 }
703 else {
704 node_ptr const group1 = group_functions_t::split_group(nf);
705 if(nl != ne) {
706 node_ptr const group2 = group_functions_t::split_group(ne);
707 if(nf == group2) { //Both first and last in the same group
708 //so join group1 and group2
709 node_ptr const end1 = group_traits::get_next(group1);
710 node_ptr const end2 = group_traits::get_next(group2);
711 group_traits::set_next(group1, end2);
712 group_traits::set_next(group2, end1);
713 }
714 }
715 }
716
717 siterator it(++siterator(sbefore_first));
718 while(it != slast){
719 node_disposer((it++).pointed_node());
720 ++n;
721 }
722 b.erase_after(sbefore_first, slast);
723 }
724 return n;
725 }
726
727 template<class NodeDisposer>
728 static std::size_t priv_erase_from_single_bucket(bucket_type &b, siterator sbefore_first, siterator slast, NodeDisposer node_disposer, detail::false_) //optimize multikey
729 {
730 std::size_t n = 0;
731 siterator it(++siterator(sbefore_first));
732 while(it != slast){
733 node_disposer((it++).pointed_node());
734 ++n;
735 }
736 b.erase_after(sbefore_first, slast);
737 return n;
738 }
739
740 template<class NodeDisposer>
741 static void priv_erase_node(bucket_type &b, siterator i, NodeDisposer node_disposer, detail::true_) //optimize multikey
742 {
743 node_ptr const ne(detail::dcast_bucket_ptr<node>(b.end().pointed_node()));
744 node_ptr n(detail::dcast_bucket_ptr<node>(i.pointed_node()));
745 node_ptr pos = node_traits::get_next(group_traits::get_next(n));
746 node_ptr bn;
747 node_ptr nn(node_traits::get_next(n));
748
749 if(pos != n) {
750 //Node is the first of the group
751 bn = group_functions_t::get_prev_to_first_in_group(ne, n);
752
753 //Unlink the rest of the group if it's not the last node of its group
754 if(nn != ne && group_traits::get_next(nn) == n){
755 group_algorithms::unlink_after(nn);
756 }
757 }
758 else if(nn != ne && group_traits::get_next(nn) == n){
759 //Node is not the end of the group
760 bn = group_traits::get_next(n);
761 group_algorithms::unlink_after(nn);
762 }
763 else{
764 //Node is the end of the group
765 bn = group_traits::get_next(n);
766 node_ptr const x(group_algorithms::get_previous_node(n));
767 group_algorithms::unlink_after(x);
768 }
769 b.erase_after_and_dispose(bucket_type::s_iterator_to(*bn), node_disposer);
770 }
771
772 template<class NodeDisposer>
773 BOOST_INTRUSIVE_FORCEINLINE static void priv_erase_node(bucket_type &b, siterator i, NodeDisposer node_disposer, detail::false_) //optimize multikey
774 { b.erase_after_and_dispose(b.previous(i), node_disposer); }
775
776 template<class NodeDisposer, bool OptimizeMultikey>
777 std::size_t priv_erase_node_range( siterator const &before_first_it, std::size_t const first_bucket
778 , siterator const &last_it, std::size_t const last_bucket
779 , NodeDisposer node_disposer, detail::bool_<OptimizeMultikey> optimize_multikey_tag)
780 {
781 std::size_t num_erased(0);
782 siterator last_step_before_it;
783 if(first_bucket != last_bucket){
784 bucket_type *b = (&this->priv_bucket_pointer()[0]);
785 num_erased += this->priv_erase_from_single_bucket
786 (b[first_bucket], before_first_it, b[first_bucket].end(), node_disposer, optimize_multikey_tag);
787 for(std::size_t i = 0, n = (last_bucket - first_bucket - 1); i != n; ++i){
788 num_erased += this->priv_erase_whole_bucket(b[first_bucket+i+1], node_disposer);
789 }
790 last_step_before_it = b[last_bucket].before_begin();
791 }
792 else{
793 last_step_before_it = before_first_it;
794 }
795 num_erased += this->priv_erase_from_single_bucket
796 (this->priv_bucket_pointer()[last_bucket], last_step_before_it, last_it, node_disposer, optimize_multikey_tag);
797 return num_erased;
798 }
799
800 static siterator priv_get_last(bucket_type &b, detail::true_) //optimize multikey
801 {
802 //First find the last node of p's group.
803 //This requires checking the first node of the next group or
804 //the bucket node.
805 slist_node_ptr end_ptr(b.end().pointed_node());
806 node_ptr possible_end(node_traits::get_next( detail::dcast_bucket_ptr<node>(end_ptr)));
807 node_ptr last_node_group(possible_end);
808
809 while(end_ptr != possible_end){
810 last_node_group = group_traits::get_next(detail::dcast_bucket_ptr<node>(possible_end));
811 possible_end = node_traits::get_next(last_node_group);
812 }
813 return bucket_type::s_iterator_to(*last_node_group);
814 }
815
816 template<class NodeDisposer>
817 std::size_t priv_erase_whole_bucket(bucket_type &b, NodeDisposer node_disposer)
818 {
819 std::size_t num_erased = 0;
820 siterator b_begin(b.before_begin());
821 siterator nxt(b_begin);
822 ++nxt;
823 siterator const end_sit(b.end());
824 while(nxt != end_sit){
825 //No need to init group links as we'll delete all bucket nodes
826 nxt = bucket_type::s_erase_after_and_dispose(b_begin, node_disposer);
827 ++num_erased;
828 }
829 return num_erased;
830 }
831
832 BOOST_INTRUSIVE_FORCEINLINE static siterator priv_get_last(bucket_type &b, detail::false_) //NOT optimize multikey
833 { return b.previous(b.end()); }
834
835 static siterator priv_get_previous(bucket_type &b, siterator i, detail::true_) //optimize multikey
836 {
837 node_ptr const elem(detail::dcast_bucket_ptr<node>(i.pointed_node()));
838 node_ptr const prev_in_group(group_traits::get_next(elem));
839 bool const first_in_group = node_traits::get_next(prev_in_group) != elem;
840 typename bucket_type::node &n = first_in_group
841 ? *group_functions_t::get_prev_to_first_in_group(b.end().pointed_node(), elem)
842 : *group_traits::get_next(elem)
843 ;
844 return bucket_type::s_iterator_to(n);
845 }
846
847 BOOST_INTRUSIVE_FORCEINLINE static siterator priv_get_previous(bucket_type &b, siterator i, detail::false_) //NOT optimize multikey
848 { return b.previous(i); }
849
850 std::size_t priv_get_bucket_num_no_hash_store(siterator it, detail::true_) //optimize multikey
851 {
852 const bucket_ptr f(this->priv_bucket_pointer()), l(f + this->priv_bucket_count() - 1);
853 slist_node_ptr bb = group_functions_t::get_bucket_before_begin
854 ( f->end().pointed_node()
855 , l->end().pointed_node()
856 , detail::dcast_bucket_ptr<node>(it.pointed_node()));
857 //Now get the bucket_impl from the iterator
858 const bucket_type &b = static_cast<const bucket_type&>
859 (bucket_type::slist_type::container_from_end_iterator(bucket_type::s_iterator_to(*bb)));
860 //Now just calculate the index b has in the bucket array
861 return static_cast<std::size_t>(&b - &*f);
862 }
863
864 std::size_t priv_get_bucket_num_no_hash_store(siterator it, detail::false_) //NO optimize multikey
865 {
866 bucket_ptr f(this->priv_bucket_pointer()), l(f + this->priv_bucket_count() - 1);
867 slist_node_ptr first_ptr(f->cend().pointed_node())
868 , last_ptr(l->cend().pointed_node());
869
870 //The end node is embedded in the singly linked list:
871 //iterate until we reach it.
872 while(!(first_ptr <= it.pointed_node() && it.pointed_node() <= last_ptr)){
873 ++it;
874 }
875 //Now get the bucket_impl from the iterator
876 const bucket_type &b = static_cast<const bucket_type&>
877 (bucket_type::container_from_end_iterator(it));
878
879 //Now just calculate the index b has in the bucket array
880 return static_cast<std::size_t>(&b - &*f);
881 }
882
883 BOOST_INTRUSIVE_FORCEINLINE static std::size_t priv_stored_hash(slist_node_ptr n, detail::true_) //store_hash
884 { return node_traits::get_hash(detail::dcast_bucket_ptr<node>(n)); }
885
886 BOOST_INTRUSIVE_FORCEINLINE static std::size_t priv_stored_hash(slist_node_ptr, detail::false_) //NO store_hash
887 { return std::size_t(-1); }
888
889 BOOST_INTRUSIVE_FORCEINLINE node &priv_value_to_node(reference v)
890 { return *this->priv_value_traits().to_node_ptr(v); }
891
892 BOOST_INTRUSIVE_FORCEINLINE const node &priv_value_to_node(const_reference v) const
893 { return *this->priv_value_traits().to_node_ptr(v); }
894
895 BOOST_INTRUSIVE_FORCEINLINE reference priv_value_from_slist_node(slist_node_ptr n)
896 { return *this->priv_value_traits().to_value_ptr(detail::dcast_bucket_ptr<node>(n)); }
897
898 BOOST_INTRUSIVE_FORCEINLINE const_reference priv_value_from_slist_node(slist_node_ptr n) const
899 { return *this->priv_value_traits().to_value_ptr(detail::dcast_bucket_ptr<node>(n)); }
900
901 void priv_clear_buckets(const bucket_ptr buckets_ptr, const std::size_t bucket_cnt)
902 {
903 bucket_ptr buckets_it = buckets_ptr;
904 for(std::size_t bucket_i = 0; bucket_i != bucket_cnt; ++buckets_it, ++bucket_i){
905 if(safemode_or_autounlink){
906 buckets_it->clear_and_dispose(detail::init_disposer<node_algorithms>());
907 }
908 else{
909 buckets_it->clear();
910 }
911 }
912 }
913
914 BOOST_INTRUSIVE_FORCEINLINE std::size_t priv_stored_or_compute_hash(const value_type &v, detail::true_) const //For store_hash == true
915 { return node_traits::get_hash(this->priv_value_traits().to_node_ptr(v)); }
916
917 typedef hashtable_iterator<bucket_plus_vtraits, false> iterator;
918 typedef hashtable_iterator<bucket_plus_vtraits, true> const_iterator;
919
920 BOOST_INTRUSIVE_FORCEINLINE iterator end()
921 { return iterator(this->priv_invalid_local_it(), 0); }
922
923 BOOST_INTRUSIVE_FORCEINLINE const_iterator end() const
924 { return this->cend(); }
925
926 BOOST_INTRUSIVE_FORCEINLINE const_iterator cend() const
927 { return const_iterator(this->priv_invalid_local_it(), 0); }
928
929 //Public functions:
930 struct data_type : public ValueTraits
931 {
932 template<class BucketTraitsType>
933 BOOST_INTRUSIVE_FORCEINLINE data_type(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits)
934 : ValueTraits(val_traits), bucket_traits_(::boost::forward<BucketTraitsType>(b_traits))
935 {}
936
937 bucket_traits bucket_traits_;
938 } data;
939 };
940
941 template<class Hash, class>
942 struct get_hash
943 {
944 typedef Hash type;
945 };
946
947 template<class T>
948 struct get_hash<void, T>
949 {
950 typedef ::boost::hash<T> type;
951 };
952
953 template<class EqualTo, class>
954 struct get_equal_to
955 {
956 typedef EqualTo type;
957 };
958
959 template<class T>
960 struct get_equal_to<void, T>
961 {
962 typedef std::equal_to<T> type;
963 };
964
965 template<class KeyOfValue, class T>
966 struct get_hash_key_of_value
967 {
968 typedef KeyOfValue type;
969 };
970
971 template<class T>
972 struct get_hash_key_of_value<void, T>
973 {
974 typedef ::boost::intrusive::detail::identity<T> type;
975 };
976
977 template<class T, class VoidOrKeyOfValue>
978 struct hash_key_types_base
979 {
980 typedef typename get_hash_key_of_value
981 < VoidOrKeyOfValue, T>::type key_of_value;
982 typedef typename key_of_value::type key_type;
983 };
984
985 template<class T, class VoidOrKeyOfValue, class VoidOrKeyHash>
986 struct hash_key_hash
987 : get_hash
988 < VoidOrKeyHash
989 , typename hash_key_types_base<T, VoidOrKeyOfValue>::key_type
990 >
991 {};
992
993 template<class T, class VoidOrKeyOfValue, class VoidOrKeyEqual>
994 struct hash_key_equal
995 : get_equal_to
996 < VoidOrKeyEqual
997 , typename hash_key_types_base<T, VoidOrKeyOfValue>::key_type
998 >
999
1000 {};
1001
1002 //bucket_hash_t
1003 //Stores bucket_plus_vtraits plust the hash function
1004 template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class BucketTraits>
1005 struct bucket_hash_t
1006 //Use public inheritance to avoid MSVC bugs with closures
1007 : public detail::ebo_functor_holder
1008 <typename hash_key_hash < typename bucket_plus_vtraits<ValueTraits,BucketTraits>::value_traits::value_type
1009 , VoidOrKeyOfValue
1010 , VoidOrKeyHash
1011 >::type
1012 >
1013 , bucket_plus_vtraits<ValueTraits, BucketTraits> //4
1014 {
1015 typedef typename bucket_plus_vtraits<ValueTraits,BucketTraits>::value_traits value_traits;
1016 typedef typename value_traits::value_type value_type;
1017 typedef typename value_traits::node_traits node_traits;
1018 typedef hash_key_hash
1019 < value_type, VoidOrKeyOfValue, VoidOrKeyHash> hash_key_hash_t;
1020 typedef typename hash_key_hash_t::type hasher;
1021 typedef typename hash_key_types_base<value_type, VoidOrKeyOfValue>::key_of_value key_of_value;
1022
1023 typedef BucketTraits bucket_traits;
1024 typedef bucket_plus_vtraits<ValueTraits, BucketTraits> bucket_plus_vtraits_t;
1025 typedef detail::ebo_functor_holder<hasher> base_t;
1026
1027 template<class BucketTraitsType>
1028 BOOST_INTRUSIVE_FORCEINLINE bucket_hash_t(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits, const hasher & h)
1029 : detail::ebo_functor_holder<hasher>(h), bucket_plus_vtraits_t(val_traits, ::boost::forward<BucketTraitsType>(b_traits))
1030 {}
1031
1032 BOOST_INTRUSIVE_FORCEINLINE const hasher &priv_hasher() const
1033 { return this->base_t::get(); }
1034
1035 hasher &priv_hasher()
1036 { return this->base_t::get(); }
1037
1038 using bucket_plus_vtraits_t::priv_stored_or_compute_hash; //For store_hash == true
1039
1040 BOOST_INTRUSIVE_FORCEINLINE std::size_t priv_stored_or_compute_hash(const value_type &v, detail::false_) const //For store_hash == false
1041 { return this->priv_hasher()(key_of_value()(v)); }
1042 };
1043
1044 template<class ValueTraits, class BucketTraits, class VoidOrKeyOfValue, class VoidOrKeyEqual>
1045 struct hashtable_equal_holder
1046 {
1047 typedef detail::ebo_functor_holder
1048 < typename hash_key_equal < typename bucket_plus_vtraits<ValueTraits, BucketTraits>::value_traits::value_type
1049 , VoidOrKeyOfValue
1050 , VoidOrKeyEqual
1051 >::type
1052 > type;
1053 };
1054
1055
1056 //bucket_hash_equal_t
1057 //Stores bucket_hash_t and the equality function when the first
1058 //non-empty bucket shall not be cached.
1059 template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class BucketTraits, bool>
1060 struct bucket_hash_equal_t
1061 //Use public inheritance to avoid MSVC bugs with closures
1062 : public bucket_hash_t<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, BucketTraits> //3
1063 , public hashtable_equal_holder<ValueTraits, BucketTraits, VoidOrKeyOfValue, VoidOrKeyEqual>::type //equal
1064 {
1065 typedef typename hashtable_equal_holder
1066 <ValueTraits, BucketTraits, VoidOrKeyOfValue, VoidOrKeyEqual>::type equal_holder_t;
1067 typedef bucket_hash_t<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, BucketTraits> bucket_hash_type;
1068 typedef bucket_plus_vtraits<ValueTraits,BucketTraits> bucket_plus_vtraits_t;
1069 typedef ValueTraits value_traits;
1070 typedef typename equal_holder_t::functor_type key_equal;
1071 typedef typename bucket_hash_type::hasher hasher;
1072 typedef BucketTraits bucket_traits;
1073 typedef typename bucket_plus_vtraits_t::slist_impl slist_impl;
1074 typedef typename slist_impl::iterator siterator;
1075 typedef detail::bucket_impl<slist_impl> bucket_type;
1076 typedef typename detail::unordered_bucket_ptr_impl<value_traits>::type bucket_ptr;
1077
1078 template<class BucketTraitsType>
1079 bucket_hash_equal_t(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits, const hasher & h, const key_equal &e)
1080 : bucket_hash_type(val_traits, ::boost::forward<BucketTraitsType>(b_traits), h)
1081 , equal_holder_t(e)
1082 {}
1083
1084 BOOST_INTRUSIVE_FORCEINLINE bucket_ptr priv_get_cache()
1085 { return this->bucket_hash_type::priv_bucket_pointer(); }
1086
1087 BOOST_INTRUSIVE_FORCEINLINE void priv_set_cache(const bucket_ptr &)
1088 {}
1089
1090 BOOST_INTRUSIVE_FORCEINLINE std::size_t priv_get_cache_bucket_num()
1091 { return 0u; }
1092
1093 BOOST_INTRUSIVE_FORCEINLINE void priv_initialize_cache()
1094 {}
1095
1096 BOOST_INTRUSIVE_FORCEINLINE void priv_swap_cache(bucket_hash_equal_t &)
1097 {}
1098
1099 siterator priv_begin() const
1100 {
1101 std::size_t n = 0;
1102 std::size_t bucket_cnt = this->bucket_hash_type::priv_bucket_count();
1103 for (n = 0; n < bucket_cnt; ++n){
1104 bucket_type &b = this->bucket_hash_type::priv_bucket_pointer()[n];
1105 if(!b.empty()){
1106 return b.begin();
1107 }
1108 }
1109 return this->bucket_hash_type::priv_invalid_local_it();
1110 }
1111
1112 BOOST_INTRUSIVE_FORCEINLINE void priv_insertion_update_cache(std::size_t)
1113 {}
1114
1115 BOOST_INTRUSIVE_FORCEINLINE void priv_erasure_update_cache_range(std::size_t, std::size_t)
1116 {}
1117
1118 BOOST_INTRUSIVE_FORCEINLINE void priv_erasure_update_cache()
1119 {}
1120
1121 BOOST_INTRUSIVE_FORCEINLINE const key_equal &priv_equal() const
1122 { return this->equal_holder_t::get(); }
1123
1124 BOOST_INTRUSIVE_FORCEINLINE key_equal &priv_equal()
1125 { return this->equal_holder_t::get(); }
1126 };
1127
1128 //bucket_hash_equal_t
1129 //Stores bucket_hash_t and the equality function when the first
1130 //non-empty bucket shall be cached.
1131 template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class BucketTraits> //cache_begin == true version
1132 struct bucket_hash_equal_t<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, true>
1133 //Use public inheritance to avoid MSVC bugs with closures
1134 : bucket_hash_t<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, BucketTraits> //2
1135 , hashtable_equal_holder<ValueTraits, BucketTraits, VoidOrKeyOfValue, VoidOrKeyEqual>::type
1136 {
1137 typedef typename hashtable_equal_holder
1138 <ValueTraits, BucketTraits, VoidOrKeyOfValue, VoidOrKeyEqual>::type equal_holder_t;
1139
1140 typedef bucket_plus_vtraits<ValueTraits,BucketTraits> bucket_plus_vtraits_t;
1141 typedef ValueTraits value_traits;
1142 typedef typename equal_holder_t::functor_type key_equal;
1143 typedef bucket_hash_t<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, BucketTraits> bucket_hash_type;
1144 typedef typename bucket_hash_type::hasher hasher;
1145 typedef BucketTraits bucket_traits;
1146 typedef typename bucket_plus_vtraits_t::slist_impl::iterator siterator;
1147
1148 template<class BucketTraitsType>
1149 bucket_hash_equal_t(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits, const hasher & h, const key_equal &e)
1150 : bucket_hash_type(val_traits, ::boost::forward<BucketTraitsType>(b_traits), h)
1151 , equal_holder_t(e)
1152 {}
1153
1154 typedef typename detail::unordered_bucket_ptr_impl
1155 <typename bucket_hash_type::value_traits>::type bucket_ptr;
1156
1157 BOOST_INTRUSIVE_FORCEINLINE bucket_ptr &priv_get_cache()
1158 { return cached_begin_; }
1159
1160 BOOST_INTRUSIVE_FORCEINLINE const bucket_ptr &priv_get_cache() const
1161 { return cached_begin_; }
1162
1163 BOOST_INTRUSIVE_FORCEINLINE void priv_set_cache(const bucket_ptr &p)
1164 { cached_begin_ = p; }
1165
1166 BOOST_INTRUSIVE_FORCEINLINE std::size_t priv_get_cache_bucket_num()
1167 { return this->cached_begin_ - this->bucket_hash_type::priv_bucket_pointer(); }
1168
1169 BOOST_INTRUSIVE_FORCEINLINE void priv_initialize_cache()
1170 { this->cached_begin_ = this->bucket_hash_type::priv_invalid_bucket(); }
1171
1172 BOOST_INTRUSIVE_FORCEINLINE void priv_swap_cache(bucket_hash_equal_t &other)
1173 {
1174 ::boost::adl_move_swap(this->cached_begin_, other.cached_begin_);
1175 }
1176
1177 siterator priv_begin() const
1178 {
1179 if(this->cached_begin_ == this->bucket_hash_type::priv_invalid_bucket()){
1180 return this->bucket_hash_type::priv_invalid_local_it();
1181 }
1182 else{
1183 return this->cached_begin_->begin();
1184 }
1185 }
1186
1187 void priv_insertion_update_cache(std::size_t insertion_bucket)
1188 {
1189 bucket_ptr p = this->bucket_hash_type::priv_bucket_pointer() + insertion_bucket;
1190 if(p < this->cached_begin_){
1191 this->cached_begin_ = p;
1192 }
1193 }
1194
1195 BOOST_INTRUSIVE_FORCEINLINE const key_equal &priv_equal() const
1196 { return this->equal_holder_t::get(); }
1197
1198 BOOST_INTRUSIVE_FORCEINLINE key_equal &priv_equal()
1199 { return this->equal_holder_t::get(); }
1200
1201 void priv_erasure_update_cache_range(std::size_t first_bucket_num, std::size_t last_bucket_num)
1202 {
1203 //If the last bucket is the end, the cache must be updated
1204 //to the last position if all
1205 if(this->priv_get_cache_bucket_num() == first_bucket_num &&
1206 this->bucket_hash_type::priv_bucket_pointer()[first_bucket_num].empty() ){
1207 this->priv_set_cache(this->bucket_hash_type::priv_bucket_pointer() + last_bucket_num);
1208 this->priv_erasure_update_cache();
1209 }
1210 }
1211
1212 void priv_erasure_update_cache()
1213 {
1214 if(this->cached_begin_ != this->bucket_hash_type::priv_invalid_bucket()){
1215 std::size_t current_n = this->priv_get_cache() - this->bucket_hash_type::priv_bucket_pointer();
1216 for( const std::size_t num_buckets = this->bucket_hash_type::priv_bucket_count()
1217 ; current_n < num_buckets
1218 ; ++current_n, ++this->priv_get_cache()){
1219 if(!this->priv_get_cache()->empty()){
1220 return;
1221 }
1222 }
1223 this->priv_initialize_cache();
1224 }
1225 }
1226
1227 bucket_ptr cached_begin_;
1228 };
1229
1230 //This wrapper around size_traits is used
1231 //to maintain minimal container size with compilers like MSVC
1232 //that have problems with EBO and multiple empty base classes
1233 template<class DeriveFrom, class SizeType, bool>
1234 struct hashtable_size_traits_wrapper
1235 : public DeriveFrom
1236 {
1237 template<class Base, class Arg0, class Arg1, class Arg2>
1238 hashtable_size_traits_wrapper( BOOST_FWD_REF(Base) base, BOOST_FWD_REF(Arg0) arg0
1239 , BOOST_FWD_REF(Arg1) arg1, BOOST_FWD_REF(Arg2) arg2)
1240 : DeriveFrom(::boost::forward<Base>(base)
1241 , ::boost::forward<Arg0>(arg0)
1242 , ::boost::forward<Arg1>(arg1)
1243 , ::boost::forward<Arg2>(arg2))
1244 {}
1245 typedef detail::size_holder < true, SizeType> size_traits;//size_traits
1246
1247 size_traits size_traits_;
1248
1249 typedef const size_traits & size_traits_const_t;
1250 typedef size_traits & size_traits_t;
1251
1252 BOOST_INTRUSIVE_FORCEINLINE size_traits_const_t priv_size_traits() const
1253 { return size_traits_; }
1254
1255 BOOST_INTRUSIVE_FORCEINLINE size_traits_t priv_size_traits()
1256 { return size_traits_; }
1257 };
1258
1259 template<class DeriveFrom, class SizeType>
1260 struct hashtable_size_traits_wrapper<DeriveFrom, SizeType, false>
1261 : public DeriveFrom
1262 {
1263 template<class Base, class Arg0, class Arg1, class Arg2>
1264 hashtable_size_traits_wrapper( BOOST_FWD_REF(Base) base, BOOST_FWD_REF(Arg0) arg0
1265 , BOOST_FWD_REF(Arg1) arg1, BOOST_FWD_REF(Arg2) arg2)
1266 : DeriveFrom(::boost::forward<Base>(base)
1267 , ::boost::forward<Arg0>(arg0)
1268 , ::boost::forward<Arg1>(arg1)
1269 , ::boost::forward<Arg2>(arg2))
1270 {}
1271
1272 typedef detail::size_holder< false, SizeType> size_traits;
1273
1274 typedef size_traits size_traits_const_t;
1275 typedef size_traits size_traits_t;
1276
1277 BOOST_INTRUSIVE_FORCEINLINE size_traits priv_size_traits() const
1278 { return size_traits(); }
1279 };
1280
1281 //hashdata_internal
1282 //Stores bucket_hash_equal_t and split_traits
1283 template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class BucketTraits, class SizeType, std::size_t BoolFlags>
1284 struct hashdata_internal
1285 : public hashtable_size_traits_wrapper
1286 < bucket_hash_equal_t
1287 < ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual
1288 , BucketTraits
1289 , 0 != (BoolFlags & hash_bool_flags::cache_begin_pos)
1290 > //2
1291 , SizeType
1292 , (BoolFlags & hash_bool_flags::incremental_pos) != 0
1293 >
1294 {
1295 typedef hashtable_size_traits_wrapper
1296 < bucket_hash_equal_t
1297 < ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual
1298 , BucketTraits
1299 , 0 != (BoolFlags & hash_bool_flags::cache_begin_pos)
1300 > //2
1301 , SizeType
1302 , (BoolFlags & hash_bool_flags::incremental_pos) != 0
1303 > internal_type;
1304 typedef typename internal_type::key_equal key_equal;
1305 typedef typename internal_type::hasher hasher;
1306 typedef bucket_plus_vtraits<ValueTraits,BucketTraits> bucket_plus_vtraits_t;
1307 typedef SizeType size_type;
1308 typedef typename internal_type::size_traits split_traits;
1309 typedef typename bucket_plus_vtraits_t::bucket_ptr bucket_ptr;
1310 typedef typename bucket_plus_vtraits_t::const_value_traits_ptr const_value_traits_ptr;
1311 typedef typename bucket_plus_vtraits_t::siterator siterator;
1312 typedef typename bucket_plus_vtraits_t::bucket_traits bucket_traits;
1313 typedef typename bucket_plus_vtraits_t::value_traits value_traits;
1314 typedef typename bucket_plus_vtraits_t::bucket_type bucket_type;
1315 typedef typename value_traits::value_type value_type;
1316 typedef typename value_traits::pointer pointer;
1317 typedef typename value_traits::const_pointer const_pointer;
1318 typedef typename pointer_traits<pointer>::reference reference;
1319 typedef typename pointer_traits
1320 <const_pointer>::reference const_reference;
1321 typedef typename value_traits::node_traits node_traits;
1322 typedef typename node_traits::node node;
1323 typedef typename node_traits::node_ptr node_ptr;
1324 typedef typename node_traits::const_node_ptr const_node_ptr;
1325 typedef detail::node_functions<node_traits> node_functions_t;
1326 typedef typename detail::get_slist_impl
1327 <typename detail::reduced_slist_node_traits
1328 <typename value_traits::node_traits>::type
1329 >::type slist_impl;
1330 typedef typename slist_impl::node_algorithms node_algorithms;
1331 typedef typename slist_impl::node_ptr slist_node_ptr;
1332
1333 typedef hash_key_types_base
1334 < typename ValueTraits::value_type
1335 , VoidOrKeyOfValue
1336 > hash_types_base;
1337 typedef typename hash_types_base::key_of_value key_of_value;
1338
1339 static const bool store_hash = detail::store_hash_is_true<node_traits>::value;
1340 static const bool safemode_or_autounlink = is_safe_autounlink<value_traits::link_mode>::value;
1341 static const bool stateful_value_traits = detail::is_stateful_value_traits<value_traits>::value;
1342
1343 typedef detail::bool_<store_hash> store_hash_t;
1344
1345 typedef detail::transform_iterator
1346 < typename slist_impl::iterator
1347 , downcast_node_to_value_t
1348 < value_traits
1349 , false> > local_iterator;
1350
1351 typedef detail::transform_iterator
1352 < typename slist_impl::iterator
1353 , downcast_node_to_value_t
1354 < value_traits
1355 , true> > const_local_iterator;
1356 //
1357
1358 template<class BucketTraitsType>
1359 hashdata_internal( const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits
1360 , const hasher & h, const key_equal &e)
1361 : internal_type(val_traits, ::boost::forward<BucketTraitsType>(b_traits), h, e)
1362 {}
1363
1364 BOOST_INTRUSIVE_FORCEINLINE typename internal_type::size_traits_t priv_split_traits()
1365 { return this->priv_size_traits(); }
1366
1367 BOOST_INTRUSIVE_FORCEINLINE typename internal_type::size_traits_const_t priv_split_traits() const
1368 { return this->priv_size_traits(); }
1369
1370 ~hashdata_internal()
1371 { this->priv_clear_buckets(); }
1372
1373 void priv_clear_buckets()
1374 {
1375 this->internal_type::priv_clear_buckets
1376 ( this->priv_get_cache()
1377 , this->internal_type::priv_bucket_count()
1378 - (this->priv_get_cache()
1379 - this->internal_type::priv_bucket_pointer()));
1380 }
1381
1382 void priv_clear_buckets_and_cache()
1383 {
1384 this->priv_clear_buckets();
1385 this->priv_initialize_cache();
1386 }
1387
1388 void priv_initialize_buckets_and_cache()
1389 {
1390 this->internal_type::priv_clear_buckets
1391 ( this->internal_type::priv_bucket_pointer()
1392 , this->internal_type::priv_bucket_count());
1393 this->priv_initialize_cache();
1394 }
1395
1396 typedef hashtable_iterator<bucket_plus_vtraits_t, false> iterator;
1397 typedef hashtable_iterator<bucket_plus_vtraits_t, true> const_iterator;
1398
1399 static std::size_t priv_stored_hash(slist_node_ptr n, detail::true_ true_value)
1400 { return bucket_plus_vtraits<ValueTraits, BucketTraits>::priv_stored_hash(n, true_value); }
1401
1402 static std::size_t priv_stored_hash(slist_node_ptr n, detail::false_ false_value)
1403 { return bucket_plus_vtraits<ValueTraits, BucketTraits>::priv_stored_hash(n, false_value); }
1404
1405 //public functions
1406 BOOST_INTRUSIVE_FORCEINLINE SizeType split_count() const
1407 {
1408 return this->priv_split_traits().get_size();
1409 }
1410
1411 BOOST_INTRUSIVE_FORCEINLINE iterator iterator_to(reference value)
1412 {
1413 return iterator(bucket_type::s_iterator_to
1414 (this->priv_value_to_node(value)), &this->get_bucket_value_traits());
1415 }
1416
1417 const_iterator iterator_to(const_reference value) const
1418 {
1419 siterator const sit = bucket_type::s_iterator_to
1420 ( *pointer_traits<node_ptr>::const_cast_from
1421 (pointer_traits<const_node_ptr>::pointer_to(this->priv_value_to_node(value)))
1422 );
1423 return const_iterator(sit, &this->get_bucket_value_traits());
1424 }
1425
1426 static local_iterator s_local_iterator_to(reference value)
1427 {
1428 BOOST_STATIC_ASSERT((!stateful_value_traits));
1429 siterator sit = bucket_type::s_iterator_to(*value_traits::to_node_ptr(value));
1430 return local_iterator(sit, const_value_traits_ptr());
1431 }
1432
1433 static const_local_iterator s_local_iterator_to(const_reference value)
1434 {
1435 BOOST_STATIC_ASSERT((!stateful_value_traits));
1436 siterator const sit = bucket_type::s_iterator_to
1437 ( *pointer_traits<node_ptr>::const_cast_from
1438 (value_traits::to_node_ptr(value))
1439 );
1440 return const_local_iterator(sit, const_value_traits_ptr());
1441 }
1442
1443 local_iterator local_iterator_to(reference value)
1444 {
1445 siterator sit = bucket_type::s_iterator_to(this->priv_value_to_node(value));
1446 return local_iterator(sit, this->priv_value_traits_ptr());
1447 }
1448
1449 const_local_iterator local_iterator_to(const_reference value) const
1450 {
1451 siterator sit = bucket_type::s_iterator_to
1452 ( *pointer_traits<node_ptr>::const_cast_from
1453 (pointer_traits<const_node_ptr>::pointer_to(this->priv_value_to_node(value)))
1454 );
1455 return const_local_iterator(sit, this->priv_value_traits_ptr());
1456 }
1457
1458 BOOST_INTRUSIVE_FORCEINLINE size_type bucket_count() const
1459 {
1460 const std::size_t bc = this->priv_bucket_count();
1461 BOOST_INTRUSIVE_INVARIANT_ASSERT(sizeof(size_type) >= sizeof(std::size_t) || bc <= size_type(-1));
1462 return static_cast<size_type>(bc);
1463 }
1464
1465 BOOST_INTRUSIVE_FORCEINLINE size_type bucket_size(size_type n) const
1466 { return this->priv_bucket_pointer()[n].size(); }
1467
1468 BOOST_INTRUSIVE_FORCEINLINE bucket_ptr bucket_pointer() const
1469 { return this->priv_bucket_pointer(); }
1470
1471 BOOST_INTRUSIVE_FORCEINLINE local_iterator begin(size_type n)
1472 { return local_iterator(this->priv_bucket_pointer()[n].begin(), this->priv_value_traits_ptr()); }
1473
1474 BOOST_INTRUSIVE_FORCEINLINE const_local_iterator begin(size_type n) const
1475 { return this->cbegin(n); }
1476
1477 static BOOST_INTRUSIVE_FORCEINLINE size_type suggested_upper_bucket_count(size_type n)
1478 {
1479 std::size_t c = prime_list_holder<0>::suggested_upper_bucket_count
1480 (sizeof(size_type) > sizeof(std::size_t) && n > std::size_t(-1) ? std::size_t(-1) : static_cast<std::size_t>(n));
1481 return sizeof(size_type) < sizeof(std::size_t) && c > size_type(-1) ? size_type(-1) : static_cast<size_type>(c);
1482 }
1483
1484 static BOOST_INTRUSIVE_FORCEINLINE size_type suggested_lower_bucket_count(size_type n)
1485 {
1486 std::size_t c = prime_list_holder<0>::suggested_lower_bucket_count
1487 (sizeof(size_type) > sizeof(std::size_t) && n > std::size_t(-1) ? std::size_t(-1) : static_cast<std::size_t>(n));
1488 return sizeof(size_type) < sizeof(std::size_t) && c > size_type(-1) ? size_type(-1) : static_cast<size_type>(c);
1489 }
1490
1491 const_local_iterator cbegin(size_type n) const
1492 {
1493 return const_local_iterator
1494 ( pointer_traits<bucket_ptr>::const_cast_from(this->priv_bucket_pointer())[n].begin()
1495 , this->priv_value_traits_ptr());
1496 }
1497
1498 using internal_type::end;
1499 using internal_type::cend;
1500 local_iterator end(size_type n)
1501 { return local_iterator(this->priv_bucket_pointer()[n].end(), this->priv_value_traits_ptr()); }
1502
1503 BOOST_INTRUSIVE_FORCEINLINE const_local_iterator end(size_type n) const
1504 { return this->cend(n); }
1505
1506 const_local_iterator cend(size_type n) const
1507 {
1508 return const_local_iterator
1509 ( pointer_traits<bucket_ptr>::const_cast_from(this->priv_bucket_pointer())[n].end()
1510 , this->priv_value_traits_ptr());
1511 }
1512
1513 //Public functions for hashtable_impl
1514
1515 BOOST_INTRUSIVE_FORCEINLINE iterator begin()
1516 { return iterator(this->priv_begin(), &this->get_bucket_value_traits()); }
1517
1518 BOOST_INTRUSIVE_FORCEINLINE const_iterator begin() const
1519 { return this->cbegin(); }
1520
1521 BOOST_INTRUSIVE_FORCEINLINE const_iterator cbegin() const
1522 { return const_iterator(this->priv_begin(), &this->get_bucket_value_traits()); }
1523
1524 BOOST_INTRUSIVE_FORCEINLINE hasher hash_function() const
1525 { return this->priv_hasher(); }
1526
1527 BOOST_INTRUSIVE_FORCEINLINE key_equal key_eq() const
1528 { return this->priv_equal(); }
1529 };
1530
1531 /// @endcond
1532
1533 //! The class template hashtable is an intrusive hash table container, that
1534 //! is used to construct intrusive unordered_set and unordered_multiset containers. The
1535 //! no-throw guarantee holds only, if the VoidOrKeyEqual object and Hasher don't throw.
1536 //!
1537 //! hashtable is a semi-intrusive container: each object to be stored in the
1538 //! container must contain a proper hook, but the container also needs
1539 //! additional auxiliary memory to work: hashtable needs a pointer to an array
1540 //! of type `bucket_type` to be passed in the constructor. This bucket array must
1541 //! have at least the same lifetime as the container. This makes the use of
1542 //! hashtable more complicated than purely intrusive containers.
1543 //! `bucket_type` is default-constructible, copyable and assignable
1544 //!
1545 //! The template parameter \c T is the type to be managed by the container.
1546 //! The user can specify additional options and if no options are provided
1547 //! default options are used.
1548 //!
1549 //! The container supports the following options:
1550 //! \c base_hook<>/member_hook<>/value_traits<>,
1551 //! \c constant_time_size<>, \c size_type<>, \c hash<> and \c equal<>
1552 //! \c bucket_traits<>, power_2_buckets<>, cache_begin<> and incremental<>.
1553 //!
1554 //! hashtable only provides forward iterators but it provides 4 iterator types:
1555 //! iterator and const_iterator to navigate through the whole container and
1556 //! local_iterator and const_local_iterator to navigate through the values
1557 //! stored in a single bucket. Local iterators are faster and smaller.
1558 //!
1559 //! It's not recommended to use non constant-time size hashtables because several
1560 //! key functions, like "empty()", become non-constant time functions. Non
1561 //! constant_time size hashtables are mainly provided to support auto-unlink hooks.
1562 //!
1563 //! hashtables, does not make automatic rehashings nor
1564 //! offers functions related to a load factor. Rehashing can be explicitly requested
1565 //! and the user must provide a new bucket array that will be used from that moment.
1566 //!
1567 //! Since no automatic rehashing is done, iterators are never invalidated when
1568 //! inserting or erasing elements. Iterators are only invalidated when rehashing.
1569 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
1570 template<class T, class ...Options>
1571 #else
1572 template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class BucketTraits, class SizeType, std::size_t BoolFlags>
1573 #endif
1574 class hashtable_impl
1575 : private hashtable_size_traits_wrapper
1576 < hashdata_internal
1577 < ValueTraits
1578 , VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual
1579 , BucketTraits, SizeType
1580 , BoolFlags & (hash_bool_flags::incremental_pos | hash_bool_flags::cache_begin_pos) //1
1581 >
1582 , SizeType
1583 , (BoolFlags & hash_bool_flags::constant_time_size_pos) != 0
1584 >
1585 {
1586 typedef hashtable_size_traits_wrapper
1587 < hashdata_internal
1588 < ValueTraits
1589 , VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual
1590 , BucketTraits, SizeType
1591 , BoolFlags & (hash_bool_flags::incremental_pos | hash_bool_flags::cache_begin_pos) //1
1592 >
1593 , SizeType
1594 , (BoolFlags & hash_bool_flags::constant_time_size_pos) != 0
1595 > internal_type;
1596 typedef typename internal_type::size_traits size_traits;
1597 typedef hash_key_types_base
1598 < typename ValueTraits::value_type
1599 , VoidOrKeyOfValue
1600 > hash_types_base;
1601 public:
1602 typedef ValueTraits value_traits;
1603
1604 /// @cond
1605 typedef BucketTraits bucket_traits;
1606
1607 typedef typename internal_type::slist_impl slist_impl;
1608 typedef bucket_plus_vtraits<ValueTraits, BucketTraits> bucket_plus_vtraits_t;
1609 typedef typename bucket_plus_vtraits_t::const_value_traits_ptr const_value_traits_ptr;
1610
1611 using internal_type::begin;
1612 using internal_type::cbegin;
1613 using internal_type::end;
1614 using internal_type::cend;
1615 using internal_type::hash_function;
1616 using internal_type::key_eq;
1617 using internal_type::bucket_size;
1618 using internal_type::bucket_count;
1619 using internal_type::local_iterator_to;
1620 using internal_type::s_local_iterator_to;
1621 using internal_type::iterator_to;
1622 using internal_type::bucket_pointer;
1623 using internal_type::suggested_upper_bucket_count;
1624 using internal_type::suggested_lower_bucket_count;
1625 using internal_type::split_count;
1626
1627 /// @endcond
1628
1629 typedef typename value_traits::pointer pointer;
1630 typedef typename value_traits::const_pointer const_pointer;
1631 typedef typename value_traits::value_type value_type;
1632 typedef typename hash_types_base::key_type key_type;
1633 typedef typename hash_types_base::key_of_value key_of_value;
1634 typedef typename pointer_traits<pointer>::reference reference;
1635 typedef typename pointer_traits<const_pointer>::reference const_reference;
1636 typedef typename pointer_traits<pointer>::difference_type difference_type;
1637 typedef SizeType size_type;
1638 typedef typename internal_type::key_equal key_equal;
1639 typedef typename internal_type::hasher hasher;
1640 typedef detail::bucket_impl<slist_impl> bucket_type;
1641 typedef typename internal_type::bucket_ptr bucket_ptr;
1642 typedef typename slist_impl::iterator siterator;
1643 typedef typename slist_impl::const_iterator const_siterator;
1644 typedef typename internal_type::iterator iterator;
1645 typedef typename internal_type::const_iterator const_iterator;
1646 typedef typename internal_type::local_iterator local_iterator;
1647 typedef typename internal_type::const_local_iterator const_local_iterator;
1648 typedef typename value_traits::node_traits node_traits;
1649 typedef typename node_traits::node node;
1650 typedef typename pointer_traits
1651 <pointer>::template rebind_pointer
1652 < node >::type node_ptr;
1653 typedef typename pointer_traits
1654 <pointer>::template rebind_pointer
1655 < const node >::type const_node_ptr;
1656 typedef typename pointer_traits
1657 <node_ptr>::reference node_reference;
1658 typedef typename pointer_traits
1659 <const_node_ptr>::reference const_node_reference;
1660 typedef typename slist_impl::node_algorithms node_algorithms;
1661
1662 static const bool stateful_value_traits = internal_type::stateful_value_traits;
1663 static const bool store_hash = internal_type::store_hash;
1664
1665 static const bool unique_keys = 0 != (BoolFlags & hash_bool_flags::unique_keys_pos);
1666 static const bool constant_time_size = 0 != (BoolFlags & hash_bool_flags::constant_time_size_pos);
1667 static const bool cache_begin = 0 != (BoolFlags & hash_bool_flags::cache_begin_pos);
1668 static const bool compare_hash = 0 != (BoolFlags & hash_bool_flags::compare_hash_pos);
1669 static const bool incremental = 0 != (BoolFlags & hash_bool_flags::incremental_pos);
1670 static const bool power_2_buckets = incremental || (0 != (BoolFlags & hash_bool_flags::power_2_buckets_pos));
1671
1672 static const bool optimize_multikey
1673 = detail::optimize_multikey_is_true<node_traits>::value && !unique_keys;
1674
1675 /// @cond
1676 static const bool is_multikey = !unique_keys;
1677 private:
1678
1679 //Configuration error: compare_hash<> can't be specified without store_hash<>
1680 //See documentation for more explanations
1681 BOOST_STATIC_ASSERT((!compare_hash || store_hash));
1682
1683 typedef typename slist_impl::node_ptr slist_node_ptr;
1684 typedef typename pointer_traits
1685 <slist_node_ptr>::template rebind_pointer
1686 < void >::type void_pointer;
1687 //We'll define group traits, but these won't be instantiated if
1688 //optimize_multikey is not true
1689 typedef unordered_group_adapter<node_traits> group_traits;
1690 typedef circular_slist_algorithms<group_traits> group_algorithms;
1691 typedef typename internal_type::store_hash_t store_hash_t;
1692 typedef detail::bool_<optimize_multikey> optimize_multikey_t;
1693 typedef detail::bool_<cache_begin> cache_begin_t;
1694 typedef detail::bool_<power_2_buckets> power_2_buckets_t;
1695 typedef typename internal_type::split_traits split_traits;
1696 typedef detail::group_functions<node_traits> group_functions_t;
1697 typedef detail::node_functions<node_traits> node_functions_t;
1698
1699 private:
1700 //noncopyable, movable
1701 BOOST_MOVABLE_BUT_NOT_COPYABLE(hashtable_impl)
1702
1703 static const bool safemode_or_autounlink = internal_type::safemode_or_autounlink;
1704
1705 //Constant-time size is incompatible with auto-unlink hooks!
1706 BOOST_STATIC_ASSERT(!(constant_time_size && ((int)value_traits::link_mode == (int)auto_unlink)));
1707 //Cache begin is incompatible with auto-unlink hooks!
1708 BOOST_STATIC_ASSERT(!(cache_begin && ((int)value_traits::link_mode == (int)auto_unlink)));
1709
1710 template<class Disposer>
1711 struct typeof_node_disposer
1712 {
1713 typedef node_cast_adaptor
1714 < detail::node_disposer< Disposer, value_traits, CircularSListAlgorithms>
1715 , slist_node_ptr, node_ptr > type;
1716 };
1717
1718 template<class Disposer>
1719 typename typeof_node_disposer<Disposer>::type
1720 make_node_disposer(const Disposer &disposer) const
1721 {
1722 typedef typename typeof_node_disposer<Disposer>::type return_t;
1723 return return_t(disposer, &this->priv_value_traits());
1724 }
1725
1726 /// @endcond
1727
1728 public:
1729 typedef detail::insert_commit_data_impl insert_commit_data;
1730
1731
1732 public:
1733
1734 //! <b>Requires</b>: buckets must not be being used by any other resource.
1735 //!
1736 //! <b>Effects</b>: Constructs an empty unordered_set, storing a reference
1737 //! to the bucket array and copies of the key_hasher and equal_func functors.
1738 //!
1739 //! <b>Complexity</b>: Constant.
1740 //!
1741 //! <b>Throws</b>: If value_traits::node_traits::node
1742 //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
1743 //! or the copy constructor or invocation of hash_func or equal_func throws.
1744 //!
1745 //! <b>Notes</b>: buckets array must be disposed only after
1746 //! *this is disposed.
1747 explicit hashtable_impl ( const bucket_traits &b_traits
1748 , const hasher & hash_func = hasher()
1749 , const key_equal &equal_func = key_equal()
1750 , const value_traits &v_traits = value_traits())
1751 : internal_type(v_traits, b_traits, hash_func, equal_func)
1752 {
1753 this->priv_initialize_buckets_and_cache();
1754 this->priv_size_traits().set_size(size_type(0));
1755 size_type bucket_sz = this->bucket_count();
1756 BOOST_INTRUSIVE_INVARIANT_ASSERT(bucket_sz != 0);
1757 //Check power of two bucket array if the option is activated
1758 BOOST_INTRUSIVE_INVARIANT_ASSERT
1759 (!power_2_buckets || (0 == (bucket_sz & (bucket_sz-1))));
1760 this->priv_split_traits().set_size(bucket_sz>>1);
1761 }
1762
1763 //! <b>Requires</b>: buckets must not be being used by any other resource
1764 //! and dereferencing iterator must yield an lvalue of type value_type.
1765 //!
1766 //! <b>Effects</b>: Constructs an empty container and inserts elements from
1767 //! [b, e).
1768 //!
1769 //! <b>Complexity</b>: If N is distance(b, e): Average case is O(N)
1770 //! (with a good hash function and with buckets_len >= N),worst case O(N^2).
1771 //!
1772 //! <b>Throws</b>: If value_traits::node_traits::node
1773 //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
1774 //! or the copy constructor or invocation of hasher or key_equal throws.
1775 //!
1776 //! <b>Notes</b>: buckets array must be disposed only after
1777 //! *this is disposed.
1778 template<class Iterator>
1779 hashtable_impl ( bool unique, Iterator b, Iterator e
1780 , const bucket_traits &b_traits
1781 , const hasher & hash_func = hasher()
1782 , const key_equal &equal_func = key_equal()
1783 , const value_traits &v_traits = value_traits())
1784 : internal_type(v_traits, b_traits, hash_func, equal_func)
1785 {
1786 this->priv_initialize_buckets_and_cache();
1787 this->priv_size_traits().set_size(size_type(0));
1788 size_type bucket_sz = this->bucket_count();
1789 BOOST_INTRUSIVE_INVARIANT_ASSERT(bucket_sz != 0);
1790 //Check power of two bucket array if the option is activated
1791 BOOST_INTRUSIVE_INVARIANT_ASSERT
1792 (!power_2_buckets || (0 == (bucket_sz & (bucket_sz-1))));
1793 this->priv_split_traits().set_size(bucket_sz>>1);
1794 //Now insert
1795 if(unique)
1796 this->insert_unique(b, e);
1797 else
1798 this->insert_equal(b, e);
1799 }
1800
1801 //! <b>Effects</b>: Constructs a container moving resources from another container.
1802 //! Internal value traits, bucket traits, hasher and comparison are move constructed and
1803 //! nodes belonging to x are linked to *this.
1804 //!
1805 //! <b>Complexity</b>: Constant.
1806 //!
1807 //! <b>Throws</b>: If value_traits::node_traits::node's
1808 //! move constructor throws (this does not happen with predefined Boost.Intrusive hooks)
1809 //! or the move constructor of value traits, bucket traits, hasher or comparison throws.
1810 hashtable_impl(BOOST_RV_REF(hashtable_impl) x)
1811 : internal_type( ::boost::move(x.priv_value_traits())
1812 , ::boost::move(x.priv_bucket_traits())
1813 , ::boost::move(x.priv_hasher())
1814 , ::boost::move(x.priv_equal())
1815 )
1816 {
1817 this->priv_swap_cache(x);
1818 x.priv_initialize_cache();
1819 this->priv_size_traits().set_size(x.priv_size_traits().get_size());
1820 x.priv_size_traits().set_size(size_type(0));
1821 this->priv_split_traits().set_size(x.priv_split_traits().get_size());
1822 x.priv_split_traits().set_size(size_type(0));
1823 }
1824
1825 //! <b>Effects</b>: Equivalent to swap.
1826 //!
1827 hashtable_impl& operator=(BOOST_RV_REF(hashtable_impl) x)
1828 { this->swap(x); return *this; }
1829
1830 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
1831 //! <b>Effects</b>: Detaches all elements from this. The objects in the unordered_set
1832 //! are not deleted (i.e. no destructors are called).
1833 //!
1834 //! <b>Complexity</b>: Linear to the number of elements in the unordered_set, if
1835 //! it's a safe-mode or auto-unlink value. Otherwise constant.
1836 //!
1837 //! <b>Throws</b>: Nothing.
1838 ~hashtable_impl();
1839
1840 //! <b>Effects</b>: Returns an iterator pointing to the beginning of the unordered_set.
1841 //!
1842 //! <b>Complexity</b>: Amortized constant time.
1843 //! Worst case (empty unordered_set): O(this->bucket_count())
1844 //!
1845 //! <b>Throws</b>: Nothing.
1846 iterator begin();
1847
1848 //! <b>Effects</b>: Returns a const_iterator pointing to the beginning
1849 //! of the unordered_set.
1850 //!
1851 //! <b>Complexity</b>: Amortized constant time.
1852 //! Worst case (empty unordered_set): O(this->bucket_count())
1853 //!
1854 //! <b>Throws</b>: Nothing.
1855 const_iterator begin() const;
1856
1857 //! <b>Effects</b>: Returns a const_iterator pointing to the beginning
1858 //! of the unordered_set.
1859 //!
1860 //! <b>Complexity</b>: Amortized constant time.
1861 //! Worst case (empty unordered_set): O(this->bucket_count())
1862 //!
1863 //! <b>Throws</b>: Nothing.
1864 const_iterator cbegin() const;
1865
1866 //! <b>Effects</b>: Returns an iterator pointing to the end of the unordered_set.
1867 //!
1868 //! <b>Complexity</b>: Constant.
1869 //!
1870 //! <b>Throws</b>: Nothing.
1871 iterator end();
1872
1873 //! <b>Effects</b>: Returns a const_iterator pointing to the end of the unordered_set.
1874 //!
1875 //! <b>Complexity</b>: Constant.
1876 //!
1877 //! <b>Throws</b>: Nothing.
1878 const_iterator end() const;
1879
1880 //! <b>Effects</b>: Returns a const_iterator pointing to the end of the unordered_set.
1881 //!
1882 //! <b>Complexity</b>: Constant.
1883 //!
1884 //! <b>Throws</b>: Nothing.
1885 const_iterator cend() const;
1886
1887 //! <b>Effects</b>: Returns the hasher object used by the unordered_set.
1888 //!
1889 //! <b>Complexity</b>: Constant.
1890 //!
1891 //! <b>Throws</b>: If hasher copy-constructor throws.
1892 hasher hash_function() const;
1893
1894 //! <b>Effects</b>: Returns the key_equal object used by the unordered_set.
1895 //!
1896 //! <b>Complexity</b>: Constant.
1897 //!
1898 //! <b>Throws</b>: If key_equal copy-constructor throws.
1899 key_equal key_eq() const;
1900
1901 #endif
1902
1903 //! <b>Effects</b>: Returns true if the container is empty.
1904 //!
1905 //! <b>Complexity</b>: if constant-time size and cache_begin options are disabled,
1906 //! average constant time (worst case, with empty() == true: O(this->bucket_count()).
1907 //! Otherwise constant.
1908 //!
1909 //! <b>Throws</b>: Nothing.
1910 bool empty() const
1911 {
1912 if(constant_time_size){
1913 return !this->size();
1914 }
1915 else if(cache_begin){
1916 return this->begin() == this->end();
1917 }
1918 else{
1919 size_type bucket_cnt = this->bucket_count();
1920 const bucket_type *b = boost::movelib::to_raw_pointer(this->priv_bucket_pointer());
1921 for (size_type n = 0; n < bucket_cnt; ++n, ++b){
1922 if(!b->empty()){
1923 return false;
1924 }
1925 }
1926 return true;
1927 }
1928 }
1929
1930 //! <b>Effects</b>: Returns the number of elements stored in the unordered_set.
1931 //!
1932 //! <b>Complexity</b>: Linear to elements contained in *this if
1933 //! constant_time_size is false. Constant-time otherwise.
1934 //!
1935 //! <b>Throws</b>: Nothing.
1936 size_type size() const
1937 {
1938 if(constant_time_size)
1939 return this->priv_size_traits().get_size();
1940 else{
1941 size_type len = 0;
1942 size_type bucket_cnt = this->bucket_count();
1943 const bucket_type *b = boost::movelib::to_raw_pointer(this->priv_bucket_pointer());
1944 for (size_type n = 0; n < bucket_cnt; ++n, ++b){
1945 len += b->size();
1946 }
1947 return len;
1948 }
1949 }
1950
1951 //! <b>Requires</b>: the hasher and the equality function unqualified swap
1952 //! call should not throw.
1953 //!
1954 //! <b>Effects</b>: Swaps the contents of two unordered_sets.
1955 //! Swaps also the contained bucket array and equality and hasher functors.
1956 //!
1957 //! <b>Complexity</b>: Constant.
1958 //!
1959 //! <b>Throws</b>: If the swap() call for the comparison or hash functors
1960 //! found using ADL throw. Basic guarantee.
1961 void swap(hashtable_impl& other)
1962 {
1963 //These can throw
1964 ::boost::adl_move_swap(this->priv_equal(), other.priv_equal());
1965 ::boost::adl_move_swap(this->priv_hasher(), other.priv_hasher());
1966 //These can't throw
1967 ::boost::adl_move_swap(this->priv_bucket_traits(), other.priv_bucket_traits());
1968 ::boost::adl_move_swap(this->priv_value_traits(), other.priv_value_traits());
1969 this->priv_swap_cache(other);
1970 this->priv_size_traits().swap(other.priv_size_traits());
1971 this->priv_split_traits().swap(other.priv_split_traits());
1972 }
1973
1974 //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw
1975 //! Cloner should yield to nodes that compare equal and produce the same
1976 //! hash than the original node.
1977 //!
1978 //! <b>Effects</b>: Erases all the elements from *this
1979 //! calling Disposer::operator()(pointer), clones all the
1980 //! elements from src calling Cloner::operator()(const_reference )
1981 //! and inserts them on *this. The hash function and the equality
1982 //! predicate are copied from the source.
1983 //!
1984 //! If store_hash option is true, this method does not use the hash function.
1985 //!
1986 //! If any operation throws, all cloned elements are unlinked and disposed
1987 //! calling Disposer::operator()(pointer).
1988 //!
1989 //! <b>Complexity</b>: Linear to erased plus inserted elements.
1990 //!
1991 //! <b>Throws</b>: If cloner or hasher throw or hash or equality predicate copying
1992 //! throws. Basic guarantee.
1993 template <class Cloner, class Disposer>
1994 BOOST_INTRUSIVE_FORCEINLINE void clone_from(const hashtable_impl &src, Cloner cloner, Disposer disposer)
1995 { this->priv_clone_from(src, cloner, disposer); }
1996
1997 //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw
1998 //! Cloner should yield to nodes that compare equal and produce the same
1999 //! hash than the original node.
2000 //!
2001 //! <b>Effects</b>: Erases all the elements from *this
2002 //! calling Disposer::operator()(pointer), clones all the
2003 //! elements from src calling Cloner::operator()(reference)
2004 //! and inserts them on *this. The hash function and the equality
2005 //! predicate are copied from the source.
2006 //!
2007 //! If store_hash option is true, this method does not use the hash function.
2008 //!
2009 //! If any operation throws, all cloned elements are unlinked and disposed
2010 //! calling Disposer::operator()(pointer).
2011 //!
2012 //! <b>Complexity</b>: Linear to erased plus inserted elements.
2013 //!
2014 //! <b>Throws</b>: If cloner or hasher throw or hash or equality predicate copying
2015 //! throws. Basic guarantee.
2016 template <class Cloner, class Disposer>
2017 BOOST_INTRUSIVE_FORCEINLINE void clone_from(BOOST_RV_REF(hashtable_impl) src, Cloner cloner, Disposer disposer)
2018 { this->priv_clone_from(static_cast<hashtable_impl&>(src), cloner, disposer); }
2019
2020 //! <b>Requires</b>: value must be an lvalue
2021 //!
2022 //! <b>Effects</b>: Inserts the value into the unordered_set.
2023 //!
2024 //! <b>Returns</b>: An iterator to the inserted value.
2025 //!
2026 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2027 //!
2028 //! <b>Throws</b>: If the internal hasher or the equality functor throws. Strong guarantee.
2029 //!
2030 //! <b>Note</b>: Does not affect the validity of iterators and references.
2031 //! No copy-constructors are called.
2032 iterator insert_equal(reference value)
2033 {
2034 size_type bucket_num;
2035 std::size_t hash_value;
2036 siterator prev;
2037 siterator const it = this->priv_find
2038 (key_of_value()(value), this->priv_hasher(), this->priv_equal(), bucket_num, hash_value, prev);
2039 bool const next_is_in_group = optimize_multikey && it != this->priv_invalid_local_it();
2040 return this->priv_insert_equal_after_find(value, bucket_num, hash_value, prev, next_is_in_group);
2041 }
2042
2043 //! <b>Requires</b>: Dereferencing iterator must yield an lvalue
2044 //! of type value_type.
2045 //!
2046 //! <b>Effects</b>: Equivalent to this->insert_equal(t) for each element in [b, e).
2047 //!
2048 //! <b>Complexity</b>: Average case O(N), where N is distance(b, e).
2049 //! Worst case O(N*this->size()).
2050 //!
2051 //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.
2052 //!
2053 //! <b>Note</b>: Does not affect the validity of iterators and references.
2054 //! No copy-constructors are called.
2055 template<class Iterator>
2056 void insert_equal(Iterator b, Iterator e)
2057 {
2058 for (; b != e; ++b)
2059 this->insert_equal(*b);
2060 }
2061
2062 //! <b>Requires</b>: value must be an lvalue
2063 //!
2064 //! <b>Effects</b>: Tries to inserts value into the unordered_set.
2065 //!
2066 //! <b>Returns</b>: If the value
2067 //! is not already present inserts it and returns a pair containing the
2068 //! iterator to the new value and true. If there is an equivalent value
2069 //! returns a pair containing an iterator to the already present value
2070 //! and false.
2071 //!
2072 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2073 //!
2074 //! <b>Throws</b>: If the internal hasher or the equality functor throws. Strong guarantee.
2075 //!
2076 //! <b>Note</b>: Does not affect the validity of iterators and references.
2077 //! No copy-constructors are called.
2078 std::pair<iterator, bool> insert_unique(reference value)
2079 {
2080 insert_commit_data commit_data;
2081 std::pair<iterator, bool> ret = this->insert_unique_check(key_of_value()(value), commit_data);
2082 if(ret.second){
2083 ret.first = this->insert_unique_commit(value, commit_data);
2084 }
2085 return ret;
2086 }
2087
2088 //! <b>Requires</b>: Dereferencing iterator must yield an lvalue
2089 //! of type value_type.
2090 //!
2091 //! <b>Effects</b>: Equivalent to this->insert_unique(t) for each element in [b, e).
2092 //!
2093 //! <b>Complexity</b>: Average case O(N), where N is distance(b, e).
2094 //! Worst case O(N*this->size()).
2095 //!
2096 //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.
2097 //!
2098 //! <b>Note</b>: Does not affect the validity of iterators and references.
2099 //! No copy-constructors are called.
2100 template<class Iterator>
2101 void insert_unique(Iterator b, Iterator e)
2102 {
2103 for (; b != e; ++b)
2104 this->insert_unique(*b);
2105 }
2106
2107 //! <b>Requires</b>: "hash_func" must be a hash function that induces
2108 //! the same hash values as the stored hasher. The difference is that
2109 //! "hash_func" hashes the given key instead of the value_type.
2110 //!
2111 //! "equal_func" must be a equality function that induces
2112 //! the same equality as key_equal. The difference is that
2113 //! "equal_func" compares an arbitrary key with the contained values.
2114 //!
2115 //! <b>Effects</b>: Checks if a value can be inserted in the unordered_set, using
2116 //! a user provided key instead of the value itself.
2117 //!
2118 //! <b>Returns</b>: If there is an equivalent value
2119 //! returns a pair containing an iterator to the already present value
2120 //! and false. If the value can be inserted returns true in the returned
2121 //! pair boolean and fills "commit_data" that is meant to be used with
2122 //! the "insert_commit" function.
2123 //!
2124 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2125 //!
2126 //! <b>Throws</b>: If hash_func or equal_func throw. Strong guarantee.
2127 //!
2128 //! <b>Notes</b>: This function is used to improve performance when constructing
2129 //! a value_type is expensive: if there is an equivalent value
2130 //! the constructed object must be discarded. Many times, the part of the
2131 //! node that is used to impose the hash or the equality is much cheaper to
2132 //! construct than the value_type and this function offers the possibility to
2133 //! use that the part to check if the insertion will be successful.
2134 //!
2135 //! If the check is successful, the user can construct the value_type and use
2136 //! "insert_commit" to insert the object in constant-time.
2137 //!
2138 //! "commit_data" remains valid for a subsequent "insert_commit" only if no more
2139 //! objects are inserted or erased from the unordered_set.
2140 //!
2141 //! After a successful rehashing insert_commit_data remains valid.
2142 template<class KeyType, class KeyHasher, class KeyEqual>
2143 std::pair<iterator, bool> insert_unique_check
2144 ( const KeyType &key
2145 , KeyHasher hash_func
2146 , KeyEqual equal_func
2147 , insert_commit_data &commit_data)
2148 {
2149 size_type bucket_num;
2150 siterator prev;
2151 siterator const pos = this->priv_find(key, hash_func, equal_func, bucket_num, commit_data.hash, prev);
2152 return std::pair<iterator, bool>
2153 ( iterator(pos, &this->get_bucket_value_traits())
2154 , pos == this->priv_invalid_local_it());
2155 }
2156
2157 //! <b>Effects</b>: Checks if a value can be inserted in the unordered_set, using
2158 //! a user provided key instead of the value itself.
2159 //!
2160 //! <b>Returns</b>: If there is an equivalent value
2161 //! returns a pair containing an iterator to the already present value
2162 //! and false. If the value can be inserted returns true in the returned
2163 //! pair boolean and fills "commit_data" that is meant to be used with
2164 //! the "insert_commit" function.
2165 //!
2166 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2167 //!
2168 //! <b>Throws</b>: If hasher or key_compare throw. Strong guarantee.
2169 //!
2170 //! <b>Notes</b>: This function is used to improve performance when constructing
2171 //! a value_type is expensive: if there is an equivalent value
2172 //! the constructed object must be discarded. Many times, the part of the
2173 //! node that is used to impose the hash or the equality is much cheaper to
2174 //! construct than the value_type and this function offers the possibility to
2175 //! use that the part to check if the insertion will be successful.
2176 //!
2177 //! If the check is successful, the user can construct the value_type and use
2178 //! "insert_commit" to insert the object in constant-time.
2179 //!
2180 //! "commit_data" remains valid for a subsequent "insert_commit" only if no more
2181 //! objects are inserted or erased from the unordered_set.
2182 //!
2183 //! After a successful rehashing insert_commit_data remains valid.
2184 BOOST_INTRUSIVE_FORCEINLINE std::pair<iterator, bool> insert_unique_check
2185 ( const key_type &key, insert_commit_data &commit_data)
2186 { return this->insert_unique_check(key, this->priv_hasher(), this->priv_equal(), commit_data); }
2187
2188 //! <b>Requires</b>: value must be an lvalue of type value_type. commit_data
2189 //! must have been obtained from a previous call to "insert_check".
2190 //! No objects should have been inserted or erased from the unordered_set between
2191 //! the "insert_check" that filled "commit_data" and the call to "insert_commit".
2192 //!
2193 //! <b>Effects</b>: Inserts the value in the unordered_set using the information obtained
2194 //! from the "commit_data" that a previous "insert_check" filled.
2195 //!
2196 //! <b>Returns</b>: An iterator to the newly inserted object.
2197 //!
2198 //! <b>Complexity</b>: Constant time.
2199 //!
2200 //! <b>Throws</b>: Nothing.
2201 //!
2202 //! <b>Notes</b>: This function has only sense if a "insert_check" has been
2203 //! previously executed to fill "commit_data". No value should be inserted or
2204 //! erased between the "insert_check" and "insert_commit" calls.
2205 //!
2206 //! After a successful rehashing insert_commit_data remains valid.
2207 iterator insert_unique_commit(reference value, const insert_commit_data &commit_data)
2208 {
2209 size_type bucket_num = this->priv_hash_to_bucket(commit_data.hash);
2210 bucket_type &b = this->priv_bucket_pointer()[bucket_num];
2211 this->priv_size_traits().increment();
2212 node_ptr const n = pointer_traits<node_ptr>::pointer_to(this->priv_value_to_node(value));
2213 BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(!safemode_or_autounlink || node_algorithms::unique(n));
2214 node_functions_t::store_hash(n, commit_data.hash, store_hash_t());
2215 this->priv_insertion_update_cache(bucket_num);
2216 group_functions_t::insert_in_group(n, n, optimize_multikey_t());
2217 return iterator(b.insert_after(b.before_begin(), *n), &this->get_bucket_value_traits());
2218 }
2219
2220 //! <b>Effects</b>: Erases the element pointed to by i.
2221 //!
2222 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2223 //!
2224 //! <b>Throws</b>: Nothing.
2225 //!
2226 //! <b>Note</b>: Invalidates the iterators (but not the references)
2227 //! to the erased element. No destructors are called.
2228 BOOST_INTRUSIVE_FORCEINLINE void erase(const_iterator i)
2229 { this->erase_and_dispose(i, detail::null_disposer()); }
2230
2231 //! <b>Effects</b>: Erases the range pointed to by b end e.
2232 //!
2233 //! <b>Complexity</b>: Average case O(distance(b, e)),
2234 //! worst case O(this->size()).
2235 //!
2236 //! <b>Throws</b>: Nothing.
2237 //!
2238 //! <b>Note</b>: Invalidates the iterators (but not the references)
2239 //! to the erased elements. No destructors are called.
2240 BOOST_INTRUSIVE_FORCEINLINE void erase(const_iterator b, const_iterator e)
2241 { this->erase_and_dispose(b, e, detail::null_disposer()); }
2242
2243 //! <b>Effects</b>: Erases all the elements with the given value.
2244 //!
2245 //! <b>Returns</b>: The number of erased elements.
2246 //!
2247 //! <b>Complexity</b>: Average case O(this->count(value)).
2248 //! Worst case O(this->size()).
2249 //!
2250 //! <b>Throws</b>: If the internal hasher or the equality functor throws.
2251 //! Basic guarantee.
2252 //!
2253 //! <b>Note</b>: Invalidates the iterators (but not the references)
2254 //! to the erased elements. No destructors are called.
2255 BOOST_INTRUSIVE_FORCEINLINE size_type erase(const key_type &key)
2256 { return this->erase(key, this->priv_hasher(), this->priv_equal()); }
2257
2258 //! <b>Requires</b>: "hash_func" must be a hash function that induces
2259 //! the same hash values as the stored hasher. The difference is that
2260 //! "hash_func" hashes the given key instead of the value_type.
2261 //!
2262 //! "equal_func" must be a equality function that induces
2263 //! the same equality as key_equal. The difference is that
2264 //! "equal_func" compares an arbitrary key with the contained values.
2265 //!
2266 //! <b>Effects</b>: Erases all the elements that have the same hash and
2267 //! compare equal with the given key.
2268 //!
2269 //! <b>Returns</b>: The number of erased elements.
2270 //!
2271 //! <b>Complexity</b>: Average case O(this->count(value)).
2272 //! Worst case O(this->size()).
2273 //!
2274 //! <b>Throws</b>: If hash_func or equal_func throw. Basic guarantee.
2275 //!
2276 //! <b>Note</b>: Invalidates the iterators (but not the references)
2277 //! to the erased elements. No destructors are called.
2278 template<class KeyType, class KeyHasher, class KeyEqual>
2279 BOOST_INTRUSIVE_FORCEINLINE size_type erase(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func)
2280 { return this->erase_and_dispose(key, hash_func, equal_func, detail::null_disposer()); }
2281
2282 //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
2283 //!
2284 //! <b>Effects</b>: Erases the element pointed to by i.
2285 //! Disposer::operator()(pointer) is called for the removed element.
2286 //!
2287 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2288 //!
2289 //! <b>Throws</b>: Nothing.
2290 //!
2291 //! <b>Note</b>: Invalidates the iterators
2292 //! to the erased elements.
2293 template<class Disposer>
2294 BOOST_INTRUSIVE_DOC1ST(void
2295 , typename detail::disable_if_convertible<Disposer BOOST_INTRUSIVE_I const_iterator>::type)
2296 erase_and_dispose(const_iterator i, Disposer disposer)
2297 {
2298 //Get the bucket number and local iterator for both iterators
2299 siterator const first_local_it(i.slist_it());
2300 size_type const first_bucket_num = this->priv_get_bucket_num(first_local_it);
2301 this->priv_erase_node(this->priv_bucket_pointer()[first_bucket_num], first_local_it, make_node_disposer(disposer), optimize_multikey_t());
2302 this->priv_size_traits().decrement();
2303 this->priv_erasure_update_cache_range(first_bucket_num, first_bucket_num);
2304 }
2305
2306 //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
2307 //!
2308 //! <b>Effects</b>: Erases the range pointed to by b end e.
2309 //! Disposer::operator()(pointer) is called for the removed elements.
2310 //!
2311 //! <b>Complexity</b>: Average case O(distance(b, e)),
2312 //! worst case O(this->size()).
2313 //!
2314 //! <b>Throws</b>: Nothing.
2315 //!
2316 //! <b>Note</b>: Invalidates the iterators
2317 //! to the erased elements.
2318 template<class Disposer>
2319 void erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer)
2320 {
2321 if(b != e){
2322 //Get the bucket number and local iterator for both iterators
2323 siterator first_local_it(b.slist_it());
2324 size_type first_bucket_num = this->priv_get_bucket_num(first_local_it);
2325
2326 const bucket_ptr buck_ptr = this->priv_bucket_pointer();
2327 siterator before_first_local_it
2328 = this->priv_get_previous(buck_ptr[first_bucket_num], first_local_it);
2329 size_type last_bucket_num;
2330 siterator last_local_it;
2331
2332 //For the end iterator, we will assign the end iterator
2333 //of the last bucket
2334 if(e == this->end()){
2335 last_bucket_num = this->bucket_count() - 1;
2336 last_local_it = buck_ptr[last_bucket_num].end();
2337 }
2338 else{
2339 last_local_it = e.slist_it();
2340 last_bucket_num = this->priv_get_bucket_num(last_local_it);
2341 }
2342 size_type const num_erased = this->priv_erase_node_range
2343 ( before_first_local_it, first_bucket_num, last_local_it, last_bucket_num
2344 , make_node_disposer(disposer), optimize_multikey_t());
2345 this->priv_size_traits().set_size(this->priv_size_traits().get_size()-num_erased);
2346 this->priv_erasure_update_cache_range(first_bucket_num, last_bucket_num);
2347 }
2348 }
2349
2350 //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
2351 //!
2352 //! <b>Effects</b>: Erases all the elements with the given value.
2353 //! Disposer::operator()(pointer) is called for the removed elements.
2354 //!
2355 //! <b>Returns</b>: The number of erased elements.
2356 //!
2357 //! <b>Complexity</b>: Average case O(this->count(value)).
2358 //! Worst case O(this->size()).
2359 //!
2360 //! <b>Throws</b>: If the internal hasher or the equality functor throws.
2361 //! Basic guarantee.
2362 //!
2363 //! <b>Note</b>: Invalidates the iterators (but not the references)
2364 //! to the erased elements. No destructors are called.
2365 template<class Disposer>
2366 BOOST_INTRUSIVE_FORCEINLINE size_type erase_and_dispose(const key_type &key, Disposer disposer)
2367 { return this->erase_and_dispose(key, this->priv_hasher(), this->priv_equal(), disposer); }
2368
2369 //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
2370 //!
2371 //! <b>Effects</b>: Erases all the elements with the given key.
2372 //! according to the comparison functor "equal_func".
2373 //! Disposer::operator()(pointer) is called for the removed elements.
2374 //!
2375 //! <b>Returns</b>: The number of erased elements.
2376 //!
2377 //! <b>Complexity</b>: Average case O(this->count(value)).
2378 //! Worst case O(this->size()).
2379 //!
2380 //! <b>Throws</b>: If hash_func or equal_func throw. Basic guarantee.
2381 //!
2382 //! <b>Note</b>: Invalidates the iterators
2383 //! to the erased elements.
2384 template<class KeyType, class KeyHasher, class KeyEqual, class Disposer>
2385 size_type erase_and_dispose(const KeyType& key, KeyHasher hash_func
2386 ,KeyEqual equal_func, Disposer disposer)
2387 {
2388 size_type bucket_num;
2389 std::size_t h;
2390 siterator prev;
2391 siterator it = this->priv_find(key, hash_func, equal_func, bucket_num, h, prev);
2392 bool const success = it != this->priv_invalid_local_it();
2393
2394 size_type cnt(0);
2395 if(success){
2396 if(optimize_multikey){
2397 cnt = this->priv_erase_from_single_bucket
2398 (this->priv_bucket_pointer()[bucket_num], prev, ++(priv_last_in_group)(it), make_node_disposer(disposer), optimize_multikey_t());
2399 }
2400 else{
2401 bucket_type &b = this->priv_bucket_pointer()[bucket_num];
2402 siterator const end_sit = b.end();
2403 do{
2404 ++cnt;
2405 ++it;
2406 }while(it != end_sit &&
2407 this->priv_is_value_equal_to_key
2408 (this->priv_value_from_slist_node(it.pointed_node()), h, key, equal_func));
2409 bucket_type::s_erase_after_and_dispose(prev, it, make_node_disposer(disposer));
2410 }
2411 this->priv_size_traits().set_size(this->priv_size_traits().get_size()-cnt);
2412 this->priv_erasure_update_cache();
2413 }
2414
2415 return cnt;
2416 }
2417
2418 //! <b>Effects</b>: Erases all of the elements.
2419 //!
2420 //! <b>Complexity</b>: Linear to the number of elements on the container.
2421 //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise.
2422 //!
2423 //! <b>Throws</b>: Nothing.
2424 //!
2425 //! <b>Note</b>: Invalidates the iterators (but not the references)
2426 //! to the erased elements. No destructors are called.
2427 void clear()
2428 {
2429 this->priv_clear_buckets_and_cache();
2430 this->priv_size_traits().set_size(size_type(0));
2431 }
2432
2433 //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
2434 //!
2435 //! <b>Effects</b>: Erases all of the elements.
2436 //!
2437 //! <b>Complexity</b>: Linear to the number of elements on the container.
2438 //! Disposer::operator()(pointer) is called for the removed elements.
2439 //!
2440 //! <b>Throws</b>: Nothing.
2441 //!
2442 //! <b>Note</b>: Invalidates the iterators (but not the references)
2443 //! to the erased elements. No destructors are called.
2444 template<class Disposer>
2445 void clear_and_dispose(Disposer disposer)
2446 {
2447 if(!constant_time_size || !this->empty()){
2448 size_type num_buckets = this->bucket_count();
2449 bucket_ptr b = this->priv_bucket_pointer();
2450 typename typeof_node_disposer<Disposer>::type d(disposer, &this->priv_value_traits());
2451 for(; num_buckets--; ++b){
2452 b->clear_and_dispose(d);
2453 }
2454 this->priv_size_traits().set_size(size_type(0));
2455 }
2456 this->priv_initialize_cache();
2457 }
2458
2459 //! <b>Effects</b>: Returns the number of contained elements with the given value
2460 //!
2461 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2462 //!
2463 //! <b>Throws</b>: If the internal hasher or the equality functor throws.
2464 BOOST_INTRUSIVE_FORCEINLINE size_type count(const key_type &key) const
2465 { return this->count(key, this->priv_hasher(), this->priv_equal()); }
2466
2467 //! <b>Requires</b>: "hash_func" must be a hash function that induces
2468 //! the same hash values as the stored hasher. The difference is that
2469 //! "hash_func" hashes the given key instead of the value_type.
2470 //!
2471 //! "equal_func" must be a equality function that induces
2472 //! the same equality as key_equal. The difference is that
2473 //! "equal_func" compares an arbitrary key with the contained values.
2474 //!
2475 //! <b>Effects</b>: Returns the number of contained elements with the given key
2476 //!
2477 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2478 //!
2479 //! <b>Throws</b>: If hash_func or equal throw.
2480 template<class KeyType, class KeyHasher, class KeyEqual>
2481 size_type count(const KeyType &key, KeyHasher hash_func, KeyEqual equal_func) const
2482 {
2483 size_type cnt;
2484 size_type n_bucket;
2485 this->priv_local_equal_range(key, hash_func, equal_func, n_bucket, cnt);
2486 return cnt;
2487 }
2488
2489 //! <b>Effects</b>: Finds an iterator to the first element is equal to
2490 //! "value" or end() if that element does not exist.
2491 //!
2492 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2493 //!
2494 //! <b>Throws</b>: If the internal hasher or the equality functor throws.
2495 BOOST_INTRUSIVE_FORCEINLINE iterator find(const key_type &key)
2496 { return this->find(key, this->priv_hasher(), this->priv_equal()); }
2497
2498 //! <b>Requires</b>: "hash_func" must be a hash function that induces
2499 //! the same hash values as the stored hasher. The difference is that
2500 //! "hash_func" hashes the given key instead of the value_type.
2501 //!
2502 //! "equal_func" must be a equality function that induces
2503 //! the same equality as key_equal. The difference is that
2504 //! "equal_func" compares an arbitrary key with the contained values.
2505 //!
2506 //! <b>Effects</b>: Finds an iterator to the first element whose key is
2507 //! "key" according to the given hash and equality functor or end() if
2508 //! that element does not exist.
2509 //!
2510 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2511 //!
2512 //! <b>Throws</b>: If hash_func or equal_func throw.
2513 //!
2514 //! <b>Note</b>: This function is used when constructing a value_type
2515 //! is expensive and the value_type can be compared with a cheaper
2516 //! key type. Usually this key is part of the value_type.
2517 template<class KeyType, class KeyHasher, class KeyEqual>
2518 iterator find(const KeyType &key, KeyHasher hash_func, KeyEqual equal_func)
2519 {
2520 size_type bucket_n;
2521 std::size_t hash;
2522 siterator prev;
2523 return iterator( this->priv_find(key, hash_func, equal_func, bucket_n, hash, prev)
2524 , &this->get_bucket_value_traits());
2525 }
2526
2527 //! <b>Effects</b>: Finds a const_iterator to the first element whose key is
2528 //! "key" or end() if that element does not exist.
2529 //!
2530 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2531 //!
2532 //! <b>Throws</b>: If the internal hasher or the equality functor throws.
2533 BOOST_INTRUSIVE_FORCEINLINE const_iterator find(const key_type &key) const
2534 { return this->find(key, this->priv_hasher(), this->priv_equal()); }
2535
2536 //! <b>Requires</b>: "hash_func" must be a hash function that induces
2537 //! the same hash values as the stored hasher. The difference is that
2538 //! "hash_func" hashes the given key instead of the value_type.
2539 //!
2540 //! "equal_func" must be a equality function that induces
2541 //! the same equality as key_equal. The difference is that
2542 //! "equal_func" compares an arbitrary key with the contained values.
2543 //!
2544 //! <b>Effects</b>: Finds an iterator to the first element whose key is
2545 //! "key" according to the given hasher and equality functor or end() if
2546 //! that element does not exist.
2547 //!
2548 //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
2549 //!
2550 //! <b>Throws</b>: If hash_func or equal_func throw.
2551 //!
2552 //! <b>Note</b>: This function is used when constructing a value_type
2553 //! is expensive and the value_type can be compared with a cheaper
2554 //! key type. Usually this key is part of the value_type.
2555 template<class KeyType, class KeyHasher, class KeyEqual>
2556 const_iterator find
2557 (const KeyType &key, KeyHasher hash_func, KeyEqual equal_func) const
2558 {
2559 size_type bucket_n;
2560 std::size_t hash_value;
2561 siterator prev;
2562 return const_iterator( this->priv_find(key, hash_func, equal_func, bucket_n, hash_value, prev)
2563 , &this->get_bucket_value_traits());
2564 }
2565
2566 //! <b>Effects</b>: Returns a range containing all elements with values equivalent
2567 //! to value. Returns std::make_pair(this->end(), this->end()) if no such
2568 //! elements exist.
2569 //!
2570 //! <b>Complexity</b>: Average case O(this->count(value)). Worst case O(this->size()).
2571 //!
2572 //! <b>Throws</b>: If the internal hasher or the equality functor throws.
2573 BOOST_INTRUSIVE_FORCEINLINE std::pair<iterator,iterator> equal_range(const key_type &key)
2574 { return this->equal_range(key, this->priv_hasher(), this->priv_equal()); }
2575
2576 //! <b>Requires</b>: "hash_func" must be a hash function that induces
2577 //! the same hash values as the stored hasher. The difference is that
2578 //! "hash_func" hashes the given key instead of the value_type.
2579 //!
2580 //! "equal_func" must be a equality function that induces
2581 //! the same equality as key_equal. The difference is that
2582 //! "equal_func" compares an arbitrary key with the contained values.
2583 //!
2584 //! <b>Effects</b>: Returns a range containing all elements with equivalent
2585 //! keys. Returns std::make_pair(this->end(), this->end()) if no such
2586 //! elements exist.
2587 //!
2588 //! <b>Complexity</b>: Average case O(this->count(key, hash_func, equal_func)).
2589 //! Worst case O(this->size()).
2590 //!
2591 //! <b>Throws</b>: If hash_func or the equal_func throw.
2592 //!
2593 //! <b>Note</b>: This function is used when constructing a value_type
2594 //! is expensive and the value_type can be compared with a cheaper
2595 //! key type. Usually this key is part of the value_type.
2596 template<class KeyType, class KeyHasher, class KeyEqual>
2597 std::pair<iterator,iterator> equal_range
2598 (const KeyType &key, KeyHasher hash_func, KeyEqual equal_func)
2599 {
2600 std::pair<siterator, siterator> ret =
2601 this->priv_equal_range(key, hash_func, equal_func);
2602 return std::pair<iterator, iterator>
2603 ( iterator(ret.first, &this->get_bucket_value_traits())
2604 , iterator(ret.second, &this->get_bucket_value_traits()));
2605 }
2606
2607 //! <b>Effects</b>: Returns a range containing all elements with values equivalent
2608 //! to value. Returns std::make_pair(this->end(), this->end()) if no such
2609 //! elements exist.
2610 //!
2611 //! <b>Complexity</b>: Average case O(this->count(value)). Worst case O(this->size()).
2612 //!
2613 //! <b>Throws</b>: If the internal hasher or the equality functor throws.
2614 BOOST_INTRUSIVE_FORCEINLINE std::pair<const_iterator, const_iterator>
2615 equal_range(const key_type &key) const
2616 { return this->equal_range(key, this->priv_hasher(), this->priv_equal()); }
2617
2618 //! <b>Requires</b>: "hash_func" must be a hash function that induces
2619 //! the same hash values as the stored hasher. The difference is that
2620 //! "hash_func" hashes the given key instead of the value_type.
2621 //!
2622 //! "equal_func" must be a equality function that induces
2623 //! the same equality as key_equal. The difference is that
2624 //! "equal_func" compares an arbitrary key with the contained values.
2625 //!
2626 //! <b>Effects</b>: Returns a range containing all elements with equivalent
2627 //! keys. Returns std::make_pair(this->end(), this->end()) if no such
2628 //! elements exist.
2629 //!
2630 //! <b>Complexity</b>: Average case O(this->count(key, hash_func, equal_func)).
2631 //! Worst case O(this->size()).
2632 //!
2633 //! <b>Throws</b>: If the hasher or equal_func throw.
2634 //!
2635 //! <b>Note</b>: This function is used when constructing a value_type
2636 //! is expensive and the value_type can be compared with a cheaper
2637 //! key type. Usually this key is part of the value_type.
2638 template<class KeyType, class KeyHasher, class KeyEqual>
2639 std::pair<const_iterator,const_iterator> equal_range
2640 (const KeyType &key, KeyHasher hash_func, KeyEqual equal_func) const
2641 {
2642 std::pair<siterator, siterator> ret =
2643 this->priv_equal_range(key, hash_func, equal_func);
2644 return std::pair<const_iterator, const_iterator>
2645 ( const_iterator(ret.first, &this->get_bucket_value_traits())
2646 , const_iterator(ret.second, &this->get_bucket_value_traits()));
2647 }
2648
2649 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
2650
2651 //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
2652 //! appropriate type. Otherwise the behavior is undefined.
2653 //!
2654 //! <b>Effects</b>: Returns: a valid iterator belonging to the unordered_set
2655 //! that points to the value
2656 //!
2657 //! <b>Complexity</b>: Constant.
2658 //!
2659 //! <b>Throws</b>: If the internal hash function throws.
2660 iterator iterator_to(reference value);
2661
2662 //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
2663 //! appropriate type. Otherwise the behavior is undefined.
2664 //!
2665 //! <b>Effects</b>: Returns: a valid const_iterator belonging to the
2666 //! unordered_set that points to the value
2667 //!
2668 //! <b>Complexity</b>: Constant.
2669 //!
2670 //! <b>Throws</b>: If the internal hash function throws.
2671 const_iterator iterator_to(const_reference value) const;
2672
2673 //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
2674 //! appropriate type. Otherwise the behavior is undefined.
2675 //!
2676 //! <b>Effects</b>: Returns: a valid local_iterator belonging to the unordered_set
2677 //! that points to the value
2678 //!
2679 //! <b>Complexity</b>: Constant.
2680 //!
2681 //! <b>Throws</b>: Nothing.
2682 //!
2683 //! <b>Note</b>: This static function is available only if the <i>value traits</i>
2684 //! is stateless.
2685 static local_iterator s_local_iterator_to(reference value);
2686
2687 //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
2688 //! appropriate type. Otherwise the behavior is undefined.
2689 //!
2690 //! <b>Effects</b>: Returns: a valid const_local_iterator belonging to
2691 //! the unordered_set that points to the value
2692 //!
2693 //! <b>Complexity</b>: Constant.
2694 //!
2695 //! <b>Throws</b>: Nothing.
2696 //!
2697 //! <b>Note</b>: This static function is available only if the <i>value traits</i>
2698 //! is stateless.
2699 static const_local_iterator s_local_iterator_to(const_reference value);
2700
2701 //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
2702 //! appropriate type. Otherwise the behavior is undefined.
2703 //!
2704 //! <b>Effects</b>: Returns: a valid local_iterator belonging to the unordered_set
2705 //! that points to the value
2706 //!
2707 //! <b>Complexity</b>: Constant.
2708 //!
2709 //! <b>Throws</b>: Nothing.
2710 local_iterator local_iterator_to(reference value);
2711
2712 //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
2713 //! appropriate type. Otherwise the behavior is undefined.
2714 //!
2715 //! <b>Effects</b>: Returns: a valid const_local_iterator belonging to
2716 //! the unordered_set that points to the value
2717 //!
2718 //! <b>Complexity</b>: Constant.
2719 //!
2720 //! <b>Throws</b>: Nothing.
2721 const_local_iterator local_iterator_to(const_reference value) const;
2722
2723 //! <b>Effects</b>: Returns the number of buckets passed in the constructor
2724 //! or the last rehash function.
2725 //!
2726 //! <b>Complexity</b>: Constant.
2727 //!
2728 //! <b>Throws</b>: Nothing.
2729 size_type bucket_count() const;
2730
2731 //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
2732 //!
2733 //! <b>Effects</b>: Returns the number of elements in the nth bucket.
2734 //!
2735 //! <b>Complexity</b>: Constant.
2736 //!
2737 //! <b>Throws</b>: Nothing.
2738 size_type bucket_size(size_type n) const;
2739 #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
2740
2741 //! <b>Effects</b>: Returns the index of the bucket in which elements
2742 //! with keys equivalent to k would be found, if any such element existed.
2743 //!
2744 //! <b>Complexity</b>: Constant.
2745 //!
2746 //! <b>Throws</b>: If the hash functor throws.
2747 //!
2748 //! <b>Note</b>: the return value is in the range [0, this->bucket_count()).
2749 BOOST_INTRUSIVE_FORCEINLINE size_type bucket(const key_type& k) const
2750 { return this->bucket(k, this->priv_hasher()); }
2751
2752 //! <b>Requires</b>: "hash_func" must be a hash function that induces
2753 //! the same hash values as the stored hasher. The difference is that
2754 //! "hash_func" hashes the given key instead of the value_type.
2755 //!
2756 //! <b>Effects</b>: Returns the index of the bucket in which elements
2757 //! with keys equivalent to k would be found, if any such element existed.
2758 //!
2759 //! <b>Complexity</b>: Constant.
2760 //!
2761 //! <b>Throws</b>: If hash_func throws.
2762 //!
2763 //! <b>Note</b>: the return value is in the range [0, this->bucket_count()).
2764 template<class KeyType, class KeyHasher>
2765 BOOST_INTRUSIVE_FORCEINLINE size_type bucket(const KeyType& k, KeyHasher hash_func) const
2766 { return this->priv_hash_to_bucket(hash_func(k)); }
2767
2768 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
2769 //! <b>Effects</b>: Returns the bucket array pointer passed in the constructor
2770 //! or the last rehash function.
2771 //!
2772 //! <b>Complexity</b>: Constant.
2773 //!
2774 //! <b>Throws</b>: Nothing.
2775 bucket_ptr bucket_pointer() const;
2776
2777 //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
2778 //!
2779 //! <b>Effects</b>: Returns a local_iterator pointing to the beginning
2780 //! of the sequence stored in the bucket n.
2781 //!
2782 //! <b>Complexity</b>: Constant.
2783 //!
2784 //! <b>Throws</b>: Nothing.
2785 //!
2786 //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
2787 //! containing all of the elements in the nth bucket.
2788 local_iterator begin(size_type n);
2789
2790 //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
2791 //!
2792 //! <b>Effects</b>: Returns a const_local_iterator pointing to the beginning
2793 //! of the sequence stored in the bucket n.
2794 //!
2795 //! <b>Complexity</b>: Constant.
2796 //!
2797 //! <b>Throws</b>: Nothing.
2798 //!
2799 //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
2800 //! containing all of the elements in the nth bucket.
2801 const_local_iterator begin(size_type n) const;
2802
2803 //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
2804 //!
2805 //! <b>Effects</b>: Returns a const_local_iterator pointing to the beginning
2806 //! of the sequence stored in the bucket n.
2807 //!
2808 //! <b>Complexity</b>: Constant.
2809 //!
2810 //! <b>Throws</b>: Nothing.
2811 //!
2812 //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
2813 //! containing all of the elements in the nth bucket.
2814 const_local_iterator cbegin(size_type n) const;
2815
2816 //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
2817 //!
2818 //! <b>Effects</b>: Returns a local_iterator pointing to the end
2819 //! of the sequence stored in the bucket n.
2820 //!
2821 //! <b>Complexity</b>: Constant.
2822 //!
2823 //! <b>Throws</b>: Nothing.
2824 //!
2825 //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
2826 //! containing all of the elements in the nth bucket.
2827 local_iterator end(size_type n);
2828
2829 //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
2830 //!
2831 //! <b>Effects</b>: Returns a const_local_iterator pointing to the end
2832 //! of the sequence stored in the bucket n.
2833 //!
2834 //! <b>Complexity</b>: Constant.
2835 //!
2836 //! <b>Throws</b>: Nothing.
2837 //!
2838 //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
2839 //! containing all of the elements in the nth bucket.
2840 const_local_iterator end(size_type n) const;
2841
2842 //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
2843 //!
2844 //! <b>Effects</b>: Returns a const_local_iterator pointing to the end
2845 //! of the sequence stored in the bucket n.
2846 //!
2847 //! <b>Complexity</b>: Constant.
2848 //!
2849 //! <b>Throws</b>: Nothing.
2850 //!
2851 //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
2852 //! containing all of the elements in the nth bucket.
2853 const_local_iterator cend(size_type n) const;
2854 #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
2855
2856 //! <b>Requires</b>: new_bucket_traits can hold a pointer to a new bucket array
2857 //! or the same as the old bucket array with a different length. new_size is the length of the
2858 //! the array pointed by new_buckets. If new_bucket_traits.bucket_begin() == this->bucket_pointer()
2859 //! new_bucket_traits.bucket_count() can be bigger or smaller than this->bucket_count().
2860 //! 'new_bucket_traits' copy constructor should not throw.
2861 //!
2862 //! <b>Effects</b>:
2863 //! If `new_bucket_traits.bucket_begin() == this->bucket_pointer()` is false,
2864 //! unlinks values from the old bucket and inserts then in the new one according
2865 //! to the hash value of values.
2866 //!
2867 //! If `new_bucket_traits.bucket_begin() == this->bucket_pointer()` is true,
2868 //! the implementations avoids moving values as much as possible.
2869 //!
2870 //! Bucket traits hold by *this is assigned from new_bucket_traits.
2871 //! If the container is configured as incremental<>, the split bucket is set
2872 //! to the new bucket_count().
2873 //!
2874 //! If store_hash option is true, this method does not use the hash function.
2875 //! If false, the implementation tries to minimize calls to the hash function
2876 //! (e.g. once for equivalent values if optimize_multikey<true> is true).
2877 //!
2878 //! If rehash is successful updates the internal bucket_traits with new_bucket_traits.
2879 //!
2880 //! <b>Complexity</b>: Average case linear in this->size(), worst case quadratic.
2881 //!
2882 //! <b>Throws</b>: If the hasher functor throws. Basic guarantee.
2883 BOOST_INTRUSIVE_FORCEINLINE void rehash(const bucket_traits &new_bucket_traits)
2884 { this->rehash_impl(new_bucket_traits, false); }
2885
2886 //! <b>Note</b>: This function is used when keys from inserted elements are changed
2887 //! (e.g. a language change when key is a string) but uniqueness and hash properties are
2888 //! preserved so a fast full rehash recovers invariants for *this without extracting and
2889 //! reinserting all elements again.
2890 //!
2891 //! <b>Requires</b>: Calls produced to the hash function should not alter the value uniqueness
2892 //! properties of already inserted elements. If hasher(key1) == hasher(key2) was true when
2893 //! elements were inserted, it shall be true during calls produced in the execution of this function.
2894 //!
2895 //! key_equal is not called inside this function so it is assumed that key_equal(value1, value2)
2896 //! should produce the same results as before for inserted elements.
2897 //!
2898 //! <b>Effects</b>: Reprocesses all values hold by *this, recalculating their hash values
2899 //! and redistributing them though the buckets.
2900 //!
2901 //! If store_hash option is true, this method uses the hash function and updates the stored hash value.
2902 //!
2903 //! <b>Complexity</b>: Average case linear in this->size(), worst case quadratic.
2904 //!
2905 //! <b>Throws</b>: If the hasher functor throws. Basic guarantee.
2906 BOOST_INTRUSIVE_FORCEINLINE void full_rehash()
2907 { this->rehash_impl(this->priv_bucket_traits(), true); }
2908
2909 //! <b>Requires</b>:
2910 //!
2911 //! <b>Effects</b>:
2912 //!
2913 //! <b>Complexity</b>:
2914 //!
2915 //! <b>Throws</b>:
2916 //!
2917 //! <b>Note</b>: this method is only available if incremental<true> option is activated.
2918 bool incremental_rehash(bool grow = true)
2919 {
2920 //This function is only available for containers with incremental hashing
2921 BOOST_STATIC_ASSERT(( incremental && power_2_buckets ));
2922 const size_type split_idx = this->priv_split_traits().get_size();
2923 const size_type bucket_cnt = this->bucket_count();
2924 const bucket_ptr buck_ptr = this->priv_bucket_pointer();
2925 bool ret = false;
2926
2927 if(grow){
2928 //Test if the split variable can be changed
2929 if((ret = split_idx < bucket_cnt)){
2930 const size_type bucket_to_rehash = split_idx - bucket_cnt/2;
2931 bucket_type &old_bucket = buck_ptr[bucket_to_rehash];
2932 this->priv_split_traits().increment();
2933
2934 //Anti-exception stuff: if an exception is thrown while
2935 //moving elements from old_bucket to the target bucket, all moved
2936 //elements are moved back to the original one.
2937 detail::incremental_rehash_rollback<bucket_type, split_traits> rollback
2938 ( buck_ptr[split_idx], old_bucket, this->priv_split_traits());
2939 for( siterator before_i(old_bucket.before_begin()), i(old_bucket.begin()), end_sit(old_bucket.end())
2940 ; i != end_sit; i = before_i, ++i){
2941 const value_type &v = this->priv_value_from_slist_node(i.pointed_node());
2942 const std::size_t hash_value = this->priv_stored_or_compute_hash(v, store_hash_t());
2943 const size_type new_n = this->priv_hash_to_bucket(hash_value);
2944 siterator const last = (priv_last_in_group)(i);
2945 if(new_n == bucket_to_rehash){
2946 before_i = last;
2947 }
2948 else{
2949 bucket_type &new_b = buck_ptr[new_n];
2950 new_b.splice_after(new_b.before_begin(), old_bucket, before_i, last);
2951 }
2952 }
2953 rollback.release();
2954 this->priv_erasure_update_cache();
2955 }
2956 }
2957 else if((ret = split_idx > bucket_cnt/2)){ //!grow
2958 const size_type target_bucket_num = split_idx - 1 - bucket_cnt/2;
2959 bucket_type &target_bucket = buck_ptr[target_bucket_num];
2960 bucket_type &source_bucket = buck_ptr[split_idx-1];
2961 target_bucket.splice_after(target_bucket.cbefore_begin(), source_bucket);
2962 this->priv_split_traits().decrement();
2963 this->priv_insertion_update_cache(target_bucket_num);
2964 }
2965 return ret;
2966 }
2967
2968 //! <b>Effects</b>: If new_bucket_traits.bucket_count() is not
2969 //! this->bucket_count()/2 or this->bucket_count()*2, or
2970 //! this->split_bucket() != new_bucket_traits.bucket_count() returns false
2971 //! and does nothing.
2972 //!
2973 //! Otherwise, copy assigns new_bucket_traits to the internal bucket_traits
2974 //! and transfers all the objects from old buckets to the new ones.
2975 //!
2976 //! <b>Complexity</b>: Linear to size().
2977 //!
2978 //! <b>Throws</b>: Nothing
2979 //!
2980 //! <b>Note</b>: this method is only available if incremental<true> option is activated.
2981 bool incremental_rehash(const bucket_traits &new_bucket_traits)
2982 {
2983 //This function is only available for containers with incremental hashing
2984 BOOST_STATIC_ASSERT(( incremental && power_2_buckets ));
2985 size_type const new_bucket_traits_size = new_bucket_traits.bucket_count();
2986 size_type const cur_bucket_traits = this->bucket_count();
2987 const size_type split_idx = this->split_count();
2988
2989 //Test new bucket size is consistent with internal bucket size and split count
2990 if(new_bucket_traits_size/2 == cur_bucket_traits){
2991 if(!(split_idx >= cur_bucket_traits))
2992 return false;
2993 }
2994 else if(new_bucket_traits_size == cur_bucket_traits/2){
2995 if(!(split_idx <= new_bucket_traits_size))
2996 return false;
2997 }
2998 else{
2999 return false;
3000 }
3001
3002 const size_type ini_n = this->priv_get_cache_bucket_num();
3003 const bucket_ptr old_buckets = this->priv_bucket_pointer();
3004 this->priv_bucket_traits() = new_bucket_traits;
3005 if(new_bucket_traits.bucket_begin() != old_buckets){
3006 for(size_type n = ini_n; n < split_idx; ++n){
3007 bucket_type &new_bucket = new_bucket_traits.bucket_begin()[n];
3008 bucket_type &old_bucket = old_buckets[n];
3009 new_bucket.splice_after(new_bucket.cbefore_begin(), old_bucket);
3010 }
3011 //Put cache to safe position
3012 this->priv_initialize_cache();
3013 this->priv_insertion_update_cache(ini_n);
3014 }
3015 return true;
3016 }
3017
3018 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
3019
3020 //! <b>Requires</b>: incremental<> option must be set
3021 //!
3022 //! <b>Effects</b>: returns the current split count
3023 //!
3024 //! <b>Complexity</b>: Constant
3025 //!
3026 //! <b>Throws</b>: Nothing
3027 size_type split_count() const;
3028
3029 //! <b>Effects</b>: Returns the nearest new bucket count optimized for
3030 //! the container that is bigger or equal than n. This suggestion can be
3031 //! used to create bucket arrays with a size that will usually improve
3032 //! container's performance. If such value does not exist, the
3033 //! higher possible value is returned.
3034 //!
3035 //! <b>Complexity</b>: Amortized constant time.
3036 //!
3037 //! <b>Throws</b>: Nothing.
3038 static size_type suggested_upper_bucket_count(size_type n);
3039
3040 //! <b>Effects</b>: Returns the nearest new bucket count optimized for
3041 //! the container that is smaller or equal than n. This suggestion can be
3042 //! used to create bucket arrays with a size that will usually improve
3043 //! container's performance. If such value does not exist, the
3044 //! lowest possible value is returned.
3045 //!
3046 //! <b>Complexity</b>: Amortized constant time.
3047 //!
3048 //! <b>Throws</b>: Nothing.
3049 static size_type suggested_lower_bucket_count(size_type n);
3050 #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
3051
3052
3053 friend bool operator==(const hashtable_impl &x, const hashtable_impl &y)
3054 {
3055 //Taken from N3068
3056 if(constant_time_size && x.size() != y.size()){
3057 return false;
3058 }
3059 for (const_iterator ix = x.cbegin(), ex = x.cend(); ix != ex; ++ix){
3060 std::pair<const_iterator, const_iterator> eqx(x.equal_range(key_of_value()(*ix))),
3061 eqy(y.equal_range(key_of_value()(*ix)));
3062 if (boost::intrusive::iterator_distance(eqx.first, eqx.second) !=
3063 boost::intrusive::iterator_distance(eqy.first, eqy.second) ||
3064 !(priv_algo_is_permutation)(eqx.first, eqx.second, eqy.first) ){
3065 return false;
3066 }
3067 ix = eqx.second;
3068 }
3069 return true;
3070 }
3071
3072 friend bool operator!=(const hashtable_impl &x, const hashtable_impl &y)
3073 { return !(x == y); }
3074
3075 friend bool operator<(const hashtable_impl &x, const hashtable_impl &y)
3076 { return ::boost::intrusive::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
3077
3078 friend bool operator>(const hashtable_impl &x, const hashtable_impl &y)
3079 { return y < x; }
3080
3081 friend bool operator<=(const hashtable_impl &x, const hashtable_impl &y)
3082 { return !(y < x); }
3083
3084 friend bool operator>=(const hashtable_impl &x, const hashtable_impl &y)
3085 { return !(x < y); }
3086
3087 /// @cond
3088 BOOST_INTRUSIVE_FORCEINLINE void check() const {}
3089 private:
3090
3091 void rehash_impl(const bucket_traits &new_bucket_traits, bool do_full_rehash)
3092 {
3093 const bucket_ptr new_buckets = new_bucket_traits.bucket_begin();
3094 size_type new_bucket_count = new_bucket_traits.bucket_count();
3095 const bucket_ptr old_buckets = this->priv_bucket_pointer();
3096 size_type old_bucket_count = this->bucket_count();
3097
3098 //Check power of two bucket array if the option is activated
3099 BOOST_INTRUSIVE_INVARIANT_ASSERT
3100 (!power_2_buckets || (0 == (new_bucket_count & (new_bucket_count-1u))));
3101
3102 size_type n = this->priv_get_cache_bucket_num();
3103 const bool same_buffer = old_buckets == new_buckets;
3104 //If the new bucket length is a common factor
3105 //of the old one we can avoid hash calculations.
3106 const bool fast_shrink = (!do_full_rehash) && (!incremental) && (old_bucket_count >= new_bucket_count) &&
3107 (power_2_buckets || (old_bucket_count % new_bucket_count) == 0);
3108 //If we are shrinking the same bucket array and it's
3109 //is a fast shrink, just rehash the last nodes
3110 size_type new_first_bucket_num = new_bucket_count;
3111 if(same_buffer && fast_shrink && (n < new_bucket_count)){
3112 new_first_bucket_num = n;
3113 n = new_bucket_count;
3114 }
3115
3116 //Anti-exception stuff: they destroy the elements if something goes wrong.
3117 //If the source and destination buckets are the same, the second rollback function
3118 //is harmless, because all elements have been already unlinked and destroyed
3119 typedef detail::init_disposer<node_algorithms> NodeDisposer;
3120 typedef detail::exception_array_disposer<bucket_type, NodeDisposer, size_type> ArrayDisposer;
3121 NodeDisposer node_disp;
3122 ArrayDisposer rollback1(new_buckets[0], node_disp, new_bucket_count);
3123 ArrayDisposer rollback2(old_buckets[0], node_disp, old_bucket_count);
3124
3125 //Put size in a safe value for rollback exception
3126 size_type const size_backup = this->priv_size_traits().get_size();
3127 this->priv_size_traits().set_size(0);
3128 //Put cache to safe position
3129 this->priv_initialize_cache();
3130 this->priv_insertion_update_cache(size_type(0u));
3131
3132 //Iterate through nodes
3133 for(; n < old_bucket_count; ++n){
3134 bucket_type &old_bucket = old_buckets[n];
3135 if(!fast_shrink){
3136 for( siterator before_i(old_bucket.before_begin()), i(old_bucket.begin()), end_sit(old_bucket.end())
3137 ; i != end_sit
3138 ; i = before_i, ++i){
3139
3140 //First obtain hash value (and store it if do_full_rehash)
3141 std::size_t hash_value;
3142 if(do_full_rehash){
3143 value_type &v = this->priv_value_from_slist_node(i.pointed_node());
3144 hash_value = this->priv_hasher()(key_of_value()(v));
3145 node_functions_t::store_hash(pointer_traits<node_ptr>::pointer_to(this->priv_value_to_node(v)), hash_value, store_hash_t());
3146 }
3147 else{
3148 const value_type &v = this->priv_value_from_slist_node(i.pointed_node());
3149 hash_value = this->priv_stored_or_compute_hash(v, store_hash_t());
3150 }
3151
3152 //Now calculate the new bucket position
3153 const size_type new_n = detail::hash_to_bucket_split<power_2_buckets, incremental>
3154 (hash_value, new_bucket_count, new_bucket_count);
3155
3156 //Update first used bucket cache
3157 if(cache_begin && new_n < new_first_bucket_num)
3158 new_first_bucket_num = new_n;
3159
3160 //If the target bucket is new, transfer the whole group
3161 siterator const last = (priv_last_in_group)(i);
3162
3163 if(same_buffer && new_n == n){
3164 before_i = last;
3165 }
3166 else{
3167 bucket_type &new_b = new_buckets[new_n];
3168 new_b.splice_after(new_b.before_begin(), old_bucket, before_i, last);
3169 }
3170 }
3171 }
3172 else{
3173 const size_type new_n = detail::hash_to_bucket_split<power_2_buckets, incremental>(n, new_bucket_count, new_bucket_count);
3174 if(cache_begin && new_n < new_first_bucket_num)
3175 new_first_bucket_num = new_n;
3176 bucket_type &new_b = new_buckets[new_n];
3177 new_b.splice_after( new_b.before_begin()
3178 , old_bucket
3179 , old_bucket.before_begin()
3180 , bucket_plus_vtraits_t::priv_get_last(old_bucket, optimize_multikey_t()));
3181 }
3182 }
3183
3184 this->priv_size_traits().set_size(size_backup);
3185 this->priv_split_traits().set_size(new_bucket_count);
3186 if(&new_bucket_traits != &this->priv_bucket_traits()){
3187 this->priv_bucket_traits() = new_bucket_traits;
3188 }
3189 this->priv_initialize_cache();
3190 this->priv_insertion_update_cache(new_first_bucket_num);
3191 rollback1.release();
3192 rollback2.release();
3193 }
3194
3195 template <class MaybeConstHashtableImpl, class Cloner, class Disposer>
3196 void priv_clone_from(MaybeConstHashtableImpl &src, Cloner cloner, Disposer disposer)
3197 {
3198 this->clear_and_dispose(disposer);
3199 if(!constant_time_size || !src.empty()){
3200 const size_type src_bucket_count = src.bucket_count();
3201 const size_type dst_bucket_count = this->bucket_count();
3202 //Check power of two bucket array if the option is activated
3203 BOOST_INTRUSIVE_INVARIANT_ASSERT
3204 (!power_2_buckets || (0 == (src_bucket_count & (src_bucket_count-1))));
3205 BOOST_INTRUSIVE_INVARIANT_ASSERT
3206 (!power_2_buckets || (0 == (dst_bucket_count & (dst_bucket_count-1))));
3207 //If src bucket count is bigger or equal, structural copy is possible
3208 const bool structural_copy = (!incremental) && (src_bucket_count >= dst_bucket_count) &&
3209 (power_2_buckets || (src_bucket_count % dst_bucket_count) == 0);
3210 if(structural_copy){
3211 this->priv_structural_clone_from(src, cloner, disposer);
3212 }
3213 else{
3214 //Unlike previous cloning algorithm, this can throw
3215 //if cloner, hasher or comparison functor throw
3216 typedef typename detail::if_c< detail::is_const<MaybeConstHashtableImpl>::value
3217 , typename MaybeConstHashtableImpl::const_iterator
3218 , typename MaybeConstHashtableImpl::iterator
3219 >::type clone_iterator;
3220 clone_iterator b(src.begin()), e(src.end());
3221 detail::exception_disposer<hashtable_impl, Disposer> rollback(*this, disposer);
3222 for(; b != e; ++b){
3223 //No need to check for duplicates and insert it in the first position
3224 //as this is an unordered container. So use minimal insertion code
3225 std::size_t const hash_to_store = this->priv_stored_or_compute_hash(*b, store_hash_t());;
3226 size_type const bucket_number = this->priv_hash_to_bucket(hash_to_store);
3227 typedef typename detail::if_c
3228 <detail::is_const<MaybeConstHashtableImpl>::value, const_reference, reference>::type reference_type;
3229 reference_type r = *b;
3230 this->priv_clone_front_in_bucket<reference_type>(bucket_number, r, hash_to_store, cloner);
3231 }
3232 rollback.release();
3233 }
3234 }
3235 }
3236
3237 template<class ValueReference, class Cloner>
3238 void priv_clone_front_in_bucket( size_type const bucket_number
3239 , typename detail::identity<ValueReference>::type src_ref
3240 , std::size_t const hash_to_store, Cloner cloner)
3241 {
3242 //No need to check for duplicates and insert it in the first position
3243 //as this is an unordered container. So use minimal insertion code
3244 //std::size_t const hash_value = this->priv_stored_or_compute_hash(src_ref, store_hash_t());;
3245 //size_type const bucket_number = this->priv_hash_to_bucket(hash_value);
3246 bucket_type &cur_bucket = this->priv_bucket_pointer()[bucket_number];
3247 siterator const prev(cur_bucket.before_begin());
3248 //Just check if the cloned node is equal to the first inserted value in the new bucket
3249 //as equal src values were contiguous and they should be already inserted in the
3250 //destination bucket.
3251 bool const next_is_in_group = optimize_multikey && !cur_bucket.empty() &&
3252 this->priv_equal()( key_of_value()(src_ref)
3253 , key_of_value()(this->priv_value_from_slist_node((++siterator(prev)).pointed_node())));
3254 this->priv_insert_equal_after_find(*cloner(src_ref), bucket_number, hash_to_store, prev, next_is_in_group);
3255 }
3256
3257 template <class MaybeConstHashtableImpl, class Cloner, class Disposer>
3258 void priv_structural_clone_from(MaybeConstHashtableImpl &src, Cloner cloner, Disposer disposer)
3259 {
3260 //First clone the first ones
3261 const size_type src_bucket_count = src.bucket_count();
3262 const size_type dst_bucket_count = this->bucket_count();
3263 const bucket_ptr src_buckets = src.priv_bucket_pointer();
3264 const bucket_ptr dst_buckets = this->priv_bucket_pointer();
3265 size_type constructed = 0;
3266 typedef node_cast_adaptor< detail::node_disposer<Disposer, value_traits, CircularSListAlgorithms>
3267 , slist_node_ptr, node_ptr > NodeDisposer;
3268 NodeDisposer node_disp(disposer, &this->priv_value_traits());
3269
3270 detail::exception_array_disposer<bucket_type, NodeDisposer, size_type>
3271 rollback(dst_buckets[0], node_disp, constructed);
3272 //Now insert the remaining ones using the modulo trick
3273 for( //"constructed" already initialized
3274 ; constructed < src_bucket_count
3275 ; ++constructed){
3276 //Since incremental hashing can't be structurally copied, avoid hash_to_bucket_split
3277 const std::size_t new_n = detail::hash_to_bucket(constructed, dst_bucket_count, detail::bool_<power_2_buckets>());
3278 bucket_type &src_b = src_buckets[constructed];
3279 for( siterator b(src_b.begin()), e(src_b.end()); b != e; ++b){
3280 slist_node_ptr const n(b.pointed_node());
3281 typedef typename detail::if_c
3282 <detail::is_const<MaybeConstHashtableImpl>::value, const_reference, reference>::type reference_type;
3283 reference_type r = this->priv_value_from_slist_node(n);
3284 this->priv_clone_front_in_bucket<reference_type>
3285 (new_n, r, this->priv_stored_hash(n, store_hash_t()), cloner);
3286 }
3287 }
3288 this->priv_hasher() = src.priv_hasher();
3289 this->priv_equal() = src.priv_equal();
3290 rollback.release();
3291 this->priv_size_traits().set_size(src.priv_size_traits().get_size());
3292 this->priv_split_traits().set_size(dst_bucket_count);
3293 this->priv_insertion_update_cache(0u);
3294 this->priv_erasure_update_cache();
3295 }
3296
3297 std::size_t priv_hash_to_bucket(std::size_t hash_value) const
3298 {
3299 return detail::hash_to_bucket_split<power_2_buckets, incremental>
3300 (hash_value, this->priv_bucket_traits().bucket_count(), this->priv_split_traits().get_size());
3301 }
3302
3303 iterator priv_insert_equal_after_find(reference value, size_type bucket_num, std::size_t hash_value, siterator prev, bool const next_is_in_group)
3304 {
3305 //Now store hash if needed
3306 node_ptr n = pointer_traits<node_ptr>::pointer_to(this->priv_value_to_node(value));
3307 node_functions_t::store_hash(n, hash_value, store_hash_t());
3308 //Checks for some modes
3309 BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(!safemode_or_autounlink || node_algorithms::unique(n));
3310 //Shortcut to optimize_multikey cases
3311 group_functions_t::insert_in_group
3312 ( next_is_in_group ? detail::dcast_bucket_ptr<node>((++siterator(prev)).pointed_node()) : n
3313 , n, optimize_multikey_t());
3314 //Update cache and increment size if needed
3315 this->priv_insertion_update_cache(bucket_num);
3316 this->priv_size_traits().increment();
3317 //Insert the element in the bucket after it
3318 return iterator(bucket_type::s_insert_after(prev, *n), &this->get_bucket_value_traits());
3319 }
3320
3321 template<class KeyType, class KeyHasher, class KeyEqual>
3322 siterator priv_find //In case it is not found previt is bucket.before_begin()
3323 ( const KeyType &key, KeyHasher hash_func
3324 , KeyEqual equal_func, size_type &bucket_number, std::size_t &h, siterator &previt) const
3325 {
3326 h = hash_func(key);
3327 return this->priv_find_with_hash(key, equal_func, bucket_number, h, previt);
3328 }
3329
3330 template<class KeyType, class KeyEqual>
3331 bool priv_is_value_equal_to_key(const value_type &v, const std::size_t h, const KeyType &key, KeyEqual equal_func) const
3332 {
3333 (void)h;
3334 return (!compare_hash || this->priv_stored_or_compute_hash(v, store_hash_t()) == h) && equal_func(key, key_of_value()(v));
3335 }
3336
3337 //return previous iterator to the next equal range group in case
3338 static siterator priv_last_in_group(const siterator &it_first_in_group)
3339 {
3340 return bucket_type::s_iterator_to
3341 (*group_functions_t::get_last_in_group
3342 (detail::dcast_bucket_ptr<node>(it_first_in_group.pointed_node()), optimize_multikey_t()));
3343 }
3344
3345 template<class KeyType, class KeyEqual>
3346 siterator priv_find_with_hash //In case it is not found previt is bucket.before_begin()
3347 ( const KeyType &key, KeyEqual equal_func, size_type &bucket_number, const std::size_t h, siterator &previt) const
3348 {
3349 bucket_number = this->priv_hash_to_bucket(h);
3350 bucket_type &b = this->priv_bucket_pointer()[bucket_number];
3351 previt = b.before_begin();
3352 siterator it = previt;
3353 siterator const endit = b.end();
3354
3355 while(++it != endit){
3356 if(this->priv_is_value_equal_to_key(this->priv_value_from_slist_node(it.pointed_node()), h, key, equal_func)){
3357 return it;
3358 }
3359 previt = it = (priv_last_in_group)(it);
3360 }
3361 previt = b.before_begin();
3362 return this->priv_invalid_local_it();
3363 }
3364
3365 template<class KeyType, class KeyHasher, class KeyEqual>
3366 std::pair<siterator, siterator> priv_local_equal_range
3367 ( const KeyType &key
3368 , KeyHasher hash_func
3369 , KeyEqual equal_func
3370 , size_type &found_bucket
3371 , size_type &cnt) const
3372 {
3373 cnt = 0;
3374 //Let's see if the element is present
3375
3376 siterator prev;
3377 size_type n_bucket;
3378 std::size_t h;
3379 std::pair<siterator, siterator> to_return
3380 ( this->priv_find(key, hash_func, equal_func, n_bucket, h, prev)
3381 , this->priv_invalid_local_it());
3382
3383 if(to_return.first != to_return.second){
3384 found_bucket = n_bucket;
3385 //If it's present, find the first that it's not equal in
3386 //the same bucket
3387 bucket_type &b = this->priv_bucket_pointer()[n_bucket];
3388 siterator it = to_return.first;
3389 ++cnt; //At least one is found
3390 if(optimize_multikey){
3391 to_return.second = ++(priv_last_in_group)(it);
3392 cnt += boost::intrusive::iterator_distance(++it, to_return.second);
3393 }
3394 else{
3395 siterator const bend = b.end();
3396 while(++it != bend &&
3397 this->priv_is_value_equal_to_key(this->priv_value_from_slist_node(it.pointed_node()), h, key, equal_func)){
3398 ++cnt;
3399 }
3400 to_return.second = it;
3401 }
3402 }
3403 return to_return;
3404 }
3405
3406 template<class KeyType, class KeyHasher, class KeyEqual>
3407 std::pair<siterator, siterator> priv_equal_range
3408 ( const KeyType &key
3409 , KeyHasher hash_func
3410 , KeyEqual equal_func) const
3411 {
3412 size_type n_bucket;
3413 size_type cnt;
3414
3415 //Let's see if the element is present
3416 std::pair<siterator, siterator> to_return
3417 (this->priv_local_equal_range(key, hash_func, equal_func, n_bucket, cnt));
3418 //If not, find the next element as ".second" if ".second" local iterator
3419 //is not pointing to an element.
3420 bucket_ptr const bp = this->priv_bucket_pointer();
3421 if(to_return.first != to_return.second &&
3422 to_return.second == bp[n_bucket].end()){
3423 to_return.second = this->priv_invalid_local_it();
3424 ++n_bucket;
3425 for( const size_type max_bucket = this->bucket_count()
3426 ; n_bucket != max_bucket
3427 ; ++n_bucket){
3428 bucket_type &b = bp[n_bucket];
3429 if(!b.empty()){
3430 to_return.second = b.begin();
3431 break;
3432 }
3433 }
3434 }
3435 return to_return;
3436 }
3437
3438 std::size_t priv_get_bucket_num(siterator it)
3439 { return this->priv_get_bucket_num_hash_dispatch(it, store_hash_t()); }
3440
3441 std::size_t priv_get_bucket_num_hash_dispatch(siterator it, detail::true_) //store_hash
3442 {
3443 return this->priv_hash_to_bucket
3444 (this->priv_stored_hash(it.pointed_node(), store_hash_t()));
3445 }
3446
3447 std::size_t priv_get_bucket_num_hash_dispatch(siterator it, detail::false_) //NO store_hash
3448 { return this->priv_get_bucket_num_no_hash_store(it, optimize_multikey_t()); }
3449
3450 static siterator priv_get_previous(bucket_type &b, siterator i)
3451 { return bucket_plus_vtraits_t::priv_get_previous(b, i, optimize_multikey_t()); }
3452
3453 /// @endcond
3454 };
3455
3456 /// @cond
3457 #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
3458 template < class T
3459 , bool UniqueKeys
3460 , class PackedOptions
3461 >
3462 #else
3463 template <class T, bool UniqueKeys, class ...Options>
3464 #endif
3465 struct make_bucket_traits
3466 {
3467 //Real value traits must be calculated from options
3468 typedef typename detail::get_value_traits
3469 <T, typename PackedOptions::proto_value_traits>::type value_traits;
3470
3471 typedef typename PackedOptions::bucket_traits specified_bucket_traits;
3472
3473 //Real bucket traits must be calculated from options and calculated value_traits
3474 typedef typename detail::get_slist_impl
3475 <typename detail::reduced_slist_node_traits
3476 <typename value_traits::node_traits>::type
3477 >::type slist_impl;
3478
3479 typedef typename
3480 detail::if_c< detail::is_same
3481 < specified_bucket_traits
3482 , default_bucket_traits
3483 >::value
3484 , detail::bucket_traits_impl<slist_impl>
3485 , specified_bucket_traits
3486 >::type type;
3487 };
3488 /// @endcond
3489
3490 //! Helper metafunction to define a \c hashtable that yields to the same type when the
3491 //! same options (either explicitly or implicitly) are used.
3492 #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
3493 template<class T, class ...Options>
3494 #else
3495 template<class T, class O1 = void, class O2 = void
3496 , class O3 = void, class O4 = void
3497 , class O5 = void, class O6 = void
3498 , class O7 = void, class O8 = void
3499 , class O9 = void, class O10= void
3500 >
3501 #endif
3502 struct make_hashtable
3503 {
3504 /// @cond
3505 typedef typename pack_options
3506 < hashtable_defaults,
3507 #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
3508 O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
3509 #else
3510 Options...
3511 #endif
3512 >::type packed_options;
3513
3514 typedef typename detail::get_value_traits
3515 <T, typename packed_options::proto_value_traits>::type value_traits;
3516
3517 typedef typename make_bucket_traits
3518 <T, false, packed_options>::type bucket_traits;
3519
3520 typedef hashtable_impl
3521 < value_traits
3522 , typename packed_options::key_of_value
3523 , typename packed_options::hash
3524 , typename packed_options::equal
3525 , bucket_traits
3526 , typename packed_options::size_type
3527 , (std::size_t(false)*hash_bool_flags::unique_keys_pos)
3528 |(std::size_t(packed_options::constant_time_size)*hash_bool_flags::constant_time_size_pos)
3529 |(std::size_t(packed_options::power_2_buckets)*hash_bool_flags::power_2_buckets_pos)
3530 |(std::size_t(packed_options::cache_begin)*hash_bool_flags::cache_begin_pos)
3531 |(std::size_t(packed_options::compare_hash)*hash_bool_flags::compare_hash_pos)
3532 |(std::size_t(packed_options::incremental)*hash_bool_flags::incremental_pos)
3533 > implementation_defined;
3534
3535 /// @endcond
3536 typedef implementation_defined type;
3537 };
3538
3539 #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
3540
3541 #if defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
3542 template<class T, class ...Options>
3543 #else
3544 template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7, class O8, class O9, class O10>
3545 #endif
3546 class hashtable
3547 : public make_hashtable<T,
3548 #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
3549 O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
3550 #else
3551 Options...
3552 #endif
3553 >::type
3554 {
3555 typedef typename make_hashtable<T,
3556 #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
3557 O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
3558 #else
3559 Options...
3560 #endif
3561 >::type Base;
3562 BOOST_MOVABLE_BUT_NOT_COPYABLE(hashtable)
3563
3564 public:
3565 typedef typename Base::value_traits value_traits;
3566 typedef typename Base::iterator iterator;
3567 typedef typename Base::const_iterator const_iterator;
3568 typedef typename Base::bucket_ptr bucket_ptr;
3569 typedef typename Base::size_type size_type;
3570 typedef typename Base::hasher hasher;
3571 typedef typename Base::bucket_traits bucket_traits;
3572 typedef typename Base::key_equal key_equal;
3573
3574 //Assert if passed value traits are compatible with the type
3575 BOOST_STATIC_ASSERT((detail::is_same<typename value_traits::value_type, T>::value));
3576
3577 BOOST_INTRUSIVE_FORCEINLINE explicit hashtable ( const bucket_traits &b_traits
3578 , const hasher & hash_func = hasher()
3579 , const key_equal &equal_func = key_equal()
3580 , const value_traits &v_traits = value_traits())
3581 : Base(b_traits, hash_func, equal_func, v_traits)
3582 {}
3583
3584 BOOST_INTRUSIVE_FORCEINLINE hashtable(BOOST_RV_REF(hashtable) x)
3585 : Base(BOOST_MOVE_BASE(Base, x))
3586 {}
3587
3588 BOOST_INTRUSIVE_FORCEINLINE hashtable& operator=(BOOST_RV_REF(hashtable) x)
3589 { return static_cast<hashtable&>(this->Base::operator=(BOOST_MOVE_BASE(Base, x))); }
3590
3591 template <class Cloner, class Disposer>
3592 BOOST_INTRUSIVE_FORCEINLINE void clone_from(const hashtable &src, Cloner cloner, Disposer disposer)
3593 { Base::clone_from(src, cloner, disposer); }
3594
3595 template <class Cloner, class Disposer>
3596 BOOST_INTRUSIVE_FORCEINLINE void clone_from(BOOST_RV_REF(hashtable) src, Cloner cloner, Disposer disposer)
3597 { Base::clone_from(BOOST_MOVE_BASE(Base, src), cloner, disposer); }
3598 };
3599
3600 #endif
3601
3602 } //namespace intrusive
3603 } //namespace boost
3604
3605 #include <boost/intrusive/detail/config_end.hpp>
3606
3607 #endif //BOOST_INTRUSIVE_HASHTABLE_HPP