1 2 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. 3 // Copyright (C) 2005-2009 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 <cstddef> 11 #include <stdexcept> 12 #include <algorithm> 13 #include <boost/config/no_tr1/cmath.hpp> 14 #include <boost/iterator/iterator_categories.hpp> 15 #include <boost/throw_exception.hpp> 16 17 #include <boost/unordered/detail/buckets.hpp> 18 19 namespace boost { namespace unordered_detail { 20 21 //////////////////////////////////////////////////////////////////////////// 22 // Helper methods 23 24 // strong exception safety, no side effects 25 template <class T> equal(key_type const & k,value_type const & v) const26 inline bool hash_table<T>::equal( 27 key_type const& k, value_type const& v) const 28 { 29 return this->key_eq()(k, get_key(v)); 30 } 31 32 // strong exception safety, no side effects 33 template <class T> 34 template <class Key, class Pred> 35 inline BOOST_DEDUCED_TYPENAME T::node_ptr find_iterator(bucket_ptr bucket,Key const & k,Pred const & eq) const36 hash_table<T>::find_iterator(bucket_ptr bucket, Key const& k, 37 Pred const& eq) const 38 { 39 node_ptr it = bucket->next_; 40 while (BOOST_UNORDERED_BORLAND_BOOL(it) && 41 !eq(k, get_key(node::get_value(it)))) 42 { 43 it = node::next_group(it); 44 } 45 46 return it; 47 } 48 49 // strong exception safety, no side effects 50 template <class T> 51 inline BOOST_DEDUCED_TYPENAME T::node_ptr find_iterator(bucket_ptr bucket,key_type const & k) const52 hash_table<T>::find_iterator( 53 bucket_ptr bucket, key_type const& k) const 54 { 55 node_ptr it = bucket->next_; 56 while (BOOST_UNORDERED_BORLAND_BOOL(it) && 57 !equal(k, node::get_value(it))) 58 { 59 it = node::next_group(it); 60 } 61 62 return it; 63 } 64 65 // strong exception safety, no side effects 66 // pre: this->buckets_ 67 template <class T> 68 inline BOOST_DEDUCED_TYPENAME T::node_ptr find_iterator(key_type const & k) const69 hash_table<T>::find_iterator(key_type const& k) const 70 { 71 return find_iterator(this->get_bucket(this->bucket_index(k)), k); 72 } 73 74 // strong exception safety, no side effects 75 template <class T> 76 inline BOOST_DEDUCED_TYPENAME T::node_ptr* find_for_erase(bucket_ptr bucket,key_type const & k) const77 hash_table<T>::find_for_erase( 78 bucket_ptr bucket, key_type const& k) const 79 { 80 node_ptr* it = &bucket->next_; 81 while(BOOST_UNORDERED_BORLAND_BOOL(*it) && 82 !equal(k, node::get_value(*it))) 83 { 84 it = &node::next_group(*it); 85 } 86 87 return it; 88 } 89 90 //////////////////////////////////////////////////////////////////////////// 91 // Load methods 92 93 // no throw 94 template <class T> max_size() const95 std::size_t hash_table<T>::max_size() const 96 { 97 using namespace std; 98 99 // size < mlf_ * count 100 return double_to_size_t(ceil( 101 (double) this->mlf_ * this->max_bucket_count())) - 1; 102 } 103 104 // strong safety 105 template <class T> bucket_index(key_type const & k) const106 inline std::size_t hash_table<T>::bucket_index( 107 key_type const& k) const 108 { 109 // hash_function can throw: 110 return this->hash_function()(k) % this->bucket_count_; 111 } 112 113 114 // no throw 115 template <class T> calculate_max_load()116 inline std::size_t hash_table<T>::calculate_max_load() 117 { 118 using namespace std; 119 120 // From 6.3.1/13: 121 // Only resize when size >= mlf_ * count 122 return double_to_size_t(ceil((double) mlf_ * this->bucket_count_)); 123 } 124 125 template <class T> max_load_factor(float z)126 void hash_table<T>::max_load_factor(float z) 127 { 128 BOOST_ASSERT(z > 0); 129 mlf_ = (std::max)(z, minimum_max_load_factor); 130 this->max_load_ = this->calculate_max_load(); 131 } 132 133 // no throw 134 template <class T> min_buckets_for_size(std::size_t size) const135 inline std::size_t hash_table<T>::min_buckets_for_size( 136 std::size_t size) const 137 { 138 BOOST_ASSERT(this->mlf_ != 0); 139 140 using namespace std; 141 142 // From 6.3.1/13: 143 // size < mlf_ * count 144 // => count > size / mlf_ 145 // 146 // Or from rehash post-condition: 147 // count > size / mlf_ 148 return next_prime(double_to_size_t(floor(size / (double) mlf_)) + 1); 149 } 150 151 //////////////////////////////////////////////////////////////////////////// 152 // recompute_begin_bucket 153 154 // init_buckets 155 156 template <class T> init_buckets()157 inline void hash_table<T>::init_buckets() 158 { 159 if (this->size_) { 160 this->cached_begin_bucket_ = this->buckets_; 161 while (!this->cached_begin_bucket_->next_) 162 ++this->cached_begin_bucket_; 163 } else { 164 this->cached_begin_bucket_ = this->get_bucket(this->bucket_count_); 165 } 166 this->max_load_ = calculate_max_load(); 167 } 168 169 // After an erase cached_begin_bucket_ might be left pointing to 170 // an empty bucket, so this is called to update it 171 // 172 // no throw 173 174 template <class T> recompute_begin_bucket(bucket_ptr b)175 inline void hash_table<T>::recompute_begin_bucket(bucket_ptr b) 176 { 177 BOOST_ASSERT(!(b < this->cached_begin_bucket_)); 178 179 if(b == this->cached_begin_bucket_) 180 { 181 if (this->size_ != 0) { 182 while (!this->cached_begin_bucket_->next_) 183 ++this->cached_begin_bucket_; 184 } else { 185 this->cached_begin_bucket_ = 186 this->get_bucket(this->bucket_count_); 187 } 188 } 189 } 190 191 // This is called when a range has been erased 192 // 193 // no throw 194 195 template <class T> recompute_begin_bucket(bucket_ptr b1,bucket_ptr b2)196 inline void hash_table<T>::recompute_begin_bucket( 197 bucket_ptr b1, bucket_ptr b2) 198 { 199 BOOST_ASSERT(!(b1 < this->cached_begin_bucket_) && !(b2 < b1)); 200 BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(b2->next_)); 201 202 if(b1 == this->cached_begin_bucket_ && !b1->next_) 203 this->cached_begin_bucket_ = b2; 204 } 205 206 // no throw 207 template <class T> load_factor() const208 inline float hash_table<T>::load_factor() const 209 { 210 BOOST_ASSERT(this->bucket_count_ != 0); 211 return static_cast<float>(this->size_) 212 / static_cast<float>(this->bucket_count_); 213 } 214 215 //////////////////////////////////////////////////////////////////////////// 216 // Constructors 217 218 template <class T> hash_table(std::size_t num_buckets,hasher const & hf,key_equal const & eq,node_allocator const & a)219 hash_table<T>::hash_table(std::size_t num_buckets, 220 hasher const& hf, key_equal const& eq, node_allocator const& a) 221 : buckets(a, next_prime(num_buckets)), 222 base(hf, eq), 223 size_(), 224 mlf_(1.0f), 225 cached_begin_bucket_(), 226 max_load_(0) 227 { 228 } 229 230 // Copy Construct with allocator 231 232 template <class T> hash_table(hash_table const & x,node_allocator const & a)233 hash_table<T>::hash_table(hash_table const& x, 234 node_allocator const& a) 235 : buckets(a, x.min_buckets_for_size(x.size_)), 236 base(x), 237 size_(x.size_), 238 mlf_(x.mlf_), 239 cached_begin_bucket_(), 240 max_load_(0) 241 { 242 if(x.size_) { 243 x.copy_buckets_to(*this); 244 this->init_buckets(); 245 } 246 } 247 248 // Move Construct 249 250 template <class T> hash_table(hash_table & x,move_tag)251 hash_table<T>::hash_table(hash_table& x, move_tag) 252 : buckets(x.node_alloc(), x.bucket_count_), 253 base(x), 254 size_(0), 255 mlf_(1.0f), 256 cached_begin_bucket_(), 257 max_load_(0) 258 { 259 this->partial_swap(x); 260 } 261 262 template <class T> hash_table(hash_table & x,node_allocator const & a,move_tag)263 hash_table<T>::hash_table(hash_table& x, 264 node_allocator const& a, move_tag) 265 : buckets(a, x.bucket_count_), 266 base(x), 267 size_(0), 268 mlf_(x.mlf_), 269 cached_begin_bucket_(), 270 max_load_(0) 271 { 272 if(a == x.node_alloc()) { 273 this->partial_swap(x); 274 } 275 else if(x.size_) { 276 x.copy_buckets_to(*this); 277 this->size_ = x.size_; 278 this->init_buckets(); 279 } 280 } 281 282 template <class T> operator =(hash_table const & x)283 hash_table<T>& hash_table<T>::operator=( 284 hash_table const& x) 285 { 286 hash_table tmp(x, this->node_alloc()); 287 this->fast_swap(tmp); 288 return *this; 289 } 290 291 //////////////////////////////////////////////////////////////////////////// 292 // Swap & Move 293 294 // Swap 295 // 296 // Strong exception safety 297 // 298 // Can throw if hash or predicate object's copy constructor throws 299 // or if allocators are unequal. 300 301 template <class T> partial_swap(hash_table & x)302 inline void hash_table<T>::partial_swap(hash_table& x) 303 { 304 this->buckets::swap(x); // No throw 305 std::swap(this->size_, x.size_); 306 std::swap(this->mlf_, x.mlf_); 307 std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); 308 std::swap(this->max_load_, x.max_load_); 309 } 310 311 template <class T> fast_swap(hash_table & x)312 inline void hash_table<T>::fast_swap(hash_table& x) 313 { 314 // These can throw, but they only affect the function objects 315 // that aren't in use so it is strongly exception safe, via. 316 // double buffering. 317 { 318 set_hash_functions<hasher, key_equal> op1(*this, x); 319 set_hash_functions<hasher, key_equal> op2(x, *this); 320 op1.commit(); 321 op2.commit(); 322 } 323 this->buckets::swap(x); // No throw 324 std::swap(this->size_, x.size_); 325 std::swap(this->mlf_, x.mlf_); 326 std::swap(this->cached_begin_bucket_, x.cached_begin_bucket_); 327 std::swap(this->max_load_, x.max_load_); 328 } 329 330 template <class T> slow_swap(hash_table & x)331 inline void hash_table<T>::slow_swap(hash_table& x) 332 { 333 if(this == &x) return; 334 335 { 336 // These can throw, but they only affect the function objects 337 // that aren't in use so it is strongly exception safe, via. 338 // double buffering. 339 set_hash_functions<hasher, key_equal> op1(*this, x); 340 set_hash_functions<hasher, key_equal> op2(x, *this); 341 342 // Create new buckets in separate hash_buckets objects 343 // which will clean up if anything throws an exception. 344 // (all can throw, but with no effect as these are new objects). 345 346 buckets b1(this->node_alloc(), x.min_buckets_for_size(x.size_)); 347 if(x.size_) x.copy_buckets_to(b1); 348 349 buckets b2(x.node_alloc(), this->min_buckets_for_size(this->size_)); 350 if(this->size_) copy_buckets_to(b2); 351 352 // Modifying the data, so no throw from now on. 353 354 b1.swap(*this); 355 b2.swap(x); 356 op1.commit(); 357 op2.commit(); 358 } 359 360 std::swap(this->size_, x.size_); 361 362 if(this->buckets_) this->init_buckets(); 363 if(x.buckets_) x.init_buckets(); 364 } 365 366 template <class T> swap(hash_table & x)367 void hash_table<T>::swap(hash_table& x) 368 { 369 if(this->node_alloc() == x.node_alloc()) { 370 if(this != &x) this->fast_swap(x); 371 } 372 else { 373 this->slow_swap(x); 374 } 375 } 376 377 378 // Move 379 // 380 // Strong exception safety (might change unused function objects) 381 // 382 // Can throw if hash or predicate object's copy constructor throws 383 // or if allocators are unequal. 384 385 template <class T> move(hash_table & x)386 void hash_table<T>::move(hash_table& x) 387 { 388 // This can throw, but it only affects the function objects 389 // that aren't in use so it is strongly exception safe, via. 390 // double buffering. 391 set_hash_functions<hasher, key_equal> new_func_this(*this, x); 392 393 if(this->node_alloc() == x.node_alloc()) { 394 this->buckets::move(x); // no throw 395 this->size_ = x.size_; 396 this->cached_begin_bucket_ = x.cached_begin_bucket_; 397 this->max_load_ = x.max_load_; 398 x.size_ = 0; 399 } 400 else { 401 // Create new buckets in separate HASH_TABLE_DATA objects 402 // which will clean up if anything throws an exception. 403 // (all can throw, but with no effect as these are new objects). 404 405 buckets b(this->node_alloc(), x.min_buckets_for_size(x.size_)); 406 if(x.size_) x.copy_buckets_to(b); 407 408 // Start updating the data here, no throw from now on. 409 this->size_ = x.size_; 410 b.swap(*this); 411 this->init_buckets(); 412 } 413 414 // We've made it, the rest is no throw. 415 this->mlf_ = x.mlf_; 416 new_func_this.commit(); 417 } 418 419 //////////////////////////////////////////////////////////////////////////// 420 // Reserve & Rehash 421 422 // basic exception safety 423 template <class T> create_for_insert(std::size_t size)424 inline void hash_table<T>::create_for_insert(std::size_t size) 425 { 426 this->bucket_count_ = (std::max)(this->bucket_count_, 427 this->min_buckets_for_size(size)); 428 this->create_buckets(); 429 this->init_buckets(); 430 } 431 432 // basic exception safety 433 template <class T> reserve_for_insert(std::size_t size)434 inline bool hash_table<T>::reserve_for_insert(std::size_t size) 435 { 436 if(size >= max_load_) { 437 std::size_t num_buckets 438 = this->min_buckets_for_size((std::max)(size, 439 this->size_ + (this->size_ >> 1))); 440 if(num_buckets != this->bucket_count_) { 441 rehash_impl(num_buckets); 442 return true; 443 } 444 } 445 446 return false; 447 } 448 449 // if hash function throws, basic exception safety 450 // strong otherwise. 451 452 template <class T> rehash(std::size_t min_buckets)453 inline void hash_table<T>::rehash(std::size_t min_buckets) 454 { 455 using namespace std; 456 457 if(!this->size_) { 458 if(this->buckets_) this->delete_buckets(); 459 this->bucket_count_ = next_prime(min_buckets); 460 } 461 else { 462 // no throw: 463 min_buckets = next_prime((std::max)(min_buckets, 464 double_to_size_t(floor(this->size_ / (double) mlf_)) + 1)); 465 if(min_buckets != this->bucket_count_) rehash_impl(min_buckets); 466 } 467 } 468 469 // if hash function throws, basic exception safety 470 // strong otherwise 471 472 template <class T> 473 void hash_table<T> rehash_impl(std::size_t num_buckets)474 ::rehash_impl(std::size_t num_buckets) 475 { 476 hasher const& hf = this->hash_function(); 477 std::size_t size = this->size_; 478 bucket_ptr end = this->get_bucket(this->bucket_count_); 479 480 buckets dst(this->node_alloc(), num_buckets); 481 dst.create_buckets(); 482 483 buckets src(this->node_alloc(), this->bucket_count_); 484 src.swap(*this); 485 this->size_ = 0; 486 487 for(bucket_ptr bucket = this->cached_begin_bucket_; 488 bucket != end; ++bucket) 489 { 490 node_ptr group = bucket->next_; 491 while(group) { 492 // Move the first group of equivalent nodes in bucket to dst. 493 494 // This next line throws iff the hash function throws. 495 bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( 496 hf(get_key_from_ptr(group))); 497 498 node_ptr& next_group = node::next_group(group); 499 bucket->next_ = next_group; 500 next_group = dst_bucket->next_; 501 dst_bucket->next_ = group; 502 group = bucket->next_; 503 } 504 } 505 506 // Swap the new nodes back into the container and setup the local 507 // variables. 508 this->size_ = size; 509 dst.swap(*this); // no throw 510 this->init_buckets(); 511 } 512 513 //////////////////////////////////////////////////////////////////////////// 514 // copy_buckets_to 515 516 // copy_buckets_to 517 // 518 // basic excpetion safety. If an exception is thrown this will 519 // leave dst partially filled. 520 521 template <class T> 522 void hash_table<T> copy_buckets_to(buckets & dst) const523 ::copy_buckets_to(buckets& dst) const 524 { 525 BOOST_ASSERT(this->buckets_ && !dst.buckets_); 526 527 hasher const& hf = this->hash_function(); 528 bucket_ptr end = this->get_bucket(this->bucket_count_); 529 530 node_constructor a(dst); 531 dst.create_buckets(); 532 533 // no throw: 534 for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) { 535 // no throw: 536 for(node_ptr it = i->next_; it;) { 537 // hash function can throw. 538 bucket_ptr dst_bucket = dst.bucket_ptr_from_hash( 539 hf(get_key_from_ptr(it))); 540 // throws, strong 541 542 node_ptr group_end = node::next_group(it); 543 544 a.construct(node::get_value(it)); 545 node_ptr n = a.release(); 546 node::add_to_bucket(n, *dst_bucket); 547 548 for(it = it->next_; it != group_end; it = it->next_) { 549 a.construct(node::get_value(it)); 550 node::add_after_node(a.release(), n); 551 } 552 } 553 } 554 } 555 556 //////////////////////////////////////////////////////////////////////////// 557 // Misc. key methods 558 559 // strong exception safety 560 561 // count 562 // 563 // strong exception safety, no side effects 564 565 template <class T> count(key_type const & k) const566 std::size_t hash_table<T>::count(key_type const& k) const 567 { 568 if(!this->size_) return 0; 569 node_ptr it = find_iterator(k); // throws, strong 570 return BOOST_UNORDERED_BORLAND_BOOL(it) ? node::group_count(it) : 0; 571 } 572 573 // find 574 // 575 // strong exception safety, no side effects 576 template <class T> 577 BOOST_DEDUCED_TYPENAME T::iterator_base find(key_type const & k) const578 hash_table<T>::find(key_type const& k) const 579 { 580 if(!this->size_) return this->end(); 581 582 bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); 583 node_ptr it = find_iterator(bucket, k); 584 585 if (BOOST_UNORDERED_BORLAND_BOOL(it)) 586 return iterator_base(bucket, it); 587 else 588 return this->end(); 589 } 590 591 template <class T> 592 template <class Key, class Hash, class Pred> find(Key const & k,Hash const & h,Pred const & eq) const593 BOOST_DEDUCED_TYPENAME T::iterator_base hash_table<T>::find(Key const& k, 594 Hash const& h, Pred const& eq) const 595 { 596 if(!this->size_) return this->end(); 597 598 bucket_ptr bucket = this->get_bucket(h(k) % this->bucket_count_); 599 node_ptr it = find_iterator(bucket, k, eq); 600 601 if (BOOST_UNORDERED_BORLAND_BOOL(it)) 602 return iterator_base(bucket, it); 603 else 604 return this->end(); 605 } 606 607 template <class T> 608 BOOST_DEDUCED_TYPENAME T::value_type& at(key_type const & k) const609 hash_table<T>::at(key_type const& k) const 610 { 611 if(!this->size_) 612 boost::throw_exception(std::out_of_range("Unable to find key in unordered_map.")); 613 614 bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); 615 node_ptr it = find_iterator(bucket, k); 616 617 if (!it) 618 boost::throw_exception(std::out_of_range("Unable to find key in unordered_map.")); 619 620 return node::get_value(it); 621 } 622 623 // equal_range 624 // 625 // strong exception safety, no side effects 626 template <class T> 627 BOOST_DEDUCED_TYPENAME T::iterator_pair equal_range(key_type const & k) const628 hash_table<T>::equal_range(key_type const& k) const 629 { 630 if(!this->size_) 631 return iterator_pair(this->end(), this->end()); 632 633 bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); 634 node_ptr it = find_iterator(bucket, k); 635 if (BOOST_UNORDERED_BORLAND_BOOL(it)) { 636 iterator_base first(iterator_base(bucket, it)); 637 iterator_base second(first); 638 second.increment_bucket(node::next_group(second.node_)); 639 return iterator_pair(first, second); 640 } 641 else { 642 return iterator_pair(this->end(), this->end()); 643 } 644 } 645 646 //////////////////////////////////////////////////////////////////////////// 647 // Erase methods 648 649 template <class T> clear()650 void hash_table<T>::clear() 651 { 652 if(!this->size_) return; 653 654 bucket_ptr end = this->get_bucket(this->bucket_count_); 655 for(bucket_ptr begin = this->buckets_; begin != end; ++begin) { 656 this->clear_bucket(begin); 657 } 658 659 this->size_ = 0; 660 this->cached_begin_bucket_ = end; 661 } 662 663 template <class T> erase_group(node_ptr * it,bucket_ptr bucket)664 inline std::size_t hash_table<T>::erase_group( 665 node_ptr* it, bucket_ptr bucket) 666 { 667 node_ptr pos = *it; 668 node_ptr end = node::next_group(pos); 669 *it = end; 670 std::size_t count = this->delete_nodes(pos, end); 671 this->size_ -= count; 672 this->recompute_begin_bucket(bucket); 673 return count; 674 } 675 676 template <class T> erase_key(key_type const & k)677 std::size_t hash_table<T>::erase_key(key_type const& k) 678 { 679 if(!this->size_) return 0; 680 681 // No side effects in initial section 682 bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); 683 node_ptr* it = this->find_for_erase(bucket, k); 684 685 // No throw. 686 return *it ? this->erase_group(it, bucket) : 0; 687 } 688 689 template <class T> erase(iterator_base r)690 void hash_table<T>::erase(iterator_base r) 691 { 692 BOOST_ASSERT(r.node_); 693 --this->size_; 694 node::unlink_node(*r.bucket_, r.node_); 695 this->delete_node(r.node_); 696 // r has been invalidated but its bucket is still valid 697 this->recompute_begin_bucket(r.bucket_); 698 } 699 700 template <class T> 701 BOOST_DEDUCED_TYPENAME T::iterator_base erase_return_iterator(iterator_base r)702 hash_table<T>::erase_return_iterator(iterator_base r) 703 { 704 BOOST_ASSERT(r.node_); 705 iterator_base next = r; 706 next.increment(); 707 --this->size_; 708 node::unlink_node(*r.bucket_, r.node_); 709 this->delete_node(r.node_); 710 // r has been invalidated but its bucket is still valid 711 this->recompute_begin_bucket(r.bucket_, next.bucket_); 712 return next; 713 } 714 715 template <class T> 716 BOOST_DEDUCED_TYPENAME T::iterator_base erase_range(iterator_base r1,iterator_base r2)717 hash_table<T>::erase_range( 718 iterator_base r1, iterator_base r2) 719 { 720 if(r1 != r2) 721 { 722 BOOST_ASSERT(r1.node_); 723 if (r1.bucket_ == r2.bucket_) { 724 node::unlink_nodes(*r1.bucket_, r1.node_, r2.node_); 725 this->size_ -= this->delete_nodes(r1.node_, r2.node_); 726 727 // No need to call recompute_begin_bucket because 728 // the nodes are only deleted from one bucket, which 729 // still contains r2 after the erase. 730 BOOST_ASSERT(r1.bucket_->next_); 731 } 732 else { 733 bucket_ptr end_bucket = r2.node_ ? 734 r2.bucket_ : this->get_bucket(this->bucket_count_); 735 BOOST_ASSERT(r1.bucket_ < end_bucket); 736 node::unlink_nodes(*r1.bucket_, r1.node_, node_ptr()); 737 this->size_ -= this->delete_nodes(r1.node_, node_ptr()); 738 739 bucket_ptr i = r1.bucket_; 740 for(++i; i != end_bucket; ++i) { 741 this->size_ -= this->delete_nodes(i->next_, node_ptr()); 742 i->next_ = node_ptr(); 743 } 744 745 if(r2.node_) { 746 node_ptr first = r2.bucket_->next_; 747 node::unlink_nodes(*r2.bucket_, r2.node_); 748 this->size_ -= this->delete_nodes(first, r2.node_); 749 } 750 751 // r1 has been invalidated but its bucket is still 752 // valid. 753 this->recompute_begin_bucket(r1.bucket_, end_bucket); 754 } 755 } 756 757 return r2; 758 } 759 760 template <class T> 761 BOOST_DEDUCED_TYPENAME hash_table<T>::iterator_base emplace_empty_impl_with_node(node_constructor & a,std::size_t size)762 hash_table<T>::emplace_empty_impl_with_node( 763 node_constructor& a, std::size_t size) 764 { 765 key_type const& k = get_key(a.value()); 766 std::size_t hash_value = this->hash_function()(k); 767 if(this->buckets_) this->reserve_for_insert(size); 768 else this->create_for_insert(size); 769 bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); 770 node_ptr n = a.release(); 771 node::add_to_bucket(n, *bucket); 772 ++this->size_; 773 this->cached_begin_bucket_ = bucket; 774 return iterator_base(bucket, n); 775 } 776 }} 777 778 #endif 779