/home/ntakagi/work/STLport-5.1.5/stlport/stl/_hashtable.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1994
00003  * Hewlett-Packard Company
00004  *
00005  * Copyright (c) 1996,1997
00006  * Silicon Graphics Computer Systems, Inc.
00007  *
00008  * Copyright (c) 1997
00009  * Moscow Center for SPARC Technology
00010  *
00011  * Copyright (c) 1999
00012  * Boris Fomitchev
00013  *
00014  * This material is provided "as is", with absolutely no warranty expressed
00015  * or implied. Any use is at your own risk.
00016  *
00017  * Permission to use or copy this software for any purpose is hereby granted
00018  * without fee, provided the above notices are retained on all copies.
00019  * Permission to modify the code and to distribute modified code is granted,
00020  * provided the above notices are retained, and a notice that the code was
00021  * modified is included with the above copyright notice.
00022  *
00023  */
00024 #ifndef _STLP_HASHTABLE_C
00025 #define _STLP_HASHTABLE_C
00026 
00027 #ifndef _STLP_INTERNAL_HASHTABLE_H
00028 #  include <stl/_hashtable.h>
00029 #endif
00030 
00031 _STLP_BEGIN_NAMESPACE
00032 
00033 #if defined (_STLP_EXPOSE_GLOBALS_IMPLEMENTATION)
00034 
00035 _STLP_MOVE_TO_PRIV_NAMESPACE
00036 
00037 #  define __PRIME_LIST_BODY { \
00038   7ul,          23ul, \
00039   53ul,         97ul,         193ul,       389ul,       769ul,      \
00040   1543ul,       3079ul,       6151ul,      12289ul,     24593ul,    \
00041   49157ul,      98317ul,      196613ul,    393241ul,    786433ul,   \
00042   1572869ul,    3145739ul,    6291469ul,   12582917ul,  25165843ul, \
00043   50331653ul,   100663319ul,  201326611ul, 402653189ul, 805306457ul,\
00044   1610612741ul, 3221225473ul, 4294967291ul  \
00045 }
00046 
00047 template <class _Dummy>
00048 size_t _STLP_CALL
00049 _Stl_prime<_Dummy>::_S_max_nb_buckets() {
00050   const size_t _list[] = __PRIME_LIST_BODY;
00051 #  ifndef __MWERKS__
00052   return _list[(sizeof(_list)/sizeof(_list[0])) - 1];
00053 #  else
00054   return _list[30/sizeof(size_t) - 1]; // stupid MWERKS!
00055 #  endif
00056 }
00057 
00058 template <class _Dummy>
00059 size_t _STLP_CALL
00060 _Stl_prime<_Dummy>::_S_next_size(size_t __n) {
00061   static const size_t _list[] = __PRIME_LIST_BODY;
00062   const size_t* __first = _list;
00063 #  ifndef __MWERKS__
00064   const size_t* __last =  _list + (sizeof(_list)/sizeof(_list[0]));
00065 #  else
00066   const size_t* __last =  _list + (30/sizeof(size_t)); // stupid MWERKS
00067 #  endif
00068   const size_t* pos = __lower_bound(__first, __last, __n, 
00069                                     __less((size_t*)0), __less((size_t*)0), (ptrdiff_t*)0);
00070   return (pos == __last ? *(__last - 1) : *pos);
00071 }
00072 
00073 #  undef __PRIME_LIST_BODY
00074 
00075 _STLP_MOVE_TO_STD_NAMESPACE
00076 
00077 #endif
00078 
00079 #if defined (_STLP_DEBUG)
00080 #  define hashtable _STLP_NON_DBG_NAME(hashtable)
00081 _STLP_MOVE_TO_PRIV_NAMESPACE
00082 #endif
00083 
00084 // fbp: these defines are for outline methods definitions.
00085 // needed to definitions to be portable. Should not be used in method bodies.
00086 
00087 #if defined ( _STLP_NESTED_TYPE_PARAM_BUG )
00088 #  define __size_type__       size_t
00089 #  define size_type           size_t
00090 #  define value_type          _Val
00091 #  define key_type            _Key
00092 #  define __reference__       _Val&
00093 
00094 #  define __iterator__        _Ht_iterator<_Val, _STLP_HEADER_TYPENAME _Traits::_NonConstTraits, \
00095                                            _Key, _HF, _ExK, _EqK, _All>
00096 #  define __const_iterator__  _Ht_iterator<_Val, _STLP_HEADER_TYPENAME _Traits::_ConstTraits, \
00097                                            _Key, _HF, _ExK, _EqK, _All>
00098 #else
00099 #  define __size_type__       _STLP_TYPENAME_ON_RETURN_TYPE hashtable<_Val, _Key, _HF, _Traits, _ExK, _EqK, _All>::size_type
00100 #  define __reference__       _STLP_TYPENAME_ON_RETURN_TYPE  hashtable<_Val, _Key, _HF, _Traits, _ExK, _EqK, _All>::reference
00101 #  define __iterator__        _STLP_TYPENAME_ON_RETURN_TYPE hashtable<_Val, _Key, _HF, _Traits, _ExK, _EqK, _All>::iterator
00102 #  define __const_iterator__  _STLP_TYPENAME_ON_RETURN_TYPE hashtable<_Val, _Key, _HF, _Traits, _ExK, _EqK, _All>::const_iterator
00103 #endif
00104 
00105 /*
00106  * This method is too difficult to implement for hashtable that do not
00107  * require a sorted operation on the stored type.
00108 template <class _Val, class _Key, class _HF,
00109           class _Traits, class _ExK, class _EqK, class _All>
00110 bool hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>::_M_equal(
00111               const hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>& __ht1,
00112               const hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>& __ht2) {
00113   return __ht1._M_buckets == __ht2._M_buckets &&
00114          __ht1._M_elems == __ht2._M_elems;
00115 }
00116 */
00117 
00118 /* Returns the iterator before the first iterator of the bucket __n and set
00119  * __n to the first previous bucket having the same first iterator as bucket
00120  * __n.
00121  */
00122 template <class _Val, class _Key, class _HF,
00123           class _Traits, class _ExK, class _EqK, class _All>
00124 __iterator__
00125 hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00126   ::_M_before_begin(size_type &__n) const {
00127   return _S_before_begin(_M_elems, _M_buckets, __n);
00128 }
00129 
00130 template <class _Val, class _Key, class _HF,
00131           class _Traits, class _ExK, class _EqK, class _All>
00132 __iterator__
00133 hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00134   ::_S_before_begin(const _ElemsCont& __elems, const _BucketVector& __buckets,
00135                     size_type &__n) {
00136   _ElemsCont &__mutable_elems = __CONST_CAST(_ElemsCont&, __elems);
00137   typename _BucketVector::const_iterator __bpos(__buckets.begin() + __n);
00138 
00139   _ElemsIte __pos(*__bpos);
00140   if (__pos == __mutable_elems.begin()) {
00141     __n = 0;
00142     return __mutable_elems.before_begin();
00143   }
00144 
00145   typename _BucketVector::const_iterator __bcur(__bpos);
00146   _BucketType *__pos_node = __pos._M_node;
00147   for (--__bcur; __pos_node == *__bcur; --__bcur);
00148 
00149   __n = __bcur - __buckets.begin() + 1;
00150   _ElemsIte __cur(*__bcur);
00151   _ElemsIte __prev = __cur++;
00152   for (; __cur != __pos; ++__prev, ++__cur);
00153   return __prev;
00154 }
00155 
00156 
00157 template <class _Val, class _Key, class _HF,
00158           class _Traits, class _ExK, class _EqK, class _All>
00159 __iterator__
00160 hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00161   ::_M_insert_noresize(size_type __n, const value_type& __obj) {
00162   //We always insert this element as 1st in the bucket to not break
00163   //the elements order as equal elements must be kept next to each other.
00164   size_type __prev = __n;
00165   _ElemsIte __pos = _M_before_begin(__prev)._M_ite;
00166 
00167   fill(_M_buckets.begin() + __prev, _M_buckets.begin() + __n + 1,
00168        _M_elems.insert_after(__pos, __obj)._M_node);
00169   ++_M_num_elements;
00170   return iterator(_ElemsIte(_M_buckets[__n]));
00171 }
00172 
00173 template <class _Val, class _Key, class _HF,
00174           class _Traits, class _ExK, class _EqK, class _All>
00175 pair<__iterator__, bool>
00176 hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00177   ::insert_unique_noresize(const value_type& __obj) {
00178   const size_type __n = _M_bkt_num(__obj);
00179   _ElemsIte __cur(_M_buckets[__n]);
00180   _ElemsIte __last(_M_buckets[__n + 1]);
00181 
00182   if (__cur != __last) {
00183     for (; __cur != __last; ++__cur) {
00184       if (_M_equals(_M_get_key(*__cur), _M_get_key(__obj))) {
00185         //We check that equivalent keys have equals hash code as otherwise, on resize,
00186         //equivalent value might not be in the same bucket
00187         _STLP_ASSERT(_M_hash(_M_get_key(*__cur)) == _M_hash(_M_get_key(__obj)))
00188         return pair<iterator, bool>(iterator(__cur), false);
00189       }
00190     }
00191     /* Here we do not rely on the _M_insert_noresize method as we know
00192      * that we cannot break element orders, elements are unique, and
00193      * insertion after the first bucket element is faster than what is
00194      * done in _M_insert_noresize.
00195      */
00196     __cur = _M_elems.insert_after(_ElemsIte(_M_buckets[__n]), __obj);
00197     ++_M_num_elements;
00198     return pair<iterator, bool>(iterator(__cur), true);
00199   }
00200 
00201   return pair<iterator, bool>(_M_insert_noresize(__n, __obj), true);
00202 }
00203 
00204 template <class _Val, class _Key, class _HF,
00205           class _Traits, class _ExK, class _EqK, class _All>
00206 __iterator__
00207 hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00208   ::insert_equal_noresize(const value_type& __obj) {
00209   const size_type __n = _M_bkt_num(__obj);
00210   {
00211     _ElemsIte __cur(_M_buckets[__n]);
00212     _ElemsIte __last(_M_buckets[__n + 1]);
00213 
00214     for (; __cur != __last; ++__cur) {
00215       if (_M_equals(_M_get_key(*__cur), _M_get_key(__obj))) {
00216         //We check that equivalent keys have equals hash code as otherwise, on resize,
00217         //equivalent value might not be in the same bucket
00218         _STLP_ASSERT(_M_hash(_M_get_key(*__cur)) == _M_hash(_M_get_key(__obj)))
00219         ++_M_num_elements;
00220         return _M_elems.insert_after(__cur, __obj);
00221       }
00222     }
00223   }
00224 
00225   return _M_insert_noresize(__n, __obj);
00226 }
00227 
00228 template <class _Val, class _Key, class _HF,
00229           class _Traits, class _ExK, class _EqK, class _All>
00230 __reference__
00231 hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00232   ::_M_insert(const value_type& __obj) {
00233   resize(_M_num_elements + 1);
00234   return *insert_unique_noresize(__obj).first;
00235 }
00236 
00237 /*
00238 template <class _Val, class _Key, class _HF,
00239           class _Traits, class _ExK, class _EqK, class _All>
00240 __reference__
00241 hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00242   ::find_or_insert(const value_type& __obj) {
00243   _Node* __first = _M_find(_M_get_key(__obj));
00244   if (__first)
00245     return __first->_M_val;
00246   else
00247     return _M_insert(__obj);
00248 }
00249 */
00250 
00251 template <class _Val, class _Key, class _HF,
00252           class _Traits, class _ExK, class _EqK, class _All>
00253 __size_type__
00254 hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00255   ::erase(const key_type& __key) {
00256   const size_type __n = _M_bkt_num_key(__key);
00257 
00258   _ElemsIte __cur(_M_buckets[__n]);
00259   _ElemsIte __last(_M_buckets[__n + 1]);
00260   if (__cur == __last)
00261     return 0;
00262 
00263   size_type __erased = 0;
00264   if (_M_equals(_M_get_key(*__cur), __key)) {
00265     //We look for the pos before __cur:
00266     size_type __prev_b = __n;
00267     _ElemsIte __prev = _M_before_begin(__prev_b)._M_ite;
00268     do {
00269       __cur = _M_elems.erase_after(__prev);
00270       ++__erased;
00271     } while ((__cur != __last) && _M_equals(_M_get_key(*__cur), __key));
00272     fill(_M_buckets.begin() + __prev_b, _M_buckets.begin() + __n + 1, __cur._M_node);
00273   }
00274   else {
00275     _ElemsIte __prev = __cur++;
00276     for (; __cur != __last; ++__prev, ++__cur) {
00277       if (_M_equals(_M_get_key(*__cur), __key)) {
00278         do {
00279           __cur = _M_elems.erase_after(__prev);
00280           ++__erased;
00281         } while ((__cur != __last) && _M_equals(_M_get_key(*__cur), __key));
00282         break;
00283       }
00284     }
00285   }
00286 
00287   _M_num_elements -= __erased;
00288   return __erased;
00289 }
00290 
00291 template <class _Val, class _Key, class _HF,
00292           class _Traits, class _ExK, class _EqK, class _All>
00293 void hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00294   ::erase(const_iterator __it) {
00295   const size_type __n = _M_bkt_num(*__it);
00296   _ElemsIte __cur(_M_buckets[__n]);
00297 
00298   if (__cur == __it._M_ite) {
00299     size_type __prev_b = __n;
00300     _ElemsIte __prev = _M_before_begin(__prev_b)._M_ite;
00301     fill(_M_buckets.begin() + __prev_b, _M_buckets.begin() + __n + 1,
00302          _M_elems.erase_after(__prev)._M_node);
00303     --_M_num_elements;
00304   }
00305   else {
00306     _ElemsIte __prev = __cur++;
00307     _ElemsIte __last(_M_buckets[__n + 1]);
00308     for (; __cur != __last; ++__prev, ++__cur) {
00309       if (__cur == __it._M_ite) {
00310         _M_elems.erase_after(__prev);
00311         --_M_num_elements;
00312         break;
00313       }
00314     }
00315   }
00316 }
00317 
00318 template <class _Val, class _Key, class _HF,
00319           class _Traits, class _ExK, class _EqK, class _All>
00320 void hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00321   ::erase(const_iterator __first, const_iterator __last) {
00322   if (__first == __last)
00323     return;
00324   size_type __f_bucket = _M_bkt_num(*__first);
00325   size_type __l_bucket = __last != end() ? _M_bkt_num(*__last) : (_M_buckets.size() - 1);
00326 
00327   _ElemsIte __cur(_M_buckets[__f_bucket]);
00328   _ElemsIte __prev;
00329   if (__cur == __first._M_ite) {
00330     __prev = _M_before_begin(__f_bucket)._M_ite;
00331   }
00332   else {
00333     _ElemsIte __last(_M_buckets[++__f_bucket]);
00334     __prev = __cur++;
00335     for (; (__cur != __last) && (__cur != __first._M_ite); ++__prev, ++__cur);
00336   }
00337   //We do not use the slist::erase_after method taking a range to count the
00338   //number of erased elements:
00339   while (__cur != __last._M_ite) {
00340     __cur = _M_elems.erase_after(__prev);
00341     --_M_num_elements;
00342   }
00343   fill(_M_buckets.begin() + __f_bucket, _M_buckets.begin() + __l_bucket + 1, __cur._M_node);
00344 }
00345 
00346 template <class _Val, class _Key, class _HF,
00347           class _Traits, class _ExK, class _EqK, class _All>
00348 void hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00349   ::rehash(size_type __num_buckets_hint) {
00350   if ((bucket_count() >= __num_buckets_hint) &&
00351       (max_load_factor() > load_factor()))
00352     return;
00353 
00354   //Here if max_load_factor is lower than 1.0 the resulting value might not be representable
00355   //as a size_type. The result concerning the respect of the max_load_factor will then be
00356   //undefined.
00357   __num_buckets_hint = (max) (__num_buckets_hint, (size_type)((float)size() / max_load_factor()));
00358   size_type __num_buckets = _STLP_PRIV _Stl_prime_type::_S_next_size(__num_buckets_hint);
00359   _M_rehash(__num_buckets);
00360 }
00361 
00362 template <class _Val, class _Key, class _HF,
00363           class _Traits, class _ExK, class _EqK, class _All>
00364 void hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00365   ::resize(size_type __num_elements_hint) {
00366   if (((float)__num_elements_hint / (float)bucket_count() <= max_load_factor()) &&
00367       (max_load_factor() >= load_factor())) {
00368     return;
00369   }
00370 
00371   size_type __num_buckets_hint = (size_type)((float)(max) (__num_elements_hint, size()) / max_load_factor());
00372   size_type __num_buckets = _STLP_PRIV _Stl_prime_type::_S_next_size(__num_buckets_hint);
00373 #if defined (_STLP_DEBUG)
00374   _M_check();
00375 #endif
00376   _M_rehash(__num_buckets);
00377 }
00378 
00379 template <class _Val, class _Key, class _HF,
00380           class _Traits, class _ExK, class _EqK, class _All>
00381 void hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00382   ::_M_rehash(size_type __num_buckets) {
00383   _ElemsCont __tmp_elems(_M_elems.get_allocator());
00384   _BucketVector __tmp(__num_buckets + 1, __STATIC_CAST(_BucketType*, 0), _M_buckets.get_allocator());
00385   _ElemsIte __cur, __last(_M_elems.end());
00386   while (!_M_elems.empty()) {
00387     __cur = _M_elems.begin();
00388     size_type __new_bucket = _M_bkt_num(*__cur, __num_buckets);
00389     _ElemsIte __ite(__cur), __before_ite(__cur);
00390     for (++__ite;
00391          __ite != __last && _M_equals(_M_get_key(*__cur), _M_get_key(*__ite));
00392          ++__ite, ++__before_ite);
00393     size_type __prev_bucket = __new_bucket;
00394     _ElemsIte  __prev = _S_before_begin(__tmp_elems, __tmp, __prev_bucket)._M_ite;
00395     __tmp_elems.splice_after(__prev, _M_elems, _M_elems.before_begin(), __before_ite);
00396     fill(__tmp.begin() + __prev_bucket, __tmp.begin() + __new_bucket + 1, __cur._M_node);
00397   }
00398   _M_elems.swap(__tmp_elems);
00399   _M_buckets.swap(__tmp);
00400 }
00401 
00402 #if defined (_STLP_DEBUG)
00403 template <class _Val, class _Key, class _HF,
00404           class _Traits, class _ExK, class _EqK, class _All>
00405 void hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>::_M_check() const {
00406   //We check that hash code of stored keys haven't change and also that equivalent
00407   //relation hasn't been modified
00408   size_t __num_buckets = bucket_count();
00409   for (size_t __b = 0; __b < __num_buckets; ++__b) {
00410     _ElemsIte __cur(_M_buckets[__b]), __last(_M_buckets[__b + 1]);
00411     _ElemsIte __fst(__cur), __snd(__cur);
00412     for (; __cur != __last; ++__cur) {
00413       _STLP_ASSERT( _M_bkt_num(*__cur, __num_buckets) == __b )
00414       _STLP_ASSERT( !_M_equals(_M_get_key(*__fst), _M_get_key(*__cur)) || _M_equals(_M_get_key(*__snd), _M_get_key(*__cur)) )
00415       if (__fst != __snd)
00416         ++__fst;
00417       if (__snd != __cur)
00418         ++__snd;
00419     }
00420   }
00421 }
00422 #endif
00423 
00424 template <class _Val, class _Key, class _HF,
00425           class _Traits, class _ExK, class _EqK, class _All>
00426 void hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>::clear() {
00427   _M_elems.clear();
00428   _M_buckets.assign(_M_buckets.size(), __STATIC_CAST(_BucketType*, 0));
00429   _M_num_elements = 0;
00430 }
00431 
00432 template <class _Val, class _Key, class _HF,
00433           class _Traits, class _ExK, class _EqK, class _All>
00434 void hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>
00435   ::_M_copy_from(const hashtable<_Val,_Key,_HF,_Traits,_ExK,_EqK,_All>& __ht) {
00436   _M_elems.clear();
00437   _M_elems.insert(_M_elems.end(), __ht._M_elems.begin(), __ht._M_elems.end());
00438   _M_buckets.resize(__ht._M_buckets.size());
00439   _ElemsConstIte __src(__ht._M_elems.begin()), __src_end(__ht._M_elems.end());
00440   _ElemsIte __dst(_M_elems.begin());
00441   typename _BucketVector::const_iterator __src_b(__ht._M_buckets.begin()),
00442                                          __src_end_b(__ht._M_buckets.end());
00443   typename _BucketVector::iterator __dst_b(_M_buckets.begin()), __dst_end_b(_M_buckets.end());
00444   for (; __src != __src_end; ++__src, ++__dst) {
00445     for (; __src_b != __src_end_b; ++__src_b, ++__dst_b) {
00446       if (*__src_b == __src._M_node) {
00447         *__dst_b = __dst._M_node;
00448       }
00449       else
00450         break;
00451     }
00452   }
00453   fill(__dst_b, __dst_end_b, __STATIC_CAST(_BucketType*, 0));
00454   _M_num_elements = __ht._M_num_elements;
00455   _M_max_load_factor = __ht._M_max_load_factor;
00456 }
00457 
00458 #undef __iterator__
00459 #undef const_iterator
00460 #undef __size_type__
00461 #undef __reference__
00462 #undef size_type
00463 #undef value_type
00464 #undef key_type
00465 #undef __stl_num_primes
00466 
00467 #if defined (_STLP_DEBUG)
00468 #  undef hashtable
00469 _STLP_MOVE_TO_STD_NAMESPACE
00470 #endif
00471 
00472 _STLP_END_NAMESPACE
00473 
00474 #endif /*  _STLP_HASHTABLE_C */
00475 
00476 // Local Variables:
00477 // mode:C++
00478 // End:



Generated on Mon Mar 10 15:32:24 2008 by  doxygen 1.5.1