Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/unordered/detail/table.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
1 | |
2 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. | |
3 // Copyright (C) 2005-2011 Daniel James | |
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | |
7 #ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED | |
8 #define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED | |
9 | |
10 #include <boost/unordered/detail/buckets.hpp> | |
11 #include <boost/unordered/detail/util.hpp> | |
12 #include <boost/type_traits/aligned_storage.hpp> | |
13 #include <boost/type_traits/alignment_of.hpp> | |
14 #include <cmath> | |
15 | |
16 #if defined(BOOST_MSVC) | |
17 #pragma warning(push) | |
18 #pragma warning(disable:4127) // conditional expression is constant | |
19 #endif | |
20 | |
21 #if defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) | |
22 | |
23 #if defined(__EDG__) | |
24 #elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__) | |
25 #pragma message("Warning: BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported.") | |
26 #elif defined(__GNUC__) || defined(__HP_aCC) || \ | |
27 defined(__SUNPRO_CC) || defined(__IBMCPP__) | |
28 #warning "BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported." | |
29 #endif | |
30 | |
31 #endif | |
32 | |
33 namespace boost { namespace unordered { namespace detail { | |
34 | |
35 //////////////////////////////////////////////////////////////////////////// | |
36 // convert double to std::size_t | |
37 | |
38 inline std::size_t double_to_size(double f) | |
39 { | |
40 return f >= static_cast<double>( | |
41 (std::numeric_limits<std::size_t>::max)()) ? | |
42 (std::numeric_limits<std::size_t>::max)() : | |
43 static_cast<std::size_t>(f); | |
44 } | |
45 | |
46 // The space used to store values in a node. | |
47 | |
48 template <typename ValueType> | |
49 struct value_base | |
50 { | |
51 typedef ValueType value_type; | |
52 | |
53 typename boost::aligned_storage< | |
54 sizeof(value_type), | |
55 boost::alignment_of<value_type>::value>::type data_; | |
56 | |
57 void* address() { | |
58 return this; | |
59 } | |
60 | |
61 value_type& value() { | |
62 return *(ValueType*) this; | |
63 } | |
64 | |
65 value_type* value_ptr() { | |
66 return (ValueType*) this; | |
67 } | |
68 | |
69 private: | |
70 | |
71 value_base& operator=(value_base const&); | |
72 }; | |
73 | |
74 template <typename NodeAlloc> | |
75 struct copy_nodes | |
76 { | |
77 typedef boost::unordered::detail::allocator_traits<NodeAlloc> | |
78 node_allocator_traits; | |
79 | |
80 node_constructor<NodeAlloc> constructor; | |
81 | |
82 explicit copy_nodes(NodeAlloc& a) : constructor(a) {} | |
83 | |
84 typename node_allocator_traits::pointer create( | |
85 typename node_allocator_traits::value_type::value_type const& v) | |
86 { | |
87 constructor.construct_with_value2(v); | |
88 return constructor.release(); | |
89 } | |
90 }; | |
91 | |
92 template <typename NodeAlloc> | |
93 struct move_nodes | |
94 { | |
95 typedef boost::unordered::detail::allocator_traits<NodeAlloc> | |
96 node_allocator_traits; | |
97 | |
98 node_constructor<NodeAlloc> constructor; | |
99 | |
100 explicit move_nodes(NodeAlloc& a) : constructor(a) {} | |
101 | |
102 typename node_allocator_traits::pointer create( | |
103 typename node_allocator_traits::value_type::value_type& v) | |
104 { | |
105 constructor.construct_with_value2(boost::move(v)); | |
106 return constructor.release(); | |
107 } | |
108 }; | |
109 | |
110 template <typename Buckets> | |
111 struct assign_nodes | |
112 { | |
113 node_holder<typename Buckets::node_allocator> holder; | |
114 | |
115 explicit assign_nodes(Buckets& b) : holder(b) {} | |
116 | |
117 typename Buckets::node_pointer create( | |
118 typename Buckets::value_type const& v) | |
119 { | |
120 return holder.copy_of(v); | |
121 } | |
122 }; | |
123 | |
124 template <typename Buckets> | |
125 struct move_assign_nodes | |
126 { | |
127 node_holder<typename Buckets::node_allocator> holder; | |
128 | |
129 explicit move_assign_nodes(Buckets& b) : holder(b) {} | |
130 | |
131 typename Buckets::node_pointer create( | |
132 typename Buckets::value_type& v) | |
133 { | |
134 return holder.move_copy_of(v); | |
135 } | |
136 }; | |
137 | |
138 template <typename Types> | |
139 struct table : | |
140 boost::unordered::detail::functions< | |
141 typename Types::hasher, | |
142 typename Types::key_equal> | |
143 { | |
144 private: | |
145 table(table const&); | |
146 table& operator=(table const&); | |
147 public: | |
148 typedef typename Types::node node; | |
149 typedef typename Types::bucket bucket; | |
150 typedef typename Types::hasher hasher; | |
151 typedef typename Types::key_equal key_equal; | |
152 typedef typename Types::key_type key_type; | |
153 typedef typename Types::extractor extractor; | |
154 typedef typename Types::value_type value_type; | |
155 typedef typename Types::table table_impl; | |
156 typedef typename Types::link_pointer link_pointer; | |
157 typedef typename Types::policy policy; | |
158 | |
159 typedef boost::unordered::detail::functions< | |
160 typename Types::hasher, | |
161 typename Types::key_equal> functions; | |
162 typedef typename functions::set_hash_functions set_hash_functions; | |
163 | |
164 typedef typename Types::allocator allocator; | |
165 typedef typename boost::unordered::detail:: | |
166 rebind_wrap<allocator, node>::type node_allocator; | |
167 typedef typename boost::unordered::detail:: | |
168 rebind_wrap<allocator, bucket>::type bucket_allocator; | |
169 typedef boost::unordered::detail::allocator_traits<node_allocator> | |
170 node_allocator_traits; | |
171 typedef boost::unordered::detail::allocator_traits<bucket_allocator> | |
172 bucket_allocator_traits; | |
173 typedef typename node_allocator_traits::pointer | |
174 node_pointer; | |
175 typedef typename node_allocator_traits::const_pointer | |
176 const_node_pointer; | |
177 typedef typename bucket_allocator_traits::pointer | |
178 bucket_pointer; | |
179 typedef boost::unordered::detail::node_constructor<node_allocator> | |
180 node_constructor; | |
181 | |
182 typedef boost::unordered::iterator_detail:: | |
183 iterator<node> iterator; | |
184 typedef boost::unordered::iterator_detail:: | |
185 c_iterator<node, const_node_pointer> c_iterator; | |
186 typedef boost::unordered::iterator_detail:: | |
187 l_iterator<node, policy> l_iterator; | |
188 typedef boost::unordered::iterator_detail:: | |
189 cl_iterator<node, const_node_pointer, policy> cl_iterator; | |
190 | |
191 //////////////////////////////////////////////////////////////////////// | |
192 // Members | |
193 | |
194 boost::unordered::detail::compressed<bucket_allocator, node_allocator> | |
195 allocators_; | |
196 std::size_t bucket_count_; | |
197 std::size_t size_; | |
198 float mlf_; | |
199 std::size_t max_load_; | |
200 bucket_pointer buckets_; | |
201 | |
202 //////////////////////////////////////////////////////////////////////// | |
203 // Data access | |
204 | |
205 bucket_allocator const& bucket_alloc() const | |
206 { | |
207 return allocators_.first(); | |
208 } | |
209 | |
210 node_allocator const& node_alloc() const | |
211 { | |
212 return allocators_.second(); | |
213 } | |
214 | |
215 bucket_allocator& bucket_alloc() | |
216 { | |
217 return allocators_.first(); | |
218 } | |
219 | |
220 node_allocator& node_alloc() | |
221 { | |
222 return allocators_.second(); | |
223 } | |
224 | |
225 std::size_t max_bucket_count() const | |
226 { | |
227 // -1 to account for the start bucket. | |
228 return policy::prev_bucket_count( | |
229 bucket_allocator_traits::max_size(bucket_alloc()) - 1); | |
230 } | |
231 | |
232 bucket_pointer get_bucket(std::size_t bucket_index) const | |
233 { | |
234 BOOST_ASSERT(buckets_); | |
235 return buckets_ + static_cast<std::ptrdiff_t>(bucket_index); | |
236 } | |
237 | |
238 link_pointer get_previous_start() const | |
239 { | |
240 return get_bucket(bucket_count_)->first_from_start(); | |
241 } | |
242 | |
243 link_pointer get_previous_start(std::size_t bucket_index) const | |
244 { | |
245 return get_bucket(bucket_index)->next_; | |
246 } | |
247 | |
248 iterator begin() const | |
249 { | |
250 return size_ ? iterator(get_previous_start()->next_) : iterator(); | |
251 } | |
252 | |
253 iterator begin(std::size_t bucket_index) const | |
254 { | |
255 if (!size_) return iterator(); | |
256 link_pointer prev = get_previous_start(bucket_index); | |
257 return prev ? iterator(prev->next_) : iterator(); | |
258 } | |
259 | |
260 std::size_t hash_to_bucket(std::size_t hash) const | |
261 { | |
262 return policy::to_bucket(bucket_count_, hash); | |
263 } | |
264 | |
265 float load_factor() const | |
266 { | |
267 BOOST_ASSERT(bucket_count_ != 0); | |
268 return static_cast<float>(size_) | |
269 / static_cast<float>(bucket_count_); | |
270 } | |
271 | |
272 std::size_t bucket_size(std::size_t index) const | |
273 { | |
274 iterator it = begin(index); | |
275 if (!it.node_) return 0; | |
276 | |
277 std::size_t count = 0; | |
278 while(it.node_ && hash_to_bucket(it.node_->hash_) == index) | |
279 { | |
280 ++count; | |
281 ++it; | |
282 } | |
283 | |
284 return count; | |
285 } | |
286 | |
287 //////////////////////////////////////////////////////////////////////// | |
288 // Load methods | |
289 | |
290 std::size_t max_size() const | |
291 { | |
292 using namespace std; | |
293 | |
294 // size < mlf_ * count | |
295 return boost::unordered::detail::double_to_size(ceil( | |
296 static_cast<double>(mlf_) * | |
297 static_cast<double>(max_bucket_count()) | |
298 )) - 1; | |
299 } | |
300 | |
301 void recalculate_max_load() | |
302 { | |
303 using namespace std; | |
304 | |
305 // From 6.3.1/13: | |
306 // Only resize when size >= mlf_ * count | |
307 max_load_ = buckets_ ? boost::unordered::detail::double_to_size(ceil( | |
308 static_cast<double>(mlf_) * | |
309 static_cast<double>(bucket_count_) | |
310 )) : 0; | |
311 | |
312 } | |
313 | |
314 void max_load_factor(float z) | |
315 { | |
316 BOOST_ASSERT(z > 0); | |
317 mlf_ = (std::max)(z, minimum_max_load_factor); | |
318 recalculate_max_load(); | |
319 } | |
320 | |
321 std::size_t min_buckets_for_size(std::size_t size) const | |
322 { | |
323 BOOST_ASSERT(mlf_ >= minimum_max_load_factor); | |
324 | |
325 using namespace std; | |
326 | |
327 // From 6.3.1/13: | |
328 // size < mlf_ * count | |
329 // => count > size / mlf_ | |
330 // | |
331 // Or from rehash post-condition: | |
332 // count > size / mlf_ | |
333 | |
334 return policy::new_bucket_count( | |
335 boost::unordered::detail::double_to_size(floor( | |
336 static_cast<double>(size) / | |
337 static_cast<double>(mlf_))) + 1); | |
338 } | |
339 | |
340 //////////////////////////////////////////////////////////////////////// | |
341 // Constructors | |
342 | |
343 table(std::size_t num_buckets, | |
344 hasher const& hf, | |
345 key_equal const& eq, | |
346 node_allocator const& a) : | |
347 functions(hf, eq), | |
348 allocators_(a,a), | |
349 bucket_count_(policy::new_bucket_count(num_buckets)), | |
350 size_(0), | |
351 mlf_(1.0f), | |
352 max_load_(0), | |
353 buckets_() | |
354 {} | |
355 | |
356 table(table const& x, node_allocator const& a) : | |
357 functions(x), | |
358 allocators_(a,a), | |
359 bucket_count_(x.min_buckets_for_size(x.size_)), | |
360 size_(0), | |
361 mlf_(x.mlf_), | |
362 max_load_(0), | |
363 buckets_() | |
364 {} | |
365 | |
366 table(table& x, boost::unordered::detail::move_tag m) : | |
367 functions(x, m), | |
368 allocators_(x.allocators_, m), | |
369 bucket_count_(x.bucket_count_), | |
370 size_(x.size_), | |
371 mlf_(x.mlf_), | |
372 max_load_(x.max_load_), | |
373 buckets_(x.buckets_) | |
374 { | |
375 x.buckets_ = bucket_pointer(); | |
376 x.size_ = 0; | |
377 x.max_load_ = 0; | |
378 } | |
379 | |
380 table(table& x, node_allocator const& a, | |
381 boost::unordered::detail::move_tag m) : | |
382 functions(x, m), | |
383 allocators_(a, a), | |
384 bucket_count_(x.bucket_count_), | |
385 size_(0), | |
386 mlf_(x.mlf_), | |
387 max_load_(x.max_load_), | |
388 buckets_() | |
389 {} | |
390 | |
391 //////////////////////////////////////////////////////////////////////// | |
392 // Initialisation. | |
393 | |
394 void init(table const& x) | |
395 { | |
396 if (x.size_) { | |
397 create_buckets(bucket_count_); | |
398 copy_nodes<node_allocator> copy(node_alloc()); | |
399 table_impl::fill_buckets(x.begin(), *this, copy); | |
400 } | |
401 } | |
402 | |
403 void move_init(table& x) | |
404 { | |
405 if(node_alloc() == x.node_alloc()) { | |
406 move_buckets_from(x); | |
407 } | |
408 else if(x.size_) { | |
409 // TODO: Could pick new bucket size? | |
410 create_buckets(bucket_count_); | |
411 | |
412 move_nodes<node_allocator> move(node_alloc()); | |
413 node_holder<node_allocator> nodes(x); | |
414 table_impl::fill_buckets(nodes.begin(), *this, move); | |
415 } | |
416 } | |
417 | |
418 //////////////////////////////////////////////////////////////////////// | |
419 // Create buckets | |
420 | |
421 void create_buckets(std::size_t new_count) | |
422 { | |
423 boost::unordered::detail::array_constructor<bucket_allocator> | |
424 constructor(bucket_alloc()); | |
425 | |
426 // Creates an extra bucket to act as the start node. | |
427 constructor.construct(bucket(), new_count + 1); | |
428 | |
429 if (buckets_) | |
430 { | |
431 // Copy the nodes to the new buckets, including the dummy | |
432 // node if there is one. | |
433 (constructor.get() + | |
434 static_cast<std::ptrdiff_t>(new_count))->next_ = | |
435 (buckets_ + static_cast<std::ptrdiff_t>( | |
436 bucket_count_))->next_; | |
437 destroy_buckets(); | |
438 } | |
439 else if (bucket::extra_node) | |
440 { | |
441 node_constructor a(node_alloc()); | |
442 a.construct(); | |
443 | |
444 (constructor.get() + | |
445 static_cast<std::ptrdiff_t>(new_count))->next_ = | |
446 a.release(); | |
447 } | |
448 | |
449 bucket_count_ = new_count; | |
450 buckets_ = constructor.release(); | |
451 recalculate_max_load(); | |
452 } | |
453 | |
454 //////////////////////////////////////////////////////////////////////// | |
455 // Swap and Move | |
456 | |
457 void swap_allocators(table& other, false_type) | |
458 { | |
459 boost::unordered::detail::func::ignore_unused_variable_warning(other); | |
460 | |
461 // According to 23.2.1.8, if propagate_on_container_swap is | |
462 // false the behaviour is undefined unless the allocators | |
463 // are equal. | |
464 BOOST_ASSERT(node_alloc() == other.node_alloc()); | |
465 } | |
466 | |
467 void swap_allocators(table& other, true_type) | |
468 { | |
469 allocators_.swap(other.allocators_); | |
470 } | |
471 | |
472 // Only swaps the allocators if propagate_on_container_swap | |
473 void swap(table& x) | |
474 { | |
475 set_hash_functions op1(*this, x); | |
476 set_hash_functions op2(x, *this); | |
477 | |
478 // I think swap can throw if Propagate::value, | |
479 // since the allocators' swap can throw. Not sure though. | |
480 swap_allocators(x, | |
481 boost::unordered::detail::integral_constant<bool, | |
482 allocator_traits<node_allocator>:: | |
483 propagate_on_container_swap::value>()); | |
484 | |
485 boost::swap(buckets_, x.buckets_); | |
486 boost::swap(bucket_count_, x.bucket_count_); | |
487 boost::swap(size_, x.size_); | |
488 std::swap(mlf_, x.mlf_); | |
489 std::swap(max_load_, x.max_load_); | |
490 op1.commit(); | |
491 op2.commit(); | |
492 } | |
493 | |
494 void move_buckets_from(table& other) | |
495 { | |
496 BOOST_ASSERT(node_alloc() == other.node_alloc()); | |
497 BOOST_ASSERT(!buckets_); | |
498 buckets_ = other.buckets_; | |
499 bucket_count_ = other.bucket_count_; | |
500 size_ = other.size_; | |
501 other.buckets_ = bucket_pointer(); | |
502 other.size_ = 0; | |
503 other.max_load_ = 0; | |
504 } | |
505 | |
506 //////////////////////////////////////////////////////////////////////// | |
507 // Delete/destruct | |
508 | |
509 ~table() | |
510 { | |
511 delete_buckets(); | |
512 } | |
513 | |
514 void delete_node(link_pointer prev) | |
515 { | |
516 node_pointer n = static_cast<node_pointer>(prev->next_); | |
517 prev->next_ = n->next_; | |
518 | |
519 boost::unordered::detail::func::destroy_value_impl(node_alloc(), | |
520 n->value_ptr()); | |
521 node_allocator_traits::destroy(node_alloc(), | |
522 boost::addressof(*n)); | |
523 node_allocator_traits::deallocate(node_alloc(), n, 1); | |
524 --size_; | |
525 } | |
526 | |
527 std::size_t delete_nodes(link_pointer prev, link_pointer end) | |
528 { | |
529 BOOST_ASSERT(prev->next_ != end); | |
530 | |
531 std::size_t count = 0; | |
532 | |
533 do { | |
534 delete_node(prev); | |
535 ++count; | |
536 } while (prev->next_ != end); | |
537 | |
538 return count; | |
539 } | |
540 | |
541 void delete_buckets() | |
542 { | |
543 if(buckets_) { | |
544 if (size_) delete_nodes(get_previous_start(), link_pointer()); | |
545 | |
546 if (bucket::extra_node) { | |
547 node_pointer n = static_cast<node_pointer>( | |
548 get_bucket(bucket_count_)->next_); | |
549 node_allocator_traits::destroy(node_alloc(), | |
550 boost::addressof(*n)); | |
551 node_allocator_traits::deallocate(node_alloc(), n, 1); | |
552 } | |
553 | |
554 destroy_buckets(); | |
555 buckets_ = bucket_pointer(); | |
556 max_load_ = 0; | |
557 } | |
558 | |
559 BOOST_ASSERT(!size_); | |
560 } | |
561 | |
562 void clear() | |
563 { | |
564 if (!size_) return; | |
565 | |
566 delete_nodes(get_previous_start(), link_pointer()); | |
567 clear_buckets(); | |
568 | |
569 BOOST_ASSERT(!size_); | |
570 } | |
571 | |
572 void clear_buckets() | |
573 { | |
574 bucket_pointer end = get_bucket(bucket_count_); | |
575 for(bucket_pointer it = buckets_; it != end; ++it) | |
576 { | |
577 it->next_ = node_pointer(); | |
578 } | |
579 } | |
580 | |
581 void destroy_buckets() | |
582 { | |
583 bucket_pointer end = get_bucket(bucket_count_ + 1); | |
584 for(bucket_pointer it = buckets_; it != end; ++it) | |
585 { | |
586 bucket_allocator_traits::destroy(bucket_alloc(), | |
587 boost::addressof(*it)); | |
588 } | |
589 | |
590 bucket_allocator_traits::deallocate(bucket_alloc(), | |
591 buckets_, bucket_count_ + 1); | |
592 } | |
593 | |
594 //////////////////////////////////////////////////////////////////////// | |
595 // Fix buckets after delete | |
596 // | |
597 | |
598 std::size_t fix_bucket(std::size_t bucket_index, link_pointer prev) | |
599 { | |
600 link_pointer end = prev->next_; | |
601 std::size_t bucket_index2 = bucket_index; | |
602 | |
603 if (end) | |
604 { | |
605 bucket_index2 = hash_to_bucket( | |
606 static_cast<node_pointer>(end)->hash_); | |
607 | |
608 // If begin and end are in the same bucket, then | |
609 // there's nothing to do. | |
610 if (bucket_index == bucket_index2) return bucket_index2; | |
611 | |
612 // Update the bucket containing end. | |
613 get_bucket(bucket_index2)->next_ = prev; | |
614 } | |
615 | |
616 // Check if this bucket is now empty. | |
617 bucket_pointer this_bucket = get_bucket(bucket_index); | |
618 if (this_bucket->next_ == prev) | |
619 this_bucket->next_ = link_pointer(); | |
620 | |
621 return bucket_index2; | |
622 } | |
623 | |
624 //////////////////////////////////////////////////////////////////////// | |
625 // Assignment | |
626 | |
627 void assign(table const& x) | |
628 { | |
629 if (this != boost::addressof(x)) | |
630 { | |
631 assign(x, | |
632 boost::unordered::detail::integral_constant<bool, | |
633 allocator_traits<node_allocator>:: | |
634 propagate_on_container_copy_assignment::value>()); | |
635 } | |
636 } | |
637 | |
638 void assign(table const& x, false_type) | |
639 { | |
640 // Strong exception safety. | |
641 set_hash_functions new_func_this(*this, x); | |
642 new_func_this.commit(); | |
643 mlf_ = x.mlf_; | |
644 recalculate_max_load(); | |
645 | |
646 if (!size_ && !x.size_) return; | |
647 | |
648 if (x.size_ >= max_load_) { | |
649 create_buckets(min_buckets_for_size(x.size_)); | |
650 } | |
651 else { | |
652 clear_buckets(); | |
653 } | |
654 | |
655 // assign_nodes takes ownership of the container's elements, | |
656 // assigning to them if possible, and deleting any that are | |
657 // left over. | |
658 assign_nodes<table> assign(*this); | |
659 table_impl::fill_buckets(x.begin(), *this, assign); | |
660 } | |
661 | |
662 void assign(table const& x, true_type) | |
663 { | |
664 if (node_alloc() == x.node_alloc()) { | |
665 allocators_.assign(x.allocators_); | |
666 assign(x, false_type()); | |
667 } | |
668 else { | |
669 set_hash_functions new_func_this(*this, x); | |
670 | |
671 // Delete everything with current allocators before assigning | |
672 // the new ones. | |
673 delete_buckets(); | |
674 allocators_.assign(x.allocators_); | |
675 | |
676 // Copy over other data, all no throw. | |
677 new_func_this.commit(); | |
678 mlf_ = x.mlf_; | |
679 bucket_count_ = min_buckets_for_size(x.size_); | |
680 max_load_ = 0; | |
681 | |
682 // Finally copy the elements. | |
683 if (x.size_) { | |
684 create_buckets(bucket_count_); | |
685 copy_nodes<node_allocator> copy(node_alloc()); | |
686 table_impl::fill_buckets(x.begin(), *this, copy); | |
687 } | |
688 } | |
689 } | |
690 | |
691 void move_assign(table& x) | |
692 { | |
693 if (this != boost::addressof(x)) | |
694 { | |
695 move_assign(x, | |
696 boost::unordered::detail::integral_constant<bool, | |
697 allocator_traits<node_allocator>:: | |
698 propagate_on_container_move_assignment::value>()); | |
699 } | |
700 } | |
701 | |
702 void move_assign(table& x, true_type) | |
703 { | |
704 delete_buckets(); | |
705 allocators_.move_assign(x.allocators_); | |
706 move_assign_no_alloc(x); | |
707 } | |
708 | |
709 void move_assign(table& x, false_type) | |
710 { | |
711 if (node_alloc() == x.node_alloc()) { | |
712 delete_buckets(); | |
713 move_assign_no_alloc(x); | |
714 } | |
715 else { | |
716 set_hash_functions new_func_this(*this, x); | |
717 new_func_this.commit(); | |
718 mlf_ = x.mlf_; | |
719 recalculate_max_load(); | |
720 | |
721 if (!size_ && !x.size_) return; | |
722 | |
723 if (x.size_ >= max_load_) { | |
724 create_buckets(min_buckets_for_size(x.size_)); | |
725 } | |
726 else { | |
727 clear_buckets(); | |
728 } | |
729 | |
730 // move_assign_nodes takes ownership of the container's | |
731 // elements, assigning to them if possible, and deleting | |
732 // any that are left over. | |
733 move_assign_nodes<table> assign(*this); | |
734 node_holder<node_allocator> nodes(x); | |
735 table_impl::fill_buckets(nodes.begin(), *this, assign); | |
736 } | |
737 } | |
738 | |
739 void move_assign_no_alloc(table& x) | |
740 { | |
741 set_hash_functions new_func_this(*this, x); | |
742 // No throw from here. | |
743 mlf_ = x.mlf_; | |
744 max_load_ = x.max_load_; | |
745 move_buckets_from(x); | |
746 new_func_this.commit(); | |
747 } | |
748 | |
749 // Accessors | |
750 | |
751 key_type const& get_key(value_type const& x) const | |
752 { | |
753 return extractor::extract(x); | |
754 } | |
755 | |
756 std::size_t hash(key_type const& k) const | |
757 { | |
758 return policy::apply_hash(this->hash_function(), k); | |
759 } | |
760 | |
761 // Find Node | |
762 | |
763 template <typename Key, typename Hash, typename Pred> | |
764 iterator generic_find_node( | |
765 Key const& k, | |
766 Hash const& hf, | |
767 Pred const& eq) const | |
768 { | |
769 return static_cast<table_impl const*>(this)-> | |
770 find_node_impl(policy::apply_hash(hf, k), k, eq); | |
771 } | |
772 | |
773 iterator find_node( | |
774 std::size_t key_hash, | |
775 key_type const& k) const | |
776 { | |
777 return static_cast<table_impl const*>(this)-> | |
778 find_node_impl(key_hash, k, this->key_eq()); | |
779 } | |
780 | |
781 iterator find_node(key_type const& k) const | |
782 { | |
783 return static_cast<table_impl const*>(this)-> | |
784 find_node_impl(hash(k), k, this->key_eq()); | |
785 } | |
786 | |
787 iterator find_matching_node(iterator n) const | |
788 { | |
789 // TODO: Does this apply to C++11? | |
790 // | |
791 // For some stupid reason, I decided to support equality comparison | |
792 // when different hash functions are used. So I can't use the hash | |
793 // value from the node here. | |
794 | |
795 return find_node(get_key(*n)); | |
796 } | |
797 | |
798 // Reserve and rehash | |
799 | |
800 void reserve_for_insert(std::size_t); | |
801 void rehash(std::size_t); | |
802 void reserve(std::size_t); | |
803 }; | |
804 | |
805 //////////////////////////////////////////////////////////////////////////// | |
806 // Reserve & Rehash | |
807 | |
808 // basic exception safety | |
809 template <typename Types> | |
810 inline void table<Types>::reserve_for_insert(std::size_t size) | |
811 { | |
812 if (!buckets_) { | |
813 create_buckets((std::max)(bucket_count_, | |
814 min_buckets_for_size(size))); | |
815 } | |
816 // According to the standard this should be 'size >= max_load_', | |
817 // but I think this is better, defect report filed. | |
818 else if(size > max_load_) { | |
819 std::size_t num_buckets | |
820 = min_buckets_for_size((std::max)(size, | |
821 size_ + (size_ >> 1))); | |
822 | |
823 if (num_buckets != bucket_count_) | |
824 static_cast<table_impl*>(this)->rehash_impl(num_buckets); | |
825 } | |
826 } | |
827 | |
828 // if hash function throws, basic exception safety | |
829 // strong otherwise. | |
830 | |
831 template <typename Types> | |
832 inline void table<Types>::rehash(std::size_t min_buckets) | |
833 { | |
834 using namespace std; | |
835 | |
836 if(!size_) { | |
837 delete_buckets(); | |
838 bucket_count_ = policy::new_bucket_count(min_buckets); | |
839 } | |
840 else { | |
841 min_buckets = policy::new_bucket_count((std::max)(min_buckets, | |
842 boost::unordered::detail::double_to_size(floor( | |
843 static_cast<double>(size_) / | |
844 static_cast<double>(mlf_))) + 1)); | |
845 | |
846 if(min_buckets != bucket_count_) | |
847 static_cast<table_impl*>(this)->rehash_impl(min_buckets); | |
848 } | |
849 } | |
850 | |
851 template <typename Types> | |
852 inline void table<Types>::reserve(std::size_t num_elements) | |
853 { | |
854 rehash(static_cast<std::size_t>( | |
855 std::ceil(static_cast<double>(num_elements) / mlf_))); | |
856 } | |
857 }}} | |
858 | |
859 #if defined(BOOST_MSVC) | |
860 #pragma warning(pop) | |
861 #endif | |
862 | |
863 #endif |