Home | History | Annotate | Download | only in backward
      1 // Hashtable implementation used by containers -*- C++ -*-
      2 
      3 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
      4 // Free Software Foundation, Inc.
      5 //
      6 // This file is part of the GNU ISO C++ Library.  This library is free
      7 // software; you can redistribute it and/or modify it under the
      8 // terms of the GNU General Public License as published by the
      9 // Free Software Foundation; either version 3, or (at your option)
     10 // any later version.
     11 
     12 // This library is distributed in the hope that it will be useful,
     13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 // GNU General Public License for more details.
     16 
     17 // Under Section 7 of GPL version 3, you are granted additional
     18 // permissions described in the GCC Runtime Library Exception, version
     19 // 3.1, as published by the Free Software Foundation.
     20 
     21 // You should have received a copy of the GNU General Public License and
     22 // a copy of the GCC Runtime Library Exception along with this program;
     23 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24 // <http://www.gnu.org/licenses/>.
     25 
     26 /*
     27  * Copyright (c) 1996,1997
     28  * Silicon Graphics Computer Systems, Inc.
     29  *
     30  * Permission to use, copy, modify, distribute and sell this software
     31  * and its documentation for any purpose is hereby granted without fee,
     32  * provided that the above copyright notice appear in all copies and
     33  * that both that copyright notice and this permission notice appear
     34  * in supporting documentation.  Silicon Graphics makes no
     35  * representations about the suitability of this software for any
     36  * purpose.  It is provided "as is" without express or implied warranty.
     37  *
     38  *
     39  * Copyright (c) 1994
     40  * Hewlett-Packard Company
     41  *
     42  * Permission to use, copy, modify, distribute and sell this software
     43  * and its documentation for any purpose is hereby granted without fee,
     44  * provided that the above copyright notice appear in all copies and
     45  * that both that copyright notice and this permission notice appear
     46  * in supporting documentation.  Hewlett-Packard Company makes no
     47  * representations about the suitability of this software for any
     48  * purpose.  It is provided "as is" without express or implied warranty.
     49  *
     50  */
     51 
     52 /** @file backward/hashtable.h
     53  *  This file is a GNU extension to the Standard C++ Library (possibly
     54  *  containing extensions from the HP/SGI STL subset).
     55  */
     56 
     57 #ifndef _HASHTABLE_H
     58 #define _HASHTABLE_H 1
     59 
     60 // Hashtable class, used to implement the hashed associative containers
     61 // hash_set, hash_map, hash_multiset, and hash_multimap.
     62 
     63 #include <vector>
     64 #include <iterator>
     65 #include <algorithm>
     66 #include <bits/stl_function.h>
     67 #include <backward/hash_fun.h>
     68 
     69 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
     70 
     71   using std::size_t;
     72   using std::ptrdiff_t;
     73   using std::forward_iterator_tag;
     74   using std::input_iterator_tag;
     75   using std::_Construct;
     76   using std::_Destroy;
     77   using std::distance;
     78   using std::vector;
     79   using std::pair;
     80   using std::__iterator_category;
     81 
     82   template<class _Val>
     83     struct _Hashtable_node
     84     {
     85       _Hashtable_node* _M_next;
     86       _Val _M_val;
     87     };
     88 
     89   template<class _Val, class _Key, class _HashFcn, class _ExtractKey,
     90 	   class _EqualKey, class _Alloc = std::allocator<_Val> >
     91     class hashtable;
     92 
     93   template<class _Val, class _Key, class _HashFcn,
     94 	   class _ExtractKey, class _EqualKey, class _Alloc>
     95     struct _Hashtable_iterator;
     96 
     97   template<class _Val, class _Key, class _HashFcn,
     98 	   class _ExtractKey, class _EqualKey, class _Alloc>
     99     struct _Hashtable_const_iterator;
    100 
    101   template<class _Val, class _Key, class _HashFcn,
    102 	   class _ExtractKey, class _EqualKey, class _Alloc>
    103     struct _Hashtable_iterator
    104     {
    105       typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>
    106         _Hashtable;
    107       typedef _Hashtable_iterator<_Val, _Key, _HashFcn,
    108 				  _ExtractKey, _EqualKey, _Alloc>
    109         iterator;
    110       typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn,
    111 					_ExtractKey, _EqualKey, _Alloc>
    112         const_iterator;
    113       typedef _Hashtable_node<_Val> _Node;
    114       typedef forward_iterator_tag iterator_category;
    115       typedef _Val value_type;
    116       typedef ptrdiff_t difference_type;
    117       typedef size_t size_type;
    118       typedef _Val& reference;
    119       typedef _Val* pointer;
    120 
    121       _Node* _M_cur;
    122       _Hashtable* _M_ht;
    123 
    124       _Hashtable_iterator(_Node* __n, _Hashtable* __tab)
    125       : _M_cur(__n), _M_ht(__tab) { }
    126 
    127       _Hashtable_iterator() { }
    128 
    129       reference
    130       operator*() const
    131       { return _M_cur->_M_val; }
    132 
    133       pointer
    134       operator->() const
    135       { return &(operator*()); }
    136 
    137       iterator&
    138       operator++();
    139 
    140       iterator
    141       operator++(int);
    142 
    143       bool
    144       operator==(const iterator& __it) const
    145       { return _M_cur == __it._M_cur; }
    146 
    147       bool
    148       operator!=(const iterator& __it) const
    149       { return _M_cur != __it._M_cur; }
    150     };
    151 
    152   template<class _Val, class _Key, class _HashFcn,
    153 	   class _ExtractKey, class _EqualKey, class _Alloc>
    154     struct _Hashtable_const_iterator
    155     {
    156       typedef hashtable<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>
    157         _Hashtable;
    158       typedef _Hashtable_iterator<_Val,_Key,_HashFcn,
    159 				  _ExtractKey,_EqualKey,_Alloc>
    160         iterator;
    161       typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn,
    162 					_ExtractKey, _EqualKey, _Alloc>
    163         const_iterator;
    164       typedef _Hashtable_node<_Val> _Node;
    165 
    166       typedef forward_iterator_tag iterator_category;
    167       typedef _Val value_type;
    168       typedef ptrdiff_t difference_type;
    169       typedef size_t size_type;
    170       typedef const _Val& reference;
    171       typedef const _Val* pointer;
    172 
    173       const _Node* _M_cur;
    174       const _Hashtable* _M_ht;
    175 
    176       _Hashtable_const_iterator(const _Node* __n, const _Hashtable* __tab)
    177       : _M_cur(__n), _M_ht(__tab) { }
    178 
    179       _Hashtable_const_iterator() { }
    180 
    181       _Hashtable_const_iterator(const iterator& __it)
    182       : _M_cur(__it._M_cur), _M_ht(__it._M_ht) { }
    183 
    184       reference
    185       operator*() const
    186       { return _M_cur->_M_val; }
    187 
    188       pointer
    189       operator->() const
    190       { return &(operator*()); }
    191 
    192       const_iterator&
    193       operator++();
    194 
    195       const_iterator
    196       operator++(int);
    197 
    198       bool
    199       operator==(const const_iterator& __it) const
    200       { return _M_cur == __it._M_cur; }
    201 
    202       bool
    203       operator!=(const const_iterator& __it) const
    204       { return _M_cur != __it._M_cur; }
    205     };
    206 
    207   // Note: assumes long is at least 32 bits.
    208   enum { _S_num_primes = 29 };
    209 
    210   static const unsigned long __stl_prime_list[_S_num_primes] =
    211     {
    212       5ul,          53ul,         97ul,         193ul,       389ul,
    213       769ul,        1543ul,       3079ul,       6151ul,      12289ul,
    214       24593ul,      49157ul,      98317ul,      196613ul,    393241ul,
    215       786433ul,     1572869ul,    3145739ul,    6291469ul,   12582917ul,
    216       25165843ul,   50331653ul,   100663319ul,  201326611ul, 402653189ul,
    217       805306457ul,  1610612741ul, 3221225473ul, 4294967291ul
    218     };
    219 
    220   inline unsigned long
    221   __stl_next_prime(unsigned long __n)
    222   {
    223     const unsigned long* __first = __stl_prime_list;
    224     const unsigned long* __last = __stl_prime_list + (int)_S_num_primes;
    225     const unsigned long* pos = std::lower_bound(__first, __last, __n);
    226     return pos == __last ? *(__last - 1) : *pos;
    227   }
    228 
    229   // Forward declaration of operator==.
    230   template<class _Val, class _Key, class _HF, class _Ex,
    231 	   class _Eq, class _All>
    232     class hashtable;
    233 
    234   template<class _Val, class _Key, class _HF, class _Ex,
    235 	   class _Eq, class _All>
    236     bool
    237     operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1,
    238 	       const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2);
    239 
    240   // Hashtables handle allocators a bit differently than other
    241   // containers do.  If we're using standard-conforming allocators, then
    242   // a hashtable unconditionally has a member variable to hold its
    243   // allocator, even if it so happens that all instances of the
    244   // allocator type are identical.  This is because, for hashtables,
    245   // this extra storage is negligible.  Additionally, a base class
    246   // wouldn't serve any other purposes; it wouldn't, for example,
    247   // simplify the exception-handling code.
    248   template<class _Val, class _Key, class _HashFcn,
    249 	   class _ExtractKey, class _EqualKey, class _Alloc>
    250     class hashtable
    251     {
    252     public:
    253       typedef _Key key_type;
    254       typedef _Val value_type;
    255       typedef _HashFcn hasher;
    256       typedef _EqualKey key_equal;
    257 
    258       typedef size_t            size_type;
    259       typedef ptrdiff_t         difference_type;
    260       typedef value_type*       pointer;
    261       typedef const value_type* const_pointer;
    262       typedef value_type&       reference;
    263       typedef const value_type& const_reference;
    264 
    265       hasher
    266       hash_funct() const
    267       { return _M_hash; }
    268 
    269       key_equal
    270       key_eq() const
    271       { return _M_equals; }
    272 
    273     private:
    274       typedef _Hashtable_node<_Val> _Node;
    275 
    276     public:
    277       typedef typename _Alloc::template rebind<value_type>::other allocator_type;
    278       allocator_type
    279       get_allocator() const
    280       { return _M_node_allocator; }
    281 
    282     private:
    283       typedef typename _Alloc::template rebind<_Node>::other _Node_Alloc;
    284       typedef typename _Alloc::template rebind<_Node*>::other _Nodeptr_Alloc;
    285       typedef vector<_Node*, _Nodeptr_Alloc> _Vector_type;
    286 
    287       _Node_Alloc _M_node_allocator;
    288 
    289       _Node*
    290       _M_get_node()
    291       { return _M_node_allocator.allocate(1); }
    292 
    293       void
    294       _M_put_node(_Node* __p)
    295       { _M_node_allocator.deallocate(__p, 1); }
    296 
    297     private:
    298       hasher                _M_hash;
    299       key_equal             _M_equals;
    300       _ExtractKey           _M_get_key;
    301       _Vector_type          _M_buckets;
    302       size_type             _M_num_elements;
    303 
    304     public:
    305       typedef _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey,
    306 				  _EqualKey, _Alloc>
    307         iterator;
    308       typedef _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey,
    309 					_EqualKey, _Alloc>
    310         const_iterator;
    311 
    312       friend struct
    313       _Hashtable_iterator<_Val, _Key, _HashFcn, _ExtractKey, _EqualKey, _Alloc>;
    314 
    315       friend struct
    316       _Hashtable_const_iterator<_Val, _Key, _HashFcn, _ExtractKey,
    317 				_EqualKey, _Alloc>;
    318 
    319     public:
    320       hashtable(size_type __n, const _HashFcn& __hf,
    321 		const _EqualKey& __eql, const _ExtractKey& __ext,
    322 		const allocator_type& __a = allocator_type())
    323       : _M_node_allocator(__a), _M_hash(__hf), _M_equals(__eql),
    324 	_M_get_key(__ext), _M_buckets(__a), _M_num_elements(0)
    325       { _M_initialize_buckets(__n); }
    326 
    327       hashtable(size_type __n, const _HashFcn& __hf,
    328 		const _EqualKey& __eql,
    329 		const allocator_type& __a = allocator_type())
    330       : _M_node_allocator(__a), _M_hash(__hf), _M_equals(__eql),
    331 	_M_get_key(_ExtractKey()), _M_buckets(__a), _M_num_elements(0)
    332       { _M_initialize_buckets(__n); }
    333 
    334       hashtable(const hashtable& __ht)
    335       : _M_node_allocator(__ht.get_allocator()), _M_hash(__ht._M_hash),
    336       _M_equals(__ht._M_equals), _M_get_key(__ht._M_get_key),
    337       _M_buckets(__ht.get_allocator()), _M_num_elements(0)
    338       { _M_copy_from(__ht); }
    339 
    340       hashtable&
    341       operator= (const hashtable& __ht)
    342       {
    343 	if (&__ht != this)
    344 	  {
    345 	    clear();
    346 	    _M_hash = __ht._M_hash;
    347 	    _M_equals = __ht._M_equals;
    348 	    _M_get_key = __ht._M_get_key;
    349 	    _M_copy_from(__ht);
    350 	  }
    351 	return *this;
    352       }
    353 
    354       ~hashtable()
    355       { clear(); }
    356 
    357       size_type
    358       size() const
    359       { return _M_num_elements; }
    360 
    361       size_type
    362       max_size() const
    363       { return size_type(-1); }
    364 
    365       bool
    366       empty() const
    367       { return size() == 0; }
    368 
    369       void
    370       swap(hashtable& __ht)
    371       {
    372 	std::swap(_M_hash, __ht._M_hash);
    373 	std::swap(_M_equals, __ht._M_equals);
    374 	std::swap(_M_get_key, __ht._M_get_key);
    375 	_M_buckets.swap(__ht._M_buckets);
    376 	std::swap(_M_num_elements, __ht._M_num_elements);
    377       }
    378 
    379       iterator
    380       begin()
    381       {
    382 	for (size_type __n = 0; __n < _M_buckets.size(); ++__n)
    383 	  if (_M_buckets[__n])
    384 	    return iterator(_M_buckets[__n], this);
    385 	return end();
    386       }
    387 
    388       iterator
    389       end()
    390       { return iterator(0, this); }
    391 
    392       const_iterator
    393       begin() const
    394       {
    395 	for (size_type __n = 0; __n < _M_buckets.size(); ++__n)
    396 	  if (_M_buckets[__n])
    397 	    return const_iterator(_M_buckets[__n], this);
    398 	return end();
    399       }
    400 
    401       const_iterator
    402       end() const
    403       { return const_iterator(0, this); }
    404 
    405       template<class _Vl, class _Ky, class _HF, class _Ex, class _Eq,
    406 		class _Al>
    407         friend bool
    408         operator==(const hashtable<_Vl, _Ky, _HF, _Ex, _Eq, _Al>&,
    409 		   const hashtable<_Vl, _Ky, _HF, _Ex, _Eq, _Al>&);
    410 
    411     public:
    412       size_type
    413       bucket_count() const
    414       { return _M_buckets.size(); }
    415 
    416       size_type
    417       max_bucket_count() const
    418       { return __stl_prime_list[(int)_S_num_primes - 1]; }
    419 
    420       size_type
    421       elems_in_bucket(size_type __bucket) const
    422       {
    423 	size_type __result = 0;
    424 	for (_Node* __n = _M_buckets[__bucket]; __n; __n = __n->_M_next)
    425 	  __result += 1;
    426 	return __result;
    427       }
    428 
    429       pair<iterator, bool>
    430       insert_unique(const value_type& __obj)
    431       {
    432 	resize(_M_num_elements + 1);
    433 	return insert_unique_noresize(__obj);
    434       }
    435 
    436       iterator
    437       insert_equal(const value_type& __obj)
    438       {
    439 	resize(_M_num_elements + 1);
    440 	return insert_equal_noresize(__obj);
    441       }
    442 
    443       pair<iterator, bool>
    444       insert_unique_noresize(const value_type& __obj);
    445 
    446       iterator
    447       insert_equal_noresize(const value_type& __obj);
    448 
    449       template<class _InputIterator>
    450         void
    451         insert_unique(_InputIterator __f, _InputIterator __l)
    452         { insert_unique(__f, __l, __iterator_category(__f)); }
    453 
    454       template<class _InputIterator>
    455         void
    456         insert_equal(_InputIterator __f, _InputIterator __l)
    457         { insert_equal(__f, __l, __iterator_category(__f)); }
    458 
    459       template<class _InputIterator>
    460         void
    461         insert_unique(_InputIterator __f, _InputIterator __l,
    462 		      input_iterator_tag)
    463         {
    464 	  for ( ; __f != __l; ++__f)
    465 	    insert_unique(*__f);
    466 	}
    467 
    468       template<class _InputIterator>
    469         void
    470         insert_equal(_InputIterator __f, _InputIterator __l,
    471 		     input_iterator_tag)
    472         {
    473 	  for ( ; __f != __l; ++__f)
    474 	    insert_equal(*__f);
    475 	}
    476 
    477       template<class _ForwardIterator>
    478         void
    479         insert_unique(_ForwardIterator __f, _ForwardIterator __l,
    480 		      forward_iterator_tag)
    481         {
    482 	  size_type __n = distance(__f, __l);
    483 	  resize(_M_num_elements + __n);
    484 	  for ( ; __n > 0; --__n, ++__f)
    485 	    insert_unique_noresize(*__f);
    486 	}
    487 
    488       template<class _ForwardIterator>
    489         void
    490         insert_equal(_ForwardIterator __f, _ForwardIterator __l,
    491 		     forward_iterator_tag)
    492         {
    493 	  size_type __n = distance(__f, __l);
    494 	  resize(_M_num_elements + __n);
    495 	  for ( ; __n > 0; --__n, ++__f)
    496 	    insert_equal_noresize(*__f);
    497 	}
    498 
    499       reference
    500       find_or_insert(const value_type& __obj);
    501 
    502       iterator
    503       find(const key_type& __key)
    504       {
    505 	size_type __n = _M_bkt_num_key(__key);
    506 	_Node* __first;
    507 	for (__first = _M_buckets[__n];
    508 	     __first && !_M_equals(_M_get_key(__first->_M_val), __key);
    509 	     __first = __first->_M_next)
    510 	  { }
    511 	return iterator(__first, this);
    512       }
    513 
    514       const_iterator
    515       find(const key_type& __key) const
    516       {
    517 	size_type __n = _M_bkt_num_key(__key);
    518 	const _Node* __first;
    519 	for (__first = _M_buckets[__n];
    520 	     __first && !_M_equals(_M_get_key(__first->_M_val), __key);
    521 	     __first = __first->_M_next)
    522 	  { }
    523 	return const_iterator(__first, this);
    524       }
    525 
    526       size_type
    527       count(const key_type& __key) const
    528       {
    529 	const size_type __n = _M_bkt_num_key(__key);
    530 	size_type __result = 0;
    531 
    532 	for (const _Node* __cur = _M_buckets[__n]; __cur;
    533 	     __cur = __cur->_M_next)
    534 	  if (_M_equals(_M_get_key(__cur->_M_val), __key))
    535 	    ++__result;
    536 	return __result;
    537       }
    538 
    539       pair<iterator, iterator>
    540       equal_range(const key_type& __key);
    541 
    542       pair<const_iterator, const_iterator>
    543       equal_range(const key_type& __key) const;
    544 
    545       size_type
    546       erase(const key_type& __key);
    547 
    548       void
    549       erase(const iterator& __it);
    550 
    551       void
    552       erase(iterator __first, iterator __last);
    553 
    554       void
    555       erase(const const_iterator& __it);
    556 
    557       void
    558       erase(const_iterator __first, const_iterator __last);
    559 
    560       void
    561       resize(size_type __num_elements_hint);
    562 
    563       void
    564       clear();
    565 
    566     private:
    567       size_type
    568       _M_next_size(size_type __n) const
    569       { return __stl_next_prime(__n); }
    570 
    571       void
    572       _M_initialize_buckets(size_type __n)
    573       {
    574 	const size_type __n_buckets = _M_next_size(__n);
    575 	_M_buckets.reserve(__n_buckets);
    576 	_M_buckets.insert(_M_buckets.end(), __n_buckets, (_Node*) 0);
    577 	_M_num_elements = 0;
    578       }
    579 
    580       size_type
    581       _M_bkt_num_key(const key_type& __key) const
    582       { return _M_bkt_num_key(__key, _M_buckets.size()); }
    583 
    584       size_type
    585       _M_bkt_num(const value_type& __obj) const
    586       { return _M_bkt_num_key(_M_get_key(__obj)); }
    587 
    588       size_type
    589       _M_bkt_num_key(const key_type& __key, size_t __n) const
    590       { return _M_hash(__key) % __n; }
    591 
    592       size_type
    593       _M_bkt_num(const value_type& __obj, size_t __n) const
    594       { return _M_bkt_num_key(_M_get_key(__obj), __n); }
    595 
    596       _Node*
    597       _M_new_node(const value_type& __obj)
    598       {
    599 	_Node* __n = _M_get_node();
    600 	__n->_M_next = 0;
    601 	__try
    602 	  {
    603 	    this->get_allocator().construct(&__n->_M_val, __obj);
    604 	    return __n;
    605 	  }
    606 	__catch(...)
    607 	  {
    608 	    _M_put_node(__n);
    609 	    __throw_exception_again;
    610 	  }
    611       }
    612 
    613       void
    614       _M_delete_node(_Node* __n)
    615       {
    616 	this->get_allocator().destroy(&__n->_M_val);
    617 	_M_put_node(__n);
    618       }
    619 
    620       void
    621       _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last);
    622 
    623       void
    624       _M_erase_bucket(const size_type __n, _Node* __last);
    625 
    626       void
    627       _M_copy_from(const hashtable& __ht);
    628     };
    629 
    630   template<class _Val, class _Key, class _HF, class _ExK, class _EqK,
    631 	    class _All>
    632     _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>&
    633     _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::
    634     operator++()
    635     {
    636       const _Node* __old = _M_cur;
    637       _M_cur = _M_cur->_M_next;
    638       if (!_M_cur)
    639 	{
    640 	  size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
    641 	  while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
    642 	    _M_cur = _M_ht->_M_buckets[__bucket];
    643 	}
    644       return *this;
    645     }
    646 
    647   template<class _Val, class _Key, class _HF, class _ExK, class _EqK,
    648 	    class _All>
    649     inline _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>
    650     _Hashtable_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::
    651     operator++(int)
    652     {
    653       iterator __tmp = *this;
    654       ++*this;
    655       return __tmp;
    656     }
    657 
    658   template<class _Val, class _Key, class _HF, class _ExK, class _EqK,
    659 	    class _All>
    660     _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>&
    661     _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::
    662     operator++()
    663     {
    664       const _Node* __old = _M_cur;
    665       _M_cur = _M_cur->_M_next;
    666       if (!_M_cur)
    667 	{
    668 	  size_type __bucket = _M_ht->_M_bkt_num(__old->_M_val);
    669 	  while (!_M_cur && ++__bucket < _M_ht->_M_buckets.size())
    670 	    _M_cur = _M_ht->_M_buckets[__bucket];
    671 	}
    672       return *this;
    673     }
    674 
    675   template<class _Val, class _Key, class _HF, class _ExK, class _EqK,
    676 	    class _All>
    677     inline _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>
    678     _Hashtable_const_iterator<_Val, _Key, _HF, _ExK, _EqK, _All>::
    679     operator++(int)
    680     {
    681       const_iterator __tmp = *this;
    682       ++*this;
    683       return __tmp;
    684     }
    685 
    686   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    687     bool
    688     operator==(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1,
    689 	       const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2)
    690     {
    691       typedef typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::_Node _Node;
    692 
    693       if (__ht1._M_buckets.size() != __ht2._M_buckets.size())
    694 	return false;
    695 
    696       for (size_t __n = 0; __n < __ht1._M_buckets.size(); ++__n)
    697 	{
    698 	  _Node* __cur1 = __ht1._M_buckets[__n];
    699 	  _Node* __cur2 = __ht2._M_buckets[__n];
    700 	  // Check same length of lists
    701 	  for (; __cur1 && __cur2;
    702 	       __cur1 = __cur1->_M_next, __cur2 = __cur2->_M_next)
    703 	    { }
    704 	  if (__cur1 || __cur2)
    705 	    return false;
    706 	  // Now check one's elements are in the other
    707 	  for (__cur1 = __ht1._M_buckets[__n] ; __cur1;
    708 	       __cur1 = __cur1->_M_next)
    709 	    {
    710 	      bool _found__cur1 = false;
    711 	      for (__cur2 = __ht2._M_buckets[__n];
    712 		   __cur2; __cur2 = __cur2->_M_next)
    713 		{
    714 		  if (__cur1->_M_val == __cur2->_M_val)
    715 		    {
    716 		      _found__cur1 = true;
    717 		      break;
    718 		    }
    719 		}
    720 	      if (!_found__cur1)
    721 		return false;
    722 	    }
    723 	}
    724       return true;
    725     }
    726 
    727   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    728     inline bool
    729     operator!=(const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht1,
    730 	       const hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>& __ht2)
    731     { return !(__ht1 == __ht2); }
    732 
    733   template<class _Val, class _Key, class _HF, class _Extract, class _EqKey,
    734 	    class _All>
    735     inline void
    736     swap(hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht1,
    737 	 hashtable<_Val, _Key, _HF, _Extract, _EqKey, _All>& __ht2)
    738     { __ht1.swap(__ht2); }
    739 
    740   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    741     pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator, bool>
    742     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
    743     insert_unique_noresize(const value_type& __obj)
    744     {
    745       const size_type __n = _M_bkt_num(__obj);
    746       _Node* __first = _M_buckets[__n];
    747 
    748       for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
    749 	if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
    750 	  return pair<iterator, bool>(iterator(__cur, this), false);
    751 
    752       _Node* __tmp = _M_new_node(__obj);
    753       __tmp->_M_next = __first;
    754       _M_buckets[__n] = __tmp;
    755       ++_M_num_elements;
    756       return pair<iterator, bool>(iterator(__tmp, this), true);
    757     }
    758 
    759   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    760     typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator
    761     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
    762     insert_equal_noresize(const value_type& __obj)
    763     {
    764       const size_type __n = _M_bkt_num(__obj);
    765       _Node* __first = _M_buckets[__n];
    766 
    767       for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
    768 	if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
    769 	  {
    770 	    _Node* __tmp = _M_new_node(__obj);
    771 	    __tmp->_M_next = __cur->_M_next;
    772 	    __cur->_M_next = __tmp;
    773 	    ++_M_num_elements;
    774 	    return iterator(__tmp, this);
    775 	  }
    776 
    777       _Node* __tmp = _M_new_node(__obj);
    778       __tmp->_M_next = __first;
    779       _M_buckets[__n] = __tmp;
    780       ++_M_num_elements;
    781       return iterator(__tmp, this);
    782     }
    783 
    784   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    785     typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::reference
    786     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
    787     find_or_insert(const value_type& __obj)
    788     {
    789       resize(_M_num_elements + 1);
    790 
    791       size_type __n = _M_bkt_num(__obj);
    792       _Node* __first = _M_buckets[__n];
    793 
    794       for (_Node* __cur = __first; __cur; __cur = __cur->_M_next)
    795 	if (_M_equals(_M_get_key(__cur->_M_val), _M_get_key(__obj)))
    796 	  return __cur->_M_val;
    797 
    798       _Node* __tmp = _M_new_node(__obj);
    799       __tmp->_M_next = __first;
    800       _M_buckets[__n] = __tmp;
    801       ++_M_num_elements;
    802       return __tmp->_M_val;
    803     }
    804 
    805   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    806     pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator,
    807 	 typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::iterator>
    808     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
    809     equal_range(const key_type& __key)
    810     {
    811       typedef pair<iterator, iterator> _Pii;
    812       const size_type __n = _M_bkt_num_key(__key);
    813 
    814       for (_Node* __first = _M_buckets[__n]; __first;
    815 	   __first = __first->_M_next)
    816 	if (_M_equals(_M_get_key(__first->_M_val), __key))
    817 	  {
    818 	    for (_Node* __cur = __first->_M_next; __cur;
    819 		 __cur = __cur->_M_next)
    820 	      if (!_M_equals(_M_get_key(__cur->_M_val), __key))
    821 		return _Pii(iterator(__first, this), iterator(__cur, this));
    822 	    for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m)
    823 	      if (_M_buckets[__m])
    824 		return _Pii(iterator(__first, this),
    825 			    iterator(_M_buckets[__m], this));
    826 	    return _Pii(iterator(__first, this), end());
    827 	  }
    828       return _Pii(end(), end());
    829     }
    830 
    831   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    832     pair<typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator,
    833 	 typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::const_iterator>
    834     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
    835     equal_range(const key_type& __key) const
    836     {
    837       typedef pair<const_iterator, const_iterator> _Pii;
    838       const size_type __n = _M_bkt_num_key(__key);
    839 
    840       for (const _Node* __first = _M_buckets[__n]; __first;
    841 	   __first = __first->_M_next)
    842 	{
    843 	  if (_M_equals(_M_get_key(__first->_M_val), __key))
    844 	    {
    845 	      for (const _Node* __cur = __first->_M_next; __cur;
    846 		   __cur = __cur->_M_next)
    847 		if (!_M_equals(_M_get_key(__cur->_M_val), __key))
    848 		  return _Pii(const_iterator(__first, this),
    849 			      const_iterator(__cur, this));
    850 	      for (size_type __m = __n + 1; __m < _M_buckets.size(); ++__m)
    851 		if (_M_buckets[__m])
    852 		  return _Pii(const_iterator(__first, this),
    853 			      const_iterator(_M_buckets[__m], this));
    854 	      return _Pii(const_iterator(__first, this), end());
    855 	    }
    856 	}
    857       return _Pii(end(), end());
    858     }
    859 
    860   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    861     typename hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::size_type
    862     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
    863     erase(const key_type& __key)
    864     {
    865       const size_type __n = _M_bkt_num_key(__key);
    866       _Node* __first = _M_buckets[__n];
    867       _Node* __saved_slot = 0;
    868       size_type __erased = 0;
    869 
    870       if (__first)
    871 	{
    872 	  _Node* __cur = __first;
    873 	  _Node* __next = __cur->_M_next;
    874 	  while (__next)
    875 	    {
    876 	      if (_M_equals(_M_get_key(__next->_M_val), __key))
    877 		{
    878 		  if (&_M_get_key(__next->_M_val) != &__key)
    879 		    {
    880 		      __cur->_M_next = __next->_M_next;
    881 		      _M_delete_node(__next);
    882 		      __next = __cur->_M_next;
    883 		      ++__erased;
    884 		      --_M_num_elements;
    885 		    }
    886 		  else
    887 		    {
    888 		      __saved_slot = __cur;
    889 		      __cur = __next;
    890 		      __next = __cur->_M_next;
    891 		    }
    892 		}
    893 	      else
    894 		{
    895 		  __cur = __next;
    896 		  __next = __cur->_M_next;
    897 		}
    898 	    }
    899 	  if (_M_equals(_M_get_key(__first->_M_val), __key))
    900 	    {
    901 	      _M_buckets[__n] = __first->_M_next;
    902 	      _M_delete_node(__first);
    903 	      ++__erased;
    904 	      --_M_num_elements;
    905 	    }
    906 	  if (__saved_slot)
    907 	    {
    908 	      __next = __saved_slot->_M_next;
    909 	      __saved_slot->_M_next = __next->_M_next;
    910 	      _M_delete_node(__next);
    911 	      ++__erased;
    912 	      --_M_num_elements;
    913 	    }
    914 	}
    915       return __erased;
    916     }
    917 
    918   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    919     void hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
    920     erase(const iterator& __it)
    921     {
    922       _Node* __p = __it._M_cur;
    923       if (__p)
    924 	{
    925 	  const size_type __n = _M_bkt_num(__p->_M_val);
    926 	  _Node* __cur = _M_buckets[__n];
    927 
    928 	  if (__cur == __p)
    929 	    {
    930 	      _M_buckets[__n] = __cur->_M_next;
    931 	      _M_delete_node(__cur);
    932 	      --_M_num_elements;
    933 	    }
    934 	  else
    935 	    {
    936 	      _Node* __next = __cur->_M_next;
    937 	      while (__next)
    938 		{
    939 		  if (__next == __p)
    940 		    {
    941 		      __cur->_M_next = __next->_M_next;
    942 		      _M_delete_node(__next);
    943 		      --_M_num_elements;
    944 		      break;
    945 		    }
    946 		  else
    947 		    {
    948 		      __cur = __next;
    949 		      __next = __cur->_M_next;
    950 		    }
    951 		}
    952 	    }
    953 	}
    954     }
    955 
    956   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    957     void
    958     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
    959     erase(iterator __first, iterator __last)
    960     {
    961       size_type __f_bucket = __first._M_cur ? _M_bkt_num(__first._M_cur->_M_val)
    962 	                                    : _M_buckets.size();
    963 
    964       size_type __l_bucket = __last._M_cur ? _M_bkt_num(__last._M_cur->_M_val)
    965 	                                   : _M_buckets.size();
    966 
    967       if (__first._M_cur == __last._M_cur)
    968 	return;
    969       else if (__f_bucket == __l_bucket)
    970 	_M_erase_bucket(__f_bucket, __first._M_cur, __last._M_cur);
    971       else
    972 	{
    973 	  _M_erase_bucket(__f_bucket, __first._M_cur, 0);
    974 	  for (size_type __n = __f_bucket + 1; __n < __l_bucket; ++__n)
    975 	    _M_erase_bucket(__n, 0);
    976 	  if (__l_bucket != _M_buckets.size())
    977 	    _M_erase_bucket(__l_bucket, __last._M_cur);
    978 	}
    979     }
    980 
    981   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    982     inline void
    983     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
    984     erase(const_iterator __first, const_iterator __last)
    985     {
    986       erase(iterator(const_cast<_Node*>(__first._M_cur),
    987 		     const_cast<hashtable*>(__first._M_ht)),
    988 	    iterator(const_cast<_Node*>(__last._M_cur),
    989 		     const_cast<hashtable*>(__last._M_ht)));
    990     }
    991 
    992   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
    993     inline void
    994     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
    995     erase(const const_iterator& __it)
    996     { erase(iterator(const_cast<_Node*>(__it._M_cur),
    997 		     const_cast<hashtable*>(__it._M_ht))); }
    998 
    999   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
   1000     void
   1001     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
   1002     resize(size_type __num_elements_hint)
   1003     {
   1004       const size_type __old_n = _M_buckets.size();
   1005       if (__num_elements_hint > __old_n)
   1006 	{
   1007 	  const size_type __n = _M_next_size(__num_elements_hint);
   1008 	  if (__n > __old_n)
   1009 	    {
   1010 	      _Vector_type __tmp(__n, (_Node*)(0), _M_buckets.get_allocator());
   1011 	      __try
   1012 		{
   1013 		  for (size_type __bucket = 0; __bucket < __old_n; ++__bucket)
   1014 		    {
   1015 		      _Node* __first = _M_buckets[__bucket];
   1016 		      while (__first)
   1017 			{
   1018 			  size_type __new_bucket = _M_bkt_num(__first->_M_val,
   1019 							      __n);
   1020 			  _M_buckets[__bucket] = __first->_M_next;
   1021 			  __first->_M_next = __tmp[__new_bucket];
   1022 			  __tmp[__new_bucket] = __first;
   1023 			  __first = _M_buckets[__bucket];
   1024 			}
   1025 		    }
   1026 		  _M_buckets.swap(__tmp);
   1027 		}
   1028 	      __catch(...)
   1029 		{
   1030 		  for (size_type __bucket = 0; __bucket < __tmp.size();
   1031 		       ++__bucket)
   1032 		    {
   1033 		      while (__tmp[__bucket])
   1034 			{
   1035 			  _Node* __next = __tmp[__bucket]->_M_next;
   1036 			  _M_delete_node(__tmp[__bucket]);
   1037 			  __tmp[__bucket] = __next;
   1038 			}
   1039 		    }
   1040 		  __throw_exception_again;
   1041 		}
   1042 	    }
   1043 	}
   1044     }
   1045 
   1046   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
   1047     void
   1048     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
   1049     _M_erase_bucket(const size_type __n, _Node* __first, _Node* __last)
   1050     {
   1051       _Node* __cur = _M_buckets[__n];
   1052       if (__cur == __first)
   1053 	_M_erase_bucket(__n, __last);
   1054       else
   1055 	{
   1056 	  _Node* __next;
   1057 	  for (__next = __cur->_M_next;
   1058 	       __next != __first;
   1059 	       __cur = __next, __next = __cur->_M_next)
   1060 	    ;
   1061 	  while (__next != __last)
   1062 	    {
   1063 	      __cur->_M_next = __next->_M_next;
   1064 	      _M_delete_node(__next);
   1065 	      __next = __cur->_M_next;
   1066 	      --_M_num_elements;
   1067 	    }
   1068 	}
   1069     }
   1070 
   1071   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
   1072     void
   1073     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
   1074     _M_erase_bucket(const size_type __n, _Node* __last)
   1075     {
   1076       _Node* __cur = _M_buckets[__n];
   1077       while (__cur != __last)
   1078 	{
   1079 	  _Node* __next = __cur->_M_next;
   1080 	  _M_delete_node(__cur);
   1081 	  __cur = __next;
   1082 	  _M_buckets[__n] = __cur;
   1083 	  --_M_num_elements;
   1084 	}
   1085     }
   1086 
   1087   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
   1088     void
   1089     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
   1090     clear()
   1091     {
   1092       if (_M_num_elements == 0)
   1093 	return;
   1094 
   1095       for (size_type __i = 0; __i < _M_buckets.size(); ++__i)
   1096 	{
   1097 	  _Node* __cur = _M_buckets[__i];
   1098 	  while (__cur != 0)
   1099 	    {
   1100 	      _Node* __next = __cur->_M_next;
   1101 	      _M_delete_node(__cur);
   1102 	      __cur = __next;
   1103 	    }
   1104 	  _M_buckets[__i] = 0;
   1105 	}
   1106       _M_num_elements = 0;
   1107     }
   1108 
   1109   template<class _Val, class _Key, class _HF, class _Ex, class _Eq, class _All>
   1110     void
   1111     hashtable<_Val, _Key, _HF, _Ex, _Eq, _All>::
   1112     _M_copy_from(const hashtable& __ht)
   1113     {
   1114       _M_buckets.clear();
   1115       _M_buckets.reserve(__ht._M_buckets.size());
   1116       _M_buckets.insert(_M_buckets.end(), __ht._M_buckets.size(), (_Node*) 0);
   1117       __try
   1118 	{
   1119 	  for (size_type __i = 0; __i < __ht._M_buckets.size(); ++__i) {
   1120 	    const _Node* __cur = __ht._M_buckets[__i];
   1121 	    if (__cur)
   1122 	      {
   1123 		_Node* __local_copy = _M_new_node(__cur->_M_val);
   1124 		_M_buckets[__i] = __local_copy;
   1125 
   1126 		for (_Node* __next = __cur->_M_next;
   1127 		     __next;
   1128 		     __cur = __next, __next = __cur->_M_next)
   1129 		  {
   1130 		    __local_copy->_M_next = _M_new_node(__next->_M_val);
   1131 		    __local_copy = __local_copy->_M_next;
   1132 		  }
   1133 	      }
   1134 	  }
   1135 	  _M_num_elements = __ht._M_num_elements;
   1136 	}
   1137       __catch(...)
   1138 	{
   1139 	  clear();
   1140 	  __throw_exception_again;
   1141 	}
   1142     }
   1143 
   1144 _GLIBCXX_END_NAMESPACE
   1145 
   1146 #endif
   1147