Line data Source code
1 : // hashtable.h header -*- C++ -*-
2 :
3 : // Copyright (C) 2007-2023 Free Software Foundation, Inc.
4 : //
5 : // This file is part of the GNU ISO C++ Library. This library is free
6 : // software; you can redistribute it and/or modify it under the
7 : // terms of the GNU General Public License as published by the
8 : // Free Software Foundation; either version 3, or (at your option)
9 : // any later version.
10 :
11 : // This library is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 :
16 : // Under Section 7 of GPL version 3, you are granted additional
17 : // permissions described in the GCC Runtime Library Exception, version
18 : // 3.1, as published by the Free Software Foundation.
19 :
20 : // You should have received a copy of the GNU General Public License and
21 : // a copy of the GCC Runtime Library Exception along with this program;
22 : // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 : // <http://www.gnu.org/licenses/>.
24 :
25 : /** @file bits/hashtable.h
26 : * This is an internal header file, included by other library headers.
27 : * Do not attempt to use it directly. @headername{unordered_map, unordered_set}
28 : */
29 :
30 : #ifndef _HASHTABLE_H
31 : #define _HASHTABLE_H 1
32 :
33 : #pragma GCC system_header
34 :
35 : #include <bits/hashtable_policy.h>
36 : #include <bits/enable_special_members.h>
37 : #include <bits/stl_function.h> // __has_is_transparent_t
38 : #if __cplusplus > 201402L
39 : # include <bits/node_handle.h>
40 : #endif
41 :
42 : namespace std _GLIBCXX_VISIBILITY(default)
43 : {
44 : _GLIBCXX_BEGIN_NAMESPACE_VERSION
45 : /// @cond undocumented
46 :
47 : template<typename _Tp, typename _Hash>
48 : using __cache_default
49 : = __not_<__and_<// Do not cache for fast hasher.
50 : __is_fast_hash<_Hash>,
51 : // Mandatory to have erase not throwing.
52 : __is_nothrow_invocable<const _Hash&, const _Tp&>>>;
53 :
54 : // Helper to conditionally delete the default constructor.
55 : // The _Hash_node_base type is used to distinguish this specialization
56 : // from any other potentially-overlapping subobjects of the hashtable.
57 : template<typename _Equal, typename _Hash, typename _Allocator>
58 : using _Hashtable_enable_default_ctor
59 : = _Enable_default_constructor<__and_<is_default_constructible<_Equal>,
60 : is_default_constructible<_Hash>,
61 : is_default_constructible<_Allocator>>{},
62 : __detail::_Hash_node_base>;
63 :
64 : /**
65 : * Primary class template _Hashtable.
66 : *
67 : * @ingroup hashtable-detail
68 : *
69 : * @tparam _Value CopyConstructible type.
70 : *
71 : * @tparam _Key CopyConstructible type.
72 : *
73 : * @tparam _Alloc An allocator type
74 : * ([lib.allocator.requirements]) whose _Alloc::value_type is
75 : * _Value. As a conforming extension, we allow for
76 : * _Alloc::value_type != _Value.
77 : *
78 : * @tparam _ExtractKey Function object that takes an object of type
79 : * _Value and returns a value of type _Key.
80 : *
81 : * @tparam _Equal Function object that takes two objects of type k
82 : * and returns a bool-like value that is true if the two objects
83 : * are considered equal.
84 : *
85 : * @tparam _Hash The hash function. A unary function object with
86 : * argument type _Key and result type size_t. Return values should
87 : * be distributed over the entire range [0, numeric_limits<size_t>:::max()].
88 : *
89 : * @tparam _RangeHash The range-hashing function (in the terminology of
90 : * Tavori and Dreizin). A binary function object whose argument
91 : * types and result type are all size_t. Given arguments r and N,
92 : * the return value is in the range [0, N).
93 : *
94 : * @tparam _Unused Not used.
95 : *
96 : * @tparam _RehashPolicy Policy class with three members, all of
97 : * which govern the bucket count. _M_next_bkt(n) returns a bucket
98 : * count no smaller than n. _M_bkt_for_elements(n) returns a
99 : * bucket count appropriate for an element count of n.
100 : * _M_need_rehash(n_bkt, n_elt, n_ins) determines whether, if the
101 : * current bucket count is n_bkt and the current element count is
102 : * n_elt, we need to increase the bucket count for n_ins insertions.
103 : * If so, returns make_pair(true, n), where n is the new bucket count. If
104 : * not, returns make_pair(false, <anything>)
105 : *
106 : * @tparam _Traits Compile-time class with three boolean
107 : * std::integral_constant members: __cache_hash_code, __constant_iterators,
108 : * __unique_keys.
109 : *
110 : * Each _Hashtable data structure has:
111 : *
112 : * - _Bucket[] _M_buckets
113 : * - _Hash_node_base _M_before_begin
114 : * - size_type _M_bucket_count
115 : * - size_type _M_element_count
116 : *
117 : * with _Bucket being _Hash_node_base* and _Hash_node containing:
118 : *
119 : * - _Hash_node* _M_next
120 : * - Tp _M_value
121 : * - size_t _M_hash_code if cache_hash_code is true
122 : *
123 : * In terms of Standard containers the hashtable is like the aggregation of:
124 : *
125 : * - std::forward_list<_Node> containing the elements
126 : * - std::vector<std::forward_list<_Node>::iterator> representing the buckets
127 : *
128 : * The non-empty buckets contain the node before the first node in the
129 : * bucket. This design makes it possible to implement something like a
130 : * std::forward_list::insert_after on container insertion and
131 : * std::forward_list::erase_after on container erase
132 : * calls. _M_before_begin is equivalent to
133 : * std::forward_list::before_begin. Empty buckets contain
134 : * nullptr. Note that one of the non-empty buckets contains
135 : * &_M_before_begin which is not a dereferenceable node so the
136 : * node pointer in a bucket shall never be dereferenced, only its
137 : * next node can be.
138 : *
139 : * Walking through a bucket's nodes requires a check on the hash code to
140 : * see if each node is still in the bucket. Such a design assumes a
141 : * quite efficient hash functor and is one of the reasons it is
142 : * highly advisable to set __cache_hash_code to true.
143 : *
144 : * The container iterators are simply built from nodes. This way
145 : * incrementing the iterator is perfectly efficient independent of
146 : * how many empty buckets there are in the container.
147 : *
148 : * On insert we compute the element's hash code and use it to find the
149 : * bucket index. If the element must be inserted in an empty bucket
150 : * we add it at the beginning of the singly linked list and make the
151 : * bucket point to _M_before_begin. The bucket that used to point to
152 : * _M_before_begin, if any, is updated to point to its new before
153 : * begin node.
154 : *
155 : * On erase, the simple iterator design requires using the hash
156 : * functor to get the index of the bucket to update. For this
157 : * reason, when __cache_hash_code is set to false the hash functor must
158 : * not throw and this is enforced by a static assertion.
159 : *
160 : * Functionality is implemented by decomposition into base classes,
161 : * where the derived _Hashtable class is used in _Map_base,
162 : * _Insert, _Rehash_base, and _Equality base classes to access the
163 : * "this" pointer. _Hashtable_base is used in the base classes as a
164 : * non-recursive, fully-completed-type so that detailed nested type
165 : * information, such as iterator type and node type, can be
166 : * used. This is similar to the "Curiously Recurring Template
167 : * Pattern" (CRTP) technique, but uses a reconstructed, not
168 : * explicitly passed, template pattern.
169 : *
170 : * Base class templates are:
171 : * - __detail::_Hashtable_base
172 : * - __detail::_Map_base
173 : * - __detail::_Insert
174 : * - __detail::_Rehash_base
175 : * - __detail::_Equality
176 : */
177 : template<typename _Key, typename _Value, typename _Alloc,
178 : typename _ExtractKey, typename _Equal,
179 : typename _Hash, typename _RangeHash, typename _Unused,
180 : typename _RehashPolicy, typename _Traits>
181 : class _Hashtable
182 : : public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
183 : _Hash, _RangeHash, _Unused, _Traits>,
184 : public __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
185 : _Hash, _RangeHash, _Unused,
186 : _RehashPolicy, _Traits>,
187 : public __detail::_Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal,
188 : _Hash, _RangeHash, _Unused,
189 : _RehashPolicy, _Traits>,
190 : public __detail::_Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
191 : _Hash, _RangeHash, _Unused,
192 : _RehashPolicy, _Traits>,
193 : public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal,
194 : _Hash, _RangeHash, _Unused,
195 : _RehashPolicy, _Traits>,
196 : private __detail::_Hashtable_alloc<
197 : __alloc_rebind<_Alloc,
198 : __detail::_Hash_node<_Value,
199 : _Traits::__hash_cached::value>>>,
200 : private _Hashtable_enable_default_ctor<_Equal, _Hash, _Alloc>
201 : {
202 : static_assert(is_same<typename remove_cv<_Value>::type, _Value>::value,
203 : "unordered container must have a non-const, non-volatile value_type");
204 : #if __cplusplus > 201703L || defined __STRICT_ANSI__
205 : static_assert(is_same<typename _Alloc::value_type, _Value>{},
206 : "unordered container must have the same value_type as its allocator");
207 : #endif
208 :
209 : using __traits_type = _Traits;
210 : using __hash_cached = typename __traits_type::__hash_cached;
211 : using __constant_iterators = typename __traits_type::__constant_iterators;
212 : using __node_type = __detail::_Hash_node<_Value, __hash_cached::value>;
213 : using __node_alloc_type = __alloc_rebind<_Alloc, __node_type>;
214 :
215 : using __hashtable_alloc = __detail::_Hashtable_alloc<__node_alloc_type>;
216 :
217 : using __node_value_type =
218 : __detail::_Hash_node_value<_Value, __hash_cached::value>;
219 : using __node_ptr = typename __hashtable_alloc::__node_ptr;
220 : using __value_alloc_traits =
221 : typename __hashtable_alloc::__value_alloc_traits;
222 : using __node_alloc_traits =
223 : typename __hashtable_alloc::__node_alloc_traits;
224 : using __node_base = typename __hashtable_alloc::__node_base;
225 : using __node_base_ptr = typename __hashtable_alloc::__node_base_ptr;
226 : using __buckets_ptr = typename __hashtable_alloc::__buckets_ptr;
227 :
228 : using __insert_base = __detail::_Insert<_Key, _Value, _Alloc, _ExtractKey,
229 : _Equal, _Hash,
230 : _RangeHash, _Unused,
231 : _RehashPolicy, _Traits>;
232 : using __enable_default_ctor
233 : = _Hashtable_enable_default_ctor<_Equal, _Hash, _Alloc>;
234 :
235 : public:
236 : typedef _Key key_type;
237 : typedef _Value value_type;
238 : typedef _Alloc allocator_type;
239 : typedef _Equal key_equal;
240 :
241 : // mapped_type, if present, comes from _Map_base.
242 : // hasher, if present, comes from _Hash_code_base/_Hashtable_base.
243 : typedef typename __value_alloc_traits::pointer pointer;
244 : typedef typename __value_alloc_traits::const_pointer const_pointer;
245 : typedef value_type& reference;
246 : typedef const value_type& const_reference;
247 :
248 : using iterator = typename __insert_base::iterator;
249 :
250 : using const_iterator = typename __insert_base::const_iterator;
251 :
252 : using local_iterator = __detail::_Local_iterator<key_type, _Value,
253 : _ExtractKey, _Hash, _RangeHash, _Unused,
254 : __constant_iterators::value,
255 : __hash_cached::value>;
256 :
257 : using const_local_iterator = __detail::_Local_const_iterator<
258 : key_type, _Value,
259 : _ExtractKey, _Hash, _RangeHash, _Unused,
260 : __constant_iterators::value, __hash_cached::value>;
261 :
262 : private:
263 : using __rehash_type = _RehashPolicy;
264 : using __rehash_state = typename __rehash_type::_State;
265 :
266 : using __unique_keys = typename __traits_type::__unique_keys;
267 :
268 : using __hashtable_base = __detail::
269 : _Hashtable_base<_Key, _Value, _ExtractKey,
270 : _Equal, _Hash, _RangeHash, _Unused, _Traits>;
271 :
272 : using __hash_code_base = typename __hashtable_base::__hash_code_base;
273 : using __hash_code = typename __hashtable_base::__hash_code;
274 : using __ireturn_type = typename __insert_base::__ireturn_type;
275 :
276 : using __map_base = __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey,
277 : _Equal, _Hash, _RangeHash, _Unused,
278 : _RehashPolicy, _Traits>;
279 :
280 : using __rehash_base = __detail::_Rehash_base<_Key, _Value, _Alloc,
281 : _ExtractKey, _Equal,
282 : _Hash, _RangeHash, _Unused,
283 : _RehashPolicy, _Traits>;
284 :
285 : using __eq_base = __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey,
286 : _Equal, _Hash, _RangeHash, _Unused,
287 : _RehashPolicy, _Traits>;
288 :
289 : using __reuse_or_alloc_node_gen_t =
290 : __detail::_ReuseOrAllocNode<__node_alloc_type>;
291 : using __alloc_node_gen_t =
292 : __detail::_AllocNode<__node_alloc_type>;
293 : using __node_builder_t =
294 : __detail::_NodeBuilder<_ExtractKey>;
295 :
296 : // Simple RAII type for managing a node containing an element
297 : struct _Scoped_node
298 : {
299 : // Take ownership of a node with a constructed element.
300 61162 : _Scoped_node(__node_ptr __n, __hashtable_alloc* __h)
301 61162 : : _M_h(__h), _M_node(__n) { }
302 :
303 : // Allocate a node and construct an element within it.
304 : template<typename... _Args>
305 198996 : _Scoped_node(__hashtable_alloc* __h, _Args&&... __args)
306 198996 : : _M_h(__h),
307 198996 : _M_node(__h->_M_allocate_node(std::forward<_Args>(__args)...))
308 198996 : { }
309 :
310 : // Destroy element and deallocate node.
311 260158 : ~_Scoped_node() { if (_M_node) _M_h->_M_deallocate_node(_M_node); };
312 :
313 : _Scoped_node(const _Scoped_node&) = delete;
314 : _Scoped_node& operator=(const _Scoped_node&) = delete;
315 :
316 : __hashtable_alloc* _M_h;
317 : __node_ptr _M_node;
318 : };
319 :
320 : template<typename _Ht>
321 : static constexpr
322 : __conditional_t<std::is_lvalue_reference<_Ht>::value,
323 : const value_type&, value_type&&>
324 : __fwd_value_for(value_type& __val) noexcept
325 : { return std::move(__val); }
326 :
327 : // Compile-time diagnostics.
328 :
329 : // _Hash_code_base has everything protected, so use this derived type to
330 : // access it.
331 : struct __hash_code_base_access : __hash_code_base
332 : { using __hash_code_base::_M_bucket_index; };
333 :
334 : // To get bucket index we need _RangeHash not to throw.
335 : static_assert(is_nothrow_default_constructible<_RangeHash>::value,
336 : "Functor used to map hash code to bucket index"
337 : " must be nothrow default constructible");
338 : static_assert(noexcept(
339 : std::declval<const _RangeHash&>()((std::size_t)0, (std::size_t)0)),
340 : "Functor used to map hash code to bucket index must be"
341 : " noexcept");
342 :
343 : // To compute bucket index we also need _ExtratKey not to throw.
344 : static_assert(is_nothrow_default_constructible<_ExtractKey>::value,
345 : "_ExtractKey must be nothrow default constructible");
346 : static_assert(noexcept(
347 : std::declval<const _ExtractKey&>()(std::declval<_Value>())),
348 : "_ExtractKey functor must be noexcept invocable");
349 :
350 : template<typename _Keya, typename _Valuea, typename _Alloca,
351 : typename _ExtractKeya, typename _Equala,
352 : typename _Hasha, typename _RangeHasha, typename _Unuseda,
353 : typename _RehashPolicya, typename _Traitsa,
354 : bool _Unique_keysa>
355 : friend struct __detail::_Map_base;
356 :
357 : template<typename _Keya, typename _Valuea, typename _Alloca,
358 : typename _ExtractKeya, typename _Equala,
359 : typename _Hasha, typename _RangeHasha, typename _Unuseda,
360 : typename _RehashPolicya, typename _Traitsa>
361 : friend struct __detail::_Insert_base;
362 :
363 : template<typename _Keya, typename _Valuea, typename _Alloca,
364 : typename _ExtractKeya, typename _Equala,
365 : typename _Hasha, typename _RangeHasha, typename _Unuseda,
366 : typename _RehashPolicya, typename _Traitsa,
367 : bool _Constant_iteratorsa>
368 : friend struct __detail::_Insert;
369 :
370 : template<typename _Keya, typename _Valuea, typename _Alloca,
371 : typename _ExtractKeya, typename _Equala,
372 : typename _Hasha, typename _RangeHasha, typename _Unuseda,
373 : typename _RehashPolicya, typename _Traitsa,
374 : bool _Unique_keysa>
375 : friend struct __detail::_Equality;
376 :
377 : public:
378 : using size_type = typename __hashtable_base::size_type;
379 : using difference_type = typename __hashtable_base::difference_type;
380 :
381 : #if __cplusplus > 201402L
382 : using node_type = _Node_handle<_Key, _Value, __node_alloc_type>;
383 : using insert_return_type = _Node_insert_return<iterator, node_type>;
384 : #endif
385 :
386 : private:
387 : __buckets_ptr _M_buckets = &_M_single_bucket;
388 : size_type _M_bucket_count = 1;
389 : __node_base _M_before_begin;
390 : size_type _M_element_count = 0;
391 : _RehashPolicy _M_rehash_policy;
392 :
393 : // A single bucket used when only need for 1 bucket. Especially
394 : // interesting in move semantic to leave hashtable with only 1 bucket
395 : // which is not allocated so that we can have those operations noexcept
396 : // qualified.
397 : // Note that we can't leave hashtable with 0 bucket without adding
398 : // numerous checks in the code to avoid 0 modulus.
399 : __node_base_ptr _M_single_bucket = nullptr;
400 :
401 : void
402 : _M_update_bbegin()
403 : {
404 : if (_M_begin())
405 : _M_buckets[_M_bucket_index(*_M_begin())] = &_M_before_begin;
406 : }
407 :
408 : void
409 : _M_update_bbegin(__node_ptr __n)
410 : {
411 : _M_before_begin._M_nxt = __n;
412 : _M_update_bbegin();
413 : }
414 :
415 : bool
416 240284 : _M_uses_single_bucket(__buckets_ptr __bkts) const
417 240284 : { return __builtin_expect(__bkts == &_M_single_bucket, false); }
418 :
419 : bool
420 : _M_uses_single_bucket() const
421 : { return _M_uses_single_bucket(_M_buckets); }
422 :
423 : static constexpr size_t
424 194614 : __small_size_threshold() noexcept
425 : {
426 : return
427 194614 : __detail::_Hashtable_hash_traits<_Hash>::__small_size_threshold();
428 : }
429 :
430 : __hashtable_alloc&
431 : _M_base_alloc() { return *this; }
432 :
433 : __buckets_ptr
434 116628 : _M_allocate_buckets(size_type __bkt_count)
435 : {
436 116628 : if (__builtin_expect(__bkt_count == 1, false))
437 : {
438 0 : _M_single_bucket = nullptr;
439 0 : return &_M_single_bucket;
440 : }
441 :
442 116628 : return __hashtable_alloc::_M_allocate_buckets(__bkt_count);
443 : }
444 :
445 : void
446 240284 : _M_deallocate_buckets(__buckets_ptr __bkts, size_type __bkt_count)
447 : {
448 240284 : if (_M_uses_single_bucket(__bkts))
449 123658 : return;
450 :
451 116626 : __hashtable_alloc::_M_deallocate_buckets(__bkts, __bkt_count);
452 : }
453 :
454 : void
455 240284 : _M_deallocate_buckets()
456 240284 : { _M_deallocate_buckets(_M_buckets, _M_bucket_count); }
457 :
458 : // Gets bucket begin, deals with the fact that non-empty buckets contain
459 : // their before begin node.
460 : __node_ptr
461 : _M_bucket_begin(size_type __bkt) const;
462 :
463 : __node_ptr
464 393732 : _M_begin() const
465 393732 : { return static_cast<__node_ptr>(_M_before_begin._M_nxt); }
466 :
467 : // Assign *this using another _Hashtable instance. Whether elements
468 : // are copied or moved depends on the _Ht reference.
469 : template<typename _Ht>
470 : void
471 : _M_assign_elements(_Ht&&);
472 :
473 : template<typename _Ht, typename _NodeGenerator>
474 : void
475 : _M_assign(_Ht&&, const _NodeGenerator&);
476 :
477 : void
478 : _M_move_assign(_Hashtable&&, true_type);
479 :
480 : void
481 : _M_move_assign(_Hashtable&&, false_type);
482 :
483 : void
484 : _M_reset() noexcept;
485 :
486 : _Hashtable(const _Hash& __h, const _Equal& __eq,
487 : const allocator_type& __a)
488 : : __hashtable_base(__h, __eq),
489 : __hashtable_alloc(__node_alloc_type(__a)),
490 : __enable_default_ctor(_Enable_default_constructor_tag{})
491 : { }
492 :
493 : template<bool _No_realloc = true>
494 : static constexpr bool
495 : _S_nothrow_move()
496 : {
497 : #if __cplusplus <= 201402L
498 : return __and_<__bool_constant<_No_realloc>,
499 : is_nothrow_copy_constructible<_Hash>,
500 : is_nothrow_copy_constructible<_Equal>>::value;
501 : #else
502 : if constexpr (_No_realloc)
503 : if constexpr (is_nothrow_copy_constructible<_Hash>())
504 : return is_nothrow_copy_constructible<_Equal>();
505 : return false;
506 : #endif
507 : }
508 :
509 : _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a,
510 : true_type /* alloc always equal */)
511 : noexcept(_S_nothrow_move());
512 :
513 : _Hashtable(_Hashtable&&, __node_alloc_type&&,
514 : false_type /* alloc always equal */);
515 :
516 : template<typename _InputIterator>
517 : _Hashtable(_InputIterator __first, _InputIterator __last,
518 : size_type __bkt_count_hint,
519 : const _Hash&, const _Equal&, const allocator_type&,
520 : true_type __uks);
521 :
522 : template<typename _InputIterator>
523 : _Hashtable(_InputIterator __first, _InputIterator __last,
524 : size_type __bkt_count_hint,
525 : const _Hash&, const _Equal&, const allocator_type&,
526 : false_type __uks);
527 :
528 : public:
529 : // Constructor, destructor, assignment, swap
530 123656 : _Hashtable() = default;
531 :
532 : _Hashtable(const _Hashtable&);
533 :
534 : _Hashtable(const _Hashtable&, const allocator_type&);
535 :
536 : explicit
537 : _Hashtable(size_type __bkt_count_hint,
538 : const _Hash& __hf = _Hash(),
539 : const key_equal& __eql = key_equal(),
540 : const allocator_type& __a = allocator_type());
541 :
542 : // Use delegating constructors.
543 : _Hashtable(_Hashtable&& __ht)
544 : noexcept(_S_nothrow_move())
545 : : _Hashtable(std::move(__ht), std::move(__ht._M_node_allocator()),
546 : true_type{})
547 : { }
548 :
549 : _Hashtable(_Hashtable&& __ht, const allocator_type& __a)
550 : noexcept(_S_nothrow_move<__node_alloc_traits::_S_always_equal()>())
551 : : _Hashtable(std::move(__ht), __node_alloc_type(__a),
552 : typename __node_alloc_traits::is_always_equal{})
553 : { }
554 :
555 : explicit
556 : _Hashtable(const allocator_type& __a)
557 : : __hashtable_alloc(__node_alloc_type(__a)),
558 : __enable_default_ctor(_Enable_default_constructor_tag{})
559 : { }
560 :
561 : template<typename _InputIterator>
562 : _Hashtable(_InputIterator __f, _InputIterator __l,
563 : size_type __bkt_count_hint = 0,
564 : const _Hash& __hf = _Hash(),
565 : const key_equal& __eql = key_equal(),
566 : const allocator_type& __a = allocator_type())
567 : : _Hashtable(__f, __l, __bkt_count_hint, __hf, __eql, __a,
568 : __unique_keys{})
569 : { }
570 :
571 : _Hashtable(initializer_list<value_type> __l,
572 : size_type __bkt_count_hint = 0,
573 : const _Hash& __hf = _Hash(),
574 : const key_equal& __eql = key_equal(),
575 : const allocator_type& __a = allocator_type())
576 : : _Hashtable(__l.begin(), __l.end(), __bkt_count_hint,
577 : __hf, __eql, __a, __unique_keys{})
578 : { }
579 :
580 : _Hashtable&
581 : operator=(const _Hashtable& __ht);
582 :
583 : _Hashtable&
584 : operator=(_Hashtable&& __ht)
585 : noexcept(__node_alloc_traits::_S_nothrow_move()
586 : && is_nothrow_move_assignable<_Hash>::value
587 : && is_nothrow_move_assignable<_Equal>::value)
588 : {
589 : constexpr bool __move_storage =
590 : __node_alloc_traits::_S_propagate_on_move_assign()
591 : || __node_alloc_traits::_S_always_equal();
592 : _M_move_assign(std::move(__ht), __bool_constant<__move_storage>());
593 : return *this;
594 : }
595 :
596 : _Hashtable&
597 : operator=(initializer_list<value_type> __l)
598 : {
599 : __reuse_or_alloc_node_gen_t __roan(_M_begin(), *this);
600 : _M_before_begin._M_nxt = nullptr;
601 : clear();
602 :
603 : // We consider that all elements of __l are going to be inserted.
604 : auto __l_bkt_count = _M_rehash_policy._M_bkt_for_elements(__l.size());
605 :
606 : // Do not shrink to keep potential user reservation.
607 : if (_M_bucket_count < __l_bkt_count)
608 : rehash(__l_bkt_count);
609 :
610 : this->_M_insert_range(__l.begin(), __l.end(), __roan, __unique_keys{});
611 : return *this;
612 : }
613 :
614 : ~_Hashtable() noexcept;
615 :
616 : void
617 : swap(_Hashtable&)
618 : noexcept(__and_<__is_nothrow_swappable<_Hash>,
619 : __is_nothrow_swappable<_Equal>>::value);
620 :
621 : // Basic container operations
622 : iterator
623 153448 : begin() noexcept
624 153448 : { return iterator(_M_begin()); }
625 :
626 : const_iterator
627 : begin() const noexcept
628 : { return const_iterator(_M_begin()); }
629 :
630 : iterator
631 284938 : end() noexcept
632 284938 : { return iterator(nullptr); }
633 :
634 : const_iterator
635 : end() const noexcept
636 : { return const_iterator(nullptr); }
637 :
638 : const_iterator
639 : cbegin() const noexcept
640 : { return const_iterator(_M_begin()); }
641 :
642 : const_iterator
643 : cend() const noexcept
644 : { return const_iterator(nullptr); }
645 :
646 : size_type
647 194614 : size() const noexcept
648 194614 : { return _M_element_count; }
649 :
650 : _GLIBCXX_NODISCARD bool
651 : empty() const noexcept
652 : { return size() == 0; }
653 :
654 : allocator_type
655 : get_allocator() const noexcept
656 : { return allocator_type(this->_M_node_allocator()); }
657 :
658 : size_type
659 : max_size() const noexcept
660 : { return __node_alloc_traits::max_size(this->_M_node_allocator()); }
661 :
662 : // Observers
663 : key_equal
664 : key_eq() const
665 : { return this->_M_eq(); }
666 :
667 : // hash_function, if present, comes from _Hash_code_base.
668 :
669 : // Bucket operations
670 : size_type
671 : bucket_count() const noexcept
672 : { return _M_bucket_count; }
673 :
674 : size_type
675 : max_bucket_count() const noexcept
676 : { return max_size(); }
677 :
678 : size_type
679 : bucket_size(size_type __bkt) const
680 : { return std::distance(begin(__bkt), end(__bkt)); }
681 :
682 : size_type
683 : bucket(const key_type& __k) const
684 : { return _M_bucket_index(this->_M_hash_code(__k)); }
685 :
686 : local_iterator
687 : begin(size_type __bkt)
688 : {
689 : return local_iterator(*this, _M_bucket_begin(__bkt),
690 : __bkt, _M_bucket_count);
691 : }
692 :
693 : local_iterator
694 : end(size_type __bkt)
695 : { return local_iterator(*this, nullptr, __bkt, _M_bucket_count); }
696 :
697 : const_local_iterator
698 : begin(size_type __bkt) const
699 : {
700 : return const_local_iterator(*this, _M_bucket_begin(__bkt),
701 : __bkt, _M_bucket_count);
702 : }
703 :
704 : const_local_iterator
705 : end(size_type __bkt) const
706 : { return const_local_iterator(*this, nullptr, __bkt, _M_bucket_count); }
707 :
708 : // DR 691.
709 : const_local_iterator
710 : cbegin(size_type __bkt) const
711 : {
712 : return const_local_iterator(*this, _M_bucket_begin(__bkt),
713 : __bkt, _M_bucket_count);
714 : }
715 :
716 : const_local_iterator
717 : cend(size_type __bkt) const
718 : { return const_local_iterator(*this, nullptr, __bkt, _M_bucket_count); }
719 :
720 : float
721 : load_factor() const noexcept
722 : {
723 : return static_cast<float>(size()) / static_cast<float>(bucket_count());
724 : }
725 :
726 : // max_load_factor, if present, comes from _Rehash_base.
727 :
728 : // Generalization of max_load_factor. Extension, not found in
729 : // TR1. Only useful if _RehashPolicy is something other than
730 : // the default.
731 : const _RehashPolicy&
732 : __rehash_policy() const
733 : { return _M_rehash_policy; }
734 :
735 : void
736 : __rehash_policy(const _RehashPolicy& __pol)
737 : { _M_rehash_policy = __pol; }
738 :
739 : // Lookup.
740 : iterator
741 : find(const key_type& __k);
742 :
743 : const_iterator
744 : find(const key_type& __k) const;
745 :
746 : size_type
747 : count(const key_type& __k) const;
748 :
749 : std::pair<iterator, iterator>
750 : equal_range(const key_type& __k);
751 :
752 : std::pair<const_iterator, const_iterator>
753 : equal_range(const key_type& __k) const;
754 :
755 : #if __cplusplus >= 202002L
756 : #define __cpp_lib_generic_unordered_lookup 201811L
757 :
758 : template<typename _Kt,
759 : typename = __has_is_transparent_t<_Hash, _Kt>,
760 : typename = __has_is_transparent_t<_Equal, _Kt>>
761 : iterator
762 : _M_find_tr(const _Kt& __k);
763 :
764 : template<typename _Kt,
765 : typename = __has_is_transparent_t<_Hash, _Kt>,
766 : typename = __has_is_transparent_t<_Equal, _Kt>>
767 : const_iterator
768 : _M_find_tr(const _Kt& __k) const;
769 :
770 : template<typename _Kt,
771 : typename = __has_is_transparent_t<_Hash, _Kt>,
772 : typename = __has_is_transparent_t<_Equal, _Kt>>
773 : size_type
774 : _M_count_tr(const _Kt& __k) const;
775 :
776 : template<typename _Kt,
777 : typename = __has_is_transparent_t<_Hash, _Kt>,
778 : typename = __has_is_transparent_t<_Equal, _Kt>>
779 : pair<iterator, iterator>
780 : _M_equal_range_tr(const _Kt& __k);
781 :
782 : template<typename _Kt,
783 : typename = __has_is_transparent_t<_Hash, _Kt>,
784 : typename = __has_is_transparent_t<_Equal, _Kt>>
785 : pair<const_iterator, const_iterator>
786 : _M_equal_range_tr(const _Kt& __k) const;
787 : #endif // C++20
788 :
789 : private:
790 : // Bucket index computation helpers.
791 : size_type
792 184146 : _M_bucket_index(const __node_value_type& __n) const noexcept
793 184146 : { return __hash_code_base::_M_bucket_index(__n, _M_bucket_count); }
794 :
795 : size_type
796 6106460 : _M_bucket_index(__hash_code __c) const
797 6106460 : { return __hash_code_base::_M_bucket_index(__c, _M_bucket_count); }
798 :
799 : __node_base_ptr
800 : _M_find_before_node(const key_type&);
801 :
802 : // Find and insert helper functions and types
803 : // Find the node before the one matching the criteria.
804 : __node_base_ptr
805 : _M_find_before_node(size_type, const key_type&, __hash_code) const;
806 :
807 : template<typename _Kt>
808 : __node_base_ptr
809 : _M_find_before_node_tr(size_type, const _Kt&, __hash_code) const;
810 :
811 : __node_ptr
812 5928642 : _M_find_node(size_type __bkt, const key_type& __key,
813 : __hash_code __c) const
814 : {
815 5928642 : __node_base_ptr __before_n = _M_find_before_node(__bkt, __key, __c);
816 5928642 : if (__before_n)
817 5724128 : return static_cast<__node_ptr>(__before_n->_M_nxt);
818 204514 : return nullptr;
819 : }
820 :
821 : template<typename _Kt>
822 : __node_ptr
823 2832 : _M_find_node_tr(size_type __bkt, const _Kt& __key,
824 : __hash_code __c) const
825 : {
826 2832 : auto __before_n = _M_find_before_node_tr(__bkt, __key, __c);
827 2832 : if (__before_n)
828 2 : return static_cast<__node_ptr>(__before_n->_M_nxt);
829 2830 : return nullptr;
830 : }
831 :
832 : // Insert a node at the beginning of a bucket.
833 : void
834 : _M_insert_bucket_begin(size_type, __node_ptr);
835 :
836 : // Remove the bucket first node
837 : void
838 : _M_remove_bucket_begin(size_type __bkt, __node_ptr __next_n,
839 : size_type __next_bkt);
840 :
841 : // Get the node before __n in the bucket __bkt
842 : __node_base_ptr
843 : _M_get_previous_node(size_type __bkt, __node_ptr __n);
844 :
845 : pair<const_iterator, __hash_code>
846 : _M_compute_hash_code(const_iterator __hint, const key_type& __k) const;
847 :
848 : // Insert node __n with hash code __code, in bucket __bkt if no
849 : // rehash (assumes no element with same key already present).
850 : // Takes ownership of __n if insertion succeeds, throws otherwise.
851 : iterator
852 : _M_insert_unique_node(size_type __bkt, __hash_code,
853 : __node_ptr __n, size_type __n_elt = 1);
854 :
855 : // Insert node __n with key __k and hash code __code.
856 : // Takes ownership of __n if insertion succeeds, throws otherwise.
857 : iterator
858 : _M_insert_multi_node(__node_ptr __hint,
859 : __hash_code __code, __node_ptr __n);
860 :
861 : template<typename... _Args>
862 : std::pair<iterator, bool>
863 : _M_emplace(true_type __uks, _Args&&... __args);
864 :
865 : template<typename... _Args>
866 : iterator
867 : _M_emplace(false_type __uks, _Args&&... __args)
868 : { return _M_emplace(cend(), __uks, std::forward<_Args>(__args)...); }
869 :
870 : // Emplace with hint, useless when keys are unique.
871 : template<typename... _Args>
872 : iterator
873 : _M_emplace(const_iterator, true_type __uks, _Args&&... __args)
874 : { return _M_emplace(__uks, std::forward<_Args>(__args)...).first; }
875 :
876 : template<typename... _Args>
877 : iterator
878 : _M_emplace(const_iterator, false_type __uks, _Args&&... __args);
879 :
880 : template<typename _Kt, typename _Arg, typename _NodeGenerator>
881 : std::pair<iterator, bool>
882 : _M_insert_unique(_Kt&&, _Arg&&, const _NodeGenerator&);
883 :
884 : template<typename _Kt>
885 : static __conditional_t<
886 : __and_<__is_nothrow_invocable<_Hash&, const key_type&>,
887 : __not_<__is_nothrow_invocable<_Hash&, _Kt>>>::value,
888 : key_type, _Kt&&>
889 : _S_forward_key(_Kt&& __k)
890 : { return std::forward<_Kt>(__k); }
891 :
892 : static const key_type&
893 61166 : _S_forward_key(const key_type& __k)
894 61166 : { return __k; }
895 :
896 : static key_type&&
897 : _S_forward_key(key_type&& __k)
898 : { return std::move(__k); }
899 :
900 : template<typename _Arg, typename _NodeGenerator>
901 : std::pair<iterator, bool>
902 61166 : _M_insert_unique_aux(_Arg&& __arg, const _NodeGenerator& __node_gen)
903 : {
904 122332 : return _M_insert_unique(
905 122332 : _S_forward_key(_ExtractKey{}(std::forward<_Arg>(__arg))),
906 122332 : std::forward<_Arg>(__arg), __node_gen);
907 : }
908 :
909 : template<typename _Arg, typename _NodeGenerator>
910 : std::pair<iterator, bool>
911 61166 : _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen,
912 : true_type /* __uks */)
913 : {
914 : using __to_value
915 : = __detail::_ConvertToValueType<_ExtractKey, value_type>;
916 122332 : return _M_insert_unique_aux(
917 122332 : __to_value{}(std::forward<_Arg>(__arg)), __node_gen);
918 : }
919 :
920 : template<typename _Arg, typename _NodeGenerator>
921 : iterator
922 : _M_insert(_Arg&& __arg, const _NodeGenerator& __node_gen,
923 : false_type __uks)
924 : {
925 : using __to_value
926 : = __detail::_ConvertToValueType<_ExtractKey, value_type>;
927 : return _M_insert(cend(),
928 : __to_value{}(std::forward<_Arg>(__arg)), __node_gen, __uks);
929 : }
930 :
931 : // Insert with hint, not used when keys are unique.
932 : template<typename _Arg, typename _NodeGenerator>
933 : iterator
934 : _M_insert(const_iterator, _Arg&& __arg,
935 : const _NodeGenerator& __node_gen, true_type __uks)
936 : {
937 : return
938 : _M_insert(std::forward<_Arg>(__arg), __node_gen, __uks).first;
939 : }
940 :
941 : // Insert with hint when keys are not unique.
942 : template<typename _Arg, typename _NodeGenerator>
943 : iterator
944 : _M_insert(const_iterator, _Arg&&,
945 : const _NodeGenerator&, false_type __uks);
946 :
947 : size_type
948 : _M_erase(true_type __uks, const key_type&);
949 :
950 : size_type
951 : _M_erase(false_type __uks, const key_type&);
952 :
953 : iterator
954 : _M_erase(size_type __bkt, __node_base_ptr __prev_n, __node_ptr __n);
955 :
956 : public:
957 : // Emplace
958 : template<typename... _Args>
959 : __ireturn_type
960 30 : emplace(_Args&&... __args)
961 30 : { return _M_emplace(__unique_keys{}, std::forward<_Args>(__args)...); }
962 :
963 : template<typename... _Args>
964 : iterator
965 : emplace_hint(const_iterator __hint, _Args&&... __args)
966 : {
967 : return _M_emplace(__hint, __unique_keys{},
968 : std::forward<_Args>(__args)...);
969 : }
970 :
971 : // Insert member functions via inheritance.
972 :
973 : // Erase
974 : iterator
975 : erase(const_iterator);
976 :
977 : // LWG 2059.
978 : iterator
979 : erase(iterator __it)
980 : { return erase(const_iterator(__it)); }
981 :
982 : size_type
983 30520 : erase(const key_type& __k)
984 30520 : { return _M_erase(__unique_keys{}, __k); }
985 :
986 : iterator
987 : erase(const_iterator, const_iterator);
988 :
989 : void
990 : clear() noexcept;
991 :
992 : // Set number of buckets keeping it appropriate for container's number
993 : // of elements.
994 : void rehash(size_type __bkt_count);
995 :
996 : // DR 1189.
997 : // reserve, if present, comes from _Rehash_base.
998 :
999 : #if __cplusplus > 201402L
1000 : /// Re-insert an extracted node into a container with unique keys.
1001 : insert_return_type
1002 : _M_reinsert_node(node_type&& __nh)
1003 : {
1004 : insert_return_type __ret;
1005 : if (__nh.empty())
1006 : __ret.position = end();
1007 : else
1008 : {
1009 : __glibcxx_assert(get_allocator() == __nh.get_allocator());
1010 :
1011 : const key_type& __k = __nh._M_key();
1012 : __hash_code __code = this->_M_hash_code(__k);
1013 : size_type __bkt = _M_bucket_index(__code);
1014 : if (__node_ptr __n = _M_find_node(__bkt, __k, __code))
1015 : {
1016 : __ret.node = std::move(__nh);
1017 : __ret.position = iterator(__n);
1018 : __ret.inserted = false;
1019 : }
1020 : else
1021 : {
1022 : __ret.position
1023 : = _M_insert_unique_node(__bkt, __code, __nh._M_ptr);
1024 : __nh._M_ptr = nullptr;
1025 : __ret.inserted = true;
1026 : }
1027 : }
1028 : return __ret;
1029 : }
1030 :
1031 : /// Re-insert an extracted node into a container with equivalent keys.
1032 : iterator
1033 : _M_reinsert_node_multi(const_iterator __hint, node_type&& __nh)
1034 : {
1035 : if (__nh.empty())
1036 : return end();
1037 :
1038 : __glibcxx_assert(get_allocator() == __nh.get_allocator());
1039 :
1040 : const key_type& __k = __nh._M_key();
1041 : auto __code = this->_M_hash_code(__k);
1042 : auto __ret
1043 : = _M_insert_multi_node(__hint._M_cur, __code, __nh._M_ptr);
1044 : __nh._M_ptr = nullptr;
1045 : return __ret;
1046 : }
1047 :
1048 : private:
1049 : node_type
1050 : _M_extract_node(size_t __bkt, __node_base_ptr __prev_n)
1051 : {
1052 : __node_ptr __n = static_cast<__node_ptr>(__prev_n->_M_nxt);
1053 : if (__prev_n == _M_buckets[__bkt])
1054 : _M_remove_bucket_begin(__bkt, __n->_M_next(),
1055 : __n->_M_nxt ? _M_bucket_index(*__n->_M_next()) : 0);
1056 : else if (__n->_M_nxt)
1057 : {
1058 : size_type __next_bkt = _M_bucket_index(*__n->_M_next());
1059 : if (__next_bkt != __bkt)
1060 : _M_buckets[__next_bkt] = __prev_n;
1061 : }
1062 :
1063 : __prev_n->_M_nxt = __n->_M_nxt;
1064 : __n->_M_nxt = nullptr;
1065 : --_M_element_count;
1066 : return { __n, this->_M_node_allocator() };
1067 : }
1068 :
1069 : // Only use the possibly cached node's hash code if its hash function
1070 : // _H2 matches _Hash and is stateless. Otherwise recompute it using _Hash.
1071 : template<typename _H2>
1072 : __hash_code
1073 : _M_src_hash_code(const _H2&, const key_type& __k,
1074 : const __node_value_type& __src_n) const
1075 : {
1076 : if constexpr (std::is_same_v<_H2, _Hash>)
1077 : if constexpr (std::is_empty_v<_Hash>)
1078 : return this->_M_hash_code(__src_n);
1079 :
1080 : return this->_M_hash_code(__k);
1081 : }
1082 :
1083 : public:
1084 : // Extract a node.
1085 : node_type
1086 : extract(const_iterator __pos)
1087 : {
1088 : size_t __bkt = _M_bucket_index(*__pos._M_cur);
1089 : return _M_extract_node(__bkt,
1090 : _M_get_previous_node(__bkt, __pos._M_cur));
1091 : }
1092 :
1093 : /// Extract a node.
1094 : node_type
1095 : extract(const _Key& __k)
1096 : {
1097 : node_type __nh;
1098 : __hash_code __code = this->_M_hash_code(__k);
1099 : std::size_t __bkt = _M_bucket_index(__code);
1100 : if (__node_base_ptr __prev_node = _M_find_before_node(__bkt, __k, __code))
1101 : __nh = _M_extract_node(__bkt, __prev_node);
1102 : return __nh;
1103 : }
1104 :
1105 : /// Merge from a compatible container into one with unique keys.
1106 : template<typename _Compatible_Hashtable>
1107 : void
1108 : _M_merge_unique(_Compatible_Hashtable& __src)
1109 : {
1110 : static_assert(is_same_v<typename _Compatible_Hashtable::node_type,
1111 : node_type>, "Node types are compatible");
1112 : __glibcxx_assert(get_allocator() == __src.get_allocator());
1113 :
1114 : auto __n_elt = __src.size();
1115 : for (auto __i = __src.cbegin(), __end = __src.cend(); __i != __end;)
1116 : {
1117 : auto __pos = __i++;
1118 : const key_type& __k = _ExtractKey{}(*__pos);
1119 : __hash_code __code
1120 : = _M_src_hash_code(__src.hash_function(), __k, *__pos._M_cur);
1121 : size_type __bkt = _M_bucket_index(__code);
1122 : if (_M_find_node(__bkt, __k, __code) == nullptr)
1123 : {
1124 : auto __nh = __src.extract(__pos);
1125 : _M_insert_unique_node(__bkt, __code, __nh._M_ptr, __n_elt);
1126 : __nh._M_ptr = nullptr;
1127 : __n_elt = 1;
1128 : }
1129 : else if (__n_elt != 1)
1130 : --__n_elt;
1131 : }
1132 : }
1133 :
1134 : /// Merge from a compatible container into one with equivalent keys.
1135 : template<typename _Compatible_Hashtable>
1136 : void
1137 : _M_merge_multi(_Compatible_Hashtable& __src)
1138 : {
1139 : static_assert(is_same_v<typename _Compatible_Hashtable::node_type,
1140 : node_type>, "Node types are compatible");
1141 : __glibcxx_assert(get_allocator() == __src.get_allocator());
1142 :
1143 : __node_ptr __hint = nullptr;
1144 : this->reserve(size() + __src.size());
1145 : for (auto __i = __src.cbegin(), __end = __src.cend(); __i != __end;)
1146 : {
1147 : auto __pos = __i++;
1148 : const key_type& __k = _ExtractKey{}(*__pos);
1149 : __hash_code __code
1150 : = _M_src_hash_code(__src.hash_function(), __k, *__pos._M_cur);
1151 : auto __nh = __src.extract(__pos);
1152 : __hint = _M_insert_multi_node(__hint, __code, __nh._M_ptr)._M_cur;
1153 : __nh._M_ptr = nullptr;
1154 : }
1155 : }
1156 : #endif // C++17
1157 :
1158 : private:
1159 : // Helper rehash method used when keys are unique.
1160 : void _M_rehash_aux(size_type __bkt_count, true_type __uks);
1161 :
1162 : // Helper rehash method used when keys can be non-unique.
1163 : void _M_rehash_aux(size_type __bkt_count, false_type __uks);
1164 :
1165 : // Unconditionally change size of bucket array to n, restore
1166 : // hash policy state to __state on exception.
1167 : void _M_rehash(size_type __bkt_count, const __rehash_state& __state);
1168 : };
1169 :
1170 : // Definitions of class template _Hashtable's out-of-line member functions.
1171 : template<typename _Key, typename _Value, typename _Alloc,
1172 : typename _ExtractKey, typename _Equal,
1173 : typename _Hash, typename _RangeHash, typename _Unused,
1174 : typename _RehashPolicy, typename _Traits>
1175 : auto
1176 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1177 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1178 : _M_bucket_begin(size_type __bkt) const
1179 : -> __node_ptr
1180 : {
1181 : __node_base_ptr __n = _M_buckets[__bkt];
1182 : return __n ? static_cast<__node_ptr>(__n->_M_nxt) : nullptr;
1183 : }
1184 :
1185 : template<typename _Key, typename _Value, typename _Alloc,
1186 : typename _ExtractKey, typename _Equal,
1187 : typename _Hash, typename _RangeHash, typename _Unused,
1188 : typename _RehashPolicy, typename _Traits>
1189 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1190 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1191 : _Hashtable(size_type __bkt_count_hint,
1192 : const _Hash& __h, const _Equal& __eq, const allocator_type& __a)
1193 : : _Hashtable(__h, __eq, __a)
1194 : {
1195 : auto __bkt_count = _M_rehash_policy._M_next_bkt(__bkt_count_hint);
1196 : if (__bkt_count > _M_bucket_count)
1197 : {
1198 : _M_buckets = _M_allocate_buckets(__bkt_count);
1199 : _M_bucket_count = __bkt_count;
1200 : }
1201 : }
1202 :
1203 : template<typename _Key, typename _Value, typename _Alloc,
1204 : typename _ExtractKey, typename _Equal,
1205 : typename _Hash, typename _RangeHash, typename _Unused,
1206 : typename _RehashPolicy, typename _Traits>
1207 : template<typename _InputIterator>
1208 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1209 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1210 : _Hashtable(_InputIterator __f, _InputIterator __l,
1211 : size_type __bkt_count_hint,
1212 : const _Hash& __h, const _Equal& __eq,
1213 : const allocator_type& __a, true_type /* __uks */)
1214 : : _Hashtable(__bkt_count_hint, __h, __eq, __a)
1215 : { this->insert(__f, __l); }
1216 :
1217 : template<typename _Key, typename _Value, typename _Alloc,
1218 : typename _ExtractKey, typename _Equal,
1219 : typename _Hash, typename _RangeHash, typename _Unused,
1220 : typename _RehashPolicy, typename _Traits>
1221 : template<typename _InputIterator>
1222 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1223 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1224 : _Hashtable(_InputIterator __f, _InputIterator __l,
1225 : size_type __bkt_count_hint,
1226 : const _Hash& __h, const _Equal& __eq,
1227 : const allocator_type& __a, false_type __uks)
1228 : : _Hashtable(__h, __eq, __a)
1229 : {
1230 : auto __nb_elems = __detail::__distance_fw(__f, __l);
1231 : auto __bkt_count =
1232 : _M_rehash_policy._M_next_bkt(
1233 : std::max(_M_rehash_policy._M_bkt_for_elements(__nb_elems),
1234 : __bkt_count_hint));
1235 :
1236 : if (__bkt_count > _M_bucket_count)
1237 : {
1238 : _M_buckets = _M_allocate_buckets(__bkt_count);
1239 : _M_bucket_count = __bkt_count;
1240 : }
1241 :
1242 : __alloc_node_gen_t __node_gen(*this);
1243 : for (; __f != __l; ++__f)
1244 : _M_insert(*__f, __node_gen, __uks);
1245 : }
1246 :
1247 : template<typename _Key, typename _Value, typename _Alloc,
1248 : typename _ExtractKey, typename _Equal,
1249 : typename _Hash, typename _RangeHash, typename _Unused,
1250 : typename _RehashPolicy, typename _Traits>
1251 : auto
1252 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1253 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1254 : operator=(const _Hashtable& __ht)
1255 : -> _Hashtable&
1256 : {
1257 : if (&__ht == this)
1258 : return *this;
1259 :
1260 : if (__node_alloc_traits::_S_propagate_on_copy_assign())
1261 : {
1262 : auto& __this_alloc = this->_M_node_allocator();
1263 : auto& __that_alloc = __ht._M_node_allocator();
1264 : if (!__node_alloc_traits::_S_always_equal()
1265 : && __this_alloc != __that_alloc)
1266 : {
1267 : // Replacement allocator cannot free existing storage.
1268 : this->_M_deallocate_nodes(_M_begin());
1269 : _M_before_begin._M_nxt = nullptr;
1270 : _M_deallocate_buckets();
1271 : _M_buckets = nullptr;
1272 : std::__alloc_on_copy(__this_alloc, __that_alloc);
1273 : __hashtable_base::operator=(__ht);
1274 : _M_bucket_count = __ht._M_bucket_count;
1275 : _M_element_count = __ht._M_element_count;
1276 : _M_rehash_policy = __ht._M_rehash_policy;
1277 : __alloc_node_gen_t __alloc_node_gen(*this);
1278 : __try
1279 : {
1280 : _M_assign(__ht, __alloc_node_gen);
1281 : }
1282 : __catch(...)
1283 : {
1284 : // _M_assign took care of deallocating all memory. Now we
1285 : // must make sure this instance remains in a usable state.
1286 : _M_reset();
1287 : __throw_exception_again;
1288 : }
1289 : return *this;
1290 : }
1291 : std::__alloc_on_copy(__this_alloc, __that_alloc);
1292 : }
1293 :
1294 : // Reuse allocated buckets and nodes.
1295 : _M_assign_elements(__ht);
1296 : return *this;
1297 : }
1298 :
1299 : template<typename _Key, typename _Value, typename _Alloc,
1300 : typename _ExtractKey, typename _Equal,
1301 : typename _Hash, typename _RangeHash, typename _Unused,
1302 : typename _RehashPolicy, typename _Traits>
1303 : template<typename _Ht>
1304 : void
1305 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1306 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1307 : _M_assign_elements(_Ht&& __ht)
1308 : {
1309 : __buckets_ptr __former_buckets = nullptr;
1310 : std::size_t __former_bucket_count = _M_bucket_count;
1311 : const __rehash_state& __former_state = _M_rehash_policy._M_state();
1312 :
1313 : if (_M_bucket_count != __ht._M_bucket_count)
1314 : {
1315 : __former_buckets = _M_buckets;
1316 : _M_buckets = _M_allocate_buckets(__ht._M_bucket_count);
1317 : _M_bucket_count = __ht._M_bucket_count;
1318 : }
1319 : else
1320 : __builtin_memset(_M_buckets, 0,
1321 : _M_bucket_count * sizeof(__node_base_ptr));
1322 :
1323 : __try
1324 : {
1325 : __hashtable_base::operator=(std::forward<_Ht>(__ht));
1326 : _M_element_count = __ht._M_element_count;
1327 : _M_rehash_policy = __ht._M_rehash_policy;
1328 : __reuse_or_alloc_node_gen_t __roan(_M_begin(), *this);
1329 : _M_before_begin._M_nxt = nullptr;
1330 : _M_assign(std::forward<_Ht>(__ht), __roan);
1331 : if (__former_buckets)
1332 : _M_deallocate_buckets(__former_buckets, __former_bucket_count);
1333 : }
1334 : __catch(...)
1335 : {
1336 : if (__former_buckets)
1337 : {
1338 : // Restore previous buckets.
1339 : _M_deallocate_buckets();
1340 : _M_rehash_policy._M_reset(__former_state);
1341 : _M_buckets = __former_buckets;
1342 : _M_bucket_count = __former_bucket_count;
1343 : }
1344 : __builtin_memset(_M_buckets, 0,
1345 : _M_bucket_count * sizeof(__node_base_ptr));
1346 : __throw_exception_again;
1347 : }
1348 : }
1349 :
1350 : template<typename _Key, typename _Value, typename _Alloc,
1351 : typename _ExtractKey, typename _Equal,
1352 : typename _Hash, typename _RangeHash, typename _Unused,
1353 : typename _RehashPolicy, typename _Traits>
1354 : template<typename _Ht, typename _NodeGenerator>
1355 : void
1356 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1357 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1358 : _M_assign(_Ht&& __ht, const _NodeGenerator& __node_gen)
1359 : {
1360 : __buckets_ptr __buckets = nullptr;
1361 : if (!_M_buckets)
1362 : _M_buckets = __buckets = _M_allocate_buckets(_M_bucket_count);
1363 :
1364 : __try
1365 : {
1366 : if (!__ht._M_before_begin._M_nxt)
1367 : return;
1368 :
1369 : // First deal with the special first node pointed to by
1370 : // _M_before_begin.
1371 : __node_ptr __ht_n = __ht._M_begin();
1372 : __node_ptr __this_n
1373 : = __node_gen(__fwd_value_for<_Ht>(__ht_n->_M_v()));
1374 : this->_M_copy_code(*__this_n, *__ht_n);
1375 : _M_update_bbegin(__this_n);
1376 :
1377 : // Then deal with other nodes.
1378 : __node_ptr __prev_n = __this_n;
1379 : for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next())
1380 : {
1381 : __this_n = __node_gen(__fwd_value_for<_Ht>(__ht_n->_M_v()));
1382 : __prev_n->_M_nxt = __this_n;
1383 : this->_M_copy_code(*__this_n, *__ht_n);
1384 : size_type __bkt = _M_bucket_index(*__this_n);
1385 : if (!_M_buckets[__bkt])
1386 : _M_buckets[__bkt] = __prev_n;
1387 : __prev_n = __this_n;
1388 : }
1389 : }
1390 : __catch(...)
1391 : {
1392 : clear();
1393 : if (__buckets)
1394 : _M_deallocate_buckets();
1395 : __throw_exception_again;
1396 : }
1397 : }
1398 :
1399 : template<typename _Key, typename _Value, typename _Alloc,
1400 : typename _ExtractKey, typename _Equal,
1401 : typename _Hash, typename _RangeHash, typename _Unused,
1402 : typename _RehashPolicy, typename _Traits>
1403 : void
1404 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1405 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1406 : _M_reset() noexcept
1407 : {
1408 : _M_rehash_policy._M_reset();
1409 : _M_bucket_count = 1;
1410 : _M_single_bucket = nullptr;
1411 : _M_buckets = &_M_single_bucket;
1412 : _M_before_begin._M_nxt = nullptr;
1413 : _M_element_count = 0;
1414 : }
1415 :
1416 : template<typename _Key, typename _Value, typename _Alloc,
1417 : typename _ExtractKey, typename _Equal,
1418 : typename _Hash, typename _RangeHash, typename _Unused,
1419 : typename _RehashPolicy, typename _Traits>
1420 : void
1421 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1422 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1423 : _M_move_assign(_Hashtable&& __ht, true_type)
1424 : {
1425 : if (__builtin_expect(std::__addressof(__ht) == this, false))
1426 : return;
1427 :
1428 : this->_M_deallocate_nodes(_M_begin());
1429 : _M_deallocate_buckets();
1430 : __hashtable_base::operator=(std::move(__ht));
1431 : _M_rehash_policy = __ht._M_rehash_policy;
1432 : if (!__ht._M_uses_single_bucket())
1433 : _M_buckets = __ht._M_buckets;
1434 : else
1435 : {
1436 : _M_buckets = &_M_single_bucket;
1437 : _M_single_bucket = __ht._M_single_bucket;
1438 : }
1439 :
1440 : _M_bucket_count = __ht._M_bucket_count;
1441 : _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt;
1442 : _M_element_count = __ht._M_element_count;
1443 : std::__alloc_on_move(this->_M_node_allocator(), __ht._M_node_allocator());
1444 :
1445 : // Fix bucket containing the _M_before_begin pointer that can't be moved.
1446 : _M_update_bbegin();
1447 : __ht._M_reset();
1448 : }
1449 :
1450 : template<typename _Key, typename _Value, typename _Alloc,
1451 : typename _ExtractKey, typename _Equal,
1452 : typename _Hash, typename _RangeHash, typename _Unused,
1453 : typename _RehashPolicy, typename _Traits>
1454 : void
1455 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1456 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1457 : _M_move_assign(_Hashtable&& __ht, false_type)
1458 : {
1459 : if (__ht._M_node_allocator() == this->_M_node_allocator())
1460 : _M_move_assign(std::move(__ht), true_type{});
1461 : else
1462 : {
1463 : // Can't move memory, move elements then.
1464 : _M_assign_elements(std::move(__ht));
1465 : __ht.clear();
1466 : }
1467 : }
1468 :
1469 : template<typename _Key, typename _Value, typename _Alloc,
1470 : typename _ExtractKey, typename _Equal,
1471 : typename _Hash, typename _RangeHash, typename _Unused,
1472 : typename _RehashPolicy, typename _Traits>
1473 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1474 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1475 : _Hashtable(const _Hashtable& __ht)
1476 : : __hashtable_base(__ht),
1477 : __map_base(__ht),
1478 : __rehash_base(__ht),
1479 : __hashtable_alloc(
1480 : __node_alloc_traits::_S_select_on_copy(__ht._M_node_allocator())),
1481 : __enable_default_ctor(__ht),
1482 : _M_buckets(nullptr),
1483 : _M_bucket_count(__ht._M_bucket_count),
1484 : _M_element_count(__ht._M_element_count),
1485 : _M_rehash_policy(__ht._M_rehash_policy)
1486 : {
1487 : __alloc_node_gen_t __alloc_node_gen(*this);
1488 : _M_assign(__ht, __alloc_node_gen);
1489 : }
1490 :
1491 : template<typename _Key, typename _Value, typename _Alloc,
1492 : typename _ExtractKey, typename _Equal,
1493 : typename _Hash, typename _RangeHash, typename _Unused,
1494 : typename _RehashPolicy, typename _Traits>
1495 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1496 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1497 : _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a,
1498 : true_type /* alloc always equal */)
1499 : noexcept(_S_nothrow_move())
1500 : : __hashtable_base(__ht),
1501 : __map_base(__ht),
1502 : __rehash_base(__ht),
1503 : __hashtable_alloc(std::move(__a)),
1504 : __enable_default_ctor(__ht),
1505 : _M_buckets(__ht._M_buckets),
1506 : _M_bucket_count(__ht._M_bucket_count),
1507 : _M_before_begin(__ht._M_before_begin._M_nxt),
1508 : _M_element_count(__ht._M_element_count),
1509 : _M_rehash_policy(__ht._M_rehash_policy)
1510 : {
1511 : // Update buckets if __ht is using its single bucket.
1512 : if (__ht._M_uses_single_bucket())
1513 : {
1514 : _M_buckets = &_M_single_bucket;
1515 : _M_single_bucket = __ht._M_single_bucket;
1516 : }
1517 :
1518 : // Fix bucket containing the _M_before_begin pointer that can't be moved.
1519 : _M_update_bbegin();
1520 :
1521 : __ht._M_reset();
1522 : }
1523 :
1524 : template<typename _Key, typename _Value, typename _Alloc,
1525 : typename _ExtractKey, typename _Equal,
1526 : typename _Hash, typename _RangeHash, typename _Unused,
1527 : typename _RehashPolicy, typename _Traits>
1528 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1529 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1530 : _Hashtable(const _Hashtable& __ht, const allocator_type& __a)
1531 : : __hashtable_base(__ht),
1532 : __map_base(__ht),
1533 : __rehash_base(__ht),
1534 : __hashtable_alloc(__node_alloc_type(__a)),
1535 : __enable_default_ctor(__ht),
1536 : _M_buckets(),
1537 : _M_bucket_count(__ht._M_bucket_count),
1538 : _M_element_count(__ht._M_element_count),
1539 : _M_rehash_policy(__ht._M_rehash_policy)
1540 : {
1541 : __alloc_node_gen_t __alloc_node_gen(*this);
1542 : _M_assign(__ht, __alloc_node_gen);
1543 : }
1544 :
1545 : template<typename _Key, typename _Value, typename _Alloc,
1546 : typename _ExtractKey, typename _Equal,
1547 : typename _Hash, typename _RangeHash, typename _Unused,
1548 : typename _RehashPolicy, typename _Traits>
1549 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1550 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1551 : _Hashtable(_Hashtable&& __ht, __node_alloc_type&& __a,
1552 : false_type /* alloc always equal */)
1553 : : __hashtable_base(__ht),
1554 : __map_base(__ht),
1555 : __rehash_base(__ht),
1556 : __hashtable_alloc(std::move(__a)),
1557 : __enable_default_ctor(__ht),
1558 : _M_buckets(nullptr),
1559 : _M_bucket_count(__ht._M_bucket_count),
1560 : _M_element_count(__ht._M_element_count),
1561 : _M_rehash_policy(__ht._M_rehash_policy)
1562 : {
1563 : if (__ht._M_node_allocator() == this->_M_node_allocator())
1564 : {
1565 : if (__ht._M_uses_single_bucket())
1566 : {
1567 : _M_buckets = &_M_single_bucket;
1568 : _M_single_bucket = __ht._M_single_bucket;
1569 : }
1570 : else
1571 : _M_buckets = __ht._M_buckets;
1572 :
1573 : // Fix bucket containing the _M_before_begin pointer that can't be
1574 : // moved.
1575 : _M_update_bbegin(__ht._M_begin());
1576 :
1577 : __ht._M_reset();
1578 : }
1579 : else
1580 : {
1581 : __alloc_node_gen_t __alloc_gen(*this);
1582 :
1583 : using _Fwd_Ht = __conditional_t<
1584 : __move_if_noexcept_cond<value_type>::value,
1585 : const _Hashtable&, _Hashtable&&>;
1586 : _M_assign(std::forward<_Fwd_Ht>(__ht), __alloc_gen);
1587 : __ht.clear();
1588 : }
1589 : }
1590 :
1591 : template<typename _Key, typename _Value, typename _Alloc,
1592 : typename _ExtractKey, typename _Equal,
1593 : typename _Hash, typename _RangeHash, typename _Unused,
1594 : typename _RehashPolicy, typename _Traits>
1595 123656 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1596 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1597 : ~_Hashtable() noexcept
1598 : {
1599 : // Getting a bucket index from a node shall not throw because it is used
1600 : // in methods (erase, swap...) that shall not throw. Need a complete
1601 : // type to check this, so do it in the destructor not at class scope.
1602 : static_assert(noexcept(declval<const __hash_code_base_access&>()
1603 : ._M_bucket_index(declval<const __node_value_type&>(),
1604 : (std::size_t)0)),
1605 : "Cache the hash code or qualify your functors involved"
1606 : " in hash code and bucket index computation with noexcept");
1607 :
1608 123656 : clear();
1609 123656 : _M_deallocate_buckets();
1610 123656 : }
1611 :
1612 : template<typename _Key, typename _Value, typename _Alloc,
1613 : typename _ExtractKey, typename _Equal,
1614 : typename _Hash, typename _RangeHash, typename _Unused,
1615 : typename _RehashPolicy, typename _Traits>
1616 : void
1617 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1618 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1619 : swap(_Hashtable& __x)
1620 : noexcept(__and_<__is_nothrow_swappable<_Hash>,
1621 : __is_nothrow_swappable<_Equal>>::value)
1622 : {
1623 : // The only base class with member variables is hash_code_base.
1624 : // We define _Hash_code_base::_M_swap because different
1625 : // specializations have different members.
1626 : this->_M_swap(__x);
1627 :
1628 : std::__alloc_on_swap(this->_M_node_allocator(), __x._M_node_allocator());
1629 : std::swap(_M_rehash_policy, __x._M_rehash_policy);
1630 :
1631 : // Deal properly with potentially moved instances.
1632 : if (this->_M_uses_single_bucket())
1633 : {
1634 : if (!__x._M_uses_single_bucket())
1635 : {
1636 : _M_buckets = __x._M_buckets;
1637 : __x._M_buckets = &__x._M_single_bucket;
1638 : }
1639 : }
1640 : else if (__x._M_uses_single_bucket())
1641 : {
1642 : __x._M_buckets = _M_buckets;
1643 : _M_buckets = &_M_single_bucket;
1644 : }
1645 : else
1646 : std::swap(_M_buckets, __x._M_buckets);
1647 :
1648 : std::swap(_M_bucket_count, __x._M_bucket_count);
1649 : std::swap(_M_before_begin._M_nxt, __x._M_before_begin._M_nxt);
1650 : std::swap(_M_element_count, __x._M_element_count);
1651 : std::swap(_M_single_bucket, __x._M_single_bucket);
1652 :
1653 : // Fix buckets containing the _M_before_begin pointers that can't be
1654 : // swapped.
1655 : _M_update_bbegin();
1656 : __x._M_update_bbegin();
1657 : }
1658 :
1659 : template<typename _Key, typename _Value, typename _Alloc,
1660 : typename _ExtractKey, typename _Equal,
1661 : typename _Hash, typename _RangeHash, typename _Unused,
1662 : typename _RehashPolicy, typename _Traits>
1663 : auto
1664 41704 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1665 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1666 : find(const key_type& __k)
1667 : -> iterator
1668 : {
1669 41704 : if (size() <= __small_size_threshold())
1670 : {
1671 69624 : for (auto __it = begin(); __it != end(); ++__it)
1672 33476 : if (this->_M_key_equals(__k, *__it._M_cur))
1673 8 : return __it;
1674 36148 : return end();
1675 : }
1676 :
1677 5548 : __hash_code __code = this->_M_hash_code(__k);
1678 5548 : std::size_t __bkt = _M_bucket_index(__code);
1679 5548 : return iterator(_M_find_node(__bkt, __k, __code));
1680 : }
1681 :
1682 : template<typename _Key, typename _Value, typename _Alloc,
1683 : typename _ExtractKey, typename _Equal,
1684 : typename _Hash, typename _RangeHash, typename _Unused,
1685 : typename _RehashPolicy, typename _Traits>
1686 : auto
1687 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1688 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1689 : find(const key_type& __k) const
1690 : -> const_iterator
1691 : {
1692 : if (size() <= __small_size_threshold())
1693 : {
1694 : for (auto __it = begin(); __it != end(); ++__it)
1695 : if (this->_M_key_equals(__k, *__it._M_cur))
1696 : return __it;
1697 : return end();
1698 : }
1699 :
1700 : __hash_code __code = this->_M_hash_code(__k);
1701 : std::size_t __bkt = _M_bucket_index(__code);
1702 : return const_iterator(_M_find_node(__bkt, __k, __code));
1703 : }
1704 :
1705 : #if __cplusplus > 201703L
1706 : template<typename _Key, typename _Value, typename _Alloc,
1707 : typename _ExtractKey, typename _Equal,
1708 : typename _Hash, typename _RangeHash, typename _Unused,
1709 : typename _RehashPolicy, typename _Traits>
1710 : template<typename _Kt, typename, typename>
1711 : auto
1712 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1713 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1714 : _M_find_tr(const _Kt& __k)
1715 : -> iterator
1716 : {
1717 : __hash_code __code = this->_M_hash_code_tr(__k);
1718 : std::size_t __bkt = _M_bucket_index(__code);
1719 : return iterator(_M_find_node_tr(__bkt, __k, __code));
1720 : }
1721 :
1722 : template<typename _Key, typename _Value, typename _Alloc,
1723 : typename _ExtractKey, typename _Equal,
1724 : typename _Hash, typename _RangeHash, typename _Unused,
1725 : typename _RehashPolicy, typename _Traits>
1726 : template<typename _Kt, typename, typename>
1727 : auto
1728 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1729 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1730 : _M_find_tr(const _Kt& __k) const
1731 : -> const_iterator
1732 : {
1733 : __hash_code __code = this->_M_hash_code_tr(__k);
1734 : std::size_t __bkt = _M_bucket_index(__code);
1735 : return const_iterator(_M_find_node_tr(__bkt, __k, __code));
1736 : }
1737 : #endif
1738 :
1739 : template<typename _Key, typename _Value, typename _Alloc,
1740 : typename _ExtractKey, typename _Equal,
1741 : typename _Hash, typename _RangeHash, typename _Unused,
1742 : typename _RehashPolicy, typename _Traits>
1743 : auto
1744 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1745 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1746 : count(const key_type& __k) const
1747 : -> size_type
1748 : {
1749 : auto __it = find(__k);
1750 : if (!__it._M_cur)
1751 : return 0;
1752 :
1753 : if (__unique_keys::value)
1754 : return 1;
1755 :
1756 : // All equivalent values are next to each other, if we find a
1757 : // non-equivalent value after an equivalent one it means that we won't
1758 : // find any new equivalent value.
1759 : size_type __result = 1;
1760 : for (auto __ref = __it++;
1761 : __it._M_cur && this->_M_node_equals(*__ref._M_cur, *__it._M_cur);
1762 : ++__it)
1763 : ++__result;
1764 :
1765 : return __result;
1766 : }
1767 :
1768 : #if __cplusplus > 201703L
1769 : template<typename _Key, typename _Value, typename _Alloc,
1770 : typename _ExtractKey, typename _Equal,
1771 : typename _Hash, typename _RangeHash, typename _Unused,
1772 : typename _RehashPolicy, typename _Traits>
1773 : template<typename _Kt, typename, typename>
1774 : auto
1775 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1776 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1777 : _M_count_tr(const _Kt& __k) const
1778 : -> size_type
1779 : {
1780 : __hash_code __code = this->_M_hash_code_tr(__k);
1781 : std::size_t __bkt = _M_bucket_index(__code);
1782 : auto __n = _M_find_node_tr(__bkt, __k, __code);
1783 : if (!__n)
1784 : return 0;
1785 :
1786 : // All equivalent values are next to each other, if we find a
1787 : // non-equivalent value after an equivalent one it means that we won't
1788 : // find any new equivalent value.
1789 : iterator __it(__n);
1790 : size_type __result = 1;
1791 : for (++__it;
1792 : __it._M_cur && this->_M_equals_tr(__k, __code, *__it._M_cur);
1793 : ++__it)
1794 : ++__result;
1795 :
1796 : return __result;
1797 : }
1798 : #endif
1799 :
1800 : template<typename _Key, typename _Value, typename _Alloc,
1801 : typename _ExtractKey, typename _Equal,
1802 : typename _Hash, typename _RangeHash, typename _Unused,
1803 : typename _RehashPolicy, typename _Traits>
1804 : auto
1805 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1806 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1807 : equal_range(const key_type& __k)
1808 : -> pair<iterator, iterator>
1809 : {
1810 : auto __ite = find(__k);
1811 : if (!__ite._M_cur)
1812 : return { __ite, __ite };
1813 :
1814 : auto __beg = __ite++;
1815 : if (__unique_keys::value)
1816 : return { __beg, __ite };
1817 :
1818 : // All equivalent values are next to each other, if we find a
1819 : // non-equivalent value after an equivalent one it means that we won't
1820 : // find any new equivalent value.
1821 : while (__ite._M_cur && this->_M_node_equals(*__beg._M_cur, *__ite._M_cur))
1822 : ++__ite;
1823 :
1824 : return { __beg, __ite };
1825 : }
1826 :
1827 : template<typename _Key, typename _Value, typename _Alloc,
1828 : typename _ExtractKey, typename _Equal,
1829 : typename _Hash, typename _RangeHash, typename _Unused,
1830 : typename _RehashPolicy, typename _Traits>
1831 : auto
1832 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1833 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1834 : equal_range(const key_type& __k) const
1835 : -> pair<const_iterator, const_iterator>
1836 : {
1837 : auto __ite = find(__k);
1838 : if (!__ite._M_cur)
1839 : return { __ite, __ite };
1840 :
1841 : auto __beg = __ite++;
1842 : if (__unique_keys::value)
1843 : return { __beg, __ite };
1844 :
1845 : // All equivalent values are next to each other, if we find a
1846 : // non-equivalent value after an equivalent one it means that we won't
1847 : // find any new equivalent value.
1848 : while (__ite._M_cur && this->_M_node_equals(*__beg._M_cur, *__ite._M_cur))
1849 : ++__ite;
1850 :
1851 : return { __beg, __ite };
1852 : }
1853 :
1854 : #if __cplusplus > 201703L
1855 : template<typename _Key, typename _Value, typename _Alloc,
1856 : typename _ExtractKey, typename _Equal,
1857 : typename _Hash, typename _RangeHash, typename _Unused,
1858 : typename _RehashPolicy, typename _Traits>
1859 : template<typename _Kt, typename, typename>
1860 : auto
1861 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1862 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1863 : _M_equal_range_tr(const _Kt& __k)
1864 : -> pair<iterator, iterator>
1865 : {
1866 : __hash_code __code = this->_M_hash_code_tr(__k);
1867 : std::size_t __bkt = _M_bucket_index(__code);
1868 : auto __n = _M_find_node_tr(__bkt, __k, __code);
1869 : iterator __ite(__n);
1870 : if (!__n)
1871 : return { __ite, __ite };
1872 :
1873 : // All equivalent values are next to each other, if we find a
1874 : // non-equivalent value after an equivalent one it means that we won't
1875 : // find any new equivalent value.
1876 : auto __beg = __ite++;
1877 : while (__ite._M_cur && this->_M_equals_tr(__k, __code, *__ite._M_cur))
1878 : ++__ite;
1879 :
1880 : return { __beg, __ite };
1881 : }
1882 :
1883 : template<typename _Key, typename _Value, typename _Alloc,
1884 : typename _ExtractKey, typename _Equal,
1885 : typename _Hash, typename _RangeHash, typename _Unused,
1886 : typename _RehashPolicy, typename _Traits>
1887 : template<typename _Kt, typename, typename>
1888 : auto
1889 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1890 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1891 : _M_equal_range_tr(const _Kt& __k) const
1892 : -> pair<const_iterator, const_iterator>
1893 : {
1894 : __hash_code __code = this->_M_hash_code_tr(__k);
1895 : std::size_t __bkt = _M_bucket_index(__code);
1896 : auto __n = _M_find_node_tr(__bkt, __k, __code);
1897 : const_iterator __ite(__n);
1898 : if (!__n)
1899 : return { __ite, __ite };
1900 :
1901 : // All equivalent values are next to each other, if we find a
1902 : // non-equivalent value after an equivalent one it means that we won't
1903 : // find any new equivalent value.
1904 : auto __beg = __ite++;
1905 : while (__ite._M_cur && this->_M_equals_tr(__k, __code, *__ite._M_cur))
1906 : ++__ite;
1907 :
1908 : return { __beg, __ite };
1909 : }
1910 : #endif
1911 :
1912 : // Find the node before the one whose key compares equal to k.
1913 : // Return nullptr if no node is found.
1914 : template<typename _Key, typename _Value, typename _Alloc,
1915 : typename _ExtractKey, typename _Equal,
1916 : typename _Hash, typename _RangeHash, typename _Unused,
1917 : typename _RehashPolicy, typename _Traits>
1918 : auto
1919 30520 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1920 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1921 : _M_find_before_node(const key_type& __k)
1922 : -> __node_base_ptr
1923 : {
1924 30520 : __node_base_ptr __prev_p = &_M_before_begin;
1925 30520 : if (!__prev_p->_M_nxt)
1926 0 : return nullptr;
1927 :
1928 30520 : for (__node_ptr __p = static_cast<__node_ptr>(__prev_p->_M_nxt);
1929 30568 : __p != nullptr;
1930 48 : __p = __p->_M_next())
1931 : {
1932 30568 : if (this->_M_key_equals(__k, *__p))
1933 30520 : return __prev_p;
1934 :
1935 48 : __prev_p = __p;
1936 : }
1937 :
1938 0 : return nullptr;
1939 : }
1940 :
1941 : // Find the node before the one whose key compares equal to k in the bucket
1942 : // bkt. Return nullptr if no node is found.
1943 : template<typename _Key, typename _Value, typename _Alloc,
1944 : typename _ExtractKey, typename _Equal,
1945 : typename _Hash, typename _RangeHash, typename _Unused,
1946 : typename _RehashPolicy, typename _Traits>
1947 : auto
1948 5928688 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1949 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1950 : _M_find_before_node(size_type __bkt, const key_type& __k,
1951 : __hash_code __code) const
1952 : -> __node_base_ptr
1953 : {
1954 5928688 : __node_base_ptr __prev_p = _M_buckets[__bkt];
1955 5928688 : if (!__prev_p)
1956 201034 : return nullptr;
1957 :
1958 5727654 : for (__node_ptr __p = static_cast<__node_ptr>(__prev_p->_M_nxt);;
1959 1966 : __p = __p->_M_next())
1960 : {
1961 5729620 : if (this->_M_equals(__k, __code, *__p))
1962 5724128 : return __prev_p;
1963 :
1964 5492 : if (!__p->_M_nxt || _M_bucket_index(*__p->_M_next()) != __bkt)
1965 3526 : break;
1966 1966 : __prev_p = __p;
1967 : }
1968 :
1969 3526 : return nullptr;
1970 : }
1971 :
1972 : template<typename _Key, typename _Value, typename _Alloc,
1973 : typename _ExtractKey, typename _Equal,
1974 : typename _Hash, typename _RangeHash, typename _Unused,
1975 : typename _RehashPolicy, typename _Traits>
1976 : template<typename _Kt>
1977 : auto
1978 2832 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
1979 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
1980 : _M_find_before_node_tr(size_type __bkt, const _Kt& __k,
1981 : __hash_code __code) const
1982 : -> __node_base_ptr
1983 : {
1984 2832 : __node_base_ptr __prev_p = _M_buckets[__bkt];
1985 2832 : if (!__prev_p)
1986 1376 : return nullptr;
1987 :
1988 1456 : for (__node_ptr __p = static_cast<__node_ptr>(__prev_p->_M_nxt);;
1989 564 : __p = __p->_M_next())
1990 : {
1991 2020 : if (this->_M_equals_tr(__k, __code, *__p))
1992 2 : return __prev_p;
1993 :
1994 2018 : if (!__p->_M_nxt || _M_bucket_index(*__p->_M_next()) != __bkt)
1995 1454 : break;
1996 564 : __prev_p = __p;
1997 : }
1998 :
1999 1454 : return nullptr;
2000 : }
2001 :
2002 : template<typename _Key, typename _Value, typename _Alloc,
2003 : typename _ExtractKey, typename _Equal,
2004 : typename _Hash, typename _RangeHash, typename _Unused,
2005 : typename _RehashPolicy, typename _Traits>
2006 : void
2007 260158 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2008 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2009 : _M_insert_bucket_begin(size_type __bkt, __node_ptr __node)
2010 : {
2011 260158 : if (_M_buckets[__bkt])
2012 : {
2013 : // Bucket is not empty, we just need to insert the new node
2014 : // after the bucket before begin.
2015 3210 : __node->_M_nxt = _M_buckets[__bkt]->_M_nxt;
2016 3210 : _M_buckets[__bkt]->_M_nxt = __node;
2017 : }
2018 : else
2019 : {
2020 : // The bucket is empty, the new node is inserted at the
2021 : // beginning of the singly-linked list and the bucket will
2022 : // contain _M_before_begin pointer.
2023 256948 : __node->_M_nxt = _M_before_begin._M_nxt;
2024 256948 : _M_before_begin._M_nxt = __node;
2025 :
2026 256948 : if (__node->_M_nxt)
2027 : // We must update former begin bucket that is pointing to
2028 : // _M_before_begin.
2029 140732 : _M_buckets[_M_bucket_index(*__node->_M_next())] = __node;
2030 :
2031 256948 : _M_buckets[__bkt] = &_M_before_begin;
2032 : }
2033 260158 : }
2034 :
2035 : template<typename _Key, typename _Value, typename _Alloc,
2036 : typename _ExtractKey, typename _Equal,
2037 : typename _Hash, typename _RangeHash, typename _Unused,
2038 : typename _RehashPolicy, typename _Traits>
2039 : void
2040 30520 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2041 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2042 : _M_remove_bucket_begin(size_type __bkt, __node_ptr __next,
2043 : size_type __next_bkt)
2044 : {
2045 30520 : if (!__next || __next_bkt != __bkt)
2046 : {
2047 : // Bucket is now empty
2048 : // First update next bucket if any
2049 30108 : if (__next)
2050 5166 : _M_buckets[__next_bkt] = _M_buckets[__bkt];
2051 :
2052 : // Second update before begin node if necessary
2053 30108 : if (&_M_before_begin == _M_buckets[__bkt])
2054 30108 : _M_before_begin._M_nxt = __next;
2055 30108 : _M_buckets[__bkt] = nullptr;
2056 : }
2057 30520 : }
2058 :
2059 : template<typename _Key, typename _Value, typename _Alloc,
2060 : typename _ExtractKey, typename _Equal,
2061 : typename _Hash, typename _RangeHash, typename _Unused,
2062 : typename _RehashPolicy, typename _Traits>
2063 : auto
2064 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2065 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2066 : _M_get_previous_node(size_type __bkt, __node_ptr __n)
2067 : -> __node_base_ptr
2068 : {
2069 : __node_base_ptr __prev_n = _M_buckets[__bkt];
2070 : while (__prev_n->_M_nxt != __n)
2071 : __prev_n = __prev_n->_M_nxt;
2072 : return __prev_n;
2073 : }
2074 :
2075 : template<typename _Key, typename _Value, typename _Alloc,
2076 : typename _ExtractKey, typename _Equal,
2077 : typename _Hash, typename _RangeHash, typename _Unused,
2078 : typename _RehashPolicy, typename _Traits>
2079 : template<typename... _Args>
2080 : auto
2081 30 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2082 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2083 : _M_emplace(true_type /* __uks */, _Args&&... __args)
2084 : -> pair<iterator, bool>
2085 : {
2086 : // First build the node to get access to the hash code
2087 30 : _Scoped_node __node { this, std::forward<_Args>(__args)... };
2088 60 : const key_type& __k = _ExtractKey{}(__node._M_node->_M_v());
2089 30 : if (size() <= __small_size_threshold())
2090 : {
2091 62 : for (auto __it = begin(); __it != end(); ++__it)
2092 32 : if (this->_M_key_equals(__k, *__it._M_cur))
2093 : // There is already an equivalent node, no insertion
2094 0 : return { __it, false };
2095 : }
2096 :
2097 30 : __hash_code __code = this->_M_hash_code(__k);
2098 30 : size_type __bkt = _M_bucket_index(__code);
2099 30 : if (size() > __small_size_threshold())
2100 0 : if (__node_ptr __p = _M_find_node(__bkt, __k, __code))
2101 : // There is already an equivalent node, no insertion
2102 0 : return { iterator(__p), false };
2103 :
2104 : // Insert the node
2105 30 : auto __pos = _M_insert_unique_node(__bkt, __code, __node._M_node);
2106 30 : __node._M_node = nullptr;
2107 30 : return { __pos, true };
2108 30 : }
2109 :
2110 : template<typename _Key, typename _Value, typename _Alloc,
2111 : typename _ExtractKey, typename _Equal,
2112 : typename _Hash, typename _RangeHash, typename _Unused,
2113 : typename _RehashPolicy, typename _Traits>
2114 : template<typename... _Args>
2115 : auto
2116 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2117 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2118 : _M_emplace(const_iterator __hint, false_type /* __uks */,
2119 : _Args&&... __args)
2120 : -> iterator
2121 : {
2122 : // First build the node to get its hash code.
2123 : _Scoped_node __node { this, std::forward<_Args>(__args)... };
2124 : const key_type& __k = _ExtractKey{}(__node._M_node->_M_v());
2125 :
2126 : auto __res = this->_M_compute_hash_code(__hint, __k);
2127 : auto __pos
2128 : = _M_insert_multi_node(__res.first._M_cur, __res.second,
2129 : __node._M_node);
2130 : __node._M_node = nullptr;
2131 : return __pos;
2132 : }
2133 :
2134 : template<typename _Key, typename _Value, typename _Alloc,
2135 : typename _ExtractKey, typename _Equal,
2136 : typename _Hash, typename _RangeHash, typename _Unused,
2137 : typename _RehashPolicy, typename _Traits>
2138 : auto
2139 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2140 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2141 : _M_compute_hash_code(const_iterator __hint, const key_type& __k) const
2142 : -> pair<const_iterator, __hash_code>
2143 : {
2144 : if (size() <= __small_size_threshold())
2145 : {
2146 : if (__hint != cend())
2147 : {
2148 : for (auto __it = __hint; __it != cend(); ++__it)
2149 : if (this->_M_key_equals(__k, *__it._M_cur))
2150 : return { __it, this->_M_hash_code(*__it._M_cur) };
2151 : }
2152 :
2153 : for (auto __it = cbegin(); __it != __hint; ++__it)
2154 : if (this->_M_key_equals(__k, *__it._M_cur))
2155 : return { __it, this->_M_hash_code(*__it._M_cur) };
2156 : }
2157 :
2158 : return { __hint, this->_M_hash_code(__k) };
2159 : }
2160 :
2161 : template<typename _Key, typename _Value, typename _Alloc,
2162 : typename _ExtractKey, typename _Equal,
2163 : typename _Hash, typename _RangeHash, typename _Unused,
2164 : typename _RehashPolicy, typename _Traits>
2165 : auto
2166 260158 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2167 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2168 : _M_insert_unique_node(size_type __bkt, __hash_code __code,
2169 : __node_ptr __node, size_type __n_elt)
2170 : -> iterator
2171 : {
2172 260158 : const __rehash_state& __saved_state = _M_rehash_policy._M_state();
2173 : std::pair<bool, std::size_t> __do_rehash
2174 260158 : = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count,
2175 : __n_elt);
2176 :
2177 260158 : if (__do_rehash.first)
2178 : {
2179 116624 : _M_rehash(__do_rehash.second, __saved_state);
2180 116624 : __bkt = _M_bucket_index(__code);
2181 : }
2182 :
2183 260158 : this->_M_store_code(*__node, __code);
2184 :
2185 : // Always insert at the beginning of the bucket.
2186 260158 : _M_insert_bucket_begin(__bkt, __node);
2187 260158 : ++_M_element_count;
2188 260158 : return iterator(__node);
2189 : }
2190 :
2191 : template<typename _Key, typename _Value, typename _Alloc,
2192 : typename _ExtractKey, typename _Equal,
2193 : typename _Hash, typename _RangeHash, typename _Unused,
2194 : typename _RehashPolicy, typename _Traits>
2195 : auto
2196 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2197 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2198 : _M_insert_multi_node(__node_ptr __hint,
2199 : __hash_code __code, __node_ptr __node)
2200 : -> iterator
2201 : {
2202 : const __rehash_state& __saved_state = _M_rehash_policy._M_state();
2203 : std::pair<bool, std::size_t> __do_rehash
2204 : = _M_rehash_policy._M_need_rehash(_M_bucket_count, _M_element_count, 1);
2205 :
2206 : if (__do_rehash.first)
2207 : _M_rehash(__do_rehash.second, __saved_state);
2208 :
2209 : this->_M_store_code(*__node, __code);
2210 : const key_type& __k = _ExtractKey{}(__node->_M_v());
2211 : size_type __bkt = _M_bucket_index(__code);
2212 :
2213 : // Find the node before an equivalent one or use hint if it exists and
2214 : // if it is equivalent.
2215 : __node_base_ptr __prev
2216 : = __builtin_expect(__hint != nullptr, false)
2217 : && this->_M_equals(__k, __code, *__hint)
2218 : ? __hint
2219 : : _M_find_before_node(__bkt, __k, __code);
2220 :
2221 : if (__prev)
2222 : {
2223 : // Insert after the node before the equivalent one.
2224 : __node->_M_nxt = __prev->_M_nxt;
2225 : __prev->_M_nxt = __node;
2226 : if (__builtin_expect(__prev == __hint, false))
2227 : // hint might be the last bucket node, in this case we need to
2228 : // update next bucket.
2229 : if (__node->_M_nxt
2230 : && !this->_M_equals(__k, __code, *__node->_M_next()))
2231 : {
2232 : size_type __next_bkt = _M_bucket_index(*__node->_M_next());
2233 : if (__next_bkt != __bkt)
2234 : _M_buckets[__next_bkt] = __node;
2235 : }
2236 : }
2237 : else
2238 : // The inserted node has no equivalent in the hashtable. We must
2239 : // insert the new node at the beginning of the bucket to preserve
2240 : // equivalent elements' relative positions.
2241 : _M_insert_bucket_begin(__bkt, __node);
2242 : ++_M_element_count;
2243 : return iterator(__node);
2244 : }
2245 :
2246 : // Insert v if no element with its key is already present.
2247 : template<typename _Key, typename _Value, typename _Alloc,
2248 : typename _ExtractKey, typename _Equal,
2249 : typename _Hash, typename _RangeHash, typename _Unused,
2250 : typename _RehashPolicy, typename _Traits>
2251 : template<typename _Kt, typename _Arg, typename _NodeGenerator>
2252 : auto
2253 61166 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2254 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2255 : _M_insert_unique(_Kt&& __k, _Arg&& __v,
2256 : const _NodeGenerator& __node_gen)
2257 : -> pair<iterator, bool>
2258 : {
2259 61166 : if (size() <= __small_size_threshold())
2260 78472 : for (auto __it = begin(); __it != end(); ++__it)
2261 20140 : if (this->_M_key_equals_tr(__k, *__it._M_cur))
2262 2 : return { __it, false };
2263 :
2264 61164 : __hash_code __code = this->_M_hash_code_tr(__k);
2265 61164 : size_type __bkt = _M_bucket_index(__code);
2266 :
2267 61164 : if (size() > __small_size_threshold())
2268 2832 : if (__node_ptr __node = _M_find_node_tr(__bkt, __k, __code))
2269 2 : return { iterator(__node), false };
2270 :
2271 61162 : _Scoped_node __node {
2272 : __node_builder_t::_S_build(std::forward<_Kt>(__k),
2273 : std::forward<_Arg>(__v),
2274 : __node_gen),
2275 : this
2276 : };
2277 : auto __pos
2278 61162 : = _M_insert_unique_node(__bkt, __code, __node._M_node);
2279 61162 : __node._M_node = nullptr;
2280 61162 : return { __pos, true };
2281 61162 : }
2282 :
2283 : // Insert v unconditionally.
2284 : template<typename _Key, typename _Value, typename _Alloc,
2285 : typename _ExtractKey, typename _Equal,
2286 : typename _Hash, typename _RangeHash, typename _Unused,
2287 : typename _RehashPolicy, typename _Traits>
2288 : template<typename _Arg, typename _NodeGenerator>
2289 : auto
2290 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2291 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2292 : _M_insert(const_iterator __hint, _Arg&& __v,
2293 : const _NodeGenerator& __node_gen,
2294 : false_type /* __uks */)
2295 : -> iterator
2296 : {
2297 : // First allocate new node so that we don't do anything if it throws.
2298 : _Scoped_node __node{ __node_gen(std::forward<_Arg>(__v)), this };
2299 :
2300 : // Second compute the hash code so that we don't rehash if it throws.
2301 : auto __res = this->_M_compute_hash_code(
2302 : __hint, _ExtractKey{}(__node._M_node->_M_v()));
2303 :
2304 : auto __pos
2305 : = _M_insert_multi_node(__res.first._M_cur, __res.second,
2306 : __node._M_node);
2307 : __node._M_node = nullptr;
2308 : return __pos;
2309 : }
2310 :
2311 : template<typename _Key, typename _Value, typename _Alloc,
2312 : typename _ExtractKey, typename _Equal,
2313 : typename _Hash, typename _RangeHash, typename _Unused,
2314 : typename _RehashPolicy, typename _Traits>
2315 : auto
2316 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2317 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2318 : erase(const_iterator __it)
2319 : -> iterator
2320 : {
2321 : __node_ptr __n = __it._M_cur;
2322 : std::size_t __bkt = _M_bucket_index(*__n);
2323 :
2324 : // Look for previous node to unlink it from the erased one, this
2325 : // is why we need buckets to contain the before begin to make
2326 : // this search fast.
2327 : __node_base_ptr __prev_n = _M_get_previous_node(__bkt, __n);
2328 : return _M_erase(__bkt, __prev_n, __n);
2329 : }
2330 :
2331 : template<typename _Key, typename _Value, typename _Alloc,
2332 : typename _ExtractKey, typename _Equal,
2333 : typename _Hash, typename _RangeHash, typename _Unused,
2334 : typename _RehashPolicy, typename _Traits>
2335 : auto
2336 30520 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2337 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2338 : _M_erase(size_type __bkt, __node_base_ptr __prev_n, __node_ptr __n)
2339 : -> iterator
2340 : {
2341 30520 : if (__prev_n == _M_buckets[__bkt])
2342 30520 : _M_remove_bucket_begin(__bkt, __n->_M_next(),
2343 30520 : __n->_M_nxt ? _M_bucket_index(*__n->_M_next()) : 0);
2344 0 : else if (__n->_M_nxt)
2345 : {
2346 0 : size_type __next_bkt = _M_bucket_index(*__n->_M_next());
2347 0 : if (__next_bkt != __bkt)
2348 0 : _M_buckets[__next_bkt] = __prev_n;
2349 : }
2350 :
2351 30520 : __prev_n->_M_nxt = __n->_M_nxt;
2352 30520 : iterator __result(__n->_M_next());
2353 30520 : this->_M_deallocate_node(__n);
2354 30520 : --_M_element_count;
2355 :
2356 30520 : return __result;
2357 : }
2358 :
2359 : template<typename _Key, typename _Value, typename _Alloc,
2360 : typename _ExtractKey, typename _Equal,
2361 : typename _Hash, typename _RangeHash, typename _Unused,
2362 : typename _RehashPolicy, typename _Traits>
2363 : auto
2364 30520 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2365 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2366 : _M_erase(true_type /* __uks */, const key_type& __k)
2367 : -> size_type
2368 : {
2369 : __node_base_ptr __prev_n;
2370 : __node_ptr __n;
2371 : std::size_t __bkt;
2372 30520 : if (size() <= __small_size_threshold())
2373 : {
2374 30520 : __prev_n = _M_find_before_node(__k);
2375 30520 : if (!__prev_n)
2376 0 : return 0;
2377 :
2378 : // We found a matching node, erase it.
2379 30520 : __n = static_cast<__node_ptr>(__prev_n->_M_nxt);
2380 30520 : __bkt = _M_bucket_index(*__n);
2381 : }
2382 : else
2383 : {
2384 0 : __hash_code __code = this->_M_hash_code(__k);
2385 0 : __bkt = _M_bucket_index(__code);
2386 :
2387 : // Look for the node before the first matching node.
2388 0 : __prev_n = _M_find_before_node(__bkt, __k, __code);
2389 0 : if (!__prev_n)
2390 0 : return 0;
2391 :
2392 : // We found a matching node, erase it.
2393 0 : __n = static_cast<__node_ptr>(__prev_n->_M_nxt);
2394 : }
2395 :
2396 30520 : _M_erase(__bkt, __prev_n, __n);
2397 30520 : return 1;
2398 : }
2399 :
2400 : template<typename _Key, typename _Value, typename _Alloc,
2401 : typename _ExtractKey, typename _Equal,
2402 : typename _Hash, typename _RangeHash, typename _Unused,
2403 : typename _RehashPolicy, typename _Traits>
2404 : auto
2405 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2406 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2407 : _M_erase(false_type /* __uks */, const key_type& __k)
2408 : -> size_type
2409 : {
2410 : std::size_t __bkt;
2411 : __node_base_ptr __prev_n;
2412 : __node_ptr __n;
2413 : if (size() <= __small_size_threshold())
2414 : {
2415 : __prev_n = _M_find_before_node(__k);
2416 : if (!__prev_n)
2417 : return 0;
2418 :
2419 : // We found a matching node, erase it.
2420 : __n = static_cast<__node_ptr>(__prev_n->_M_nxt);
2421 : __bkt = _M_bucket_index(*__n);
2422 : }
2423 : else
2424 : {
2425 : __hash_code __code = this->_M_hash_code(__k);
2426 : __bkt = _M_bucket_index(__code);
2427 :
2428 : // Look for the node before the first matching node.
2429 : __prev_n = _M_find_before_node(__bkt, __k, __code);
2430 : if (!__prev_n)
2431 : return 0;
2432 :
2433 : __n = static_cast<__node_ptr>(__prev_n->_M_nxt);
2434 : }
2435 :
2436 : // _GLIBCXX_RESOLVE_LIB_DEFECTS
2437 : // 526. Is it undefined if a function in the standard changes
2438 : // in parameters?
2439 : // We use one loop to find all matching nodes and another to deallocate
2440 : // them so that the key stays valid during the first loop. It might be
2441 : // invalidated indirectly when destroying nodes.
2442 : __node_ptr __n_last = __n->_M_next();
2443 : while (__n_last && this->_M_node_equals(*__n, *__n_last))
2444 : __n_last = __n_last->_M_next();
2445 :
2446 : std::size_t __n_last_bkt = __n_last ? _M_bucket_index(*__n_last) : __bkt;
2447 :
2448 : // Deallocate nodes.
2449 : size_type __result = 0;
2450 : do
2451 : {
2452 : __node_ptr __p = __n->_M_next();
2453 : this->_M_deallocate_node(__n);
2454 : __n = __p;
2455 : ++__result;
2456 : }
2457 : while (__n != __n_last);
2458 :
2459 : _M_element_count -= __result;
2460 : if (__prev_n == _M_buckets[__bkt])
2461 : _M_remove_bucket_begin(__bkt, __n_last, __n_last_bkt);
2462 : else if (__n_last_bkt != __bkt)
2463 : _M_buckets[__n_last_bkt] = __prev_n;
2464 : __prev_n->_M_nxt = __n_last;
2465 : return __result;
2466 : }
2467 :
2468 : template<typename _Key, typename _Value, typename _Alloc,
2469 : typename _ExtractKey, typename _Equal,
2470 : typename _Hash, typename _RangeHash, typename _Unused,
2471 : typename _RehashPolicy, typename _Traits>
2472 : auto
2473 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2474 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2475 : erase(const_iterator __first, const_iterator __last)
2476 : -> iterator
2477 : {
2478 : __node_ptr __n = __first._M_cur;
2479 : __node_ptr __last_n = __last._M_cur;
2480 : if (__n == __last_n)
2481 : return iterator(__n);
2482 :
2483 : std::size_t __bkt = _M_bucket_index(*__n);
2484 :
2485 : __node_base_ptr __prev_n = _M_get_previous_node(__bkt, __n);
2486 : bool __is_bucket_begin = __n == _M_bucket_begin(__bkt);
2487 : std::size_t __n_bkt = __bkt;
2488 : for (;;)
2489 : {
2490 : do
2491 : {
2492 : __node_ptr __tmp = __n;
2493 : __n = __n->_M_next();
2494 : this->_M_deallocate_node(__tmp);
2495 : --_M_element_count;
2496 : if (!__n)
2497 : break;
2498 : __n_bkt = _M_bucket_index(*__n);
2499 : }
2500 : while (__n != __last_n && __n_bkt == __bkt);
2501 : if (__is_bucket_begin)
2502 : _M_remove_bucket_begin(__bkt, __n, __n_bkt);
2503 : if (__n == __last_n)
2504 : break;
2505 : __is_bucket_begin = true;
2506 : __bkt = __n_bkt;
2507 : }
2508 :
2509 : if (__n && (__n_bkt != __bkt || __is_bucket_begin))
2510 : _M_buckets[__n_bkt] = __prev_n;
2511 : __prev_n->_M_nxt = __n;
2512 : return iterator(__n);
2513 : }
2514 :
2515 : template<typename _Key, typename _Value, typename _Alloc,
2516 : typename _ExtractKey, typename _Equal,
2517 : typename _Hash, typename _RangeHash, typename _Unused,
2518 : typename _RehashPolicy, typename _Traits>
2519 : void
2520 123656 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2521 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2522 : clear() noexcept
2523 : {
2524 123656 : this->_M_deallocate_nodes(_M_begin());
2525 123656 : __builtin_memset(_M_buckets, 0,
2526 123656 : _M_bucket_count * sizeof(__node_base_ptr));
2527 123656 : _M_element_count = 0;
2528 123656 : _M_before_begin._M_nxt = nullptr;
2529 123656 : }
2530 :
2531 : template<typename _Key, typename _Value, typename _Alloc,
2532 : typename _ExtractKey, typename _Equal,
2533 : typename _Hash, typename _RangeHash, typename _Unused,
2534 : typename _RehashPolicy, typename _Traits>
2535 : void
2536 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2537 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2538 : rehash(size_type __bkt_count)
2539 : {
2540 : const __rehash_state& __saved_state = _M_rehash_policy._M_state();
2541 : __bkt_count
2542 : = std::max(_M_rehash_policy._M_bkt_for_elements(_M_element_count + 1),
2543 : __bkt_count);
2544 : __bkt_count = _M_rehash_policy._M_next_bkt(__bkt_count);
2545 :
2546 : if (__bkt_count != _M_bucket_count)
2547 : _M_rehash(__bkt_count, __saved_state);
2548 : else
2549 : // No rehash, restore previous state to keep it consistent with
2550 : // container state.
2551 : _M_rehash_policy._M_reset(__saved_state);
2552 : }
2553 :
2554 : template<typename _Key, typename _Value, typename _Alloc,
2555 : typename _ExtractKey, typename _Equal,
2556 : typename _Hash, typename _RangeHash, typename _Unused,
2557 : typename _RehashPolicy, typename _Traits>
2558 : void
2559 116628 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2560 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2561 : _M_rehash(size_type __bkt_count, const __rehash_state& __state)
2562 : {
2563 : __try
2564 : {
2565 116628 : _M_rehash_aux(__bkt_count, __unique_keys{});
2566 : }
2567 0 : __catch(...)
2568 : {
2569 : // A failure here means that buckets allocation failed. We only
2570 : // have to restore hash policy previous state.
2571 0 : _M_rehash_policy._M_reset(__state);
2572 0 : __throw_exception_again;
2573 : }
2574 116628 : }
2575 :
2576 : // Rehash when there is no equivalent elements.
2577 : template<typename _Key, typename _Value, typename _Alloc,
2578 : typename _ExtractKey, typename _Equal,
2579 : typename _Hash, typename _RangeHash, typename _Unused,
2580 : typename _RehashPolicy, typename _Traits>
2581 : void
2582 116628 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2583 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2584 : _M_rehash_aux(size_type __bkt_count, true_type /* __uks */)
2585 : {
2586 116628 : __buckets_ptr __new_buckets = _M_allocate_buckets(__bkt_count);
2587 116628 : __node_ptr __p = _M_begin();
2588 116628 : _M_before_begin._M_nxt = nullptr;
2589 116628 : std::size_t __bbegin_bkt = 0;
2590 125964 : while (__p)
2591 : {
2592 9336 : __node_ptr __next = __p->_M_next();
2593 : std::size_t __bkt
2594 9336 : = __hash_code_base::_M_bucket_index(*__p, __bkt_count);
2595 9336 : if (!__new_buckets[__bkt])
2596 : {
2597 8344 : __p->_M_nxt = _M_before_begin._M_nxt;
2598 8344 : _M_before_begin._M_nxt = __p;
2599 8344 : __new_buckets[__bkt] = &_M_before_begin;
2600 8344 : if (__p->_M_nxt)
2601 7932 : __new_buckets[__bbegin_bkt] = __p;
2602 8344 : __bbegin_bkt = __bkt;
2603 : }
2604 : else
2605 : {
2606 992 : __p->_M_nxt = __new_buckets[__bkt]->_M_nxt;
2607 992 : __new_buckets[__bkt]->_M_nxt = __p;
2608 : }
2609 :
2610 9336 : __p = __next;
2611 : }
2612 :
2613 116628 : _M_deallocate_buckets();
2614 116628 : _M_bucket_count = __bkt_count;
2615 116628 : _M_buckets = __new_buckets;
2616 116628 : }
2617 :
2618 : // Rehash when there can be equivalent elements, preserve their relative
2619 : // order.
2620 : template<typename _Key, typename _Value, typename _Alloc,
2621 : typename _ExtractKey, typename _Equal,
2622 : typename _Hash, typename _RangeHash, typename _Unused,
2623 : typename _RehashPolicy, typename _Traits>
2624 : void
2625 : _Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal,
2626 : _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits>::
2627 : _M_rehash_aux(size_type __bkt_count, false_type /* __uks */)
2628 : {
2629 : __buckets_ptr __new_buckets = _M_allocate_buckets(__bkt_count);
2630 : __node_ptr __p = _M_begin();
2631 : _M_before_begin._M_nxt = nullptr;
2632 : std::size_t __bbegin_bkt = 0;
2633 : std::size_t __prev_bkt = 0;
2634 : __node_ptr __prev_p = nullptr;
2635 : bool __check_bucket = false;
2636 :
2637 : while (__p)
2638 : {
2639 : __node_ptr __next = __p->_M_next();
2640 : std::size_t __bkt
2641 : = __hash_code_base::_M_bucket_index(*__p, __bkt_count);
2642 :
2643 : if (__prev_p && __prev_bkt == __bkt)
2644 : {
2645 : // Previous insert was already in this bucket, we insert after
2646 : // the previously inserted one to preserve equivalent elements
2647 : // relative order.
2648 : __p->_M_nxt = __prev_p->_M_nxt;
2649 : __prev_p->_M_nxt = __p;
2650 :
2651 : // Inserting after a node in a bucket require to check that we
2652 : // haven't change the bucket last node, in this case next
2653 : // bucket containing its before begin node must be updated. We
2654 : // schedule a check as soon as we move out of the sequence of
2655 : // equivalent nodes to limit the number of checks.
2656 : __check_bucket = true;
2657 : }
2658 : else
2659 : {
2660 : if (__check_bucket)
2661 : {
2662 : // Check if we shall update the next bucket because of
2663 : // insertions into __prev_bkt bucket.
2664 : if (__prev_p->_M_nxt)
2665 : {
2666 : std::size_t __next_bkt
2667 : = __hash_code_base::_M_bucket_index(
2668 : *__prev_p->_M_next(), __bkt_count);
2669 : if (__next_bkt != __prev_bkt)
2670 : __new_buckets[__next_bkt] = __prev_p;
2671 : }
2672 : __check_bucket = false;
2673 : }
2674 :
2675 : if (!__new_buckets[__bkt])
2676 : {
2677 : __p->_M_nxt = _M_before_begin._M_nxt;
2678 : _M_before_begin._M_nxt = __p;
2679 : __new_buckets[__bkt] = &_M_before_begin;
2680 : if (__p->_M_nxt)
2681 : __new_buckets[__bbegin_bkt] = __p;
2682 : __bbegin_bkt = __bkt;
2683 : }
2684 : else
2685 : {
2686 : __p->_M_nxt = __new_buckets[__bkt]->_M_nxt;
2687 : __new_buckets[__bkt]->_M_nxt = __p;
2688 : }
2689 : }
2690 : __prev_p = __p;
2691 : __prev_bkt = __bkt;
2692 : __p = __next;
2693 : }
2694 :
2695 : if (__check_bucket && __prev_p->_M_nxt)
2696 : {
2697 : std::size_t __next_bkt
2698 : = __hash_code_base::_M_bucket_index(*__prev_p->_M_next(),
2699 : __bkt_count);
2700 : if (__next_bkt != __prev_bkt)
2701 : __new_buckets[__next_bkt] = __prev_p;
2702 : }
2703 :
2704 : _M_deallocate_buckets();
2705 : _M_bucket_count = __bkt_count;
2706 : _M_buckets = __new_buckets;
2707 : }
2708 :
2709 : #if __cplusplus > 201402L
2710 : template<typename, typename, typename> class _Hash_merge_helper { };
2711 : #endif // C++17
2712 :
2713 : #if __cpp_deduction_guides >= 201606
2714 : // Used to constrain deduction guides
2715 : template<typename _Hash>
2716 : using _RequireNotAllocatorOrIntegral
2717 : = __enable_if_t<!__or_<is_integral<_Hash>, __is_allocator<_Hash>>::value>;
2718 : #endif
2719 :
2720 : /// @endcond
2721 : _GLIBCXX_END_NAMESPACE_VERSION
2722 : } // namespace std
2723 :
2724 : #endif // _HASHTABLE_H
|