xref: /dflybsd-src/contrib/gcc-8.0/libstdc++-v3/include/bits/hashtable.h (revision 95059079af47f9a66a175f374f2da1a5020e3255)
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 
_GLIBCXX_VISIBILITY(default)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