1 // hashtable.h header -*- C++ -*- 2 3 // Copyright (C) 2007-2015 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file bits/hashtable.h 26 * This is an internal header file, included by other library headers. 27 * Do not attempt to use it directly. @headername{unordered_map, unordered_set} 28 */ 29 30 #ifndef _HASHTABLE_H 31 #define _HASHTABLE_H 1 32 33 #pragma GCC system_header 34 35 #include <bits/hashtable_policy.h> 36 37 namespace std _GLIBCXX_VISIBILITY(default) 38 { 39 _GLIBCXX_BEGIN_NAMESPACE_VERSION 40 41 template<typename _Tp, typename _Hash> 42 using __cache_default 43 = __not_<__and_<// Do not cache for fast hasher. 44 __is_fast_hash<_Hash>, 45 // Mandatory to have erase not throwing. 46 __detail::__is_noexcept_hash<_Tp, _Hash>>>; 47 48 /** 49 * Primary class template _Hashtable. 50 * 51 * @ingroup hashtable-detail 52 * 53 * @tparam _Value CopyConstructible type. 54 * 55 * @tparam _Key CopyConstructible type. 56 * 57 * @tparam _Alloc An allocator type 58 * ([lib.allocator.requirements]) whose _Alloc::value_type is 59 * _Value. As a conforming extension, we allow for 60 * _Alloc::value_type != _Value. 61 * 62 * @tparam _ExtractKey Function object that takes an object of type 63 * _Value and returns a value of type _Key. 64 * 65 * @tparam _Equal Function object that takes two objects of type k 66 * and returns a bool-like value that is true if the two objects 67 * are considered equal. 68 * 69 * @tparam _H1 The hash function. A unary function object with 70 * argument type _Key and result type size_t. Return values should 71 * be distributed over the entire range [0, numeric_limits<size_t>:::max()]. 72 * 73 * @tparam _H2 The range-hashing function (in the terminology of 74 * Tavori and Dreizin). A binary function object whose argument 75 * types and result type are all size_t. Given arguments r and N, 76 * the return value is in the range [0, N). 77 * 78 * @tparam _Hash The ranged hash function (Tavori and Dreizin). A 79 * binary function whose argument types are _Key and size_t and 80 * whose result type is size_t. Given arguments k and N, the 81 * return value is in the range [0, N). Default: hash(k, N) = 82 * h2(h1(k), N). If _Hash is anything other than the default, _H1 83 * and _H2 are ignored. 84 * 85 * @tparam _RehashPolicy Policy class with three members, all of 86 * which govern the bucket count. _M_next_bkt(n) returns a bucket 87 * count no smaller than n. _M_bkt_for_elements(n) returns a 88 * bucket count appropriate for an element count of n. 89 * _M_need_rehash(n_bkt, n_elt, n_ins) determines whether, if the 90 * current bucket count is n_bkt and the current element count is 91 * n_elt, we need to increase the bucket count. If so, returns 92 * make_pair(true, n), where n is the new bucket count. If not, 93 * returns make_pair(false, <anything>) 94 * 95 * @tparam _Traits Compile-time class with three boolean 96 * std::integral_constant members: __cache_hash_code, __constant_iterators, 97 * __unique_keys. 98 * 99 * Each _Hashtable data structure has: 100 * 101 * - _Bucket[] _M_buckets 102 * - _Hash_node_base _M_before_begin 103 * - size_type _M_bucket_count 104 * - size_type _M_element_count 105 * 106 * with _Bucket being _Hash_node* and _Hash_node containing: 107 * 108 * - _Hash_node* _M_next 109 * - Tp _M_value 110 * - size_t _M_hash_code if cache_hash_code is true 111 * 112 * In terms of Standard containers the hashtable is like the aggregation of: 113 * 114 * - std::forward_list<_Node> containing the elements 115 * - std::vector<std::forward_list<_Node>::iterator> representing the buckets 116 * 117 * The non-empty buckets contain the node before the first node in the 118 * bucket. This design makes it possible to implement something like a 119 * std::forward_list::insert_after on container insertion and 120 * std::forward_list::erase_after on container erase 121 * calls. _M_before_begin is equivalent to 122 * std::forward_list::before_begin. Empty buckets contain 123 * nullptr. Note that one of the non-empty buckets contains 124 * &_M_before_begin which is not a dereferenceable node so the 125 * node pointer in a bucket shall never be dereferenced, only its 126 * next node can be. 127 * 128 * Walking through a bucket's nodes requires a check on the hash code to 129 * see if each node is still in the bucket. Such a design assumes a 130 * quite efficient hash functor and is one of the reasons it is 131 * highly advisable to set __cache_hash_code to true. 132 * 133 * The container iterators are simply built from nodes. This way 134 * incrementing the iterator is perfectly efficient independent of 135 * how many empty buckets there are in the container. 136 * 137 * On insert we compute the element's hash code and use it to find the 138 * bucket index. If the element must be inserted in an empty bucket 139 * we add it at the beginning of the singly linked list and make the 140 * bucket point to _M_before_begin. The bucket that used to point to 141 * _M_before_begin, if any, is updated to point to its new before 142 * begin node. 143 * 144 * On erase, the simple iterator design requires using the hash 145 * functor to get the index of the bucket to update. For this 146 * reason, when __cache_hash_code is set to false the hash functor must 147 * not throw and this is enforced by a static assertion. 148 * 149 * Functionality is implemented by decomposition into base classes, 150 * where the derived _Hashtable class is used in _Map_base, 151 * _Insert, _Rehash_base, and _Equality base classes to access the 152 * "this" pointer. _Hashtable_base is used in the base classes as a 153 * non-recursive, fully-completed-type so that detailed nested type 154 * information, such as iterator type and node type, can be 155 * used. This is similar to the "Curiously Recurring Template 156 * Pattern" (CRTP) technique, but uses a reconstructed, not 157 * explicitly passed, template pattern. 158 * 159 * Base class templates are: 160 * - __detail::_Hashtable_base 161 * - __detail::_Map_base 162 * - __detail::_Insert 163 * - __detail::_Rehash_base 164 * - __detail::_Equality 165 */ 166 template<typename _Key, typename _Value, typename _Alloc, 167 typename _ExtractKey, typename _Equal, 168 typename _H1, typename _H2, typename _Hash, 169 typename _RehashPolicy, typename _Traits> 170 class _Hashtable 171 : public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, 172 _H1, _H2, _Hash, _Traits>, 173 public __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, 174 _H1, _H2, _Hash, _RehashPolicy, _Traits>, 175 public __detail::_Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal, 176 _H1, _H2, _Hash, _RehashPolicy, _Traits>, 177 public __detail::_Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, 178 _H1, _H2, _Hash, _RehashPolicy, _Traits>, 179 public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, 180 _H1, _H2, _Hash, _RehashPolicy, _Traits>, 181 private __detail::_Hashtable_alloc< 182 typename __alloctr_rebind<_Alloc, 183 __detail::_Hash_node<_Value, 184 _Traits::__hash_cached::value> >::__type> 185 { 186 using __traits_type = _Traits; 187 using __hash_cached = typename __traits_type::__hash_cached; 188 using __node_type = __detail::_Hash_node<_Value, __hash_cached::value>; 189 using __node_alloc_type = 190 typename __alloctr_rebind<_Alloc, __node_type>::__type; 191 192 using __hashtable_alloc = __detail::_Hashtable_alloc<__node_alloc_type>; 193 194 using __value_alloc_traits = 195 typename __hashtable_alloc::__value_alloc_traits; 196 using __node_alloc_traits = 197 typename __hashtable_alloc::__node_alloc_traits; 198 using __node_base = typename __hashtable_alloc::__node_base; 199 using __bucket_type = typename __hashtable_alloc::__bucket_type; 200 201 public: 202 typedef _Key key_type; 203 typedef _Value value_type; 204 typedef _Alloc allocator_type; 205 typedef _Equal key_equal; 206 207 // mapped_type, if present, comes from _Map_base. 208 // hasher, if present, comes from _Hash_code_base/_Hashtable_base. 209 typedef typename __value_alloc_traits::pointer pointer; 210 typedef typename __value_alloc_traits::const_pointer const_pointer; 211 typedef value_type& reference; 212 typedef const value_type& const_reference; 213 214 private: 215 using __rehash_type = _RehashPolicy; 216 using __rehash_state = typename __rehash_type::_State; 217 218 using __constant_iterators = typename __traits_type::__constant_iterators; 219 using __unique_keys = typename __traits_type::__unique_keys; 220 221 using __key_extract = typename std::conditional< 222 __constant_iterators::value, 223 __detail::_Identity, 224 __detail::_Select1st>::type; 225 226 using __hashtable_base = __detail:: 227 _Hashtable_base<_Key, _Value, _ExtractKey, 228 _Equal, _H1, _H2, _Hash, _Traits>; 229 230 using __hash_code_base = typename __hashtable_base::__hash_code_base; 231 using __hash_code = typename __hashtable_base::__hash_code; 232 using __ireturn_type = typename __hashtable_base::__ireturn_type; 233 234 using __map_base = __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, 235 _Equal, _H1, _H2, _Hash, 236 _RehashPolicy, _Traits>; 237 238 using __rehash_base = __detail::_Rehash_base<_Key, _Value, _Alloc, 239 _ExtractKey, _Equal, 240 _H1, _H2, _Hash, 241 _RehashPolicy, _Traits>; 242 243 using __eq_base = __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, 244 _Equal, _H1, _H2, _Hash, 245 _RehashPolicy, _Traits>; 246 247 using __reuse_or_alloc_node_type = 248 __detail::_ReuseOrAllocNode<__node_alloc_type>; 249 250 // Metaprogramming for picking apart hash caching. 251 template<typename _Cond> 252 using __if_hash_cached = __or_<__not_<__hash_cached>, _Cond>; 253 254 template<typename _Cond> 255 using __if_hash_not_cached = __or_<__hash_cached, _Cond>; 256 257 // Compile-time diagnostics. 258 259 // _Hash_code_base has everything protected, so use this derived type to 260 // access it. 261 struct __hash_code_base_access : __hash_code_base 262 { using __hash_code_base::_M_bucket_index; }; 263 264 // Getting a bucket index from a node shall not throw because it is used 265 // in methods (erase, swap...) that shall not throw. 266 static_assert(noexcept(declval<const __hash_code_base_access&>() 267 ._M_bucket_index((const __node_type*)nullptr, 268 (std::size_t)0)), 269 "Cache the hash code or qualify your functors involved" 270 " in hash code and bucket index computation with noexcept"); 271 272 // Following two static assertions are necessary to guarantee 273 // that local_iterator will be default constructible. 274 275 // When hash codes are cached local iterator inherits from H2 functor 276 // which must then be default constructible. 277 static_assert(__if_hash_cached<is_default_constructible<_H2>>::value, 278 "Functor used to map hash code to bucket index" 279 " must be default constructible"); 280 281 template<typename _Keya, typename _Valuea, typename _Alloca, 282 typename _ExtractKeya, typename _Equala, 283 typename _H1a, typename _H2a, typename _Hasha, 284 typename _RehashPolicya, typename _Traitsa, 285 bool _Unique_keysa> 286 friend struct __detail::_Map_base; 287 288 template<typename _Keya, typename _Valuea, typename _Alloca, 289 typename _ExtractKeya, typename _Equala, 290 typename _H1a, typename _H2a, typename _Hasha, 291 typename _RehashPolicya, typename _Traitsa> 292 friend struct __detail::_Insert_base; 293 294 template<typename _Keya, typename _Valuea, typename _Alloca, 295 typename _ExtractKeya, typename _Equala, 296 typename _H1a, typename _H2a, typename _Hasha, 297 typename _RehashPolicya, typename _Traitsa, 298 bool _Constant_iteratorsa, bool _Unique_keysa> 299 friend struct __detail::_Insert; 300 301 public: 302 using size_type = typename __hashtable_base::size_type; 303 using difference_type = typename __hashtable_base::difference_type; 304 305 using iterator = typename __hashtable_base::iterator; 306 using const_iterator = typename __hashtable_base::const_iterator; 307 308 using local_iterator = typename __hashtable_base::local_iterator; 309 using const_local_iterator = typename __hashtable_base:: 310 const_local_iterator; 311 312 private: 313 __bucket_type* _M_buckets = &_M_single_bucket; 314 size_type _M_bucket_count = 1; 315 __node_base _M_before_begin; 316 size_type _M_element_count = 0; 317 _RehashPolicy _M_rehash_policy; 318 319 // A single bucket used when only need for 1 bucket. Especially 320 // interesting in move semantic to leave hashtable with only 1 buckets 321 // which is not allocated so that we can have those operations noexcept 322 // qualified. 323 // Note that we can't leave hashtable with 0 bucket without adding 324 // numerous checks in the code to avoid 0 modulus. 325 __bucket_type _M_single_bucket = nullptr; 326 327 bool 328 _M_uses_single_bucket(__bucket_type* __bkts) const 329 { return __builtin_expect(__bkts == &_M_single_bucket, false); } 330 331 bool 332 _M_uses_single_bucket() const 333 { return _M_uses_single_bucket(_M_buckets); } 334 335 __hashtable_alloc& 336 _M_base_alloc() { return *this; } 337 338 __bucket_type* 339 _M_allocate_buckets(size_type __n) 340 { 341 if (__builtin_expect(__n == 1, false)) 342 { 343 _M_single_bucket = nullptr; 344 return &_M_single_bucket; 345 } 346 347 return __hashtable_alloc::_M_allocate_buckets(__n); 348 } 349 350 void 351 _M_deallocate_buckets(__bucket_type* __bkts, size_type __n) 352 { 353 if (_M_uses_single_bucket(__bkts)) 354 return; 355 356 __hashtable_alloc::_M_deallocate_buckets(__bkts, __n); 357 } 358 359 void 360 _M_deallocate_buckets() 361 { _M_deallocate_buckets(_M_buckets, _M_bucket_count); } 362 363 // Gets bucket begin, deals with the fact that non-empty buckets contain 364 // their before begin node. 365 __node_type* 366 _M_bucket_begin(size_type __bkt) const; 367 368 __node_type* 369 _M_begin() const 370 { return static_cast<__node_type*>(_M_before_begin._M_nxt); } 371 372 template<typename _NodeGenerator> 373 void 374 _M_assign(const _Hashtable&, const _NodeGenerator&); 375 376 void 377 _M_move_assign(_Hashtable&&, std::true_type); 378 379 void 380 _M_move_assign(_Hashtable&&, std::false_type); 381 382 void 383 _M_reset() noexcept; 384 385 _Hashtable(const _H1& __h1, const _H2& __h2, const _Hash& __h, 386 const _Equal& __eq, const _ExtractKey& __exk, 387 const allocator_type& __a) 388 : __hashtable_base(__exk, __h1, __h2, __h, __eq), 389 __hashtable_alloc(__node_alloc_type(__a)) 390 { } 391 392 public: 393 // Constructor, destructor, assignment, swap 394 _Hashtable() = default; 395 _Hashtable(size_type __bucket_hint, 396 const _H1&, const _H2&, const _Hash&, 397 const _Equal&, const _ExtractKey&, 398 const allocator_type&); 399 400 template<typename _InputIterator> 401 _Hashtable(_InputIterator __first, _InputIterator __last, 402 size_type __bucket_hint, 403 const _H1&, const _H2&, const _Hash&, 404 const _Equal&, const _ExtractKey&, 405 const allocator_type&); 406 407 _Hashtable(const _Hashtable&); 408 409 _Hashtable(_Hashtable&&) noexcept; 410 411 _Hashtable(const _Hashtable&, const allocator_type&); 412 413 _Hashtable(_Hashtable&&, const allocator_type&); 414 415 // Use delegating constructors. 416 explicit 417 _Hashtable(const allocator_type& __a) 418 : __hashtable_alloc(__node_alloc_type(__a)) 419 { } 420 421 explicit 422 _Hashtable(size_type __n, 423 const _H1& __hf = _H1(), 424 const key_equal& __eql = key_equal(), 425 const allocator_type& __a = allocator_type()) 426 : _Hashtable(__n, __hf, _H2(), _Hash(), __eql, 427 __key_extract(), __a) 428 { } 429 430 template<typename _InputIterator> 431 _Hashtable(_InputIterator __f, _InputIterator __l, 432 size_type __n = 0, 433 const _H1& __hf = _H1(), 434 const key_equal& __eql = key_equal(), 435 const allocator_type& __a = allocator_type()) 436 : _Hashtable(__f, __l, __n, __hf, _H2(), _Hash(), __eql, 437 __key_extract(), __a) 438 { } 439 440 _Hashtable(initializer_list<value_type> __l, 441 size_type __n = 0, 442 const _H1& __hf = _H1(), 443 const key_equal& __eql = key_equal(), 444 const allocator_type& __a = allocator_type()) 445 : _Hashtable(__l.begin(), __l.end(), __n, __hf, _H2(), _Hash(), __eql, 446 __key_extract(), __a) 447 { } 448 449 _Hashtable& 450 operator=(const _Hashtable& __ht); 451 452 _Hashtable& 453 operator=(_Hashtable&& __ht) 454 noexcept(__node_alloc_traits::_S_nothrow_move()) 455 { 456 constexpr bool __move_storage = 457 __node_alloc_traits::_S_propagate_on_move_assign() 458 || __node_alloc_traits::_S_always_equal(); 459 _M_move_assign(std::move(__ht), 460 integral_constant<bool, __move_storage>()); 461 return *this; 462 } 463 464 _Hashtable& 465 operator=(initializer_list<value_type> __l) 466 { 467 __reuse_or_alloc_node_type __roan(_M_begin(), *this); 468 _M_before_begin._M_nxt = nullptr; 469 clear(); 470 this->_M_insert_range(__l.begin(), __l.end(), __roan); 471 return *this; 472 } 473 474 ~_Hashtable() noexcept; 475 476 void 477 swap(_Hashtable&) 478 noexcept(__node_alloc_traits::_S_nothrow_swap()); 479 480 // Basic container operations 481 iterator 482 begin() noexcept 483 { return iterator(_M_begin()); } 484 485 const_iterator 486 begin() const noexcept 487 { return const_iterator(_M_begin()); } 488 489 iterator 490 end() noexcept 491 { return iterator(nullptr); } 492 493 const_iterator 494 end() const noexcept 495 { return const_iterator(nullptr); } 496 497 const_iterator 498 cbegin() const noexcept 499 { return const_iterator(_M_begin()); } 500 501 const_iterator 502 cend() const noexcept 503 { return const_iterator(nullptr); } 504 505 size_type 506 size() const noexcept 507 { return _M_element_count; } 508 509 bool 510 empty() const noexcept 511 { return size() == 0; } 512 513 allocator_type 514 get_allocator() const noexcept 515 { return allocator_type(this->_M_node_allocator()); } 516 517 size_type 518 max_size() const noexcept 519 { return __node_alloc_traits::max_size(this->_M_node_allocator()); } 520 521 // Observers 522 key_equal 523 key_eq() const 524 { return this->_M_eq(); } 525 526 // hash_function, if present, comes from _Hash_code_base. 527 528 // Bucket operations 529 size_type 530 bucket_count() const noexcept 531 { return _M_bucket_count; } 532 533 size_type 534 max_bucket_count() const noexcept 535 { return max_size(); } 536 537 size_type 538 bucket_size(size_type __n) const 539 { return std::distance(begin(__n), end(__n)); } 540 541 size_type 542 bucket(const key_type& __k) const 543 { return _M_bucket_index(__k, this->_M_hash_code(__k)); } 544 545 local_iterator 546 begin(size_type __n) 547 { 548 return local_iterator(*this, _M_bucket_begin(__n), 549 __n, _M_bucket_count); 550 } 551 552 local_iterator 553 end(size_type __n) 554 { return local_iterator(*this, nullptr, __n, _M_bucket_count); } 555 556 const_local_iterator 557 begin(size_type __n) const 558 { 559 return const_local_iterator(*this, _M_bucket_begin(__n), 560 __n, _M_bucket_count); 561 } 562 563 const_local_iterator 564 end(size_type __n) const 565 { return const_local_iterator(*this, nullptr, __n, _M_bucket_count); } 566 567 // DR 691. 568 const_local_iterator 569 cbegin(size_type __n) const 570 { 571 return const_local_iterator(*this, _M_bucket_begin(__n), 572 __n, _M_bucket_count); 573 } 574 575 const_local_iterator 576 cend(size_type __n) const 577 { return const_local_iterator(*this, nullptr, __n, _M_bucket_count); } 578 579 float 580 load_factor() const noexcept 581 { 582 return static_cast<float>(size()) / static_cast<float>(bucket_count()); 583 } 584 585 // max_load_factor, if present, comes from _Rehash_base. 586 587 // Generalization of max_load_factor. Extension, not found in 588 // TR1. Only useful if _RehashPolicy is something other than 589 // the default. 590 const _RehashPolicy& 591 __rehash_policy() const 592 { return _M_rehash_policy; } 593 594 void 595 __rehash_policy(const _RehashPolicy&); 596 597 // Lookup. 598 iterator 599 find(const key_type& __k); 600 601 const_iterator 602 find(const key_type& __k) const; 603 604 size_type 605 count(const key_type& __k) const; 606 607 std::pair<iterator, iterator> 608 equal_range(const key_type& __k); 609 610 std::pair<const_iterator, const_iterator> 611 equal_range(const key_type& __k) const; 612 613 protected: 614 // Bucket index computation helpers. 615 size_type 616 _M_bucket_index(__node_type* __n) const noexcept 617 { return __hash_code_base::_M_bucket_index(__n, _M_bucket_count); } 618 619 size_type 620 _M_bucket_index(const key_type& __k, __hash_code __c) const 621 { return __hash_code_base::_M_bucket_index(__k, __c, _M_bucket_count); } 622 623 // Find and insert helper functions and types 624 // Find the node before the one matching the criteria. 625 __node_base* 626 _M_find_before_node(size_type, const key_type&, __hash_code) const; 627 628 __node_type* 629 _M_find_node(size_type __bkt, const key_type& __key, 630 __hash_code __c) const 631 { 632 __node_base* __before_n = _M_find_before_node(__bkt, __key, __c); 633 if (__before_n) 634 return static_cast<__node_type*>(__before_n->_M_nxt); 635 return nullptr; 636 } 637 638 // Insert a node at the beginning of a bucket. 639 void 640 _M_insert_bucket_begin(size_type, __node_type*); 641 642 // Remove the bucket first node 643 void 644 _M_remove_bucket_begin(size_type __bkt, __node_type* __next_n, 645 size_type __next_bkt); 646 647 // Get the node before __n in the bucket __bkt 648 __node_base* 649 _M_get_previous_node(size_type __bkt, __node_base* __n); 650 651 // Insert node with hash code __code, in bucket bkt if no rehash (assumes 652 // no element with its key already present). Take ownership of the node, 653 // deallocate it on exception. 654 iterator 655 _M_insert_unique_node(size_type __bkt, __hash_code __code, 656 __node_type* __n); 657 658 // Insert node with hash code __code. Take ownership of the node, 659 // deallocate it on exception. 660 iterator 661 _M_insert_multi_node(__node_type* __hint, 662 __hash_code __code, __node_type* __n); 663 664 template<typename... _Args> 665 std::pair<iterator, bool> 666 _M_emplace(std::true_type, _Args&&... __args); 667 668 template<typename... _Args> 669 iterator 670 _M_emplace(std::false_type __uk, _Args&&... __args) 671 { return _M_emplace(cend(), __uk, std::forward<_Args>(__args)...); } 672 673 // Emplace with hint, useless when keys are unique. 674 template<typename... _Args> 675 iterator 676 _M_emplace(const_iterator, std::true_type __uk, _Args&&... __args) 677 { return _M_emplace(__uk, std::forward<_Args>(__args)...).first; } 678 679 template<typename... _Args> 680 iterator 681 _M_emplace(const_iterator, std::false_type, _Args&&... __args); 682 683 template<typename _Arg, typename _NodeGenerator> 684 std::pair<iterator, bool> 685 _M_insert(_Arg&&, const _NodeGenerator&, std::true_type); 686 687 template<typename _Arg, typename _NodeGenerator> 688 iterator 689 _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen, 690 std::false_type __uk) 691 { 692 return _M_insert(cend(), std::forward<_Arg>(__arg), __node_gen, 693 __uk); 694 } 695 696 // Insert with hint, not used when keys are unique. 697 template<typename _Arg, typename _NodeGenerator> 698 iterator 699 _M_insert(const_iterator, _Arg&& __arg, 700 const _NodeGenerator& __node_gen, std::true_type __uk) 701 { 702 return 703 _M_insert(std::forward<_Arg>(__arg), __node_gen, __uk).first; 704 } 705 706 // Insert with hint when keys are not unique. 707 template<typename _Arg, typename _NodeGenerator> 708 iterator 709 _M_insert(const_iterator, _Arg&&, 710 const _NodeGenerator&, std::false_type); 711 712 size_type 713 _M_erase(std::true_type, const key_type&); 714 715 size_type 716 _M_erase(std::false_type, const key_type&); 717 718 iterator 719 _M_erase(size_type __bkt, __node_base* __prev_n, __node_type* __n); 720 721 public: 722 // Emplace 723 template<typename... _Args> 724 __ireturn_type 725 emplace(_Args&&... __args) 726 { return _M_emplace(__unique_keys(), std::forward<_Args>(__args)...); } 727 728 template<typename... _Args> 729 iterator 730 emplace_hint(const_iterator __hint, _Args&&... __args) 731 { 732 return _M_emplace(__hint, __unique_keys(), 733 std::forward<_Args>(__args)...); 734 } 735 736 // Insert member functions via inheritance. 737 738 // Erase 739 iterator 740 erase(const_iterator); 741 742 // LWG 2059. 743 iterator 744 erase(iterator __it) 745 { return erase(const_iterator(__it)); } 746 747 size_type 748 erase(const key_type& __k) 749 { return _M_erase(__unique_keys(), __k); } 750 751 iterator 752 erase(const_iterator, const_iterator); 753 754 void 755 clear() noexcept; 756 757 // Set number of buckets to be appropriate for container of n element. 758 void rehash(size_type __n); 759 760 // DR 1189. 761 // reserve, if present, comes from _Rehash_base. 762 763 private: 764 // Helper rehash method used when keys are unique. 765 void _M_rehash_aux(size_type __n, std::true_type); 766 767 // Helper rehash method used when keys can be non-unique. 768 void _M_rehash_aux(size_type __n, std::false_type); 769 770 // Unconditionally change size of bucket array to n, restore 771 // hash policy state to __state on exception. 772 void _M_rehash(size_type __n, const __rehash_state& __state); 773 }; 774 775 776 // Definitions of class template _Hashtable's out-of-line member functions. 777 template<typename _Key, typename _Value, 778 typename _Alloc, typename _ExtractKey, typename _Equal, 779 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 780 typename _Traits> 781 auto 782 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 783 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 784 _M_bucket_begin(size_type __bkt) const 785 -> __node_type* 786 { 787 __node_base* __n = _M_buckets[__bkt]; 788 return __n ? static_cast<__node_type*>(__n->_M_nxt) : nullptr; 789 } 790 791 template<typename _Key, typename _Value, 792 typename _Alloc, typename _ExtractKey, typename _Equal, 793 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 794 typename _Traits> 795 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 796 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 797 _Hashtable(size_type __bucket_hint, 798 const _H1& __h1, const _H2& __h2, const _Hash& __h, 799 const _Equal& __eq, const _ExtractKey& __exk, 800 const allocator_type& __a) 801 : _Hashtable(__h1, __h2, __h, __eq, __exk, __a) 802 { 803 auto __bkt = _M_rehash_policy._M_next_bkt(__bucket_hint); 804 if (__bkt > _M_bucket_count) 805 { 806 _M_buckets = _M_allocate_buckets(__bkt); 807 _M_bucket_count = __bkt; 808 } 809 } 810 811 template<typename _Key, typename _Value, 812 typename _Alloc, typename _ExtractKey, typename _Equal, 813 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 814 typename _Traits> 815 template<typename _InputIterator> 816 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 817 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 818 _Hashtable(_InputIterator __f, _InputIterator __l, 819 size_type __bucket_hint, 820 const _H1& __h1, const _H2& __h2, const _Hash& __h, 821 const _Equal& __eq, const _ExtractKey& __exk, 822 const allocator_type& __a) 823 : _Hashtable(__h1, __h2, __h, __eq, __exk, __a) 824 { 825 auto __nb_elems = __detail::__distance_fw(__f, __l); 826 auto __bkt_count = 827 _M_rehash_policy._M_next_bkt( 828 std::max(_M_rehash_policy._M_bkt_for_elements(__nb_elems), 829 __bucket_hint)); 830 831 if (__bkt_count > _M_bucket_count) 832 { 833 _M_buckets = _M_allocate_buckets(__bkt_count); 834 _M_bucket_count = __bkt_count; 835 } 836 837 for (; __f != __l; ++__f) 838 this->insert(*__f); 839 } 840 841 template<typename _Key, typename _Value, 842 typename _Alloc, typename _ExtractKey, typename _Equal, 843 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 844 typename _Traits> 845 auto 846 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 847 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 848 operator=(const _Hashtable& __ht) 849 -> _Hashtable& 850 { 851 if (&__ht == this) 852 return *this; 853 854 if (__node_alloc_traits::_S_propagate_on_copy_assign()) 855 { 856 auto& __this_alloc = this->_M_node_allocator(); 857 auto& __that_alloc = __ht._M_node_allocator(); 858 if (!__node_alloc_traits::_S_always_equal() 859 && __this_alloc != __that_alloc) 860 { 861 // Replacement allocator cannot free existing storage. 862 this->_M_deallocate_nodes(_M_begin()); 863 _M_before_begin._M_nxt = nullptr; 864 _M_deallocate_buckets(); 865 _M_buckets = nullptr; 866 std::__alloc_on_copy(__this_alloc, __that_alloc); 867 __hashtable_base::operator=(__ht); 868 _M_bucket_count = __ht._M_bucket_count; 869 _M_element_count = __ht._M_element_count; 870 _M_rehash_policy = __ht._M_rehash_policy; 871 __try 872 { 873 _M_assign(__ht, 874 [this](const __node_type* __n) 875 { return this->_M_allocate_node(__n->_M_v()); }); 876 } 877 __catch(...) 878 { 879 // _M_assign took care of deallocating all memory. Now we 880 // must make sure this instance remains in a usable state. 881 _M_reset(); 882 __throw_exception_again; 883 } 884 return *this; 885 } 886 std::__alloc_on_copy(__this_alloc, __that_alloc); 887 } 888 889 // Reuse allocated buckets and nodes. 890 __bucket_type* __former_buckets = nullptr; 891 std::size_t __former_bucket_count = _M_bucket_count; 892 const __rehash_state& __former_state = _M_rehash_policy._M_state(); 893 894 if (_M_bucket_count != __ht._M_bucket_count) 895 { 896 __former_buckets = _M_buckets; 897 _M_buckets = _M_allocate_buckets(__ht._M_bucket_count); 898 _M_bucket_count = __ht._M_bucket_count; 899 } 900 else 901 __builtin_memset(_M_buckets, 0, 902 _M_bucket_count * sizeof(__bucket_type)); 903 904 __try 905 { 906 __hashtable_base::operator=(__ht); 907 _M_element_count = __ht._M_element_count; 908 _M_rehash_policy = __ht._M_rehash_policy; 909 __reuse_or_alloc_node_type __roan(_M_begin(), *this); 910 _M_before_begin._M_nxt = nullptr; 911 _M_assign(__ht, 912 [&__roan](const __node_type* __n) 913 { return __roan(__n->_M_v()); }); 914 if (__former_buckets) 915 _M_deallocate_buckets(__former_buckets, __former_bucket_count); 916 } 917 __catch(...) 918 { 919 if (__former_buckets) 920 { 921 // Restore previous buckets. 922 _M_deallocate_buckets(); 923 _M_rehash_policy._M_reset(__former_state); 924 _M_buckets = __former_buckets; 925 _M_bucket_count = __former_bucket_count; 926 } 927 __builtin_memset(_M_buckets, 0, 928 _M_bucket_count * sizeof(__bucket_type)); 929 __throw_exception_again; 930 } 931 return *this; 932 } 933 934 template<typename _Key, typename _Value, 935 typename _Alloc, typename _ExtractKey, typename _Equal, 936 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 937 typename _Traits> 938 template<typename _NodeGenerator> 939 void 940 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 941 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 942 _M_assign(const _Hashtable& __ht, const _NodeGenerator& __node_gen) 943 { 944 __bucket_type* __buckets = nullptr; 945 if (!_M_buckets) 946 _M_buckets = __buckets = _M_allocate_buckets(_M_bucket_count); 947 948 __try 949 { 950 if (!__ht._M_before_begin._M_nxt) 951 return; 952 953 // First deal with the special first node pointed to by 954 // _M_before_begin. 955 __node_type* __ht_n = __ht._M_begin(); 956 __node_type* __this_n = __node_gen(__ht_n); 957 this->_M_copy_code(__this_n, __ht_n); 958 _M_before_begin._M_nxt = __this_n; 959 _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin; 960 961 // Then deal with other nodes. 962 __node_base* __prev_n = __this_n; 963 for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next()) 964 { 965 __this_n = __node_gen(__ht_n); 966 __prev_n->_M_nxt = __this_n; 967 this->_M_copy_code(__this_n, __ht_n); 968 size_type __bkt = _M_bucket_index(__this_n); 969 if (!_M_buckets[__bkt]) 970 _M_buckets[__bkt] = __prev_n; 971 __prev_n = __this_n; 972 } 973 } 974 __catch(...) 975 { 976 clear(); 977 if (__buckets) 978 _M_deallocate_buckets(); 979 __throw_exception_again; 980 } 981 } 982 983 template<typename _Key, typename _Value, 984 typename _Alloc, typename _ExtractKey, typename _Equal, 985 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 986 typename _Traits> 987 void 988 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 989 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 990 _M_reset() noexcept 991 { 992 _M_rehash_policy._M_reset(); 993 _M_bucket_count = 1; 994 _M_single_bucket = nullptr; 995 _M_buckets = &_M_single_bucket; 996 _M_before_begin._M_nxt = nullptr; 997 _M_element_count = 0; 998 } 999 1000 template<typename _Key, typename _Value, 1001 typename _Alloc, typename _ExtractKey, typename _Equal, 1002 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1003 typename _Traits> 1004 void 1005 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1006 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1007 _M_move_assign(_Hashtable&& __ht, std::true_type) 1008 { 1009 this->_M_deallocate_nodes(_M_begin()); 1010 _M_deallocate_buckets(); 1011 __hashtable_base::operator=(std::move(__ht)); 1012 _M_rehash_policy = __ht._M_rehash_policy; 1013 if (!__ht._M_uses_single_bucket()) 1014 _M_buckets = __ht._M_buckets; 1015 else 1016 { 1017 _M_buckets = &_M_single_bucket; 1018 _M_single_bucket = __ht._M_single_bucket; 1019 } 1020 _M_bucket_count = __ht._M_bucket_count; 1021 _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt; 1022 _M_element_count = __ht._M_element_count; 1023 std::__alloc_on_move(this->_M_node_allocator(), __ht._M_node_allocator()); 1024 1025 // Fix buckets containing the _M_before_begin pointers that can't be 1026 // moved. 1027 if (_M_begin()) 1028 _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 1029 __ht._M_reset(); 1030 } 1031 1032 template<typename _Key, typename _Value, 1033 typename _Alloc, typename _ExtractKey, typename _Equal, 1034 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1035 typename _Traits> 1036 void 1037 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1038 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1039 _M_move_assign(_Hashtable&& __ht, std::false_type) 1040 { 1041 if (__ht._M_node_allocator() == this->_M_node_allocator()) 1042 _M_move_assign(std::move(__ht), std::true_type()); 1043 else 1044 { 1045 // Can't move memory, move elements then. 1046 __bucket_type* __former_buckets = nullptr; 1047 size_type __former_bucket_count = _M_bucket_count; 1048 const __rehash_state& __former_state = _M_rehash_policy._M_state(); 1049 1050 if (_M_bucket_count != __ht._M_bucket_count) 1051 { 1052 __former_buckets = _M_buckets; 1053 _M_buckets = _M_allocate_buckets(__ht._M_bucket_count); 1054 _M_bucket_count = __ht._M_bucket_count; 1055 } 1056 else 1057 __builtin_memset(_M_buckets, 0, 1058 _M_bucket_count * sizeof(__bucket_type)); 1059 1060 __try 1061 { 1062 __hashtable_base::operator=(std::move(__ht)); 1063 _M_element_count = __ht._M_element_count; 1064 _M_rehash_policy = __ht._M_rehash_policy; 1065 __reuse_or_alloc_node_type __roan(_M_begin(), *this); 1066 _M_before_begin._M_nxt = nullptr; 1067 _M_assign(__ht, 1068 [&__roan](__node_type* __n) 1069 { return __roan(std::move_if_noexcept(__n->_M_v())); }); 1070 __ht.clear(); 1071 } 1072 __catch(...) 1073 { 1074 if (__former_buckets) 1075 { 1076 _M_deallocate_buckets(); 1077 _M_rehash_policy._M_reset(__former_state); 1078 _M_buckets = __former_buckets; 1079 _M_bucket_count = __former_bucket_count; 1080 } 1081 __builtin_memset(_M_buckets, 0, 1082 _M_bucket_count * sizeof(__bucket_type)); 1083 __throw_exception_again; 1084 } 1085 } 1086 } 1087 1088 template<typename _Key, typename _Value, 1089 typename _Alloc, typename _ExtractKey, typename _Equal, 1090 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1091 typename _Traits> 1092 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1093 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1094 _Hashtable(const _Hashtable& __ht) 1095 : __hashtable_base(__ht), 1096 __map_base(__ht), 1097 __rehash_base(__ht), 1098 __hashtable_alloc( 1099 __node_alloc_traits::_S_select_on_copy(__ht._M_node_allocator())), 1100 _M_buckets(nullptr), 1101 _M_bucket_count(__ht._M_bucket_count), 1102 _M_element_count(__ht._M_element_count), 1103 _M_rehash_policy(__ht._M_rehash_policy) 1104 { 1105 _M_assign(__ht, 1106 [this](const __node_type* __n) 1107 { return this->_M_allocate_node(__n->_M_v()); }); 1108 } 1109 1110 template<typename _Key, typename _Value, 1111 typename _Alloc, typename _ExtractKey, typename _Equal, 1112 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1113 typename _Traits> 1114 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1115 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1116 _Hashtable(_Hashtable&& __ht) noexcept 1117 : __hashtable_base(__ht), 1118 __map_base(__ht), 1119 __rehash_base(__ht), 1120 __hashtable_alloc(std::move(__ht._M_base_alloc())), 1121 _M_buckets(__ht._M_buckets), 1122 _M_bucket_count(__ht._M_bucket_count), 1123 _M_before_begin(__ht._M_before_begin._M_nxt), 1124 _M_element_count(__ht._M_element_count), 1125 _M_rehash_policy(__ht._M_rehash_policy) 1126 { 1127 // Update, if necessary, buckets if __ht is using its single bucket. 1128 if (__ht._M_uses_single_bucket()) 1129 { 1130 _M_buckets = &_M_single_bucket; 1131 _M_single_bucket = __ht._M_single_bucket; 1132 } 1133 1134 // Update, if necessary, bucket pointing to before begin that hasn't 1135 // moved. 1136 if (_M_begin()) 1137 _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 1138 1139 __ht._M_reset(); 1140 } 1141 1142 template<typename _Key, typename _Value, 1143 typename _Alloc, typename _ExtractKey, typename _Equal, 1144 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1145 typename _Traits> 1146 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1147 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1148 _Hashtable(const _Hashtable& __ht, const allocator_type& __a) 1149 : __hashtable_base(__ht), 1150 __map_base(__ht), 1151 __rehash_base(__ht), 1152 __hashtable_alloc(__node_alloc_type(__a)), 1153 _M_buckets(), 1154 _M_bucket_count(__ht._M_bucket_count), 1155 _M_element_count(__ht._M_element_count), 1156 _M_rehash_policy(__ht._M_rehash_policy) 1157 { 1158 _M_assign(__ht, 1159 [this](const __node_type* __n) 1160 { return this->_M_allocate_node(__n->_M_v()); }); 1161 } 1162 1163 template<typename _Key, typename _Value, 1164 typename _Alloc, typename _ExtractKey, typename _Equal, 1165 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1166 typename _Traits> 1167 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1168 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1169 _Hashtable(_Hashtable&& __ht, const allocator_type& __a) 1170 : __hashtable_base(__ht), 1171 __map_base(__ht), 1172 __rehash_base(__ht), 1173 __hashtable_alloc(__node_alloc_type(__a)), 1174 _M_buckets(nullptr), 1175 _M_bucket_count(__ht._M_bucket_count), 1176 _M_element_count(__ht._M_element_count), 1177 _M_rehash_policy(__ht._M_rehash_policy) 1178 { 1179 if (__ht._M_node_allocator() == this->_M_node_allocator()) 1180 { 1181 if (__ht._M_uses_single_bucket()) 1182 { 1183 _M_buckets = &_M_single_bucket; 1184 _M_single_bucket = __ht._M_single_bucket; 1185 } 1186 else 1187 _M_buckets = __ht._M_buckets; 1188 1189 _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt; 1190 // Update, if necessary, bucket pointing to before begin that hasn't 1191 // moved. 1192 if (_M_begin()) 1193 _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 1194 __ht._M_reset(); 1195 } 1196 else 1197 { 1198 _M_assign(__ht, 1199 [this](__node_type* __n) 1200 { 1201 return this->_M_allocate_node( 1202 std::move_if_noexcept(__n->_M_v())); 1203 }); 1204 __ht.clear(); 1205 } 1206 } 1207 1208 template<typename _Key, typename _Value, 1209 typename _Alloc, typename _ExtractKey, typename _Equal, 1210 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1211 typename _Traits> 1212 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1213 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1214 ~_Hashtable() noexcept 1215 { 1216 clear(); 1217 _M_deallocate_buckets(); 1218 } 1219 1220 template<typename _Key, typename _Value, 1221 typename _Alloc, typename _ExtractKey, typename _Equal, 1222 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1223 typename _Traits> 1224 void 1225 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1226 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1227 swap(_Hashtable& __x) 1228 noexcept(__node_alloc_traits::_S_nothrow_swap()) 1229 { 1230 // The only base class with member variables is hash_code_base. 1231 // We define _Hash_code_base::_M_swap because different 1232 // specializations have different members. 1233 this->_M_swap(__x); 1234 1235 std::__alloc_on_swap(this->_M_node_allocator(), __x._M_node_allocator()); 1236 std::swap(_M_rehash_policy, __x._M_rehash_policy); 1237 1238 // Deal properly with potentially moved instances. 1239 if (this->_M_uses_single_bucket()) 1240 { 1241 if (!__x._M_uses_single_bucket()) 1242 { 1243 _M_buckets = __x._M_buckets; 1244 __x._M_buckets = &__x._M_single_bucket; 1245 } 1246 } 1247 else if (__x._M_uses_single_bucket()) 1248 { 1249 __x._M_buckets = _M_buckets; 1250 _M_buckets = &_M_single_bucket; 1251 } 1252 else 1253 std::swap(_M_buckets, __x._M_buckets); 1254 1255 std::swap(_M_bucket_count, __x._M_bucket_count); 1256 std::swap(_M_before_begin._M_nxt, __x._M_before_begin._M_nxt); 1257 std::swap(_M_element_count, __x._M_element_count); 1258 std::swap(_M_single_bucket, __x._M_single_bucket); 1259 1260 // Fix buckets containing the _M_before_begin pointers that can't be 1261 // swapped. 1262 if (_M_begin()) 1263 _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 1264 1265 if (__x._M_begin()) 1266 __x._M_buckets[__x._M_bucket_index(__x._M_begin())] 1267 = &__x._M_before_begin; 1268 } 1269 1270 template<typename _Key, typename _Value, 1271 typename _Alloc, typename _ExtractKey, typename _Equal, 1272 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1273 typename _Traits> 1274 void 1275 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1276 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1277 __rehash_policy(const _RehashPolicy& __pol) 1278 { 1279 auto __do_rehash = 1280 __pol._M_need_rehash(_M_bucket_count, _M_element_count, 0); 1281 if (__do_rehash.first) 1282 _M_rehash(__do_rehash.second, _M_rehash_policy._M_state()); 1283 _M_rehash_policy = __pol; 1284 } 1285 1286 template<typename _Key, typename _Value, 1287 typename _Alloc, typename _ExtractKey, typename _Equal, 1288 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1289 typename _Traits> 1290 auto 1291 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1292 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1293 find(const key_type& __k) 1294 -> iterator 1295 { 1296 __hash_code __code = this->_M_hash_code(__k); 1297 std::size_t __n = _M_bucket_index(__k, __code); 1298 __node_type* __p = _M_find_node(__n, __k, __code); 1299 return __p ? iterator(__p) : end(); 1300 } 1301 1302 template<typename _Key, typename _Value, 1303 typename _Alloc, typename _ExtractKey, typename _Equal, 1304 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1305 typename _Traits> 1306 auto 1307 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1308 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1309 find(const key_type& __k) const 1310 -> const_iterator 1311 { 1312 __hash_code __code = this->_M_hash_code(__k); 1313 std::size_t __n = _M_bucket_index(__k, __code); 1314 __node_type* __p = _M_find_node(__n, __k, __code); 1315 return __p ? const_iterator(__p) : end(); 1316 } 1317 1318 template<typename _Key, typename _Value, 1319 typename _Alloc, typename _ExtractKey, typename _Equal, 1320 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1321 typename _Traits> 1322 auto 1323 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1324 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1325 count(const key_type& __k) const 1326 -> size_type 1327 { 1328 __hash_code __code = this->_M_hash_code(__k); 1329 std::size_t __n = _M_bucket_index(__k, __code); 1330 __node_type* __p = _M_bucket_begin(__n); 1331 if (!__p) 1332 return 0; 1333 1334 std::size_t __result = 0; 1335 for (;; __p = __p->_M_next()) 1336 { 1337 if (this->_M_equals(__k, __code, __p)) 1338 ++__result; 1339 else if (__result) 1340 // All equivalent values are next to each other, if we 1341 // found a non-equivalent value after an equivalent one it 1342 // means that we won't find any new equivalent value. 1343 break; 1344 if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n) 1345 break; 1346 } 1347 return __result; 1348 } 1349 1350 template<typename _Key, typename _Value, 1351 typename _Alloc, typename _ExtractKey, typename _Equal, 1352 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1353 typename _Traits> 1354 auto 1355 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1356 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1357 equal_range(const key_type& __k) 1358 -> pair<iterator, iterator> 1359 { 1360 __hash_code __code = this->_M_hash_code(__k); 1361 std::size_t __n = _M_bucket_index(__k, __code); 1362 __node_type* __p = _M_find_node(__n, __k, __code); 1363 1364 if (__p) 1365 { 1366 __node_type* __p1 = __p->_M_next(); 1367 while (__p1 && _M_bucket_index(__p1) == __n 1368 && this->_M_equals(__k, __code, __p1)) 1369 __p1 = __p1->_M_next(); 1370 1371 return std::make_pair(iterator(__p), iterator(__p1)); 1372 } 1373 else 1374 return std::make_pair(end(), end()); 1375 } 1376 1377 template<typename _Key, typename _Value, 1378 typename _Alloc, typename _ExtractKey, typename _Equal, 1379 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1380 typename _Traits> 1381 auto 1382 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1383 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1384 equal_range(const key_type& __k) const 1385 -> pair<const_iterator, const_iterator> 1386 { 1387 __hash_code __code = this->_M_hash_code(__k); 1388 std::size_t __n = _M_bucket_index(__k, __code); 1389 __node_type* __p = _M_find_node(__n, __k, __code); 1390 1391 if (__p) 1392 { 1393 __node_type* __p1 = __p->_M_next(); 1394 while (__p1 && _M_bucket_index(__p1) == __n 1395 && this->_M_equals(__k, __code, __p1)) 1396 __p1 = __p1->_M_next(); 1397 1398 return std::make_pair(const_iterator(__p), const_iterator(__p1)); 1399 } 1400 else 1401 return std::make_pair(end(), end()); 1402 } 1403 1404 // Find the node whose key compares equal to k in the bucket n. 1405 // Return nullptr if no node is found. 1406 template<typename _Key, typename _Value, 1407 typename _Alloc, typename _ExtractKey, typename _Equal, 1408 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1409 typename _Traits> 1410 auto 1411 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1412 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1413 _M_find_before_node(size_type __n, const key_type& __k, 1414 __hash_code __code) const 1415 -> __node_base* 1416 { 1417 __node_base* __prev_p = _M_buckets[__n]; 1418 if (!__prev_p) 1419 return nullptr; 1420 1421 for (__node_type* __p = static_cast<__node_type*>(__prev_p->_M_nxt);; 1422 __p = __p->_M_next()) 1423 { 1424 if (this->_M_equals(__k, __code, __p)) 1425 return __prev_p; 1426 1427 if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n) 1428 break; 1429 __prev_p = __p; 1430 } 1431 return nullptr; 1432 } 1433 1434 template<typename _Key, typename _Value, 1435 typename _Alloc, typename _ExtractKey, typename _Equal, 1436 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1437 typename _Traits> 1438 void 1439 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1440 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1441 _M_insert_bucket_begin(size_type __bkt, __node_type* __node) 1442 { 1443 if (_M_buckets[__bkt]) 1444 { 1445 // Bucket is not empty, we just need to insert the new node 1446 // after the bucket before begin. 1447 __node->_M_nxt = _M_buckets[__bkt]->_M_nxt; 1448 _M_buckets[__bkt]->_M_nxt = __node; 1449 } 1450 else 1451 { 1452 // The bucket is empty, the new node is inserted at the 1453 // beginning of the singly-linked list and the bucket will 1454 // contain _M_before_begin pointer. 1455 __node->_M_nxt = _M_before_begin._M_nxt; 1456 _M_before_begin._M_nxt = __node; 1457 if (__node->_M_nxt) 1458 // We must update former begin bucket that is pointing to 1459 // _M_before_begin. 1460 _M_buckets[_M_bucket_index(__node->_M_next())] = __node; 1461 _M_buckets[__bkt] = &_M_before_begin; 1462 } 1463 } 1464 1465 template<typename _Key, typename _Value, 1466 typename _Alloc, typename _ExtractKey, typename _Equal, 1467 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1468 typename _Traits> 1469 void 1470 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1471 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1472 _M_remove_bucket_begin(size_type __bkt, __node_type* __next, 1473 size_type __next_bkt) 1474 { 1475 if (!__next || __next_bkt != __bkt) 1476 { 1477 // Bucket is now empty 1478 // First update next bucket if any 1479 if (__next) 1480 _M_buckets[__next_bkt] = _M_buckets[__bkt]; 1481 1482 // Second update before begin node if necessary 1483 if (&_M_before_begin == _M_buckets[__bkt]) 1484 _M_before_begin._M_nxt = __next; 1485 _M_buckets[__bkt] = nullptr; 1486 } 1487 } 1488 1489 template<typename _Key, typename _Value, 1490 typename _Alloc, typename _ExtractKey, typename _Equal, 1491 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1492 typename _Traits> 1493 auto 1494 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1495 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1496 _M_get_previous_node(size_type __bkt, __node_base* __n) 1497 -> __node_base* 1498 { 1499 __node_base* __prev_n = _M_buckets[__bkt]; 1500 while (__prev_n->_M_nxt != __n) 1501 __prev_n = __prev_n->_M_nxt; 1502 return __prev_n; 1503 } 1504 1505 template<typename _Key, typename _Value, 1506 typename _Alloc, typename _ExtractKey, typename _Equal, 1507 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1508 typename _Traits> 1509 template<typename... _Args> 1510 auto 1511 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1512 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1513 _M_emplace(std::true_type, _Args&&... __args) 1514 -> pair<iterator, bool> 1515 { 1516 // First build the node to get access to the hash code 1517 __node_type* __node = this->_M_allocate_node(std::forward<_Args>(__args)...); 1518 const key_type& __k = this->_M_extract()(__node->_M_v()); 1519 __hash_code __code; 1520 __try 1521 { 1522 __code = this->_M_hash_code(__k); 1523 } 1524 __catch(...) 1525 { 1526 this->_M_deallocate_node(__node); 1527 __throw_exception_again; 1528 } 1529 1530 size_type __bkt = _M_bucket_index(__k, __code); 1531 if (__node_type* __p = _M_find_node(__bkt, __k, __code)) 1532 { 1533 // There is already an equivalent node, no insertion 1534 this->_M_deallocate_node(__node); 1535 return std::make_pair(iterator(__p), false); 1536 } 1537 1538 // Insert the node 1539 return std::make_pair(_M_insert_unique_node(__bkt, __code, __node), 1540 true); 1541 } 1542 1543 template<typename _Key, typename _Value, 1544 typename _Alloc, typename _ExtractKey, typename _Equal, 1545 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1546 typename _Traits> 1547 template<typename... _Args> 1548 auto 1549 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1550 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1551 _M_emplace(const_iterator __hint, std::false_type, _Args&&... __args) 1552 -> iterator 1553 { 1554 // First build the node to get its hash code. 1555 __node_type* __node = 1556 this->_M_allocate_node(std::forward<_Args>(__args)...); 1557 1558 __hash_code __code; 1559 __try 1560 { 1561 __code = this->_M_hash_code(this->_M_extract()(__node->_M_v())); 1562 } 1563 __catch(...) 1564 { 1565 this->_M_deallocate_node(__node); 1566 __throw_exception_again; 1567 } 1568 1569 return _M_insert_multi_node(__hint._M_cur, __code, __node); 1570 } 1571 1572 template<typename _Key, typename _Value, 1573 typename _Alloc, typename _ExtractKey, typename _Equal, 1574 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1575 typename _Traits> 1576 auto 1577 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1578 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1579 _M_insert_unique_node(size_type __bkt, __hash_code __code, 1580 __node_type* __node) 1581 -> iterator 1582 { 1583 const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 1584 std::pair<bool, std::size_t> __do_rehash 1585 = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1); 1586 1587 __try 1588 { 1589 if (__do_rehash.first) 1590 { 1591 _M_rehash(__do_rehash.second, __saved_state); 1592 __bkt = _M_bucket_index(this->_M_extract()(__node->_M_v()), __code); 1593 } 1594 1595 this->_M_store_code(__node, __code); 1596 1597 // Always insert at the beginning of the bucket. 1598 _M_insert_bucket_begin(__bkt, __node); 1599 ++_M_element_count; 1600 return iterator(__node); 1601 } 1602 __catch(...) 1603 { 1604 this->_M_deallocate_node(__node); 1605 __throw_exception_again; 1606 } 1607 } 1608 1609 // Insert node, in bucket bkt if no rehash (assumes no element with its key 1610 // already present). Take ownership of the node, deallocate it on exception. 1611 template<typename _Key, typename _Value, 1612 typename _Alloc, typename _ExtractKey, typename _Equal, 1613 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1614 typename _Traits> 1615 auto 1616 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1617 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1618 _M_insert_multi_node(__node_type* __hint, __hash_code __code, 1619 __node_type* __node) 1620 -> iterator 1621 { 1622 const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 1623 std::pair<bool, std::size_t> __do_rehash 1624 = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1); 1625 1626 __try 1627 { 1628 if (__do_rehash.first) 1629 _M_rehash(__do_rehash.second, __saved_state); 1630 1631 this->_M_store_code(__node, __code); 1632 const key_type& __k = this->_M_extract()(__node->_M_v()); 1633 size_type __bkt = _M_bucket_index(__k, __code); 1634 1635 // Find the node before an equivalent one or use hint if it exists and 1636 // if it is equivalent. 1637 __node_base* __prev 1638 = __builtin_expect(__hint != nullptr, false) 1639 && this->_M_equals(__k, __code, __hint) 1640 ? __hint 1641 : _M_find_before_node(__bkt, __k, __code); 1642 if (__prev) 1643 { 1644 // Insert after the node before the equivalent one. 1645 __node->_M_nxt = __prev->_M_nxt; 1646 __prev->_M_nxt = __node; 1647 if (__builtin_expect(__prev == __hint, false)) 1648 // hint might be the last bucket node, in this case we need to 1649 // update next bucket. 1650 if (__node->_M_nxt 1651 && !this->_M_equals(__k, __code, __node->_M_next())) 1652 { 1653 size_type __next_bkt = _M_bucket_index(__node->_M_next()); 1654 if (__next_bkt != __bkt) 1655 _M_buckets[__next_bkt] = __node; 1656 } 1657 } 1658 else 1659 // The inserted node has no equivalent in the 1660 // hashtable. We must insert the new node at the 1661 // beginning of the bucket to preserve equivalent 1662 // elements' relative positions. 1663 _M_insert_bucket_begin(__bkt, __node); 1664 ++_M_element_count; 1665 return iterator(__node); 1666 } 1667 __catch(...) 1668 { 1669 this->_M_deallocate_node(__node); 1670 __throw_exception_again; 1671 } 1672 } 1673 1674 // Insert v if no element with its key is already present. 1675 template<typename _Key, typename _Value, 1676 typename _Alloc, typename _ExtractKey, typename _Equal, 1677 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1678 typename _Traits> 1679 template<typename _Arg, typename _NodeGenerator> 1680 auto 1681 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1682 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1683 _M_insert(_Arg&& __v, const _NodeGenerator& __node_gen, std::true_type) 1684 -> pair<iterator, bool> 1685 { 1686 const key_type& __k = this->_M_extract()(__v); 1687 __hash_code __code = this->_M_hash_code(__k); 1688 size_type __bkt = _M_bucket_index(__k, __code); 1689 1690 __node_type* __n = _M_find_node(__bkt, __k, __code); 1691 if (__n) 1692 return std::make_pair(iterator(__n), false); 1693 1694 __n = __node_gen(std::forward<_Arg>(__v)); 1695 return std::make_pair(_M_insert_unique_node(__bkt, __code, __n), true); 1696 } 1697 1698 // Insert v unconditionally. 1699 template<typename _Key, typename _Value, 1700 typename _Alloc, typename _ExtractKey, typename _Equal, 1701 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1702 typename _Traits> 1703 template<typename _Arg, typename _NodeGenerator> 1704 auto 1705 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1706 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1707 _M_insert(const_iterator __hint, _Arg&& __v, 1708 const _NodeGenerator& __node_gen, std::false_type) 1709 -> iterator 1710 { 1711 // First compute the hash code so that we don't do anything if it 1712 // throws. 1713 __hash_code __code = this->_M_hash_code(this->_M_extract()(__v)); 1714 1715 // Second allocate new node so that we don't rehash if it throws. 1716 __node_type* __node = __node_gen(std::forward<_Arg>(__v)); 1717 1718 return _M_insert_multi_node(__hint._M_cur, __code, __node); 1719 } 1720 1721 template<typename _Key, typename _Value, 1722 typename _Alloc, typename _ExtractKey, typename _Equal, 1723 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1724 typename _Traits> 1725 auto 1726 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1727 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1728 erase(const_iterator __it) 1729 -> iterator 1730 { 1731 __node_type* __n = __it._M_cur; 1732 std::size_t __bkt = _M_bucket_index(__n); 1733 1734 // Look for previous node to unlink it from the erased one, this 1735 // is why we need buckets to contain the before begin to make 1736 // this search fast. 1737 __node_base* __prev_n = _M_get_previous_node(__bkt, __n); 1738 return _M_erase(__bkt, __prev_n, __n); 1739 } 1740 1741 template<typename _Key, typename _Value, 1742 typename _Alloc, typename _ExtractKey, typename _Equal, 1743 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1744 typename _Traits> 1745 auto 1746 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1747 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1748 _M_erase(size_type __bkt, __node_base* __prev_n, __node_type* __n) 1749 -> iterator 1750 { 1751 if (__prev_n == _M_buckets[__bkt]) 1752 _M_remove_bucket_begin(__bkt, __n->_M_next(), 1753 __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0); 1754 else if (__n->_M_nxt) 1755 { 1756 size_type __next_bkt = _M_bucket_index(__n->_M_next()); 1757 if (__next_bkt != __bkt) 1758 _M_buckets[__next_bkt] = __prev_n; 1759 } 1760 1761 __prev_n->_M_nxt = __n->_M_nxt; 1762 iterator __result(__n->_M_next()); 1763 this->_M_deallocate_node(__n); 1764 --_M_element_count; 1765 1766 return __result; 1767 } 1768 1769 template<typename _Key, typename _Value, 1770 typename _Alloc, typename _ExtractKey, typename _Equal, 1771 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1772 typename _Traits> 1773 auto 1774 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1775 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1776 _M_erase(std::true_type, const key_type& __k) 1777 -> size_type 1778 { 1779 __hash_code __code = this->_M_hash_code(__k); 1780 std::size_t __bkt = _M_bucket_index(__k, __code); 1781 1782 // Look for the node before the first matching node. 1783 __node_base* __prev_n = _M_find_before_node(__bkt, __k, __code); 1784 if (!__prev_n) 1785 return 0; 1786 1787 // We found a matching node, erase it. 1788 __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt); 1789 _M_erase(__bkt, __prev_n, __n); 1790 return 1; 1791 } 1792 1793 template<typename _Key, typename _Value, 1794 typename _Alloc, typename _ExtractKey, typename _Equal, 1795 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1796 typename _Traits> 1797 auto 1798 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1799 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1800 _M_erase(std::false_type, const key_type& __k) 1801 -> size_type 1802 { 1803 __hash_code __code = this->_M_hash_code(__k); 1804 std::size_t __bkt = _M_bucket_index(__k, __code); 1805 1806 // Look for the node before the first matching node. 1807 __node_base* __prev_n = _M_find_before_node(__bkt, __k, __code); 1808 if (!__prev_n) 1809 return 0; 1810 1811 // _GLIBCXX_RESOLVE_LIB_DEFECTS 1812 // 526. Is it undefined if a function in the standard changes 1813 // in parameters? 1814 // We use one loop to find all matching nodes and another to deallocate 1815 // them so that the key stays valid during the first loop. It might be 1816 // invalidated indirectly when destroying nodes. 1817 __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt); 1818 __node_type* __n_last = __n; 1819 std::size_t __n_last_bkt = __bkt; 1820 do 1821 { 1822 __n_last = __n_last->_M_next(); 1823 if (!__n_last) 1824 break; 1825 __n_last_bkt = _M_bucket_index(__n_last); 1826 } 1827 while (__n_last_bkt == __bkt && this->_M_equals(__k, __code, __n_last)); 1828 1829 // Deallocate nodes. 1830 size_type __result = 0; 1831 do 1832 { 1833 __node_type* __p = __n->_M_next(); 1834 this->_M_deallocate_node(__n); 1835 __n = __p; 1836 ++__result; 1837 --_M_element_count; 1838 } 1839 while (__n != __n_last); 1840 1841 if (__prev_n == _M_buckets[__bkt]) 1842 _M_remove_bucket_begin(__bkt, __n_last, __n_last_bkt); 1843 else if (__n_last && __n_last_bkt != __bkt) 1844 _M_buckets[__n_last_bkt] = __prev_n; 1845 __prev_n->_M_nxt = __n_last; 1846 return __result; 1847 } 1848 1849 template<typename _Key, typename _Value, 1850 typename _Alloc, typename _ExtractKey, typename _Equal, 1851 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1852 typename _Traits> 1853 auto 1854 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1855 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1856 erase(const_iterator __first, const_iterator __last) 1857 -> iterator 1858 { 1859 __node_type* __n = __first._M_cur; 1860 __node_type* __last_n = __last._M_cur; 1861 if (__n == __last_n) 1862 return iterator(__n); 1863 1864 std::size_t __bkt = _M_bucket_index(__n); 1865 1866 __node_base* __prev_n = _M_get_previous_node(__bkt, __n); 1867 bool __is_bucket_begin = __n == _M_bucket_begin(__bkt); 1868 std::size_t __n_bkt = __bkt; 1869 for (;;) 1870 { 1871 do 1872 { 1873 __node_type* __tmp = __n; 1874 __n = __n->_M_next(); 1875 this->_M_deallocate_node(__tmp); 1876 --_M_element_count; 1877 if (!__n) 1878 break; 1879 __n_bkt = _M_bucket_index(__n); 1880 } 1881 while (__n != __last_n && __n_bkt == __bkt); 1882 if (__is_bucket_begin) 1883 _M_remove_bucket_begin(__bkt, __n, __n_bkt); 1884 if (__n == __last_n) 1885 break; 1886 __is_bucket_begin = true; 1887 __bkt = __n_bkt; 1888 } 1889 1890 if (__n && (__n_bkt != __bkt || __is_bucket_begin)) 1891 _M_buckets[__n_bkt] = __prev_n; 1892 __prev_n->_M_nxt = __n; 1893 return iterator(__n); 1894 } 1895 1896 template<typename _Key, typename _Value, 1897 typename _Alloc, typename _ExtractKey, typename _Equal, 1898 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1899 typename _Traits> 1900 void 1901 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1902 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1903 clear() noexcept 1904 { 1905 this->_M_deallocate_nodes(_M_begin()); 1906 __builtin_memset(_M_buckets, 0, _M_bucket_count * sizeof(__bucket_type)); 1907 _M_element_count = 0; 1908 _M_before_begin._M_nxt = nullptr; 1909 } 1910 1911 template<typename _Key, typename _Value, 1912 typename _Alloc, typename _ExtractKey, typename _Equal, 1913 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1914 typename _Traits> 1915 void 1916 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1917 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1918 rehash(size_type __n) 1919 { 1920 const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 1921 std::size_t __buckets 1922 = std::max(_M_rehash_policy._M_bkt_for_elements(_M_element_count + 1), 1923 __n); 1924 __buckets = _M_rehash_policy._M_next_bkt(__buckets); 1925 1926 if (__buckets != _M_bucket_count) 1927 _M_rehash(__buckets, __saved_state); 1928 else 1929 // No rehash, restore previous state to keep a consistent state. 1930 _M_rehash_policy._M_reset(__saved_state); 1931 } 1932 1933 template<typename _Key, typename _Value, 1934 typename _Alloc, typename _ExtractKey, typename _Equal, 1935 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1936 typename _Traits> 1937 void 1938 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1939 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1940 _M_rehash(size_type __n, const __rehash_state& __state) 1941 { 1942 __try 1943 { 1944 _M_rehash_aux(__n, __unique_keys()); 1945 } 1946 __catch(...) 1947 { 1948 // A failure here means that buckets allocation failed. We only 1949 // have to restore hash policy previous state. 1950 _M_rehash_policy._M_reset(__state); 1951 __throw_exception_again; 1952 } 1953 } 1954 1955 // Rehash when there is no equivalent elements. 1956 template<typename _Key, typename _Value, 1957 typename _Alloc, typename _ExtractKey, typename _Equal, 1958 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 1959 typename _Traits> 1960 void 1961 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 1962 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 1963 _M_rehash_aux(size_type __n, std::true_type) 1964 { 1965 __bucket_type* __new_buckets = _M_allocate_buckets(__n); 1966 __node_type* __p = _M_begin(); 1967 _M_before_begin._M_nxt = nullptr; 1968 std::size_t __bbegin_bkt = 0; 1969 while (__p) 1970 { 1971 __node_type* __next = __p->_M_next(); 1972 std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); 1973 if (!__new_buckets[__bkt]) 1974 { 1975 __p->_M_nxt = _M_before_begin._M_nxt; 1976 _M_before_begin._M_nxt = __p; 1977 __new_buckets[__bkt] = &_M_before_begin; 1978 if (__p->_M_nxt) 1979 __new_buckets[__bbegin_bkt] = __p; 1980 __bbegin_bkt = __bkt; 1981 } 1982 else 1983 { 1984 __p->_M_nxt = __new_buckets[__bkt]->_M_nxt; 1985 __new_buckets[__bkt]->_M_nxt = __p; 1986 } 1987 __p = __next; 1988 } 1989 1990 _M_deallocate_buckets(); 1991 _M_bucket_count = __n; 1992 _M_buckets = __new_buckets; 1993 } 1994 1995 // Rehash when there can be equivalent elements, preserve their relative 1996 // order. 1997 template<typename _Key, typename _Value, 1998 typename _Alloc, typename _ExtractKey, typename _Equal, 1999 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 2000 typename _Traits> 2001 void 2002 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 2003 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 2004 _M_rehash_aux(size_type __n, std::false_type) 2005 { 2006 __bucket_type* __new_buckets = _M_allocate_buckets(__n); 2007 2008 __node_type* __p = _M_begin(); 2009 _M_before_begin._M_nxt = nullptr; 2010 std::size_t __bbegin_bkt = 0; 2011 std::size_t __prev_bkt = 0; 2012 __node_type* __prev_p = nullptr; 2013 bool __check_bucket = false; 2014 2015 while (__p) 2016 { 2017 __node_type* __next = __p->_M_next(); 2018 std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); 2019 2020 if (__prev_p && __prev_bkt == __bkt) 2021 { 2022 // Previous insert was already in this bucket, we insert after 2023 // the previously inserted one to preserve equivalent elements 2024 // relative order. 2025 __p->_M_nxt = __prev_p->_M_nxt; 2026 __prev_p->_M_nxt = __p; 2027 2028 // Inserting after a node in a bucket require to check that we 2029 // haven't change the bucket last node, in this case next 2030 // bucket containing its before begin node must be updated. We 2031 // schedule a check as soon as we move out of the sequence of 2032 // equivalent nodes to limit the number of checks. 2033 __check_bucket = true; 2034 } 2035 else 2036 { 2037 if (__check_bucket) 2038 { 2039 // Check if we shall update the next bucket because of 2040 // insertions into __prev_bkt bucket. 2041 if (__prev_p->_M_nxt) 2042 { 2043 std::size_t __next_bkt 2044 = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), 2045 __n); 2046 if (__next_bkt != __prev_bkt) 2047 __new_buckets[__next_bkt] = __prev_p; 2048 } 2049 __check_bucket = false; 2050 } 2051 2052 if (!__new_buckets[__bkt]) 2053 { 2054 __p->_M_nxt = _M_before_begin._M_nxt; 2055 _M_before_begin._M_nxt = __p; 2056 __new_buckets[__bkt] = &_M_before_begin; 2057 if (__p->_M_nxt) 2058 __new_buckets[__bbegin_bkt] = __p; 2059 __bbegin_bkt = __bkt; 2060 } 2061 else 2062 { 2063 __p->_M_nxt = __new_buckets[__bkt]->_M_nxt; 2064 __new_buckets[__bkt]->_M_nxt = __p; 2065 } 2066 } 2067 __prev_p = __p; 2068 __prev_bkt = __bkt; 2069 __p = __next; 2070 } 2071 2072 if (__check_bucket && __prev_p->_M_nxt) 2073 { 2074 std::size_t __next_bkt 2075 = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), __n); 2076 if (__next_bkt != __prev_bkt) 2077 __new_buckets[__next_bkt] = __prev_p; 2078 } 2079 2080 _M_deallocate_buckets(); 2081 _M_bucket_count = __n; 2082 _M_buckets = __new_buckets; 2083 } 2084 2085 _GLIBCXX_END_NAMESPACE_VERSION 2086 } // namespace std 2087 2088 #endif // _HASHTABLE_H 2089