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