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