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