libstdc++
bits/hashtable.h
Go to the documentation of this file.
00001 // hashtable.h header -*- C++ -*-
00002 
00003 // Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
00004 // Free Software Foundation, Inc.
00005 //
00006 // This file is part of the GNU ISO C++ Library.  This library is free
00007 // software; you can redistribute it and/or modify it under the
00008 // terms of the GNU General Public License as published by the
00009 // Free Software Foundation; either version 3, or (at your option)
00010 // any later version.
00011 
00012 // This library is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 
00017 // Under Section 7 of GPL version 3, you are granted additional
00018 // permissions described in the GCC Runtime Library Exception, version
00019 // 3.1, as published by the Free Software Foundation.
00020 
00021 // You should have received a copy of the GNU General Public License and
00022 // a copy of the GCC Runtime Library Exception along with this program;
00023 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00024 // <http://www.gnu.org/licenses/>.
00025 
00026 /** @file bits/hashtable.h
00027  *  This is an internal header file, included by other library headers.
00028  *  Do not attempt to use it directly. @headername{unordered_map, unordered_set}
00029  */
00030 
00031 #ifndef _HASHTABLE_H
00032 #define _HASHTABLE_H 1
00033 
00034 #pragma GCC system_header
00035 
00036 #include <bits/hashtable_policy.h>
00037 
00038 namespace std _GLIBCXX_VISIBILITY(default)
00039 {
00040 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00041 
00042   template<typename _Tp, typename _Hash>
00043     using __cache_default =  __not_<__and_<is_integral<_Tp>,
00044                        is_empty<_Hash>,
00045                   integral_constant<bool, !__is_final(_Hash)>,
00046                  __detail::__is_noexcept_hash<_Tp, _Hash> >>;
00047 
00048   /**
00049    *  Primary class template _Hashtable.
00050    *
00051    *  @ingroup hashtable-detail
00052    *
00053    *  @tparam _Value  CopyConstructible type.
00054    *
00055    *  @tparam _Key    CopyConstructible type.
00056    *
00057    *  @tparam _Alloc  An allocator type
00058    *  ([lib.allocator.requirements]) whose _Alloc::value_type is
00059    *  _Value.  As a conforming extension, we allow for
00060    *  _Alloc::value_type != _Value.
00061    *
00062    *  @tparam _ExtractKey  Function object that takes an object of type
00063    *  _Value and returns a value of type _Key.
00064    *
00065    *  @tparam _Equal  Function object that takes two objects of type k
00066    *  and returns a bool-like value that is true if the two objects
00067    *  are considered equal.
00068    *
00069    *  @tparam _H1  The hash function. A unary function object with
00070    *  argument type _Key and result type size_t. Return values should
00071    *  be distributed over the entire range [0, numeric_limits<size_t>:::max()].
00072    *
00073    *  @tparam _H2  The range-hashing function (in the terminology of
00074    *  Tavori and Dreizin).  A binary function object whose argument
00075    *  types and result type are all size_t.  Given arguments r and N,
00076    *  the return value is in the range [0, N).
00077    *
00078    *  @tparam _Hash  The ranged hash function (Tavori and Dreizin). A
00079    *  binary function whose argument types are _Key and size_t and
00080    *  whose result type is size_t.  Given arguments k and N, the
00081    *  return value is in the range [0, N).  Default: hash(k, N) =
00082    *  h2(h1(k), N).  If _Hash is anything other than the default, _H1
00083    *  and _H2 are ignored.
00084    *
00085    *  @tparam _RehashPolicy  Policy class with three members, all of
00086    *  which govern the bucket count. _M_next_bkt(n) returns a bucket
00087    *  count no smaller than n.  _M_bkt_for_elements(n) returns a
00088    *  bucket count appropriate for an element count of n.
00089    *  _M_need_rehash(n_bkt, n_elt, n_ins) determines whether, if the
00090    *  current bucket count is n_bkt and the current element count is
00091    *  n_elt, we need to increase the bucket count.  If so, returns
00092    *  make_pair(true, n), where n is the new bucket count.  If not,
00093    *  returns make_pair(false, <anything>)
00094    *
00095    *  @tparam _Traits  Compile-time class with three boolean
00096    *  std::integral_constant members:  __cache_hash_code, __constant_iterators,
00097    *   __unique_keys.
00098    *
00099    *  Each _Hashtable data structure has:
00100    *
00101    *  - _Bucket[]       _M_buckets
00102    *  - _Hash_node_base _M_before_begin
00103    *  - size_type       _M_bucket_count
00104    *  - size_type       _M_element_count
00105    *
00106    *  with _Bucket being _Hash_node* and _Hash_node constaining:
00107    *
00108    *  - _Hash_node*   _M_next
00109    *  - Tp            _M_value
00110    *  - size_t        _M_code if cache_hash_code is true
00111    *
00112    *  In terms of Standard containers the hastable is like the aggregation of:
00113    *
00114    *  - std::forward_list<_Node> containing the elements
00115    *  - std::vector<std::forward_list<_Node>::iterator> representing the buckets
00116    *
00117    *  The non-empty buckets contain the node before the first bucket
00118    *  node. This design allow to implement something like a
00119    *  std::forward_list::insert_after on container insertion and
00120    *  std::forward_list::erase_after on container erase
00121    *  calls. _M_before_begin is equivalent to
00122    *  std::foward_list::before_begin. Empty buckets are containing
00123    *  nullptr.  Note that one of the non-empty bucket contains
00124    *  &_M_before_begin which is not a derefenrenceable node so the
00125    *  node pointers in buckets shall never be derefenrenced, only its
00126    *  next node can be.
00127    *
00128    *  Walk through a bucket nodes require a check on the hash code to
00129    *  see if the node is still in the bucket. Such a design impose a
00130    *  quite efficient hash functor and is one of the reasons it is
00131    *  highly advise to set __cache_hash_code to true.
00132    *
00133    *  The container iterators are simply built from nodes. This way
00134    *  incrementing the iterator is perfectly efficient independent of
00135    *  how many empty buckets there are in the container.
00136    *
00137    *  On insert we compute element hash code and thanks to it find the
00138    *  bucket index. If the element must be inserted on an empty bucket
00139    *  we add it at the beginning of the singly linked list and make the
00140    *  bucket point to _M_before_begin. The bucket that used to point to
00141    *  _M_before_begin, if any, is updated to point to its new before
00142    *  begin node.
00143    *
00144    *  On erase, the simple iterator design impose to use the hash
00145    *  functor to get the index of the bucket to update. For this
00146    *  reason, when __cache_hash_code is set to false, there is a static
00147    *  assertion that the hash functor cannot throw.
00148    *
00149    *  Functionality is implemented by decomposition into base classes,
00150    *  where the derived _Hashtable class is used in _Map_base,
00151    *  _Insert, _Rehash_base, and _Equality base classes to access the
00152    *  "this" pointer. _Hashtable_base is used in the base classes as a
00153    *  non-recursive, fully-completed-type so that detailed nested type
00154    *  information, such as iterator type and node type, can be
00155    *  used. This is similar to the "Curiously Recurring Template
00156    *  Pattern" (CRTP) technique, but uses a reconstructed, not
00157    *  explicitly passed, template pattern.
00158    *
00159    *  Base class templates are: 
00160    *    - __detail::_Hashtable_base
00161    *    - __detail::_Map_base
00162    *    - __detail::_Insert
00163    *    - __detail::_Rehash_base
00164    *    - __detail::_Equality
00165    */
00166   template<typename _Key, typename _Value, typename _Alloc,
00167        typename _ExtractKey, typename _Equal,
00168        typename _H1, typename _H2, typename _Hash,
00169        typename _RehashPolicy, typename _Traits>
00170     class _Hashtable
00171     : public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
00172                        _H1, _H2, _Hash, _Traits>,
00173       public __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00174                  _H1, _H2, _Hash, _RehashPolicy, _Traits>,
00175       public __detail::_Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00176                    _H1, _H2, _Hash, _RehashPolicy, _Traits>,
00177       public __detail::_Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00178                     _H1, _H2, _Hash, _RehashPolicy, _Traits>,
00179       public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00180                  _H1, _H2, _Hash, _RehashPolicy, _Traits>
00181     {
00182     public:
00183       typedef _Key                                    key_type;
00184       typedef _Value                                  value_type;
00185       typedef _Alloc                                  allocator_type;
00186       typedef _Equal                                  key_equal;
00187 
00188       // mapped_type, if present, comes from _Map_base.
00189       // hasher, if present, comes from _Hash_code_base/_Hashtable_base.
00190       typedef typename _Alloc::pointer            pointer;
00191       typedef typename _Alloc::const_pointer          const_pointer;
00192       typedef typename _Alloc::reference              reference;
00193       typedef typename _Alloc::const_reference        const_reference;
00194 
00195     private:
00196       using __rehash_type = _RehashPolicy;
00197       using __rehash_state = typename __rehash_type::_State;
00198 
00199       using __traits_type = _Traits;
00200       using __hash_cached = typename __traits_type::__hash_cached;
00201       using __constant_iterators = typename __traits_type::__constant_iterators;
00202       using __unique_keys = typename __traits_type::__unique_keys;
00203 
00204       using __key_extract = typename std::conditional<
00205                          __constant_iterators::value,
00206                              std::_Identity<value_type>,
00207                          std::_Select1st<value_type>>::type;
00208 
00209       using __hashtable_base = __detail::
00210 			       _Hashtable_base<_Key, _Value, _ExtractKey,
00211                           _Equal, _H1, _H2, _Hash, _Traits>;
00212 
00213       using __hash_code_base =  typename __hashtable_base::__hash_code_base;
00214       using __hash_code =  typename __hashtable_base::__hash_code;
00215       using __node_type = typename __hashtable_base::__node_type;
00216       using __node_base = typename __hashtable_base::__node_base;
00217       using __bucket_type = typename __hashtable_base::__bucket_type;
00218       using __ireturn_type = typename __hashtable_base::__ireturn_type;
00219       using __iconv_type = typename __hashtable_base::__iconv_type;
00220 
00221       using __map_base = __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey,
00222                          _Equal, _H1, _H2, _Hash,
00223                          _RehashPolicy, _Traits>;
00224 
00225       using __rehash_base = __detail::_Rehash_base<_Key, _Value, _Alloc,
00226                            _ExtractKey, _Equal,
00227                            _H1, _H2, _Hash,
00228                            _RehashPolicy, _Traits>;
00229 
00230       using __eq_base = __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey,
00231                         _Equal, _H1, _H2, _Hash,
00232                         _RehashPolicy, _Traits>;
00233 
00234       // Metaprogramming for picking apart hash caching.
00235       using __hash_noexcept = __detail::__is_noexcept_hash<_Key, _H1>;
00236 
00237       template<typename _Cond>
00238     using __if_hash_cached = __or_<__not_<__hash_cached>, _Cond>;
00239 
00240       template<typename _Cond>
00241     using __if_hash_not_cached = __or_<__hash_cached, _Cond>;
00242 
00243       // Compile-time diagnostics.
00244 
00245       // When hash codes are not cached the hash functor shall not
00246       // throw because it is used in methods (erase, swap...) that
00247       // shall not throw.
00248       static_assert(__if_hash_not_cached<__hash_noexcept>::value,
00249             "Cache the hash code"
00250             " or qualify your hash functor with noexcept");
00251 
00252       // Following two static assertions are necessary to guarantee
00253       // that swapping two hashtable instances won't invalidate
00254       // associated local iterators.
00255 
00256       // When hash codes are cached local iterator only uses H2 which
00257       // must then be empty.
00258       static_assert(__if_hash_cached<is_empty<_H2>>::value,
00259             "Functor used to map hash code to bucket index"
00260             " must be empty");
00261 
00262       // When hash codes are not cached local iterator is going to use
00263       // __hash_code_base above to compute node bucket index so it has
00264       // to be empty.
00265       static_assert(__if_hash_not_cached<is_empty<__hash_code_base>>::value,
00266            "Cache the hash code or make functors involved in hash code"
00267            " and bucket index computation empty");
00268 
00269     public:
00270       template<typename _Keya, typename _Valuea, typename _Alloca,
00271            typename _ExtractKeya, typename _Equala,
00272            typename _H1a, typename _H2a, typename _Hasha,
00273            typename _RehashPolicya, typename _Traitsa,
00274            bool _Unique_keysa>
00275     friend struct __detail::_Map_base;
00276 
00277       template<typename _Keya, typename _Valuea, typename _Alloca,
00278            typename _ExtractKeya, typename _Equala,
00279            typename _H1a, typename _H2a, typename _Hasha,
00280            typename _RehashPolicya, typename _Traitsa>
00281     friend struct __detail::_Insert_base;
00282 
00283       template<typename _Keya, typename _Valuea, typename _Alloca,
00284            typename _ExtractKeya, typename _Equala,
00285            typename _H1a, typename _H2a, typename _Hasha,
00286            typename _RehashPolicya, typename _Traitsa,
00287            bool _Constant_iteratorsa, bool _Unique_keysa>
00288     friend struct __detail::_Insert;
00289 
00290       using size_type = typename __hashtable_base::size_type;
00291       using difference_type = typename __hashtable_base::difference_type;
00292 
00293       using iterator = typename __hashtable_base::iterator;
00294       using const_iterator = typename __hashtable_base::const_iterator;
00295 
00296       using local_iterator = typename __hashtable_base::local_iterator;
00297       using const_local_iterator = typename __hashtable_base::
00298                    const_local_iterator;
00299 
00300     private:
00301       typedef typename _Alloc::template rebind<__node_type>::other
00302                             _Node_allocator_type;
00303       typedef typename _Alloc::template rebind<__bucket_type>::other
00304                             _Bucket_allocator_type;
00305       typedef typename _Alloc::template rebind<value_type>::other
00306                             _Value_allocator_type;
00307 
00308 
00309       _Node_allocator_type  _M_node_allocator;
00310       __bucket_type*        _M_buckets;
00311       size_type         _M_bucket_count;
00312       __node_base           _M_before_begin;
00313       size_type         _M_element_count;
00314       _RehashPolicy     _M_rehash_policy;
00315 
00316       template<typename... _Args>
00317     __node_type*
00318     _M_allocate_node(_Args&&... __args);
00319 
00320       void
00321       _M_deallocate_node(__node_type* __n);
00322 
00323       // Deallocate the linked list of nodes pointed to by __n
00324       void
00325       _M_deallocate_nodes(__node_type* __n);
00326 
00327       __bucket_type*
00328       _M_allocate_buckets(size_type __n);
00329 
00330       void
00331       _M_deallocate_buckets(__bucket_type*, size_type __n);
00332 
00333       // Gets bucket begin, deals with the fact that non-empty buckets contain
00334       // their before begin node.
00335       __node_type*
00336       _M_bucket_begin(size_type __bkt) const;
00337 
00338       __node_type*
00339       _M_begin() const
00340       { return static_cast<__node_type*>(_M_before_begin._M_nxt); }
00341 
00342     public:
00343       // Constructor, destructor, assignment, swap
00344       _Hashtable(size_type __bucket_hint,
00345          const _H1&, const _H2&, const _Hash&,
00346          const _Equal&, const _ExtractKey&,
00347          const allocator_type&);
00348 
00349       template<typename _InputIterator>
00350     _Hashtable(_InputIterator __first, _InputIterator __last,
00351            size_type __bucket_hint,
00352            const _H1&, const _H2&, const _Hash&,
00353            const _Equal&, const _ExtractKey&,
00354            const allocator_type&);
00355 
00356       _Hashtable(const _Hashtable&);
00357 
00358       _Hashtable(_Hashtable&&);
00359 
00360       // Use delegating construtors.
00361       explicit
00362       _Hashtable(size_type __n = 10,
00363          const _H1& __hf = _H1(),
00364          const key_equal& __eql = key_equal(),
00365          const allocator_type& __a = allocator_type())
00366       : _Hashtable(__n, __hf, __detail::_Mod_range_hashing(),
00367            __detail::_Default_ranged_hash(), __eql,
00368            __key_extract(), __a)
00369       { }
00370 
00371       template<typename _InputIterator>
00372     _Hashtable(_InputIterator __f, _InputIterator __l,
00373            size_type __n = 0,
00374            const _H1& __hf = _H1(),
00375            const key_equal& __eql = key_equal(),
00376            const allocator_type& __a = allocator_type())
00377     : _Hashtable(__f, __l, __n, __hf, __detail::_Mod_range_hashing(),
00378              __detail::_Default_ranged_hash(), __eql,
00379              __key_extract(), __a)
00380     { }
00381 
00382       _Hashtable(initializer_list<value_type> __l,
00383          size_type __n = 0,
00384          const _H1& __hf = _H1(),
00385          const key_equal& __eql = key_equal(),
00386          const allocator_type& __a = allocator_type())
00387       : _Hashtable(__l.begin(), __l.end(), __n, __hf,
00388            __detail::_Mod_range_hashing(),
00389            __detail::_Default_ranged_hash(), __eql,
00390            __key_extract(), __a)
00391       { }
00392 
00393       _Hashtable&
00394       operator=(const _Hashtable& __ht)
00395       {
00396     _Hashtable __tmp(__ht);
00397     this->swap(__tmp);
00398     return *this;
00399       }
00400 
00401       _Hashtable&
00402       operator=(_Hashtable&& __ht)
00403       {
00404     // NB: DR 1204.
00405     // NB: DR 675.
00406     this->clear();
00407     this->swap(__ht);
00408     return *this;
00409       }
00410 
00411       _Hashtable&
00412       operator=(initializer_list<value_type> __l)
00413       {
00414     this->clear();
00415     this->insert(__l.begin(), __l.end());
00416     return *this;
00417       }
00418 
00419       ~_Hashtable() noexcept;
00420 
00421       void swap(_Hashtable&);
00422 
00423       // Basic container operations
00424       iterator
00425       begin() noexcept
00426       { return iterator(_M_begin()); }
00427 
00428       const_iterator
00429       begin() const noexcept
00430       { return const_iterator(_M_begin()); }
00431 
00432       iterator
00433       end() noexcept
00434       { return iterator(nullptr); }
00435 
00436       const_iterator
00437       end() const noexcept
00438       { return const_iterator(nullptr); }
00439 
00440       const_iterator
00441       cbegin() const noexcept
00442       { return const_iterator(_M_begin()); }
00443 
00444       const_iterator
00445       cend() const noexcept
00446       { return const_iterator(nullptr); }
00447 
00448       size_type
00449       size() const noexcept
00450       { return _M_element_count; }
00451 
00452       bool
00453       empty() const noexcept
00454       { return size() == 0; }
00455 
00456       allocator_type
00457       get_allocator() const noexcept
00458       { return allocator_type(_M_node_allocator); }
00459 
00460       size_type
00461       max_size() const noexcept
00462       { return _M_node_allocator.max_size(); }
00463 
00464       // Observers
00465       key_equal
00466       key_eq() const
00467       { return this->_M_eq(); }
00468 
00469       // hash_function, if present, comes from _Hash_code_base.
00470 
00471       // Bucket operations
00472       size_type
00473       bucket_count() const noexcept
00474       { return _M_bucket_count; }
00475 
00476       size_type
00477       max_bucket_count() const noexcept
00478       { return max_size(); }
00479 
00480       size_type
00481       bucket_size(size_type __n) const
00482       { return std::distance(begin(__n), end(__n)); }
00483 
00484       size_type
00485       bucket(const key_type& __k) const
00486       { return _M_bucket_index(__k, this->_M_hash_code(__k)); }
00487 
00488       local_iterator
00489       begin(size_type __n)
00490       { return local_iterator(_M_bucket_begin(__n), __n, _M_bucket_count); }
00491 
00492       local_iterator
00493       end(size_type __n)
00494       { return local_iterator(nullptr, __n, _M_bucket_count); }
00495 
00496       const_local_iterator
00497       begin(size_type __n) const
00498       { return const_local_iterator(_M_bucket_begin(__n), __n,
00499                     _M_bucket_count); }
00500 
00501       const_local_iterator
00502       end(size_type __n) const
00503       { return const_local_iterator(nullptr, __n, _M_bucket_count); }
00504 
00505       // DR 691.
00506       const_local_iterator
00507       cbegin(size_type __n) const
00508       { return const_local_iterator(_M_bucket_begin(__n), __n,
00509                     _M_bucket_count); }
00510 
00511       const_local_iterator
00512       cend(size_type __n) const
00513       { return const_local_iterator(nullptr, __n, _M_bucket_count); }
00514 
00515       float
00516       load_factor() const noexcept
00517       {
00518     return static_cast<float>(size()) / static_cast<float>(bucket_count());
00519       }
00520 
00521       // max_load_factor, if present, comes from _Rehash_base.
00522 
00523       // Generalization of max_load_factor.  Extension, not found in
00524       // TR1.  Only useful if _RehashPolicy is something other than
00525       // the default.
00526       const _RehashPolicy&
00527       __rehash_policy() const
00528       { return _M_rehash_policy; }
00529 
00530       void
00531       __rehash_policy(const _RehashPolicy&);
00532 
00533       // Lookup.
00534       iterator
00535       find(const key_type& __k);
00536 
00537       const_iterator
00538       find(const key_type& __k) const;
00539 
00540       size_type
00541       count(const key_type& __k) const;
00542 
00543       std::pair<iterator, iterator>
00544       equal_range(const key_type& __k);
00545 
00546       std::pair<const_iterator, const_iterator>
00547       equal_range(const key_type& __k) const;
00548 
00549     protected:
00550       // Bucket index computation helpers.
00551       size_type
00552       _M_bucket_index(__node_type* __n) const
00553       { return __hash_code_base::_M_bucket_index(__n, _M_bucket_count); }
00554 
00555       size_type
00556       _M_bucket_index(const key_type& __k, __hash_code __c) const
00557       { return __hash_code_base::_M_bucket_index(__k, __c, _M_bucket_count); }
00558 
00559       // Find and insert helper functions and types
00560       // Find the node before the one matching the criteria.
00561       __node_base*
00562       _M_find_before_node(size_type, const key_type&, __hash_code) const;
00563 
00564       __node_type*
00565       _M_find_node(size_type __bkt, const key_type& __key,
00566            __hash_code __c) const
00567       {
00568     __node_base* __before_n = _M_find_before_node(__bkt, __key, __c);
00569     if (__before_n)
00570       return static_cast<__node_type*>(__before_n->_M_nxt);
00571     return nullptr;
00572       }
00573 
00574       // Insert a node at the beginning of a bucket.
00575       void
00576       _M_insert_bucket_begin(size_type, __node_type*);
00577 
00578       // Remove the bucket first node
00579       void
00580       _M_remove_bucket_begin(size_type __bkt, __node_type* __next_n,
00581                  size_type __next_bkt);
00582 
00583       // Get the node before __n in the bucket __bkt
00584       __node_base*
00585       _M_get_previous_node(size_type __bkt, __node_base* __n);
00586 
00587       template<typename _Arg>
00588     iterator
00589     _M_insert_bucket(_Arg&&, size_type, __hash_code);
00590 
00591 
00592       template<typename... _Args>
00593     std::pair<iterator, bool>
00594     _M_emplace(std::true_type, _Args&&... __args);
00595 
00596       template<typename... _Args>
00597     iterator
00598     _M_emplace(std::false_type, _Args&&... __args);
00599 
00600       template<typename _Arg>
00601     std::pair<iterator, bool>
00602     _M_insert(_Arg&&, std::true_type);
00603 
00604       template<typename _Arg>
00605     iterator
00606     _M_insert(_Arg&&, std::false_type);
00607 
00608     public:
00609       // Emplace
00610       template<typename... _Args>
00611     __ireturn_type
00612     emplace(_Args&&... __args)
00613     { return _M_emplace(__unique_keys(), std::forward<_Args>(__args)...); }
00614 
00615       template<typename... _Args>
00616     iterator
00617     emplace_hint(const_iterator, _Args&&... __args)
00618     { return __iconv_type()(emplace(std::forward<_Args>(__args)...)); }
00619 
00620       // Insert member functions via inheritance.
00621 
00622       // Erase
00623       iterator
00624       erase(const_iterator);
00625 
00626       // LWG 2059.
00627       iterator
00628       erase(iterator __it)
00629       { return erase(const_iterator(__it)); }
00630 
00631       size_type
00632       erase(const key_type&);
00633 
00634       iterator
00635       erase(const_iterator, const_iterator);
00636 
00637       void
00638       clear() noexcept;
00639 
00640       // Set number of buckets to be appropriate for container of n element.
00641       void rehash(size_type __n);
00642 
00643       // DR 1189.
00644       // reserve, if present, comes from _Rehash_base.
00645 
00646     private:
00647       // Helper rehash method used when keys are unique.
00648       void _M_rehash_aux(size_type __n, std::true_type);
00649 
00650       // Helper rehash method used when keys can be non-unique.
00651       void _M_rehash_aux(size_type __n, std::false_type);
00652 
00653       // Unconditionally change size of bucket array to n, restore
00654       // hash policy state to __state on exception.
00655       void _M_rehash(size_type __n, const __rehash_state& __state);
00656     };
00657 
00658 
00659   // Definitions of class template _Hashtable's out-of-line member functions.
00660   template<typename _Key, typename _Value,
00661        typename _Alloc, typename _ExtractKey, typename _Equal,
00662        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00663        typename _Traits>
00664     template<typename... _Args>
00665       typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00666               _H1, _H2, _Hash, _RehashPolicy, _Traits>::__node_type*
00667       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00668          _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00669       _M_allocate_node(_Args&&... __args)
00670       {
00671     __node_type* __n = _M_node_allocator.allocate(1);
00672     __try
00673       {
00674         _M_node_allocator.construct(__n, std::forward<_Args>(__args)...);
00675         return __n;
00676       }
00677     __catch(...)
00678       {
00679         _M_node_allocator.deallocate(__n, 1);
00680         __throw_exception_again;
00681       }
00682       }
00683 
00684   template<typename _Key, typename _Value,
00685        typename _Alloc, typename _ExtractKey, typename _Equal,
00686        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00687        typename _Traits>
00688     void
00689     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00690            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00691     _M_deallocate_node(__node_type* __n)
00692     {
00693       _M_node_allocator.destroy(__n);
00694       _M_node_allocator.deallocate(__n, 1);
00695     }
00696 
00697   template<typename _Key, typename _Value,
00698        typename _Alloc, typename _ExtractKey, typename _Equal,
00699        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00700        typename _Traits>
00701     void
00702     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00703            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00704     _M_deallocate_nodes(__node_type* __n)
00705     {
00706       while (__n)
00707     {
00708       __node_type* __tmp = __n;
00709       __n = __n->_M_next();
00710       _M_deallocate_node(__tmp);
00711     }
00712     }
00713 
00714   template<typename _Key, typename _Value,
00715        typename _Alloc, typename _ExtractKey, typename _Equal,
00716        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00717        typename _Traits>
00718     typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00719             _H1, _H2, _Hash, _RehashPolicy, _Traits>::__bucket_type*
00720     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00721            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00722     _M_allocate_buckets(size_type __n)
00723     {
00724       _Bucket_allocator_type __alloc(_M_node_allocator);
00725 
00726       __bucket_type* __p = __alloc.allocate(__n);
00727       __builtin_memset(__p, 0, __n * sizeof(__bucket_type));
00728       return __p;
00729     }
00730 
00731   template<typename _Key, typename _Value,
00732        typename _Alloc, typename _ExtractKey, typename _Equal,
00733        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00734        typename _Traits>
00735     void
00736     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00737            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00738     _M_deallocate_buckets(__bucket_type* __p, size_type __n)
00739     {
00740       _Bucket_allocator_type __alloc(_M_node_allocator);
00741       __alloc.deallocate(__p, __n);
00742     }
00743 
00744   template<typename _Key, typename _Value,
00745        typename _Alloc, typename _ExtractKey, typename _Equal,
00746        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00747        typename _Traits>
00748     typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
00749             _Equal, _H1, _H2, _Hash, _RehashPolicy,
00750             _Traits>::__node_type*
00751     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00752            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00753     _M_bucket_begin(size_type __bkt) const
00754     {
00755       __node_base* __n = _M_buckets[__bkt];
00756       return __n ? static_cast<__node_type*>(__n->_M_nxt) : nullptr;
00757     }
00758 
00759   template<typename _Key, typename _Value,
00760        typename _Alloc, typename _ExtractKey, typename _Equal,
00761        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00762        typename _Traits>
00763     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00764            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00765     _Hashtable(size_type __bucket_hint,
00766            const _H1& __h1, const _H2& __h2, const _Hash& __h,
00767            const _Equal& __eq, const _ExtractKey& __exk,
00768            const allocator_type& __a)
00769     : __hashtable_base(__exk, __h1, __h2, __h, __eq),
00770       __map_base(),
00771       __rehash_base(),
00772       _M_node_allocator(__a),
00773       _M_bucket_count(0),
00774       _M_element_count(0),
00775       _M_rehash_policy()
00776     {
00777       _M_bucket_count = _M_rehash_policy._M_next_bkt(__bucket_hint);
00778 
00779       // We don't want the rehash policy to ask for the hashtable to
00780       // shrink on the first insertion so we need to reset its
00781       // previous resize level.
00782       _M_rehash_policy._M_prev_resize = 0;
00783       _M_buckets = _M_allocate_buckets(_M_bucket_count);
00784     }
00785 
00786   template<typename _Key, typename _Value,
00787        typename _Alloc, typename _ExtractKey, typename _Equal,
00788        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00789        typename _Traits>
00790     template<typename _InputIterator>
00791       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00792          _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00793       _Hashtable(_InputIterator __f, _InputIterator __l,
00794          size_type __bucket_hint,
00795          const _H1& __h1, const _H2& __h2, const _Hash& __h,
00796          const _Equal& __eq, const _ExtractKey& __exk,
00797          const allocator_type& __a)
00798       : __hashtable_base(__exk, __h1, __h2, __h, __eq),
00799     __map_base(),
00800     __rehash_base(),
00801     _M_node_allocator(__a),
00802     _M_bucket_count(0),
00803     _M_element_count(0),
00804     _M_rehash_policy()
00805       {
00806     _M_bucket_count = std::max(_M_rehash_policy._M_next_bkt(__bucket_hint),
00807                    _M_rehash_policy.
00808                    _M_bkt_for_elements(__detail::
00809                                __distance_fw(__f,
00810                                      __l)));
00811 
00812     // We don't want the rehash policy to ask for the hashtable to
00813     // shrink on the first insertion so we need to reset its
00814     // previous resize level.
00815     _M_rehash_policy._M_prev_resize = 0;
00816     _M_buckets = _M_allocate_buckets(_M_bucket_count);
00817     __try
00818       {
00819         for (; __f != __l; ++__f)
00820           this->insert(*__f);
00821       }
00822     __catch(...)
00823       {
00824         clear();
00825         _M_deallocate_buckets(_M_buckets, _M_bucket_count);
00826         __throw_exception_again;
00827       }
00828       }
00829 
00830   template<typename _Key, typename _Value,
00831        typename _Alloc, typename _ExtractKey, typename _Equal,
00832        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00833        typename _Traits>
00834     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00835            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00836     _Hashtable(const _Hashtable& __ht)
00837     : __hashtable_base(__ht),
00838       __map_base(__ht),
00839       __rehash_base(__ht),
00840       _M_node_allocator(__ht._M_node_allocator),
00841       _M_bucket_count(__ht._M_bucket_count),
00842       _M_element_count(__ht._M_element_count),
00843       _M_rehash_policy(__ht._M_rehash_policy)
00844     {
00845       _M_buckets = _M_allocate_buckets(_M_bucket_count);
00846       __try
00847     {
00848       if (!__ht._M_before_begin._M_nxt)
00849         return;
00850 
00851       // First deal with the special first node pointed to by
00852       // _M_before_begin.
00853       const __node_type* __ht_n = __ht._M_begin();
00854       __node_type* __this_n = _M_allocate_node(__ht_n->_M_v);
00855       this->_M_copy_code(__this_n, __ht_n);
00856       _M_before_begin._M_nxt = __this_n;
00857       _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin;
00858 
00859       // Then deal with other nodes.
00860       __node_base* __prev_n = __this_n;
00861       for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next())
00862         {
00863           __this_n = _M_allocate_node(__ht_n->_M_v);
00864           __prev_n->_M_nxt = __this_n;
00865           this->_M_copy_code(__this_n, __ht_n);
00866           size_type __bkt = _M_bucket_index(__this_n);
00867           if (!_M_buckets[__bkt])
00868         _M_buckets[__bkt] = __prev_n;
00869           __prev_n = __this_n;
00870         }
00871     }
00872       __catch(...)
00873     {
00874       clear();
00875       _M_deallocate_buckets(_M_buckets, _M_bucket_count);
00876       __throw_exception_again;
00877     }
00878     }
00879 
00880   template<typename _Key, typename _Value,
00881        typename _Alloc, typename _ExtractKey, typename _Equal,
00882        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00883        typename _Traits>
00884     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00885            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00886     _Hashtable(_Hashtable&& __ht)
00887     : __hashtable_base(__ht),
00888       __map_base(__ht),
00889       __rehash_base(__ht),
00890       _M_node_allocator(std::move(__ht._M_node_allocator)),
00891       _M_buckets(__ht._M_buckets),
00892       _M_bucket_count(__ht._M_bucket_count),
00893       _M_before_begin(__ht._M_before_begin._M_nxt),
00894       _M_element_count(__ht._M_element_count),
00895       _M_rehash_policy(__ht._M_rehash_policy)
00896     {
00897       // Update, if necessary, bucket pointing to before begin that hasn't move.
00898       if (_M_begin())
00899     _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
00900       __ht._M_rehash_policy = _RehashPolicy();
00901       __ht._M_bucket_count = __ht._M_rehash_policy._M_next_bkt(0);
00902       __ht._M_buckets = __ht._M_allocate_buckets(__ht._M_bucket_count);
00903       __ht._M_before_begin._M_nxt = nullptr;
00904       __ht._M_element_count = 0;
00905     }
00906 
00907   template<typename _Key, typename _Value,
00908        typename _Alloc, typename _ExtractKey, typename _Equal,
00909        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00910        typename _Traits>
00911     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00912            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00913     ~_Hashtable() noexcept
00914     {
00915       clear();
00916       _M_deallocate_buckets(_M_buckets, _M_bucket_count);
00917     }
00918 
00919   template<typename _Key, typename _Value,
00920        typename _Alloc, typename _ExtractKey, typename _Equal,
00921        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00922        typename _Traits>
00923     void
00924     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00925            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00926     swap(_Hashtable& __x)
00927     {
00928       // The only base class with member variables is hash_code_base.
00929       // We define _Hash_code_base::_M_swap because different
00930       // specializations have different members.
00931       this->_M_swap(__x);
00932 
00933       // _GLIBCXX_RESOLVE_LIB_DEFECTS
00934       // 431. Swapping containers with unequal allocators.
00935       std::__alloc_swap<_Node_allocator_type>::_S_do_it(_M_node_allocator,
00936                             __x._M_node_allocator);
00937 
00938       std::swap(_M_rehash_policy, __x._M_rehash_policy);
00939       std::swap(_M_buckets, __x._M_buckets);
00940       std::swap(_M_bucket_count, __x._M_bucket_count);
00941       std::swap(_M_before_begin._M_nxt, __x._M_before_begin._M_nxt);
00942       std::swap(_M_element_count, __x._M_element_count);
00943 
00944       // Fix buckets containing the _M_before_begin pointers that
00945       // can't be swapped.
00946       if (_M_begin())
00947     _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
00948       if (__x._M_begin())
00949     __x._M_buckets[__x._M_bucket_index(__x._M_begin())]
00950       = &(__x._M_before_begin);
00951     }
00952 
00953   template<typename _Key, typename _Value,
00954        typename _Alloc, typename _ExtractKey, typename _Equal,
00955        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00956        typename _Traits>
00957     void
00958     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00959            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00960     __rehash_policy(const _RehashPolicy& __pol)
00961     {
00962       size_type __n_bkt = __pol._M_bkt_for_elements(_M_element_count);
00963       if (__n_bkt != _M_bucket_count)
00964     _M_rehash(__n_bkt, _M_rehash_policy._M_state());
00965       _M_rehash_policy = __pol;
00966     }
00967 
00968   template<typename _Key, typename _Value,
00969        typename _Alloc, typename _ExtractKey, typename _Equal,
00970        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00971        typename _Traits>
00972     typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00973             _H1, _H2, _Hash, _RehashPolicy,
00974             _Traits>::iterator
00975     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00976            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00977     find(const key_type& __k)
00978     {
00979       __hash_code __code = this->_M_hash_code(__k);
00980       std::size_t __n = _M_bucket_index(__k, __code);
00981       __node_type* __p = _M_find_node(__n, __k, __code);
00982       return __p ? iterator(__p) : this->end();
00983     }
00984 
00985   template<typename _Key, typename _Value,
00986        typename _Alloc, typename _ExtractKey, typename _Equal,
00987        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
00988        typename _Traits>
00989     typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00990             _H1, _H2, _Hash, _RehashPolicy,
00991             _Traits>::const_iterator
00992     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
00993            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
00994     find(const key_type& __k) const
00995     {
00996       __hash_code __code = this->_M_hash_code(__k);
00997       std::size_t __n = _M_bucket_index(__k, __code);
00998       __node_type* __p = _M_find_node(__n, __k, __code);
00999       return __p ? const_iterator(__p) : this->end();
01000     }
01001 
01002   template<typename _Key, typename _Value,
01003        typename _Alloc, typename _ExtractKey, typename _Equal,
01004        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01005        typename _Traits>
01006     typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01007             _H1, _H2, _Hash, _RehashPolicy,
01008             _Traits>::size_type
01009     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01010            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01011     count(const key_type& __k) const
01012     {
01013       __hash_code __code = this->_M_hash_code(__k);
01014       std::size_t __n = _M_bucket_index(__k, __code);
01015       __node_type* __p = _M_bucket_begin(__n);
01016       if (!__p)
01017     return 0;
01018 
01019       std::size_t __result = 0;
01020       for (;; __p = __p->_M_next())
01021     {
01022       if (this->_M_equals(__k, __code, __p))
01023         ++__result;
01024       else if (__result)
01025         // All equivalent values are next to each other, if we
01026         // found a not equivalent value after an equivalent one it
01027         // means that we won't find anymore an equivalent value.
01028         break;
01029       if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n)
01030         break;
01031     }
01032       return __result;
01033     }
01034 
01035   template<typename _Key, typename _Value,
01036        typename _Alloc, typename _ExtractKey, typename _Equal,
01037        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01038        typename _Traits>
01039     std::pair<typename _Hashtable<_Key, _Value, _Alloc,
01040                   _ExtractKey, _Equal, _H1,
01041                   _H2, _Hash, _RehashPolicy,
01042                   _Traits>::iterator,
01043           typename _Hashtable<_Key, _Value, _Alloc,
01044                   _ExtractKey, _Equal, _H1,
01045                   _H2, _Hash, _RehashPolicy,
01046                   _Traits>::iterator>
01047     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01048            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01049     equal_range(const key_type& __k)
01050     {
01051       __hash_code __code = this->_M_hash_code(__k);
01052       std::size_t __n = _M_bucket_index(__k, __code);
01053       __node_type* __p = _M_find_node(__n, __k, __code);
01054 
01055       if (__p)
01056     {
01057       __node_type* __p1 = __p->_M_next();
01058       while (__p1 && _M_bucket_index(__p1) == __n
01059          && this->_M_equals(__k, __code, __p1))
01060         __p1 = __p1->_M_next();
01061 
01062       return std::make_pair(iterator(__p), iterator(__p1));
01063     }
01064       else
01065     return std::make_pair(this->end(), this->end());
01066     }
01067 
01068   template<typename _Key, typename _Value,
01069        typename _Alloc, typename _ExtractKey, typename _Equal,
01070        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01071        typename _Traits>
01072     std::pair<typename _Hashtable<_Key, _Value, _Alloc,
01073                   _ExtractKey, _Equal, _H1,
01074                   _H2, _Hash, _RehashPolicy,
01075                   _Traits>::const_iterator,
01076           typename _Hashtable<_Key, _Value, _Alloc,
01077                   _ExtractKey, _Equal, _H1,
01078                   _H2, _Hash, _RehashPolicy,
01079                   _Traits>::const_iterator>
01080     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01081            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01082     equal_range(const key_type& __k) const
01083     {
01084       __hash_code __code = this->_M_hash_code(__k);
01085       std::size_t __n = _M_bucket_index(__k, __code);
01086       __node_type* __p = _M_find_node(__n, __k, __code);
01087 
01088       if (__p)
01089     {
01090       __node_type* __p1 = __p->_M_next();
01091       while (__p1 && _M_bucket_index(__p1) == __n
01092          && this->_M_equals(__k, __code, __p1))
01093         __p1 = __p1->_M_next();
01094 
01095       return std::make_pair(const_iterator(__p), const_iterator(__p1));
01096     }
01097       else
01098     return std::make_pair(this->end(), this->end());
01099     }
01100 
01101   // Find the node whose key compares equal to k in the bucket n.
01102   // Return nullptr if no node is found.
01103   template<typename _Key, typename _Value,
01104        typename _Alloc, typename _ExtractKey, typename _Equal,
01105        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01106        typename _Traits>
01107     typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
01108             _Equal, _H1, _H2, _Hash, _RehashPolicy,
01109             _Traits>::__node_base*
01110     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01111            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01112     _M_find_before_node(size_type __n, const key_type& __k,
01113             __hash_code __code) const
01114     {
01115       __node_base* __prev_p = _M_buckets[__n];
01116       if (!__prev_p)
01117     return nullptr;
01118       __node_type* __p = static_cast<__node_type*>(__prev_p->_M_nxt);
01119       for (;; __p = __p->_M_next())
01120     {
01121       if (this->_M_equals(__k, __code, __p))
01122         return __prev_p;
01123       if (!(__p->_M_nxt) || _M_bucket_index(__p->_M_next()) != __n)
01124         break;
01125       __prev_p = __p;
01126     }
01127       return nullptr;
01128     }
01129 
01130   template<typename _Key, typename _Value,
01131        typename _Alloc, typename _ExtractKey, typename _Equal,
01132        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01133        typename _Traits>
01134     void
01135     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01136            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01137     _M_insert_bucket_begin(size_type __bkt, __node_type* __node)
01138     {
01139       if (_M_buckets[__bkt])
01140     {
01141       // Bucket is not empty, we just need to insert the new node
01142       // after the bucket before begin.
01143       __node->_M_nxt = _M_buckets[__bkt]->_M_nxt;
01144       _M_buckets[__bkt]->_M_nxt = __node;
01145     }
01146       else
01147     {
01148       // The bucket is empty, the new node is inserted at the
01149       // beginning of the singly linked list and the bucket will
01150       // contain _M_before_begin pointer.
01151       __node->_M_nxt = _M_before_begin._M_nxt;
01152       _M_before_begin._M_nxt = __node;
01153       if (__node->_M_nxt)
01154         // We must update former begin bucket that is pointing to
01155         // _M_before_begin.
01156         _M_buckets[_M_bucket_index(__node->_M_next())] = __node;
01157       _M_buckets[__bkt] = &_M_before_begin;
01158     }
01159     }
01160 
01161   template<typename _Key, typename _Value,
01162        typename _Alloc, typename _ExtractKey, typename _Equal,
01163        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01164        typename _Traits>
01165     void
01166     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01167            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01168     _M_remove_bucket_begin(size_type __bkt, __node_type* __next,
01169                size_type __next_bkt)
01170     {
01171       if (!__next || __next_bkt != __bkt)
01172     {
01173       // Bucket is now empty
01174       // First update next bucket if any
01175       if (__next)
01176         _M_buckets[__next_bkt] = _M_buckets[__bkt];
01177 
01178       // Second update before begin node if necessary
01179       if (&_M_before_begin == _M_buckets[__bkt])
01180         _M_before_begin._M_nxt = __next;
01181       _M_buckets[__bkt] = nullptr;
01182     }
01183     }
01184 
01185   template<typename _Key, typename _Value,
01186        typename _Alloc, typename _ExtractKey, typename _Equal,
01187        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01188        typename _Traits>
01189     typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
01190             _Equal, _H1, _H2, _Hash, _RehashPolicy,
01191             _Traits>::__node_base*
01192     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01193            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01194     _M_get_previous_node(size_type __bkt, __node_base* __n)
01195     {
01196       __node_base* __prev_n = _M_buckets[__bkt];
01197       while (__prev_n->_M_nxt != __n)
01198     __prev_n = __prev_n->_M_nxt;
01199       return __prev_n;
01200     }
01201 
01202   template<typename _Key, typename _Value,
01203        typename _Alloc, typename _ExtractKey, typename _Equal,
01204        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01205        typename _Traits>
01206     template<typename... _Args>
01207       std::pair<typename _Hashtable<_Key, _Value, _Alloc,
01208                     _ExtractKey, _Equal, _H1,
01209                     _H2, _Hash, _RehashPolicy,
01210                     _Traits>::iterator, bool>
01211       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01212          _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01213       _M_emplace(std::true_type, _Args&&... __args)
01214       {
01215     // First build the node to get access to the hash code
01216     __node_type* __node = _M_allocate_node(std::forward<_Args>(__args)...);
01217     __try
01218       {
01219         const key_type& __k = this->_M_extract()(__node->_M_v);
01220         __hash_code __code = this->_M_hash_code(__k);
01221         size_type __bkt = _M_bucket_index(__k, __code);
01222 
01223         if (__node_type* __p = _M_find_node(__bkt, __k, __code))
01224           {
01225         // There is already an equivalent node, no insertion
01226         _M_deallocate_node(__node);
01227         return std::make_pair(iterator(__p), false);
01228           }
01229 
01230         // We are going to insert this node
01231         this->_M_store_code(__node, __code);
01232         const __rehash_state& __saved_state
01233           = _M_rehash_policy._M_state();
01234         std::pair<bool, std::size_t> __do_rehash
01235           = _M_rehash_policy._M_need_rehash(_M_bucket_count,
01236                         _M_element_count, 1);
01237 
01238         if (__do_rehash.first)
01239           {
01240         _M_rehash(__do_rehash.second, __saved_state);
01241         __bkt = _M_bucket_index(__k, __code);
01242           }
01243 
01244         _M_insert_bucket_begin(__bkt, __node);
01245         ++_M_element_count;
01246         return std::make_pair(iterator(__node), true);
01247       }
01248     __catch(...)
01249       {
01250         _M_deallocate_node(__node);
01251         __throw_exception_again;
01252       }
01253       }
01254 
01255   template<typename _Key, typename _Value,
01256        typename _Alloc, typename _ExtractKey, typename _Equal,
01257        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01258        typename _Traits>
01259     template<typename... _Args>
01260       typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01261               _H1, _H2, _Hash, _RehashPolicy,
01262               _Traits>::iterator
01263       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01264          _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01265       _M_emplace(std::false_type, _Args&&... __args)
01266       {
01267     const __rehash_state& __saved_state = _M_rehash_policy._M_state();
01268     std::pair<bool, std::size_t> __do_rehash
01269       = _M_rehash_policy._M_need_rehash(_M_bucket_count,
01270                         _M_element_count, 1);
01271 
01272     // First build the node to get its hash code.
01273     __node_type* __node = _M_allocate_node(std::forward<_Args>(__args)...);
01274     __try
01275       {
01276         const key_type& __k = this->_M_extract()(__node->_M_v);
01277         __hash_code __code = this->_M_hash_code(__k);
01278         this->_M_store_code(__node, __code);
01279 
01280         // Second, do rehash if necessary.
01281         if (__do_rehash.first)
01282         _M_rehash(__do_rehash.second, __saved_state);
01283 
01284         // Third, find the node before an equivalent one.
01285         size_type __bkt = _M_bucket_index(__k, __code);
01286         __node_base* __prev = _M_find_before_node(__bkt, __k, __code);
01287 
01288         if (__prev)
01289           {
01290         // Insert after the node before the equivalent one.
01291         __node->_M_nxt = __prev->_M_nxt;
01292         __prev->_M_nxt = __node;
01293           }
01294         else
01295           // The inserted node has no equivalent in the
01296           // hashtable. We must insert the new node at the
01297           // beginning of the bucket to preserve equivalent
01298           // elements relative positions.
01299           _M_insert_bucket_begin(__bkt, __node);
01300         ++_M_element_count;
01301         return iterator(__node);
01302       }
01303     __catch(...)
01304       {
01305         _M_deallocate_node(__node);
01306         __throw_exception_again;
01307       }
01308       }
01309 
01310   // Insert v in bucket n (assumes no element with its key already present).
01311   template<typename _Key, typename _Value,
01312        typename _Alloc, typename _ExtractKey, typename _Equal,
01313        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01314        typename _Traits>
01315     template<typename _Arg>
01316       typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01317               _H1, _H2, _Hash, _RehashPolicy,
01318               _Traits>::iterator
01319       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01320          _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01321       _M_insert_bucket(_Arg&& __v, size_type __n, __hash_code __code)
01322       {
01323     const __rehash_state& __saved_state = _M_rehash_policy._M_state();
01324     std::pair<bool, std::size_t> __do_rehash
01325       = _M_rehash_policy._M_need_rehash(_M_bucket_count,
01326                         _M_element_count, 1);
01327 
01328     if (__do_rehash.first)
01329       {
01330         const key_type& __k = this->_M_extract()(__v);
01331         __n = __hash_code_base::_M_bucket_index(__k, __code,
01332                             __do_rehash.second);
01333       }
01334 
01335     __node_type* __node = nullptr;
01336     __try
01337       {
01338         // Allocate the new node before doing the rehash so that we
01339         // don't do a rehash if the allocation throws.
01340         __node = _M_allocate_node(std::forward<_Arg>(__v));
01341         this->_M_store_code(__node, __code);
01342         if (__do_rehash.first)
01343           _M_rehash(__do_rehash.second, __saved_state);
01344 
01345         _M_insert_bucket_begin(__n, __node);
01346         ++_M_element_count;
01347         return iterator(__node);
01348       }
01349     __catch(...)
01350       {
01351         if (!__node)
01352           _M_rehash_policy._M_reset(__saved_state);
01353         else
01354           _M_deallocate_node(__node);
01355         __throw_exception_again;
01356       }
01357       }
01358 
01359   // Insert v if no element with its key is already present.
01360   template<typename _Key, typename _Value,
01361        typename _Alloc, typename _ExtractKey, typename _Equal,
01362        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01363        typename _Traits>
01364     template<typename _Arg>
01365       std::pair<typename _Hashtable<_Key, _Value, _Alloc,
01366                     _ExtractKey, _Equal, _H1,
01367                     _H2, _Hash, _RehashPolicy,
01368                     _Traits>::iterator, bool>
01369       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01370          _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01371       _M_insert(_Arg&& __v, std::true_type)
01372       {
01373     const key_type& __k = this->_M_extract()(__v);
01374     __hash_code __code = this->_M_hash_code(__k);
01375     size_type __n = _M_bucket_index(__k, __code);
01376 
01377     if (__node_type* __p = _M_find_node(__n, __k, __code))
01378       return std::make_pair(iterator(__p), false);
01379     return std::make_pair(_M_insert_bucket(std::forward<_Arg>(__v),
01380                   __n, __code), true);
01381       }
01382 
01383   // Insert v unconditionally.
01384   template<typename _Key, typename _Value,
01385        typename _Alloc, typename _ExtractKey, typename _Equal,
01386        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01387        typename _Traits>
01388     template<typename _Arg>
01389       typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01390               _H1, _H2, _Hash, _RehashPolicy,
01391               _Traits>::iterator
01392       _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01393          _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01394       _M_insert(_Arg&& __v, std::false_type)
01395       {
01396     const __rehash_state& __saved_state = _M_rehash_policy._M_state();
01397     std::pair<bool, std::size_t> __do_rehash
01398       = _M_rehash_policy._M_need_rehash(_M_bucket_count,
01399                         _M_element_count, 1);
01400 
01401     // First compute the hash code so that we don't do anything if
01402     // it throws.
01403     __hash_code __code = this->_M_hash_code(this->_M_extract()(__v));
01404 
01405     __node_type* __node = nullptr;
01406     __try
01407       {
01408         // Second allocate new node so that we don't rehash if it throws.
01409         __node = _M_allocate_node(std::forward<_Arg>(__v));
01410         this->_M_store_code(__node, __code);
01411         if (__do_rehash.first)
01412         _M_rehash(__do_rehash.second, __saved_state);
01413 
01414         // Third, find the node before an equivalent one.
01415         size_type __bkt = _M_bucket_index(__node);
01416         __node_base* __prev
01417           = _M_find_before_node(__bkt, this->_M_extract()(__node->_M_v),
01418                     __code);
01419         if (__prev)
01420           {
01421         // Insert after the node before the equivalent one.
01422         __node->_M_nxt = __prev->_M_nxt;
01423         __prev->_M_nxt = __node;
01424           }
01425         else
01426           // The inserted node has no equivalent in the
01427           // hashtable. We must insert the new node at the
01428           // beginning of the bucket to preserve equivalent
01429           // elements relative positions.
01430           _M_insert_bucket_begin(__bkt, __node);
01431         ++_M_element_count;
01432         return iterator(__node);
01433       }
01434     __catch(...)
01435       {
01436         if (!__node)
01437           _M_rehash_policy._M_reset(__saved_state);
01438         else
01439           _M_deallocate_node(__node);
01440         __throw_exception_again;
01441       }
01442       }
01443 
01444 
01445   template<typename _Key, typename _Value,
01446        typename _Alloc, typename _ExtractKey, typename _Equal,
01447        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01448        typename _Traits>
01449     typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01450             _H1, _H2, _Hash, _RehashPolicy,
01451             _Traits>::iterator
01452     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01453            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01454     erase(const_iterator __it)
01455     {
01456       __node_type* __n = __it._M_cur;
01457       std::size_t __bkt = _M_bucket_index(__n);
01458 
01459       // Look for previous node to unlink it from the erased one, this
01460       // is why we need buckets to contain the before begin to make
01461       // this research fast.
01462       __node_base* __prev_n = _M_get_previous_node(__bkt, __n);
01463       if (__n == _M_bucket_begin(__bkt))
01464     _M_remove_bucket_begin(__bkt, __n->_M_next(),
01465        __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0);
01466       else if (__n->_M_nxt)
01467     {
01468       size_type __next_bkt = _M_bucket_index(__n->_M_next());
01469       if (__next_bkt != __bkt)
01470         _M_buckets[__next_bkt] = __prev_n;
01471     }
01472 
01473       __prev_n->_M_nxt = __n->_M_nxt;
01474       iterator __result(__n->_M_next());
01475       _M_deallocate_node(__n);
01476       --_M_element_count;
01477 
01478       return __result;
01479     }
01480 
01481   template<typename _Key, typename _Value,
01482        typename _Alloc, typename _ExtractKey, typename _Equal,
01483        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01484        typename _Traits>
01485     typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01486             _H1, _H2, _Hash, _RehashPolicy,
01487             _Traits>::size_type
01488     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01489            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01490     erase(const key_type& __k)
01491     {
01492       __hash_code __code = this->_M_hash_code(__k);
01493       std::size_t __bkt = _M_bucket_index(__k, __code);
01494 
01495       // Look for the node before the first matching node.
01496       __node_base* __prev_n = _M_find_before_node(__bkt, __k, __code);
01497       if (!__prev_n)
01498     return 0;
01499       __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt);
01500       bool __is_bucket_begin = _M_buckets[__bkt] == __prev_n;
01501 
01502       // We found a matching node, start deallocation loop from it
01503       std::size_t __next_bkt = __bkt;
01504       __node_type* __next_n = __n;
01505       size_type __result = 0;
01506       __node_type* __saved_n = nullptr;
01507       do
01508     {
01509       __node_type* __p = __next_n;
01510       __next_n = __p->_M_next();
01511 
01512       // _GLIBCXX_RESOLVE_LIB_DEFECTS
01513       // 526. Is it undefined if a function in the standard changes
01514       // in parameters?
01515       if (std::__addressof(this->_M_extract()(__p->_M_v))
01516           != std::__addressof(__k))
01517         _M_deallocate_node(__p);
01518       else
01519         __saved_n = __p;
01520       --_M_element_count;
01521       ++__result;
01522       if (!__next_n)
01523         break;
01524       __next_bkt = _M_bucket_index(__next_n);
01525     }
01526       while (__next_bkt == __bkt && this->_M_equals(__k, __code, __next_n));
01527 
01528       if (__saved_n)
01529     _M_deallocate_node(__saved_n);
01530       if (__is_bucket_begin)
01531     _M_remove_bucket_begin(__bkt, __next_n, __next_bkt);
01532       else if (__next_n && __next_bkt != __bkt)
01533     _M_buckets[__next_bkt] = __prev_n;
01534       if (__prev_n)
01535     __prev_n->_M_nxt = __next_n;
01536       return __result;
01537     }
01538 
01539   template<typename _Key, typename _Value,
01540        typename _Alloc, typename _ExtractKey, typename _Equal,
01541        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01542        typename _Traits>
01543     typename _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01544             _H1, _H2, _Hash, _RehashPolicy,
01545             _Traits>::iterator
01546     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01547            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01548     erase(const_iterator __first, const_iterator __last)
01549     {
01550       __node_type* __n = __first._M_cur;
01551       __node_type* __last_n = __last._M_cur;
01552       if (__n == __last_n)
01553     return iterator(__n);
01554 
01555       std::size_t __bkt = _M_bucket_index(__n);
01556 
01557       __node_base* __prev_n = _M_get_previous_node(__bkt, __n);
01558       bool __is_bucket_begin = __n == _M_bucket_begin(__bkt);
01559       std::size_t __n_bkt = __bkt;
01560       for (;;)
01561     {
01562       do
01563         {
01564           __node_type* __tmp = __n;
01565           __n = __n->_M_next();
01566           _M_deallocate_node(__tmp);
01567           --_M_element_count;
01568           if (!__n)
01569         break;
01570           __n_bkt = _M_bucket_index(__n);
01571         }
01572       while (__n != __last_n && __n_bkt == __bkt);
01573       if (__is_bucket_begin)
01574         _M_remove_bucket_begin(__bkt, __n, __n_bkt);
01575       if (__n == __last_n)
01576         break;
01577       __is_bucket_begin = true;
01578       __bkt = __n_bkt;
01579     }
01580 
01581       if (__n && (__n_bkt != __bkt || __is_bucket_begin))
01582     _M_buckets[__n_bkt] = __prev_n;
01583       __prev_n->_M_nxt = __n;
01584       return iterator(__n);
01585     }
01586 
01587   template<typename _Key, typename _Value,
01588        typename _Alloc, typename _ExtractKey, typename _Equal,
01589        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01590        typename _Traits>
01591     void
01592     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01593            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01594     clear() noexcept
01595     {
01596       _M_deallocate_nodes(_M_begin());
01597       __builtin_memset(_M_buckets, 0, _M_bucket_count * sizeof(__bucket_type));
01598       _M_element_count = 0;
01599       _M_before_begin._M_nxt = nullptr;
01600     }
01601 
01602   template<typename _Key, typename _Value,
01603        typename _Alloc, typename _ExtractKey, typename _Equal,
01604        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01605        typename _Traits>
01606     void
01607     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01608            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01609     rehash(size_type __n)
01610     {
01611       const __rehash_state& __saved_state = _M_rehash_policy._M_state();
01612       _M_rehash(std::max(_M_rehash_policy._M_next_bkt(__n),
01613              _M_rehash_policy._M_bkt_for_elements(_M_element_count
01614                                   + 1)),
01615         __saved_state);
01616     }
01617 
01618   template<typename _Key, typename _Value,
01619        typename _Alloc, typename _ExtractKey, typename _Equal,
01620        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01621        typename _Traits>
01622     void
01623     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01624            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01625     _M_rehash(size_type __n, const __rehash_state& __state)
01626     {
01627       __try
01628     {
01629       _M_rehash_aux(__n, __unique_keys());
01630     }
01631       __catch(...)
01632     {
01633       // A failure here means that buckets allocation failed.  We only
01634       // have to restore hash policy previous state.
01635       _M_rehash_policy._M_reset(__state);
01636       __throw_exception_again;
01637     }
01638     }
01639 
01640   // Rehash when there is no equivalent elements.
01641   template<typename _Key, typename _Value,
01642        typename _Alloc, typename _ExtractKey, typename _Equal,
01643        typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
01644        typename _Traits>
01645     void
01646     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01647            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01648     _M_rehash_aux(size_type __n, std::true_type)
01649     {
01650       __bucket_type* __new_buckets = _M_allocate_buckets(__n);
01651       __node_type* __p = _M_begin();
01652       _M_before_begin._M_nxt = nullptr;
01653       std::size_t __bbegin_bkt;
01654       while (__p)
01655     {
01656       __node_type* __next = __p->_M_next();
01657       std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n);
01658       if (!__new_buckets[__bkt])
01659         {
01660           __p->_M_nxt = _M_before_begin._M_nxt;
01661           _M_before_begin._M_nxt = __p;
01662           __new_buckets[__bkt] = &_M_before_begin;
01663           if (__p->_M_nxt)
01664         __new_buckets[__bbegin_bkt] = __p;
01665           __bbegin_bkt = __bkt;
01666         }
01667       else
01668         {
01669           __p->_M_nxt = __new_buckets[__bkt]->_M_nxt;
01670           __new_buckets[__bkt]->_M_nxt = __p;
01671         }
01672       __p = __next;
01673     }
01674       _M_deallocate_buckets(_M_buckets, _M_bucket_count);
01675       _M_bucket_count = __n;
01676       _M_buckets = __new_buckets;
01677     }
01678 
01679   // Rehash when there can be equivalent elements, preserve their relative
01680   // order.
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     void
01686     _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
01687            _H1, _H2, _Hash, _RehashPolicy, _Traits>::
01688     _M_rehash_aux(size_type __n, std::false_type)
01689     {
01690       __bucket_type* __new_buckets = _M_allocate_buckets(__n);
01691 
01692       __node_type* __p = _M_begin();
01693       _M_before_begin._M_nxt = nullptr;
01694       std::size_t __bbegin_bkt;
01695       std::size_t __prev_bkt;
01696       __node_type* __prev_p = nullptr;
01697       bool __check_bucket = false;
01698 
01699       while (__p)
01700     {
01701       __node_type* __next = __p->_M_next();
01702       std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n);
01703 
01704       if (__prev_p && __prev_bkt == __bkt)
01705         {
01706           // Previous insert was already in this bucket, we insert after
01707           // the previously inserted one to preserve equivalent elements
01708           // relative order.
01709           __p->_M_nxt = __prev_p->_M_nxt;
01710           __prev_p->_M_nxt = __p;
01711 
01712           // Inserting after a node in a bucket require to check that we
01713           // haven't change the bucket last node, in this case next
01714           // bucket containing its before begin node must be updated. We
01715           // schedule a check as soon as we move out of the sequence of
01716           // equivalent nodes to limit the number of checks.
01717           __check_bucket = true;
01718         }
01719       else
01720         {
01721           if (__check_bucket)
01722         {
01723           // Check if we shall update the next bucket because of insertions
01724           // into __prev_bkt bucket.
01725           if (__prev_p->_M_nxt)
01726             {
01727               std::size_t __next_bkt
01728             = __hash_code_base::_M_bucket_index(__prev_p->_M_next(),
01729                                 __n);
01730               if (__next_bkt != __prev_bkt)
01731             __new_buckets[__next_bkt] = __prev_p;
01732             }
01733           __check_bucket = false;
01734         }
01735 
01736           if (!__new_buckets[__bkt])
01737         {
01738           __p->_M_nxt = _M_before_begin._M_nxt;
01739           _M_before_begin._M_nxt = __p;
01740           __new_buckets[__bkt] = &_M_before_begin;
01741           if (__p->_M_nxt)
01742             __new_buckets[__bbegin_bkt] = __p;
01743           __bbegin_bkt = __bkt;
01744         }
01745           else
01746         {
01747           __p->_M_nxt = __new_buckets[__bkt]->_M_nxt;
01748           __new_buckets[__bkt]->_M_nxt = __p;
01749         }
01750         }
01751       __prev_p = __p;
01752       __prev_bkt = __bkt;
01753       __p = __next;
01754     }
01755 
01756       if (__check_bucket && __prev_p->_M_nxt)
01757     {
01758       std::size_t __next_bkt
01759         = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), __n);
01760       if (__next_bkt != __prev_bkt)
01761         __new_buckets[__next_bkt] = __prev_p;
01762     }
01763 
01764       _M_deallocate_buckets(_M_buckets, _M_bucket_count);
01765       _M_bucket_count = __n;
01766       _M_buckets = __new_buckets;
01767     }
01768 
01769 _GLIBCXX_END_NAMESPACE_VERSION
01770 } // namespace std
01771 
01772 #endif // _HASHTABLE_H