hashtable_policy.h

Go to the documentation of this file.
00001 // Internal policy header for unordered_set and unordered_map -*- C++ -*-
00002 
00003 // Copyright (C) 2010 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 3, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // Under Section 7 of GPL version 3, you are granted additional
00017 // permissions described in the GCC Runtime Library Exception, version
00018 // 3.1, as published by the Free Software Foundation.
00019 
00020 // You should have received a copy of the GNU General Public License and
00021 // a copy of the GCC Runtime Library Exception along with this program;
00022 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023 // <http://www.gnu.org/licenses/>.
00024 
00025 /** @file bits/hashtable_policy.h
00026  *  This is an internal header file, included by other library headers.
00027  *  You should not attempt to use it directly.
00028  */
00029 
00030 #ifndef _HASHTABLE_POLICY_H
00031 #define _HASHTABLE_POLICY_H 1
00032 
00033 namespace std
00034 {
00035 namespace __detail
00036 {
00037   // Helper function: return distance(first, last) for forward
00038   // iterators, or 0 for input iterators.
00039   template<class _Iterator>
00040     inline typename std::iterator_traits<_Iterator>::difference_type
00041     __distance_fw(_Iterator __first, _Iterator __last,
00042           std::input_iterator_tag)
00043     { return 0; }
00044 
00045   template<class _Iterator>
00046     inline typename std::iterator_traits<_Iterator>::difference_type
00047     __distance_fw(_Iterator __first, _Iterator __last,
00048           std::forward_iterator_tag)
00049     { return std::distance(__first, __last); }
00050 
00051   template<class _Iterator>
00052     inline typename std::iterator_traits<_Iterator>::difference_type
00053     __distance_fw(_Iterator __first, _Iterator __last)
00054     {
00055       typedef typename std::iterator_traits<_Iterator>::iterator_category _Tag;
00056       return __distance_fw(__first, __last, _Tag());
00057     }
00058 
00059   template<typename _RAIter, typename _Tp>
00060     _RAIter
00061     __lower_bound(_RAIter __first, _RAIter __last, const _Tp& __val)
00062     {
00063       typedef typename std::iterator_traits<_RAIter>::difference_type _DType;
00064 
00065       _DType __len = __last - __first;
00066       while (__len > 0)
00067     {
00068       _DType __half = __len >> 1;
00069       _RAIter __middle = __first + __half;
00070       if (*__middle < __val)
00071         {
00072           __first = __middle;
00073           ++__first;
00074           __len = __len - __half - 1;
00075         }
00076       else
00077         __len = __half;
00078     }
00079       return __first;
00080     }
00081 
00082   // Auxiliary types used for all instantiations of _Hashtable: nodes
00083   // and iterators.
00084   
00085   // Nodes, used to wrap elements stored in the hash table.  A policy
00086   // template parameter of class template _Hashtable controls whether
00087   // nodes also store a hash code. In some cases (e.g. strings) this
00088   // may be a performance win.
00089   template<typename _Value, bool __cache_hash_code>
00090     struct _Hash_node;
00091 
00092   template<typename _Value>
00093     struct _Hash_node<_Value, true>
00094     {
00095       _Value       _M_v;
00096       std::size_t  _M_hash_code;
00097       _Hash_node*  _M_next;
00098 
00099       template<typename... _Args>
00100         _Hash_node(_Args&&... __args)
00101     : _M_v(std::forward<_Args>(__args)...),
00102       _M_hash_code(), _M_next() { }
00103     };
00104 
00105   template<typename _Value>
00106     struct _Hash_node<_Value, false>
00107     {
00108       _Value       _M_v;
00109       _Hash_node*  _M_next;
00110 
00111       template<typename... _Args>
00112         _Hash_node(_Args&&... __args)
00113     : _M_v(std::forward<_Args>(__args)...),
00114       _M_next() { }
00115     };
00116 
00117   // Local iterators, used to iterate within a bucket but not between
00118   // buckets.
00119   template<typename _Value, bool __cache>
00120     struct _Node_iterator_base
00121     {
00122       _Node_iterator_base(_Hash_node<_Value, __cache>* __p)
00123       : _M_cur(__p) { }
00124       
00125       void
00126       _M_incr()
00127       { _M_cur = _M_cur->_M_next; }
00128 
00129       _Hash_node<_Value, __cache>*  _M_cur;
00130     };
00131 
00132   template<typename _Value, bool __cache>
00133     inline bool
00134     operator==(const _Node_iterator_base<_Value, __cache>& __x,
00135            const _Node_iterator_base<_Value, __cache>& __y)
00136     { return __x._M_cur == __y._M_cur; }
00137 
00138   template<typename _Value, bool __cache>
00139     inline bool
00140     operator!=(const _Node_iterator_base<_Value, __cache>& __x,
00141            const _Node_iterator_base<_Value, __cache>& __y)
00142     { return __x._M_cur != __y._M_cur; }
00143 
00144   template<typename _Value, bool __constant_iterators, bool __cache>
00145     struct _Node_iterator
00146     : public _Node_iterator_base<_Value, __cache>
00147     {
00148       typedef _Value                                   value_type;
00149       typedef typename std::conditional<__constant_iterators,
00150                     const _Value*, _Value*>::type
00151                                                        pointer;
00152       typedef typename std::conditional<__constant_iterators,
00153                     const _Value&, _Value&>::type
00154                                                        reference;
00155       typedef std::ptrdiff_t                           difference_type;
00156       typedef std::forward_iterator_tag                iterator_category;
00157 
00158       _Node_iterator()
00159       : _Node_iterator_base<_Value, __cache>(0) { }
00160 
00161       explicit
00162       _Node_iterator(_Hash_node<_Value, __cache>* __p)
00163       : _Node_iterator_base<_Value, __cache>(__p) { }
00164 
00165       reference
00166       operator*() const
00167       { return this->_M_cur->_M_v; }
00168   
00169       pointer
00170       operator->() const
00171       { return &this->_M_cur->_M_v; }
00172 
00173       _Node_iterator&
00174       operator++()
00175       { 
00176     this->_M_incr();
00177     return *this; 
00178       }
00179   
00180       _Node_iterator
00181       operator++(int)
00182       { 
00183     _Node_iterator __tmp(*this);
00184     this->_M_incr();
00185     return __tmp;
00186       }
00187     };
00188 
00189   template<typename _Value, bool __constant_iterators, bool __cache>
00190     struct _Node_const_iterator
00191     : public _Node_iterator_base<_Value, __cache>
00192     {
00193       typedef _Value                                   value_type;
00194       typedef const _Value*                            pointer;
00195       typedef const _Value&                            reference;
00196       typedef std::ptrdiff_t                           difference_type;
00197       typedef std::forward_iterator_tag                iterator_category;
00198 
00199       _Node_const_iterator()
00200       : _Node_iterator_base<_Value, __cache>(0) { }
00201 
00202       explicit
00203       _Node_const_iterator(_Hash_node<_Value, __cache>* __p)
00204       : _Node_iterator_base<_Value, __cache>(__p) { }
00205 
00206       _Node_const_iterator(const _Node_iterator<_Value, __constant_iterators,
00207                __cache>& __x)
00208       : _Node_iterator_base<_Value, __cache>(__x._M_cur) { }
00209 
00210       reference
00211       operator*() const
00212       { return this->_M_cur->_M_v; }
00213   
00214       pointer
00215       operator->() const
00216       { return &this->_M_cur->_M_v; }
00217 
00218       _Node_const_iterator&
00219       operator++()
00220       { 
00221     this->_M_incr();
00222     return *this; 
00223       }
00224   
00225       _Node_const_iterator
00226       operator++(int)
00227       { 
00228     _Node_const_iterator __tmp(*this);
00229     this->_M_incr();
00230     return __tmp;
00231       }
00232     };
00233 
00234   template<typename _Value, bool __cache>
00235     struct _Hashtable_iterator_base
00236     {
00237       _Hashtable_iterator_base(_Hash_node<_Value, __cache>* __node,
00238                    _Hash_node<_Value, __cache>** __bucket)
00239       : _M_cur_node(__node), _M_cur_bucket(__bucket) { }
00240 
00241       void
00242       _M_incr()
00243       {
00244     _M_cur_node = _M_cur_node->_M_next;
00245     if (!_M_cur_node)
00246       _M_incr_bucket();
00247       }
00248 
00249       void
00250       _M_incr_bucket();
00251 
00252       _Hash_node<_Value, __cache>*   _M_cur_node;
00253       _Hash_node<_Value, __cache>**  _M_cur_bucket;
00254     };
00255 
00256   // Global iterators, used for arbitrary iteration within a hash
00257   // table.  Larger and more expensive than local iterators.
00258   template<typename _Value, bool __cache>
00259     void
00260     _Hashtable_iterator_base<_Value, __cache>::
00261     _M_incr_bucket()
00262     {
00263       ++_M_cur_bucket;
00264 
00265       // This loop requires the bucket array to have a non-null sentinel.
00266       while (!*_M_cur_bucket)
00267     ++_M_cur_bucket;
00268       _M_cur_node = *_M_cur_bucket;
00269     }
00270 
00271   template<typename _Value, bool __cache>
00272     inline bool
00273     operator==(const _Hashtable_iterator_base<_Value, __cache>& __x,
00274            const _Hashtable_iterator_base<_Value, __cache>& __y)
00275     { return __x._M_cur_node == __y._M_cur_node; }
00276 
00277   template<typename _Value, bool __cache>
00278     inline bool
00279     operator!=(const _Hashtable_iterator_base<_Value, __cache>& __x,
00280            const _Hashtable_iterator_base<_Value, __cache>& __y)
00281     { return __x._M_cur_node != __y._M_cur_node; }
00282 
00283   template<typename _Value, bool __constant_iterators, bool __cache>
00284     struct _Hashtable_iterator
00285     : public _Hashtable_iterator_base<_Value, __cache>
00286     {
00287       typedef _Value                                   value_type;
00288       typedef typename std::conditional<__constant_iterators,
00289                     const _Value*, _Value*>::type
00290                                                        pointer;
00291       typedef typename std::conditional<__constant_iterators,
00292                     const _Value&, _Value&>::type
00293                                                        reference;
00294       typedef std::ptrdiff_t                           difference_type;
00295       typedef std::forward_iterator_tag                iterator_category;
00296 
00297       _Hashtable_iterator()
00298       : _Hashtable_iterator_base<_Value, __cache>(0, 0) { }
00299 
00300       _Hashtable_iterator(_Hash_node<_Value, __cache>* __p,
00301               _Hash_node<_Value, __cache>** __b)
00302       : _Hashtable_iterator_base<_Value, __cache>(__p, __b) { }
00303 
00304       explicit
00305       _Hashtable_iterator(_Hash_node<_Value, __cache>** __b)
00306       : _Hashtable_iterator_base<_Value, __cache>(*__b, __b) { }
00307 
00308       reference
00309       operator*() const
00310       { return this->_M_cur_node->_M_v; }
00311   
00312       pointer
00313       operator->() const
00314       { return &this->_M_cur_node->_M_v; }
00315 
00316       _Hashtable_iterator&
00317       operator++()
00318       { 
00319     this->_M_incr();
00320     return *this;
00321       }
00322   
00323       _Hashtable_iterator
00324       operator++(int)
00325       { 
00326     _Hashtable_iterator __tmp(*this);
00327     this->_M_incr();
00328     return __tmp;
00329       }
00330     };
00331 
00332   template<typename _Value, bool __constant_iterators, bool __cache>
00333     struct _Hashtable_const_iterator
00334     : public _Hashtable_iterator_base<_Value, __cache>
00335     {
00336       typedef _Value                                   value_type;
00337       typedef const _Value*                            pointer;
00338       typedef const _Value&                            reference;
00339       typedef std::ptrdiff_t                           difference_type;
00340       typedef std::forward_iterator_tag                iterator_category;
00341 
00342       _Hashtable_const_iterator()
00343       : _Hashtable_iterator_base<_Value, __cache>(0, 0) { }
00344 
00345       _Hashtable_const_iterator(_Hash_node<_Value, __cache>* __p,
00346                 _Hash_node<_Value, __cache>** __b)
00347       : _Hashtable_iterator_base<_Value, __cache>(__p, __b) { }
00348 
00349       explicit
00350       _Hashtable_const_iterator(_Hash_node<_Value, __cache>** __b)
00351       : _Hashtable_iterator_base<_Value, __cache>(*__b, __b) { }
00352 
00353       _Hashtable_const_iterator(const _Hashtable_iterator<_Value,
00354                 __constant_iterators, __cache>& __x)
00355       : _Hashtable_iterator_base<_Value, __cache>(__x._M_cur_node,
00356                           __x._M_cur_bucket) { }
00357 
00358       reference
00359       operator*() const
00360       { return this->_M_cur_node->_M_v; }
00361   
00362       pointer
00363       operator->() const
00364       { return &this->_M_cur_node->_M_v; }
00365 
00366       _Hashtable_const_iterator&
00367       operator++()
00368       { 
00369     this->_M_incr();
00370     return *this;
00371       }
00372   
00373       _Hashtable_const_iterator
00374       operator++(int)
00375       { 
00376     _Hashtable_const_iterator __tmp(*this);
00377     this->_M_incr();
00378     return __tmp;
00379       }
00380     };
00381 
00382 
00383   // Many of class template _Hashtable's template parameters are policy
00384   // classes.  These are defaults for the policies.
00385 
00386   // Default range hashing function: use division to fold a large number
00387   // into the range [0, N).
00388   struct _Mod_range_hashing
00389   {
00390     typedef std::size_t first_argument_type;
00391     typedef std::size_t second_argument_type;
00392     typedef std::size_t result_type;
00393 
00394     result_type
00395     operator()(first_argument_type __num, second_argument_type __den) const
00396     { return __num % __den; }
00397   };
00398 
00399   // Default ranged hash function H.  In principle it should be a
00400   // function object composed from objects of type H1 and H2 such that
00401   // h(k, N) = h2(h1(k), N), but that would mean making extra copies of
00402   // h1 and h2.  So instead we'll just use a tag to tell class template
00403   // hashtable to do that composition.
00404   struct _Default_ranged_hash { };
00405 
00406   // Default value for rehash policy.  Bucket size is (usually) the
00407   // smallest prime that keeps the load factor small enough.
00408   struct _Prime_rehash_policy
00409   {
00410     _Prime_rehash_policy(float __z = 1.0)
00411     : _M_max_load_factor(__z), _M_growth_factor(2.f), _M_next_resize(0) { }
00412 
00413     float
00414     max_load_factor() const
00415     { return _M_max_load_factor; }      
00416 
00417     // Return a bucket size no smaller than n.
00418     std::size_t
00419     _M_next_bkt(std::size_t __n) const;
00420     
00421     // Return a bucket count appropriate for n elements
00422     std::size_t
00423     _M_bkt_for_elements(std::size_t __n) const;
00424     
00425     // __n_bkt is current bucket count, __n_elt is current element count,
00426     // and __n_ins is number of elements to be inserted.  Do we need to
00427     // increase bucket count?  If so, return make_pair(true, n), where n
00428     // is the new bucket count.  If not, return make_pair(false, 0).
00429     std::pair<bool, std::size_t>
00430     _M_need_rehash(std::size_t __n_bkt, std::size_t __n_elt,
00431            std::size_t __n_ins) const;
00432 
00433     enum { _S_n_primes = sizeof(unsigned long) != 8 ? 256 : 256 + 48 };
00434 
00435     float                _M_max_load_factor;
00436     float                _M_growth_factor;
00437     mutable std::size_t  _M_next_resize;
00438   };
00439 
00440   extern const unsigned long __prime_list[];
00441 
00442   // XXX This is a hack.  There's no good reason for any of
00443   // _Prime_rehash_policy's member functions to be inline.  
00444 
00445   // Return a prime no smaller than n.
00446   inline std::size_t
00447   _Prime_rehash_policy::
00448   _M_next_bkt(std::size_t __n) const
00449   {
00450     const unsigned long* __p = __lower_bound(__prime_list, __prime_list
00451                          + _S_n_primes, __n);
00452     _M_next_resize = 
00453       static_cast<std::size_t>(__builtin_ceil(*__p * _M_max_load_factor));
00454     return *__p;
00455   }
00456 
00457   // Return the smallest prime p such that alpha p >= n, where alpha
00458   // is the load factor.
00459   inline std::size_t
00460   _Prime_rehash_policy::
00461   _M_bkt_for_elements(std::size_t __n) const
00462   {
00463     const float __min_bkts = __n / _M_max_load_factor;
00464     const unsigned long* __p = __lower_bound(__prime_list, __prime_list
00465                          + _S_n_primes, __min_bkts);
00466     _M_next_resize =
00467       static_cast<std::size_t>(__builtin_ceil(*__p * _M_max_load_factor));
00468     return *__p;
00469   }
00470 
00471   // Finds the smallest prime p such that alpha p > __n_elt + __n_ins.
00472   // If p > __n_bkt, return make_pair(true, p); otherwise return
00473   // make_pair(false, 0).  In principle this isn't very different from 
00474   // _M_bkt_for_elements.
00475 
00476   // The only tricky part is that we're caching the element count at
00477   // which we need to rehash, so we don't have to do a floating-point
00478   // multiply for every insertion.
00479 
00480   inline std::pair<bool, std::size_t>
00481   _Prime_rehash_policy::
00482   _M_need_rehash(std::size_t __n_bkt, std::size_t __n_elt,
00483          std::size_t __n_ins) const
00484   {
00485     if (__n_elt + __n_ins > _M_next_resize)
00486       {
00487     float __min_bkts = ((float(__n_ins) + float(__n_elt))
00488                 / _M_max_load_factor);
00489     if (__min_bkts > __n_bkt)
00490       {
00491         __min_bkts = std::max(__min_bkts, _M_growth_factor * __n_bkt);
00492         const unsigned long* __p =
00493           __lower_bound(__prime_list, __prime_list + _S_n_primes,
00494                 __min_bkts);
00495         _M_next_resize = static_cast<std::size_t>
00496           (__builtin_ceil(*__p * _M_max_load_factor));
00497         return std::make_pair(true, *__p);
00498       }
00499     else 
00500       {
00501         _M_next_resize = static_cast<std::size_t>
00502           (__builtin_ceil(__n_bkt * _M_max_load_factor));
00503         return std::make_pair(false, 0);
00504       }
00505       }
00506     else
00507       return std::make_pair(false, 0);
00508   }
00509 
00510   // Base classes for std::tr1::_Hashtable.  We define these base
00511   // classes because in some cases we want to do different things
00512   // depending on the value of a policy class.  In some cases the
00513   // policy class affects which member functions and nested typedefs
00514   // are defined; we handle that by specializing base class templates.
00515   // Several of the base class templates need to access other members
00516   // of class template _Hashtable, so we use the "curiously recurring
00517   // template pattern" for them.
00518 
00519   // class template _Map_base.  If the hashtable has a value type of the
00520   // form pair<T1, T2> and a key extraction policy that returns the
00521   // first part of the pair, the hashtable gets a mapped_type typedef.
00522   // If it satisfies those criteria and also has unique keys, then it
00523   // also gets an operator[].  
00524   template<typename _Key, typename _Value, typename _Ex, bool __unique,
00525        typename _Hashtable>
00526     struct _Map_base { };
00527       
00528   template<typename _Key, typename _Pair, typename _Hashtable>
00529     struct _Map_base<_Key, _Pair, std::_Select1st<_Pair>, false, _Hashtable>
00530     {
00531       typedef typename _Pair::second_type mapped_type;
00532     };
00533 
00534   template<typename _Key, typename _Pair, typename _Hashtable>
00535     struct _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>
00536     {
00537       typedef typename _Pair::second_type mapped_type;
00538       
00539       mapped_type&
00540       operator[](const _Key& __k);
00541 
00542       // _GLIBCXX_RESOLVE_LIB_DEFECTS
00543       // DR 761. unordered_map needs an at() member function.
00544       mapped_type&
00545       at(const _Key& __k);
00546 
00547       const mapped_type&
00548       at(const _Key& __k) const;
00549     };
00550 
00551   template<typename _Key, typename _Pair, typename _Hashtable>
00552     typename _Map_base<_Key, _Pair, std::_Select1st<_Pair>,
00553                true, _Hashtable>::mapped_type&
00554     _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::
00555     operator[](const _Key& __k)
00556     {
00557       _Hashtable* __h = static_cast<_Hashtable*>(this);
00558       typename _Hashtable::_Hash_code_type __code = __h->_M_hash_code(__k);
00559       std::size_t __n = __h->_M_bucket_index(__k, __code,
00560                          __h->_M_bucket_count);
00561 
00562       typename _Hashtable::_Node* __p =
00563     __h->_M_find_node(__h->_M_buckets[__n], __k, __code);
00564       if (!__p)
00565     return __h->_M_insert_bucket(std::make_pair(__k, mapped_type()),
00566                      __n, __code)->second;
00567       return (__p->_M_v).second;
00568     }
00569 
00570   template<typename _Key, typename _Pair, typename _Hashtable>
00571     typename _Map_base<_Key, _Pair, std::_Select1st<_Pair>,
00572                true, _Hashtable>::mapped_type&
00573     _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::
00574     at(const _Key& __k)
00575     {
00576       _Hashtable* __h = static_cast<_Hashtable*>(this);
00577       typename _Hashtable::_Hash_code_type __code = __h->_M_hash_code(__k);
00578       std::size_t __n = __h->_M_bucket_index(__k, __code,
00579                          __h->_M_bucket_count);
00580 
00581       typename _Hashtable::_Node* __p =
00582     __h->_M_find_node(__h->_M_buckets[__n], __k, __code);
00583       if (!__p)
00584     __throw_out_of_range(__N("_Map_base::at"));
00585       return (__p->_M_v).second;
00586     }
00587 
00588   template<typename _Key, typename _Pair, typename _Hashtable>
00589     const typename _Map_base<_Key, _Pair, std::_Select1st<_Pair>,
00590                  true, _Hashtable>::mapped_type&
00591     _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>::
00592     at(const _Key& __k) const
00593     {
00594       const _Hashtable* __h = static_cast<const _Hashtable*>(this);
00595       typename _Hashtable::_Hash_code_type __code = __h->_M_hash_code(__k);
00596       std::size_t __n = __h->_M_bucket_index(__k, __code,
00597                          __h->_M_bucket_count);
00598 
00599       typename _Hashtable::_Node* __p =
00600     __h->_M_find_node(__h->_M_buckets[__n], __k, __code);
00601       if (!__p)
00602     __throw_out_of_range(__N("_Map_base::at"));
00603       return (__p->_M_v).second;
00604     }
00605 
00606   // class template _Rehash_base.  Give hashtable the max_load_factor
00607   // functions and reserve iff the rehash policy is _Prime_rehash_policy.
00608   template<typename _RehashPolicy, typename _Hashtable>
00609     struct _Rehash_base { };
00610 
00611   template<typename _Hashtable>
00612     struct _Rehash_base<_Prime_rehash_policy, _Hashtable>
00613     {
00614       float
00615       max_load_factor() const
00616       {
00617     const _Hashtable* __this = static_cast<const _Hashtable*>(this);
00618     return __this->__rehash_policy().max_load_factor();
00619       }
00620 
00621       void
00622       max_load_factor(float __z)
00623       {
00624     _Hashtable* __this = static_cast<_Hashtable*>(this);
00625     __this->__rehash_policy(_Prime_rehash_policy(__z));
00626       }
00627 
00628       void
00629       reserve(std::size_t __n)
00630       {
00631     _Hashtable* __this = static_cast<_Hashtable*>(this);
00632     __this->rehash(__builtin_ceil(__n / max_load_factor()));
00633       }
00634     };
00635 
00636   // Class template _Hash_code_base.  Encapsulates two policy issues that
00637   // aren't quite orthogonal.
00638   //   (1) the difference between using a ranged hash function and using
00639   //       the combination of a hash function and a range-hashing function.
00640   //       In the former case we don't have such things as hash codes, so
00641   //       we have a dummy type as placeholder.
00642   //   (2) Whether or not we cache hash codes.  Caching hash codes is
00643   //       meaningless if we have a ranged hash function.
00644   // We also put the key extraction and equality comparison function 
00645   // objects here, for convenience.
00646   
00647   // Primary template: unused except as a hook for specializations.  
00648   template<typename _Key, typename _Value,
00649        typename _ExtractKey, typename _Equal,
00650        typename _H1, typename _H2, typename _Hash,
00651        bool __cache_hash_code>
00652     struct _Hash_code_base;
00653 
00654   // Specialization: ranged hash function, no caching hash codes.  H1
00655   // and H2 are provided but ignored.  We define a dummy hash code type.
00656   template<typename _Key, typename _Value,
00657        typename _ExtractKey, typename _Equal,
00658        typename _H1, typename _H2, typename _Hash>
00659     struct _Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2,
00660                _Hash, false>
00661     {
00662     protected:
00663       _Hash_code_base(const _ExtractKey& __ex, const _Equal& __eq,
00664               const _H1&, const _H2&, const _Hash& __h)
00665       : _M_extract(__ex), _M_eq(__eq), _M_ranged_hash(__h) { }
00666 
00667       typedef void* _Hash_code_type;
00668   
00669       _Hash_code_type
00670       _M_hash_code(const _Key& __key) const
00671       { return 0; }
00672   
00673       std::size_t
00674       _M_bucket_index(const _Key& __k, _Hash_code_type,
00675               std::size_t __n) const
00676       { return _M_ranged_hash(__k, __n); }
00677 
00678       std::size_t
00679       _M_bucket_index(const _Hash_node<_Value, false>* __p,
00680               std::size_t __n) const
00681       { return _M_ranged_hash(_M_extract(__p->_M_v), __n); }
00682   
00683       bool
00684       _M_compare(const _Key& __k, _Hash_code_type,
00685          _Hash_node<_Value, false>* __n) const
00686       { return _M_eq(__k, _M_extract(__n->_M_v)); }
00687 
00688       void
00689       _M_store_code(_Hash_node<_Value, false>*, _Hash_code_type) const
00690       { }
00691 
00692       void
00693       _M_copy_code(_Hash_node<_Value, false>*,
00694            const _Hash_node<_Value, false>*) const
00695       { }
00696       
00697       void
00698       _M_swap(_Hash_code_base& __x)
00699       {
00700     std::swap(_M_extract, __x._M_extract);
00701     std::swap(_M_eq, __x._M_eq);
00702     std::swap(_M_ranged_hash, __x._M_ranged_hash);
00703       }
00704 
00705     protected:
00706       _ExtractKey  _M_extract;
00707       _Equal       _M_eq;
00708       _Hash        _M_ranged_hash;
00709     };
00710 
00711 
00712   // No specialization for ranged hash function while caching hash codes.
00713   // That combination is meaningless, and trying to do it is an error.
00714   
00715   
00716   // Specialization: ranged hash function, cache hash codes.  This
00717   // combination is meaningless, so we provide only a declaration
00718   // and no definition.  
00719   template<typename _Key, typename _Value,
00720        typename _ExtractKey, typename _Equal,
00721        typename _H1, typename _H2, typename _Hash>
00722     struct _Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2,
00723                _Hash, true>;
00724 
00725   // Specialization: hash function and range-hashing function, no
00726   // caching of hash codes.  H is provided but ignored.  Provides
00727   // typedef and accessor required by TR1.  
00728   template<typename _Key, typename _Value,
00729        typename _ExtractKey, typename _Equal,
00730        typename _H1, typename _H2>
00731     struct _Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2,
00732                _Default_ranged_hash, false>
00733     {
00734       typedef _H1 hasher;
00735 
00736       hasher
00737       hash_function() const
00738       { return _M_h1; }
00739 
00740     protected:
00741       _Hash_code_base(const _ExtractKey& __ex, const _Equal& __eq,
00742               const _H1& __h1, const _H2& __h2,
00743               const _Default_ranged_hash&)
00744       : _M_extract(__ex), _M_eq(__eq), _M_h1(__h1), _M_h2(__h2) { }
00745 
00746       typedef std::size_t _Hash_code_type;
00747 
00748       _Hash_code_type
00749       _M_hash_code(const _Key& __k) const
00750       { return _M_h1(__k); }
00751       
00752       std::size_t
00753       _M_bucket_index(const _Key&, _Hash_code_type __c,
00754               std::size_t __n) const
00755       { return _M_h2(__c, __n); }
00756 
00757       std::size_t
00758       _M_bucket_index(const _Hash_node<_Value, false>* __p,
00759               std::size_t __n) const
00760       { return _M_h2(_M_h1(_M_extract(__p->_M_v)), __n); }
00761 
00762       bool
00763       _M_compare(const _Key& __k, _Hash_code_type,
00764          _Hash_node<_Value, false>* __n) const
00765       { return _M_eq(__k, _M_extract(__n->_M_v)); }
00766 
00767       void
00768       _M_store_code(_Hash_node<_Value, false>*, _Hash_code_type) const
00769       { }
00770 
00771       void
00772       _M_copy_code(_Hash_node<_Value, false>*,
00773            const _Hash_node<_Value, false>*) const
00774       { }
00775 
00776       void
00777       _M_swap(_Hash_code_base& __x)
00778       {
00779     std::swap(_M_extract, __x._M_extract);
00780     std::swap(_M_eq, __x._M_eq);
00781     std::swap(_M_h1, __x._M_h1);
00782     std::swap(_M_h2, __x._M_h2);
00783       }
00784 
00785     protected:
00786       _ExtractKey  _M_extract;
00787       _Equal       _M_eq;
00788       _H1          _M_h1;
00789       _H2          _M_h2;
00790     };
00791 
00792   // Specialization: hash function and range-hashing function, 
00793   // caching hash codes.  H is provided but ignored.  Provides
00794   // typedef and accessor required by TR1.
00795   template<typename _Key, typename _Value,
00796        typename _ExtractKey, typename _Equal,
00797        typename _H1, typename _H2>
00798     struct _Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2,
00799                _Default_ranged_hash, true>
00800     {
00801       typedef _H1 hasher;
00802       
00803       hasher
00804       hash_function() const
00805       { return _M_h1; }
00806 
00807     protected:
00808       _Hash_code_base(const _ExtractKey& __ex, const _Equal& __eq,
00809               const _H1& __h1, const _H2& __h2,
00810               const _Default_ranged_hash&)
00811       : _M_extract(__ex), _M_eq(__eq), _M_h1(__h1), _M_h2(__h2) { }
00812 
00813       typedef std::size_t _Hash_code_type;
00814   
00815       _Hash_code_type
00816       _M_hash_code(const _Key& __k) const
00817       { return _M_h1(__k); }
00818   
00819       std::size_t
00820       _M_bucket_index(const _Key&, _Hash_code_type __c,
00821               std::size_t __n) const
00822       { return _M_h2(__c, __n); }
00823 
00824       std::size_t
00825       _M_bucket_index(const _Hash_node<_Value, true>* __p,
00826               std::size_t __n) const
00827       { return _M_h2(__p->_M_hash_code, __n); }
00828 
00829       bool
00830       _M_compare(const _Key& __k, _Hash_code_type __c,
00831          _Hash_node<_Value, true>* __n) const
00832       { return __c == __n->_M_hash_code && _M_eq(__k, _M_extract(__n->_M_v)); }
00833 
00834       void
00835       _M_store_code(_Hash_node<_Value, true>* __n, _Hash_code_type __c) const
00836       { __n->_M_hash_code = __c; }
00837 
00838       void
00839       _M_copy_code(_Hash_node<_Value, true>* __to,
00840            const _Hash_node<_Value, true>* __from) const
00841       { __to->_M_hash_code = __from->_M_hash_code; }
00842 
00843       void
00844       _M_swap(_Hash_code_base& __x)
00845       {
00846     std::swap(_M_extract, __x._M_extract);
00847     std::swap(_M_eq, __x._M_eq);
00848     std::swap(_M_h1, __x._M_h1);
00849     std::swap(_M_h2, __x._M_h2);
00850       }
00851       
00852     protected:
00853       _ExtractKey  _M_extract;
00854       _Equal       _M_eq;
00855       _H1          _M_h1;
00856       _H2          _M_h2;
00857     };
00858 } // namespace __detail
00859 }
00860 
00861 #endif // _HASHTABLE_POLICY_H

Generated on 12 Mar 2010 for libstdc++ by  doxygen 1.6.1