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