Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/c++/15/bits/hashtable_policy.h
1 // Internal policy header for unordered_set and unordered_map -*- C++ -*- 2 3 // Copyright (C) 2010-2025 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_policy.h 26 * This is an internal header file, included by other library headers. 27 * Do not attempt to use it directly. 28 * @headername{unordered_map,unordered_set} 29 */ 30 31 #ifndef _HASHTABLE_POLICY_H 32 #define _HASHTABLE_POLICY_H 1 33 34 #include <tuple> // for std::tuple, std::forward_as_tuple 35 #include <bits/functional_hash.h> // for __is_fast_hash 36 #include <bits/stl_algobase.h> // for std::min 37 #include <bits/stl_pair.h> // for std::pair 38 #include <ext/aligned_buffer.h> // for __gnu_cxx::__aligned_buffer 39 #include <ext/alloc_traits.h> // for std::__alloc_rebind 40 #include <ext/numeric_traits.h> // for __gnu_cxx::__int_traits 41 42 namespace std _GLIBCXX_VISIBILITY(default) 43 { 44 _GLIBCXX_BEGIN_NAMESPACE_VERSION 45 /// @cond undocumented 46 47 template<typename _Key, typename _Value, typename _Alloc, 48 typename _ExtractKey, typename _Equal, 49 typename _Hash, typename _RangeHash, typename _Unused, 50 typename _RehashPolicy, typename _Traits> 51 class _Hashtable; 52 53 namespace __detail 54 { 55 /** 56 * @defgroup hashtable-detail Base and Implementation Classes 57 * @ingroup unordered_associative_containers 58 * @{ 59 */ 60 template<typename _Key, typename _Value, typename _ExtractKey, 61 typename _Equal, typename _Hash, typename _RangeHash, 62 typename _Unused, typename _Traits> 63 struct _Hashtable_base; 64 65 #pragma GCC diagnostic push 66 #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr 67 // Helper function: return distance(first, last) for forward 68 // iterators, or 0/1 for input iterators. 69 template<typename _Iterator> 70 inline typename std::iterator_traits<_Iterator>::difference_type 71 __distance_fw(_Iterator __first, _Iterator __last) 72 { 73 using _Cat = typename std::iterator_traits<_Iterator>::iterator_category; 74 if constexpr (is_convertible<_Cat, forward_iterator_tag>::value) 75 return std::distance(__first, __last); 76 else 77 return __first != __last ? 1 : 0; 78 } 79 #pragma GCC diagnostic pop 80 81 struct _Identity 82 { 83 template<typename _Tp> 84 _Tp&& 85 operator()(_Tp&& __x) const noexcept 86 { return std::forward<_Tp>(__x); } 87 }; 88 89 struct _Select1st 90 { 91 template<typename _Pair> 92 struct __1st_type; 93 94 template<typename _Tp, typename _Up> 95 struct __1st_type<pair<_Tp, _Up>> 96 { using type = _Tp; }; 97 98 template<typename _Tp, typename _Up> 99 struct __1st_type<const pair<_Tp, _Up>> 100 { using type = const _Tp; }; 101 102 template<typename _Pair> 103 struct __1st_type<_Pair&> 104 { using type = typename __1st_type<_Pair>::type&; }; 105 106 template<typename _Tp> 107 typename __1st_type<_Tp>::type&& 108 operator()(_Tp&& __x) const noexcept 109 { return std::forward<_Tp>(__x).first; } 110 }; 111 112 template<typename _ExKey> 113 struct _NodeBuilder; 114 115 template<> 116 struct _NodeBuilder<_Select1st> 117 { 118 template<typename _Kt, typename _Arg, typename _NodeGenerator> 119 static auto 120 _S_build(_Kt&& __k, _Arg&& __arg, _NodeGenerator& __node_gen) 121 -> typename _NodeGenerator::__node_ptr 122 { 123 return __node_gen(std::forward<_Kt>(__k), 124 std::forward<_Arg>(__arg).second); 125 } 126 }; 127 128 template<> 129 struct _NodeBuilder<_Identity> 130 { 131 template<typename _Kt, typename _Arg, typename _NodeGenerator> 132 static auto 133 _S_build(_Kt&& __k, _Arg&&, _NodeGenerator& __node_gen) 134 -> typename _NodeGenerator::__node_ptr 135 { return __node_gen(std::forward<_Kt>(__k)); } 136 }; 137 138 template<typename _HashtableAlloc, typename _NodePtr> 139 struct _NodePtrGuard 140 { 141 _HashtableAlloc& _M_h; 142 _NodePtr _M_ptr; 143 144 ~_NodePtrGuard() 145 { 146 if (_M_ptr) 147 _M_h._M_deallocate_node_ptr(_M_ptr); 148 } 149 }; 150 151 template<typename _NodeAlloc> 152 struct _Hashtable_alloc; 153 154 // Functor recycling a pool of nodes and using allocation once the pool is 155 // empty. 156 template<typename _NodeAlloc> 157 struct _ReuseOrAllocNode 158 { 159 private: 160 using __node_alloc_type = _NodeAlloc; 161 using __hashtable_alloc = _Hashtable_alloc<__node_alloc_type>; 162 using __node_alloc_traits = 163 typename __hashtable_alloc::__node_alloc_traits; 164 165 public: 166 using __node_ptr = typename __hashtable_alloc::__node_ptr; 167 168 _ReuseOrAllocNode(__node_ptr __nodes, __hashtable_alloc& __h) 169 : _M_nodes(__nodes), _M_h(__h) { } 170 _ReuseOrAllocNode(const _ReuseOrAllocNode&) = delete; 171 172 ~_ReuseOrAllocNode() 173 { _M_h._M_deallocate_nodes(_M_nodes); } 174 175 #pragma GCC diagnostic push 176 #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr 177 template<typename _Arg> 178 __node_ptr 179 operator()(_Arg&& __arg) 180 { 181 if (!_M_nodes) 182 return _M_h._M_allocate_node(std::forward<_Arg>(__arg)); 183 184 using value_type = typename _NodeAlloc::value_type::value_type; 185 186 __node_ptr __node = _M_nodes; 187 if constexpr (is_assignable<value_type&, _Arg>::value) 188 { 189 __node->_M_v() = std::forward<_Arg>(__arg); 190 _M_nodes = _M_nodes->_M_next(); 191 __node->_M_nxt = nullptr; 192 } 193 else 194 { 195 _M_nodes = _M_nodes->_M_next(); 196 __node->_M_nxt = nullptr; 197 auto& __a = _M_h._M_node_allocator(); 198 __node_alloc_traits::destroy(__a, __node->_M_valptr()); 199 _NodePtrGuard<__hashtable_alloc, __node_ptr> 200 __guard{ _M_h, __node }; 201 __node_alloc_traits::construct(__a, __node->_M_valptr(), 202 std::forward<_Arg>(__arg)); 203 __guard._M_ptr = nullptr; 204 } 205 return __node; 206 } 207 #pragma GCC diagnostic pop 208 209 private: 210 __node_ptr _M_nodes; 211 __hashtable_alloc& _M_h; 212 }; 213 214 // Functor similar to the previous one but without any pool of nodes to 215 // recycle. 216 template<typename _NodeAlloc> 217 struct _AllocNode 218 { 219 private: 220 using __hashtable_alloc = _Hashtable_alloc<_NodeAlloc>; 221 222 public: 223 using __node_ptr = typename __hashtable_alloc::__node_ptr; 224 225 _AllocNode(__hashtable_alloc& __h) 226 : _M_h(__h) { } 227 228 template<typename... _Args> 229 __node_ptr 230 operator()(_Args&&... __args) const 231 { return _M_h._M_allocate_node(std::forward<_Args>(__args)...); } 232 233 private: 234 __hashtable_alloc& _M_h; 235 }; 236 237 // Auxiliary types used for all instantiations of _Hashtable nodes 238 // and iterators. 239 240 /** 241 * struct _Hashtable_traits 242 * 243 * Important traits for hash tables. 244 * 245 * @tparam _Cache_hash_code Boolean value. True if the value of 246 * the hash function is stored along with the value. This is a 247 * time-space tradeoff. Storing it may improve lookup speed by 248 * reducing the number of times we need to call the _Hash or _Equal 249 * functors. 250 * 251 * @tparam _Constant_iterators Boolean value. True if iterator and 252 * const_iterator are both constant iterator types. This is true 253 * for unordered_set and unordered_multiset, false for 254 * unordered_map and unordered_multimap. 255 * 256 * @tparam _Unique_keys Boolean value. True if the return value 257 * of _Hashtable::count(k) is always at most one, false if it may 258 * be an arbitrary number. This is true for unordered_set and 259 * unordered_map, false for unordered_multiset and 260 * unordered_multimap. 261 */ 262 template<bool _Cache_hash_code, bool _Constant_iterators, bool _Unique_keys> 263 struct _Hashtable_traits 264 { 265 using __hash_cached = __bool_constant<_Cache_hash_code>; 266 using __constant_iterators = __bool_constant<_Constant_iterators>; 267 using __unique_keys = __bool_constant<_Unique_keys>; 268 }; 269 270 /** 271 * struct _Hashtable_hash_traits 272 * 273 * Important traits for hash tables depending on associated hasher. 274 * 275 */ 276 template<typename _Hash> 277 struct _Hashtable_hash_traits 278 { 279 static constexpr size_t 280 __small_size_threshold() noexcept 281 { return std::__is_fast_hash<_Hash>::value ? 0 : 20; } 282 }; 283 284 /** 285 * struct _Hash_node_base 286 * 287 * Nodes, used to wrap elements stored in the hash table. A policy 288 * template parameter of class template _Hashtable controls whether 289 * nodes also store a hash code. In some cases (e.g. strings) this 290 * may be a performance win. 291 */ 292 struct _Hash_node_base 293 { 294 _Hash_node_base* _M_nxt; 295 296 _Hash_node_base() noexcept : _M_nxt() { } 297 298 _Hash_node_base(_Hash_node_base* __next) noexcept : _M_nxt(__next) { } 299 }; 300 301 /** 302 * struct _Hash_node_value_base 303 * 304 * Node type with the value to store. 305 */ 306 template<typename _Value> 307 struct _Hash_node_value_base 308 { 309 using value_type = _Value; 310 311 __gnu_cxx::__aligned_buffer<_Value> _M_storage; 312 313 // These member functions must be always_inline, see PR 111050 314 315 [[__gnu__::__always_inline__]] 316 _Value* 317 _M_valptr() noexcept 318 { return _M_storage._M_ptr(); } 319 320 [[__gnu__::__always_inline__]] 321 const _Value* 322 _M_valptr() const noexcept 323 { return _M_storage._M_ptr(); } 324 325 [[__gnu__::__always_inline__]] 326 _Value& 327 _M_v() noexcept 328 { return *_M_valptr(); } 329 330 [[__gnu__::__always_inline__]] 331 const _Value& 332 _M_v() const noexcept 333 { return *_M_valptr(); } 334 }; 335 336 /** 337 * Primary template struct _Hash_node_code_cache. 338 */ 339 template<bool _Cache_hash_code> 340 struct _Hash_node_code_cache 341 { }; 342 343 /** 344 * Specialization for node with cache, struct _Hash_node_code_cache. 345 */ 346 template<> 347 struct _Hash_node_code_cache<true> 348 { size_t _M_hash_code; }; 349 350 template<typename _Value, bool _Cache_hash_code> 351 struct _Hash_node_value 352 : _Hash_node_value_base<_Value> 353 , _Hash_node_code_cache<_Cache_hash_code> 354 { }; 355 356 /** 357 * Primary template struct _Hash_node. 358 */ 359 template<typename _Value, bool _Cache_hash_code> 360 struct _Hash_node 361 : _Hash_node_base 362 , _Hash_node_value<_Value, _Cache_hash_code> 363 { 364 _Hash_node* 365 _M_next() const noexcept 366 { return static_cast<_Hash_node*>(this->_M_nxt); } 367 }; 368 369 /// Base class for node iterators. 370 template<typename _Value, bool _Cache_hash_code> 371 struct _Node_iterator_base 372 { 373 using __node_type = _Hash_node<_Value, _Cache_hash_code>; 374 375 __node_type* _M_cur; 376 377 _Node_iterator_base() : _M_cur(nullptr) { } 378 _Node_iterator_base(__node_type* __p) noexcept 379 : _M_cur(__p) { } 380 381 void 382 _M_incr() noexcept 383 { _M_cur = _M_cur->_M_next(); } 384 385 friend bool 386 operator==(const _Node_iterator_base& __x, const _Node_iterator_base& __y) 387 noexcept 388 { return __x._M_cur == __y._M_cur; } 389 390 #if __cpp_impl_three_way_comparison < 201907L 391 friend bool 392 operator!=(const _Node_iterator_base& __x, const _Node_iterator_base& __y) 393 noexcept 394 { return __x._M_cur != __y._M_cur; } 395 #endif 396 }; 397 398 /// Node iterators, used to iterate through all the hashtable. 399 template<typename _Value, bool __constant_iterators, bool __cache> 400 struct _Node_iterator 401 : public _Node_iterator_base<_Value, __cache> 402 { 403 private: 404 using __base_type = _Node_iterator_base<_Value, __cache>; 405 using __node_type = typename __base_type::__node_type; 406 407 public: 408 using value_type = _Value; 409 using difference_type = ptrdiff_t; 410 using iterator_category = forward_iterator_tag; 411 412 using pointer = __conditional_t<__constant_iterators, 413 const value_type*, value_type*>; 414 415 using reference = __conditional_t<__constant_iterators, 416 const value_type&, value_type&>; 417 418 _Node_iterator() = default; 419 420 explicit 421 _Node_iterator(__node_type* __p) noexcept 422 : __base_type(__p) { } 423 424 reference 425 operator*() const noexcept 426 { return this->_M_cur->_M_v(); } 427 428 pointer 429 operator->() const noexcept 430 { return this->_M_cur->_M_valptr(); } 431 432 _Node_iterator& 433 operator++() noexcept 434 { 435 this->_M_incr(); 436 return *this; 437 } 438 439 _Node_iterator 440 operator++(int) noexcept 441 { 442 _Node_iterator __tmp(*this); 443 this->_M_incr(); 444 return __tmp; 445 } 446 447 #if __cpp_impl_three_way_comparison >= 201907L 448 friend bool 449 operator==(const _Node_iterator&, const _Node_iterator&) = default; 450 #else 451 friend bool 452 operator==(const _Node_iterator& __x, const _Node_iterator& __y) noexcept 453 { 454 const __base_type& __bx = __x; 455 const __base_type& __by = __y; 456 return __bx == __by; 457 } 458 459 friend bool 460 operator!=(const _Node_iterator& __x, const _Node_iterator& __y) noexcept 461 { return !(__x == __y); } 462 #endif 463 }; 464 465 /// Node const_iterators, used to iterate through all the hashtable. 466 template<typename _Value, bool __constant_iterators, bool __cache> 467 struct _Node_const_iterator 468 : public _Node_iterator_base<_Value, __cache> 469 { 470 private: 471 using __base_type = _Node_iterator_base<_Value, __cache>; 472 using __node_type = typename __base_type::__node_type; 473 474 // The corresponding non-const iterator. 475 using __iterator 476 = _Node_iterator<_Value, __constant_iterators, __cache>; 477 478 public: 479 using value_type = _Value; 480 using difference_type = ptrdiff_t; 481 using iterator_category = forward_iterator_tag; 482 483 using pointer = const value_type*; 484 using reference = const value_type&; 485 486 _Node_const_iterator() = default; 487 488 explicit 489 _Node_const_iterator(__node_type* __p) noexcept 490 : __base_type(__p) { } 491 492 _Node_const_iterator(const __iterator& __x) noexcept 493 : __base_type(__x._M_cur) { } 494 495 reference 496 operator*() const noexcept 497 { return this->_M_cur->_M_v(); } 498 499 pointer 500 operator->() const noexcept 501 { return this->_M_cur->_M_valptr(); } 502 503 _Node_const_iterator& 504 operator++() noexcept 505 { 506 this->_M_incr(); 507 return *this; 508 } 509 510 _Node_const_iterator 511 operator++(int) noexcept 512 { 513 _Node_const_iterator __tmp(*this); 514 this->_M_incr(); 515 return __tmp; 516 } 517 518 #if __cpp_impl_three_way_comparison >= 201907L 519 friend bool 520 operator==(const _Node_const_iterator&, 521 const _Node_const_iterator&) = default; 522 523 friend bool 524 operator==(const _Node_const_iterator& __x, const __iterator& __y) 525 { 526 const __base_type& __bx = __x; 527 const __base_type& __by = __y; 528 return __bx == __by; 529 } 530 #else 531 friend bool 532 operator==(const _Node_const_iterator& __x, 533 const _Node_const_iterator& __y) noexcept 534 { 535 const __base_type& __bx = __x; 536 const __base_type& __by = __y; 537 return __bx == __by; 538 } 539 540 friend bool 541 operator!=(const _Node_const_iterator& __x, 542 const _Node_const_iterator& __y) noexcept 543 { return !(__x == __y); } 544 545 friend bool 546 operator==(const _Node_const_iterator& __x, 547 const __iterator& __y) noexcept 548 { 549 const __base_type& __bx = __x; 550 const __base_type& __by = __y; 551 return __bx == __by; 552 } 553 554 friend bool 555 operator!=(const _Node_const_iterator& __x, 556 const __iterator& __y) noexcept 557 { return !(__x == __y); } 558 559 friend bool 560 operator==(const __iterator& __x, 561 const _Node_const_iterator& __y) noexcept 562 { 563 const __base_type& __bx = __x; 564 const __base_type& __by = __y; 565 return __bx == __by; 566 } 567 568 friend bool 569 operator!=(const __iterator& __x, 570 const _Node_const_iterator& __y) noexcept 571 { return !(__x == __y); } 572 #endif 573 }; 574 575 // Many of class template _Hashtable's template parameters are policy 576 // classes. These are defaults for the policies. 577 578 /// Default range hashing function: use division to fold a large number 579 /// into the range [0, N). 580 struct _Mod_range_hashing 581 { 582 size_t 583 operator()(size_t __num, size_t __den) const noexcept 584 { return __num % __den; } 585 }; 586 587 /// Default ranged hash function H. In principle it should be a 588 /// function object composed from objects of type H1 and H2 such that 589 /// h(k, N) = h2(h1(k), N), but that would mean making extra copies of 590 /// h1 and h2. So instead we'll just use a tag to tell class template 591 /// hashtable to do that composition. 592 struct _Default_ranged_hash { }; 593 594 /// Default value for rehash policy. Bucket size is (usually) the 595 /// smallest prime that keeps the load factor small enough. 596 struct _Prime_rehash_policy 597 { 598 using __has_load_factor = true_type; 599 600 _Prime_rehash_policy(float __z = 1.0) noexcept 601 : _M_max_load_factor(__z), _M_next_resize(0) { } 602 603 float 604 max_load_factor() const noexcept 605 { return _M_max_load_factor; } 606 607 // Return a bucket size no smaller than n. 608 // TODO: 'const' qualifier is kept for abi compatibility reason. 609 size_t 610 _M_next_bkt(size_t __n) const; 611 612 // Return a bucket count appropriate for n elements 613 size_t 614 _M_bkt_for_elements(size_t __n) const 615 { return __builtin_ceil(__n / (double)_M_max_load_factor); } 616 617 // __n_bkt is current bucket count, __n_elt is current element count, 618 // and __n_ins is number of elements to be inserted. Do we need to 619 // increase bucket count? If so, return make_pair(true, n), where n 620 // is the new bucket count. If not, return make_pair(false, 0). 621 // TODO: 'const' qualifier is kept for abi compatibility reason. 622 std::pair<bool, size_t> 623 _M_need_rehash(size_t __n_bkt, size_t __n_elt, 624 size_t __n_ins) const; 625 626 using _State = size_t; 627 628 _State 629 _M_state() const 630 { return _M_next_resize; } 631 632 void 633 _M_reset() noexcept 634 { _M_next_resize = 0; } 635 636 void 637 _M_reset(_State __state) 638 { _M_next_resize = __state; } 639 640 static const size_t _S_growth_factor = 2; 641 642 float _M_max_load_factor; 643 644 // TODO: 'mutable' kept for abi compatibility reason. 645 mutable size_t _M_next_resize; 646 }; 647 648 /// Range hashing function assuming that second arg is a power of 2. 649 struct _Mask_range_hashing 650 { 651 size_t 652 operator()(size_t __num, size_t __den) const noexcept 653 { return __num & (__den - 1); } 654 }; 655 656 /// Compute closest power of 2 not less than __n 657 inline size_t 658 __clp2(size_t __n) noexcept 659 { 660 using __gnu_cxx::__int_traits; 661 // Equivalent to return __n ? std::bit_ceil(__n) : 0; 662 if (__n < 2) 663 return __n; 664 const unsigned __lz = sizeof(size_t) > sizeof(long) 665 ? __builtin_clzll(__n - 1ull) 666 : __builtin_clzl(__n - 1ul); 667 // Doing two shifts avoids undefined behaviour when __lz == 0. 668 return (size_t(1) << (__int_traits<size_t>::__digits - __lz - 1)) << 1; 669 } 670 671 /// Rehash policy providing power of 2 bucket numbers. Avoids modulo 672 /// operations. 673 struct _Power2_rehash_policy 674 { 675 using __has_load_factor = true_type; 676 677 _Power2_rehash_policy(float __z = 1.0) noexcept 678 : _M_max_load_factor(__z), _M_next_resize(0) { } 679 680 float 681 max_load_factor() const noexcept 682 { return _M_max_load_factor; } 683 684 // Return a bucket size no smaller than n (as long as n is not above the 685 // highest power of 2). 686 size_t 687 _M_next_bkt(size_t __n) noexcept 688 { 689 if (__n == 0) 690 // Special case on container 1st initialization with 0 bucket count 691 // hint. We keep _M_next_resize to 0 to make sure that next time we 692 // want to add an element allocation will take place. 693 return 1; 694 695 const auto __max_width = std::min<size_t>(sizeof(size_t), 8); 696 const auto __max_bkt = size_t(1) << (__max_width * __CHAR_BIT__ - 1); 697 size_t __res = __clp2(__n); 698 699 if (__res == 0) 700 __res = __max_bkt; 701 else if (__res == 1) 702 // If __res is 1 we force it to 2 to make sure there will be an 703 // allocation so that nothing need to be stored in the initial 704 // single bucket 705 __res = 2; 706 707 if (__res == __max_bkt) 708 // Set next resize to the max value so that we never try to rehash again 709 // as we already reach the biggest possible bucket number. 710 // Note that it might result in max_load_factor not being respected. 711 _M_next_resize = size_t(-1); 712 else 713 _M_next_resize 714 = __builtin_floor(__res * (double)_M_max_load_factor); 715 716 return __res; 717 } 718 719 // Return a bucket count appropriate for n elements 720 size_t 721 _M_bkt_for_elements(size_t __n) const noexcept 722 { return __builtin_ceil(__n / (double)_M_max_load_factor); } 723 724 // __n_bkt is current bucket count, __n_elt is current element count, 725 // and __n_ins is number of elements to be inserted. Do we need to 726 // increase bucket count? If so, return make_pair(true, n), where n 727 // is the new bucket count. If not, return make_pair(false, 0). 728 std::pair<bool, size_t> 729 _M_need_rehash(size_t __n_bkt, size_t __n_elt, size_t __n_ins) noexcept 730 { 731 if (__n_elt + __n_ins > _M_next_resize) 732 { 733 // If _M_next_resize is 0 it means that we have nothing allocated so 734 // far and that we start inserting elements. In this case we start 735 // with an initial bucket size of 11. 736 double __min_bkts 737 = std::max<size_t>(__n_elt + __n_ins, _M_next_resize ? 0 : 11) 738 / (double)_M_max_load_factor; 739 if (__min_bkts >= __n_bkt) 740 return { true, 741 _M_next_bkt(std::max<size_t>(__builtin_floor(__min_bkts) + 1, 742 __n_bkt * _S_growth_factor)) }; 743 744 _M_next_resize 745 = __builtin_floor(__n_bkt * (double)_M_max_load_factor); 746 return { false, 0 }; 747 } 748 else 749 return { false, 0 }; 750 } 751 752 using _State = size_t; 753 754 _State 755 _M_state() const noexcept 756 { return _M_next_resize; } 757 758 void 759 _M_reset() noexcept 760 { _M_next_resize = 0; } 761 762 void 763 _M_reset(_State __state) noexcept 764 { _M_next_resize = __state; } 765 766 static const size_t _S_growth_factor = 2; 767 768 float _M_max_load_factor; 769 size_t _M_next_resize; 770 }; 771 772 template<typename _RehashPolicy> 773 struct _RehashStateGuard 774 { 775 _RehashPolicy* _M_guarded_obj; 776 typename _RehashPolicy::_State _M_prev_state; 777 778 _RehashStateGuard(_RehashPolicy& __policy) 779 : _M_guarded_obj(std::__addressof(__policy)) 780 , _M_prev_state(__policy._M_state()) 781 { } 782 _RehashStateGuard(const _RehashStateGuard&) = delete; 783 784 ~_RehashStateGuard() 785 { 786 if (_M_guarded_obj) 787 _M_guarded_obj->_M_reset(_M_prev_state); 788 } 789 }; 790 791 // Base classes for std::_Hashtable. We define these base classes 792 // because in some cases we want to do different things depending on 793 // the value of a policy class. In some cases the policy class 794 // affects which member functions and nested typedefs are defined; 795 // we handle that by specializing base class templates. Several of 796 // the base class templates need to access other members of class 797 // template _Hashtable, so we use a variant of the "Curiously 798 // Recurring Template Pattern" (CRTP) technique. 799 800 /** 801 * Primary class template _Map_base. 802 * 803 * If the hashtable has a value type of the form pair<const T1, T2> and 804 * a key extraction policy (_ExtractKey) that returns the first part 805 * of the pair, the hashtable gets a mapped_type typedef. If it 806 * satisfies those criteria and also has unique keys, then it also 807 * gets an operator[]. 808 */ 809 template<typename _Key, typename _Value, typename _Alloc, 810 typename _ExtractKey, typename _Equal, 811 typename _Hash, typename _RangeHash, typename _Unused, 812 typename _RehashPolicy, typename _Traits, 813 bool _Unique_keys = _Traits::__unique_keys::value> 814 struct _Map_base { }; 815 816 /// Partial specialization, __unique_keys set to false, std::pair value type. 817 template<typename _Key, typename _Val, typename _Alloc, typename _Equal, 818 typename _Hash, typename _RangeHash, typename _Unused, 819 typename _RehashPolicy, typename _Traits> 820 struct _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal, 821 _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, false> 822 { 823 using mapped_type = _Val; 824 }; 825 826 /// Partial specialization, __unique_keys set to true. 827 template<typename _Key, typename _Val, typename _Alloc, typename _Equal, 828 typename _Hash, typename _RangeHash, typename _Unused, 829 typename _RehashPolicy, typename _Traits> 830 struct _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal, 831 _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, true> 832 { 833 private: 834 using __hashtable_base = _Hashtable_base<_Key, pair<const _Key, _Val>, 835 _Select1st, _Equal, _Hash, 836 _RangeHash, _Unused, 837 _Traits>; 838 839 using __hashtable = _Hashtable<_Key, pair<const _Key, _Val>, _Alloc, 840 _Select1st, _Equal, _Hash, _RangeHash, 841 _Unused, _RehashPolicy, _Traits>; 842 843 using __hash_code = typename __hashtable_base::__hash_code; 844 845 public: 846 using key_type = typename __hashtable_base::key_type; 847 using mapped_type = _Val; 848 849 mapped_type& 850 operator[](const key_type& __k); 851 852 mapped_type& 853 operator[](key_type&& __k); 854 855 // _GLIBCXX_RESOLVE_LIB_DEFECTS 856 // DR 761. unordered_map needs an at() member function. 857 mapped_type& 858 at(const key_type& __k) 859 { 860 auto __ite = static_cast<__hashtable*>(this)->find(__k); 861 if (!__ite._M_cur) 862 __throw_out_of_range(__N("unordered_map::at")); 863 return __ite->second; 864 } 865 866 const mapped_type& 867 at(const key_type& __k) const 868 { 869 auto __ite = static_cast<const __hashtable*>(this)->find(__k); 870 if (!__ite._M_cur) 871 __throw_out_of_range(__N("unordered_map::at")); 872 return __ite->second; 873 } 874 }; 875 876 template<typename _Key, typename _Val, typename _Alloc, typename _Equal, 877 typename _Hash, typename _RangeHash, typename _Unused, 878 typename _RehashPolicy, typename _Traits> 879 auto 880 _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal, 881 _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, true>:: 882 operator[](const key_type& __k) 883 -> mapped_type& 884 { 885 __hashtable* __h = static_cast<__hashtable*>(this); 886 __hash_code __code = __h->_M_hash_code(__k); 887 size_t __bkt = __h->_M_bucket_index(__code); 888 if (auto __node = __h->_M_find_node(__bkt, __k, __code)) 889 return __node->_M_v().second; 890 891 typename __hashtable::_Scoped_node __node { 892 __h, 893 std::piecewise_construct, 894 std::tuple<const key_type&>(__k), 895 std::tuple<>() 896 }; 897 auto __pos 898 = __h->_M_insert_unique_node(__bkt, __code, __node._M_node); 899 __node._M_node = nullptr; 900 return __pos->second; 901 } 902 903 template<typename _Key, typename _Val, typename _Alloc, typename _Equal, 904 typename _Hash, typename _RangeHash, typename _Unused, 905 typename _RehashPolicy, typename _Traits> 906 auto 907 _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal, 908 _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, true>:: 909 operator[](key_type&& __k) 910 -> mapped_type& 911 { 912 __hashtable* __h = static_cast<__hashtable*>(this); 913 __hash_code __code = __h->_M_hash_code(__k); 914 size_t __bkt = __h->_M_bucket_index(__code); 915 if (auto __node = __h->_M_find_node(__bkt, __k, __code)) 916 return __node->_M_v().second; 917 918 typename __hashtable::_Scoped_node __node { 919 __h, 920 std::piecewise_construct, 921 std::forward_as_tuple(std::move(__k)), 922 std::tuple<>() 923 }; 924 auto __pos 925 = __h->_M_insert_unique_node(__bkt, __code, __node._M_node); 926 __node._M_node = nullptr; 927 return __pos->second; 928 } 929 930 // Partial specialization for unordered_map<const T, U>, see PR 104174. 931 template<typename _Key, typename _Val, typename _Alloc, typename _Equal, 932 typename _Hash, typename _RangeHash, typename _Unused, 933 typename _RehashPolicy, typename _Traits, bool __uniq> 934 struct _Map_base<const _Key, pair<const _Key, _Val>, 935 _Alloc, _Select1st, _Equal, _Hash, 936 _RangeHash, _Unused, _RehashPolicy, _Traits, __uniq> 937 : _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal, _Hash, 938 _RangeHash, _Unused, _RehashPolicy, _Traits, __uniq> 939 { }; 940 941 template<typename _Policy> 942 using __has_load_factor = typename _Policy::__has_load_factor; 943 944 /** 945 * Primary class template _Rehash_base. 946 * 947 * Give hashtable the max_load_factor functions and reserve iff the 948 * rehash policy supports it. 949 */ 950 template<typename _Key, typename _Value, typename _Alloc, 951 typename _ExtractKey, typename _Equal, 952 typename _Hash, typename _RangeHash, typename _Unused, 953 typename _RehashPolicy, typename _Traits, 954 typename = 955 __detected_or_t<false_type, __has_load_factor, _RehashPolicy>> 956 struct _Rehash_base; 957 958 /// Specialization when rehash policy doesn't provide load factor management. 959 template<typename _Key, typename _Value, typename _Alloc, 960 typename _ExtractKey, typename _Equal, 961 typename _Hash, typename _RangeHash, typename _Unused, 962 typename _RehashPolicy, typename _Traits> 963 struct _Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, 964 _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, 965 false_type /* Has load factor */> 966 { 967 }; 968 969 /// Specialization when rehash policy provide load factor management. 970 template<typename _Key, typename _Value, typename _Alloc, 971 typename _ExtractKey, typename _Equal, 972 typename _Hash, typename _RangeHash, typename _Unused, 973 typename _RehashPolicy, typename _Traits> 974 struct _Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, 975 _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, 976 true_type /* Has load factor */> 977 { 978 private: 979 using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey, 980 _Equal, _Hash, _RangeHash, _Unused, 981 _RehashPolicy, _Traits>; 982 983 public: 984 float 985 max_load_factor() const noexcept 986 { 987 const __hashtable* __this = static_cast<const __hashtable*>(this); 988 return __this->__rehash_policy().max_load_factor(); 989 } 990 991 void 992 max_load_factor(float __z) 993 { 994 __hashtable* __this = static_cast<__hashtable*>(this); 995 __this->__rehash_policy(_RehashPolicy(__z)); 996 } 997 998 void 999 reserve(size_t __n) 1000 { 1001 __hashtable* __this = static_cast<__hashtable*>(this); 1002 __this->rehash(__this->__rehash_policy()._M_bkt_for_elements(__n)); 1003 } 1004 }; 1005 1006 /** 1007 * Primary class template _Hashtable_ebo_helper. 1008 * 1009 * Helper class using [[no_unique_address]] to reduce object size. 1010 */ 1011 template<typename _Tp, 1012 bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)> 1013 struct _Hashtable_ebo_helper 1014 { 1015 [[__no_unique_address__]] _Tp _M_obj; 1016 }; 1017 1018 #if ! _GLIBCXX_INLINE_VERSION 1019 // For ABI compatibility reasons, [[no_unique_address]] is only used 1020 // for empty non-final types. 1021 template<typename _Tp> 1022 struct _Hashtable_ebo_helper<_Tp, false> 1023 { 1024 _Tp _M_obj; 1025 }; 1026 #endif 1027 1028 /** 1029 * Primary class template _Local_iterator_base. 1030 * 1031 * Base class for local iterators, used to iterate within a bucket 1032 * but not between buckets. 1033 */ 1034 template<typename _Key, typename _Value, typename _ExtractKey, 1035 typename _Hash, typename _RangeHash, typename _Unused, 1036 bool __cache_hash_code> 1037 struct _Local_iterator_base; 1038 1039 // Wraps the _Hash object and provides some utility functions for using it. 1040 template<typename _Key, typename _Value, typename _ExtractKey, 1041 typename _Hash, typename _RangeHash, typename _Unused, 1042 bool /* __cache_hash_code */> 1043 struct _Hash_code_base 1044 { 1045 // Gives the local iterator implementation access to _M_bucket_index(). 1046 friend struct _Local_iterator_base<_Key, _Value, _ExtractKey, 1047 _Hash, _RangeHash, _Unused, false>; 1048 public: 1049 using hasher = _Hash; 1050 1051 hasher 1052 hash_function() const 1053 { return _M_hash._M_obj; } 1054 1055 protected: 1056 [[__no_unique_address__]] _Hashtable_ebo_helper<_Hash> _M_hash{}; 1057 1058 using __hash_code = size_t; 1059 1060 // We need the default constructor for the local iterators and _Hashtable 1061 // default constructor. 1062 _Hash_code_base() = default; 1063 1064 _Hash_code_base(const _Hash& __hash) : _M_hash{__hash} { } 1065 1066 __hash_code 1067 _M_hash_code(const _Key& __k) const 1068 { 1069 static_assert(__is_invocable<const _Hash&, const _Key&>{}, 1070 "hash function must be invocable with an argument of key type"); 1071 return _M_hash._M_obj(__k); 1072 } 1073 1074 template<typename _Kt> 1075 __hash_code 1076 _M_hash_code_tr(const _Kt& __k) const 1077 { 1078 static_assert(__is_invocable<const _Hash&, const _Kt&>{}, 1079 "hash function must be invocable with an argument of key type"); 1080 return _M_hash._M_obj(__k); 1081 } 1082 1083 __hash_code 1084 _M_hash_code(const _Hash_node_value<_Value, false>& __n) const 1085 { return _M_hash_code(_ExtractKey{}(__n._M_v())); } 1086 1087 __hash_code 1088 _M_hash_code(const _Hash_node_value<_Value, true>& __n) const 1089 { return __n._M_hash_code; } 1090 1091 size_t 1092 _M_bucket_index(__hash_code __c, size_t __bkt_count) const 1093 { return _RangeHash{}(__c, __bkt_count); } 1094 1095 size_t 1096 _M_bucket_index(const _Hash_node_value<_Value, false>& __n, 1097 size_t __bkt_count) const 1098 noexcept( noexcept(declval<const _Hash&>()(declval<const _Key&>())) ) 1099 { 1100 return _RangeHash{}(_M_hash_code(_ExtractKey{}(__n._M_v())), 1101 __bkt_count); 1102 } 1103 1104 size_t 1105 _M_bucket_index(const _Hash_node_value<_Value, true>& __n, 1106 size_t __bkt_count) const noexcept 1107 { return _RangeHash{}(__n._M_hash_code, __bkt_count); } 1108 }; 1109 1110 /// Partial specialization used when nodes contain a cached hash code. 1111 template<typename _Key, typename _Value, typename _ExtractKey, 1112 typename _Hash, typename _RangeHash, typename _Unused> 1113 struct _Local_iterator_base<_Key, _Value, _ExtractKey, 1114 _Hash, _RangeHash, _Unused, true> 1115 : public _Node_iterator_base<_Value, true> 1116 { 1117 protected: 1118 using __base_node_iter = _Node_iterator_base<_Value, true>; 1119 using __hash_code_base = _Hash_code_base<_Key, _Value, _ExtractKey, 1120 _Hash, _RangeHash, _Unused, true>; 1121 1122 _Local_iterator_base() = default; 1123 1124 _Local_iterator_base(const __hash_code_base&, 1125 _Hash_node<_Value, true>* __p, 1126 size_t __bkt, size_t __bkt_count) 1127 : __base_node_iter(__p), _M_bucket(__bkt), _M_bucket_count(__bkt_count) 1128 { } 1129 1130 void 1131 _M_incr() 1132 { 1133 __base_node_iter::_M_incr(); 1134 if (this->_M_cur) 1135 { 1136 size_t __bkt 1137 = _RangeHash{}(this->_M_cur->_M_hash_code, _M_bucket_count); 1138 if (__bkt != _M_bucket) 1139 this->_M_cur = nullptr; 1140 } 1141 } 1142 1143 size_t _M_bucket = 0; 1144 size_t _M_bucket_count = 0; 1145 1146 public: 1147 size_t 1148 _M_get_bucket() const { return _M_bucket; } // for debug mode 1149 }; 1150 1151 // Uninitialized storage for a _Hash object in a local iterator. 1152 // This type is DefaultConstructible even if the _Hash type isn't, 1153 // so that _Local_iterator_base<..., false> can be DefaultConstructible. 1154 template<typename _Hash> 1155 struct _Hash_obj_storage 1156 { 1157 union _Uninit_storage 1158 { 1159 _Uninit_storage() noexcept { } 1160 ~_Uninit_storage() { } 1161 1162 [[__no_unique_address__]] _Hash _M_h; 1163 }; 1164 1165 [[__no_unique_address__]] _Uninit_storage _M_u; 1166 }; 1167 1168 // Partial specialization used when hash codes are not cached 1169 template<typename _Key, typename _Value, typename _ExtractKey, 1170 typename _Hash, typename _RangeHash, typename _Unused> 1171 struct _Local_iterator_base<_Key, _Value, _ExtractKey, 1172 _Hash, _RangeHash, _Unused, false> 1173 : _Hash_obj_storage<_Hash>, _Node_iterator_base<_Value, false> 1174 { 1175 protected: 1176 using __hash_code_base = _Hash_code_base<_Key, _Value, _ExtractKey, 1177 _Hash, _RangeHash, _Unused, false>; 1178 using __hash_obj_storage = _Hash_obj_storage<_Hash>; 1179 using __node_iter_base = _Node_iterator_base<_Value, false>; 1180 1181 _Local_iterator_base() = default; 1182 1183 _Local_iterator_base(const __hash_code_base& __base, 1184 _Hash_node<_Value, false>* __p, 1185 size_t __bkt, size_t __bkt_count) 1186 : __node_iter_base(__p), _M_bucket(__bkt), _M_bucket_count(__bkt_count) 1187 { _M_init(__base._M_hash._M_obj); } 1188 1189 ~_Local_iterator_base() 1190 { 1191 if (_M_bucket_count != size_t(-1)) 1192 _M_destroy(); 1193 } 1194 1195 _Local_iterator_base(const _Local_iterator_base& __iter) 1196 : __node_iter_base(__iter._M_cur), _M_bucket(__iter._M_bucket) 1197 , _M_bucket_count(__iter._M_bucket_count) 1198 { 1199 if (_M_bucket_count != size_t(-1)) 1200 _M_init(__iter._M_h()); 1201 } 1202 1203 _Local_iterator_base& 1204 operator=(const _Local_iterator_base& __iter) 1205 { 1206 if (_M_bucket_count != size_t(-1)) 1207 _M_destroy(); 1208 this->_M_cur = __iter._M_cur; 1209 _M_bucket = __iter._M_bucket; 1210 _M_bucket_count = __iter._M_bucket_count; 1211 if (_M_bucket_count != size_t(-1)) 1212 _M_init(__iter._M_h()); 1213 return *this; 1214 } 1215 1216 void 1217 _M_incr() 1218 { 1219 __node_iter_base::_M_incr(); 1220 if (this->_M_cur) 1221 { 1222 const auto __code = _M_h()(_ExtractKey{}(this->_M_cur->_M_v())); 1223 size_t __bkt = _RangeHash{}(__code, _M_bucket_count); 1224 if (__bkt != _M_bucket) 1225 this->_M_cur = nullptr; 1226 } 1227 } 1228 1229 size_t _M_bucket = 0; 1230 size_t _M_bucket_count = -1; 1231 1232 void 1233 _M_init(const _Hash& __h) 1234 { std::_Construct(std::__addressof(__hash_obj_storage::_M_u._M_h), __h); } 1235 1236 void 1237 _M_destroy() { __hash_obj_storage::_M_u._M_h.~_Hash(); } 1238 1239 const _Hash& 1240 _M_h() const { return __hash_obj_storage::_M_u._M_h; } 1241 1242 public: 1243 size_t 1244 _M_get_bucket() const { return _M_bucket; } // for debug mode 1245 }; 1246 1247 /// local iterators 1248 template<typename _Key, typename _Value, typename _ExtractKey, 1249 typename _Hash, typename _RangeHash, typename _Unused, 1250 bool __constant_iterators, bool __cache> 1251 struct _Local_iterator 1252 : public _Local_iterator_base<_Key, _Value, _ExtractKey, 1253 _Hash, _RangeHash, _Unused, __cache> 1254 { 1255 private: 1256 using __base_type = _Local_iterator_base<_Key, _Value, _ExtractKey, 1257 _Hash, _RangeHash, _Unused, __cache>; 1258 using __hash_code_base = typename __base_type::__hash_code_base; 1259 1260 public: 1261 using value_type = _Value; 1262 using pointer = __conditional_t<__constant_iterators, 1263 const value_type*, value_type*>; 1264 using reference = __conditional_t<__constant_iterators, 1265 const value_type&, value_type&>; 1266 using difference_type = ptrdiff_t; 1267 using iterator_category = forward_iterator_tag; 1268 1269 _Local_iterator() = default; 1270 1271 _Local_iterator(const __hash_code_base& __base, 1272 _Hash_node<_Value, __cache>* __n, 1273 size_t __bkt, size_t __bkt_count) 1274 : __base_type(__base, __n, __bkt, __bkt_count) 1275 { } 1276 1277 reference 1278 operator*() const 1279 { return this->_M_cur->_M_v(); } 1280 1281 pointer 1282 operator->() const 1283 { return this->_M_cur->_M_valptr(); } 1284 1285 _Local_iterator& 1286 operator++() 1287 { 1288 this->_M_incr(); 1289 return *this; 1290 } 1291 1292 _Local_iterator 1293 operator++(int) 1294 { 1295 _Local_iterator __tmp(*this); 1296 this->_M_incr(); 1297 return __tmp; 1298 } 1299 }; 1300 1301 /// local const_iterators 1302 template<typename _Key, typename _Value, typename _ExtractKey, 1303 typename _Hash, typename _RangeHash, typename _Unused, 1304 bool __constant_iterators, bool __cache> 1305 struct _Local_const_iterator 1306 : public _Local_iterator_base<_Key, _Value, _ExtractKey, 1307 _Hash, _RangeHash, _Unused, __cache> 1308 { 1309 private: 1310 using __base_type = _Local_iterator_base<_Key, _Value, _ExtractKey, 1311 _Hash, _RangeHash, _Unused, __cache>; 1312 using __hash_code_base = typename __base_type::__hash_code_base; 1313 1314 public: 1315 using value_type = _Value; 1316 using pointer = const value_type*; 1317 using reference = const value_type&; 1318 using difference_type = ptrdiff_t; 1319 using iterator_category = forward_iterator_tag; 1320 1321 _Local_const_iterator() = default; 1322 1323 _Local_const_iterator(const __hash_code_base& __base, 1324 _Hash_node<_Value, __cache>* __n, 1325 size_t __bkt, size_t __bkt_count) 1326 : __base_type(__base, __n, __bkt, __bkt_count) 1327 { } 1328 1329 _Local_const_iterator(const _Local_iterator<_Key, _Value, _ExtractKey, 1330 _Hash, _RangeHash, _Unused, 1331 __constant_iterators, 1332 __cache>& __x) 1333 : __base_type(__x) 1334 { } 1335 1336 reference 1337 operator*() const 1338 { return this->_M_cur->_M_v(); } 1339 1340 pointer 1341 operator->() const 1342 { return this->_M_cur->_M_valptr(); } 1343 1344 _Local_const_iterator& 1345 operator++() 1346 { 1347 this->_M_incr(); 1348 return *this; 1349 } 1350 1351 _Local_const_iterator 1352 operator++(int) 1353 { 1354 _Local_const_iterator __tmp(*this); 1355 this->_M_incr(); 1356 return __tmp; 1357 } 1358 }; 1359 1360 /** 1361 * Primary class template _Hashtable_base. 1362 * 1363 * Helper class adding management of _Equal functor to 1364 * _Hash_code_base type. 1365 * 1366 * Base class templates are: 1367 * - __detail::_Hash_code_base 1368 */ 1369 template<typename _Key, typename _Value, typename _ExtractKey, 1370 typename _Equal, typename _Hash, typename _RangeHash, 1371 typename _Unused, typename _Traits> 1372 struct _Hashtable_base 1373 : public _Hash_code_base<_Key, _Value, _ExtractKey, _Hash, _RangeHash, 1374 _Unused, _Traits::__hash_cached::value> 1375 { 1376 public: 1377 using key_type = _Key; 1378 using value_type = _Value; 1379 using key_equal = _Equal; 1380 using size_type = size_t; 1381 using difference_type = ptrdiff_t; 1382 1383 using __traits_type = _Traits; 1384 using __hash_cached = typename __traits_type::__hash_cached; 1385 1386 using __hash_code_base = _Hash_code_base<_Key, _Value, _ExtractKey, 1387 _Hash, _RangeHash, _Unused, 1388 __hash_cached::value>; 1389 1390 using __hash_code = typename __hash_code_base::__hash_code; 1391 1392 protected: 1393 [[__no_unique_address__]] _Hashtable_ebo_helper<_Equal> _M_equal{}; 1394 1395 _Hashtable_base() = default; 1396 1397 _Hashtable_base(const _Hash& __hash, const _Equal& __eq) 1398 : __hash_code_base(__hash), _M_equal{__eq} 1399 { } 1400 1401 bool 1402 _M_key_equals(const _Key& __k, 1403 const _Hash_node_value<_Value, 1404 __hash_cached::value>& __n) const 1405 { 1406 static_assert(__is_invocable<const _Equal&, const _Key&, const _Key&>{}, 1407 "key equality predicate must be invocable with two arguments of " 1408 "key type"); 1409 return _M_eq()(__k, _ExtractKey{}(__n._M_v())); 1410 } 1411 1412 template<typename _Kt> 1413 bool 1414 _M_key_equals_tr(const _Kt& __k, 1415 const _Hash_node_value<_Value, 1416 __hash_cached::value>& __n) const 1417 { 1418 static_assert( 1419 __is_invocable<const _Equal&, const _Kt&, const _Key&>{}, 1420 "key equality predicate must be invocable with the argument type " 1421 "and the key type"); 1422 return _M_eq()(__k, _ExtractKey{}(__n._M_v())); 1423 } 1424 1425 #pragma GCC diagnostic push 1426 #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr 1427 bool 1428 _M_equals(const _Key& __k, __hash_code __c, 1429 const _Hash_node_value<_Value, __hash_cached::value>& __n) const 1430 { 1431 if constexpr (__hash_cached::value) 1432 if (__c != __n._M_hash_code) 1433 return false; 1434 1435 return _M_key_equals(__k, __n); 1436 } 1437 1438 template<typename _Kt> 1439 bool 1440 _M_equals_tr(const _Kt& __k, __hash_code __c, 1441 const _Hash_node_value<_Value, 1442 __hash_cached::value>& __n) const 1443 { 1444 if constexpr (__hash_cached::value) 1445 if (__c != __n._M_hash_code) 1446 return false; 1447 1448 return _M_key_equals_tr(__k, __n); 1449 } 1450 1451 bool 1452 _M_node_equals( 1453 const _Hash_node_value<_Value, __hash_cached::value>& __lhn, 1454 const _Hash_node_value<_Value, __hash_cached::value>& __rhn) const 1455 { 1456 if constexpr (__hash_cached::value) 1457 if (__lhn._M_hash_code != __rhn._M_hash_code) 1458 return false; 1459 1460 return _M_key_equals(_ExtractKey{}(__lhn._M_v()), __rhn); 1461 } 1462 #pragma GCC diagnostic pop 1463 1464 const _Equal& 1465 _M_eq() const noexcept { return _M_equal._M_obj; } 1466 }; 1467 1468 /** 1469 * This type deals with all allocation and keeps an allocator instance. 1470 */ 1471 template<typename _NodeAlloc> 1472 struct _Hashtable_alloc 1473 { 1474 private: 1475 [[__no_unique_address__]] _Hashtable_ebo_helper<_NodeAlloc> _M_alloc{}; 1476 1477 template<typename> 1478 struct __get_value_type; 1479 template<typename _Val, bool _Cache_hash_code> 1480 struct __get_value_type<_Hash_node<_Val, _Cache_hash_code>> 1481 { using type = _Val; }; 1482 1483 public: 1484 using __node_type = typename _NodeAlloc::value_type; 1485 using __node_alloc_type = _NodeAlloc; 1486 // Use __gnu_cxx to benefit from _S_always_equal and al. 1487 using __node_alloc_traits = __gnu_cxx::__alloc_traits<__node_alloc_type>; 1488 1489 using __value_alloc_traits = typename __node_alloc_traits::template 1490 rebind_traits<typename __get_value_type<__node_type>::type>; 1491 1492 using __node_ptr = __node_type*; 1493 using __node_base = _Hash_node_base; 1494 using __node_base_ptr = __node_base*; 1495 using __buckets_alloc_type = 1496 __alloc_rebind<__node_alloc_type, __node_base_ptr>; 1497 using __buckets_alloc_traits = std::allocator_traits<__buckets_alloc_type>; 1498 using __buckets_ptr = __node_base_ptr*; 1499 1500 _Hashtable_alloc() = default; 1501 _Hashtable_alloc(const _Hashtable_alloc&) = default; 1502 _Hashtable_alloc(_Hashtable_alloc&&) = default; 1503 1504 template<typename _Alloc> 1505 _Hashtable_alloc(_Alloc&& __a) 1506 : _M_alloc{std::forward<_Alloc>(__a)} 1507 { } 1508 1509 __node_alloc_type& 1510 _M_node_allocator() 1511 { return _M_alloc._M_obj; } 1512 1513 const __node_alloc_type& 1514 _M_node_allocator() const 1515 { return _M_alloc._M_obj; } 1516 1517 // Allocate a node and construct an element within it. 1518 template<typename... _Args> 1519 __node_ptr 1520 _M_allocate_node(_Args&&... __args); 1521 1522 // Destroy the element within a node and deallocate the node. 1523 void 1524 _M_deallocate_node(__node_ptr __n); 1525 1526 // Deallocate a node. 1527 void 1528 _M_deallocate_node_ptr(__node_ptr __n); 1529 1530 // Deallocate the linked list of nodes pointed to by __n. 1531 // The elements within the nodes are destroyed. 1532 void 1533 _M_deallocate_nodes(__node_ptr __n); 1534 1535 __buckets_ptr 1536 _M_allocate_buckets(size_t __bkt_count); 1537 1538 void 1539 _M_deallocate_buckets(__buckets_ptr, size_t __bkt_count); 1540 }; 1541 1542 // Definitions of class template _Hashtable_alloc's out-of-line member 1543 // functions. 1544 template<typename _NodeAlloc> 1545 template<typename... _Args> 1546 auto 1547 _Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&&... __args) 1548 -> __node_ptr 1549 { 1550 auto& __alloc = _M_node_allocator(); 1551 auto __nptr = __node_alloc_traits::allocate(__alloc, 1); 1552 __node_ptr __n = std::__to_address(__nptr); 1553 __try 1554 { 1555 ::new ((void*)__n) __node_type; 1556 __node_alloc_traits::construct(__alloc, __n->_M_valptr(), 1557 std::forward<_Args>(__args)...); 1558 return __n; 1559 } 1560 __catch(...) 1561 { 1562 __n->~__node_type(); 1563 __node_alloc_traits::deallocate(__alloc, __nptr, 1); 1564 __throw_exception_again; 1565 } 1566 } 1567 1568 template<typename _NodeAlloc> 1569 void 1570 _Hashtable_alloc<_NodeAlloc>::_M_deallocate_node(__node_ptr __n) 1571 { 1572 __node_alloc_traits::destroy(_M_node_allocator(), __n->_M_valptr()); 1573 _M_deallocate_node_ptr(__n); 1574 } 1575 1576 template<typename _NodeAlloc> 1577 void 1578 _Hashtable_alloc<_NodeAlloc>::_M_deallocate_node_ptr(__node_ptr __n) 1579 { 1580 using _Ptr = typename __node_alloc_traits::pointer; 1581 auto __ptr = std::pointer_traits<_Ptr>::pointer_to(*__n); 1582 __n->~__node_type(); 1583 __node_alloc_traits::deallocate(_M_node_allocator(), __ptr, 1); 1584 } 1585 1586 template<typename _NodeAlloc> 1587 void 1588 _Hashtable_alloc<_NodeAlloc>::_M_deallocate_nodes(__node_ptr __n) 1589 { 1590 while (__n) 1591 { 1592 __node_ptr __tmp = __n; 1593 __n = __n->_M_next(); 1594 _M_deallocate_node(__tmp); 1595 } 1596 } 1597 1598 template<typename _NodeAlloc> 1599 auto 1600 _Hashtable_alloc<_NodeAlloc>::_M_allocate_buckets(size_t __bkt_count) 1601 -> __buckets_ptr 1602 { 1603 __buckets_alloc_type __alloc(_M_node_allocator()); 1604 1605 auto __ptr = __buckets_alloc_traits::allocate(__alloc, __bkt_count); 1606 __buckets_ptr __p = std::__to_address(__ptr); 1607 __builtin_memset(__p, 0, __bkt_count * sizeof(__node_base_ptr)); 1608 return __p; 1609 } 1610 1611 template<typename _NodeAlloc> 1612 void 1613 _Hashtable_alloc<_NodeAlloc>:: 1614 _M_deallocate_buckets(__buckets_ptr __bkts, size_t __bkt_count) 1615 { 1616 using _Ptr = typename __buckets_alloc_traits::pointer; 1617 auto __ptr = std::pointer_traits<_Ptr>::pointer_to(*__bkts); 1618 __buckets_alloc_type __alloc(_M_node_allocator()); 1619 __buckets_alloc_traits::deallocate(__alloc, __ptr, __bkt_count); 1620 } 1621 1622 ///@} hashtable-detail 1623 } // namespace __detail 1624 /// @endcond 1625 _GLIBCXX_END_NAMESPACE_VERSION 1626 } // namespace std 1627 1628 #endif // _HASHTABLE_POLICY_H