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