138fd1498Szrj // hashtable.h header -*- C++ -*- 238fd1498Szrj 338fd1498Szrj // Copyright (C) 2007-2018 Free Software Foundation, Inc. 438fd1498Szrj // 538fd1498Szrj // This file is part of the GNU ISO C++ Library. This library is free 638fd1498Szrj // software; you can redistribute it and/or modify it under the 738fd1498Szrj // terms of the GNU General Public License as published by the 838fd1498Szrj // Free Software Foundation; either version 3, or (at your option) 938fd1498Szrj // any later version. 1038fd1498Szrj 1138fd1498Szrj // This library is distributed in the hope that it will be useful, 1238fd1498Szrj // but WITHOUT ANY WARRANTY; without even the implied warranty of 1338fd1498Szrj // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1438fd1498Szrj // GNU General Public License for more details. 1538fd1498Szrj 1638fd1498Szrj // Under Section 7 of GPL version 3, you are granted additional 1738fd1498Szrj // permissions described in the GCC Runtime Library Exception, version 1838fd1498Szrj // 3.1, as published by the Free Software Foundation. 1938fd1498Szrj 2038fd1498Szrj // You should have received a copy of the GNU General Public License and 2138fd1498Szrj // a copy of the GCC Runtime Library Exception along with this program; 2238fd1498Szrj // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 2338fd1498Szrj // <http://www.gnu.org/licenses/>. 2438fd1498Szrj 2538fd1498Szrj /** @file bits/hashtable.h 2638fd1498Szrj * This is an internal header file, included by other library headers. 2738fd1498Szrj * Do not attempt to use it directly. @headername{unordered_map, unordered_set} 2838fd1498Szrj */ 2938fd1498Szrj 3038fd1498Szrj #ifndef _HASHTABLE_H 3138fd1498Szrj #define _HASHTABLE_H 1 3238fd1498Szrj 3338fd1498Szrj #pragma GCC system_header 3438fd1498Szrj 3538fd1498Szrj #include <bits/hashtable_policy.h> 3638fd1498Szrj #if __cplusplus > 201402L 3738fd1498Szrj # include <bits/node_handle.h> 3838fd1498Szrj #endif 3938fd1498Szrj 4038fd1498Szrj namespace std _GLIBCXX_VISIBILITY(default) 4138fd1498Szrj { 4238fd1498Szrj _GLIBCXX_BEGIN_NAMESPACE_VERSION 4338fd1498Szrj 4438fd1498Szrj template<typename _Tp, typename _Hash> 4538fd1498Szrj using __cache_default 4638fd1498Szrj = __not_<__and_<// Do not cache for fast hasher. 4738fd1498Szrj __is_fast_hash<_Hash>, 4838fd1498Szrj // Mandatory to have erase not throwing. 4938fd1498Szrj __is_nothrow_invocable<const _Hash&, const _Tp&>>>; 5038fd1498Szrj 5138fd1498Szrj /** 5238fd1498Szrj * Primary class template _Hashtable. 5338fd1498Szrj * 5438fd1498Szrj * @ingroup hashtable-detail 5538fd1498Szrj * 5638fd1498Szrj * @tparam _Value CopyConstructible type. 5738fd1498Szrj * 5838fd1498Szrj * @tparam _Key CopyConstructible type. 5938fd1498Szrj * 6038fd1498Szrj * @tparam _Alloc An allocator type 6138fd1498Szrj * ([lib.allocator.requirements]) whose _Alloc::value_type is 6238fd1498Szrj * _Value. As a conforming extension, we allow for 6338fd1498Szrj * _Alloc::value_type != _Value. 6438fd1498Szrj * 6538fd1498Szrj * @tparam _ExtractKey Function object that takes an object of type 6638fd1498Szrj * _Value and returns a value of type _Key. 6738fd1498Szrj * 6838fd1498Szrj * @tparam _Equal Function object that takes two objects of type k 6938fd1498Szrj * and returns a bool-like value that is true if the two objects 7038fd1498Szrj * are considered equal. 7138fd1498Szrj * 7238fd1498Szrj * @tparam _H1 The hash function. A unary function object with 7338fd1498Szrj * argument type _Key and result type size_t. Return values should 7438fd1498Szrj * be distributed over the entire range [0, numeric_limits<size_t>:::max()]. 7538fd1498Szrj * 7638fd1498Szrj * @tparam _H2 The range-hashing function (in the terminology of 7738fd1498Szrj * Tavori and Dreizin). A binary function object whose argument 7838fd1498Szrj * types and result type are all size_t. Given arguments r and N, 7938fd1498Szrj * the return value is in the range [0, N). 8038fd1498Szrj * 8138fd1498Szrj * @tparam _Hash The ranged hash function (Tavori and Dreizin). A 8238fd1498Szrj * binary function whose argument types are _Key and size_t and 8338fd1498Szrj * whose result type is size_t. Given arguments k and N, the 8438fd1498Szrj * return value is in the range [0, N). Default: hash(k, N) = 8538fd1498Szrj * h2(h1(k), N). If _Hash is anything other than the default, _H1 8638fd1498Szrj * and _H2 are ignored. 8738fd1498Szrj * 8838fd1498Szrj * @tparam _RehashPolicy Policy class with three members, all of 8938fd1498Szrj * which govern the bucket count. _M_next_bkt(n) returns a bucket 9038fd1498Szrj * count no smaller than n. _M_bkt_for_elements(n) returns a 9138fd1498Szrj * bucket count appropriate for an element count of n. 9238fd1498Szrj * _M_need_rehash(n_bkt, n_elt, n_ins) determines whether, if the 9338fd1498Szrj * current bucket count is n_bkt and the current element count is 9438fd1498Szrj * n_elt, we need to increase the bucket count. If so, returns 9538fd1498Szrj * make_pair(true, n), where n is the new bucket count. If not, 9638fd1498Szrj * returns make_pair(false, <anything>) 9738fd1498Szrj * 9838fd1498Szrj * @tparam _Traits Compile-time class with three boolean 9938fd1498Szrj * std::integral_constant members: __cache_hash_code, __constant_iterators, 10038fd1498Szrj * __unique_keys. 10138fd1498Szrj * 10238fd1498Szrj * Each _Hashtable data structure has: 10338fd1498Szrj * 10438fd1498Szrj * - _Bucket[] _M_buckets 10538fd1498Szrj * - _Hash_node_base _M_before_begin 10638fd1498Szrj * - size_type _M_bucket_count 10738fd1498Szrj * - size_type _M_element_count 10838fd1498Szrj * 10938fd1498Szrj * with _Bucket being _Hash_node* and _Hash_node containing: 11038fd1498Szrj * 11138fd1498Szrj * - _Hash_node* _M_next 11238fd1498Szrj * - Tp _M_value 11338fd1498Szrj * - size_t _M_hash_code if cache_hash_code is true 11438fd1498Szrj * 11538fd1498Szrj * In terms of Standard containers the hashtable is like the aggregation of: 11638fd1498Szrj * 11738fd1498Szrj * - std::forward_list<_Node> containing the elements 11838fd1498Szrj * - std::vector<std::forward_list<_Node>::iterator> representing the buckets 11938fd1498Szrj * 12038fd1498Szrj * The non-empty buckets contain the node before the first node in the 12138fd1498Szrj * bucket. This design makes it possible to implement something like a 12238fd1498Szrj * std::forward_list::insert_after on container insertion and 12338fd1498Szrj * std::forward_list::erase_after on container erase 12438fd1498Szrj * calls. _M_before_begin is equivalent to 12538fd1498Szrj * std::forward_list::before_begin. Empty buckets contain 12638fd1498Szrj * nullptr. Note that one of the non-empty buckets contains 12738fd1498Szrj * &_M_before_begin which is not a dereferenceable node so the 12838fd1498Szrj * node pointer in a bucket shall never be dereferenced, only its 12938fd1498Szrj * next node can be. 13038fd1498Szrj * 13138fd1498Szrj * Walking through a bucket's nodes requires a check on the hash code to 13238fd1498Szrj * see if each node is still in the bucket. Such a design assumes a 13338fd1498Szrj * quite efficient hash functor and is one of the reasons it is 13438fd1498Szrj * highly advisable to set __cache_hash_code to true. 13538fd1498Szrj * 13638fd1498Szrj * The container iterators are simply built from nodes. This way 13738fd1498Szrj * incrementing the iterator is perfectly efficient independent of 13838fd1498Szrj * how many empty buckets there are in the container. 13938fd1498Szrj * 14038fd1498Szrj * On insert we compute the element's hash code and use it to find the 14138fd1498Szrj * bucket index. If the element must be inserted in an empty bucket 14238fd1498Szrj * we add it at the beginning of the singly linked list and make the 14338fd1498Szrj * bucket point to _M_before_begin. The bucket that used to point to 14438fd1498Szrj * _M_before_begin, if any, is updated to point to its new before 14538fd1498Szrj * begin node. 14638fd1498Szrj * 14738fd1498Szrj * On erase, the simple iterator design requires using the hash 14838fd1498Szrj * functor to get the index of the bucket to update. For this 14938fd1498Szrj * reason, when __cache_hash_code is set to false the hash functor must 15038fd1498Szrj * not throw and this is enforced by a static assertion. 15138fd1498Szrj * 15238fd1498Szrj * Functionality is implemented by decomposition into base classes, 15338fd1498Szrj * where the derived _Hashtable class is used in _Map_base, 15438fd1498Szrj * _Insert, _Rehash_base, and _Equality base classes to access the 15538fd1498Szrj * "this" pointer. _Hashtable_base is used in the base classes as a 15638fd1498Szrj * non-recursive, fully-completed-type so that detailed nested type 15738fd1498Szrj * information, such as iterator type and node type, can be 15838fd1498Szrj * used. This is similar to the "Curiously Recurring Template 15938fd1498Szrj * Pattern" (CRTP) technique, but uses a reconstructed, not 16038fd1498Szrj * explicitly passed, template pattern. 16138fd1498Szrj * 16238fd1498Szrj * Base class templates are: 16338fd1498Szrj * - __detail::_Hashtable_base 16438fd1498Szrj * - __detail::_Map_base 16538fd1498Szrj * - __detail::_Insert 16638fd1498Szrj * - __detail::_Rehash_base 16738fd1498Szrj * - __detail::_Equality 16838fd1498Szrj */ 16938fd1498Szrj template<typename _Key, typename _Value, typename _Alloc, 17038fd1498Szrj typename _ExtractKey, typename _Equal, 17138fd1498Szrj typename _H1, typename _H2, typename _Hash, 17238fd1498Szrj typename _RehashPolicy, typename _Traits> 17338fd1498Szrj class _Hashtable 17438fd1498Szrj : public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, 17538fd1498Szrj _H1, _H2, _Hash, _Traits>, 17638fd1498Szrj public __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, 17738fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>, 17838fd1498Szrj public __detail::_Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal, 17938fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>, 18038fd1498Szrj public __detail::_Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, 18138fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>, 18238fd1498Szrj public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, 18338fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>, 18438fd1498Szrj private __detail::_Hashtable_alloc< 18538fd1498Szrj __alloc_rebind<_Alloc, 18638fd1498Szrj __detail::_Hash_node<_Value, 18738fd1498Szrj _Traits::__hash_cached::value>>> 18838fd1498Szrj { 18938fd1498Szrj static_assert(is_same<typename remove_cv<_Value>::type, _Value>::value, 19038fd1498Szrj "unordered container must have a non-const, non-volatile value_type"); 19138fd1498Szrj #ifdef __STRICT_ANSI__ 19238fd1498Szrj static_assert(is_same<typename _Alloc::value_type, _Value>{}, 19338fd1498Szrj "unordered container must have the same value_type as its allocator"); 19438fd1498Szrj #endif 19538fd1498Szrj static_assert(__is_invocable<const _H1&, const _Key&>{}, 19638fd1498Szrj "hash function must be invocable with an argument of key type"); 19738fd1498Szrj static_assert(__is_invocable<const _Equal&, const _Key&, const _Key&>{}, 19838fd1498Szrj "key equality predicate must be invocable with two arguments of " 19938fd1498Szrj "key type"); 20038fd1498Szrj 20138fd1498Szrj using __traits_type = _Traits; 20238fd1498Szrj using __hash_cached = typename __traits_type::__hash_cached; 20338fd1498Szrj using __node_type = __detail::_Hash_node<_Value, __hash_cached::value>; 20438fd1498Szrj using __node_alloc_type = __alloc_rebind<_Alloc, __node_type>; 20538fd1498Szrj 20638fd1498Szrj using __hashtable_alloc = __detail::_Hashtable_alloc<__node_alloc_type>; 20738fd1498Szrj 20838fd1498Szrj using __value_alloc_traits = 20938fd1498Szrj typename __hashtable_alloc::__value_alloc_traits; 21038fd1498Szrj using __node_alloc_traits = 21138fd1498Szrj typename __hashtable_alloc::__node_alloc_traits; 21238fd1498Szrj using __node_base = typename __hashtable_alloc::__node_base; 21338fd1498Szrj using __bucket_type = typename __hashtable_alloc::__bucket_type; 21438fd1498Szrj 21538fd1498Szrj public: 21638fd1498Szrj typedef _Key key_type; 21738fd1498Szrj typedef _Value value_type; 21838fd1498Szrj typedef _Alloc allocator_type; 21938fd1498Szrj typedef _Equal key_equal; 22038fd1498Szrj 22138fd1498Szrj // mapped_type, if present, comes from _Map_base. 22238fd1498Szrj // hasher, if present, comes from _Hash_code_base/_Hashtable_base. 22338fd1498Szrj typedef typename __value_alloc_traits::pointer pointer; 22438fd1498Szrj typedef typename __value_alloc_traits::const_pointer const_pointer; 22538fd1498Szrj typedef value_type& reference; 22638fd1498Szrj typedef const value_type& const_reference; 22738fd1498Szrj 22838fd1498Szrj private: 22938fd1498Szrj using __rehash_type = _RehashPolicy; 23038fd1498Szrj using __rehash_state = typename __rehash_type::_State; 23138fd1498Szrj 23238fd1498Szrj using __constant_iterators = typename __traits_type::__constant_iterators; 23338fd1498Szrj using __unique_keys = typename __traits_type::__unique_keys; 23438fd1498Szrj 23538fd1498Szrj using __key_extract = typename std::conditional< 23638fd1498Szrj __constant_iterators::value, 23738fd1498Szrj __detail::_Identity, 23838fd1498Szrj __detail::_Select1st>::type; 23938fd1498Szrj 24038fd1498Szrj using __hashtable_base = __detail:: 24138fd1498Szrj _Hashtable_base<_Key, _Value, _ExtractKey, 24238fd1498Szrj _Equal, _H1, _H2, _Hash, _Traits>; 24338fd1498Szrj 24438fd1498Szrj using __hash_code_base = typename __hashtable_base::__hash_code_base; 24538fd1498Szrj using __hash_code = typename __hashtable_base::__hash_code; 24638fd1498Szrj using __ireturn_type = typename __hashtable_base::__ireturn_type; 24738fd1498Szrj 24838fd1498Szrj using __map_base = __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, 24938fd1498Szrj _Equal, _H1, _H2, _Hash, 25038fd1498Szrj _RehashPolicy, _Traits>; 25138fd1498Szrj 25238fd1498Szrj using __rehash_base = __detail::_Rehash_base<_Key, _Value, _Alloc, 25338fd1498Szrj _ExtractKey, _Equal, 25438fd1498Szrj _H1, _H2, _Hash, 25538fd1498Szrj _RehashPolicy, _Traits>; 25638fd1498Szrj 25738fd1498Szrj using __eq_base = __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, 25838fd1498Szrj _Equal, _H1, _H2, _Hash, 25938fd1498Szrj _RehashPolicy, _Traits>; 26038fd1498Szrj 26138fd1498Szrj using __reuse_or_alloc_node_type = 26238fd1498Szrj __detail::_ReuseOrAllocNode<__node_alloc_type>; 26338fd1498Szrj 26438fd1498Szrj // Metaprogramming for picking apart hash caching. 26538fd1498Szrj template<typename _Cond> 26638fd1498Szrj using __if_hash_cached = __or_<__not_<__hash_cached>, _Cond>; 26738fd1498Szrj 26838fd1498Szrj template<typename _Cond> 26938fd1498Szrj using __if_hash_not_cached = __or_<__hash_cached, _Cond>; 27038fd1498Szrj 27138fd1498Szrj // Compile-time diagnostics. 27238fd1498Szrj 27338fd1498Szrj // _Hash_code_base has everything protected, so use this derived type to 27438fd1498Szrj // access it. 27538fd1498Szrj struct __hash_code_base_access : __hash_code_base 27638fd1498Szrj { using __hash_code_base::_M_bucket_index; }; 27738fd1498Szrj 27838fd1498Szrj // Getting a bucket index from a node shall not throw because it is used 27938fd1498Szrj // in methods (erase, swap...) that shall not throw. 28038fd1498Szrj static_assert(noexcept(declval<const __hash_code_base_access&>() 28138fd1498Szrj ._M_bucket_index((const __node_type*)nullptr, 28238fd1498Szrj (std::size_t)0)), 28338fd1498Szrj "Cache the hash code or qualify your functors involved" 28438fd1498Szrj " in hash code and bucket index computation with noexcept"); 28538fd1498Szrj 28638fd1498Szrj // Following two static assertions are necessary to guarantee 28738fd1498Szrj // that local_iterator will be default constructible. 28838fd1498Szrj 28938fd1498Szrj // When hash codes are cached local iterator inherits from H2 functor 29038fd1498Szrj // which must then be default constructible. 29138fd1498Szrj static_assert(__if_hash_cached<is_default_constructible<_H2>>::value, 29238fd1498Szrj "Functor used to map hash code to bucket index" 29338fd1498Szrj " must be default constructible"); 29438fd1498Szrj 29538fd1498Szrj template<typename _Keya, typename _Valuea, typename _Alloca, 29638fd1498Szrj typename _ExtractKeya, typename _Equala, 29738fd1498Szrj typename _H1a, typename _H2a, typename _Hasha, 29838fd1498Szrj typename _RehashPolicya, typename _Traitsa, 29938fd1498Szrj bool _Unique_keysa> 30038fd1498Szrj friend struct __detail::_Map_base; 30138fd1498Szrj 30238fd1498Szrj template<typename _Keya, typename _Valuea, typename _Alloca, 30338fd1498Szrj typename _ExtractKeya, typename _Equala, 30438fd1498Szrj typename _H1a, typename _H2a, typename _Hasha, 30538fd1498Szrj typename _RehashPolicya, typename _Traitsa> 30638fd1498Szrj friend struct __detail::_Insert_base; 30738fd1498Szrj 30838fd1498Szrj template<typename _Keya, typename _Valuea, typename _Alloca, 30938fd1498Szrj typename _ExtractKeya, typename _Equala, 31038fd1498Szrj typename _H1a, typename _H2a, typename _Hasha, 31138fd1498Szrj typename _RehashPolicya, typename _Traitsa, 31238fd1498Szrj bool _Constant_iteratorsa> 31338fd1498Szrj friend struct __detail::_Insert; 31438fd1498Szrj 31538fd1498Szrj public: 31638fd1498Szrj using size_type = typename __hashtable_base::size_type; 31738fd1498Szrj using difference_type = typename __hashtable_base::difference_type; 31838fd1498Szrj 31938fd1498Szrj using iterator = typename __hashtable_base::iterator; 32038fd1498Szrj using const_iterator = typename __hashtable_base::const_iterator; 32138fd1498Szrj 32238fd1498Szrj using local_iterator = typename __hashtable_base::local_iterator; 32338fd1498Szrj using const_local_iterator = typename __hashtable_base:: 32438fd1498Szrj const_local_iterator; 32538fd1498Szrj 32638fd1498Szrj #if __cplusplus > 201402L 32738fd1498Szrj using node_type = _Node_handle<_Key, _Value, __node_alloc_type>; 32838fd1498Szrj using insert_return_type = _Node_insert_return<iterator, node_type>; 32938fd1498Szrj #endif 33038fd1498Szrj 33138fd1498Szrj private: 33238fd1498Szrj __bucket_type* _M_buckets = &_M_single_bucket; 33338fd1498Szrj size_type _M_bucket_count = 1; 33438fd1498Szrj __node_base _M_before_begin; 33538fd1498Szrj size_type _M_element_count = 0; 33638fd1498Szrj _RehashPolicy _M_rehash_policy; 33738fd1498Szrj 33838fd1498Szrj // A single bucket used when only need for 1 bucket. Especially 33938fd1498Szrj // interesting in move semantic to leave hashtable with only 1 buckets 34038fd1498Szrj // which is not allocated so that we can have those operations noexcept 34138fd1498Szrj // qualified. 34238fd1498Szrj // Note that we can't leave hashtable with 0 bucket without adding 34338fd1498Szrj // numerous checks in the code to avoid 0 modulus. 34438fd1498Szrj __bucket_type _M_single_bucket = nullptr; 34538fd1498Szrj 34638fd1498Szrj bool 34738fd1498Szrj _M_uses_single_bucket(__bucket_type* __bkts) const 34838fd1498Szrj { return __builtin_expect(__bkts == &_M_single_bucket, false); } 34938fd1498Szrj 35038fd1498Szrj bool 35138fd1498Szrj _M_uses_single_bucket() const 35238fd1498Szrj { return _M_uses_single_bucket(_M_buckets); } 35338fd1498Szrj 35438fd1498Szrj __hashtable_alloc& 35538fd1498Szrj _M_base_alloc() { return *this; } 35638fd1498Szrj 35738fd1498Szrj __bucket_type* 35838fd1498Szrj _M_allocate_buckets(size_type __n) 35938fd1498Szrj { 36038fd1498Szrj if (__builtin_expect(__n == 1, false)) 36138fd1498Szrj { 36238fd1498Szrj _M_single_bucket = nullptr; 36338fd1498Szrj return &_M_single_bucket; 36438fd1498Szrj } 36538fd1498Szrj 36638fd1498Szrj return __hashtable_alloc::_M_allocate_buckets(__n); 36738fd1498Szrj } 36838fd1498Szrj 36938fd1498Szrj void 37038fd1498Szrj _M_deallocate_buckets(__bucket_type* __bkts, size_type __n) 37138fd1498Szrj { 37238fd1498Szrj if (_M_uses_single_bucket(__bkts)) 37338fd1498Szrj return; 37438fd1498Szrj 37538fd1498Szrj __hashtable_alloc::_M_deallocate_buckets(__bkts, __n); 37638fd1498Szrj } 37738fd1498Szrj 37838fd1498Szrj void 37938fd1498Szrj _M_deallocate_buckets() 38038fd1498Szrj { _M_deallocate_buckets(_M_buckets, _M_bucket_count); } 38138fd1498Szrj 38238fd1498Szrj // Gets bucket begin, deals with the fact that non-empty buckets contain 38338fd1498Szrj // their before begin node. 38438fd1498Szrj __node_type* 38538fd1498Szrj _M_bucket_begin(size_type __bkt) const; 38638fd1498Szrj 38738fd1498Szrj __node_type* 38838fd1498Szrj _M_begin() const 38938fd1498Szrj { return static_cast<__node_type*>(_M_before_begin._M_nxt); } 39038fd1498Szrj 39138fd1498Szrj template<typename _NodeGenerator> 39238fd1498Szrj void 39338fd1498Szrj _M_assign(const _Hashtable&, const _NodeGenerator&); 39438fd1498Szrj 39538fd1498Szrj void 39638fd1498Szrj _M_move_assign(_Hashtable&&, std::true_type); 39738fd1498Szrj 39838fd1498Szrj void 39938fd1498Szrj _M_move_assign(_Hashtable&&, std::false_type); 40038fd1498Szrj 40138fd1498Szrj void 40238fd1498Szrj _M_reset() noexcept; 40338fd1498Szrj 40438fd1498Szrj _Hashtable(const _H1& __h1, const _H2& __h2, const _Hash& __h, 40538fd1498Szrj const _Equal& __eq, const _ExtractKey& __exk, 40638fd1498Szrj const allocator_type& __a) 40738fd1498Szrj : __hashtable_base(__exk, __h1, __h2, __h, __eq), 40838fd1498Szrj __hashtable_alloc(__node_alloc_type(__a)) 40938fd1498Szrj { } 41038fd1498Szrj 41138fd1498Szrj public: 41238fd1498Szrj // Constructor, destructor, assignment, swap 41338fd1498Szrj _Hashtable() = default; 41438fd1498Szrj _Hashtable(size_type __bucket_hint, 41538fd1498Szrj const _H1&, const _H2&, const _Hash&, 41638fd1498Szrj const _Equal&, const _ExtractKey&, 41738fd1498Szrj const allocator_type&); 41838fd1498Szrj 41938fd1498Szrj template<typename _InputIterator> 42038fd1498Szrj _Hashtable(_InputIterator __first, _InputIterator __last, 42138fd1498Szrj size_type __bucket_hint, 42238fd1498Szrj const _H1&, const _H2&, const _Hash&, 42338fd1498Szrj const _Equal&, const _ExtractKey&, 42438fd1498Szrj const allocator_type&); 42538fd1498Szrj 42638fd1498Szrj _Hashtable(const _Hashtable&); 42738fd1498Szrj 42838fd1498Szrj _Hashtable(_Hashtable&&) noexcept; 42938fd1498Szrj 43038fd1498Szrj _Hashtable(const _Hashtable&, const allocator_type&); 43138fd1498Szrj 43238fd1498Szrj _Hashtable(_Hashtable&&, const allocator_type&); 43338fd1498Szrj 43438fd1498Szrj // Use delegating constructors. 43538fd1498Szrj explicit 43638fd1498Szrj _Hashtable(const allocator_type& __a) 43738fd1498Szrj : __hashtable_alloc(__node_alloc_type(__a)) 43838fd1498Szrj { } 43938fd1498Szrj 44038fd1498Szrj explicit 44138fd1498Szrj _Hashtable(size_type __n, 44238fd1498Szrj const _H1& __hf = _H1(), 44338fd1498Szrj const key_equal& __eql = key_equal(), 44438fd1498Szrj const allocator_type& __a = allocator_type()) 44538fd1498Szrj : _Hashtable(__n, __hf, _H2(), _Hash(), __eql, 44638fd1498Szrj __key_extract(), __a) 44738fd1498Szrj { } 44838fd1498Szrj 44938fd1498Szrj template<typename _InputIterator> 45038fd1498Szrj _Hashtable(_InputIterator __f, _InputIterator __l, 45138fd1498Szrj size_type __n = 0, 45238fd1498Szrj const _H1& __hf = _H1(), 45338fd1498Szrj const key_equal& __eql = key_equal(), 45438fd1498Szrj const allocator_type& __a = allocator_type()) 45538fd1498Szrj : _Hashtable(__f, __l, __n, __hf, _H2(), _Hash(), __eql, 45638fd1498Szrj __key_extract(), __a) 45738fd1498Szrj { } 45838fd1498Szrj 45938fd1498Szrj _Hashtable(initializer_list<value_type> __l, 46038fd1498Szrj size_type __n = 0, 46138fd1498Szrj const _H1& __hf = _H1(), 46238fd1498Szrj const key_equal& __eql = key_equal(), 46338fd1498Szrj const allocator_type& __a = allocator_type()) 46438fd1498Szrj : _Hashtable(__l.begin(), __l.end(), __n, __hf, _H2(), _Hash(), __eql, 46538fd1498Szrj __key_extract(), __a) 46638fd1498Szrj { } 46738fd1498Szrj 46838fd1498Szrj _Hashtable& 46938fd1498Szrj operator=(const _Hashtable& __ht); 47038fd1498Szrj 47138fd1498Szrj _Hashtable& 47238fd1498Szrj operator=(_Hashtable&& __ht) 47338fd1498Szrj noexcept(__node_alloc_traits::_S_nothrow_move() 47438fd1498Szrj && is_nothrow_move_assignable<_H1>::value 47538fd1498Szrj && is_nothrow_move_assignable<_Equal>::value) 47638fd1498Szrj { 47738fd1498Szrj constexpr bool __move_storage = 47838fd1498Szrj __node_alloc_traits::_S_propagate_on_move_assign() 47938fd1498Szrj || __node_alloc_traits::_S_always_equal(); 48038fd1498Szrj _M_move_assign(std::move(__ht), __bool_constant<__move_storage>()); 48138fd1498Szrj return *this; 48238fd1498Szrj } 48338fd1498Szrj 48438fd1498Szrj _Hashtable& 48538fd1498Szrj operator=(initializer_list<value_type> __l) 48638fd1498Szrj { 48738fd1498Szrj __reuse_or_alloc_node_type __roan(_M_begin(), *this); 48838fd1498Szrj _M_before_begin._M_nxt = nullptr; 48938fd1498Szrj clear(); 49038fd1498Szrj this->_M_insert_range(__l.begin(), __l.end(), __roan, __unique_keys()); 49138fd1498Szrj return *this; 49238fd1498Szrj } 49338fd1498Szrj 49438fd1498Szrj ~_Hashtable() noexcept; 49538fd1498Szrj 49638fd1498Szrj void 49738fd1498Szrj swap(_Hashtable&) 49838fd1498Szrj noexcept(__and_<__is_nothrow_swappable<_H1>, 49938fd1498Szrj __is_nothrow_swappable<_Equal>>::value); 50038fd1498Szrj 50138fd1498Szrj // Basic container operations 50238fd1498Szrj iterator 50338fd1498Szrj begin() noexcept 50438fd1498Szrj { return iterator(_M_begin()); } 50538fd1498Szrj 50638fd1498Szrj const_iterator 50738fd1498Szrj begin() const noexcept 50838fd1498Szrj { return const_iterator(_M_begin()); } 50938fd1498Szrj 51038fd1498Szrj iterator 51138fd1498Szrj end() noexcept 51238fd1498Szrj { return iterator(nullptr); } 51338fd1498Szrj 51438fd1498Szrj const_iterator 51538fd1498Szrj end() const noexcept 51638fd1498Szrj { return const_iterator(nullptr); } 51738fd1498Szrj 51838fd1498Szrj const_iterator 51938fd1498Szrj cbegin() const noexcept 52038fd1498Szrj { return const_iterator(_M_begin()); } 52138fd1498Szrj 52238fd1498Szrj const_iterator 52338fd1498Szrj cend() const noexcept 52438fd1498Szrj { return const_iterator(nullptr); } 52538fd1498Szrj 52638fd1498Szrj size_type 52738fd1498Szrj size() const noexcept 52838fd1498Szrj { return _M_element_count; } 52938fd1498Szrj 53038fd1498Szrj bool 53138fd1498Szrj empty() const noexcept 53238fd1498Szrj { return size() == 0; } 53338fd1498Szrj 53438fd1498Szrj allocator_type 53538fd1498Szrj get_allocator() const noexcept 53638fd1498Szrj { return allocator_type(this->_M_node_allocator()); } 53738fd1498Szrj 53838fd1498Szrj size_type 53938fd1498Szrj max_size() const noexcept 54038fd1498Szrj { return __node_alloc_traits::max_size(this->_M_node_allocator()); } 54138fd1498Szrj 54238fd1498Szrj // Observers 54338fd1498Szrj key_equal 54438fd1498Szrj key_eq() const 54538fd1498Szrj { return this->_M_eq(); } 54638fd1498Szrj 54738fd1498Szrj // hash_function, if present, comes from _Hash_code_base. 54838fd1498Szrj 54938fd1498Szrj // Bucket operations 55038fd1498Szrj size_type 55138fd1498Szrj bucket_count() const noexcept 55238fd1498Szrj { return _M_bucket_count; } 55338fd1498Szrj 55438fd1498Szrj size_type 55538fd1498Szrj max_bucket_count() const noexcept 55638fd1498Szrj { return max_size(); } 55738fd1498Szrj 55838fd1498Szrj size_type 55938fd1498Szrj bucket_size(size_type __n) const 56038fd1498Szrj { return std::distance(begin(__n), end(__n)); } 56138fd1498Szrj 56238fd1498Szrj size_type 56338fd1498Szrj bucket(const key_type& __k) const 56438fd1498Szrj { return _M_bucket_index(__k, this->_M_hash_code(__k)); } 56538fd1498Szrj 56638fd1498Szrj local_iterator 56738fd1498Szrj begin(size_type __n) 56838fd1498Szrj { 56938fd1498Szrj return local_iterator(*this, _M_bucket_begin(__n), 57038fd1498Szrj __n, _M_bucket_count); 57138fd1498Szrj } 57238fd1498Szrj 57338fd1498Szrj local_iterator 57438fd1498Szrj end(size_type __n) 57538fd1498Szrj { return local_iterator(*this, nullptr, __n, _M_bucket_count); } 57638fd1498Szrj 57738fd1498Szrj const_local_iterator 57838fd1498Szrj begin(size_type __n) const 57938fd1498Szrj { 58038fd1498Szrj return const_local_iterator(*this, _M_bucket_begin(__n), 58138fd1498Szrj __n, _M_bucket_count); 58238fd1498Szrj } 58338fd1498Szrj 58438fd1498Szrj const_local_iterator 58538fd1498Szrj end(size_type __n) const 58638fd1498Szrj { return const_local_iterator(*this, nullptr, __n, _M_bucket_count); } 58738fd1498Szrj 58838fd1498Szrj // DR 691. 58938fd1498Szrj const_local_iterator 59038fd1498Szrj cbegin(size_type __n) const 59138fd1498Szrj { 59238fd1498Szrj return const_local_iterator(*this, _M_bucket_begin(__n), 59338fd1498Szrj __n, _M_bucket_count); 59438fd1498Szrj } 59538fd1498Szrj 59638fd1498Szrj const_local_iterator 59738fd1498Szrj cend(size_type __n) const 59838fd1498Szrj { return const_local_iterator(*this, nullptr, __n, _M_bucket_count); } 59938fd1498Szrj 60038fd1498Szrj float 60138fd1498Szrj load_factor() const noexcept 60238fd1498Szrj { 60338fd1498Szrj return static_cast<float>(size()) / static_cast<float>(bucket_count()); 60438fd1498Szrj } 60538fd1498Szrj 60638fd1498Szrj // max_load_factor, if present, comes from _Rehash_base. 60738fd1498Szrj 60838fd1498Szrj // Generalization of max_load_factor. Extension, not found in 60938fd1498Szrj // TR1. Only useful if _RehashPolicy is something other than 61038fd1498Szrj // the default. 61138fd1498Szrj const _RehashPolicy& 61238fd1498Szrj __rehash_policy() const 61338fd1498Szrj { return _M_rehash_policy; } 61438fd1498Szrj 61538fd1498Szrj void 61638fd1498Szrj __rehash_policy(const _RehashPolicy& __pol) 61738fd1498Szrj { _M_rehash_policy = __pol; } 61838fd1498Szrj 61938fd1498Szrj // Lookup. 62038fd1498Szrj iterator 62138fd1498Szrj find(const key_type& __k); 62238fd1498Szrj 62338fd1498Szrj const_iterator 62438fd1498Szrj find(const key_type& __k) const; 62538fd1498Szrj 62638fd1498Szrj size_type 62738fd1498Szrj count(const key_type& __k) const; 62838fd1498Szrj 62938fd1498Szrj std::pair<iterator, iterator> 63038fd1498Szrj equal_range(const key_type& __k); 63138fd1498Szrj 63238fd1498Szrj std::pair<const_iterator, const_iterator> 63338fd1498Szrj equal_range(const key_type& __k) const; 63438fd1498Szrj 63538fd1498Szrj protected: 63638fd1498Szrj // Bucket index computation helpers. 63738fd1498Szrj size_type 63838fd1498Szrj _M_bucket_index(__node_type* __n) const noexcept 63938fd1498Szrj { return __hash_code_base::_M_bucket_index(__n, _M_bucket_count); } 64038fd1498Szrj 64138fd1498Szrj size_type 64238fd1498Szrj _M_bucket_index(const key_type& __k, __hash_code __c) const 64338fd1498Szrj { return __hash_code_base::_M_bucket_index(__k, __c, _M_bucket_count); } 64438fd1498Szrj 64538fd1498Szrj // Find and insert helper functions and types 64638fd1498Szrj // Find the node before the one matching the criteria. 64738fd1498Szrj __node_base* 64838fd1498Szrj _M_find_before_node(size_type, const key_type&, __hash_code) const; 64938fd1498Szrj 65038fd1498Szrj __node_type* 65138fd1498Szrj _M_find_node(size_type __bkt, const key_type& __key, 65238fd1498Szrj __hash_code __c) const 65338fd1498Szrj { 65438fd1498Szrj __node_base* __before_n = _M_find_before_node(__bkt, __key, __c); 65538fd1498Szrj if (__before_n) 65638fd1498Szrj return static_cast<__node_type*>(__before_n->_M_nxt); 65738fd1498Szrj return nullptr; 65838fd1498Szrj } 65938fd1498Szrj 66038fd1498Szrj // Insert a node at the beginning of a bucket. 66138fd1498Szrj void 66238fd1498Szrj _M_insert_bucket_begin(size_type, __node_type*); 66338fd1498Szrj 66438fd1498Szrj // Remove the bucket first node 66538fd1498Szrj void 66638fd1498Szrj _M_remove_bucket_begin(size_type __bkt, __node_type* __next_n, 66738fd1498Szrj size_type __next_bkt); 66838fd1498Szrj 66938fd1498Szrj // Get the node before __n in the bucket __bkt 67038fd1498Szrj __node_base* 67138fd1498Szrj _M_get_previous_node(size_type __bkt, __node_base* __n); 67238fd1498Szrj 67338fd1498Szrj // Insert node with hash code __code, in bucket bkt if no rehash (assumes 67438fd1498Szrj // no element with its key already present). Take ownership of the node, 67538fd1498Szrj // deallocate it on exception. 67638fd1498Szrj iterator 67738fd1498Szrj _M_insert_unique_node(size_type __bkt, __hash_code __code, 67838fd1498Szrj __node_type* __n, size_type __n_elt = 1); 67938fd1498Szrj 68038fd1498Szrj // Insert node with hash code __code. Take ownership of the node, 68138fd1498Szrj // deallocate it on exception. 68238fd1498Szrj iterator 68338fd1498Szrj _M_insert_multi_node(__node_type* __hint, 68438fd1498Szrj __hash_code __code, __node_type* __n); 68538fd1498Szrj 68638fd1498Szrj template<typename... _Args> 68738fd1498Szrj std::pair<iterator, bool> 68838fd1498Szrj _M_emplace(std::true_type, _Args&&... __args); 68938fd1498Szrj 69038fd1498Szrj template<typename... _Args> 69138fd1498Szrj iterator 69238fd1498Szrj _M_emplace(std::false_type __uk, _Args&&... __args) 69338fd1498Szrj { return _M_emplace(cend(), __uk, std::forward<_Args>(__args)...); } 69438fd1498Szrj 69538fd1498Szrj // Emplace with hint, useless when keys are unique. 69638fd1498Szrj template<typename... _Args> 69738fd1498Szrj iterator 69838fd1498Szrj _M_emplace(const_iterator, std::true_type __uk, _Args&&... __args) 69938fd1498Szrj { return _M_emplace(__uk, std::forward<_Args>(__args)...).first; } 70038fd1498Szrj 70138fd1498Szrj template<typename... _Args> 70238fd1498Szrj iterator 70338fd1498Szrj _M_emplace(const_iterator, std::false_type, _Args&&... __args); 70438fd1498Szrj 70538fd1498Szrj template<typename _Arg, typename _NodeGenerator> 70638fd1498Szrj std::pair<iterator, bool> 70738fd1498Szrj _M_insert(_Arg&&, const _NodeGenerator&, true_type, size_type = 1); 70838fd1498Szrj 70938fd1498Szrj template<typename _Arg, typename _NodeGenerator> 71038fd1498Szrj iterator 71138fd1498Szrj _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen, 71238fd1498Szrj false_type __uk) 71338fd1498Szrj { 71438fd1498Szrj return _M_insert(cend(), std::forward<_Arg>(__arg), __node_gen, 71538fd1498Szrj __uk); 71638fd1498Szrj } 71738fd1498Szrj 71838fd1498Szrj // Insert with hint, not used when keys are unique. 71938fd1498Szrj template<typename _Arg, typename _NodeGenerator> 72038fd1498Szrj iterator 72138fd1498Szrj _M_insert(const_iterator, _Arg&& __arg, 72238fd1498Szrj const _NodeGenerator& __node_gen, true_type __uk) 72338fd1498Szrj { 72438fd1498Szrj return 72538fd1498Szrj _M_insert(std::forward<_Arg>(__arg), __node_gen, __uk).first; 72638fd1498Szrj } 72738fd1498Szrj 72838fd1498Szrj // Insert with hint when keys are not unique. 72938fd1498Szrj template<typename _Arg, typename _NodeGenerator> 73038fd1498Szrj iterator 73138fd1498Szrj _M_insert(const_iterator, _Arg&&, 73238fd1498Szrj const _NodeGenerator&, false_type); 73338fd1498Szrj 73438fd1498Szrj size_type 73538fd1498Szrj _M_erase(std::true_type, const key_type&); 73638fd1498Szrj 73738fd1498Szrj size_type 73838fd1498Szrj _M_erase(std::false_type, const key_type&); 73938fd1498Szrj 74038fd1498Szrj iterator 74138fd1498Szrj _M_erase(size_type __bkt, __node_base* __prev_n, __node_type* __n); 74238fd1498Szrj 74338fd1498Szrj public: 74438fd1498Szrj // Emplace 74538fd1498Szrj template<typename... _Args> 74638fd1498Szrj __ireturn_type 74738fd1498Szrj emplace(_Args&&... __args) 74838fd1498Szrj { return _M_emplace(__unique_keys(), std::forward<_Args>(__args)...); } 74938fd1498Szrj 75038fd1498Szrj template<typename... _Args> 75138fd1498Szrj iterator 75238fd1498Szrj emplace_hint(const_iterator __hint, _Args&&... __args) 75338fd1498Szrj { 75438fd1498Szrj return _M_emplace(__hint, __unique_keys(), 75538fd1498Szrj std::forward<_Args>(__args)...); 75638fd1498Szrj } 75738fd1498Szrj 75838fd1498Szrj // Insert member functions via inheritance. 75938fd1498Szrj 76038fd1498Szrj // Erase 76138fd1498Szrj iterator 76238fd1498Szrj erase(const_iterator); 76338fd1498Szrj 76438fd1498Szrj // LWG 2059. 76538fd1498Szrj iterator 76638fd1498Szrj erase(iterator __it) 76738fd1498Szrj { return erase(const_iterator(__it)); } 76838fd1498Szrj 76938fd1498Szrj size_type 77038fd1498Szrj erase(const key_type& __k) 77138fd1498Szrj { return _M_erase(__unique_keys(), __k); } 77238fd1498Szrj 77338fd1498Szrj iterator 77438fd1498Szrj erase(const_iterator, const_iterator); 77538fd1498Szrj 77638fd1498Szrj void 77738fd1498Szrj clear() noexcept; 77838fd1498Szrj 77938fd1498Szrj // Set number of buckets to be appropriate for container of n element. 78038fd1498Szrj void rehash(size_type __n); 78138fd1498Szrj 78238fd1498Szrj // DR 1189. 78338fd1498Szrj // reserve, if present, comes from _Rehash_base. 78438fd1498Szrj 78538fd1498Szrj #if __cplusplus > 201402L 78638fd1498Szrj /// Re-insert an extracted node into a container with unique keys. 78738fd1498Szrj insert_return_type 78838fd1498Szrj _M_reinsert_node(node_type&& __nh) 78938fd1498Szrj { 79038fd1498Szrj insert_return_type __ret; 79138fd1498Szrj if (__nh.empty()) 79238fd1498Szrj __ret.position = end(); 79338fd1498Szrj else 79438fd1498Szrj { 79538fd1498Szrj __glibcxx_assert(get_allocator() == __nh.get_allocator()); 79638fd1498Szrj 79738fd1498Szrj const key_type& __k = __nh._M_key(); 79838fd1498Szrj __hash_code __code = this->_M_hash_code(__k); 79938fd1498Szrj size_type __bkt = _M_bucket_index(__k, __code); 80038fd1498Szrj if (__node_type* __n = _M_find_node(__bkt, __k, __code)) 80138fd1498Szrj { 80238fd1498Szrj __ret.node = std::move(__nh); 80338fd1498Szrj __ret.position = iterator(__n); 80438fd1498Szrj __ret.inserted = false; 80538fd1498Szrj } 80638fd1498Szrj else 80738fd1498Szrj { 80838fd1498Szrj __ret.position 80938fd1498Szrj = _M_insert_unique_node(__bkt, __code, __nh._M_ptr); 81038fd1498Szrj __nh._M_ptr = nullptr; 81138fd1498Szrj __ret.inserted = true; 81238fd1498Szrj } 81338fd1498Szrj } 81438fd1498Szrj return __ret; 81538fd1498Szrj } 81638fd1498Szrj 81738fd1498Szrj /// Re-insert an extracted node into a container with equivalent keys. 81838fd1498Szrj iterator 81938fd1498Szrj _M_reinsert_node_multi(const_iterator __hint, node_type&& __nh) 82038fd1498Szrj { 82138fd1498Szrj iterator __ret; 82238fd1498Szrj if (__nh.empty()) 82338fd1498Szrj __ret = end(); 82438fd1498Szrj else 82538fd1498Szrj { 82638fd1498Szrj __glibcxx_assert(get_allocator() == __nh.get_allocator()); 82738fd1498Szrj 82838fd1498Szrj auto __code = this->_M_hash_code(__nh._M_key()); 82938fd1498Szrj auto __node = std::exchange(__nh._M_ptr, nullptr); 83038fd1498Szrj // FIXME: this deallocates the node on exception. 83138fd1498Szrj __ret = _M_insert_multi_node(__hint._M_cur, __code, __node); 83238fd1498Szrj } 83338fd1498Szrj return __ret; 83438fd1498Szrj } 83538fd1498Szrj 83638fd1498Szrj /// Extract a node. 83738fd1498Szrj node_type 83838fd1498Szrj extract(const_iterator __pos) 83938fd1498Szrj { 84038fd1498Szrj __node_type* __n = __pos._M_cur; 84138fd1498Szrj size_t __bkt = _M_bucket_index(__n); 84238fd1498Szrj 84338fd1498Szrj // Look for previous node to unlink it from the erased one, this 84438fd1498Szrj // is why we need buckets to contain the before begin to make 84538fd1498Szrj // this search fast. 84638fd1498Szrj __node_base* __prev_n = _M_get_previous_node(__bkt, __n); 84738fd1498Szrj 84838fd1498Szrj if (__prev_n == _M_buckets[__bkt]) 84938fd1498Szrj _M_remove_bucket_begin(__bkt, __n->_M_next(), 85038fd1498Szrj __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0); 85138fd1498Szrj else if (__n->_M_nxt) 85238fd1498Szrj { 85338fd1498Szrj size_type __next_bkt = _M_bucket_index(__n->_M_next()); 85438fd1498Szrj if (__next_bkt != __bkt) 85538fd1498Szrj _M_buckets[__next_bkt] = __prev_n; 85638fd1498Szrj } 85738fd1498Szrj 85838fd1498Szrj __prev_n->_M_nxt = __n->_M_nxt; 85938fd1498Szrj __n->_M_nxt = nullptr; 86038fd1498Szrj --_M_element_count; 86138fd1498Szrj return { __n, this->_M_node_allocator() }; 86238fd1498Szrj } 86338fd1498Szrj 86438fd1498Szrj /// Extract a node. 86538fd1498Szrj node_type 86638fd1498Szrj extract(const _Key& __k) 86738fd1498Szrj { 86838fd1498Szrj node_type __nh; 86938fd1498Szrj auto __pos = find(__k); 87038fd1498Szrj if (__pos != end()) 87138fd1498Szrj __nh = extract(const_iterator(__pos)); 87238fd1498Szrj return __nh; 87338fd1498Szrj } 87438fd1498Szrj 87538fd1498Szrj /// Merge from a compatible container into one with unique keys. 87638fd1498Szrj template<typename _Compatible_Hashtable> 87738fd1498Szrj void 87838fd1498Szrj _M_merge_unique(_Compatible_Hashtable& __src) noexcept 87938fd1498Szrj { 88038fd1498Szrj static_assert(is_same_v<typename _Compatible_Hashtable::node_type, 88138fd1498Szrj node_type>, "Node types are compatible"); 88238fd1498Szrj __glibcxx_assert(get_allocator() == __src.get_allocator()); 88338fd1498Szrj 88438fd1498Szrj auto __n_elt = __src.size(); 88538fd1498Szrj for (auto __i = __src.begin(), __end = __src.end(); __i != __end;) 88638fd1498Szrj { 88738fd1498Szrj auto __pos = __i++; 88838fd1498Szrj const key_type& __k = this->_M_extract()(__pos._M_cur->_M_v()); 88938fd1498Szrj __hash_code __code = this->_M_hash_code(__k); 89038fd1498Szrj size_type __bkt = _M_bucket_index(__k, __code); 89138fd1498Szrj if (_M_find_node(__bkt, __k, __code) == nullptr) 89238fd1498Szrj { 89338fd1498Szrj auto __nh = __src.extract(__pos); 89438fd1498Szrj _M_insert_unique_node(__bkt, __code, __nh._M_ptr, __n_elt); 89538fd1498Szrj __nh._M_ptr = nullptr; 89638fd1498Szrj __n_elt = 1; 89738fd1498Szrj } 89838fd1498Szrj else if (__n_elt != 1) 89938fd1498Szrj --__n_elt; 90038fd1498Szrj } 90138fd1498Szrj } 90238fd1498Szrj 90338fd1498Szrj /// Merge from a compatible container into one with equivalent keys. 90438fd1498Szrj template<typename _Compatible_Hashtable> 90538fd1498Szrj void 90638fd1498Szrj _M_merge_multi(_Compatible_Hashtable& __src) noexcept 90738fd1498Szrj { 90838fd1498Szrj static_assert(is_same_v<typename _Compatible_Hashtable::node_type, 90938fd1498Szrj node_type>, "Node types are compatible"); 91038fd1498Szrj __glibcxx_assert(get_allocator() == __src.get_allocator()); 91138fd1498Szrj 91238fd1498Szrj this->reserve(size() + __src.size()); 91338fd1498Szrj for (auto __i = __src.begin(), __end = __src.end(); __i != __end;) 91438fd1498Szrj _M_reinsert_node_multi(cend(), __src.extract(__i++)); 91538fd1498Szrj } 91638fd1498Szrj #endif // C++17 91738fd1498Szrj 91838fd1498Szrj private: 91938fd1498Szrj // Helper rehash method used when keys are unique. 92038fd1498Szrj void _M_rehash_aux(size_type __n, std::true_type); 92138fd1498Szrj 92238fd1498Szrj // Helper rehash method used when keys can be non-unique. 92338fd1498Szrj void _M_rehash_aux(size_type __n, std::false_type); 92438fd1498Szrj 92538fd1498Szrj // Unconditionally change size of bucket array to n, restore 92638fd1498Szrj // hash policy state to __state on exception. 92738fd1498Szrj void _M_rehash(size_type __n, const __rehash_state& __state); 92838fd1498Szrj }; 92938fd1498Szrj 93038fd1498Szrj 93138fd1498Szrj // Definitions of class template _Hashtable's out-of-line member functions. 93238fd1498Szrj template<typename _Key, typename _Value, 93338fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 93438fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 93538fd1498Szrj typename _Traits> 93638fd1498Szrj auto 93738fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 93838fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 93938fd1498Szrj _M_bucket_begin(size_type __bkt) const 94038fd1498Szrj -> __node_type* 94138fd1498Szrj { 94238fd1498Szrj __node_base* __n = _M_buckets[__bkt]; 94338fd1498Szrj return __n ? static_cast<__node_type*>(__n->_M_nxt) : nullptr; 94438fd1498Szrj } 94538fd1498Szrj 94638fd1498Szrj template<typename _Key, typename _Value, 94738fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 94838fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 94938fd1498Szrj typename _Traits> 95038fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 95138fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 95238fd1498Szrj _Hashtable(size_type __bucket_hint, 95338fd1498Szrj const _H1& __h1, const _H2& __h2, const _Hash& __h, 95438fd1498Szrj const _Equal& __eq, const _ExtractKey& __exk, 95538fd1498Szrj const allocator_type& __a) 95638fd1498Szrj : _Hashtable(__h1, __h2, __h, __eq, __exk, __a) 95738fd1498Szrj { 95838fd1498Szrj auto __bkt = _M_rehash_policy._M_next_bkt(__bucket_hint); 95938fd1498Szrj if (__bkt > _M_bucket_count) 96038fd1498Szrj { 96138fd1498Szrj _M_buckets = _M_allocate_buckets(__bkt); 96238fd1498Szrj _M_bucket_count = __bkt; 96338fd1498Szrj } 96438fd1498Szrj } 96538fd1498Szrj 96638fd1498Szrj template<typename _Key, typename _Value, 96738fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 96838fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 96938fd1498Szrj typename _Traits> 97038fd1498Szrj template<typename _InputIterator> 97138fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 97238fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 97338fd1498Szrj _Hashtable(_InputIterator __f, _InputIterator __l, 97438fd1498Szrj size_type __bucket_hint, 97538fd1498Szrj const _H1& __h1, const _H2& __h2, const _Hash& __h, 97638fd1498Szrj const _Equal& __eq, const _ExtractKey& __exk, 97738fd1498Szrj const allocator_type& __a) 97838fd1498Szrj : _Hashtable(__h1, __h2, __h, __eq, __exk, __a) 97938fd1498Szrj { 98038fd1498Szrj auto __nb_elems = __detail::__distance_fw(__f, __l); 98138fd1498Szrj auto __bkt_count = 98238fd1498Szrj _M_rehash_policy._M_next_bkt( 98338fd1498Szrj std::max(_M_rehash_policy._M_bkt_for_elements(__nb_elems), 98438fd1498Szrj __bucket_hint)); 98538fd1498Szrj 98638fd1498Szrj if (__bkt_count > _M_bucket_count) 98738fd1498Szrj { 98838fd1498Szrj _M_buckets = _M_allocate_buckets(__bkt_count); 98938fd1498Szrj _M_bucket_count = __bkt_count; 99038fd1498Szrj } 99138fd1498Szrj 99238fd1498Szrj for (; __f != __l; ++__f) 99338fd1498Szrj this->insert(*__f); 99438fd1498Szrj } 99538fd1498Szrj 99638fd1498Szrj template<typename _Key, typename _Value, 99738fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 99838fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 99938fd1498Szrj typename _Traits> 100038fd1498Szrj auto 100138fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 100238fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 100338fd1498Szrj operator=(const _Hashtable& __ht) 100438fd1498Szrj -> _Hashtable& 100538fd1498Szrj { 100638fd1498Szrj if (&__ht == this) 100738fd1498Szrj return *this; 100838fd1498Szrj 100938fd1498Szrj if (__node_alloc_traits::_S_propagate_on_copy_assign()) 101038fd1498Szrj { 101138fd1498Szrj auto& __this_alloc = this->_M_node_allocator(); 101238fd1498Szrj auto& __that_alloc = __ht._M_node_allocator(); 101338fd1498Szrj if (!__node_alloc_traits::_S_always_equal() 101438fd1498Szrj && __this_alloc != __that_alloc) 101538fd1498Szrj { 101638fd1498Szrj // Replacement allocator cannot free existing storage. 101738fd1498Szrj this->_M_deallocate_nodes(_M_begin()); 101838fd1498Szrj _M_before_begin._M_nxt = nullptr; 101938fd1498Szrj _M_deallocate_buckets(); 102038fd1498Szrj _M_buckets = nullptr; 102138fd1498Szrj std::__alloc_on_copy(__this_alloc, __that_alloc); 102238fd1498Szrj __hashtable_base::operator=(__ht); 102338fd1498Szrj _M_bucket_count = __ht._M_bucket_count; 102438fd1498Szrj _M_element_count = __ht._M_element_count; 102538fd1498Szrj _M_rehash_policy = __ht._M_rehash_policy; 102638fd1498Szrj __try 102738fd1498Szrj { 102838fd1498Szrj _M_assign(__ht, 102938fd1498Szrj [this](const __node_type* __n) 103038fd1498Szrj { return this->_M_allocate_node(__n->_M_v()); }); 103138fd1498Szrj } 103238fd1498Szrj __catch(...) 103338fd1498Szrj { 103438fd1498Szrj // _M_assign took care of deallocating all memory. Now we 103538fd1498Szrj // must make sure this instance remains in a usable state. 103638fd1498Szrj _M_reset(); 103738fd1498Szrj __throw_exception_again; 103838fd1498Szrj } 103938fd1498Szrj return *this; 104038fd1498Szrj } 104138fd1498Szrj std::__alloc_on_copy(__this_alloc, __that_alloc); 104238fd1498Szrj } 104338fd1498Szrj 104438fd1498Szrj // Reuse allocated buckets and nodes. 104538fd1498Szrj __bucket_type* __former_buckets = nullptr; 104638fd1498Szrj std::size_t __former_bucket_count = _M_bucket_count; 104738fd1498Szrj const __rehash_state& __former_state = _M_rehash_policy._M_state(); 104838fd1498Szrj 104938fd1498Szrj if (_M_bucket_count != __ht._M_bucket_count) 105038fd1498Szrj { 105138fd1498Szrj __former_buckets = _M_buckets; 105238fd1498Szrj _M_buckets = _M_allocate_buckets(__ht._M_bucket_count); 105338fd1498Szrj _M_bucket_count = __ht._M_bucket_count; 105438fd1498Szrj } 105538fd1498Szrj else 105638fd1498Szrj __builtin_memset(_M_buckets, 0, 105738fd1498Szrj _M_bucket_count * sizeof(__bucket_type)); 105838fd1498Szrj 105938fd1498Szrj __try 106038fd1498Szrj { 106138fd1498Szrj __hashtable_base::operator=(__ht); 106238fd1498Szrj _M_element_count = __ht._M_element_count; 106338fd1498Szrj _M_rehash_policy = __ht._M_rehash_policy; 106438fd1498Szrj __reuse_or_alloc_node_type __roan(_M_begin(), *this); 106538fd1498Szrj _M_before_begin._M_nxt = nullptr; 106638fd1498Szrj _M_assign(__ht, 106738fd1498Szrj [&__roan](const __node_type* __n) 106838fd1498Szrj { return __roan(__n->_M_v()); }); 106938fd1498Szrj if (__former_buckets) 107038fd1498Szrj _M_deallocate_buckets(__former_buckets, __former_bucket_count); 107138fd1498Szrj } 107238fd1498Szrj __catch(...) 107338fd1498Szrj { 107438fd1498Szrj if (__former_buckets) 107538fd1498Szrj { 107638fd1498Szrj // Restore previous buckets. 107738fd1498Szrj _M_deallocate_buckets(); 107838fd1498Szrj _M_rehash_policy._M_reset(__former_state); 107938fd1498Szrj _M_buckets = __former_buckets; 108038fd1498Szrj _M_bucket_count = __former_bucket_count; 108138fd1498Szrj } 108238fd1498Szrj __builtin_memset(_M_buckets, 0, 108338fd1498Szrj _M_bucket_count * sizeof(__bucket_type)); 108438fd1498Szrj __throw_exception_again; 108538fd1498Szrj } 108638fd1498Szrj return *this; 108738fd1498Szrj } 108838fd1498Szrj 108938fd1498Szrj template<typename _Key, typename _Value, 109038fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 109138fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 109238fd1498Szrj typename _Traits> 109338fd1498Szrj template<typename _NodeGenerator> 109438fd1498Szrj void 109538fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 109638fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 109738fd1498Szrj _M_assign(const _Hashtable& __ht, const _NodeGenerator& __node_gen) 109838fd1498Szrj { 109938fd1498Szrj __bucket_type* __buckets = nullptr; 110038fd1498Szrj if (!_M_buckets) 110138fd1498Szrj _M_buckets = __buckets = _M_allocate_buckets(_M_bucket_count); 110238fd1498Szrj 110338fd1498Szrj __try 110438fd1498Szrj { 110538fd1498Szrj if (!__ht._M_before_begin._M_nxt) 110638fd1498Szrj return; 110738fd1498Szrj 110838fd1498Szrj // First deal with the special first node pointed to by 110938fd1498Szrj // _M_before_begin. 111038fd1498Szrj __node_type* __ht_n = __ht._M_begin(); 111138fd1498Szrj __node_type* __this_n = __node_gen(__ht_n); 111238fd1498Szrj this->_M_copy_code(__this_n, __ht_n); 111338fd1498Szrj _M_before_begin._M_nxt = __this_n; 111438fd1498Szrj _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin; 111538fd1498Szrj 111638fd1498Szrj // Then deal with other nodes. 111738fd1498Szrj __node_base* __prev_n = __this_n; 111838fd1498Szrj for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next()) 111938fd1498Szrj { 112038fd1498Szrj __this_n = __node_gen(__ht_n); 112138fd1498Szrj __prev_n->_M_nxt = __this_n; 112238fd1498Szrj this->_M_copy_code(__this_n, __ht_n); 112338fd1498Szrj size_type __bkt = _M_bucket_index(__this_n); 112438fd1498Szrj if (!_M_buckets[__bkt]) 112538fd1498Szrj _M_buckets[__bkt] = __prev_n; 112638fd1498Szrj __prev_n = __this_n; 112738fd1498Szrj } 112838fd1498Szrj } 112938fd1498Szrj __catch(...) 113038fd1498Szrj { 113138fd1498Szrj clear(); 113238fd1498Szrj if (__buckets) 113338fd1498Szrj _M_deallocate_buckets(); 113438fd1498Szrj __throw_exception_again; 113538fd1498Szrj } 113638fd1498Szrj } 113738fd1498Szrj 113838fd1498Szrj template<typename _Key, typename _Value, 113938fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 114038fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 114138fd1498Szrj typename _Traits> 114238fd1498Szrj void 114338fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 114438fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 114538fd1498Szrj _M_reset() noexcept 114638fd1498Szrj { 114738fd1498Szrj _M_rehash_policy._M_reset(); 114838fd1498Szrj _M_bucket_count = 1; 114938fd1498Szrj _M_single_bucket = nullptr; 115038fd1498Szrj _M_buckets = &_M_single_bucket; 115138fd1498Szrj _M_before_begin._M_nxt = nullptr; 115238fd1498Szrj _M_element_count = 0; 115338fd1498Szrj } 115438fd1498Szrj 115538fd1498Szrj template<typename _Key, typename _Value, 115638fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 115738fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 115838fd1498Szrj typename _Traits> 115938fd1498Szrj void 116038fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 116138fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 116238fd1498Szrj _M_move_assign(_Hashtable&& __ht, std::true_type) 116338fd1498Szrj { 116438fd1498Szrj this->_M_deallocate_nodes(_M_begin()); 116538fd1498Szrj _M_deallocate_buckets(); 116638fd1498Szrj __hashtable_base::operator=(std::move(__ht)); 116738fd1498Szrj _M_rehash_policy = __ht._M_rehash_policy; 116838fd1498Szrj if (!__ht._M_uses_single_bucket()) 116938fd1498Szrj _M_buckets = __ht._M_buckets; 117038fd1498Szrj else 117138fd1498Szrj { 117238fd1498Szrj _M_buckets = &_M_single_bucket; 117338fd1498Szrj _M_single_bucket = __ht._M_single_bucket; 117438fd1498Szrj } 117538fd1498Szrj _M_bucket_count = __ht._M_bucket_count; 117638fd1498Szrj _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt; 117738fd1498Szrj _M_element_count = __ht._M_element_count; 117838fd1498Szrj std::__alloc_on_move(this->_M_node_allocator(), __ht._M_node_allocator()); 117938fd1498Szrj 118038fd1498Szrj // Fix buckets containing the _M_before_begin pointers that can't be 118138fd1498Szrj // moved. 118238fd1498Szrj if (_M_begin()) 118338fd1498Szrj _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 118438fd1498Szrj __ht._M_reset(); 118538fd1498Szrj } 118638fd1498Szrj 118738fd1498Szrj template<typename _Key, typename _Value, 118838fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 118938fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 119038fd1498Szrj typename _Traits> 119138fd1498Szrj void 119238fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 119338fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 119438fd1498Szrj _M_move_assign(_Hashtable&& __ht, std::false_type) 119538fd1498Szrj { 119638fd1498Szrj if (__ht._M_node_allocator() == this->_M_node_allocator()) 119738fd1498Szrj _M_move_assign(std::move(__ht), std::true_type()); 119838fd1498Szrj else 119938fd1498Szrj { 120038fd1498Szrj // Can't move memory, move elements then. 120138fd1498Szrj __bucket_type* __former_buckets = nullptr; 120238fd1498Szrj size_type __former_bucket_count = _M_bucket_count; 120338fd1498Szrj const __rehash_state& __former_state = _M_rehash_policy._M_state(); 120438fd1498Szrj 120538fd1498Szrj if (_M_bucket_count != __ht._M_bucket_count) 120638fd1498Szrj { 120738fd1498Szrj __former_buckets = _M_buckets; 120838fd1498Szrj _M_buckets = _M_allocate_buckets(__ht._M_bucket_count); 120938fd1498Szrj _M_bucket_count = __ht._M_bucket_count; 121038fd1498Szrj } 121138fd1498Szrj else 121238fd1498Szrj __builtin_memset(_M_buckets, 0, 121338fd1498Szrj _M_bucket_count * sizeof(__bucket_type)); 121438fd1498Szrj 121538fd1498Szrj __try 121638fd1498Szrj { 121738fd1498Szrj __hashtable_base::operator=(std::move(__ht)); 121838fd1498Szrj _M_element_count = __ht._M_element_count; 121938fd1498Szrj _M_rehash_policy = __ht._M_rehash_policy; 122038fd1498Szrj __reuse_or_alloc_node_type __roan(_M_begin(), *this); 122138fd1498Szrj _M_before_begin._M_nxt = nullptr; 122238fd1498Szrj _M_assign(__ht, 122338fd1498Szrj [&__roan](__node_type* __n) 122438fd1498Szrj { return __roan(std::move_if_noexcept(__n->_M_v())); }); 1225*58e805e6Szrj 1226*58e805e6Szrj if (__former_buckets) 1227*58e805e6Szrj _M_deallocate_buckets(__former_buckets, __former_bucket_count); 122838fd1498Szrj __ht.clear(); 122938fd1498Szrj } 123038fd1498Szrj __catch(...) 123138fd1498Szrj { 123238fd1498Szrj if (__former_buckets) 123338fd1498Szrj { 123438fd1498Szrj _M_deallocate_buckets(); 123538fd1498Szrj _M_rehash_policy._M_reset(__former_state); 123638fd1498Szrj _M_buckets = __former_buckets; 123738fd1498Szrj _M_bucket_count = __former_bucket_count; 123838fd1498Szrj } 123938fd1498Szrj __builtin_memset(_M_buckets, 0, 124038fd1498Szrj _M_bucket_count * sizeof(__bucket_type)); 124138fd1498Szrj __throw_exception_again; 124238fd1498Szrj } 124338fd1498Szrj } 124438fd1498Szrj } 124538fd1498Szrj 124638fd1498Szrj template<typename _Key, typename _Value, 124738fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 124838fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 124938fd1498Szrj typename _Traits> 125038fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 125138fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 125238fd1498Szrj _Hashtable(const _Hashtable& __ht) 125338fd1498Szrj : __hashtable_base(__ht), 125438fd1498Szrj __map_base(__ht), 125538fd1498Szrj __rehash_base(__ht), 125638fd1498Szrj __hashtable_alloc( 125738fd1498Szrj __node_alloc_traits::_S_select_on_copy(__ht._M_node_allocator())), 125838fd1498Szrj _M_buckets(nullptr), 125938fd1498Szrj _M_bucket_count(__ht._M_bucket_count), 126038fd1498Szrj _M_element_count(__ht._M_element_count), 126138fd1498Szrj _M_rehash_policy(__ht._M_rehash_policy) 126238fd1498Szrj { 126338fd1498Szrj _M_assign(__ht, 126438fd1498Szrj [this](const __node_type* __n) 126538fd1498Szrj { return this->_M_allocate_node(__n->_M_v()); }); 126638fd1498Szrj } 126738fd1498Szrj 126838fd1498Szrj template<typename _Key, typename _Value, 126938fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 127038fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 127138fd1498Szrj typename _Traits> 127238fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 127338fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 127438fd1498Szrj _Hashtable(_Hashtable&& __ht) noexcept 127538fd1498Szrj : __hashtable_base(__ht), 127638fd1498Szrj __map_base(__ht), 127738fd1498Szrj __rehash_base(__ht), 127838fd1498Szrj __hashtable_alloc(std::move(__ht._M_base_alloc())), 127938fd1498Szrj _M_buckets(__ht._M_buckets), 128038fd1498Szrj _M_bucket_count(__ht._M_bucket_count), 128138fd1498Szrj _M_before_begin(__ht._M_before_begin._M_nxt), 128238fd1498Szrj _M_element_count(__ht._M_element_count), 128338fd1498Szrj _M_rehash_policy(__ht._M_rehash_policy) 128438fd1498Szrj { 128538fd1498Szrj // Update, if necessary, buckets if __ht is using its single bucket. 128638fd1498Szrj if (__ht._M_uses_single_bucket()) 128738fd1498Szrj { 128838fd1498Szrj _M_buckets = &_M_single_bucket; 128938fd1498Szrj _M_single_bucket = __ht._M_single_bucket; 129038fd1498Szrj } 129138fd1498Szrj 129238fd1498Szrj // Update, if necessary, bucket pointing to before begin that hasn't 129338fd1498Szrj // moved. 129438fd1498Szrj if (_M_begin()) 129538fd1498Szrj _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 129638fd1498Szrj 129738fd1498Szrj __ht._M_reset(); 129838fd1498Szrj } 129938fd1498Szrj 130038fd1498Szrj template<typename _Key, typename _Value, 130138fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 130238fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 130338fd1498Szrj typename _Traits> 130438fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 130538fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 130638fd1498Szrj _Hashtable(const _Hashtable& __ht, const allocator_type& __a) 130738fd1498Szrj : __hashtable_base(__ht), 130838fd1498Szrj __map_base(__ht), 130938fd1498Szrj __rehash_base(__ht), 131038fd1498Szrj __hashtable_alloc(__node_alloc_type(__a)), 131138fd1498Szrj _M_buckets(), 131238fd1498Szrj _M_bucket_count(__ht._M_bucket_count), 131338fd1498Szrj _M_element_count(__ht._M_element_count), 131438fd1498Szrj _M_rehash_policy(__ht._M_rehash_policy) 131538fd1498Szrj { 131638fd1498Szrj _M_assign(__ht, 131738fd1498Szrj [this](const __node_type* __n) 131838fd1498Szrj { return this->_M_allocate_node(__n->_M_v()); }); 131938fd1498Szrj } 132038fd1498Szrj 132138fd1498Szrj template<typename _Key, typename _Value, 132238fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 132338fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 132438fd1498Szrj typename _Traits> 132538fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 132638fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 132738fd1498Szrj _Hashtable(_Hashtable&& __ht, const allocator_type& __a) 132838fd1498Szrj : __hashtable_base(__ht), 132938fd1498Szrj __map_base(__ht), 133038fd1498Szrj __rehash_base(__ht), 133138fd1498Szrj __hashtable_alloc(__node_alloc_type(__a)), 133238fd1498Szrj _M_buckets(nullptr), 133338fd1498Szrj _M_bucket_count(__ht._M_bucket_count), 133438fd1498Szrj _M_element_count(__ht._M_element_count), 133538fd1498Szrj _M_rehash_policy(__ht._M_rehash_policy) 133638fd1498Szrj { 133738fd1498Szrj if (__ht._M_node_allocator() == this->_M_node_allocator()) 133838fd1498Szrj { 133938fd1498Szrj if (__ht._M_uses_single_bucket()) 134038fd1498Szrj { 134138fd1498Szrj _M_buckets = &_M_single_bucket; 134238fd1498Szrj _M_single_bucket = __ht._M_single_bucket; 134338fd1498Szrj } 134438fd1498Szrj else 134538fd1498Szrj _M_buckets = __ht._M_buckets; 134638fd1498Szrj 134738fd1498Szrj _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt; 134838fd1498Szrj // Update, if necessary, bucket pointing to before begin that hasn't 134938fd1498Szrj // moved. 135038fd1498Szrj if (_M_begin()) 135138fd1498Szrj _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 135238fd1498Szrj __ht._M_reset(); 135338fd1498Szrj } 135438fd1498Szrj else 135538fd1498Szrj { 135638fd1498Szrj _M_assign(__ht, 135738fd1498Szrj [this](__node_type* __n) 135838fd1498Szrj { 135938fd1498Szrj return this->_M_allocate_node( 136038fd1498Szrj std::move_if_noexcept(__n->_M_v())); 136138fd1498Szrj }); 136238fd1498Szrj __ht.clear(); 136338fd1498Szrj } 136438fd1498Szrj } 136538fd1498Szrj 136638fd1498Szrj template<typename _Key, typename _Value, 136738fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 136838fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 136938fd1498Szrj typename _Traits> 137038fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 137138fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 137238fd1498Szrj ~_Hashtable() noexcept 137338fd1498Szrj { 137438fd1498Szrj clear(); 137538fd1498Szrj _M_deallocate_buckets(); 137638fd1498Szrj } 137738fd1498Szrj 137838fd1498Szrj template<typename _Key, typename _Value, 137938fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 138038fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 138138fd1498Szrj typename _Traits> 138238fd1498Szrj void 138338fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 138438fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 138538fd1498Szrj swap(_Hashtable& __x) 138638fd1498Szrj noexcept(__and_<__is_nothrow_swappable<_H1>, 138738fd1498Szrj __is_nothrow_swappable<_Equal>>::value) 138838fd1498Szrj { 138938fd1498Szrj // The only base class with member variables is hash_code_base. 139038fd1498Szrj // We define _Hash_code_base::_M_swap because different 139138fd1498Szrj // specializations have different members. 139238fd1498Szrj this->_M_swap(__x); 139338fd1498Szrj 139438fd1498Szrj std::__alloc_on_swap(this->_M_node_allocator(), __x._M_node_allocator()); 139538fd1498Szrj std::swap(_M_rehash_policy, __x._M_rehash_policy); 139638fd1498Szrj 139738fd1498Szrj // Deal properly with potentially moved instances. 139838fd1498Szrj if (this->_M_uses_single_bucket()) 139938fd1498Szrj { 140038fd1498Szrj if (!__x._M_uses_single_bucket()) 140138fd1498Szrj { 140238fd1498Szrj _M_buckets = __x._M_buckets; 140338fd1498Szrj __x._M_buckets = &__x._M_single_bucket; 140438fd1498Szrj } 140538fd1498Szrj } 140638fd1498Szrj else if (__x._M_uses_single_bucket()) 140738fd1498Szrj { 140838fd1498Szrj __x._M_buckets = _M_buckets; 140938fd1498Szrj _M_buckets = &_M_single_bucket; 141038fd1498Szrj } 141138fd1498Szrj else 141238fd1498Szrj std::swap(_M_buckets, __x._M_buckets); 141338fd1498Szrj 141438fd1498Szrj std::swap(_M_bucket_count, __x._M_bucket_count); 141538fd1498Szrj std::swap(_M_before_begin._M_nxt, __x._M_before_begin._M_nxt); 141638fd1498Szrj std::swap(_M_element_count, __x._M_element_count); 141738fd1498Szrj std::swap(_M_single_bucket, __x._M_single_bucket); 141838fd1498Szrj 141938fd1498Szrj // Fix buckets containing the _M_before_begin pointers that can't be 142038fd1498Szrj // swapped. 142138fd1498Szrj if (_M_begin()) 142238fd1498Szrj _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 142338fd1498Szrj 142438fd1498Szrj if (__x._M_begin()) 142538fd1498Szrj __x._M_buckets[__x._M_bucket_index(__x._M_begin())] 142638fd1498Szrj = &__x._M_before_begin; 142738fd1498Szrj } 142838fd1498Szrj 142938fd1498Szrj template<typename _Key, typename _Value, 143038fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 143138fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 143238fd1498Szrj typename _Traits> 143338fd1498Szrj auto 143438fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 143538fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 143638fd1498Szrj find(const key_type& __k) 143738fd1498Szrj -> iterator 143838fd1498Szrj { 143938fd1498Szrj __hash_code __code = this->_M_hash_code(__k); 144038fd1498Szrj std::size_t __n = _M_bucket_index(__k, __code); 144138fd1498Szrj __node_type* __p = _M_find_node(__n, __k, __code); 144238fd1498Szrj return __p ? iterator(__p) : end(); 144338fd1498Szrj } 144438fd1498Szrj 144538fd1498Szrj template<typename _Key, typename _Value, 144638fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 144738fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 144838fd1498Szrj typename _Traits> 144938fd1498Szrj auto 145038fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 145138fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 145238fd1498Szrj find(const key_type& __k) const 145338fd1498Szrj -> const_iterator 145438fd1498Szrj { 145538fd1498Szrj __hash_code __code = this->_M_hash_code(__k); 145638fd1498Szrj std::size_t __n = _M_bucket_index(__k, __code); 145738fd1498Szrj __node_type* __p = _M_find_node(__n, __k, __code); 145838fd1498Szrj return __p ? const_iterator(__p) : end(); 145938fd1498Szrj } 146038fd1498Szrj 146138fd1498Szrj template<typename _Key, typename _Value, 146238fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 146338fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 146438fd1498Szrj typename _Traits> 146538fd1498Szrj auto 146638fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 146738fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 146838fd1498Szrj count(const key_type& __k) const 146938fd1498Szrj -> size_type 147038fd1498Szrj { 147138fd1498Szrj __hash_code __code = this->_M_hash_code(__k); 147238fd1498Szrj std::size_t __n = _M_bucket_index(__k, __code); 147338fd1498Szrj __node_type* __p = _M_bucket_begin(__n); 147438fd1498Szrj if (!__p) 147538fd1498Szrj return 0; 147638fd1498Szrj 147738fd1498Szrj std::size_t __result = 0; 147838fd1498Szrj for (;; __p = __p->_M_next()) 147938fd1498Szrj { 148038fd1498Szrj if (this->_M_equals(__k, __code, __p)) 148138fd1498Szrj ++__result; 148238fd1498Szrj else if (__result) 148338fd1498Szrj // All equivalent values are next to each other, if we 148438fd1498Szrj // found a non-equivalent value after an equivalent one it 148538fd1498Szrj // means that we won't find any new equivalent value. 148638fd1498Szrj break; 148738fd1498Szrj if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n) 148838fd1498Szrj break; 148938fd1498Szrj } 149038fd1498Szrj return __result; 149138fd1498Szrj } 149238fd1498Szrj 149338fd1498Szrj template<typename _Key, typename _Value, 149438fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 149538fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 149638fd1498Szrj typename _Traits> 149738fd1498Szrj auto 149838fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 149938fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 150038fd1498Szrj equal_range(const key_type& __k) 150138fd1498Szrj -> pair<iterator, iterator> 150238fd1498Szrj { 150338fd1498Szrj __hash_code __code = this->_M_hash_code(__k); 150438fd1498Szrj std::size_t __n = _M_bucket_index(__k, __code); 150538fd1498Szrj __node_type* __p = _M_find_node(__n, __k, __code); 150638fd1498Szrj 150738fd1498Szrj if (__p) 150838fd1498Szrj { 150938fd1498Szrj __node_type* __p1 = __p->_M_next(); 151038fd1498Szrj while (__p1 && _M_bucket_index(__p1) == __n 151138fd1498Szrj && this->_M_equals(__k, __code, __p1)) 151238fd1498Szrj __p1 = __p1->_M_next(); 151338fd1498Szrj 151438fd1498Szrj return std::make_pair(iterator(__p), iterator(__p1)); 151538fd1498Szrj } 151638fd1498Szrj else 151738fd1498Szrj return std::make_pair(end(), end()); 151838fd1498Szrj } 151938fd1498Szrj 152038fd1498Szrj template<typename _Key, typename _Value, 152138fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 152238fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 152338fd1498Szrj typename _Traits> 152438fd1498Szrj auto 152538fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 152638fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 152738fd1498Szrj equal_range(const key_type& __k) const 152838fd1498Szrj -> pair<const_iterator, const_iterator> 152938fd1498Szrj { 153038fd1498Szrj __hash_code __code = this->_M_hash_code(__k); 153138fd1498Szrj std::size_t __n = _M_bucket_index(__k, __code); 153238fd1498Szrj __node_type* __p = _M_find_node(__n, __k, __code); 153338fd1498Szrj 153438fd1498Szrj if (__p) 153538fd1498Szrj { 153638fd1498Szrj __node_type* __p1 = __p->_M_next(); 153738fd1498Szrj while (__p1 && _M_bucket_index(__p1) == __n 153838fd1498Szrj && this->_M_equals(__k, __code, __p1)) 153938fd1498Szrj __p1 = __p1->_M_next(); 154038fd1498Szrj 154138fd1498Szrj return std::make_pair(const_iterator(__p), const_iterator(__p1)); 154238fd1498Szrj } 154338fd1498Szrj else 154438fd1498Szrj return std::make_pair(end(), end()); 154538fd1498Szrj } 154638fd1498Szrj 154738fd1498Szrj // Find the node whose key compares equal to k in the bucket n. 154838fd1498Szrj // Return nullptr if no node is found. 154938fd1498Szrj template<typename _Key, typename _Value, 155038fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 155138fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 155238fd1498Szrj typename _Traits> 155338fd1498Szrj auto 155438fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 155538fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 155638fd1498Szrj _M_find_before_node(size_type __n, const key_type& __k, 155738fd1498Szrj __hash_code __code) const 155838fd1498Szrj -> __node_base* 155938fd1498Szrj { 156038fd1498Szrj __node_base* __prev_p = _M_buckets[__n]; 156138fd1498Szrj if (!__prev_p) 156238fd1498Szrj return nullptr; 156338fd1498Szrj 156438fd1498Szrj for (__node_type* __p = static_cast<__node_type*>(__prev_p->_M_nxt);; 156538fd1498Szrj __p = __p->_M_next()) 156638fd1498Szrj { 156738fd1498Szrj if (this->_M_equals(__k, __code, __p)) 156838fd1498Szrj return __prev_p; 156938fd1498Szrj 157038fd1498Szrj if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n) 157138fd1498Szrj break; 157238fd1498Szrj __prev_p = __p; 157338fd1498Szrj } 157438fd1498Szrj return nullptr; 157538fd1498Szrj } 157638fd1498Szrj 157738fd1498Szrj template<typename _Key, typename _Value, 157838fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 157938fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 158038fd1498Szrj typename _Traits> 158138fd1498Szrj void 158238fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 158338fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 158438fd1498Szrj _M_insert_bucket_begin(size_type __bkt, __node_type* __node) 158538fd1498Szrj { 158638fd1498Szrj if (_M_buckets[__bkt]) 158738fd1498Szrj { 158838fd1498Szrj // Bucket is not empty, we just need to insert the new node 158938fd1498Szrj // after the bucket before begin. 159038fd1498Szrj __node->_M_nxt = _M_buckets[__bkt]->_M_nxt; 159138fd1498Szrj _M_buckets[__bkt]->_M_nxt = __node; 159238fd1498Szrj } 159338fd1498Szrj else 159438fd1498Szrj { 159538fd1498Szrj // The bucket is empty, the new node is inserted at the 159638fd1498Szrj // beginning of the singly-linked list and the bucket will 159738fd1498Szrj // contain _M_before_begin pointer. 159838fd1498Szrj __node->_M_nxt = _M_before_begin._M_nxt; 159938fd1498Szrj _M_before_begin._M_nxt = __node; 160038fd1498Szrj if (__node->_M_nxt) 160138fd1498Szrj // We must update former begin bucket that is pointing to 160238fd1498Szrj // _M_before_begin. 160338fd1498Szrj _M_buckets[_M_bucket_index(__node->_M_next())] = __node; 160438fd1498Szrj _M_buckets[__bkt] = &_M_before_begin; 160538fd1498Szrj } 160638fd1498Szrj } 160738fd1498Szrj 160838fd1498Szrj template<typename _Key, typename _Value, 160938fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 161038fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 161138fd1498Szrj typename _Traits> 161238fd1498Szrj void 161338fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 161438fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 161538fd1498Szrj _M_remove_bucket_begin(size_type __bkt, __node_type* __next, 161638fd1498Szrj size_type __next_bkt) 161738fd1498Szrj { 161838fd1498Szrj if (!__next || __next_bkt != __bkt) 161938fd1498Szrj { 162038fd1498Szrj // Bucket is now empty 162138fd1498Szrj // First update next bucket if any 162238fd1498Szrj if (__next) 162338fd1498Szrj _M_buckets[__next_bkt] = _M_buckets[__bkt]; 162438fd1498Szrj 162538fd1498Szrj // Second update before begin node if necessary 162638fd1498Szrj if (&_M_before_begin == _M_buckets[__bkt]) 162738fd1498Szrj _M_before_begin._M_nxt = __next; 162838fd1498Szrj _M_buckets[__bkt] = nullptr; 162938fd1498Szrj } 163038fd1498Szrj } 163138fd1498Szrj 163238fd1498Szrj template<typename _Key, typename _Value, 163338fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 163438fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 163538fd1498Szrj typename _Traits> 163638fd1498Szrj auto 163738fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 163838fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 163938fd1498Szrj _M_get_previous_node(size_type __bkt, __node_base* __n) 164038fd1498Szrj -> __node_base* 164138fd1498Szrj { 164238fd1498Szrj __node_base* __prev_n = _M_buckets[__bkt]; 164338fd1498Szrj while (__prev_n->_M_nxt != __n) 164438fd1498Szrj __prev_n = __prev_n->_M_nxt; 164538fd1498Szrj return __prev_n; 164638fd1498Szrj } 164738fd1498Szrj 164838fd1498Szrj template<typename _Key, typename _Value, 164938fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 165038fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 165138fd1498Szrj typename _Traits> 165238fd1498Szrj template<typename... _Args> 165338fd1498Szrj auto 165438fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 165538fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 165638fd1498Szrj _M_emplace(std::true_type, _Args&&... __args) 165738fd1498Szrj -> pair<iterator, bool> 165838fd1498Szrj { 165938fd1498Szrj // First build the node to get access to the hash code 166038fd1498Szrj __node_type* __node = this->_M_allocate_node(std::forward<_Args>(__args)...); 166138fd1498Szrj const key_type& __k = this->_M_extract()(__node->_M_v()); 166238fd1498Szrj __hash_code __code; 166338fd1498Szrj __try 166438fd1498Szrj { 166538fd1498Szrj __code = this->_M_hash_code(__k); 166638fd1498Szrj } 166738fd1498Szrj __catch(...) 166838fd1498Szrj { 166938fd1498Szrj this->_M_deallocate_node(__node); 167038fd1498Szrj __throw_exception_again; 167138fd1498Szrj } 167238fd1498Szrj 167338fd1498Szrj size_type __bkt = _M_bucket_index(__k, __code); 167438fd1498Szrj if (__node_type* __p = _M_find_node(__bkt, __k, __code)) 167538fd1498Szrj { 167638fd1498Szrj // There is already an equivalent node, no insertion 167738fd1498Szrj this->_M_deallocate_node(__node); 167838fd1498Szrj return std::make_pair(iterator(__p), false); 167938fd1498Szrj } 168038fd1498Szrj 168138fd1498Szrj // Insert the node 168238fd1498Szrj return std::make_pair(_M_insert_unique_node(__bkt, __code, __node), 168338fd1498Szrj true); 168438fd1498Szrj } 168538fd1498Szrj 168638fd1498Szrj template<typename _Key, typename _Value, 168738fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 168838fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 168938fd1498Szrj typename _Traits> 169038fd1498Szrj template<typename... _Args> 169138fd1498Szrj auto 169238fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 169338fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 169438fd1498Szrj _M_emplace(const_iterator __hint, std::false_type, _Args&&... __args) 169538fd1498Szrj -> iterator 169638fd1498Szrj { 169738fd1498Szrj // First build the node to get its hash code. 169838fd1498Szrj __node_type* __node = 169938fd1498Szrj this->_M_allocate_node(std::forward<_Args>(__args)...); 170038fd1498Szrj 170138fd1498Szrj __hash_code __code; 170238fd1498Szrj __try 170338fd1498Szrj { 170438fd1498Szrj __code = this->_M_hash_code(this->_M_extract()(__node->_M_v())); 170538fd1498Szrj } 170638fd1498Szrj __catch(...) 170738fd1498Szrj { 170838fd1498Szrj this->_M_deallocate_node(__node); 170938fd1498Szrj __throw_exception_again; 171038fd1498Szrj } 171138fd1498Szrj 171238fd1498Szrj return _M_insert_multi_node(__hint._M_cur, __code, __node); 171338fd1498Szrj } 171438fd1498Szrj 171538fd1498Szrj template<typename _Key, typename _Value, 171638fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 171738fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 171838fd1498Szrj typename _Traits> 171938fd1498Szrj auto 172038fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 172138fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 172238fd1498Szrj _M_insert_unique_node(size_type __bkt, __hash_code __code, 172338fd1498Szrj __node_type* __node, size_type __n_elt) 172438fd1498Szrj -> iterator 172538fd1498Szrj { 172638fd1498Szrj const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 172738fd1498Szrj std::pair<bool, std::size_t> __do_rehash 172838fd1498Szrj = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 172938fd1498Szrj __n_elt); 173038fd1498Szrj 173138fd1498Szrj __try 173238fd1498Szrj { 173338fd1498Szrj if (__do_rehash.first) 173438fd1498Szrj { 173538fd1498Szrj _M_rehash(__do_rehash.second, __saved_state); 173638fd1498Szrj __bkt = _M_bucket_index(this->_M_extract()(__node->_M_v()), __code); 173738fd1498Szrj } 173838fd1498Szrj 173938fd1498Szrj this->_M_store_code(__node, __code); 174038fd1498Szrj 174138fd1498Szrj // Always insert at the beginning of the bucket. 174238fd1498Szrj _M_insert_bucket_begin(__bkt, __node); 174338fd1498Szrj ++_M_element_count; 174438fd1498Szrj return iterator(__node); 174538fd1498Szrj } 174638fd1498Szrj __catch(...) 174738fd1498Szrj { 174838fd1498Szrj this->_M_deallocate_node(__node); 174938fd1498Szrj __throw_exception_again; 175038fd1498Szrj } 175138fd1498Szrj } 175238fd1498Szrj 175338fd1498Szrj // Insert node, in bucket bkt if no rehash (assumes no element with its key 175438fd1498Szrj // already present). Take ownership of the node, deallocate it on exception. 175538fd1498Szrj template<typename _Key, typename _Value, 175638fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 175738fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 175838fd1498Szrj typename _Traits> 175938fd1498Szrj auto 176038fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 176138fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 176238fd1498Szrj _M_insert_multi_node(__node_type* __hint, __hash_code __code, 176338fd1498Szrj __node_type* __node) 176438fd1498Szrj -> iterator 176538fd1498Szrj { 176638fd1498Szrj const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 176738fd1498Szrj std::pair<bool, std::size_t> __do_rehash 176838fd1498Szrj = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1); 176938fd1498Szrj 177038fd1498Szrj __try 177138fd1498Szrj { 177238fd1498Szrj if (__do_rehash.first) 177338fd1498Szrj _M_rehash(__do_rehash.second, __saved_state); 177438fd1498Szrj 177538fd1498Szrj this->_M_store_code(__node, __code); 177638fd1498Szrj const key_type& __k = this->_M_extract()(__node->_M_v()); 177738fd1498Szrj size_type __bkt = _M_bucket_index(__k, __code); 177838fd1498Szrj 177938fd1498Szrj // Find the node before an equivalent one or use hint if it exists and 178038fd1498Szrj // if it is equivalent. 178138fd1498Szrj __node_base* __prev 178238fd1498Szrj = __builtin_expect(__hint != nullptr, false) 178338fd1498Szrj && this->_M_equals(__k, __code, __hint) 178438fd1498Szrj ? __hint 178538fd1498Szrj : _M_find_before_node(__bkt, __k, __code); 178638fd1498Szrj if (__prev) 178738fd1498Szrj { 178838fd1498Szrj // Insert after the node before the equivalent one. 178938fd1498Szrj __node->_M_nxt = __prev->_M_nxt; 179038fd1498Szrj __prev->_M_nxt = __node; 179138fd1498Szrj if (__builtin_expect(__prev == __hint, false)) 179238fd1498Szrj // hint might be the last bucket node, in this case we need to 179338fd1498Szrj // update next bucket. 179438fd1498Szrj if (__node->_M_nxt 179538fd1498Szrj && !this->_M_equals(__k, __code, __node->_M_next())) 179638fd1498Szrj { 179738fd1498Szrj size_type __next_bkt = _M_bucket_index(__node->_M_next()); 179838fd1498Szrj if (__next_bkt != __bkt) 179938fd1498Szrj _M_buckets[__next_bkt] = __node; 180038fd1498Szrj } 180138fd1498Szrj } 180238fd1498Szrj else 180338fd1498Szrj // The inserted node has no equivalent in the 180438fd1498Szrj // hashtable. We must insert the new node at the 180538fd1498Szrj // beginning of the bucket to preserve equivalent 180638fd1498Szrj // elements' relative positions. 180738fd1498Szrj _M_insert_bucket_begin(__bkt, __node); 180838fd1498Szrj ++_M_element_count; 180938fd1498Szrj return iterator(__node); 181038fd1498Szrj } 181138fd1498Szrj __catch(...) 181238fd1498Szrj { 181338fd1498Szrj this->_M_deallocate_node(__node); 181438fd1498Szrj __throw_exception_again; 181538fd1498Szrj } 181638fd1498Szrj } 181738fd1498Szrj 181838fd1498Szrj // Insert v if no element with its key is already present. 181938fd1498Szrj template<typename _Key, typename _Value, 182038fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 182138fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 182238fd1498Szrj typename _Traits> 182338fd1498Szrj template<typename _Arg, typename _NodeGenerator> 182438fd1498Szrj auto 182538fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 182638fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 182738fd1498Szrj _M_insert(_Arg&& __v, const _NodeGenerator& __node_gen, true_type, 182838fd1498Szrj size_type __n_elt) 182938fd1498Szrj -> pair<iterator, bool> 183038fd1498Szrj { 183138fd1498Szrj const key_type& __k = this->_M_extract()(__v); 183238fd1498Szrj __hash_code __code = this->_M_hash_code(__k); 183338fd1498Szrj size_type __bkt = _M_bucket_index(__k, __code); 183438fd1498Szrj 183538fd1498Szrj __node_type* __n = _M_find_node(__bkt, __k, __code); 183638fd1498Szrj if (__n) 183738fd1498Szrj return std::make_pair(iterator(__n), false); 183838fd1498Szrj 183938fd1498Szrj __n = __node_gen(std::forward<_Arg>(__v)); 184038fd1498Szrj return { _M_insert_unique_node(__bkt, __code, __n, __n_elt), true }; 184138fd1498Szrj } 184238fd1498Szrj 184338fd1498Szrj // Insert v unconditionally. 184438fd1498Szrj template<typename _Key, typename _Value, 184538fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 184638fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 184738fd1498Szrj typename _Traits> 184838fd1498Szrj template<typename _Arg, typename _NodeGenerator> 184938fd1498Szrj auto 185038fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 185138fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 185238fd1498Szrj _M_insert(const_iterator __hint, _Arg&& __v, 185338fd1498Szrj const _NodeGenerator& __node_gen, false_type) 185438fd1498Szrj -> iterator 185538fd1498Szrj { 185638fd1498Szrj // First compute the hash code so that we don't do anything if it 185738fd1498Szrj // throws. 185838fd1498Szrj __hash_code __code = this->_M_hash_code(this->_M_extract()(__v)); 185938fd1498Szrj 186038fd1498Szrj // Second allocate new node so that we don't rehash if it throws. 186138fd1498Szrj __node_type* __node = __node_gen(std::forward<_Arg>(__v)); 186238fd1498Szrj 186338fd1498Szrj return _M_insert_multi_node(__hint._M_cur, __code, __node); 186438fd1498Szrj } 186538fd1498Szrj 186638fd1498Szrj template<typename _Key, typename _Value, 186738fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 186838fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 186938fd1498Szrj typename _Traits> 187038fd1498Szrj auto 187138fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 187238fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 187338fd1498Szrj erase(const_iterator __it) 187438fd1498Szrj -> iterator 187538fd1498Szrj { 187638fd1498Szrj __node_type* __n = __it._M_cur; 187738fd1498Szrj std::size_t __bkt = _M_bucket_index(__n); 187838fd1498Szrj 187938fd1498Szrj // Look for previous node to unlink it from the erased one, this 188038fd1498Szrj // is why we need buckets to contain the before begin to make 188138fd1498Szrj // this search fast. 188238fd1498Szrj __node_base* __prev_n = _M_get_previous_node(__bkt, __n); 188338fd1498Szrj return _M_erase(__bkt, __prev_n, __n); 188438fd1498Szrj } 188538fd1498Szrj 188638fd1498Szrj template<typename _Key, typename _Value, 188738fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 188838fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 188938fd1498Szrj typename _Traits> 189038fd1498Szrj auto 189138fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 189238fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 189338fd1498Szrj _M_erase(size_type __bkt, __node_base* __prev_n, __node_type* __n) 189438fd1498Szrj -> iterator 189538fd1498Szrj { 189638fd1498Szrj if (__prev_n == _M_buckets[__bkt]) 189738fd1498Szrj _M_remove_bucket_begin(__bkt, __n->_M_next(), 189838fd1498Szrj __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0); 189938fd1498Szrj else if (__n->_M_nxt) 190038fd1498Szrj { 190138fd1498Szrj size_type __next_bkt = _M_bucket_index(__n->_M_next()); 190238fd1498Szrj if (__next_bkt != __bkt) 190338fd1498Szrj _M_buckets[__next_bkt] = __prev_n; 190438fd1498Szrj } 190538fd1498Szrj 190638fd1498Szrj __prev_n->_M_nxt = __n->_M_nxt; 190738fd1498Szrj iterator __result(__n->_M_next()); 190838fd1498Szrj this->_M_deallocate_node(__n); 190938fd1498Szrj --_M_element_count; 191038fd1498Szrj 191138fd1498Szrj return __result; 191238fd1498Szrj } 191338fd1498Szrj 191438fd1498Szrj template<typename _Key, typename _Value, 191538fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 191638fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 191738fd1498Szrj typename _Traits> 191838fd1498Szrj auto 191938fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 192038fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 192138fd1498Szrj _M_erase(std::true_type, const key_type& __k) 192238fd1498Szrj -> size_type 192338fd1498Szrj { 192438fd1498Szrj __hash_code __code = this->_M_hash_code(__k); 192538fd1498Szrj std::size_t __bkt = _M_bucket_index(__k, __code); 192638fd1498Szrj 192738fd1498Szrj // Look for the node before the first matching node. 192838fd1498Szrj __node_base* __prev_n = _M_find_before_node(__bkt, __k, __code); 192938fd1498Szrj if (!__prev_n) 193038fd1498Szrj return 0; 193138fd1498Szrj 193238fd1498Szrj // We found a matching node, erase it. 193338fd1498Szrj __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt); 193438fd1498Szrj _M_erase(__bkt, __prev_n, __n); 193538fd1498Szrj return 1; 193638fd1498Szrj } 193738fd1498Szrj 193838fd1498Szrj template<typename _Key, typename _Value, 193938fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 194038fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 194138fd1498Szrj typename _Traits> 194238fd1498Szrj auto 194338fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 194438fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 194538fd1498Szrj _M_erase(std::false_type, const key_type& __k) 194638fd1498Szrj -> size_type 194738fd1498Szrj { 194838fd1498Szrj __hash_code __code = this->_M_hash_code(__k); 194938fd1498Szrj std::size_t __bkt = _M_bucket_index(__k, __code); 195038fd1498Szrj 195138fd1498Szrj // Look for the node before the first matching node. 195238fd1498Szrj __node_base* __prev_n = _M_find_before_node(__bkt, __k, __code); 195338fd1498Szrj if (!__prev_n) 195438fd1498Szrj return 0; 195538fd1498Szrj 195638fd1498Szrj // _GLIBCXX_RESOLVE_LIB_DEFECTS 195738fd1498Szrj // 526. Is it undefined if a function in the standard changes 195838fd1498Szrj // in parameters? 195938fd1498Szrj // We use one loop to find all matching nodes and another to deallocate 196038fd1498Szrj // them so that the key stays valid during the first loop. It might be 196138fd1498Szrj // invalidated indirectly when destroying nodes. 196238fd1498Szrj __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt); 196338fd1498Szrj __node_type* __n_last = __n; 196438fd1498Szrj std::size_t __n_last_bkt = __bkt; 196538fd1498Szrj do 196638fd1498Szrj { 196738fd1498Szrj __n_last = __n_last->_M_next(); 196838fd1498Szrj if (!__n_last) 196938fd1498Szrj break; 197038fd1498Szrj __n_last_bkt = _M_bucket_index(__n_last); 197138fd1498Szrj } 197238fd1498Szrj while (__n_last_bkt == __bkt && this->_M_equals(__k, __code, __n_last)); 197338fd1498Szrj 197438fd1498Szrj // Deallocate nodes. 197538fd1498Szrj size_type __result = 0; 197638fd1498Szrj do 197738fd1498Szrj { 197838fd1498Szrj __node_type* __p = __n->_M_next(); 197938fd1498Szrj this->_M_deallocate_node(__n); 198038fd1498Szrj __n = __p; 198138fd1498Szrj ++__result; 198238fd1498Szrj --_M_element_count; 198338fd1498Szrj } 198438fd1498Szrj while (__n != __n_last); 198538fd1498Szrj 198638fd1498Szrj if (__prev_n == _M_buckets[__bkt]) 198738fd1498Szrj _M_remove_bucket_begin(__bkt, __n_last, __n_last_bkt); 198838fd1498Szrj else if (__n_last && __n_last_bkt != __bkt) 198938fd1498Szrj _M_buckets[__n_last_bkt] = __prev_n; 199038fd1498Szrj __prev_n->_M_nxt = __n_last; 199138fd1498Szrj return __result; 199238fd1498Szrj } 199338fd1498Szrj 199438fd1498Szrj template<typename _Key, typename _Value, 199538fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 199638fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 199738fd1498Szrj typename _Traits> 199838fd1498Szrj auto 199938fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 200038fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 200138fd1498Szrj erase(const_iterator __first, const_iterator __last) 200238fd1498Szrj -> iterator 200338fd1498Szrj { 200438fd1498Szrj __node_type* __n = __first._M_cur; 200538fd1498Szrj __node_type* __last_n = __last._M_cur; 200638fd1498Szrj if (__n == __last_n) 200738fd1498Szrj return iterator(__n); 200838fd1498Szrj 200938fd1498Szrj std::size_t __bkt = _M_bucket_index(__n); 201038fd1498Szrj 201138fd1498Szrj __node_base* __prev_n = _M_get_previous_node(__bkt, __n); 201238fd1498Szrj bool __is_bucket_begin = __n == _M_bucket_begin(__bkt); 201338fd1498Szrj std::size_t __n_bkt = __bkt; 201438fd1498Szrj for (;;) 201538fd1498Szrj { 201638fd1498Szrj do 201738fd1498Szrj { 201838fd1498Szrj __node_type* __tmp = __n; 201938fd1498Szrj __n = __n->_M_next(); 202038fd1498Szrj this->_M_deallocate_node(__tmp); 202138fd1498Szrj --_M_element_count; 202238fd1498Szrj if (!__n) 202338fd1498Szrj break; 202438fd1498Szrj __n_bkt = _M_bucket_index(__n); 202538fd1498Szrj } 202638fd1498Szrj while (__n != __last_n && __n_bkt == __bkt); 202738fd1498Szrj if (__is_bucket_begin) 202838fd1498Szrj _M_remove_bucket_begin(__bkt, __n, __n_bkt); 202938fd1498Szrj if (__n == __last_n) 203038fd1498Szrj break; 203138fd1498Szrj __is_bucket_begin = true; 203238fd1498Szrj __bkt = __n_bkt; 203338fd1498Szrj } 203438fd1498Szrj 203538fd1498Szrj if (__n && (__n_bkt != __bkt || __is_bucket_begin)) 203638fd1498Szrj _M_buckets[__n_bkt] = __prev_n; 203738fd1498Szrj __prev_n->_M_nxt = __n; 203838fd1498Szrj return iterator(__n); 203938fd1498Szrj } 204038fd1498Szrj 204138fd1498Szrj template<typename _Key, typename _Value, 204238fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 204338fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 204438fd1498Szrj typename _Traits> 204538fd1498Szrj void 204638fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 204738fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 204838fd1498Szrj clear() noexcept 204938fd1498Szrj { 205038fd1498Szrj this->_M_deallocate_nodes(_M_begin()); 205138fd1498Szrj __builtin_memset(_M_buckets, 0, _M_bucket_count * sizeof(__bucket_type)); 205238fd1498Szrj _M_element_count = 0; 205338fd1498Szrj _M_before_begin._M_nxt = nullptr; 205438fd1498Szrj } 205538fd1498Szrj 205638fd1498Szrj template<typename _Key, typename _Value, 205738fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 205838fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 205938fd1498Szrj typename _Traits> 206038fd1498Szrj void 206138fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 206238fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 206338fd1498Szrj rehash(size_type __n) 206438fd1498Szrj { 206538fd1498Szrj const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 206638fd1498Szrj std::size_t __buckets 206738fd1498Szrj = std::max(_M_rehash_policy._M_bkt_for_elements(_M_element_count + 1), 206838fd1498Szrj __n); 206938fd1498Szrj __buckets = _M_rehash_policy._M_next_bkt(__buckets); 207038fd1498Szrj 207138fd1498Szrj if (__buckets != _M_bucket_count) 207238fd1498Szrj _M_rehash(__buckets, __saved_state); 207338fd1498Szrj else 207438fd1498Szrj // No rehash, restore previous state to keep a consistent state. 207538fd1498Szrj _M_rehash_policy._M_reset(__saved_state); 207638fd1498Szrj } 207738fd1498Szrj 207838fd1498Szrj template<typename _Key, typename _Value, 207938fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 208038fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 208138fd1498Szrj typename _Traits> 208238fd1498Szrj void 208338fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 208438fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 208538fd1498Szrj _M_rehash(size_type __n, const __rehash_state& __state) 208638fd1498Szrj { 208738fd1498Szrj __try 208838fd1498Szrj { 208938fd1498Szrj _M_rehash_aux(__n, __unique_keys()); 209038fd1498Szrj } 209138fd1498Szrj __catch(...) 209238fd1498Szrj { 209338fd1498Szrj // A failure here means that buckets allocation failed. We only 209438fd1498Szrj // have to restore hash policy previous state. 209538fd1498Szrj _M_rehash_policy._M_reset(__state); 209638fd1498Szrj __throw_exception_again; 209738fd1498Szrj } 209838fd1498Szrj } 209938fd1498Szrj 210038fd1498Szrj // Rehash when there is no equivalent elements. 210138fd1498Szrj template<typename _Key, typename _Value, 210238fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 210338fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 210438fd1498Szrj typename _Traits> 210538fd1498Szrj void 210638fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 210738fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 210838fd1498Szrj _M_rehash_aux(size_type __n, std::true_type) 210938fd1498Szrj { 211038fd1498Szrj __bucket_type* __new_buckets = _M_allocate_buckets(__n); 211138fd1498Szrj __node_type* __p = _M_begin(); 211238fd1498Szrj _M_before_begin._M_nxt = nullptr; 211338fd1498Szrj std::size_t __bbegin_bkt = 0; 211438fd1498Szrj while (__p) 211538fd1498Szrj { 211638fd1498Szrj __node_type* __next = __p->_M_next(); 211738fd1498Szrj std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); 211838fd1498Szrj if (!__new_buckets[__bkt]) 211938fd1498Szrj { 212038fd1498Szrj __p->_M_nxt = _M_before_begin._M_nxt; 212138fd1498Szrj _M_before_begin._M_nxt = __p; 212238fd1498Szrj __new_buckets[__bkt] = &_M_before_begin; 212338fd1498Szrj if (__p->_M_nxt) 212438fd1498Szrj __new_buckets[__bbegin_bkt] = __p; 212538fd1498Szrj __bbegin_bkt = __bkt; 212638fd1498Szrj } 212738fd1498Szrj else 212838fd1498Szrj { 212938fd1498Szrj __p->_M_nxt = __new_buckets[__bkt]->_M_nxt; 213038fd1498Szrj __new_buckets[__bkt]->_M_nxt = __p; 213138fd1498Szrj } 213238fd1498Szrj __p = __next; 213338fd1498Szrj } 213438fd1498Szrj 213538fd1498Szrj _M_deallocate_buckets(); 213638fd1498Szrj _M_bucket_count = __n; 213738fd1498Szrj _M_buckets = __new_buckets; 213838fd1498Szrj } 213938fd1498Szrj 214038fd1498Szrj // Rehash when there can be equivalent elements, preserve their relative 214138fd1498Szrj // order. 214238fd1498Szrj template<typename _Key, typename _Value, 214338fd1498Szrj typename _Alloc, typename _ExtractKey, typename _Equal, 214438fd1498Szrj typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 214538fd1498Szrj typename _Traits> 214638fd1498Szrj void 214738fd1498Szrj _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 214838fd1498Szrj _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 214938fd1498Szrj _M_rehash_aux(size_type __n, std::false_type) 215038fd1498Szrj { 215138fd1498Szrj __bucket_type* __new_buckets = _M_allocate_buckets(__n); 215238fd1498Szrj 215338fd1498Szrj __node_type* __p = _M_begin(); 215438fd1498Szrj _M_before_begin._M_nxt = nullptr; 215538fd1498Szrj std::size_t __bbegin_bkt = 0; 215638fd1498Szrj std::size_t __prev_bkt = 0; 215738fd1498Szrj __node_type* __prev_p = nullptr; 215838fd1498Szrj bool __check_bucket = false; 215938fd1498Szrj 216038fd1498Szrj while (__p) 216138fd1498Szrj { 216238fd1498Szrj __node_type* __next = __p->_M_next(); 216338fd1498Szrj std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); 216438fd1498Szrj 216538fd1498Szrj if (__prev_p && __prev_bkt == __bkt) 216638fd1498Szrj { 216738fd1498Szrj // Previous insert was already in this bucket, we insert after 216838fd1498Szrj // the previously inserted one to preserve equivalent elements 216938fd1498Szrj // relative order. 217038fd1498Szrj __p->_M_nxt = __prev_p->_M_nxt; 217138fd1498Szrj __prev_p->_M_nxt = __p; 217238fd1498Szrj 217338fd1498Szrj // Inserting after a node in a bucket require to check that we 217438fd1498Szrj // haven't change the bucket last node, in this case next 217538fd1498Szrj // bucket containing its before begin node must be updated. We 217638fd1498Szrj // schedule a check as soon as we move out of the sequence of 217738fd1498Szrj // equivalent nodes to limit the number of checks. 217838fd1498Szrj __check_bucket = true; 217938fd1498Szrj } 218038fd1498Szrj else 218138fd1498Szrj { 218238fd1498Szrj if (__check_bucket) 218338fd1498Szrj { 218438fd1498Szrj // Check if we shall update the next bucket because of 218538fd1498Szrj // insertions into __prev_bkt bucket. 218638fd1498Szrj if (__prev_p->_M_nxt) 218738fd1498Szrj { 218838fd1498Szrj std::size_t __next_bkt 218938fd1498Szrj = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), 219038fd1498Szrj __n); 219138fd1498Szrj if (__next_bkt != __prev_bkt) 219238fd1498Szrj __new_buckets[__next_bkt] = __prev_p; 219338fd1498Szrj } 219438fd1498Szrj __check_bucket = false; 219538fd1498Szrj } 219638fd1498Szrj 219738fd1498Szrj if (!__new_buckets[__bkt]) 219838fd1498Szrj { 219938fd1498Szrj __p->_M_nxt = _M_before_begin._M_nxt; 220038fd1498Szrj _M_before_begin._M_nxt = __p; 220138fd1498Szrj __new_buckets[__bkt] = &_M_before_begin; 220238fd1498Szrj if (__p->_M_nxt) 220338fd1498Szrj __new_buckets[__bbegin_bkt] = __p; 220438fd1498Szrj __bbegin_bkt = __bkt; 220538fd1498Szrj } 220638fd1498Szrj else 220738fd1498Szrj { 220838fd1498Szrj __p->_M_nxt = __new_buckets[__bkt]->_M_nxt; 220938fd1498Szrj __new_buckets[__bkt]->_M_nxt = __p; 221038fd1498Szrj } 221138fd1498Szrj } 221238fd1498Szrj __prev_p = __p; 221338fd1498Szrj __prev_bkt = __bkt; 221438fd1498Szrj __p = __next; 221538fd1498Szrj } 221638fd1498Szrj 221738fd1498Szrj if (__check_bucket && __prev_p->_M_nxt) 221838fd1498Szrj { 221938fd1498Szrj std::size_t __next_bkt 222038fd1498Szrj = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), __n); 222138fd1498Szrj if (__next_bkt != __prev_bkt) 222238fd1498Szrj __new_buckets[__next_bkt] = __prev_p; 222338fd1498Szrj } 222438fd1498Szrj 222538fd1498Szrj _M_deallocate_buckets(); 222638fd1498Szrj _M_bucket_count = __n; 222738fd1498Szrj _M_buckets = __new_buckets; 222838fd1498Szrj } 222938fd1498Szrj 223038fd1498Szrj #if __cplusplus > 201402L 223138fd1498Szrj template<typename, typename, typename> class _Hash_merge_helper { }; 223238fd1498Szrj #endif // C++17 223338fd1498Szrj 223438fd1498Szrj _GLIBCXX_END_NAMESPACE_VERSION 223538fd1498Szrj } // namespace std 223638fd1498Szrj 223738fd1498Szrj #endif // _HASHTABLE_H 2238