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