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