|
libstdc++
|
00001 // hashtable.h header -*- C++ -*- 00002 00003 // Copyright (C) 2007-2015 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 template<typename _Tp, typename _Hash> 00042 using __cache_default 00043 = __not_<__and_<// Do not cache for fast hasher. 00044 __is_fast_hash<_Hash>, 00045 // Mandatory to have erase not throwing. 00046 __detail::__is_noexcept_hash<_Tp, _Hash>>>; 00047 00048 /** 00049 * Primary class template _Hashtable. 00050 * 00051 * @ingroup hashtable-detail 00052 * 00053 * @tparam _Value CopyConstructible type. 00054 * 00055 * @tparam _Key CopyConstructible type. 00056 * 00057 * @tparam _Alloc An allocator type 00058 * ([lib.allocator.requirements]) whose _Alloc::value_type is 00059 * _Value. As a conforming extension, we allow for 00060 * _Alloc::value_type != _Value. 00061 * 00062 * @tparam _ExtractKey Function object that takes an object of type 00063 * _Value and returns a value of type _Key. 00064 * 00065 * @tparam _Equal Function object that takes two objects of type k 00066 * and returns a bool-like value that is true if the two objects 00067 * are considered equal. 00068 * 00069 * @tparam _H1 The hash function. A unary function object with 00070 * argument type _Key and result type size_t. Return values should 00071 * be distributed over the entire range [0, numeric_limits<size_t>:::max()]. 00072 * 00073 * @tparam _H2 The range-hashing function (in the terminology of 00074 * Tavori and Dreizin). A binary function object whose argument 00075 * types and result type are all size_t. Given arguments r and N, 00076 * the return value is in the range [0, N). 00077 * 00078 * @tparam _Hash The ranged hash function (Tavori and Dreizin). A 00079 * binary function whose argument types are _Key and size_t and 00080 * whose result type is size_t. Given arguments k and N, the 00081 * return value is in the range [0, N). Default: hash(k, N) = 00082 * h2(h1(k), N). If _Hash is anything other than the default, _H1 00083 * and _H2 are ignored. 00084 * 00085 * @tparam _RehashPolicy Policy class with three members, all of 00086 * which govern the bucket count. _M_next_bkt(n) returns a bucket 00087 * count no smaller than n. _M_bkt_for_elements(n) returns a 00088 * bucket count appropriate for an element count of n. 00089 * _M_need_rehash(n_bkt, n_elt, n_ins) determines whether, if the 00090 * current bucket count is n_bkt and the current element count is 00091 * n_elt, we need to increase the bucket count. If so, returns 00092 * make_pair(true, n), where n is the new bucket count. If not, 00093 * returns make_pair(false, <anything>) 00094 * 00095 * @tparam _Traits Compile-time class with three boolean 00096 * std::integral_constant members: __cache_hash_code, __constant_iterators, 00097 * __unique_keys. 00098 * 00099 * Each _Hashtable data structure has: 00100 * 00101 * - _Bucket[] _M_buckets 00102 * - _Hash_node_base _M_before_begin 00103 * - size_type _M_bucket_count 00104 * - size_type _M_element_count 00105 * 00106 * with _Bucket being _Hash_node* and _Hash_node containing: 00107 * 00108 * - _Hash_node* _M_next 00109 * - Tp _M_value 00110 * - size_t _M_hash_code if cache_hash_code is true 00111 * 00112 * In terms of Standard containers the hashtable is like the aggregation of: 00113 * 00114 * - std::forward_list<_Node> containing the elements 00115 * - std::vector<std::forward_list<_Node>::iterator> representing the buckets 00116 * 00117 * The non-empty buckets contain the node before the first node in the 00118 * bucket. This design makes it possible to implement something like a 00119 * std::forward_list::insert_after on container insertion and 00120 * std::forward_list::erase_after on container erase 00121 * calls. _M_before_begin is equivalent to 00122 * std::forward_list::before_begin. Empty buckets contain 00123 * nullptr. Note that one of the non-empty buckets contains 00124 * &_M_before_begin which is not a dereferenceable node so the 00125 * node pointer in a bucket shall never be dereferenced, only its 00126 * next node can be. 00127 * 00128 * Walking through a bucket's nodes requires a check on the hash code to 00129 * see if each node is still in the bucket. Such a design assumes a 00130 * quite efficient hash functor and is one of the reasons it is 00131 * highly advisable to set __cache_hash_code to true. 00132 * 00133 * The container iterators are simply built from nodes. This way 00134 * incrementing the iterator is perfectly efficient independent of 00135 * how many empty buckets there are in the container. 00136 * 00137 * On insert we compute the element's hash code and use it to find the 00138 * bucket index. If the element must be inserted in an empty bucket 00139 * we add it at the beginning of the singly linked list and make the 00140 * bucket point to _M_before_begin. The bucket that used to point to 00141 * _M_before_begin, if any, is updated to point to its new before 00142 * begin node. 00143 * 00144 * On erase, the simple iterator design requires using the hash 00145 * functor to get the index of the bucket to update. For this 00146 * reason, when __cache_hash_code is set to false the hash functor must 00147 * not throw and this is enforced by a static assertion. 00148 * 00149 * Functionality is implemented by decomposition into base classes, 00150 * where the derived _Hashtable class is used in _Map_base, 00151 * _Insert, _Rehash_base, and _Equality base classes to access the 00152 * "this" pointer. _Hashtable_base is used in the base classes as a 00153 * non-recursive, fully-completed-type so that detailed nested type 00154 * information, such as iterator type and node type, can be 00155 * used. This is similar to the "Curiously Recurring Template 00156 * Pattern" (CRTP) technique, but uses a reconstructed, not 00157 * explicitly passed, template pattern. 00158 * 00159 * Base class templates are: 00160 * - __detail::_Hashtable_base 00161 * - __detail::_Map_base 00162 * - __detail::_Insert 00163 * - __detail::_Rehash_base 00164 * - __detail::_Equality 00165 */ 00166 template<typename _Key, typename _Value, typename _Alloc, 00167 typename _ExtractKey, typename _Equal, 00168 typename _H1, typename _H2, typename _Hash, 00169 typename _RehashPolicy, typename _Traits> 00170 class _Hashtable 00171 : public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal, 00172 _H1, _H2, _Hash, _Traits>, 00173 public __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, 00174 _H1, _H2, _Hash, _RehashPolicy, _Traits>, 00175 public __detail::_Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal, 00176 _H1, _H2, _Hash, _RehashPolicy, _Traits>, 00177 public __detail::_Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal, 00178 _H1, _H2, _Hash, _RehashPolicy, _Traits>, 00179 public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal, 00180 _H1, _H2, _Hash, _RehashPolicy, _Traits>, 00181 private __detail::_Hashtable_alloc< 00182 typename __alloctr_rebind<_Alloc, 00183 __detail::_Hash_node<_Value, 00184 _Traits::__hash_cached::value> >::__type> 00185 { 00186 using __traits_type = _Traits; 00187 using __hash_cached = typename __traits_type::__hash_cached; 00188 using __node_type = __detail::_Hash_node<_Value, __hash_cached::value>; 00189 using __node_alloc_type = 00190 typename __alloctr_rebind<_Alloc, __node_type>::__type; 00191 00192 using __hashtable_alloc = __detail::_Hashtable_alloc<__node_alloc_type>; 00193 00194 using __value_alloc_traits = 00195 typename __hashtable_alloc::__value_alloc_traits; 00196 using __node_alloc_traits = 00197 typename __hashtable_alloc::__node_alloc_traits; 00198 using __node_base = typename __hashtable_alloc::__node_base; 00199 using __bucket_type = typename __hashtable_alloc::__bucket_type; 00200 00201 public: 00202 typedef _Key key_type; 00203 typedef _Value value_type; 00204 typedef _Alloc allocator_type; 00205 typedef _Equal key_equal; 00206 00207 // mapped_type, if present, comes from _Map_base. 00208 // hasher, if present, comes from _Hash_code_base/_Hashtable_base. 00209 typedef typename __value_alloc_traits::pointer pointer; 00210 typedef typename __value_alloc_traits::const_pointer const_pointer; 00211 typedef value_type& reference; 00212 typedef const value_type& const_reference; 00213 00214 private: 00215 using __rehash_type = _RehashPolicy; 00216 using __rehash_state = typename __rehash_type::_State; 00217 00218 using __constant_iterators = typename __traits_type::__constant_iterators; 00219 using __unique_keys = typename __traits_type::__unique_keys; 00220 00221 using __key_extract = typename std::conditional< 00222 __constant_iterators::value, 00223 __detail::_Identity, 00224 __detail::_Select1st>::type; 00225 00226 using __hashtable_base = __detail:: 00227 _Hashtable_base<_Key, _Value, _ExtractKey, 00228 _Equal, _H1, _H2, _Hash, _Traits>; 00229 00230 using __hash_code_base = typename __hashtable_base::__hash_code_base; 00231 using __hash_code = typename __hashtable_base::__hash_code; 00232 using __ireturn_type = typename __hashtable_base::__ireturn_type; 00233 00234 using __map_base = __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, 00235 _Equal, _H1, _H2, _Hash, 00236 _RehashPolicy, _Traits>; 00237 00238 using __rehash_base = __detail::_Rehash_base<_Key, _Value, _Alloc, 00239 _ExtractKey, _Equal, 00240 _H1, _H2, _Hash, 00241 _RehashPolicy, _Traits>; 00242 00243 using __eq_base = __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, 00244 _Equal, _H1, _H2, _Hash, 00245 _RehashPolicy, _Traits>; 00246 00247 using __reuse_or_alloc_node_type = 00248 __detail::_ReuseOrAllocNode<__node_alloc_type>; 00249 00250 // Metaprogramming for picking apart hash caching. 00251 template<typename _Cond> 00252 using __if_hash_cached = __or_<__not_<__hash_cached>, _Cond>; 00253 00254 template<typename _Cond> 00255 using __if_hash_not_cached = __or_<__hash_cached, _Cond>; 00256 00257 // Compile-time diagnostics. 00258 00259 // _Hash_code_base has everything protected, so use this derived type to 00260 // access it. 00261 struct __hash_code_base_access : __hash_code_base 00262 { using __hash_code_base::_M_bucket_index; }; 00263 00264 // Getting a bucket index from a node shall not throw because it is used 00265 // in methods (erase, swap...) that shall not throw. 00266 static_assert(noexcept(declval<const __hash_code_base_access&>() 00267 ._M_bucket_index((const __node_type*)nullptr, 00268 (std::size_t)0)), 00269 "Cache the hash code or qualify your functors involved" 00270 " in hash code and bucket index computation with noexcept"); 00271 00272 // Following two static assertions are necessary to guarantee 00273 // that local_iterator will be default constructible. 00274 00275 // When hash codes are cached local iterator inherits from H2 functor 00276 // which must then be default constructible. 00277 static_assert(__if_hash_cached<is_default_constructible<_H2>>::value, 00278 "Functor used to map hash code to bucket index" 00279 " must be default constructible"); 00280 00281 template<typename _Keya, typename _Valuea, typename _Alloca, 00282 typename _ExtractKeya, typename _Equala, 00283 typename _H1a, typename _H2a, typename _Hasha, 00284 typename _RehashPolicya, typename _Traitsa, 00285 bool _Unique_keysa> 00286 friend struct __detail::_Map_base; 00287 00288 template<typename _Keya, typename _Valuea, typename _Alloca, 00289 typename _ExtractKeya, typename _Equala, 00290 typename _H1a, typename _H2a, typename _Hasha, 00291 typename _RehashPolicya, typename _Traitsa> 00292 friend struct __detail::_Insert_base; 00293 00294 template<typename _Keya, typename _Valuea, typename _Alloca, 00295 typename _ExtractKeya, typename _Equala, 00296 typename _H1a, typename _H2a, typename _Hasha, 00297 typename _RehashPolicya, typename _Traitsa, 00298 bool _Constant_iteratorsa, bool _Unique_keysa> 00299 friend struct __detail::_Insert; 00300 00301 public: 00302 using size_type = typename __hashtable_base::size_type; 00303 using difference_type = typename __hashtable_base::difference_type; 00304 00305 using iterator = typename __hashtable_base::iterator; 00306 using const_iterator = typename __hashtable_base::const_iterator; 00307 00308 using local_iterator = typename __hashtable_base::local_iterator; 00309 using const_local_iterator = typename __hashtable_base:: 00310 const_local_iterator; 00311 00312 private: 00313 __bucket_type* _M_buckets = &_M_single_bucket; 00314 size_type _M_bucket_count = 1; 00315 __node_base _M_before_begin; 00316 size_type _M_element_count = 0; 00317 _RehashPolicy _M_rehash_policy; 00318 00319 // A single bucket used when only need for 1 bucket. Especially 00320 // interesting in move semantic to leave hashtable with only 1 buckets 00321 // which is not allocated so that we can have those operations noexcept 00322 // qualified. 00323 // Note that we can't leave hashtable with 0 bucket without adding 00324 // numerous checks in the code to avoid 0 modulus. 00325 __bucket_type _M_single_bucket = nullptr; 00326 00327 bool 00328 _M_uses_single_bucket(__bucket_type* __bkts) const 00329 { return __builtin_expect(__bkts == &_M_single_bucket, false); } 00330 00331 bool 00332 _M_uses_single_bucket() const 00333 { return _M_uses_single_bucket(_M_buckets); } 00334 00335 __hashtable_alloc& 00336 _M_base_alloc() { return *this; } 00337 00338 __bucket_type* 00339 _M_allocate_buckets(size_type __n) 00340 { 00341 if (__builtin_expect(__n == 1, false)) 00342 { 00343 _M_single_bucket = nullptr; 00344 return &_M_single_bucket; 00345 } 00346 00347 return __hashtable_alloc::_M_allocate_buckets(__n); 00348 } 00349 00350 void 00351 _M_deallocate_buckets(__bucket_type* __bkts, size_type __n) 00352 { 00353 if (_M_uses_single_bucket(__bkts)) 00354 return; 00355 00356 __hashtable_alloc::_M_deallocate_buckets(__bkts, __n); 00357 } 00358 00359 void 00360 _M_deallocate_buckets() 00361 { _M_deallocate_buckets(_M_buckets, _M_bucket_count); } 00362 00363 // Gets bucket begin, deals with the fact that non-empty buckets contain 00364 // their before begin node. 00365 __node_type* 00366 _M_bucket_begin(size_type __bkt) const; 00367 00368 __node_type* 00369 _M_begin() const 00370 { return static_cast<__node_type*>(_M_before_begin._M_nxt); } 00371 00372 template<typename _NodeGenerator> 00373 void 00374 _M_assign(const _Hashtable&, const _NodeGenerator&); 00375 00376 void 00377 _M_move_assign(_Hashtable&&, std::true_type); 00378 00379 void 00380 _M_move_assign(_Hashtable&&, std::false_type); 00381 00382 void 00383 _M_reset() noexcept; 00384 00385 _Hashtable(const _H1& __h1, const _H2& __h2, const _Hash& __h, 00386 const _Equal& __eq, const _ExtractKey& __exk, 00387 const allocator_type& __a) 00388 : __hashtable_base(__exk, __h1, __h2, __h, __eq), 00389 __hashtable_alloc(__node_alloc_type(__a)) 00390 { } 00391 00392 public: 00393 // Constructor, destructor, assignment, swap 00394 _Hashtable() = default; 00395 _Hashtable(size_type __bucket_hint, 00396 const _H1&, const _H2&, const _Hash&, 00397 const _Equal&, const _ExtractKey&, 00398 const allocator_type&); 00399 00400 template<typename _InputIterator> 00401 _Hashtable(_InputIterator __first, _InputIterator __last, 00402 size_type __bucket_hint, 00403 const _H1&, const _H2&, const _Hash&, 00404 const _Equal&, const _ExtractKey&, 00405 const allocator_type&); 00406 00407 _Hashtable(const _Hashtable&); 00408 00409 _Hashtable(_Hashtable&&) noexcept; 00410 00411 _Hashtable(const _Hashtable&, const allocator_type&); 00412 00413 _Hashtable(_Hashtable&&, const allocator_type&); 00414 00415 // Use delegating constructors. 00416 explicit 00417 _Hashtable(const allocator_type& __a) 00418 : __hashtable_alloc(__node_alloc_type(__a)) 00419 { } 00420 00421 explicit 00422 _Hashtable(size_type __n, 00423 const _H1& __hf = _H1(), 00424 const key_equal& __eql = key_equal(), 00425 const allocator_type& __a = allocator_type()) 00426 : _Hashtable(__n, __hf, _H2(), _Hash(), __eql, 00427 __key_extract(), __a) 00428 { } 00429 00430 template<typename _InputIterator> 00431 _Hashtable(_InputIterator __f, _InputIterator __l, 00432 size_type __n = 0, 00433 const _H1& __hf = _H1(), 00434 const key_equal& __eql = key_equal(), 00435 const allocator_type& __a = allocator_type()) 00436 : _Hashtable(__f, __l, __n, __hf, _H2(), _Hash(), __eql, 00437 __key_extract(), __a) 00438 { } 00439 00440 _Hashtable(initializer_list<value_type> __l, 00441 size_type __n = 0, 00442 const _H1& __hf = _H1(), 00443 const key_equal& __eql = key_equal(), 00444 const allocator_type& __a = allocator_type()) 00445 : _Hashtable(__l.begin(), __l.end(), __n, __hf, _H2(), _Hash(), __eql, 00446 __key_extract(), __a) 00447 { } 00448 00449 _Hashtable& 00450 operator=(const _Hashtable& __ht); 00451 00452 _Hashtable& 00453 operator=(_Hashtable&& __ht) 00454 noexcept(__node_alloc_traits::_S_nothrow_move()) 00455 { 00456 constexpr bool __move_storage = 00457 __node_alloc_traits::_S_propagate_on_move_assign() 00458 || __node_alloc_traits::_S_always_equal(); 00459 _M_move_assign(std::move(__ht), 00460 integral_constant<bool, __move_storage>()); 00461 return *this; 00462 } 00463 00464 _Hashtable& 00465 operator=(initializer_list<value_type> __l) 00466 { 00467 __reuse_or_alloc_node_type __roan(_M_begin(), *this); 00468 _M_before_begin._M_nxt = nullptr; 00469 clear(); 00470 this->_M_insert_range(__l.begin(), __l.end(), __roan); 00471 return *this; 00472 } 00473 00474 ~_Hashtable() noexcept; 00475 00476 void 00477 swap(_Hashtable&) 00478 noexcept(__node_alloc_traits::_S_nothrow_swap()); 00479 00480 // Basic container operations 00481 iterator 00482 begin() noexcept 00483 { return iterator(_M_begin()); } 00484 00485 const_iterator 00486 begin() const noexcept 00487 { return const_iterator(_M_begin()); } 00488 00489 iterator 00490 end() noexcept 00491 { return iterator(nullptr); } 00492 00493 const_iterator 00494 end() const noexcept 00495 { return const_iterator(nullptr); } 00496 00497 const_iterator 00498 cbegin() const noexcept 00499 { return const_iterator(_M_begin()); } 00500 00501 const_iterator 00502 cend() const noexcept 00503 { return const_iterator(nullptr); } 00504 00505 size_type 00506 size() const noexcept 00507 { return _M_element_count; } 00508 00509 bool 00510 empty() const noexcept 00511 { return size() == 0; } 00512 00513 allocator_type 00514 get_allocator() const noexcept 00515 { return allocator_type(this->_M_node_allocator()); } 00516 00517 size_type 00518 max_size() const noexcept 00519 { return __node_alloc_traits::max_size(this->_M_node_allocator()); } 00520 00521 // Observers 00522 key_equal 00523 key_eq() const 00524 { return this->_M_eq(); } 00525 00526 // hash_function, if present, comes from _Hash_code_base. 00527 00528 // Bucket operations 00529 size_type 00530 bucket_count() const noexcept 00531 { return _M_bucket_count; } 00532 00533 size_type 00534 max_bucket_count() const noexcept 00535 { return max_size(); } 00536 00537 size_type 00538 bucket_size(size_type __n) const 00539 { return std::distance(begin(__n), end(__n)); } 00540 00541 size_type 00542 bucket(const key_type& __k) const 00543 { return _M_bucket_index(__k, this->_M_hash_code(__k)); } 00544 00545 local_iterator 00546 begin(size_type __n) 00547 { 00548 return local_iterator(*this, _M_bucket_begin(__n), 00549 __n, _M_bucket_count); 00550 } 00551 00552 local_iterator 00553 end(size_type __n) 00554 { return local_iterator(*this, nullptr, __n, _M_bucket_count); } 00555 00556 const_local_iterator 00557 begin(size_type __n) const 00558 { 00559 return const_local_iterator(*this, _M_bucket_begin(__n), 00560 __n, _M_bucket_count); 00561 } 00562 00563 const_local_iterator 00564 end(size_type __n) const 00565 { return const_local_iterator(*this, nullptr, __n, _M_bucket_count); } 00566 00567 // DR 691. 00568 const_local_iterator 00569 cbegin(size_type __n) const 00570 { 00571 return const_local_iterator(*this, _M_bucket_begin(__n), 00572 __n, _M_bucket_count); 00573 } 00574 00575 const_local_iterator 00576 cend(size_type __n) const 00577 { return const_local_iterator(*this, nullptr, __n, _M_bucket_count); } 00578 00579 float 00580 load_factor() const noexcept 00581 { 00582 return static_cast<float>(size()) / static_cast<float>(bucket_count()); 00583 } 00584 00585 // max_load_factor, if present, comes from _Rehash_base. 00586 00587 // Generalization of max_load_factor. Extension, not found in 00588 // TR1. Only useful if _RehashPolicy is something other than 00589 // the default. 00590 const _RehashPolicy& 00591 __rehash_policy() const 00592 { return _M_rehash_policy; } 00593 00594 void 00595 __rehash_policy(const _RehashPolicy&); 00596 00597 // Lookup. 00598 iterator 00599 find(const key_type& __k); 00600 00601 const_iterator 00602 find(const key_type& __k) const; 00603 00604 size_type 00605 count(const key_type& __k) const; 00606 00607 std::pair<iterator, iterator> 00608 equal_range(const key_type& __k); 00609 00610 std::pair<const_iterator, const_iterator> 00611 equal_range(const key_type& __k) const; 00612 00613 protected: 00614 // Bucket index computation helpers. 00615 size_type 00616 _M_bucket_index(__node_type* __n) const noexcept 00617 { return __hash_code_base::_M_bucket_index(__n, _M_bucket_count); } 00618 00619 size_type 00620 _M_bucket_index(const key_type& __k, __hash_code __c) const 00621 { return __hash_code_base::_M_bucket_index(__k, __c, _M_bucket_count); } 00622 00623 // Find and insert helper functions and types 00624 // Find the node before the one matching the criteria. 00625 __node_base* 00626 _M_find_before_node(size_type, const key_type&, __hash_code) const; 00627 00628 __node_type* 00629 _M_find_node(size_type __bkt, const key_type& __key, 00630 __hash_code __c) const 00631 { 00632 __node_base* __before_n = _M_find_before_node(__bkt, __key, __c); 00633 if (__before_n) 00634 return static_cast<__node_type*>(__before_n->_M_nxt); 00635 return nullptr; 00636 } 00637 00638 // Insert a node at the beginning of a bucket. 00639 void 00640 _M_insert_bucket_begin(size_type, __node_type*); 00641 00642 // Remove the bucket first node 00643 void 00644 _M_remove_bucket_begin(size_type __bkt, __node_type* __next_n, 00645 size_type __next_bkt); 00646 00647 // Get the node before __n in the bucket __bkt 00648 __node_base* 00649 _M_get_previous_node(size_type __bkt, __node_base* __n); 00650 00651 // Insert node with hash code __code, in bucket bkt if no rehash (assumes 00652 // no element with its key already present). Take ownership of the node, 00653 // deallocate it on exception. 00654 iterator 00655 _M_insert_unique_node(size_type __bkt, __hash_code __code, 00656 __node_type* __n); 00657 00658 // Insert node with hash code __code. Take ownership of the node, 00659 // deallocate it on exception. 00660 iterator 00661 _M_insert_multi_node(__node_type* __hint, 00662 __hash_code __code, __node_type* __n); 00663 00664 template<typename... _Args> 00665 std::pair<iterator, bool> 00666 _M_emplace(std::true_type, _Args&&... __args); 00667 00668 template<typename... _Args> 00669 iterator 00670 _M_emplace(std::false_type __uk, _Args&&... __args) 00671 { return _M_emplace(cend(), __uk, std::forward<_Args>(__args)...); } 00672 00673 // Emplace with hint, useless when keys are unique. 00674 template<typename... _Args> 00675 iterator 00676 _M_emplace(const_iterator, std::true_type __uk, _Args&&... __args) 00677 { return _M_emplace(__uk, std::forward<_Args>(__args)...).first; } 00678 00679 template<typename... _Args> 00680 iterator 00681 _M_emplace(const_iterator, std::false_type, _Args&&... __args); 00682 00683 template<typename _Arg, typename _NodeGenerator> 00684 std::pair<iterator, bool> 00685 _M_insert(_Arg&&, const _NodeGenerator&, std::true_type); 00686 00687 template<typename _Arg, typename _NodeGenerator> 00688 iterator 00689 _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen, 00690 std::false_type __uk) 00691 { 00692 return _M_insert(cend(), std::forward<_Arg>(__arg), __node_gen, 00693 __uk); 00694 } 00695 00696 // Insert with hint, not used when keys are unique. 00697 template<typename _Arg, typename _NodeGenerator> 00698 iterator 00699 _M_insert(const_iterator, _Arg&& __arg, 00700 const _NodeGenerator& __node_gen, std::true_type __uk) 00701 { 00702 return 00703 _M_insert(std::forward<_Arg>(__arg), __node_gen, __uk).first; 00704 } 00705 00706 // Insert with hint when keys are not unique. 00707 template<typename _Arg, typename _NodeGenerator> 00708 iterator 00709 _M_insert(const_iterator, _Arg&&, 00710 const _NodeGenerator&, std::false_type); 00711 00712 size_type 00713 _M_erase(std::true_type, const key_type&); 00714 00715 size_type 00716 _M_erase(std::false_type, const key_type&); 00717 00718 iterator 00719 _M_erase(size_type __bkt, __node_base* __prev_n, __node_type* __n); 00720 00721 public: 00722 // Emplace 00723 template<typename... _Args> 00724 __ireturn_type 00725 emplace(_Args&&... __args) 00726 { return _M_emplace(__unique_keys(), std::forward<_Args>(__args)...); } 00727 00728 template<typename... _Args> 00729 iterator 00730 emplace_hint(const_iterator __hint, _Args&&... __args) 00731 { 00732 return _M_emplace(__hint, __unique_keys(), 00733 std::forward<_Args>(__args)...); 00734 } 00735 00736 // Insert member functions via inheritance. 00737 00738 // Erase 00739 iterator 00740 erase(const_iterator); 00741 00742 // LWG 2059. 00743 iterator 00744 erase(iterator __it) 00745 { return erase(const_iterator(__it)); } 00746 00747 size_type 00748 erase(const key_type& __k) 00749 { return _M_erase(__unique_keys(), __k); } 00750 00751 iterator 00752 erase(const_iterator, const_iterator); 00753 00754 void 00755 clear() noexcept; 00756 00757 // Set number of buckets to be appropriate for container of n element. 00758 void rehash(size_type __n); 00759 00760 // DR 1189. 00761 // reserve, if present, comes from _Rehash_base. 00762 00763 private: 00764 // Helper rehash method used when keys are unique. 00765 void _M_rehash_aux(size_type __n, std::true_type); 00766 00767 // Helper rehash method used when keys can be non-unique. 00768 void _M_rehash_aux(size_type __n, std::false_type); 00769 00770 // Unconditionally change size of bucket array to n, restore 00771 // hash policy state to __state on exception. 00772 void _M_rehash(size_type __n, const __rehash_state& __state); 00773 }; 00774 00775 00776 // Definitions of class template _Hashtable's out-of-line member functions. 00777 template<typename _Key, typename _Value, 00778 typename _Alloc, typename _ExtractKey, typename _Equal, 00779 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 00780 typename _Traits> 00781 auto 00782 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 00783 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 00784 _M_bucket_begin(size_type __bkt) const 00785 -> __node_type* 00786 { 00787 __node_base* __n = _M_buckets[__bkt]; 00788 return __n ? static_cast<__node_type*>(__n->_M_nxt) : nullptr; 00789 } 00790 00791 template<typename _Key, typename _Value, 00792 typename _Alloc, typename _ExtractKey, typename _Equal, 00793 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 00794 typename _Traits> 00795 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 00796 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 00797 _Hashtable(size_type __bucket_hint, 00798 const _H1& __h1, const _H2& __h2, const _Hash& __h, 00799 const _Equal& __eq, const _ExtractKey& __exk, 00800 const allocator_type& __a) 00801 : _Hashtable(__h1, __h2, __h, __eq, __exk, __a) 00802 { 00803 auto __bkt = _M_rehash_policy._M_next_bkt(__bucket_hint); 00804 if (__bkt > _M_bucket_count) 00805 { 00806 _M_buckets = _M_allocate_buckets(__bkt); 00807 _M_bucket_count = __bkt; 00808 } 00809 } 00810 00811 template<typename _Key, typename _Value, 00812 typename _Alloc, typename _ExtractKey, typename _Equal, 00813 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 00814 typename _Traits> 00815 template<typename _InputIterator> 00816 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 00817 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 00818 _Hashtable(_InputIterator __f, _InputIterator __l, 00819 size_type __bucket_hint, 00820 const _H1& __h1, const _H2& __h2, const _Hash& __h, 00821 const _Equal& __eq, const _ExtractKey& __exk, 00822 const allocator_type& __a) 00823 : _Hashtable(__h1, __h2, __h, __eq, __exk, __a) 00824 { 00825 auto __nb_elems = __detail::__distance_fw(__f, __l); 00826 auto __bkt_count = 00827 _M_rehash_policy._M_next_bkt( 00828 std::max(_M_rehash_policy._M_bkt_for_elements(__nb_elems), 00829 __bucket_hint)); 00830 00831 if (__bkt_count > _M_bucket_count) 00832 { 00833 _M_buckets = _M_allocate_buckets(__bkt_count); 00834 _M_bucket_count = __bkt_count; 00835 } 00836 00837 for (; __f != __l; ++__f) 00838 this->insert(*__f); 00839 } 00840 00841 template<typename _Key, typename _Value, 00842 typename _Alloc, typename _ExtractKey, typename _Equal, 00843 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 00844 typename _Traits> 00845 auto 00846 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 00847 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 00848 operator=(const _Hashtable& __ht) 00849 -> _Hashtable& 00850 { 00851 if (&__ht == this) 00852 return *this; 00853 00854 if (__node_alloc_traits::_S_propagate_on_copy_assign()) 00855 { 00856 auto& __this_alloc = this->_M_node_allocator(); 00857 auto& __that_alloc = __ht._M_node_allocator(); 00858 if (!__node_alloc_traits::_S_always_equal() 00859 && __this_alloc != __that_alloc) 00860 { 00861 // Replacement allocator cannot free existing storage. 00862 this->_M_deallocate_nodes(_M_begin()); 00863 _M_before_begin._M_nxt = nullptr; 00864 _M_deallocate_buckets(); 00865 _M_buckets = nullptr; 00866 std::__alloc_on_copy(__this_alloc, __that_alloc); 00867 __hashtable_base::operator=(__ht); 00868 _M_bucket_count = __ht._M_bucket_count; 00869 _M_element_count = __ht._M_element_count; 00870 _M_rehash_policy = __ht._M_rehash_policy; 00871 __try 00872 { 00873 _M_assign(__ht, 00874 [this](const __node_type* __n) 00875 { return this->_M_allocate_node(__n->_M_v()); }); 00876 } 00877 __catch(...) 00878 { 00879 // _M_assign took care of deallocating all memory. Now we 00880 // must make sure this instance remains in a usable state. 00881 _M_reset(); 00882 __throw_exception_again; 00883 } 00884 return *this; 00885 } 00886 std::__alloc_on_copy(__this_alloc, __that_alloc); 00887 } 00888 00889 // Reuse allocated buckets and nodes. 00890 __bucket_type* __former_buckets = nullptr; 00891 std::size_t __former_bucket_count = _M_bucket_count; 00892 const __rehash_state& __former_state = _M_rehash_policy._M_state(); 00893 00894 if (_M_bucket_count != __ht._M_bucket_count) 00895 { 00896 __former_buckets = _M_buckets; 00897 _M_buckets = _M_allocate_buckets(__ht._M_bucket_count); 00898 _M_bucket_count = __ht._M_bucket_count; 00899 } 00900 else 00901 __builtin_memset(_M_buckets, 0, 00902 _M_bucket_count * sizeof(__bucket_type)); 00903 00904 __try 00905 { 00906 __hashtable_base::operator=(__ht); 00907 _M_element_count = __ht._M_element_count; 00908 _M_rehash_policy = __ht._M_rehash_policy; 00909 __reuse_or_alloc_node_type __roan(_M_begin(), *this); 00910 _M_before_begin._M_nxt = nullptr; 00911 _M_assign(__ht, 00912 [&__roan](const __node_type* __n) 00913 { return __roan(__n->_M_v()); }); 00914 if (__former_buckets) 00915 _M_deallocate_buckets(__former_buckets, __former_bucket_count); 00916 } 00917 __catch(...) 00918 { 00919 if (__former_buckets) 00920 { 00921 // Restore previous buckets. 00922 _M_deallocate_buckets(); 00923 _M_rehash_policy._M_reset(__former_state); 00924 _M_buckets = __former_buckets; 00925 _M_bucket_count = __former_bucket_count; 00926 } 00927 __builtin_memset(_M_buckets, 0, 00928 _M_bucket_count * sizeof(__bucket_type)); 00929 __throw_exception_again; 00930 } 00931 return *this; 00932 } 00933 00934 template<typename _Key, typename _Value, 00935 typename _Alloc, typename _ExtractKey, typename _Equal, 00936 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 00937 typename _Traits> 00938 template<typename _NodeGenerator> 00939 void 00940 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 00941 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 00942 _M_assign(const _Hashtable& __ht, const _NodeGenerator& __node_gen) 00943 { 00944 __bucket_type* __buckets = nullptr; 00945 if (!_M_buckets) 00946 _M_buckets = __buckets = _M_allocate_buckets(_M_bucket_count); 00947 00948 __try 00949 { 00950 if (!__ht._M_before_begin._M_nxt) 00951 return; 00952 00953 // First deal with the special first node pointed to by 00954 // _M_before_begin. 00955 __node_type* __ht_n = __ht._M_begin(); 00956 __node_type* __this_n = __node_gen(__ht_n); 00957 this->_M_copy_code(__this_n, __ht_n); 00958 _M_before_begin._M_nxt = __this_n; 00959 _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin; 00960 00961 // Then deal with other nodes. 00962 __node_base* __prev_n = __this_n; 00963 for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next()) 00964 { 00965 __this_n = __node_gen(__ht_n); 00966 __prev_n->_M_nxt = __this_n; 00967 this->_M_copy_code(__this_n, __ht_n); 00968 size_type __bkt = _M_bucket_index(__this_n); 00969 if (!_M_buckets[__bkt]) 00970 _M_buckets[__bkt] = __prev_n; 00971 __prev_n = __this_n; 00972 } 00973 } 00974 __catch(...) 00975 { 00976 clear(); 00977 if (__buckets) 00978 _M_deallocate_buckets(); 00979 __throw_exception_again; 00980 } 00981 } 00982 00983 template<typename _Key, typename _Value, 00984 typename _Alloc, typename _ExtractKey, typename _Equal, 00985 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 00986 typename _Traits> 00987 void 00988 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 00989 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 00990 _M_reset() noexcept 00991 { 00992 _M_rehash_policy._M_reset(); 00993 _M_bucket_count = 1; 00994 _M_single_bucket = nullptr; 00995 _M_buckets = &_M_single_bucket; 00996 _M_before_begin._M_nxt = nullptr; 00997 _M_element_count = 0; 00998 } 00999 01000 template<typename _Key, typename _Value, 01001 typename _Alloc, typename _ExtractKey, typename _Equal, 01002 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01003 typename _Traits> 01004 void 01005 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01006 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01007 _M_move_assign(_Hashtable&& __ht, std::true_type) 01008 { 01009 this->_M_deallocate_nodes(_M_begin()); 01010 _M_deallocate_buckets(); 01011 __hashtable_base::operator=(std::move(__ht)); 01012 _M_rehash_policy = __ht._M_rehash_policy; 01013 if (!__ht._M_uses_single_bucket()) 01014 _M_buckets = __ht._M_buckets; 01015 else 01016 { 01017 _M_buckets = &_M_single_bucket; 01018 _M_single_bucket = __ht._M_single_bucket; 01019 } 01020 _M_bucket_count = __ht._M_bucket_count; 01021 _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt; 01022 _M_element_count = __ht._M_element_count; 01023 std::__alloc_on_move(this->_M_node_allocator(), __ht._M_node_allocator()); 01024 01025 // Fix buckets containing the _M_before_begin pointers that can't be 01026 // moved. 01027 if (_M_begin()) 01028 _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 01029 __ht._M_reset(); 01030 } 01031 01032 template<typename _Key, typename _Value, 01033 typename _Alloc, typename _ExtractKey, typename _Equal, 01034 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01035 typename _Traits> 01036 void 01037 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01038 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01039 _M_move_assign(_Hashtable&& __ht, std::false_type) 01040 { 01041 if (__ht._M_node_allocator() == this->_M_node_allocator()) 01042 _M_move_assign(std::move(__ht), std::true_type()); 01043 else 01044 { 01045 // Can't move memory, move elements then. 01046 __bucket_type* __former_buckets = nullptr; 01047 size_type __former_bucket_count = _M_bucket_count; 01048 const __rehash_state& __former_state = _M_rehash_policy._M_state(); 01049 01050 if (_M_bucket_count != __ht._M_bucket_count) 01051 { 01052 __former_buckets = _M_buckets; 01053 _M_buckets = _M_allocate_buckets(__ht._M_bucket_count); 01054 _M_bucket_count = __ht._M_bucket_count; 01055 } 01056 else 01057 __builtin_memset(_M_buckets, 0, 01058 _M_bucket_count * sizeof(__bucket_type)); 01059 01060 __try 01061 { 01062 __hashtable_base::operator=(std::move(__ht)); 01063 _M_element_count = __ht._M_element_count; 01064 _M_rehash_policy = __ht._M_rehash_policy; 01065 __reuse_or_alloc_node_type __roan(_M_begin(), *this); 01066 _M_before_begin._M_nxt = nullptr; 01067 _M_assign(__ht, 01068 [&__roan](__node_type* __n) 01069 { return __roan(std::move_if_noexcept(__n->_M_v())); }); 01070 __ht.clear(); 01071 } 01072 __catch(...) 01073 { 01074 if (__former_buckets) 01075 { 01076 _M_deallocate_buckets(); 01077 _M_rehash_policy._M_reset(__former_state); 01078 _M_buckets = __former_buckets; 01079 _M_bucket_count = __former_bucket_count; 01080 } 01081 __builtin_memset(_M_buckets, 0, 01082 _M_bucket_count * sizeof(__bucket_type)); 01083 __throw_exception_again; 01084 } 01085 } 01086 } 01087 01088 template<typename _Key, typename _Value, 01089 typename _Alloc, typename _ExtractKey, typename _Equal, 01090 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01091 typename _Traits> 01092 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01093 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01094 _Hashtable(const _Hashtable& __ht) 01095 : __hashtable_base(__ht), 01096 __map_base(__ht), 01097 __rehash_base(__ht), 01098 __hashtable_alloc( 01099 __node_alloc_traits::_S_select_on_copy(__ht._M_node_allocator())), 01100 _M_buckets(nullptr), 01101 _M_bucket_count(__ht._M_bucket_count), 01102 _M_element_count(__ht._M_element_count), 01103 _M_rehash_policy(__ht._M_rehash_policy) 01104 { 01105 _M_assign(__ht, 01106 [this](const __node_type* __n) 01107 { return this->_M_allocate_node(__n->_M_v()); }); 01108 } 01109 01110 template<typename _Key, typename _Value, 01111 typename _Alloc, typename _ExtractKey, typename _Equal, 01112 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01113 typename _Traits> 01114 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01115 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01116 _Hashtable(_Hashtable&& __ht) noexcept 01117 : __hashtable_base(__ht), 01118 __map_base(__ht), 01119 __rehash_base(__ht), 01120 __hashtable_alloc(std::move(__ht._M_base_alloc())), 01121 _M_buckets(__ht._M_buckets), 01122 _M_bucket_count(__ht._M_bucket_count), 01123 _M_before_begin(__ht._M_before_begin._M_nxt), 01124 _M_element_count(__ht._M_element_count), 01125 _M_rehash_policy(__ht._M_rehash_policy) 01126 { 01127 // Update, if necessary, buckets if __ht is using its single bucket. 01128 if (__ht._M_uses_single_bucket()) 01129 { 01130 _M_buckets = &_M_single_bucket; 01131 _M_single_bucket = __ht._M_single_bucket; 01132 } 01133 01134 // Update, if necessary, bucket pointing to before begin that hasn't 01135 // moved. 01136 if (_M_begin()) 01137 _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 01138 01139 __ht._M_reset(); 01140 } 01141 01142 template<typename _Key, typename _Value, 01143 typename _Alloc, typename _ExtractKey, typename _Equal, 01144 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01145 typename _Traits> 01146 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01147 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01148 _Hashtable(const _Hashtable& __ht, const allocator_type& __a) 01149 : __hashtable_base(__ht), 01150 __map_base(__ht), 01151 __rehash_base(__ht), 01152 __hashtable_alloc(__node_alloc_type(__a)), 01153 _M_buckets(), 01154 _M_bucket_count(__ht._M_bucket_count), 01155 _M_element_count(__ht._M_element_count), 01156 _M_rehash_policy(__ht._M_rehash_policy) 01157 { 01158 _M_assign(__ht, 01159 [this](const __node_type* __n) 01160 { return this->_M_allocate_node(__n->_M_v()); }); 01161 } 01162 01163 template<typename _Key, typename _Value, 01164 typename _Alloc, typename _ExtractKey, typename _Equal, 01165 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01166 typename _Traits> 01167 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01168 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01169 _Hashtable(_Hashtable&& __ht, const allocator_type& __a) 01170 : __hashtable_base(__ht), 01171 __map_base(__ht), 01172 __rehash_base(__ht), 01173 __hashtable_alloc(__node_alloc_type(__a)), 01174 _M_buckets(nullptr), 01175 _M_bucket_count(__ht._M_bucket_count), 01176 _M_element_count(__ht._M_element_count), 01177 _M_rehash_policy(__ht._M_rehash_policy) 01178 { 01179 if (__ht._M_node_allocator() == this->_M_node_allocator()) 01180 { 01181 if (__ht._M_uses_single_bucket()) 01182 { 01183 _M_buckets = &_M_single_bucket; 01184 _M_single_bucket = __ht._M_single_bucket; 01185 } 01186 else 01187 _M_buckets = __ht._M_buckets; 01188 01189 _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt; 01190 // Update, if necessary, bucket pointing to before begin that hasn't 01191 // moved. 01192 if (_M_begin()) 01193 _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 01194 __ht._M_reset(); 01195 } 01196 else 01197 { 01198 _M_assign(__ht, 01199 [this](__node_type* __n) 01200 { 01201 return this->_M_allocate_node( 01202 std::move_if_noexcept(__n->_M_v())); 01203 }); 01204 __ht.clear(); 01205 } 01206 } 01207 01208 template<typename _Key, typename _Value, 01209 typename _Alloc, typename _ExtractKey, typename _Equal, 01210 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01211 typename _Traits> 01212 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01213 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01214 ~_Hashtable() noexcept 01215 { 01216 clear(); 01217 _M_deallocate_buckets(); 01218 } 01219 01220 template<typename _Key, typename _Value, 01221 typename _Alloc, typename _ExtractKey, typename _Equal, 01222 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01223 typename _Traits> 01224 void 01225 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01226 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01227 swap(_Hashtable& __x) 01228 noexcept(__node_alloc_traits::_S_nothrow_swap()) 01229 { 01230 // The only base class with member variables is hash_code_base. 01231 // We define _Hash_code_base::_M_swap because different 01232 // specializations have different members. 01233 this->_M_swap(__x); 01234 01235 std::__alloc_on_swap(this->_M_node_allocator(), __x._M_node_allocator()); 01236 std::swap(_M_rehash_policy, __x._M_rehash_policy); 01237 01238 // Deal properly with potentially moved instances. 01239 if (this->_M_uses_single_bucket()) 01240 { 01241 if (!__x._M_uses_single_bucket()) 01242 { 01243 _M_buckets = __x._M_buckets; 01244 __x._M_buckets = &__x._M_single_bucket; 01245 } 01246 } 01247 else if (__x._M_uses_single_bucket()) 01248 { 01249 __x._M_buckets = _M_buckets; 01250 _M_buckets = &_M_single_bucket; 01251 } 01252 else 01253 std::swap(_M_buckets, __x._M_buckets); 01254 01255 std::swap(_M_bucket_count, __x._M_bucket_count); 01256 std::swap(_M_before_begin._M_nxt, __x._M_before_begin._M_nxt); 01257 std::swap(_M_element_count, __x._M_element_count); 01258 std::swap(_M_single_bucket, __x._M_single_bucket); 01259 01260 // Fix buckets containing the _M_before_begin pointers that can't be 01261 // swapped. 01262 if (_M_begin()) 01263 _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin; 01264 01265 if (__x._M_begin()) 01266 __x._M_buckets[__x._M_bucket_index(__x._M_begin())] 01267 = &__x._M_before_begin; 01268 } 01269 01270 template<typename _Key, typename _Value, 01271 typename _Alloc, typename _ExtractKey, typename _Equal, 01272 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01273 typename _Traits> 01274 void 01275 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01276 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01277 __rehash_policy(const _RehashPolicy& __pol) 01278 { 01279 auto __do_rehash = 01280 __pol._M_need_rehash(_M_bucket_count, _M_element_count, 0); 01281 if (__do_rehash.first) 01282 _M_rehash(__do_rehash.second, _M_rehash_policy._M_state()); 01283 _M_rehash_policy = __pol; 01284 } 01285 01286 template<typename _Key, typename _Value, 01287 typename _Alloc, typename _ExtractKey, typename _Equal, 01288 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01289 typename _Traits> 01290 auto 01291 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01292 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01293 find(const key_type& __k) 01294 -> iterator 01295 { 01296 __hash_code __code = this->_M_hash_code(__k); 01297 std::size_t __n = _M_bucket_index(__k, __code); 01298 __node_type* __p = _M_find_node(__n, __k, __code); 01299 return __p ? iterator(__p) : end(); 01300 } 01301 01302 template<typename _Key, typename _Value, 01303 typename _Alloc, typename _ExtractKey, typename _Equal, 01304 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01305 typename _Traits> 01306 auto 01307 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01308 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01309 find(const key_type& __k) const 01310 -> const_iterator 01311 { 01312 __hash_code __code = this->_M_hash_code(__k); 01313 std::size_t __n = _M_bucket_index(__k, __code); 01314 __node_type* __p = _M_find_node(__n, __k, __code); 01315 return __p ? const_iterator(__p) : end(); 01316 } 01317 01318 template<typename _Key, typename _Value, 01319 typename _Alloc, typename _ExtractKey, typename _Equal, 01320 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01321 typename _Traits> 01322 auto 01323 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01324 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01325 count(const key_type& __k) const 01326 -> size_type 01327 { 01328 __hash_code __code = this->_M_hash_code(__k); 01329 std::size_t __n = _M_bucket_index(__k, __code); 01330 __node_type* __p = _M_bucket_begin(__n); 01331 if (!__p) 01332 return 0; 01333 01334 std::size_t __result = 0; 01335 for (;; __p = __p->_M_next()) 01336 { 01337 if (this->_M_equals(__k, __code, __p)) 01338 ++__result; 01339 else if (__result) 01340 // All equivalent values are next to each other, if we 01341 // found a non-equivalent value after an equivalent one it 01342 // means that we won't find any new equivalent value. 01343 break; 01344 if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n) 01345 break; 01346 } 01347 return __result; 01348 } 01349 01350 template<typename _Key, typename _Value, 01351 typename _Alloc, typename _ExtractKey, typename _Equal, 01352 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01353 typename _Traits> 01354 auto 01355 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01356 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01357 equal_range(const key_type& __k) 01358 -> pair<iterator, iterator> 01359 { 01360 __hash_code __code = this->_M_hash_code(__k); 01361 std::size_t __n = _M_bucket_index(__k, __code); 01362 __node_type* __p = _M_find_node(__n, __k, __code); 01363 01364 if (__p) 01365 { 01366 __node_type* __p1 = __p->_M_next(); 01367 while (__p1 && _M_bucket_index(__p1) == __n 01368 && this->_M_equals(__k, __code, __p1)) 01369 __p1 = __p1->_M_next(); 01370 01371 return std::make_pair(iterator(__p), iterator(__p1)); 01372 } 01373 else 01374 return std::make_pair(end(), end()); 01375 } 01376 01377 template<typename _Key, typename _Value, 01378 typename _Alloc, typename _ExtractKey, typename _Equal, 01379 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01380 typename _Traits> 01381 auto 01382 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01383 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01384 equal_range(const key_type& __k) const 01385 -> pair<const_iterator, const_iterator> 01386 { 01387 __hash_code __code = this->_M_hash_code(__k); 01388 std::size_t __n = _M_bucket_index(__k, __code); 01389 __node_type* __p = _M_find_node(__n, __k, __code); 01390 01391 if (__p) 01392 { 01393 __node_type* __p1 = __p->_M_next(); 01394 while (__p1 && _M_bucket_index(__p1) == __n 01395 && this->_M_equals(__k, __code, __p1)) 01396 __p1 = __p1->_M_next(); 01397 01398 return std::make_pair(const_iterator(__p), const_iterator(__p1)); 01399 } 01400 else 01401 return std::make_pair(end(), end()); 01402 } 01403 01404 // Find the node whose key compares equal to k in the bucket n. 01405 // Return nullptr if no node is found. 01406 template<typename _Key, typename _Value, 01407 typename _Alloc, typename _ExtractKey, typename _Equal, 01408 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01409 typename _Traits> 01410 auto 01411 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01412 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01413 _M_find_before_node(size_type __n, const key_type& __k, 01414 __hash_code __code) const 01415 -> __node_base* 01416 { 01417 __node_base* __prev_p = _M_buckets[__n]; 01418 if (!__prev_p) 01419 return nullptr; 01420 01421 for (__node_type* __p = static_cast<__node_type*>(__prev_p->_M_nxt);; 01422 __p = __p->_M_next()) 01423 { 01424 if (this->_M_equals(__k, __code, __p)) 01425 return __prev_p; 01426 01427 if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n) 01428 break; 01429 __prev_p = __p; 01430 } 01431 return nullptr; 01432 } 01433 01434 template<typename _Key, typename _Value, 01435 typename _Alloc, typename _ExtractKey, typename _Equal, 01436 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01437 typename _Traits> 01438 void 01439 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01440 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01441 _M_insert_bucket_begin(size_type __bkt, __node_type* __node) 01442 { 01443 if (_M_buckets[__bkt]) 01444 { 01445 // Bucket is not empty, we just need to insert the new node 01446 // after the bucket before begin. 01447 __node->_M_nxt = _M_buckets[__bkt]->_M_nxt; 01448 _M_buckets[__bkt]->_M_nxt = __node; 01449 } 01450 else 01451 { 01452 // The bucket is empty, the new node is inserted at the 01453 // beginning of the singly-linked list and the bucket will 01454 // contain _M_before_begin pointer. 01455 __node->_M_nxt = _M_before_begin._M_nxt; 01456 _M_before_begin._M_nxt = __node; 01457 if (__node->_M_nxt) 01458 // We must update former begin bucket that is pointing to 01459 // _M_before_begin. 01460 _M_buckets[_M_bucket_index(__node->_M_next())] = __node; 01461 _M_buckets[__bkt] = &_M_before_begin; 01462 } 01463 } 01464 01465 template<typename _Key, typename _Value, 01466 typename _Alloc, typename _ExtractKey, typename _Equal, 01467 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01468 typename _Traits> 01469 void 01470 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01471 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01472 _M_remove_bucket_begin(size_type __bkt, __node_type* __next, 01473 size_type __next_bkt) 01474 { 01475 if (!__next || __next_bkt != __bkt) 01476 { 01477 // Bucket is now empty 01478 // First update next bucket if any 01479 if (__next) 01480 _M_buckets[__next_bkt] = _M_buckets[__bkt]; 01481 01482 // Second update before begin node if necessary 01483 if (&_M_before_begin == _M_buckets[__bkt]) 01484 _M_before_begin._M_nxt = __next; 01485 _M_buckets[__bkt] = nullptr; 01486 } 01487 } 01488 01489 template<typename _Key, typename _Value, 01490 typename _Alloc, typename _ExtractKey, typename _Equal, 01491 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01492 typename _Traits> 01493 auto 01494 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01495 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01496 _M_get_previous_node(size_type __bkt, __node_base* __n) 01497 -> __node_base* 01498 { 01499 __node_base* __prev_n = _M_buckets[__bkt]; 01500 while (__prev_n->_M_nxt != __n) 01501 __prev_n = __prev_n->_M_nxt; 01502 return __prev_n; 01503 } 01504 01505 template<typename _Key, typename _Value, 01506 typename _Alloc, typename _ExtractKey, typename _Equal, 01507 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01508 typename _Traits> 01509 template<typename... _Args> 01510 auto 01511 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01512 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01513 _M_emplace(std::true_type, _Args&&... __args) 01514 -> pair<iterator, bool> 01515 { 01516 // First build the node to get access to the hash code 01517 __node_type* __node = this->_M_allocate_node(std::forward<_Args>(__args)...); 01518 const key_type& __k = this->_M_extract()(__node->_M_v()); 01519 __hash_code __code; 01520 __try 01521 { 01522 __code = this->_M_hash_code(__k); 01523 } 01524 __catch(...) 01525 { 01526 this->_M_deallocate_node(__node); 01527 __throw_exception_again; 01528 } 01529 01530 size_type __bkt = _M_bucket_index(__k, __code); 01531 if (__node_type* __p = _M_find_node(__bkt, __k, __code)) 01532 { 01533 // There is already an equivalent node, no insertion 01534 this->_M_deallocate_node(__node); 01535 return std::make_pair(iterator(__p), false); 01536 } 01537 01538 // Insert the node 01539 return std::make_pair(_M_insert_unique_node(__bkt, __code, __node), 01540 true); 01541 } 01542 01543 template<typename _Key, typename _Value, 01544 typename _Alloc, typename _ExtractKey, typename _Equal, 01545 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01546 typename _Traits> 01547 template<typename... _Args> 01548 auto 01549 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01550 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01551 _M_emplace(const_iterator __hint, std::false_type, _Args&&... __args) 01552 -> iterator 01553 { 01554 // First build the node to get its hash code. 01555 __node_type* __node = 01556 this->_M_allocate_node(std::forward<_Args>(__args)...); 01557 01558 __hash_code __code; 01559 __try 01560 { 01561 __code = this->_M_hash_code(this->_M_extract()(__node->_M_v())); 01562 } 01563 __catch(...) 01564 { 01565 this->_M_deallocate_node(__node); 01566 __throw_exception_again; 01567 } 01568 01569 return _M_insert_multi_node(__hint._M_cur, __code, __node); 01570 } 01571 01572 template<typename _Key, typename _Value, 01573 typename _Alloc, typename _ExtractKey, typename _Equal, 01574 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01575 typename _Traits> 01576 auto 01577 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01578 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01579 _M_insert_unique_node(size_type __bkt, __hash_code __code, 01580 __node_type* __node) 01581 -> iterator 01582 { 01583 const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 01584 std::pair<bool, std::size_t> __do_rehash 01585 = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1); 01586 01587 __try 01588 { 01589 if (__do_rehash.first) 01590 { 01591 _M_rehash(__do_rehash.second, __saved_state); 01592 __bkt = _M_bucket_index(this->_M_extract()(__node->_M_v()), __code); 01593 } 01594 01595 this->_M_store_code(__node, __code); 01596 01597 // Always insert at the beginning of the bucket. 01598 _M_insert_bucket_begin(__bkt, __node); 01599 ++_M_element_count; 01600 return iterator(__node); 01601 } 01602 __catch(...) 01603 { 01604 this->_M_deallocate_node(__node); 01605 __throw_exception_again; 01606 } 01607 } 01608 01609 // Insert node, in bucket bkt if no rehash (assumes no element with its key 01610 // already present). Take ownership of the node, deallocate it on exception. 01611 template<typename _Key, typename _Value, 01612 typename _Alloc, typename _ExtractKey, typename _Equal, 01613 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01614 typename _Traits> 01615 auto 01616 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01617 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01618 _M_insert_multi_node(__node_type* __hint, __hash_code __code, 01619 __node_type* __node) 01620 -> iterator 01621 { 01622 const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 01623 std::pair<bool, std::size_t> __do_rehash 01624 = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1); 01625 01626 __try 01627 { 01628 if (__do_rehash.first) 01629 _M_rehash(__do_rehash.second, __saved_state); 01630 01631 this->_M_store_code(__node, __code); 01632 const key_type& __k = this->_M_extract()(__node->_M_v()); 01633 size_type __bkt = _M_bucket_index(__k, __code); 01634 01635 // Find the node before an equivalent one or use hint if it exists and 01636 // if it is equivalent. 01637 __node_base* __prev 01638 = __builtin_expect(__hint != nullptr, false) 01639 && this->_M_equals(__k, __code, __hint) 01640 ? __hint 01641 : _M_find_before_node(__bkt, __k, __code); 01642 if (__prev) 01643 { 01644 // Insert after the node before the equivalent one. 01645 __node->_M_nxt = __prev->_M_nxt; 01646 __prev->_M_nxt = __node; 01647 if (__builtin_expect(__prev == __hint, false)) 01648 // hint might be the last bucket node, in this case we need to 01649 // update next bucket. 01650 if (__node->_M_nxt 01651 && !this->_M_equals(__k, __code, __node->_M_next())) 01652 { 01653 size_type __next_bkt = _M_bucket_index(__node->_M_next()); 01654 if (__next_bkt != __bkt) 01655 _M_buckets[__next_bkt] = __node; 01656 } 01657 } 01658 else 01659 // The inserted node has no equivalent in the 01660 // hashtable. We must insert the new node at the 01661 // beginning of the bucket to preserve equivalent 01662 // elements' relative positions. 01663 _M_insert_bucket_begin(__bkt, __node); 01664 ++_M_element_count; 01665 return iterator(__node); 01666 } 01667 __catch(...) 01668 { 01669 this->_M_deallocate_node(__node); 01670 __throw_exception_again; 01671 } 01672 } 01673 01674 // Insert v if no element with its key is already present. 01675 template<typename _Key, typename _Value, 01676 typename _Alloc, typename _ExtractKey, typename _Equal, 01677 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01678 typename _Traits> 01679 template<typename _Arg, typename _NodeGenerator> 01680 auto 01681 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01682 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01683 _M_insert(_Arg&& __v, const _NodeGenerator& __node_gen, std::true_type) 01684 -> pair<iterator, bool> 01685 { 01686 const key_type& __k = this->_M_extract()(__v); 01687 __hash_code __code = this->_M_hash_code(__k); 01688 size_type __bkt = _M_bucket_index(__k, __code); 01689 01690 __node_type* __n = _M_find_node(__bkt, __k, __code); 01691 if (__n) 01692 return std::make_pair(iterator(__n), false); 01693 01694 __n = __node_gen(std::forward<_Arg>(__v)); 01695 return std::make_pair(_M_insert_unique_node(__bkt, __code, __n), true); 01696 } 01697 01698 // Insert v unconditionally. 01699 template<typename _Key, typename _Value, 01700 typename _Alloc, typename _ExtractKey, typename _Equal, 01701 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01702 typename _Traits> 01703 template<typename _Arg, typename _NodeGenerator> 01704 auto 01705 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01706 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01707 _M_insert(const_iterator __hint, _Arg&& __v, 01708 const _NodeGenerator& __node_gen, std::false_type) 01709 -> iterator 01710 { 01711 // First compute the hash code so that we don't do anything if it 01712 // throws. 01713 __hash_code __code = this->_M_hash_code(this->_M_extract()(__v)); 01714 01715 // Second allocate new node so that we don't rehash if it throws. 01716 __node_type* __node = __node_gen(std::forward<_Arg>(__v)); 01717 01718 return _M_insert_multi_node(__hint._M_cur, __code, __node); 01719 } 01720 01721 template<typename _Key, typename _Value, 01722 typename _Alloc, typename _ExtractKey, typename _Equal, 01723 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01724 typename _Traits> 01725 auto 01726 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01727 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01728 erase(const_iterator __it) 01729 -> iterator 01730 { 01731 __node_type* __n = __it._M_cur; 01732 std::size_t __bkt = _M_bucket_index(__n); 01733 01734 // Look for previous node to unlink it from the erased one, this 01735 // is why we need buckets to contain the before begin to make 01736 // this search fast. 01737 __node_base* __prev_n = _M_get_previous_node(__bkt, __n); 01738 return _M_erase(__bkt, __prev_n, __n); 01739 } 01740 01741 template<typename _Key, typename _Value, 01742 typename _Alloc, typename _ExtractKey, typename _Equal, 01743 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01744 typename _Traits> 01745 auto 01746 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01747 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01748 _M_erase(size_type __bkt, __node_base* __prev_n, __node_type* __n) 01749 -> iterator 01750 { 01751 if (__prev_n == _M_buckets[__bkt]) 01752 _M_remove_bucket_begin(__bkt, __n->_M_next(), 01753 __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0); 01754 else if (__n->_M_nxt) 01755 { 01756 size_type __next_bkt = _M_bucket_index(__n->_M_next()); 01757 if (__next_bkt != __bkt) 01758 _M_buckets[__next_bkt] = __prev_n; 01759 } 01760 01761 __prev_n->_M_nxt = __n->_M_nxt; 01762 iterator __result(__n->_M_next()); 01763 this->_M_deallocate_node(__n); 01764 --_M_element_count; 01765 01766 return __result; 01767 } 01768 01769 template<typename _Key, typename _Value, 01770 typename _Alloc, typename _ExtractKey, typename _Equal, 01771 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01772 typename _Traits> 01773 auto 01774 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01775 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01776 _M_erase(std::true_type, const key_type& __k) 01777 -> size_type 01778 { 01779 __hash_code __code = this->_M_hash_code(__k); 01780 std::size_t __bkt = _M_bucket_index(__k, __code); 01781 01782 // Look for the node before the first matching node. 01783 __node_base* __prev_n = _M_find_before_node(__bkt, __k, __code); 01784 if (!__prev_n) 01785 return 0; 01786 01787 // We found a matching node, erase it. 01788 __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt); 01789 _M_erase(__bkt, __prev_n, __n); 01790 return 1; 01791 } 01792 01793 template<typename _Key, typename _Value, 01794 typename _Alloc, typename _ExtractKey, typename _Equal, 01795 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01796 typename _Traits> 01797 auto 01798 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01799 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01800 _M_erase(std::false_type, const key_type& __k) 01801 -> size_type 01802 { 01803 __hash_code __code = this->_M_hash_code(__k); 01804 std::size_t __bkt = _M_bucket_index(__k, __code); 01805 01806 // Look for the node before the first matching node. 01807 __node_base* __prev_n = _M_find_before_node(__bkt, __k, __code); 01808 if (!__prev_n) 01809 return 0; 01810 01811 // _GLIBCXX_RESOLVE_LIB_DEFECTS 01812 // 526. Is it undefined if a function in the standard changes 01813 // in parameters? 01814 // We use one loop to find all matching nodes and another to deallocate 01815 // them so that the key stays valid during the first loop. It might be 01816 // invalidated indirectly when destroying nodes. 01817 __node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt); 01818 __node_type* __n_last = __n; 01819 std::size_t __n_last_bkt = __bkt; 01820 do 01821 { 01822 __n_last = __n_last->_M_next(); 01823 if (!__n_last) 01824 break; 01825 __n_last_bkt = _M_bucket_index(__n_last); 01826 } 01827 while (__n_last_bkt == __bkt && this->_M_equals(__k, __code, __n_last)); 01828 01829 // Deallocate nodes. 01830 size_type __result = 0; 01831 do 01832 { 01833 __node_type* __p = __n->_M_next(); 01834 this->_M_deallocate_node(__n); 01835 __n = __p; 01836 ++__result; 01837 --_M_element_count; 01838 } 01839 while (__n != __n_last); 01840 01841 if (__prev_n == _M_buckets[__bkt]) 01842 _M_remove_bucket_begin(__bkt, __n_last, __n_last_bkt); 01843 else if (__n_last && __n_last_bkt != __bkt) 01844 _M_buckets[__n_last_bkt] = __prev_n; 01845 __prev_n->_M_nxt = __n_last; 01846 return __result; 01847 } 01848 01849 template<typename _Key, typename _Value, 01850 typename _Alloc, typename _ExtractKey, typename _Equal, 01851 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01852 typename _Traits> 01853 auto 01854 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01855 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01856 erase(const_iterator __first, const_iterator __last) 01857 -> iterator 01858 { 01859 __node_type* __n = __first._M_cur; 01860 __node_type* __last_n = __last._M_cur; 01861 if (__n == __last_n) 01862 return iterator(__n); 01863 01864 std::size_t __bkt = _M_bucket_index(__n); 01865 01866 __node_base* __prev_n = _M_get_previous_node(__bkt, __n); 01867 bool __is_bucket_begin = __n == _M_bucket_begin(__bkt); 01868 std::size_t __n_bkt = __bkt; 01869 for (;;) 01870 { 01871 do 01872 { 01873 __node_type* __tmp = __n; 01874 __n = __n->_M_next(); 01875 this->_M_deallocate_node(__tmp); 01876 --_M_element_count; 01877 if (!__n) 01878 break; 01879 __n_bkt = _M_bucket_index(__n); 01880 } 01881 while (__n != __last_n && __n_bkt == __bkt); 01882 if (__is_bucket_begin) 01883 _M_remove_bucket_begin(__bkt, __n, __n_bkt); 01884 if (__n == __last_n) 01885 break; 01886 __is_bucket_begin = true; 01887 __bkt = __n_bkt; 01888 } 01889 01890 if (__n && (__n_bkt != __bkt || __is_bucket_begin)) 01891 _M_buckets[__n_bkt] = __prev_n; 01892 __prev_n->_M_nxt = __n; 01893 return iterator(__n); 01894 } 01895 01896 template<typename _Key, typename _Value, 01897 typename _Alloc, typename _ExtractKey, typename _Equal, 01898 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01899 typename _Traits> 01900 void 01901 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01902 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01903 clear() noexcept 01904 { 01905 this->_M_deallocate_nodes(_M_begin()); 01906 __builtin_memset(_M_buckets, 0, _M_bucket_count * sizeof(__bucket_type)); 01907 _M_element_count = 0; 01908 _M_before_begin._M_nxt = nullptr; 01909 } 01910 01911 template<typename _Key, typename _Value, 01912 typename _Alloc, typename _ExtractKey, typename _Equal, 01913 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01914 typename _Traits> 01915 void 01916 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01917 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01918 rehash(size_type __n) 01919 { 01920 const __rehash_state& __saved_state = _M_rehash_policy._M_state(); 01921 std::size_t __buckets 01922 = std::max(_M_rehash_policy._M_bkt_for_elements(_M_element_count + 1), 01923 __n); 01924 __buckets = _M_rehash_policy._M_next_bkt(__buckets); 01925 01926 if (__buckets != _M_bucket_count) 01927 _M_rehash(__buckets, __saved_state); 01928 else 01929 // No rehash, restore previous state to keep a consistent state. 01930 _M_rehash_policy._M_reset(__saved_state); 01931 } 01932 01933 template<typename _Key, typename _Value, 01934 typename _Alloc, typename _ExtractKey, typename _Equal, 01935 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01936 typename _Traits> 01937 void 01938 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01939 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01940 _M_rehash(size_type __n, const __rehash_state& __state) 01941 { 01942 __try 01943 { 01944 _M_rehash_aux(__n, __unique_keys()); 01945 } 01946 __catch(...) 01947 { 01948 // A failure here means that buckets allocation failed. We only 01949 // have to restore hash policy previous state. 01950 _M_rehash_policy._M_reset(__state); 01951 __throw_exception_again; 01952 } 01953 } 01954 01955 // Rehash when there is no equivalent elements. 01956 template<typename _Key, typename _Value, 01957 typename _Alloc, typename _ExtractKey, typename _Equal, 01958 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 01959 typename _Traits> 01960 void 01961 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 01962 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 01963 _M_rehash_aux(size_type __n, std::true_type) 01964 { 01965 __bucket_type* __new_buckets = _M_allocate_buckets(__n); 01966 __node_type* __p = _M_begin(); 01967 _M_before_begin._M_nxt = nullptr; 01968 std::size_t __bbegin_bkt = 0; 01969 while (__p) 01970 { 01971 __node_type* __next = __p->_M_next(); 01972 std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); 01973 if (!__new_buckets[__bkt]) 01974 { 01975 __p->_M_nxt = _M_before_begin._M_nxt; 01976 _M_before_begin._M_nxt = __p; 01977 __new_buckets[__bkt] = &_M_before_begin; 01978 if (__p->_M_nxt) 01979 __new_buckets[__bbegin_bkt] = __p; 01980 __bbegin_bkt = __bkt; 01981 } 01982 else 01983 { 01984 __p->_M_nxt = __new_buckets[__bkt]->_M_nxt; 01985 __new_buckets[__bkt]->_M_nxt = __p; 01986 } 01987 __p = __next; 01988 } 01989 01990 _M_deallocate_buckets(); 01991 _M_bucket_count = __n; 01992 _M_buckets = __new_buckets; 01993 } 01994 01995 // Rehash when there can be equivalent elements, preserve their relative 01996 // order. 01997 template<typename _Key, typename _Value, 01998 typename _Alloc, typename _ExtractKey, typename _Equal, 01999 typename _H1, typename _H2, typename _Hash, typename _RehashPolicy, 02000 typename _Traits> 02001 void 02002 _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, 02003 _H1, _H2, _Hash, _RehashPolicy, _Traits>:: 02004 _M_rehash_aux(size_type __n, std::false_type) 02005 { 02006 __bucket_type* __new_buckets = _M_allocate_buckets(__n); 02007 02008 __node_type* __p = _M_begin(); 02009 _M_before_begin._M_nxt = nullptr; 02010 std::size_t __bbegin_bkt = 0; 02011 std::size_t __prev_bkt = 0; 02012 __node_type* __prev_p = nullptr; 02013 bool __check_bucket = false; 02014 02015 while (__p) 02016 { 02017 __node_type* __next = __p->_M_next(); 02018 std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); 02019 02020 if (__prev_p && __prev_bkt == __bkt) 02021 { 02022 // Previous insert was already in this bucket, we insert after 02023 // the previously inserted one to preserve equivalent elements 02024 // relative order. 02025 __p->_M_nxt = __prev_p->_M_nxt; 02026 __prev_p->_M_nxt = __p; 02027 02028 // Inserting after a node in a bucket require to check that we 02029 // haven't change the bucket last node, in this case next 02030 // bucket containing its before begin node must be updated. We 02031 // schedule a check as soon as we move out of the sequence of 02032 // equivalent nodes to limit the number of checks. 02033 __check_bucket = true; 02034 } 02035 else 02036 { 02037 if (__check_bucket) 02038 { 02039 // Check if we shall update the next bucket because of 02040 // insertions into __prev_bkt bucket. 02041 if (__prev_p->_M_nxt) 02042 { 02043 std::size_t __next_bkt 02044 = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), 02045 __n); 02046 if (__next_bkt != __prev_bkt) 02047 __new_buckets[__next_bkt] = __prev_p; 02048 } 02049 __check_bucket = false; 02050 } 02051 02052 if (!__new_buckets[__bkt]) 02053 { 02054 __p->_M_nxt = _M_before_begin._M_nxt; 02055 _M_before_begin._M_nxt = __p; 02056 __new_buckets[__bkt] = &_M_before_begin; 02057 if (__p->_M_nxt) 02058 __new_buckets[__bbegin_bkt] = __p; 02059 __bbegin_bkt = __bkt; 02060 } 02061 else 02062 { 02063 __p->_M_nxt = __new_buckets[__bkt]->_M_nxt; 02064 __new_buckets[__bkt]->_M_nxt = __p; 02065 } 02066 } 02067 __prev_p = __p; 02068 __prev_bkt = __bkt; 02069 __p = __next; 02070 } 02071 02072 if (__check_bucket && __prev_p->_M_nxt) 02073 { 02074 std::size_t __next_bkt 02075 = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), __n); 02076 if (__next_bkt != __prev_bkt) 02077 __new_buckets[__next_bkt] = __prev_p; 02078 } 02079 02080 _M_deallocate_buckets(); 02081 _M_bucket_count = __n; 02082 _M_buckets = __new_buckets; 02083 } 02084 02085 _GLIBCXX_END_NAMESPACE_VERSION 02086 } // namespace std 02087 02088 #endif // _HASHTABLE_H