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