libstdc++
hashtable.h
Go to the documentation of this file.
00001 // hashtable.h header -*- C++ -*-
00002 
00003 // Copyright (C) 2007-2018 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 3, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // Under Section 7 of GPL version 3, you are granted additional
00017 // permissions described in the GCC Runtime Library Exception, version
00018 // 3.1, as published by the Free Software Foundation.
00019 
00020 // You should have received a copy of the GNU General Public License and
00021 // a copy of the GCC Runtime Library Exception along with this program;
00022 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023 // <http://www.gnu.org/licenses/>.
00024 
00025 /** @file bits/hashtable.h
00026  *  This is an internal header file, included by other library headers.
00027  *  Do not attempt to use it directly. @headername{unordered_map, unordered_set}
00028  */
00029 
00030 #ifndef _HASHTABLE_H
00031 #define _HASHTABLE_H 1
00032 
00033 #pragma GCC system_header
00034 
00035 #include <bits/hashtable_policy.h>
00036 #if __cplusplus > 201402L
00037 # include <bits/node_handle.h>
00038 #endif
00039 
00040 namespace std _GLIBCXX_VISIBILITY(default)
00041 {
00042 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00043 
00044   template<typename _Tp, typename _Hash>
00045     using __cache_default
00046       =  __not_<__and_<// Do not cache for fast hasher.
00047                        __is_fast_hash<_Hash>,
00048                        // Mandatory to have erase not throwing.
00049                        __is_nothrow_invocable<const _Hash&, const _Tp&>>>;
00050 
00051   /**
00052    *  Primary class template _Hashtable.
00053    *
00054    *  @ingroup hashtable-detail
00055    *
00056    *  @tparam _Value  CopyConstructible type.
00057    *
00058    *  @tparam _Key    CopyConstructible type.
00059    *
00060    *  @tparam _Alloc  An allocator type
00061    *  ([lib.allocator.requirements]) whose _Alloc::value_type is
00062    *  _Value.  As a conforming extension, we allow for
00063    *  _Alloc::value_type != _Value.
00064    *
00065    *  @tparam _ExtractKey  Function object that takes an object of type
00066    *  _Value and returns a value of type _Key.
00067    *
00068    *  @tparam _Equal  Function object that takes two objects of type k
00069    *  and returns a bool-like value that is true if the two objects
00070    *  are considered equal.
00071    *
00072    *  @tparam _H1  The hash function. A unary function object with
00073    *  argument type _Key and result type size_t. Return values should
00074    *  be distributed over the entire range [0, numeric_limits<size_t>:::max()].
00075    *
00076    *  @tparam _H2  The range-hashing function (in the terminology of
00077    *  Tavori and Dreizin).  A binary function object whose argument
00078    *  types and result type are all size_t.  Given arguments r and N,
00079    *  the return value is in the range [0, N).
00080    *
00081    *  @tparam _Hash  The ranged hash function (Tavori and Dreizin). A
00082    *  binary function whose argument types are _Key and size_t and
00083    *  whose result type is size_t.  Given arguments k and N, the
00084    *  return value is in the range [0, N).  Default: hash(k, N) =
00085    *  h2(h1(k), N).  If _Hash is anything other than the default, _H1
00086    *  and _H2 are ignored.
00087    *
00088    *  @tparam _RehashPolicy  Policy class with three members, all of
00089    *  which govern the bucket count. _M_next_bkt(n) returns a bucket
00090    *  count no smaller than n.  _M_bkt_for_elements(n) returns a
00091    *  bucket count appropriate for an element count of n.
00092    *  _M_need_rehash(n_bkt, n_elt, n_ins) determines whether, if the
00093    *  current bucket count is n_bkt and the current element count is
00094    *  n_elt, we need to increase the bucket count.  If so, returns
00095    *  make_pair(true, n), where n is the new bucket count.  If not,
00096    *  returns make_pair(false, <anything>)
00097    *
00098    *  @tparam _Traits  Compile-time class with three boolean
00099    *  std::integral_constant members:  __cache_hash_code, __constant_iterators,
00100    *   __unique_keys.
00101    *
00102    *  Each _Hashtable data structure has:
00103    *
00104    *  - _Bucket[]       _M_buckets
00105    *  - _Hash_node_base _M_before_begin
00106    *  - size_type       _M_bucket_count
00107    *  - size_type       _M_element_count
00108    *
00109    *  with _Bucket being _Hash_node* and _Hash_node containing:
00110    *
00111    *  - _Hash_node*   _M_next
00112    *  - Tp            _M_value
00113    *  - size_t        _M_hash_code if cache_hash_code is true
00114    *
00115    *  In terms of Standard containers the hashtable is like the aggregation of:
00116    *
00117    *  - std::forward_list<_Node> containing the elements
00118    *  - std::vector<std::forward_list<_Node>::iterator> representing the buckets
00119    *
00120    *  The non-empty buckets contain the node before the first node in the
00121    *  bucket. This design makes it possible to implement something like a
00122    *  std::forward_list::insert_after on container insertion and
00123    *  std::forward_list::erase_after on container erase
00124    *  calls. _M_before_begin is equivalent to
00125    *  std::forward_list::before_begin. Empty buckets contain
00126    *  nullptr.  Note that one of the non-empty buckets contains
00127    *  &_M_before_begin which is not a dereferenceable node so the
00128    *  node pointer in a bucket shall never be dereferenced, only its
00129    *  next node can be.
00130    *
00131    *  Walking through a bucket's nodes requires a check on the hash code to
00132    *  see if each node is still in the bucket. Such a design assumes a
00133    *  quite efficient hash functor and is one of the reasons it is
00134    *  highly advisable to set __cache_hash_code to true.
00135    *
00136    *  The container iterators are simply built from nodes. This way
00137    *  incrementing the iterator is perfectly efficient independent of
00138    *  how many empty buckets there are in the container.
00139    *
00140    *  On insert we compute the element's hash code and use it to find the
00141    *  bucket index. If the element must be inserted in an empty bucket
00142    *  we add it at the beginning of the singly linked list and make the
00143    *  bucket point to _M_before_begin. The bucket that used to point to
00144    *  _M_before_begin, if any, is updated to point to its new before
00145    *  begin node.
00146    *
00147    *  On erase, the simple iterator design requires using the hash
00148    *  functor to get the index of the bucket to update. For this
00149    *  reason, when __cache_hash_code is set to false the hash functor must
00150    *  not throw and this is enforced by a static assertion.
00151    *
00152    *  Functionality is implemented by decomposition into base classes,
00153    *  where the derived _Hashtable class is used in _Map_base,
00154    *  _Insert, _Rehash_base, and _Equality base classes to access the
00155    *  "this" pointer. _Hashtable_base is used in the base classes as a
00156    *  non-recursive, fully-completed-type so that detailed nested type
00157    *  information, such as iterator type and node type, can be
00158    *  used. This is similar to the "Curiously Recurring Template
00159    *  Pattern" (CRTP) technique, but uses a reconstructed, not
00160    *  explicitly passed, template pattern.
00161    *
00162    *  Base class templates are: 
00163    *    - __detail::_Hashtable_base
00164    *    - __detail::_Map_base
00165    *    - __detail::_Insert
00166    *    - __detail::_Rehash_base
00167    *    - __detail::_Equality
00168    */
00169   template<typename _Key, typename _Value, typename _Alloc,
00170            typename _ExtractKey, typename _Equal,
00171            typename _H1, typename _H2, typename _Hash,
00172            typename _RehashPolicy, typename _Traits>
00173     class _Hashtable
00174     : public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
00175                                        _H1, _H2, _Hash, _Traits>,
00176       public __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00177                                  _H1, _H2, _Hash, _RehashPolicy, _Traits>,
00178       public __detail::_Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00179                                _H1, _H2, _Hash, _RehashPolicy, _Traits>,
00180       public __detail::_Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00181                                     _H1, _H2, _Hash, _RehashPolicy, _Traits>,
00182       public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00183                                  _H1, _H2, _Hash, _RehashPolicy, _Traits>,
00184       private __detail::_Hashtable_alloc<
00185         __alloc_rebind<_Alloc,
00186                        __detail::_Hash_node<_Value,
00187                                             _Traits::__hash_cached::value>>>
00188     {
00189       static_assert(is_same<typename remove_cv<_Value>::type, _Value>::value,
00190           "unordered container must have a non-const, non-volatile value_type");
00191 #ifdef __STRICT_ANSI__
00192       static_assert(is_same<typename _Alloc::value_type, _Value>{},
00193           "unordered container must have the same value_type as its allocator");
00194 #endif
00195 
00196       using __traits_type = _Traits;
00197       using __hash_cached = typename __traits_type::__hash_cached;
00198       using __node_type = __detail::_Hash_node<_Value, __hash_cached::value>;
00199       using __node_alloc_type = __alloc_rebind<_Alloc, __node_type>;
00200 
00201       using __hashtable_alloc = __detail::_Hashtable_alloc<__node_alloc_type>;
00202 
00203       using __value_alloc_traits =
00204         typename __hashtable_alloc::__value_alloc_traits;
00205       using __node_alloc_traits =
00206         typename __hashtable_alloc::__node_alloc_traits;
00207       using __node_base = typename __hashtable_alloc::__node_base;
00208       using __bucket_type = typename __hashtable_alloc::__bucket_type;
00209 
00210     public:
00211       typedef _Key                                              key_type;
00212       typedef _Value                                            value_type;
00213       typedef _Alloc                                            allocator_type;
00214       typedef _Equal                                            key_equal;
00215 
00216       // mapped_type, if present, comes from _Map_base.
00217       // hasher, if present, comes from _Hash_code_base/_Hashtable_base.
00218       typedef typename __value_alloc_traits::pointer            pointer;
00219       typedef typename __value_alloc_traits::const_pointer      const_pointer;
00220       typedef value_type&                                       reference;
00221       typedef const value_type&                                 const_reference;
00222 
00223     private:
00224       using __rehash_type = _RehashPolicy;
00225       using __rehash_state = typename __rehash_type::_State;
00226 
00227       using __constant_iterators = typename __traits_type::__constant_iterators;
00228       using __unique_keys = typename __traits_type::__unique_keys;
00229 
00230       using __key_extract = typename std::conditional<
00231                                              __constant_iterators::value,
00232                                              __detail::_Identity,
00233                                              __detail::_Select1st>::type;
00234 
00235       using __hashtable_base = __detail::
00236 			       _Hashtable_base<_Key, _Value, _ExtractKey,
00237                                               _Equal, _H1, _H2, _Hash, _Traits>;
00238 
00239       using __hash_code_base =  typename __hashtable_base::__hash_code_base;
00240       using __hash_code =  typename __hashtable_base::__hash_code;
00241       using __ireturn_type = typename __hashtable_base::__ireturn_type;
00242 
00243       using __map_base = __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey,
00244                                              _Equal, _H1, _H2, _Hash,
00245                                              _RehashPolicy, _Traits>;
00246 
00247       using __rehash_base = __detail::_Rehash_base<_Key, _Value, _Alloc,
00248                                                    _ExtractKey, _Equal,
00249                                                    _H1, _H2, _Hash,
00250                                                    _RehashPolicy, _Traits>;
00251 
00252       using __eq_base = __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey,
00253                                             _Equal, _H1, _H2, _Hash,
00254                                             _RehashPolicy, _Traits>;
00255 
00256       using __reuse_or_alloc_node_type =
00257         __detail::_ReuseOrAllocNode<__node_alloc_type>;
00258 
00259       // Metaprogramming for picking apart hash caching.
00260       template<typename _Cond>
00261         using __if_hash_cached = __or_<__not_<__hash_cached>, _Cond>;
00262 
00263       template<typename _Cond>
00264         using __if_hash_not_cached = __or_<__hash_cached, _Cond>;
00265 
00266       // Compile-time diagnostics.
00267 
00268       // _Hash_code_base has everything protected, so use this derived type to
00269       // access it.
00270       struct __hash_code_base_access : __hash_code_base
00271       { using __hash_code_base::_M_bucket_index; };
00272 
00273       // Getting a bucket index from a node shall not throw because it is used
00274       // in methods (erase, swap...) that shall not throw.
00275       static_assert(noexcept(declval<const __hash_code_base_access&>()
00276                              ._M_bucket_index((const __node_type*)nullptr,
00277                                               (std::size_t)0)),
00278                     "Cache the hash code or qualify your functors involved"
00279                     " in hash code and bucket index computation with noexcept");
00280 
00281       // Following two static assertions are necessary to guarantee
00282       // that local_iterator will be default constructible.
00283 
00284       // When hash codes are cached local iterator inherits from H2 functor
00285       // which must then be default constructible.
00286       static_assert(__if_hash_cached<is_default_constructible<_H2>>::value,
00287                     "Functor used to map hash code to bucket index"
00288                     " must be default constructible");
00289 
00290       template<typename _Keya, typename _Valuea, typename _Alloca,
00291                typename _ExtractKeya, typename _Equala,
00292                typename _H1a, typename _H2a, typename _Hasha,
00293                typename _RehashPolicya, typename _Traitsa,
00294                bool _Unique_keysa>
00295         friend struct __detail::_Map_base;
00296 
00297       template<typename _Keya, typename _Valuea, typename _Alloca,
00298                typename _ExtractKeya, typename _Equala,
00299                typename _H1a, typename _H2a, typename _Hasha,
00300                typename _RehashPolicya, typename _Traitsa>
00301         friend struct __detail::_Insert_base;
00302 
00303       template<typename _Keya, typename _Valuea, typename _Alloca,
00304                typename _ExtractKeya, typename _Equala,
00305                typename _H1a, typename _H2a, typename _Hasha,
00306                typename _RehashPolicya, typename _Traitsa,
00307                bool _Constant_iteratorsa>
00308         friend struct __detail::_Insert;
00309 
00310     public:
00311       using size_type = typename __hashtable_base::size_type;
00312       using difference_type = typename __hashtable_base::difference_type;
00313 
00314       using iterator = typename __hashtable_base::iterator;
00315       using const_iterator = typename __hashtable_base::const_iterator;
00316 
00317       using local_iterator = typename __hashtable_base::local_iterator;
00318       using const_local_iterator = typename __hashtable_base::
00319                                    const_local_iterator;
00320 
00321 #if __cplusplus > 201402L
00322       using node_type = _Node_handle<_Key, _Value, __node_alloc_type>;
00323       using insert_return_type = _Node_insert_return<iterator, node_type>;
00324 #endif
00325 
00326     private:
00327       __bucket_type*            _M_buckets              = &_M_single_bucket;
00328       size_type                 _M_bucket_count         = 1;
00329       __node_base               _M_before_begin;
00330       size_type                 _M_element_count        = 0;
00331       _RehashPolicy             _M_rehash_policy;
00332 
00333       // A single bucket used when only need for 1 bucket. Especially
00334       // interesting in move semantic to leave hashtable with only 1 buckets
00335       // which is not allocated so that we can have those operations noexcept
00336       // qualified.
00337       // Note that we can't leave hashtable with 0 bucket without adding
00338       // numerous checks in the code to avoid 0 modulus.
00339       __bucket_type             _M_single_bucket        = nullptr;
00340 
00341       bool
00342       _M_uses_single_bucket(__bucket_type* __bkts) const
00343       { return __builtin_expect(__bkts == &_M_single_bucket, false); }
00344 
00345       bool
00346       _M_uses_single_bucket() const
00347       { return _M_uses_single_bucket(_M_buckets); }
00348 
00349       __hashtable_alloc&
00350       _M_base_alloc() { return *this; }
00351 
00352       __bucket_type*
00353       _M_allocate_buckets(size_type __n)
00354       {
00355         if (__builtin_expect(__n == 1, false))
00356           {
00357             _M_single_bucket = nullptr;
00358             return &_M_single_bucket;
00359           }
00360 
00361         return __hashtable_alloc::_M_allocate_buckets(__n);
00362       }
00363 
00364       void
00365       _M_deallocate_buckets(__bucket_type* __bkts, size_type __n)
00366       {
00367         if (_M_uses_single_bucket(__bkts))
00368           return;
00369 
00370         __hashtable_alloc::_M_deallocate_buckets(__bkts, __n);
00371       }
00372 
00373       void
00374       _M_deallocate_buckets()
00375       { _M_deallocate_buckets(_M_buckets, _M_bucket_count); }
00376 
00377       // Gets bucket begin, deals with the fact that non-empty buckets contain
00378       // their before begin node.
00379       __node_type*
00380       _M_bucket_begin(size_type __bkt) const;
00381 
00382       __node_type*
00383       _M_begin() const
00384       { return static_cast<__node_type*>(_M_before_begin._M_nxt); }
00385 
00386       template<typename _NodeGenerator>
00387         void
00388         _M_assign(const _Hashtable&, const _NodeGenerator&);
00389 
00390       void
00391       _M_move_assign(_Hashtable&&, std::true_type);
00392 
00393       void
00394       _M_move_assign(_Hashtable&&, std::false_type);
00395 
00396       void
00397       _M_reset() noexcept;
00398 
00399       _Hashtable(const _H1& __h1, const _H2& __h2, const _Hash& __h,
00400                  const _Equal& __eq, const _ExtractKey& __exk,
00401                  const allocator_type& __a)
00402         : __hashtable_base(__exk, __h1, __h2, __h, __eq),
00403           __hashtable_alloc(__node_alloc_type(__a))
00404       { }
00405 
00406     public:
00407       // Constructor, destructor, assignment, swap
00408       _Hashtable() = default;
00409       _Hashtable(size_type __bucket_hint,
00410                  const _H1&, const _H2&, const _Hash&,
00411                  const _Equal&, const _ExtractKey&,
00412                  const allocator_type&);
00413 
00414       template<typename _InputIterator>
00415         _Hashtable(_InputIterator __first, _InputIterator __last,
00416                    size_type __bucket_hint,
00417                    const _H1&, const _H2&, const _Hash&,
00418                    const _Equal&, const _ExtractKey&,
00419                    const allocator_type&);
00420 
00421       _Hashtable(const _Hashtable&);
00422 
00423       _Hashtable(_Hashtable&&) noexcept;
00424 
00425       _Hashtable(const _Hashtable&, const allocator_type&);
00426 
00427       _Hashtable(_Hashtable&&, const allocator_type&);
00428 
00429       // Use delegating constructors.
00430       explicit
00431       _Hashtable(const allocator_type& __a)
00432         : __hashtable_alloc(__node_alloc_type(__a))
00433       { }
00434 
00435       explicit
00436       _Hashtable(size_type __n,
00437                  const _H1& __hf = _H1(),
00438                  const key_equal& __eql = key_equal(),
00439                  const allocator_type& __a = allocator_type())
00440       : _Hashtable(__n, __hf, _H2(), _Hash(), __eql,
00441                    __key_extract(), __a)
00442       { }
00443 
00444       template<typename _InputIterator>
00445         _Hashtable(_InputIterator __f, _InputIterator __l,
00446                    size_type __n = 0,
00447                    const _H1& __hf = _H1(),
00448                    const key_equal& __eql = key_equal(),
00449                    const allocator_type& __a = allocator_type())
00450         : _Hashtable(__f, __l, __n, __hf, _H2(), _Hash(), __eql,
00451                      __key_extract(), __a)
00452         { }
00453 
00454       _Hashtable(initializer_list<value_type> __l,
00455                  size_type __n = 0,
00456                  const _H1& __hf = _H1(),
00457                  const key_equal& __eql = key_equal(),
00458                  const allocator_type& __a = allocator_type())
00459       : _Hashtable(__l.begin(), __l.end(), __n, __hf, _H2(), _Hash(), __eql,
00460                    __key_extract(), __a)
00461       { }
00462 
00463       _Hashtable&
00464       operator=(const _Hashtable& __ht);
00465 
00466       _Hashtable&
00467       operator=(_Hashtable&& __ht)
00468       noexcept(__node_alloc_traits::_S_nothrow_move()
00469                && is_nothrow_move_assignable<_H1>::value
00470                && is_nothrow_move_assignable<_Equal>::value)
00471       {
00472         constexpr bool __move_storage =
00473           __node_alloc_traits::_S_propagate_on_move_assign()
00474           || __node_alloc_traits::_S_always_equal();
00475         _M_move_assign(std::move(__ht), __bool_constant<__move_storage>());
00476         return *this;
00477       }
00478 
00479       _Hashtable&
00480       operator=(initializer_list<value_type> __l)
00481       {
00482         __reuse_or_alloc_node_type __roan(_M_begin(), *this);
00483         _M_before_begin._M_nxt = nullptr;
00484         clear();
00485         this->_M_insert_range(__l.begin(), __l.end(), __roan, __unique_keys());
00486         return *this;
00487       }
00488 
00489       ~_Hashtable() noexcept;
00490 
00491       void
00492       swap(_Hashtable&)
00493       noexcept(__and_<__is_nothrow_swappable<_H1>,
00494                           __is_nothrow_swappable<_Equal>>::value);
00495 
00496       // Basic container operations
00497       iterator
00498       begin() noexcept
00499       { return iterator(_M_begin()); }
00500 
00501       const_iterator
00502       begin() const noexcept
00503       { return const_iterator(_M_begin()); }
00504 
00505       iterator
00506       end() noexcept
00507       { return iterator(nullptr); }
00508 
00509       const_iterator
00510       end() const noexcept
00511       { return const_iterator(nullptr); }
00512 
00513       const_iterator
00514       cbegin() const noexcept
00515       { return const_iterator(_M_begin()); }
00516 
00517       const_iterator
00518       cend() const noexcept
00519       { return const_iterator(nullptr); }
00520 
00521       size_type
00522       size() const noexcept
00523       { return _M_element_count; }
00524 
00525       bool
00526       empty() const noexcept
00527       { return size() == 0; }
00528 
00529       allocator_type
00530       get_allocator() const noexcept
00531       { return allocator_type(this->_M_node_allocator()); }
00532 
00533       size_type
00534       max_size() const noexcept
00535       { return __node_alloc_traits::max_size(this->_M_node_allocator()); }
00536 
00537       // Observers
00538       key_equal
00539       key_eq() const
00540       { return this->_M_eq(); }
00541 
00542       // hash_function, if present, comes from _Hash_code_base.
00543 
00544       // Bucket operations
00545       size_type
00546       bucket_count() const noexcept
00547       { return _M_bucket_count; }
00548 
00549       size_type
00550       max_bucket_count() const noexcept
00551       { return max_size(); }
00552 
00553       size_type
00554       bucket_size(size_type __n) const
00555       { return std::distance(begin(__n), end(__n)); }
00556 
00557       size_type
00558       bucket(const key_type& __k) const
00559       { return _M_bucket_index(__k, this->_M_hash_code(__k)); }
00560 
00561       local_iterator
00562       begin(size_type __n)
00563       {
00564         return local_iterator(*this, _M_bucket_begin(__n),
00565                               __n, _M_bucket_count);
00566       }
00567 
00568       local_iterator
00569       end(size_type __n)
00570       { return local_iterator(*this, nullptr, __n, _M_bucket_count); }
00571 
00572       const_local_iterator
00573       begin(size_type __n) const
00574       {
00575         return const_local_iterator(*this, _M_bucket_begin(__n),
00576                                     __n, _M_bucket_count);
00577       }
00578 
00579       const_local_iterator
00580       end(size_type __n) const
00581       { return const_local_iterator(*this, nullptr, __n, _M_bucket_count); }
00582 
00583       // DR 691.
00584       const_local_iterator
00585       cbegin(size_type __n) const
00586       {
00587         return const_local_iterator(*this, _M_bucket_begin(__n),
00588                                     __n, _M_bucket_count);
00589       }
00590 
00591       const_local_iterator
00592       cend(size_type __n) const
00593       { return const_local_iterator(*this, nullptr, __n, _M_bucket_count); }
00594 
00595       float
00596       load_factor() const noexcept
00597       {
00598         return static_cast<float>(size()) / static_cast<float>(bucket_count());
00599       }
00600 
00601       // max_load_factor, if present, comes from _Rehash_base.
00602 
00603       // Generalization of max_load_factor.  Extension, not found in
00604       // TR1.  Only useful if _RehashPolicy is something other than
00605       // the default.
00606       const _RehashPolicy&
00607       __rehash_policy() const
00608       { return _M_rehash_policy; }
00609 
00610       void
00611       __rehash_policy(const _RehashPolicy& __pol)
00612       { _M_rehash_policy = __pol; }
00613 
00614       // Lookup.
00615       iterator
00616       find(const key_type& __k);
00617 
00618       const_iterator
00619       find(const key_type& __k) const;
00620 
00621       size_type
00622       count(const key_type& __k) const;
00623 
00624       std::pair<iterator, iterator>
00625       equal_range(const key_type& __k);
00626 
00627       std::pair<const_iterator, const_iterator>
00628       equal_range(const key_type& __k) const;
00629 
00630     protected:
00631       // Bucket index computation helpers.
00632       size_type
00633       _M_bucket_index(__node_type* __n) const noexcept
00634       { return __hash_code_base::_M_bucket_index(__n, _M_bucket_count); }
00635 
00636       size_type
00637       _M_bucket_index(const key_type& __k, __hash_code __c) const
00638       { return __hash_code_base::_M_bucket_index(__k, __c, _M_bucket_count); }
00639 
00640       // Find and insert helper functions and types
00641       // Find the node before the one matching the criteria.
00642       __node_base*
00643       _M_find_before_node(size_type, const key_type&, __hash_code) const;
00644 
00645       __node_type*
00646       _M_find_node(size_type __bkt, const key_type& __key,
00647                    __hash_code __c) const
00648       {
00649         __node_base* __before_n = _M_find_before_node(__bkt, __key, __c);
00650         if (__before_n)
00651           return static_cast<__node_type*>(__before_n->_M_nxt);
00652         return nullptr;
00653       }
00654 
00655       // Insert a node at the beginning of a bucket.
00656       void
00657       _M_insert_bucket_begin(size_type, __node_type*);
00658 
00659       // Remove the bucket first node
00660       void
00661       _M_remove_bucket_begin(size_type __bkt, __node_type* __next_n,
00662                              size_type __next_bkt);
00663 
00664       // Get the node before __n in the bucket __bkt
00665       __node_base*
00666       _M_get_previous_node(size_type __bkt, __node_base* __n);
00667 
00668       // Insert node with hash code __code, in bucket bkt if no rehash (assumes
00669       // no element with its key already present). Take ownership of the node,
00670       // deallocate it on exception.
00671       iterator
00672       _M_insert_unique_node(size_type __bkt, __hash_code __code,
00673                             __node_type* __n, size_type __n_elt = 1);
00674 
00675       // Insert node with hash code __code. Take ownership of the node,
00676       // deallocate it on exception.
00677       iterator
00678       _M_insert_multi_node(__node_type* __hint,
00679                            __hash_code __code, __node_type* __n);
00680 
00681       template<typename... _Args>
00682         std::pair<iterator, bool>
00683         _M_emplace(std::true_type, _Args&&... __args);
00684 
00685       template<typename... _Args>
00686         iterator
00687         _M_emplace(std::false_type __uk, _Args&&... __args)
00688         { return _M_emplace(cend(), __uk, std::forward<_Args>(__args)...); }
00689 
00690       // Emplace with hint, useless when keys are unique.
00691       template<typename... _Args>
00692         iterator
00693         _M_emplace(const_iterator, std::true_type __uk, _Args&&... __args)
00694         { return _M_emplace(__uk, std::forward<_Args>(__args)...).first; }
00695 
00696       template<typename... _Args>
00697         iterator
00698         _M_emplace(const_iterator, std::false_type, _Args&&... __args);
00699 
00700       template<typename _Arg, typename _NodeGenerator>
00701         std::pair<iterator, bool>
00702         _M_insert(_Arg&&, const _NodeGenerator&, true_type, size_type = 1);
00703 
00704       template<typename _Arg, typename _NodeGenerator>
00705         iterator
00706         _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen,
00707                   false_type __uk)
00708         {
00709           return _M_insert(cend(), std::forward<_Arg>(__arg), __node_gen,
00710                            __uk);
00711         }
00712 
00713       // Insert with hint, not used when keys are unique.
00714       template<typename _Arg, typename _NodeGenerator>
00715         iterator
00716         _M_insert(const_iterator, _Arg&& __arg,
00717                   const _NodeGenerator& __node_gen, true_type __uk)
00718         {
00719           return
00720             _M_insert(std::forward<_Arg>(__arg), __node_gen, __uk).first;
00721         }
00722 
00723       // Insert with hint when keys are not unique.
00724       template<typename _Arg, typename _NodeGenerator>
00725         iterator
00726         _M_insert(const_iterator, _Arg&&,
00727                   const _NodeGenerator&, false_type);
00728 
00729       size_type
00730       _M_erase(std::true_type, const key_type&);
00731 
00732       size_type
00733       _M_erase(std::false_type, const key_type&);
00734 
00735       iterator
00736       _M_erase(size_type __bkt, __node_base* __prev_n, __node_type* __n);
00737 
00738     public:
00739       // Emplace
00740       template<typename... _Args>
00741         __ireturn_type
00742         emplace(_Args&&... __args)
00743         { return _M_emplace(__unique_keys(), std::forward<_Args>(__args)...); }
00744 
00745       template<typename... _Args>
00746         iterator
00747         emplace_hint(const_iterator __hint, _Args&&... __args)
00748         {
00749           return _M_emplace(__hint, __unique_keys(),
00750                             std::forward<_Args>(__args)...);
00751         }
00752 
00753       // Insert member functions via inheritance.
00754 
00755       // Erase
00756       iterator
00757       erase(const_iterator);
00758 
00759       // LWG 2059.
00760       iterator
00761       erase(iterator __it)
00762       { return erase(const_iterator(__it)); }
00763 
00764       size_type
00765       erase(const key_type& __k)
00766       { return _M_erase(__unique_keys(), __k); }
00767 
00768       iterator
00769       erase(const_iterator, const_iterator);
00770 
00771       void
00772       clear() noexcept;
00773 
00774       // Set number of buckets to be appropriate for container of n element.
00775       void rehash(size_type __n);
00776 
00777       // DR 1189.
00778       // reserve, if present, comes from _Rehash_base.
00779 
00780 #if __cplusplus > 201402L
00781       /// Re-insert an extracted node into a container with unique keys.
00782       insert_return_type
00783       _M_reinsert_node(node_type&& __nh)
00784       {
00785         insert_return_type __ret;
00786         if (__nh.empty())
00787           __ret.position = end();
00788         else
00789           {
00790             __glibcxx_assert(get_allocator() == __nh.get_allocator());
00791 
00792             const key_type& __k = __nh._M_key();
00793             __hash_code __code = this->_M_hash_code(__k);
00794             size_type __bkt = _M_bucket_index(__k, __code);
00795             if (__node_type* __n = _M_find_node(__bkt, __k, __code))
00796               {
00797                 __ret.node = std::move(__nh);
00798                 __ret.position = iterator(__n);
00799                 __ret.inserted = false;
00800               }
00801             else
00802               {
00803                 __ret.position
00804                   = _M_insert_unique_node(__bkt, __code, __nh._M_ptr);
00805                 __nh._M_ptr = nullptr;
00806                 __ret.inserted = true;
00807               }
00808           }
00809         return __ret;
00810       }
00811 
00812       /// Re-insert an extracted node into a container with equivalent keys.
00813       iterator
00814       _M_reinsert_node_multi(const_iterator __hint, node_type&& __nh)
00815       {
00816         iterator __ret;
00817         if (__nh.empty())
00818           __ret = end();
00819         else
00820           {
00821             __glibcxx_assert(get_allocator() == __nh.get_allocator());
00822 
00823             auto __code = this->_M_hash_code(__nh._M_key());
00824             auto __node = std::exchange(__nh._M_ptr, nullptr);
00825             // FIXME: this deallocates the node on exception.
00826             __ret = _M_insert_multi_node(__hint._M_cur, __code, __node);
00827           }
00828         return __ret;
00829       }
00830 
00831       /// Extract a node.
00832       node_type
00833       extract(const_iterator __pos)
00834       {
00835         __node_type* __n = __pos._M_cur;
00836         size_t __bkt = _M_bucket_index(__n);
00837 
00838         // Look for previous node to unlink it from the erased one, this
00839         // is why we need buckets to contain the before begin to make
00840         // this search fast.
00841         __node_base* __prev_n = _M_get_previous_node(__bkt, __n);
00842 
00843         if (__prev_n == _M_buckets[__bkt])
00844           _M_remove_bucket_begin(__bkt, __n->_M_next(),
00845              __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0);
00846         else if (__n->_M_nxt)
00847           {
00848             size_type __next_bkt = _M_bucket_index(__n->_M_next());
00849             if (__next_bkt != __bkt)
00850               _M_buckets[__next_bkt] = __prev_n;
00851           }
00852 
00853         __prev_n->_M_nxt = __n->_M_nxt;
00854         __n->_M_nxt = nullptr;
00855         --_M_element_count;
00856         return { __n, this->_M_node_allocator() };
00857       }
00858 
00859       /// Extract a node.
00860       node_type
00861       extract(const _Key& __k)
00862       {
00863         node_type __nh;
00864         auto __pos = find(__k);
00865         if (__pos != end())
00866           __nh = extract(const_iterator(__pos));
00867         return __nh;
00868       }
00869 
00870       /// Merge from a compatible container into one with unique keys.
00871       template<typename _Compatible_Hashtable>
00872         void
00873         _M_merge_unique(_Compatible_Hashtable& __src) noexcept
00874         {
00875           static_assert(is_same_v<typename _Compatible_Hashtable::node_type,
00876               node_type>, "Node types are compatible");
00877           __glibcxx_assert(get_allocator() == __src.get_allocator());
00878 
00879           auto __n_elt = __src.size();
00880           for (auto __i = __src.begin(), __end = __src.end(); __i != __end;)
00881             {
00882               auto __pos = __i++;
00883               const key_type& __k = this->_M_extract()(__pos._M_cur->_M_v());
00884               __hash_code __code = this->_M_hash_code(__k);
00885               size_type __bkt = _M_bucket_index(__k, __code);
00886               if (_M_find_node(__bkt, __k, __code) == nullptr)
00887                 {
00888                   auto __nh = __src.extract(__pos);
00889                   _M_insert_unique_node(__bkt, __code, __nh._M_ptr, __n_elt);
00890                   __nh._M_ptr = nullptr;
00891                   __n_elt = 1;
00892                 }
00893               else if (__n_elt != 1)
00894                 --__n_elt;
00895             }
00896         }
00897 
00898       /// Merge from a compatible container into one with equivalent keys.
00899       template<typename _Compatible_Hashtable>
00900         void
00901         _M_merge_multi(_Compatible_Hashtable& __src) noexcept
00902         {
00903           static_assert(is_same_v<typename _Compatible_Hashtable::node_type,
00904               node_type>, "Node types are compatible");
00905           __glibcxx_assert(get_allocator() == __src.get_allocator());
00906 
00907           this->reserve(size() + __src.size());
00908           for (auto __i = __src.begin(), __end = __src.end(); __i != __end;)
00909             _M_reinsert_node_multi(cend(), __src.extract(__i++));
00910         }
00911 #endif // C++17
00912 
00913     private:
00914       // Helper rehash method used when keys are unique.
00915       void _M_rehash_aux(size_type __n, std::true_type);
00916 
00917       // Helper rehash method used when keys can be non-unique.
00918       void _M_rehash_aux(size_type __n, std::false_type);
00919 
00920       // Unconditionally change size of bucket array to n, restore
00921       // hash policy state to __state on exception.
00922       void _M_rehash(size_type __n, const __rehash_state& __state);
00923     };
00924 
00925 
00926   // Definitions of class template _Hashtable's out-of-line member functions.
00927   template<typename _Key, typename _Value,
00928            typename _Alloc, typename _ExtractKey, typename _Equal,
00929            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00930            typename _Traits>
00931     auto
00932     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00933                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00934     _M_bucket_begin(size_type __bkt) const
00935     -> __node_type*
00936     {
00937       __node_base* __n = _M_buckets[__bkt];
00938       return __n ? static_cast<__node_type*>(__n->_M_nxt) : nullptr;
00939     }
00940 
00941   template<typename _Key, typename _Value,
00942            typename _Alloc, typename _ExtractKey, typename _Equal,
00943            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00944            typename _Traits>
00945     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00946                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00947     _Hashtable(size_type __bucket_hint,
00948                const _H1& __h1, const _H2& __h2, const _Hash& __h,
00949                const _Equal& __eq, const _ExtractKey& __exk,
00950                const allocator_type& __a)
00951       : _Hashtable(__h1, __h2, __h, __eq, __exk, __a)
00952     {
00953       auto __bkt = _M_rehash_policy._M_next_bkt(__bucket_hint);
00954       if (__bkt > _M_bucket_count)
00955         {
00956           _M_buckets = _M_allocate_buckets(__bkt);
00957           _M_bucket_count = __bkt;
00958         }
00959     }
00960 
00961   template<typename _Key, typename _Value,
00962            typename _Alloc, typename _ExtractKey, typename _Equal,
00963            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00964            typename _Traits>
00965     template<typename _InputIterator>
00966       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00967                  _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00968       _Hashtable(_InputIterator __f, _InputIterator __l,
00969                  size_type __bucket_hint,
00970                  const _H1& __h1, const _H2& __h2, const _Hash& __h,
00971                  const _Equal& __eq, const _ExtractKey& __exk,
00972                  const allocator_type& __a)
00973         : _Hashtable(__h1, __h2, __h, __eq, __exk, __a)
00974       {
00975         auto __nb_elems = __detail::__distance_fw(__f, __l);
00976         auto __bkt_count =
00977           _M_rehash_policy._M_next_bkt(
00978             std::max(_M_rehash_policy._M_bkt_for_elements(__nb_elems),
00979                      __bucket_hint));
00980 
00981         if (__bkt_count > _M_bucket_count)
00982           {
00983             _M_buckets = _M_allocate_buckets(__bkt_count);
00984             _M_bucket_count = __bkt_count;
00985           }
00986 
00987         for (; __f != __l; ++__f)
00988           this->insert(*__f);
00989       }
00990 
00991   template<typename _Key, typename _Value,
00992            typename _Alloc, typename _ExtractKey, typename _Equal,
00993            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00994            typename _Traits>
00995     auto
00996     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00997                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00998     operator=(const _Hashtable& __ht)
00999     -> _Hashtable&
01000     {
01001       if (&__ht == this)
01002         return *this;
01003 
01004       if (__node_alloc_traits::_S_propagate_on_copy_assign())
01005         {
01006           auto& __this_alloc = this->_M_node_allocator();
01007           auto& __that_alloc = __ht._M_node_allocator();
01008           if (!__node_alloc_traits::_S_always_equal()
01009               && __this_alloc != __that_alloc)
01010             {
01011               // Replacement allocator cannot free existing storage.
01012               this->_M_deallocate_nodes(_M_begin());
01013               _M_before_begin._M_nxt = nullptr;
01014               _M_deallocate_buckets();
01015               _M_buckets = nullptr;
01016               std::__alloc_on_copy(__this_alloc, __that_alloc);
01017               __hashtable_base::operator=(__ht);
01018               _M_bucket_count = __ht._M_bucket_count;
01019               _M_element_count = __ht._M_element_count;
01020               _M_rehash_policy = __ht._M_rehash_policy;
01021               __try
01022                 {
01023                   _M_assign(__ht,
01024                             [this](const __node_type* __n)
01025                             { return this->_M_allocate_node(__n->_M_v()); });
01026                 }
01027               __catch(...)
01028                 {
01029                   // _M_assign took care of deallocating all memory. Now we
01030                   // must make sure this instance remains in a usable state.
01031                   _M_reset();
01032                   __throw_exception_again;
01033                 }
01034               return *this;
01035             }
01036           std::__alloc_on_copy(__this_alloc, __that_alloc);
01037         }
01038 
01039       // Reuse allocated buckets and nodes.
01040       __bucket_type* __former_buckets = nullptr;
01041       std::size_t __former_bucket_count = _M_bucket_count;
01042       const __rehash_state& __former_state = _M_rehash_policy._M_state();
01043 
01044       if (_M_bucket_count != __ht._M_bucket_count)
01045         {
01046           __former_buckets = _M_buckets;
01047           _M_buckets = _M_allocate_buckets(__ht._M_bucket_count);
01048           _M_bucket_count = __ht._M_bucket_count;
01049         }
01050       else
01051         __builtin_memset(_M_buckets, 0,
01052                          _M_bucket_count * sizeof(__bucket_type));
01053 
01054       __try
01055         {
01056           __hashtable_base::operator=(__ht);
01057           _M_element_count = __ht._M_element_count;
01058           _M_rehash_policy = __ht._M_rehash_policy;
01059           __reuse_or_alloc_node_type __roan(_M_begin(), *this);
01060           _M_before_begin._M_nxt = nullptr;
01061           _M_assign(__ht,
01062                     [&__roan](const __node_type* __n)
01063                     { return __roan(__n->_M_v()); });
01064           if (__former_buckets)
01065             _M_deallocate_buckets(__former_buckets, __former_bucket_count);
01066         }
01067       __catch(...)
01068         {
01069           if (__former_buckets)
01070             {
01071               // Restore previous buckets.
01072               _M_deallocate_buckets();
01073               _M_rehash_policy._M_reset(__former_state);
01074               _M_buckets = __former_buckets;
01075               _M_bucket_count = __former_bucket_count;
01076             }
01077           __builtin_memset(_M_buckets, 0,
01078                            _M_bucket_count * sizeof(__bucket_type));
01079           __throw_exception_again;
01080         }
01081       return *this;
01082     }
01083 
01084   template<typename _Key, typename _Value,
01085            typename _Alloc, typename _ExtractKey, typename _Equal,
01086            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01087            typename _Traits>
01088     template<typename _NodeGenerator>
01089       void
01090       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01091                  _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01092       _M_assign(const _Hashtable& __ht, const _NodeGenerator& __node_gen)
01093       {
01094         __bucket_type* __buckets = nullptr;
01095         if (!_M_buckets)
01096           _M_buckets = __buckets = _M_allocate_buckets(_M_bucket_count);
01097 
01098         __try
01099           {
01100             if (!__ht._M_before_begin._M_nxt)
01101               return;
01102 
01103             // First deal with the special first node pointed to by
01104             // _M_before_begin.
01105             __node_type* __ht_n = __ht._M_begin();
01106             __node_type* __this_n = __node_gen(__ht_n);
01107             this->_M_copy_code(__this_n, __ht_n);
01108             _M_before_begin._M_nxt = __this_n;
01109             _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin;
01110 
01111             // Then deal with other nodes.
01112             __node_base* __prev_n = __this_n;
01113             for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next())
01114               {
01115                 __this_n = __node_gen(__ht_n);
01116                 __prev_n->_M_nxt = __this_n;
01117                 this->_M_copy_code(__this_n, __ht_n);
01118                 size_type __bkt = _M_bucket_index(__this_n);
01119                 if (!_M_buckets[__bkt])
01120                   _M_buckets[__bkt] = __prev_n;
01121                 __prev_n = __this_n;
01122               }
01123           }
01124         __catch(...)
01125           {
01126             clear();
01127             if (__buckets)
01128               _M_deallocate_buckets();
01129             __throw_exception_again;
01130           }
01131       }
01132 
01133   template<typename _Key, typename _Value,
01134            typename _Alloc, typename _ExtractKey, typename _Equal,
01135            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01136            typename _Traits>
01137     void
01138     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01139                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01140     _M_reset() noexcept
01141     {
01142       _M_rehash_policy._M_reset();
01143       _M_bucket_count = 1;
01144       _M_single_bucket = nullptr;
01145       _M_buckets = &_M_single_bucket;
01146       _M_before_begin._M_nxt = nullptr;
01147       _M_element_count = 0;
01148     }
01149 
01150   template<typename _Key, typename _Value,
01151            typename _Alloc, typename _ExtractKey, typename _Equal,
01152            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01153            typename _Traits>
01154     void
01155     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01156                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01157     _M_move_assign(_Hashtable&& __ht, std::true_type)
01158     {
01159       this->_M_deallocate_nodes(_M_begin());
01160       _M_deallocate_buckets();
01161       __hashtable_base::operator=(std::move(__ht));
01162       _M_rehash_policy = __ht._M_rehash_policy;
01163       if (!__ht._M_uses_single_bucket())
01164         _M_buckets = __ht._M_buckets;
01165       else
01166         {
01167           _M_buckets = &_M_single_bucket;
01168           _M_single_bucket = __ht._M_single_bucket;
01169         }
01170       _M_bucket_count = __ht._M_bucket_count;
01171       _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt;
01172       _M_element_count = __ht._M_element_count;
01173       std::__alloc_on_move(this->_M_node_allocator(), __ht._M_node_allocator());
01174 
01175       // Fix buckets containing the _M_before_begin pointers that can't be
01176       // moved.
01177       if (_M_begin())
01178         _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
01179       __ht._M_reset();
01180     }
01181 
01182   template<typename _Key, typename _Value,
01183            typename _Alloc, typename _ExtractKey, typename _Equal,
01184            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01185            typename _Traits>
01186     void
01187     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01188                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01189     _M_move_assign(_Hashtable&& __ht, std::false_type)
01190     {
01191       if (__ht._M_node_allocator() == this->_M_node_allocator())
01192         _M_move_assign(std::move(__ht), std::true_type());
01193       else
01194         {
01195           // Can't move memory, move elements then.
01196           __bucket_type* __former_buckets = nullptr;
01197           size_type __former_bucket_count = _M_bucket_count;
01198           const __rehash_state& __former_state = _M_rehash_policy._M_state();
01199 
01200           if (_M_bucket_count != __ht._M_bucket_count)
01201             {
01202               __former_buckets = _M_buckets;
01203               _M_buckets = _M_allocate_buckets(__ht._M_bucket_count);
01204               _M_bucket_count = __ht._M_bucket_count;
01205             }
01206           else
01207             __builtin_memset(_M_buckets, 0,
01208                              _M_bucket_count * sizeof(__bucket_type));
01209 
01210           __try
01211             {
01212               __hashtable_base::operator=(std::move(__ht));
01213               _M_element_count = __ht._M_element_count;
01214               _M_rehash_policy = __ht._M_rehash_policy;
01215               __reuse_or_alloc_node_type __roan(_M_begin(), *this);
01216               _M_before_begin._M_nxt = nullptr;
01217               _M_assign(__ht,
01218                         [&__roan](__node_type* __n)
01219                         { return __roan(std::move_if_noexcept(__n->_M_v())); });
01220 
01221               if (__former_buckets)
01222                 _M_deallocate_buckets(__former_buckets, __former_bucket_count);
01223               __ht.clear();
01224             }
01225           __catch(...)
01226             {
01227               if (__former_buckets)
01228                 {
01229                   _M_deallocate_buckets();
01230                   _M_rehash_policy._M_reset(__former_state);
01231                   _M_buckets = __former_buckets;
01232                   _M_bucket_count = __former_bucket_count;
01233                 }
01234               __builtin_memset(_M_buckets, 0,
01235                                _M_bucket_count * sizeof(__bucket_type));
01236               __throw_exception_again;
01237             }
01238         }
01239     }
01240 
01241   template<typename _Key, typename _Value,
01242            typename _Alloc, typename _ExtractKey, typename _Equal,
01243            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01244            typename _Traits>
01245     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01246                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01247     _Hashtable(const _Hashtable& __ht)
01248     : __hashtable_base(__ht),
01249       __map_base(__ht),
01250       __rehash_base(__ht),
01251       __hashtable_alloc(
01252         __node_alloc_traits::_S_select_on_copy(__ht._M_node_allocator())),
01253       _M_buckets(nullptr),
01254       _M_bucket_count(__ht._M_bucket_count),
01255       _M_element_count(__ht._M_element_count),
01256       _M_rehash_policy(__ht._M_rehash_policy)
01257     {
01258       _M_assign(__ht,
01259                 [this](const __node_type* __n)
01260                 { return this->_M_allocate_node(__n->_M_v()); });
01261     }
01262 
01263   template<typename _Key, typename _Value,
01264            typename _Alloc, typename _ExtractKey, typename _Equal,
01265            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01266            typename _Traits>
01267     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01268                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01269     _Hashtable(_Hashtable&& __ht) noexcept
01270     : __hashtable_base(__ht),
01271       __map_base(__ht),
01272       __rehash_base(__ht),
01273       __hashtable_alloc(std::move(__ht._M_base_alloc())),
01274       _M_buckets(__ht._M_buckets),
01275       _M_bucket_count(__ht._M_bucket_count),
01276       _M_before_begin(__ht._M_before_begin._M_nxt),
01277       _M_element_count(__ht._M_element_count),
01278       _M_rehash_policy(__ht._M_rehash_policy)
01279     {
01280       // Update, if necessary, buckets if __ht is using its single bucket.
01281       if (__ht._M_uses_single_bucket())
01282         {
01283           _M_buckets = &_M_single_bucket;
01284           _M_single_bucket = __ht._M_single_bucket;
01285         }
01286 
01287       // Update, if necessary, bucket pointing to before begin that hasn't
01288       // moved.
01289       if (_M_begin())
01290         _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
01291 
01292       __ht._M_reset();
01293     }
01294 
01295   template<typename _Key, typename _Value,
01296            typename _Alloc, typename _ExtractKey, typename _Equal,
01297            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01298            typename _Traits>
01299     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01300                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01301     _Hashtable(const _Hashtable& __ht, const allocator_type& __a)
01302     : __hashtable_base(__ht),
01303       __map_base(__ht),
01304       __rehash_base(__ht),
01305       __hashtable_alloc(__node_alloc_type(__a)),
01306       _M_buckets(),
01307       _M_bucket_count(__ht._M_bucket_count),
01308       _M_element_count(__ht._M_element_count),
01309       _M_rehash_policy(__ht._M_rehash_policy)
01310     {
01311       _M_assign(__ht,
01312                 [this](const __node_type* __n)
01313                 { return this->_M_allocate_node(__n->_M_v()); });
01314     }
01315 
01316   template<typename _Key, typename _Value,
01317            typename _Alloc, typename _ExtractKey, typename _Equal,
01318            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01319            typename _Traits>
01320     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01321                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01322     _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
01323     : __hashtable_base(__ht),
01324       __map_base(__ht),
01325       __rehash_base(__ht),
01326       __hashtable_alloc(__node_alloc_type(__a)),
01327       _M_buckets(nullptr),
01328       _M_bucket_count(__ht._M_bucket_count),
01329       _M_element_count(__ht._M_element_count),
01330       _M_rehash_policy(__ht._M_rehash_policy)
01331     {
01332       if (__ht._M_node_allocator() == this->_M_node_allocator())
01333         {
01334           if (__ht._M_uses_single_bucket())
01335             {
01336               _M_buckets = &_M_single_bucket;
01337               _M_single_bucket = __ht._M_single_bucket;
01338             }
01339           else
01340             _M_buckets = __ht._M_buckets;
01341 
01342           _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt;
01343           // Update, if necessary, bucket pointing to before begin that hasn't
01344           // moved.
01345           if (_M_begin())
01346             _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
01347           __ht._M_reset();
01348         }
01349       else
01350         {
01351           _M_assign(__ht,
01352                     [this](__node_type* __n)
01353                     {
01354                       return this->_M_allocate_node(
01355                                         std::move_if_noexcept(__n->_M_v()));
01356                     });
01357           __ht.clear();
01358         }
01359     }
01360 
01361   template<typename _Key, typename _Value,
01362            typename _Alloc, typename _ExtractKey, typename _Equal,
01363            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01364            typename _Traits>
01365     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01366                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01367     ~_Hashtable() noexcept
01368     {
01369       clear();
01370       _M_deallocate_buckets();
01371     }
01372 
01373   template<typename _Key, typename _Value,
01374            typename _Alloc, typename _ExtractKey, typename _Equal,
01375            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01376            typename _Traits>
01377     void
01378     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01379                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01380     swap(_Hashtable& __x)
01381     noexcept(__and_<__is_nothrow_swappable<_H1>,
01382                         __is_nothrow_swappable<_Equal>>::value)
01383     {
01384       // The only base class with member variables is hash_code_base.
01385       // We define _Hash_code_base::_M_swap because different
01386       // specializations have different members.
01387       this->_M_swap(__x);
01388 
01389       std::__alloc_on_swap(this->_M_node_allocator(), __x._M_node_allocator());
01390       std::swap(_M_rehash_policy, __x._M_rehash_policy);
01391 
01392       // Deal properly with potentially moved instances.
01393       if (this->_M_uses_single_bucket())
01394         {
01395           if (!__x._M_uses_single_bucket())
01396             {
01397               _M_buckets = __x._M_buckets;
01398               __x._M_buckets = &__x._M_single_bucket;
01399             }
01400         }
01401       else if (__x._M_uses_single_bucket())
01402         {
01403           __x._M_buckets = _M_buckets;
01404           _M_buckets = &_M_single_bucket;
01405         }       
01406       else
01407         std::swap(_M_buckets, __x._M_buckets);
01408 
01409       std::swap(_M_bucket_count, __x._M_bucket_count);
01410       std::swap(_M_before_begin._M_nxt, __x._M_before_begin._M_nxt);
01411       std::swap(_M_element_count, __x._M_element_count);
01412       std::swap(_M_single_bucket, __x._M_single_bucket);
01413 
01414       // Fix buckets containing the _M_before_begin pointers that can't be
01415       // swapped.
01416       if (_M_begin())
01417         _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
01418 
01419       if (__x._M_begin())
01420         __x._M_buckets[__x._M_bucket_index(__x._M_begin())]
01421           = &__x._M_before_begin;
01422     }
01423 
01424   template<typename _Key, typename _Value,
01425            typename _Alloc, typename _ExtractKey, typename _Equal,
01426            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01427            typename _Traits>
01428     auto
01429     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01430                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01431     find(const key_type& __k)
01432     -> iterator
01433     {
01434       __hash_code __code = this->_M_hash_code(__k);
01435       std::size_t __n = _M_bucket_index(__k, __code);
01436       __node_type* __p = _M_find_node(__n, __k, __code);
01437       return __p ? iterator(__p) : end();
01438     }
01439 
01440   template<typename _Key, typename _Value,
01441            typename _Alloc, typename _ExtractKey, typename _Equal,
01442            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01443            typename _Traits>
01444     auto
01445     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01446                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01447     find(const key_type& __k) const
01448     -> const_iterator
01449     {
01450       __hash_code __code = this->_M_hash_code(__k);
01451       std::size_t __n = _M_bucket_index(__k, __code);
01452       __node_type* __p = _M_find_node(__n, __k, __code);
01453       return __p ? const_iterator(__p) : end();
01454     }
01455 
01456   template<typename _Key, typename _Value,
01457            typename _Alloc, typename _ExtractKey, typename _Equal,
01458            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01459            typename _Traits>
01460     auto
01461     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01462                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01463     count(const key_type& __k) const
01464     -> size_type
01465     {
01466       __hash_code __code = this->_M_hash_code(__k);
01467       std::size_t __n = _M_bucket_index(__k, __code);
01468       __node_type* __p = _M_bucket_begin(__n);
01469       if (!__p)
01470         return 0;
01471 
01472       std::size_t __result = 0;
01473       for (;; __p = __p->_M_next())
01474         {
01475           if (this->_M_equals(__k, __code, __p))
01476             ++__result;
01477           else if (__result)
01478             // All equivalent values are next to each other, if we
01479             // found a non-equivalent value after an equivalent one it
01480             // means that we won't find any new equivalent value.
01481             break;
01482           if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n)
01483             break;
01484         }
01485       return __result;
01486     }
01487 
01488   template<typename _Key, typename _Value,
01489            typename _Alloc, typename _ExtractKey, typename _Equal,
01490            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01491            typename _Traits>
01492     auto
01493     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01494                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01495     equal_range(const key_type& __k)
01496     -> pair<iterator, iterator>
01497     {
01498       __hash_code __code = this->_M_hash_code(__k);
01499       std::size_t __n = _M_bucket_index(__k, __code);
01500       __node_type* __p = _M_find_node(__n, __k, __code);
01501 
01502       if (__p)
01503         {
01504           __node_type* __p1 = __p->_M_next();
01505           while (__p1 && _M_bucket_index(__p1) == __n
01506                  && this->_M_equals(__k, __code, __p1))
01507             __p1 = __p1->_M_next();
01508 
01509           return std::make_pair(iterator(__p), iterator(__p1));
01510         }
01511       else
01512         return std::make_pair(end(), end());
01513     }
01514 
01515   template<typename _Key, typename _Value,
01516            typename _Alloc, typename _ExtractKey, typename _Equal,
01517            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01518            typename _Traits>
01519     auto
01520     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01521                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01522     equal_range(const key_type& __k) const
01523     -> pair<const_iterator, const_iterator>
01524     {
01525       __hash_code __code = this->_M_hash_code(__k);
01526       std::size_t __n = _M_bucket_index(__k, __code);
01527       __node_type* __p = _M_find_node(__n, __k, __code);
01528 
01529       if (__p)
01530         {
01531           __node_type* __p1 = __p->_M_next();
01532           while (__p1 && _M_bucket_index(__p1) == __n
01533                  && this->_M_equals(__k, __code, __p1))
01534             __p1 = __p1->_M_next();
01535 
01536           return std::make_pair(const_iterator(__p), const_iterator(__p1));
01537         }
01538       else
01539         return std::make_pair(end(), end());
01540     }
01541 
01542   // Find the node whose key compares equal to k in the bucket n.
01543   // Return nullptr if no node is found.
01544   template<typename _Key, typename _Value,
01545            typename _Alloc, typename _ExtractKey, typename _Equal,
01546            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01547            typename _Traits>
01548     auto
01549     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01550                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01551     _M_find_before_node(size_type __n, const key_type& __k,
01552                         __hash_code __code) const
01553     -> __node_base*
01554     {
01555       __node_base* __prev_p = _M_buckets[__n];
01556       if (!__prev_p)
01557         return nullptr;
01558 
01559       for (__node_type* __p = static_cast<__node_type*>(__prev_p->_M_nxt);;
01560            __p = __p->_M_next())
01561         {
01562           if (this->_M_equals(__k, __code, __p))
01563             return __prev_p;
01564 
01565           if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n)
01566             break;
01567           __prev_p = __p;
01568         }
01569       return nullptr;
01570     }
01571 
01572   template<typename _Key, typename _Value,
01573            typename _Alloc, typename _ExtractKey, typename _Equal,
01574            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01575            typename _Traits>
01576     void
01577     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01578                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01579     _M_insert_bucket_begin(size_type __bkt, __node_type* __node)
01580     {
01581       if (_M_buckets[__bkt])
01582         {
01583           // Bucket is not empty, we just need to insert the new node
01584           // after the bucket before begin.
01585           __node->_M_nxt = _M_buckets[__bkt]->_M_nxt;
01586           _M_buckets[__bkt]->_M_nxt = __node;
01587         }
01588       else
01589         {
01590           // The bucket is empty, the new node is inserted at the
01591           // beginning of the singly-linked list and the bucket will
01592           // contain _M_before_begin pointer.
01593           __node->_M_nxt = _M_before_begin._M_nxt;
01594           _M_before_begin._M_nxt = __node;
01595           if (__node->_M_nxt)
01596             // We must update former begin bucket that is pointing to
01597             // _M_before_begin.
01598             _M_buckets[_M_bucket_index(__node->_M_next())] = __node;
01599           _M_buckets[__bkt] = &_M_before_begin;
01600         }
01601     }
01602 
01603   template<typename _Key, typename _Value,
01604            typename _Alloc, typename _ExtractKey, typename _Equal,
01605            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01606            typename _Traits>
01607     void
01608     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01609                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01610     _M_remove_bucket_begin(size_type __bkt, __node_type* __next,
01611                            size_type __next_bkt)
01612     {
01613       if (!__next || __next_bkt != __bkt)
01614         {
01615           // Bucket is now empty
01616           // First update next bucket if any
01617           if (__next)
01618             _M_buckets[__next_bkt] = _M_buckets[__bkt];
01619 
01620           // Second update before begin node if necessary
01621           if (&_M_before_begin == _M_buckets[__bkt])
01622             _M_before_begin._M_nxt = __next;
01623           _M_buckets[__bkt] = nullptr;
01624         }
01625     }
01626 
01627   template<typename _Key, typename _Value,
01628            typename _Alloc, typename _ExtractKey, typename _Equal,
01629            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01630            typename _Traits>
01631     auto
01632     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01633                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01634     _M_get_previous_node(size_type __bkt, __node_base* __n)
01635     -> __node_base*
01636     {
01637       __node_base* __prev_n = _M_buckets[__bkt];
01638       while (__prev_n->_M_nxt != __n)
01639         __prev_n = __prev_n->_M_nxt;
01640       return __prev_n;
01641     }
01642 
01643   template<typename _Key, typename _Value,
01644            typename _Alloc, typename _ExtractKey, typename _Equal,
01645            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01646            typename _Traits>
01647     template<typename... _Args>
01648       auto
01649       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01650                  _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01651       _M_emplace(std::true_type, _Args&&... __args)
01652       -> pair<iterator, bool>
01653       {
01654         // First build the node to get access to the hash code
01655         __node_type* __node = this->_M_allocate_node(std::forward<_Args>(__args)...);
01656         const key_type& __k = this->_M_extract()(__node->_M_v());
01657         __hash_code __code;
01658         __try
01659           {
01660             __code = this->_M_hash_code(__k);
01661           }
01662         __catch(...)
01663           {
01664             this->_M_deallocate_node(__node);
01665             __throw_exception_again;
01666           }
01667 
01668         size_type __bkt = _M_bucket_index(__k, __code);
01669         if (__node_type* __p = _M_find_node(__bkt, __k, __code))
01670           {
01671             // There is already an equivalent node, no insertion
01672             this->_M_deallocate_node(__node);
01673             return std::make_pair(iterator(__p), false);
01674           }
01675 
01676         // Insert the node
01677         return std::make_pair(_M_insert_unique_node(__bkt, __code, __node),
01678                               true);
01679       }
01680 
01681   template<typename _Key, typename _Value,
01682            typename _Alloc, typename _ExtractKey, typename _Equal,
01683            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01684            typename _Traits>
01685     template<typename... _Args>
01686       auto
01687       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01688                  _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01689       _M_emplace(const_iterator __hint, std::false_type, _Args&&... __args)
01690       -> iterator
01691       {
01692         // First build the node to get its hash code.
01693         __node_type* __node =
01694           this->_M_allocate_node(std::forward<_Args>(__args)...);
01695 
01696         __hash_code __code;
01697         __try
01698           {
01699             __code = this->_M_hash_code(this->_M_extract()(__node->_M_v()));
01700           }
01701         __catch(...)
01702           {
01703             this->_M_deallocate_node(__node);
01704             __throw_exception_again;
01705           }
01706 
01707         return _M_insert_multi_node(__hint._M_cur, __code, __node);
01708       }
01709 
01710   template<typename _Key, typename _Value,
01711            typename _Alloc, typename _ExtractKey, typename _Equal,
01712            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01713            typename _Traits>
01714     auto
01715     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01716                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01717     _M_insert_unique_node(size_type __bkt, __hash_code __code,
01718                           __node_type* __node, size_type __n_elt)
01719     -> iterator
01720     {
01721       const __rehash_state& __saved_state = _M_rehash_policy._M_state();
01722       std::pair<bool, std::size_t> __do_rehash
01723         = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count,
01724                                           __n_elt);
01725 
01726       __try
01727         {
01728           if (__do_rehash.first)
01729             {
01730               _M_rehash(__do_rehash.second, __saved_state);
01731               __bkt = _M_bucket_index(this->_M_extract()(__node->_M_v()), __code);
01732             }
01733 
01734           this->_M_store_code(__node, __code);
01735 
01736           // Always insert at the beginning of the bucket.
01737           _M_insert_bucket_begin(__bkt, __node);
01738           ++_M_element_count;
01739           return iterator(__node);
01740         }
01741       __catch(...)
01742         {
01743           this->_M_deallocate_node(__node);
01744           __throw_exception_again;
01745         }
01746     }
01747 
01748   // Insert node, in bucket bkt if no rehash (assumes no element with its key
01749   // already present). Take ownership of the node, deallocate it on exception.
01750   template<typename _Key, typename _Value,
01751            typename _Alloc, typename _ExtractKey, typename _Equal,
01752            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01753            typename _Traits>
01754     auto
01755     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01756                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01757     _M_insert_multi_node(__node_type* __hint, __hash_code __code,
01758                          __node_type* __node)
01759     -> iterator
01760     {
01761       const __rehash_state& __saved_state = _M_rehash_policy._M_state();
01762       std::pair<bool, std::size_t> __do_rehash
01763         = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1);
01764 
01765       __try
01766         {
01767           if (__do_rehash.first)
01768             _M_rehash(__do_rehash.second, __saved_state);
01769 
01770           this->_M_store_code(__node, __code);
01771           const key_type& __k = this->_M_extract()(__node->_M_v());
01772           size_type __bkt = _M_bucket_index(__k, __code);
01773 
01774           // Find the node before an equivalent one or use hint if it exists and
01775           // if it is equivalent.
01776           __node_base* __prev
01777             = __builtin_expect(__hint != nullptr, false)
01778               && this->_M_equals(__k, __code, __hint)
01779                 ? __hint
01780                 : _M_find_before_node(__bkt, __k, __code);
01781           if (__prev)
01782             {
01783               // Insert after the node before the equivalent one.
01784               __node->_M_nxt = __prev->_M_nxt;
01785               __prev->_M_nxt = __node;
01786               if (__builtin_expect(__prev == __hint, false))
01787                 // hint might be the last bucket node, in this case we need to
01788                 // update next bucket.
01789                 if (__node->_M_nxt
01790                     && !this->_M_equals(__k, __code, __node->_M_next()))
01791                   {
01792                     size_type __next_bkt = _M_bucket_index(__node->_M_next());
01793                     if (__next_bkt != __bkt)
01794                       _M_buckets[__next_bkt] = __node;
01795                   }
01796             }
01797           else
01798             // The inserted node has no equivalent in the
01799             // hashtable. We must insert the new node at the
01800             // beginning of the bucket to preserve equivalent
01801             // elements' relative positions.
01802             _M_insert_bucket_begin(__bkt, __node);
01803           ++_M_element_count;
01804           return iterator(__node);
01805         }
01806       __catch(...)
01807         {
01808           this->_M_deallocate_node(__node);
01809           __throw_exception_again;
01810         }
01811     }
01812 
01813   // Insert v if no element with its key is already present.
01814   template<typename _Key, typename _Value,
01815            typename _Alloc, typename _ExtractKey, typename _Equal,
01816            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01817            typename _Traits>
01818     template<typename _Arg, typename _NodeGenerator>
01819       auto
01820       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01821                  _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01822       _M_insert(_Arg&& __v, const _NodeGenerator& __node_gen, true_type,
01823                 size_type __n_elt)
01824       -> pair<iterator, bool>
01825       {
01826         const key_type& __k = this->_M_extract()(__v);
01827         __hash_code __code = this->_M_hash_code(__k);
01828         size_type __bkt = _M_bucket_index(__k, __code);
01829 
01830         __node_type* __n = _M_find_node(__bkt, __k, __code);
01831         if (__n)
01832           return std::make_pair(iterator(__n), false);
01833 
01834         __n = __node_gen(std::forward<_Arg>(__v));
01835         return { _M_insert_unique_node(__bkt, __code, __n, __n_elt), true };
01836       }
01837 
01838   // Insert v unconditionally.
01839   template<typename _Key, typename _Value,
01840            typename _Alloc, typename _ExtractKey, typename _Equal,
01841            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01842            typename _Traits>
01843     template<typename _Arg, typename _NodeGenerator>
01844       auto
01845       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01846                  _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01847       _M_insert(const_iterator __hint, _Arg&& __v,
01848                 const _NodeGenerator& __node_gen, false_type)
01849       -> iterator
01850       {
01851         // First compute the hash code so that we don't do anything if it
01852         // throws.
01853         __hash_code __code = this->_M_hash_code(this->_M_extract()(__v));
01854 
01855         // Second allocate new node so that we don't rehash if it throws.
01856         __node_type* __node = __node_gen(std::forward<_Arg>(__v));
01857 
01858         return _M_insert_multi_node(__hint._M_cur, __code, __node);
01859       }
01860 
01861   template<typename _Key, typename _Value,
01862            typename _Alloc, typename _ExtractKey, typename _Equal,
01863            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01864            typename _Traits>
01865     auto
01866     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01867                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01868     erase(const_iterator __it)
01869     -> iterator
01870     {
01871       __node_type* __n = __it._M_cur;
01872       std::size_t __bkt = _M_bucket_index(__n);
01873 
01874       // Look for previous node to unlink it from the erased one, this
01875       // is why we need buckets to contain the before begin to make
01876       // this search fast.
01877       __node_base* __prev_n = _M_get_previous_node(__bkt, __n);
01878       return _M_erase(__bkt, __prev_n, __n);
01879     }
01880 
01881   template<typename _Key, typename _Value,
01882            typename _Alloc, typename _ExtractKey, typename _Equal,
01883            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01884            typename _Traits>
01885     auto
01886     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01887                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01888     _M_erase(size_type __bkt, __node_base* __prev_n, __node_type* __n)
01889     -> iterator
01890     {
01891       if (__prev_n == _M_buckets[__bkt])
01892         _M_remove_bucket_begin(__bkt, __n->_M_next(),
01893            __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0);
01894       else if (__n->_M_nxt)
01895         {
01896           size_type __next_bkt = _M_bucket_index(__n->_M_next());
01897           if (__next_bkt != __bkt)
01898             _M_buckets[__next_bkt] = __prev_n;
01899         }
01900 
01901       __prev_n->_M_nxt = __n->_M_nxt;
01902       iterator __result(__n->_M_next());
01903       this->_M_deallocate_node(__n);
01904       --_M_element_count;
01905 
01906       return __result;
01907     }
01908 
01909   template<typename _Key, typename _Value,
01910            typename _Alloc, typename _ExtractKey, typename _Equal,
01911            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01912            typename _Traits>
01913     auto
01914     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01915                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01916     _M_erase(std::true_type, const key_type& __k)
01917     -> size_type
01918     {
01919       __hash_code __code = this->_M_hash_code(__k);
01920       std::size_t __bkt = _M_bucket_index(__k, __code);
01921 
01922       // Look for the node before the first matching node.
01923       __node_base* __prev_n = _M_find_before_node(__bkt, __k, __code);
01924       if (!__prev_n)
01925         return 0;
01926 
01927       // We found a matching node, erase it.
01928       __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt);
01929       _M_erase(__bkt, __prev_n, __n);
01930       return 1;
01931     }
01932 
01933   template<typename _Key, typename _Value,
01934            typename _Alloc, typename _ExtractKey, typename _Equal,
01935            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01936            typename _Traits>
01937     auto
01938     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01939                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01940     _M_erase(std::false_type, const key_type& __k)
01941     -> size_type
01942     {
01943       __hash_code __code = this->_M_hash_code(__k);
01944       std::size_t __bkt = _M_bucket_index(__k, __code);
01945 
01946       // Look for the node before the first matching node.
01947       __node_base* __prev_n = _M_find_before_node(__bkt, __k, __code);
01948       if (!__prev_n)
01949         return 0;
01950 
01951       // _GLIBCXX_RESOLVE_LIB_DEFECTS
01952       // 526. Is it undefined if a function in the standard changes
01953       // in parameters?
01954       // We use one loop to find all matching nodes and another to deallocate
01955       // them so that the key stays valid during the first loop. It might be
01956       // invalidated indirectly when destroying nodes.
01957       __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt);
01958       __node_type* __n_last = __n;
01959       std::size_t __n_last_bkt = __bkt;
01960       do
01961         {
01962           __n_last = __n_last->_M_next();
01963           if (!__n_last)
01964             break;
01965           __n_last_bkt = _M_bucket_index(__n_last);
01966         }
01967       while (__n_last_bkt == __bkt && this->_M_equals(__k, __code, __n_last));
01968 
01969       // Deallocate nodes.
01970       size_type __result = 0;
01971       do
01972         {
01973           __node_type* __p = __n->_M_next();
01974           this->_M_deallocate_node(__n);
01975           __n = __p;
01976           ++__result;
01977           --_M_element_count;
01978         }
01979       while (__n != __n_last);
01980 
01981       if (__prev_n == _M_buckets[__bkt])
01982         _M_remove_bucket_begin(__bkt, __n_last, __n_last_bkt);
01983       else if (__n_last && __n_last_bkt != __bkt)
01984         _M_buckets[__n_last_bkt] = __prev_n;
01985       __prev_n->_M_nxt = __n_last;
01986       return __result;
01987     }
01988 
01989   template<typename _Key, typename _Value,
01990            typename _Alloc, typename _ExtractKey, typename _Equal,
01991            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01992            typename _Traits>
01993     auto
01994     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01995                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01996     erase(const_iterator __first, const_iterator __last)
01997     -> iterator
01998     {
01999       __node_type* __n = __first._M_cur;
02000       __node_type* __last_n = __last._M_cur;
02001       if (__n == __last_n)
02002         return iterator(__n);
02003 
02004       std::size_t __bkt = _M_bucket_index(__n);
02005 
02006       __node_base* __prev_n = _M_get_previous_node(__bkt, __n);
02007       bool __is_bucket_begin = __n == _M_bucket_begin(__bkt);
02008       std::size_t __n_bkt = __bkt;
02009       for (;;)
02010         {
02011           do
02012             {
02013               __node_type* __tmp = __n;
02014               __n = __n->_M_next();
02015               this->_M_deallocate_node(__tmp);
02016               --_M_element_count;
02017               if (!__n)
02018                 break;
02019               __n_bkt = _M_bucket_index(__n);
02020             }
02021           while (__n != __last_n && __n_bkt == __bkt);
02022           if (__is_bucket_begin)
02023             _M_remove_bucket_begin(__bkt, __n, __n_bkt);
02024           if (__n == __last_n)
02025             break;
02026           __is_bucket_begin = true;
02027           __bkt = __n_bkt;
02028         }
02029 
02030       if (__n && (__n_bkt != __bkt || __is_bucket_begin))
02031         _M_buckets[__n_bkt] = __prev_n;
02032       __prev_n->_M_nxt = __n;
02033       return iterator(__n);
02034     }
02035 
02036   template<typename _Key, typename _Value,
02037            typename _Alloc, typename _ExtractKey, typename _Equal,
02038            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
02039            typename _Traits>
02040     void
02041     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
02042                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
02043     clear() noexcept
02044     {
02045       this->_M_deallocate_nodes(_M_begin());
02046       __builtin_memset(_M_buckets, 0, _M_bucket_count * sizeof(__bucket_type));
02047       _M_element_count = 0;
02048       _M_before_begin._M_nxt = nullptr;
02049     }
02050 
02051   template<typename _Key, typename _Value,
02052            typename _Alloc, typename _ExtractKey, typename _Equal,
02053            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
02054            typename _Traits>
02055     void
02056     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
02057                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
02058     rehash(size_type __n)
02059     {
02060       const __rehash_state& __saved_state = _M_rehash_policy._M_state();
02061       std::size_t __buckets
02062         = std::max(_M_rehash_policy._M_bkt_for_elements(_M_element_count + 1),
02063                    __n);
02064       __buckets = _M_rehash_policy._M_next_bkt(__buckets);
02065 
02066       if (__buckets != _M_bucket_count)
02067         _M_rehash(__buckets, __saved_state);
02068       else
02069         // No rehash, restore previous state to keep a consistent state.
02070         _M_rehash_policy._M_reset(__saved_state);
02071     }
02072 
02073   template<typename _Key, typename _Value,
02074            typename _Alloc, typename _ExtractKey, typename _Equal,
02075            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
02076            typename _Traits>
02077     void
02078     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
02079                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
02080     _M_rehash(size_type __n, const __rehash_state& __state)
02081     {
02082       __try
02083         {
02084           _M_rehash_aux(__n, __unique_keys());
02085         }
02086       __catch(...)
02087         {
02088           // A failure here means that buckets allocation failed.  We only
02089           // have to restore hash policy previous state.
02090           _M_rehash_policy._M_reset(__state);
02091           __throw_exception_again;
02092         }
02093     }
02094 
02095   // Rehash when there is no equivalent elements.
02096   template<typename _Key, typename _Value,
02097            typename _Alloc, typename _ExtractKey, typename _Equal,
02098            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
02099            typename _Traits>
02100     void
02101     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
02102                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
02103     _M_rehash_aux(size_type __n, std::true_type)
02104     {
02105       __bucket_type* __new_buckets = _M_allocate_buckets(__n);
02106       __node_type* __p = _M_begin();
02107       _M_before_begin._M_nxt = nullptr;
02108       std::size_t __bbegin_bkt = 0;
02109       while (__p)
02110         {
02111           __node_type* __next = __p->_M_next();
02112           std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n);
02113           if (!__new_buckets[__bkt])
02114             {
02115               __p->_M_nxt = _M_before_begin._M_nxt;
02116               _M_before_begin._M_nxt = __p;
02117               __new_buckets[__bkt] = &_M_before_begin;
02118               if (__p->_M_nxt)
02119                 __new_buckets[__bbegin_bkt] = __p;
02120               __bbegin_bkt = __bkt;
02121             }
02122           else
02123             {
02124               __p->_M_nxt = __new_buckets[__bkt]->_M_nxt;
02125               __new_buckets[__bkt]->_M_nxt = __p;
02126             }
02127           __p = __next;
02128         }
02129 
02130       _M_deallocate_buckets();
02131       _M_bucket_count = __n;
02132       _M_buckets = __new_buckets;
02133     }
02134 
02135   // Rehash when there can be equivalent elements, preserve their relative
02136   // order.
02137   template<typename _Key, typename _Value,
02138            typename _Alloc, typename _ExtractKey, typename _Equal,
02139            typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
02140            typename _Traits>
02141     void
02142     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
02143                _H1, _H2, _Hash, _RehashPolicy, _Traits>::
02144     _M_rehash_aux(size_type __n, std::false_type)
02145     {
02146       __bucket_type* __new_buckets = _M_allocate_buckets(__n);
02147 
02148       __node_type* __p = _M_begin();
02149       _M_before_begin._M_nxt = nullptr;
02150       std::size_t __bbegin_bkt = 0;
02151       std::size_t __prev_bkt = 0;
02152       __node_type* __prev_p = nullptr;
02153       bool __check_bucket = false;
02154 
02155       while (__p)
02156         {
02157           __node_type* __next = __p->_M_next();
02158           std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n);
02159 
02160           if (__prev_p && __prev_bkt == __bkt)
02161             {
02162               // Previous insert was already in this bucket, we insert after
02163               // the previously inserted one to preserve equivalent elements
02164               // relative order.
02165               __p->_M_nxt = __prev_p->_M_nxt;
02166               __prev_p->_M_nxt = __p;
02167 
02168               // Inserting after a node in a bucket require to check that we
02169               // haven't change the bucket last node, in this case next
02170               // bucket containing its before begin node must be updated. We
02171               // schedule a check as soon as we move out of the sequence of
02172               // equivalent nodes to limit the number of checks.
02173               __check_bucket = true;
02174             }
02175           else
02176             {
02177               if (__check_bucket)
02178                 {
02179                   // Check if we shall update the next bucket because of
02180                   // insertions into __prev_bkt bucket.
02181                   if (__prev_p->_M_nxt)
02182                     {
02183                       std::size_t __next_bkt
02184                         = __hash_code_base::_M_bucket_index(__prev_p->_M_next(),
02185                                                             __n);
02186                       if (__next_bkt != __prev_bkt)
02187                         __new_buckets[__next_bkt] = __prev_p;
02188                     }
02189                   __check_bucket = false;
02190                 }
02191 
02192               if (!__new_buckets[__bkt])
02193                 {
02194                   __p->_M_nxt = _M_before_begin._M_nxt;
02195                   _M_before_begin._M_nxt = __p;
02196                   __new_buckets[__bkt] = &_M_before_begin;
02197                   if (__p->_M_nxt)
02198                     __new_buckets[__bbegin_bkt] = __p;
02199                   __bbegin_bkt = __bkt;
02200                 }
02201               else
02202                 {
02203                   __p->_M_nxt = __new_buckets[__bkt]->_M_nxt;
02204                   __new_buckets[__bkt]->_M_nxt = __p;
02205                 }
02206             }
02207           __prev_p = __p;
02208           __prev_bkt = __bkt;
02209           __p = __next;
02210         }
02211 
02212       if (__check_bucket && __prev_p->_M_nxt)
02213         {
02214           std::size_t __next_bkt
02215             = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), __n);
02216           if (__next_bkt != __prev_bkt)
02217             __new_buckets[__next_bkt] = __prev_p;
02218         }
02219 
02220       _M_deallocate_buckets();
02221       _M_bucket_count = __n;
02222       _M_buckets = __new_buckets;
02223     }
02224 
02225 #if __cplusplus > 201402L
02226   template<typename, typename, typename> class _Hash_merge_helper { };
02227 #endif // C++17
02228 
02229 _GLIBCXX_END_NAMESPACE_VERSION
02230 } // namespace std
02231 
02232 #endif // _HASHTABLE_H