1e4b17023SJohn Marino // hashtable.h header -*- C++ -*-
2e4b17023SJohn Marino
3*5ce9237cSJohn Marino // Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013
4e4b17023SJohn Marino // Free Software Foundation, Inc.
5e4b17023SJohn Marino //
6e4b17023SJohn Marino // This file is part of the GNU ISO C++ Library. This library is free
7e4b17023SJohn Marino // software; you can redistribute it and/or modify it under the
8e4b17023SJohn Marino // terms of the GNU General Public License as published by the
9e4b17023SJohn Marino // Free Software Foundation; either version 3, or (at your option)
10e4b17023SJohn Marino // any later version.
11e4b17023SJohn Marino
12e4b17023SJohn Marino // This library is distributed in the hope that it will be useful,
13e4b17023SJohn Marino // but WITHOUT ANY WARRANTY; without even the implied warranty of
14e4b17023SJohn Marino // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15e4b17023SJohn Marino // GNU General Public License for more details.
16e4b17023SJohn Marino
17e4b17023SJohn Marino // Under Section 7 of GPL version 3, you are granted additional
18e4b17023SJohn Marino // permissions described in the GCC Runtime Library Exception, version
19e4b17023SJohn Marino // 3.1, as published by the Free Software Foundation.
20e4b17023SJohn Marino
21e4b17023SJohn Marino // You should have received a copy of the GNU General Public License and
22e4b17023SJohn Marino // a copy of the GCC Runtime Library Exception along with this program;
23e4b17023SJohn Marino // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24e4b17023SJohn Marino // <http://www.gnu.org/licenses/>.
25e4b17023SJohn Marino
26e4b17023SJohn Marino /** @file bits/hashtable.h
27e4b17023SJohn Marino * This is an internal header file, included by other library headers.
28e4b17023SJohn Marino * Do not attempt to use it directly. @headername{unordered_map, unordered_set}
29e4b17023SJohn Marino */
30e4b17023SJohn Marino
31e4b17023SJohn Marino #ifndef _HASHTABLE_H
32e4b17023SJohn Marino #define _HASHTABLE_H 1
33e4b17023SJohn Marino
34e4b17023SJohn Marino #pragma GCC system_header
35e4b17023SJohn Marino
36e4b17023SJohn Marino #include <bits/hashtable_policy.h>
37e4b17023SJohn Marino
_GLIBCXX_VISIBILITY(default)38e4b17023SJohn Marino namespace std _GLIBCXX_VISIBILITY(default)
39e4b17023SJohn Marino {
40e4b17023SJohn Marino _GLIBCXX_BEGIN_NAMESPACE_VERSION
41e4b17023SJohn Marino
42e4b17023SJohn Marino // Class template _Hashtable, class definition.
43e4b17023SJohn Marino
44e4b17023SJohn Marino // Meaning of class template _Hashtable's template parameters
45e4b17023SJohn Marino
46e4b17023SJohn Marino // _Key and _Value: arbitrary CopyConstructible types.
47e4b17023SJohn Marino
48e4b17023SJohn Marino // _Allocator: an allocator type ([lib.allocator.requirements]) whose
49e4b17023SJohn Marino // value type is Value. As a conforming extension, we allow for
50e4b17023SJohn Marino // value type != Value.
51e4b17023SJohn Marino
52e4b17023SJohn Marino // _ExtractKey: function object that takes an object of type Value
53e4b17023SJohn Marino // and returns a value of type _Key.
54e4b17023SJohn Marino
55e4b17023SJohn Marino // _Equal: function object that takes two objects of type k and returns
56e4b17023SJohn Marino // a bool-like value that is true if the two objects are considered equal.
57e4b17023SJohn Marino
58e4b17023SJohn Marino // _H1: the hash function. A unary function object with argument type
59e4b17023SJohn Marino // Key and result type size_t. Return values should be distributed
60e4b17023SJohn Marino // over the entire range [0, numeric_limits<size_t>:::max()].
61e4b17023SJohn Marino
62e4b17023SJohn Marino // _H2: the range-hashing function (in the terminology of Tavori and
63e4b17023SJohn Marino // Dreizin). A binary function object whose argument types and result
64e4b17023SJohn Marino // type are all size_t. Given arguments r and N, the return value is
65e4b17023SJohn Marino // in the range [0, N).
66e4b17023SJohn Marino
67e4b17023SJohn Marino // _Hash: the ranged hash function (Tavori and Dreizin). A binary function
68e4b17023SJohn Marino // whose argument types are _Key and size_t and whose result type is
69e4b17023SJohn Marino // size_t. Given arguments k and N, the return value is in the range
70e4b17023SJohn Marino // [0, N). Default: hash(k, N) = h2(h1(k), N). If _Hash is anything other
71e4b17023SJohn Marino // than the default, _H1 and _H2 are ignored.
72e4b17023SJohn Marino
73e4b17023SJohn Marino // _RehashPolicy: Policy class with three members, all of which govern
74e4b17023SJohn Marino // the bucket count. _M_next_bkt(n) returns a bucket count no smaller
75e4b17023SJohn Marino // than n. _M_bkt_for_elements(n) returns a bucket count appropriate
76e4b17023SJohn Marino // for an element count of n. _M_need_rehash(n_bkt, n_elt, n_ins)
77e4b17023SJohn Marino // determines whether, if the current bucket count is n_bkt and the
78e4b17023SJohn Marino // current element count is n_elt, we need to increase the bucket
79e4b17023SJohn Marino // count. If so, returns make_pair(true, n), where n is the new
80e4b17023SJohn Marino // bucket count. If not, returns make_pair(false, <anything>).
81e4b17023SJohn Marino
82e4b17023SJohn Marino // __cache_hash_code: bool. true if we store the value of the hash
83e4b17023SJohn Marino // function along with the value. This is a time-space tradeoff.
84e4b17023SJohn Marino // Storing it may improve lookup speed by reducing the number of times
85e4b17023SJohn Marino // we need to call the Equal function.
86e4b17023SJohn Marino
87e4b17023SJohn Marino // __constant_iterators: bool. true if iterator and const_iterator are
88e4b17023SJohn Marino // both constant iterator types. This is true for unordered_set and
89e4b17023SJohn Marino // unordered_multiset, false for unordered_map and unordered_multimap.
90e4b17023SJohn Marino
91e4b17023SJohn Marino // __unique_keys: bool. true if the return value of _Hashtable::count(k)
92e4b17023SJohn Marino // is always at most one, false if it may be an arbitrary number. This
93e4b17023SJohn Marino // true for unordered_set and unordered_map, false for unordered_multiset
94e4b17023SJohn Marino // and unordered_multimap.
95e4b17023SJohn Marino /**
96e4b17023SJohn Marino * Here's _Hashtable data structure, each _Hashtable has:
97e4b17023SJohn Marino * - _Bucket[] _M_buckets
98e4b17023SJohn Marino * - _Hash_node_base _M_before_begin
99e4b17023SJohn Marino * - size_type _M_bucket_count
100e4b17023SJohn Marino * - size_type _M_element_count
101e4b17023SJohn Marino *
102*5ce9237cSJohn Marino * with _Bucket being _Hash_node* and _Hash_node containing:
103e4b17023SJohn Marino * - _Hash_node* _M_next
104e4b17023SJohn Marino * - Tp _M_value
105*5ce9237cSJohn Marino * - size_t _M_hash_code if cache_hash_code is true
106e4b17023SJohn Marino *
107*5ce9237cSJohn Marino * In terms of Standard containers the hashtable is like the aggregation of:
108e4b17023SJohn Marino * - std::forward_list<_Node> containing the elements
109e4b17023SJohn Marino * - std::vector<std::forward_list<_Node>::iterator> representing the buckets
110e4b17023SJohn Marino *
111*5ce9237cSJohn Marino * The non-empty buckets contain the node before the first node in the
112*5ce9237cSJohn Marino * bucket. This design makes it possible to implement something like a
113*5ce9237cSJohn Marino * std::forward_list::insert_after on container insertion and
114*5ce9237cSJohn Marino * std::forward_list::erase_after on container erase calls.
115*5ce9237cSJohn Marino * _M_before_begin is equivalent to std::foward_list::before_begin.
116*5ce9237cSJohn Marino * Empty buckets contain nullptr.
117*5ce9237cSJohn Marino * Note that one of the non-empty buckets contains &_M_before_begin which is
118*5ce9237cSJohn Marino * not a dereferenceable node so the node pointer in a bucket shall never be
119*5ce9237cSJohn Marino * dereferenced, only its next node can be.
120e4b17023SJohn Marino *
121*5ce9237cSJohn Marino * Walking through a bucket's nodes requires a check on the hash code to see
122*5ce9237cSJohn Marino * if each node is still in the bucket. Such a design assumes a quite
123*5ce9237cSJohn Marino * efficient hash functor and is one of the reasons it is
124*5ce9237cSJohn Marino * highly advisable to set __cache_hash_code to true.
125e4b17023SJohn Marino *
126e4b17023SJohn Marino * The container iterators are simply built from nodes. This way incrementing
127e4b17023SJohn Marino * the iterator is perfectly efficient independent of how many empty buckets
128e4b17023SJohn Marino * there are in the container.
129e4b17023SJohn Marino *
130*5ce9237cSJohn Marino * On insert we compute the element's hash code and use it to it find the
131*5ce9237cSJohn Marino * bucket index. If the element must be inserted in an empty bucket we add
132*5ce9237cSJohn Marino * it at the beginning of the singly linked list and make the bucket point to
133e4b17023SJohn Marino * _M_before_begin. The bucket that used to point to _M_before_begin, if any,
134e4b17023SJohn Marino * is updated to point to its new before begin node.
135e4b17023SJohn Marino *
136*5ce9237cSJohn Marino * On erase, the simple iterator design requires using the hash functor to
137*5ce9237cSJohn Marino * get the index of the bucket to update. For this reason, when
138*5ce9237cSJohn Marino * __cache_hash_code is set to false, the hash functor must not throw
139*5ce9237cSJohn Marino * and this is enforced by a statied assertion.
140e4b17023SJohn Marino */
141e4b17023SJohn Marino
142e4b17023SJohn Marino template<typename _Key, typename _Value, typename _Allocator,
143e4b17023SJohn Marino typename _ExtractKey, typename _Equal,
144e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash,
145e4b17023SJohn Marino typename _RehashPolicy,
146e4b17023SJohn Marino bool __cache_hash_code,
147e4b17023SJohn Marino bool __constant_iterators,
148e4b17023SJohn Marino bool __unique_keys>
149e4b17023SJohn Marino class _Hashtable
150e4b17023SJohn Marino : public __detail::_Rehash_base<_RehashPolicy,
151e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator,
152e4b17023SJohn Marino _ExtractKey,
153e4b17023SJohn Marino _Equal, _H1, _H2, _Hash,
154e4b17023SJohn Marino _RehashPolicy,
155e4b17023SJohn Marino __cache_hash_code,
156e4b17023SJohn Marino __constant_iterators,
157e4b17023SJohn Marino __unique_keys> >,
158e4b17023SJohn Marino public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
159e4b17023SJohn Marino _H1, _H2, _Hash, __cache_hash_code>,
160e4b17023SJohn Marino public __detail::_Map_base<_Key, _Value, _ExtractKey, __unique_keys,
161e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator,
162e4b17023SJohn Marino _ExtractKey,
163e4b17023SJohn Marino _Equal, _H1, _H2, _Hash,
164e4b17023SJohn Marino _RehashPolicy,
165e4b17023SJohn Marino __cache_hash_code,
166e4b17023SJohn Marino __constant_iterators,
167e4b17023SJohn Marino __unique_keys> >,
168e4b17023SJohn Marino public __detail::_Equality_base<_ExtractKey, __unique_keys,
169e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator,
170e4b17023SJohn Marino _ExtractKey,
171e4b17023SJohn Marino _Equal, _H1, _H2, _Hash,
172e4b17023SJohn Marino _RehashPolicy,
173e4b17023SJohn Marino __cache_hash_code,
174e4b17023SJohn Marino __constant_iterators,
175e4b17023SJohn Marino __unique_keys> >
176e4b17023SJohn Marino {
177e4b17023SJohn Marino template<typename _Cond>
178e4b17023SJohn Marino using __if_hash_code_cached
179e4b17023SJohn Marino = __or_<__not_<integral_constant<bool, __cache_hash_code>>, _Cond>;
180e4b17023SJohn Marino
181e4b17023SJohn Marino template<typename _Cond>
182e4b17023SJohn Marino using __if_hash_code_not_cached
183e4b17023SJohn Marino = __or_<integral_constant<bool, __cache_hash_code>, _Cond>;
184e4b17023SJohn Marino
185e4b17023SJohn Marino // When hash codes are not cached the hash functor shall not throw
186e4b17023SJohn Marino // because it is used in methods (erase, swap...) that shall not throw.
187e4b17023SJohn Marino static_assert(__if_hash_code_not_cached<__detail::__is_noexcept_hash<_Key,
188e4b17023SJohn Marino _H1>>::value,
189e4b17023SJohn Marino "Cache the hash code or qualify your hash functor with noexcept");
190e4b17023SJohn Marino
191e4b17023SJohn Marino // Following two static assertions are necessary to guarantee that
192e4b17023SJohn Marino // swapping two hashtable instances won't invalidate associated local
193e4b17023SJohn Marino // iterators.
194e4b17023SJohn Marino
195e4b17023SJohn Marino // When hash codes are cached local iterator only uses H2 which must then
196e4b17023SJohn Marino // be empty.
197e4b17023SJohn Marino static_assert(__if_hash_code_cached<is_empty<_H2>>::value,
198e4b17023SJohn Marino "Functor used to map hash code to bucket index must be empty");
199e4b17023SJohn Marino
200e4b17023SJohn Marino typedef __detail::_Hash_code_base<_Key, _Value, _ExtractKey,
201e4b17023SJohn Marino _H1, _H2, _Hash,
202e4b17023SJohn Marino __cache_hash_code> _HCBase;
203e4b17023SJohn Marino
204e4b17023SJohn Marino // When hash codes are not cached local iterator is going to use _HCBase
205e4b17023SJohn Marino // above to compute node bucket index so it has to be empty.
206e4b17023SJohn Marino static_assert(__if_hash_code_not_cached<is_empty<_HCBase>>::value,
207e4b17023SJohn Marino "Cache the hash code or make functors involved in hash code"
208e4b17023SJohn Marino " and bucket index computation empty");
209e4b17023SJohn Marino
210e4b17023SJohn Marino public:
211e4b17023SJohn Marino typedef _Allocator allocator_type;
212e4b17023SJohn Marino typedef _Value value_type;
213e4b17023SJohn Marino typedef _Key key_type;
214e4b17023SJohn Marino typedef _Equal key_equal;
215e4b17023SJohn Marino // mapped_type, if present, comes from _Map_base.
216e4b17023SJohn Marino // hasher, if present, comes from _Hash_code_base.
217e4b17023SJohn Marino typedef typename _Allocator::pointer pointer;
218e4b17023SJohn Marino typedef typename _Allocator::const_pointer const_pointer;
219e4b17023SJohn Marino typedef typename _Allocator::reference reference;
220e4b17023SJohn Marino typedef typename _Allocator::const_reference const_reference;
221e4b17023SJohn Marino
222e4b17023SJohn Marino typedef std::size_t size_type;
223e4b17023SJohn Marino typedef std::ptrdiff_t difference_type;
224e4b17023SJohn Marino typedef __detail::_Local_iterator<key_type, value_type, _ExtractKey,
225e4b17023SJohn Marino _H1, _H2, _Hash,
226e4b17023SJohn Marino __constant_iterators,
227e4b17023SJohn Marino __cache_hash_code>
228e4b17023SJohn Marino local_iterator;
229e4b17023SJohn Marino typedef __detail::_Local_const_iterator<key_type, value_type, _ExtractKey,
230e4b17023SJohn Marino _H1, _H2, _Hash,
231e4b17023SJohn Marino __constant_iterators,
232e4b17023SJohn Marino __cache_hash_code>
233e4b17023SJohn Marino const_local_iterator;
234e4b17023SJohn Marino typedef __detail::_Node_iterator<value_type, __constant_iterators,
235e4b17023SJohn Marino __cache_hash_code>
236e4b17023SJohn Marino iterator;
237e4b17023SJohn Marino typedef __detail::_Node_const_iterator<value_type,
238e4b17023SJohn Marino __constant_iterators,
239e4b17023SJohn Marino __cache_hash_code>
240e4b17023SJohn Marino const_iterator;
241e4b17023SJohn Marino
242e4b17023SJohn Marino template<typename _Key2, typename _Value2, typename _Ex2, bool __unique2,
243e4b17023SJohn Marino typename _Hashtable2>
244e4b17023SJohn Marino friend struct __detail::_Map_base;
245e4b17023SJohn Marino
246e4b17023SJohn Marino private:
247e4b17023SJohn Marino typedef typename _RehashPolicy::_State _RehashPolicyState;
248e4b17023SJohn Marino typedef __detail::_Hash_node<_Value, __cache_hash_code> _Node;
249e4b17023SJohn Marino typedef typename _Allocator::template rebind<_Node>::other
250e4b17023SJohn Marino _Node_allocator_type;
251e4b17023SJohn Marino typedef __detail::_Hash_node_base _BaseNode;
252e4b17023SJohn Marino typedef _BaseNode* _Bucket;
253e4b17023SJohn Marino typedef typename _Allocator::template rebind<_Bucket>::other
254e4b17023SJohn Marino _Bucket_allocator_type;
255e4b17023SJohn Marino
256e4b17023SJohn Marino typedef typename _Allocator::template rebind<_Value>::other
257e4b17023SJohn Marino _Value_allocator_type;
258e4b17023SJohn Marino
259e4b17023SJohn Marino _Node_allocator_type _M_node_allocator;
260e4b17023SJohn Marino _Bucket* _M_buckets;
261e4b17023SJohn Marino size_type _M_bucket_count;
262e4b17023SJohn Marino _BaseNode _M_before_begin;
263e4b17023SJohn Marino size_type _M_element_count;
264e4b17023SJohn Marino _RehashPolicy _M_rehash_policy;
265e4b17023SJohn Marino
266e4b17023SJohn Marino template<typename... _Args>
267e4b17023SJohn Marino _Node*
268e4b17023SJohn Marino _M_allocate_node(_Args&&... __args);
269e4b17023SJohn Marino
270e4b17023SJohn Marino void
271e4b17023SJohn Marino _M_deallocate_node(_Node* __n);
272e4b17023SJohn Marino
273e4b17023SJohn Marino // Deallocate the linked list of nodes pointed to by __n
274e4b17023SJohn Marino void
275e4b17023SJohn Marino _M_deallocate_nodes(_Node* __n);
276e4b17023SJohn Marino
277e4b17023SJohn Marino _Bucket*
278e4b17023SJohn Marino _M_allocate_buckets(size_type __n);
279e4b17023SJohn Marino
280e4b17023SJohn Marino void
281e4b17023SJohn Marino _M_deallocate_buckets(_Bucket*, size_type __n);
282e4b17023SJohn Marino
283e4b17023SJohn Marino // Gets bucket begin, deals with the fact that non-empty buckets contain
284e4b17023SJohn Marino // their before begin node.
285e4b17023SJohn Marino _Node*
286e4b17023SJohn Marino _M_bucket_begin(size_type __bkt) const;
287e4b17023SJohn Marino
288e4b17023SJohn Marino _Node*
289e4b17023SJohn Marino _M_begin() const
290e4b17023SJohn Marino { return static_cast<_Node*>(_M_before_begin._M_nxt); }
291e4b17023SJohn Marino
292e4b17023SJohn Marino public:
293e4b17023SJohn Marino // Constructor, destructor, assignment, swap
294e4b17023SJohn Marino _Hashtable(size_type __bucket_hint,
295e4b17023SJohn Marino const _H1&, const _H2&, const _Hash&,
296e4b17023SJohn Marino const _Equal&, const _ExtractKey&,
297e4b17023SJohn Marino const allocator_type&);
298e4b17023SJohn Marino
299e4b17023SJohn Marino template<typename _InputIterator>
300e4b17023SJohn Marino _Hashtable(_InputIterator __first, _InputIterator __last,
301e4b17023SJohn Marino size_type __bucket_hint,
302e4b17023SJohn Marino const _H1&, const _H2&, const _Hash&,
303e4b17023SJohn Marino const _Equal&, const _ExtractKey&,
304e4b17023SJohn Marino const allocator_type&);
305e4b17023SJohn Marino
306e4b17023SJohn Marino _Hashtable(const _Hashtable&);
307e4b17023SJohn Marino
308e4b17023SJohn Marino _Hashtable(_Hashtable&&);
309e4b17023SJohn Marino
310e4b17023SJohn Marino _Hashtable&
311e4b17023SJohn Marino operator=(const _Hashtable& __ht)
312e4b17023SJohn Marino {
313e4b17023SJohn Marino _Hashtable __tmp(__ht);
314e4b17023SJohn Marino this->swap(__tmp);
315e4b17023SJohn Marino return *this;
316e4b17023SJohn Marino }
317e4b17023SJohn Marino
318e4b17023SJohn Marino _Hashtable&
319e4b17023SJohn Marino operator=(_Hashtable&& __ht)
320e4b17023SJohn Marino {
321e4b17023SJohn Marino // NB: DR 1204.
322e4b17023SJohn Marino // NB: DR 675.
323e4b17023SJohn Marino this->clear();
324e4b17023SJohn Marino this->swap(__ht);
325e4b17023SJohn Marino return *this;
326e4b17023SJohn Marino }
327e4b17023SJohn Marino
328e4b17023SJohn Marino ~_Hashtable() noexcept;
329e4b17023SJohn Marino
330e4b17023SJohn Marino void swap(_Hashtable&);
331e4b17023SJohn Marino
332e4b17023SJohn Marino // Basic container operations
333e4b17023SJohn Marino iterator
334e4b17023SJohn Marino begin() noexcept
335e4b17023SJohn Marino { return iterator(_M_begin()); }
336e4b17023SJohn Marino
337e4b17023SJohn Marino const_iterator
338e4b17023SJohn Marino begin() const noexcept
339e4b17023SJohn Marino { return const_iterator(_M_begin()); }
340e4b17023SJohn Marino
341e4b17023SJohn Marino iterator
342e4b17023SJohn Marino end() noexcept
343e4b17023SJohn Marino { return iterator(nullptr); }
344e4b17023SJohn Marino
345e4b17023SJohn Marino const_iterator
346e4b17023SJohn Marino end() const noexcept
347e4b17023SJohn Marino { return const_iterator(nullptr); }
348e4b17023SJohn Marino
349e4b17023SJohn Marino const_iterator
350e4b17023SJohn Marino cbegin() const noexcept
351e4b17023SJohn Marino { return const_iterator(_M_begin()); }
352e4b17023SJohn Marino
353e4b17023SJohn Marino const_iterator
354e4b17023SJohn Marino cend() const noexcept
355e4b17023SJohn Marino { return const_iterator(nullptr); }
356e4b17023SJohn Marino
357e4b17023SJohn Marino size_type
358e4b17023SJohn Marino size() const noexcept
359e4b17023SJohn Marino { return _M_element_count; }
360e4b17023SJohn Marino
361e4b17023SJohn Marino bool
362e4b17023SJohn Marino empty() const noexcept
363e4b17023SJohn Marino { return size() == 0; }
364e4b17023SJohn Marino
365e4b17023SJohn Marino allocator_type
366e4b17023SJohn Marino get_allocator() const noexcept
367e4b17023SJohn Marino { return allocator_type(_M_node_allocator); }
368e4b17023SJohn Marino
369e4b17023SJohn Marino size_type
370e4b17023SJohn Marino max_size() const noexcept
371e4b17023SJohn Marino { return _M_node_allocator.max_size(); }
372e4b17023SJohn Marino
373e4b17023SJohn Marino // Observers
374e4b17023SJohn Marino key_equal
375e4b17023SJohn Marino key_eq() const
376e4b17023SJohn Marino { return this->_M_eq(); }
377e4b17023SJohn Marino
378e4b17023SJohn Marino // hash_function, if present, comes from _Hash_code_base.
379e4b17023SJohn Marino
380e4b17023SJohn Marino // Bucket operations
381e4b17023SJohn Marino size_type
382e4b17023SJohn Marino bucket_count() const noexcept
383e4b17023SJohn Marino { return _M_bucket_count; }
384e4b17023SJohn Marino
385e4b17023SJohn Marino size_type
386e4b17023SJohn Marino max_bucket_count() const noexcept
387e4b17023SJohn Marino { return max_size(); }
388e4b17023SJohn Marino
389e4b17023SJohn Marino size_type
390e4b17023SJohn Marino bucket_size(size_type __n) const
391e4b17023SJohn Marino { return std::distance(begin(__n), end(__n)); }
392e4b17023SJohn Marino
393e4b17023SJohn Marino size_type
394e4b17023SJohn Marino bucket(const key_type& __k) const
395e4b17023SJohn Marino { return _M_bucket_index(__k, this->_M_hash_code(__k)); }
396e4b17023SJohn Marino
397e4b17023SJohn Marino local_iterator
398e4b17023SJohn Marino begin(size_type __n)
399e4b17023SJohn Marino { return local_iterator(_M_bucket_begin(__n), __n,
400e4b17023SJohn Marino _M_bucket_count); }
401e4b17023SJohn Marino
402e4b17023SJohn Marino local_iterator
403e4b17023SJohn Marino end(size_type __n)
404e4b17023SJohn Marino { return local_iterator(nullptr, __n, _M_bucket_count); }
405e4b17023SJohn Marino
406e4b17023SJohn Marino const_local_iterator
407e4b17023SJohn Marino begin(size_type __n) const
408e4b17023SJohn Marino { return const_local_iterator(_M_bucket_begin(__n), __n,
409e4b17023SJohn Marino _M_bucket_count); }
410e4b17023SJohn Marino
411e4b17023SJohn Marino const_local_iterator
412e4b17023SJohn Marino end(size_type __n) const
413e4b17023SJohn Marino { return const_local_iterator(nullptr, __n, _M_bucket_count); }
414e4b17023SJohn Marino
415e4b17023SJohn Marino // DR 691.
416e4b17023SJohn Marino const_local_iterator
417e4b17023SJohn Marino cbegin(size_type __n) const
418e4b17023SJohn Marino { return const_local_iterator(_M_bucket_begin(__n), __n,
419e4b17023SJohn Marino _M_bucket_count); }
420e4b17023SJohn Marino
421e4b17023SJohn Marino const_local_iterator
422e4b17023SJohn Marino cend(size_type __n) const
423e4b17023SJohn Marino { return const_local_iterator(nullptr, __n, _M_bucket_count); }
424e4b17023SJohn Marino
425e4b17023SJohn Marino float
426e4b17023SJohn Marino load_factor() const noexcept
427e4b17023SJohn Marino {
428e4b17023SJohn Marino return static_cast<float>(size()) / static_cast<float>(bucket_count());
429e4b17023SJohn Marino }
430e4b17023SJohn Marino
431e4b17023SJohn Marino // max_load_factor, if present, comes from _Rehash_base.
432e4b17023SJohn Marino
433e4b17023SJohn Marino // Generalization of max_load_factor. Extension, not found in TR1. Only
434e4b17023SJohn Marino // useful if _RehashPolicy is something other than the default.
435e4b17023SJohn Marino const _RehashPolicy&
436e4b17023SJohn Marino __rehash_policy() const
437e4b17023SJohn Marino { return _M_rehash_policy; }
438e4b17023SJohn Marino
439e4b17023SJohn Marino void
440e4b17023SJohn Marino __rehash_policy(const _RehashPolicy&);
441e4b17023SJohn Marino
442e4b17023SJohn Marino // Lookup.
443e4b17023SJohn Marino iterator
444e4b17023SJohn Marino find(const key_type& __k);
445e4b17023SJohn Marino
446e4b17023SJohn Marino const_iterator
447e4b17023SJohn Marino find(const key_type& __k) const;
448e4b17023SJohn Marino
449e4b17023SJohn Marino size_type
450e4b17023SJohn Marino count(const key_type& __k) const;
451e4b17023SJohn Marino
452e4b17023SJohn Marino std::pair<iterator, iterator>
453e4b17023SJohn Marino equal_range(const key_type& __k);
454e4b17023SJohn Marino
455e4b17023SJohn Marino std::pair<const_iterator, const_iterator>
456e4b17023SJohn Marino equal_range(const key_type& __k) const;
457e4b17023SJohn Marino
458e4b17023SJohn Marino private:
459e4b17023SJohn Marino // Bucket index computation helpers.
460e4b17023SJohn Marino size_type
461e4b17023SJohn Marino _M_bucket_index(_Node* __n) const
462e4b17023SJohn Marino { return _HCBase::_M_bucket_index(__n, _M_bucket_count); }
463e4b17023SJohn Marino
464e4b17023SJohn Marino size_type
465e4b17023SJohn Marino _M_bucket_index(const key_type& __k,
466e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __c) const
467e4b17023SJohn Marino { return _HCBase::_M_bucket_index(__k, __c, _M_bucket_count); }
468e4b17023SJohn Marino
469e4b17023SJohn Marino // Find and insert helper functions and types
470e4b17023SJohn Marino // Find the node before the one matching the criteria.
471e4b17023SJohn Marino _BaseNode*
472e4b17023SJohn Marino _M_find_before_node(size_type, const key_type&,
473e4b17023SJohn Marino typename _Hashtable::_Hash_code_type) const;
474e4b17023SJohn Marino
475e4b17023SJohn Marino _Node*
476e4b17023SJohn Marino _M_find_node(size_type __bkt, const key_type& __key,
477e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __c) const
478e4b17023SJohn Marino {
479e4b17023SJohn Marino _BaseNode* __before_n = _M_find_before_node(__bkt, __key, __c);
480e4b17023SJohn Marino if (__before_n)
481e4b17023SJohn Marino return static_cast<_Node*>(__before_n->_M_nxt);
482e4b17023SJohn Marino return nullptr;
483e4b17023SJohn Marino }
484e4b17023SJohn Marino
485e4b17023SJohn Marino // Insert a node at the beginning of a bucket.
486e4b17023SJohn Marino void
487e4b17023SJohn Marino _M_insert_bucket_begin(size_type, _Node*);
488e4b17023SJohn Marino
489e4b17023SJohn Marino // Remove the bucket first node
490e4b17023SJohn Marino void
491e4b17023SJohn Marino _M_remove_bucket_begin(size_type __bkt, _Node* __next_n,
492e4b17023SJohn Marino size_type __next_bkt);
493e4b17023SJohn Marino
494e4b17023SJohn Marino // Get the node before __n in the bucket __bkt
495e4b17023SJohn Marino _BaseNode*
496e4b17023SJohn Marino _M_get_previous_node(size_type __bkt, _BaseNode* __n);
497e4b17023SJohn Marino
498e4b17023SJohn Marino template<typename _Arg>
499e4b17023SJohn Marino iterator
500e4b17023SJohn Marino _M_insert_bucket(_Arg&&, size_type,
501e4b17023SJohn Marino typename _Hashtable::_Hash_code_type);
502e4b17023SJohn Marino
503e4b17023SJohn Marino typedef typename std::conditional<__unique_keys,
504e4b17023SJohn Marino std::pair<iterator, bool>,
505e4b17023SJohn Marino iterator>::type
506e4b17023SJohn Marino _Insert_Return_Type;
507e4b17023SJohn Marino
508e4b17023SJohn Marino typedef typename std::conditional<__unique_keys,
509e4b17023SJohn Marino std::_Select1st<_Insert_Return_Type>,
510e4b17023SJohn Marino std::_Identity<_Insert_Return_Type>
511e4b17023SJohn Marino >::type
512e4b17023SJohn Marino _Insert_Conv_Type;
513e4b17023SJohn Marino
514e4b17023SJohn Marino protected:
515e4b17023SJohn Marino template<typename... _Args>
516e4b17023SJohn Marino std::pair<iterator, bool>
517e4b17023SJohn Marino _M_emplace(std::true_type, _Args&&... __args);
518e4b17023SJohn Marino
519e4b17023SJohn Marino template<typename... _Args>
520e4b17023SJohn Marino iterator
521e4b17023SJohn Marino _M_emplace(std::false_type, _Args&&... __args);
522e4b17023SJohn Marino
523e4b17023SJohn Marino template<typename _Arg>
524e4b17023SJohn Marino std::pair<iterator, bool>
525e4b17023SJohn Marino _M_insert(_Arg&&, std::true_type);
526e4b17023SJohn Marino
527e4b17023SJohn Marino template<typename _Arg>
528e4b17023SJohn Marino iterator
529e4b17023SJohn Marino _M_insert(_Arg&&, std::false_type);
530e4b17023SJohn Marino
531e4b17023SJohn Marino public:
532e4b17023SJohn Marino // Emplace, insert and erase
533e4b17023SJohn Marino template<typename... _Args>
534e4b17023SJohn Marino _Insert_Return_Type
535e4b17023SJohn Marino emplace(_Args&&... __args)
536e4b17023SJohn Marino { return _M_emplace(integral_constant<bool, __unique_keys>(),
537e4b17023SJohn Marino std::forward<_Args>(__args)...); }
538e4b17023SJohn Marino
539e4b17023SJohn Marino template<typename... _Args>
540e4b17023SJohn Marino iterator
541e4b17023SJohn Marino emplace_hint(const_iterator, _Args&&... __args)
542e4b17023SJohn Marino { return _Insert_Conv_Type()(emplace(std::forward<_Args>(__args)...)); }
543e4b17023SJohn Marino
544e4b17023SJohn Marino _Insert_Return_Type
545e4b17023SJohn Marino insert(const value_type& __v)
546e4b17023SJohn Marino { return _M_insert(__v, integral_constant<bool, __unique_keys>()); }
547e4b17023SJohn Marino
548e4b17023SJohn Marino iterator
549e4b17023SJohn Marino insert(const_iterator, const value_type& __v)
550e4b17023SJohn Marino { return _Insert_Conv_Type()(insert(__v)); }
551e4b17023SJohn Marino
552e4b17023SJohn Marino template<typename _Pair, typename = typename
553e4b17023SJohn Marino std::enable_if<__and_<integral_constant<bool, !__constant_iterators>,
554e4b17023SJohn Marino std::is_constructible<value_type,
555e4b17023SJohn Marino _Pair&&>>::value>::type>
556e4b17023SJohn Marino _Insert_Return_Type
557e4b17023SJohn Marino insert(_Pair&& __v)
558e4b17023SJohn Marino { return _M_insert(std::forward<_Pair>(__v),
559e4b17023SJohn Marino integral_constant<bool, __unique_keys>()); }
560e4b17023SJohn Marino
561e4b17023SJohn Marino template<typename _Pair, typename = typename
562e4b17023SJohn Marino std::enable_if<__and_<integral_constant<bool, !__constant_iterators>,
563e4b17023SJohn Marino std::is_constructible<value_type,
564e4b17023SJohn Marino _Pair&&>>::value>::type>
565e4b17023SJohn Marino iterator
566e4b17023SJohn Marino insert(const_iterator, _Pair&& __v)
567e4b17023SJohn Marino { return _Insert_Conv_Type()(insert(std::forward<_Pair>(__v))); }
568e4b17023SJohn Marino
569e4b17023SJohn Marino template<typename _InputIterator>
570e4b17023SJohn Marino void
571e4b17023SJohn Marino insert(_InputIterator __first, _InputIterator __last);
572e4b17023SJohn Marino
573e4b17023SJohn Marino void
574e4b17023SJohn Marino insert(initializer_list<value_type> __l)
575e4b17023SJohn Marino { this->insert(__l.begin(), __l.end()); }
576e4b17023SJohn Marino
577e4b17023SJohn Marino iterator
578e4b17023SJohn Marino erase(const_iterator);
579e4b17023SJohn Marino
580e4b17023SJohn Marino // LWG 2059.
581e4b17023SJohn Marino iterator
582e4b17023SJohn Marino erase(iterator __it)
583e4b17023SJohn Marino { return erase(const_iterator(__it)); }
584e4b17023SJohn Marino
585e4b17023SJohn Marino size_type
586e4b17023SJohn Marino erase(const key_type&);
587e4b17023SJohn Marino
588e4b17023SJohn Marino iterator
589e4b17023SJohn Marino erase(const_iterator, const_iterator);
590e4b17023SJohn Marino
591e4b17023SJohn Marino void
592e4b17023SJohn Marino clear() noexcept;
593e4b17023SJohn Marino
594e4b17023SJohn Marino // Set number of buckets to be appropriate for container of n element.
595e4b17023SJohn Marino void rehash(size_type __n);
596e4b17023SJohn Marino
597e4b17023SJohn Marino // DR 1189.
598e4b17023SJohn Marino // reserve, if present, comes from _Rehash_base.
599e4b17023SJohn Marino
600e4b17023SJohn Marino private:
601e4b17023SJohn Marino // Helper rehash method used when keys are unique.
602e4b17023SJohn Marino void _M_rehash_aux(size_type __n, std::true_type);
603e4b17023SJohn Marino
604e4b17023SJohn Marino // Helper rehash method used when keys can be non-unique.
605e4b17023SJohn Marino void _M_rehash_aux(size_type __n, std::false_type);
606e4b17023SJohn Marino
607e4b17023SJohn Marino // Unconditionally change size of bucket array to n, restore hash policy
608e4b17023SJohn Marino // state to __state on exception.
609e4b17023SJohn Marino void _M_rehash(size_type __n, const _RehashPolicyState& __state);
610e4b17023SJohn Marino };
611e4b17023SJohn Marino
612e4b17023SJohn Marino
613e4b17023SJohn Marino // Definitions of class template _Hashtable's out-of-line member functions.
614e4b17023SJohn Marino template<typename _Key, typename _Value,
615e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
616e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
617e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
618e4b17023SJohn Marino template<typename... _Args>
619e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
620e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
621e4b17023SJohn Marino __chc, __cit, __uk>::_Node*
622e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
623e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
624e4b17023SJohn Marino _M_allocate_node(_Args&&... __args)
625e4b17023SJohn Marino {
626e4b17023SJohn Marino _Node* __n = _M_node_allocator.allocate(1);
627e4b17023SJohn Marino __try
628e4b17023SJohn Marino {
629e4b17023SJohn Marino _M_node_allocator.construct(__n, std::forward<_Args>(__args)...);
630e4b17023SJohn Marino return __n;
631e4b17023SJohn Marino }
632e4b17023SJohn Marino __catch(...)
633e4b17023SJohn Marino {
634e4b17023SJohn Marino _M_node_allocator.deallocate(__n, 1);
635e4b17023SJohn Marino __throw_exception_again;
636e4b17023SJohn Marino }
637e4b17023SJohn Marino }
638e4b17023SJohn Marino
639e4b17023SJohn Marino template<typename _Key, typename _Value,
640e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
641e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
642e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
643e4b17023SJohn Marino void
644e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
645e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
646e4b17023SJohn Marino _M_deallocate_node(_Node* __n)
647e4b17023SJohn Marino {
648e4b17023SJohn Marino _M_node_allocator.destroy(__n);
649e4b17023SJohn Marino _M_node_allocator.deallocate(__n, 1);
650e4b17023SJohn Marino }
651e4b17023SJohn Marino
652e4b17023SJohn Marino template<typename _Key, typename _Value,
653e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
654e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
655e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
656e4b17023SJohn Marino void
657e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
658e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
659e4b17023SJohn Marino _M_deallocate_nodes(_Node* __n)
660e4b17023SJohn Marino {
661e4b17023SJohn Marino while (__n)
662e4b17023SJohn Marino {
663e4b17023SJohn Marino _Node* __tmp = __n;
664e4b17023SJohn Marino __n = __n->_M_next();
665e4b17023SJohn Marino _M_deallocate_node(__tmp);
666e4b17023SJohn Marino }
667e4b17023SJohn Marino }
668e4b17023SJohn Marino
669e4b17023SJohn Marino template<typename _Key, typename _Value,
670e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
671e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
672e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
673e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
674e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
675e4b17023SJohn Marino __chc, __cit, __uk>::_Bucket*
676e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
677e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
678e4b17023SJohn Marino _M_allocate_buckets(size_type __n)
679e4b17023SJohn Marino {
680e4b17023SJohn Marino _Bucket_allocator_type __alloc(_M_node_allocator);
681e4b17023SJohn Marino
682e4b17023SJohn Marino _Bucket* __p = __alloc.allocate(__n);
683e4b17023SJohn Marino __builtin_memset(__p, 0, __n * sizeof(_Bucket));
684e4b17023SJohn Marino return __p;
685e4b17023SJohn Marino }
686e4b17023SJohn Marino
687e4b17023SJohn Marino template<typename _Key, typename _Value,
688e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
689e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
690e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
691e4b17023SJohn Marino void
692e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
693e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
694e4b17023SJohn Marino _M_deallocate_buckets(_Bucket* __p, size_type __n)
695e4b17023SJohn Marino {
696e4b17023SJohn Marino _Bucket_allocator_type __alloc(_M_node_allocator);
697e4b17023SJohn Marino __alloc.deallocate(__p, __n);
698e4b17023SJohn Marino }
699e4b17023SJohn Marino
700e4b17023SJohn Marino template<typename _Key, typename _Value,
701e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
702e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
703e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
704e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey,
705e4b17023SJohn Marino _Equal, _H1, _H2, _Hash, _RehashPolicy,
706e4b17023SJohn Marino __chc, __cit, __uk>::_Node*
707e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
708e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
709e4b17023SJohn Marino _M_bucket_begin(size_type __bkt) const
710e4b17023SJohn Marino {
711e4b17023SJohn Marino _BaseNode* __n = _M_buckets[__bkt];
712e4b17023SJohn Marino return __n ? static_cast<_Node*>(__n->_M_nxt) : nullptr;
713e4b17023SJohn Marino }
714e4b17023SJohn Marino
715e4b17023SJohn Marino template<typename _Key, typename _Value,
716e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
717e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
718e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
719e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
720e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
721e4b17023SJohn Marino _Hashtable(size_type __bucket_hint,
722e4b17023SJohn Marino const _H1& __h1, const _H2& __h2, const _Hash& __h,
723e4b17023SJohn Marino const _Equal& __eq, const _ExtractKey& __exk,
724e4b17023SJohn Marino const allocator_type& __a)
725e4b17023SJohn Marino : __detail::_Rehash_base<_RehashPolicy, _Hashtable>(),
726e4b17023SJohn Marino __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
727e4b17023SJohn Marino _H1, _H2, _Hash, __chc>(__exk, __h1, __h2, __h,
728e4b17023SJohn Marino __eq),
729e4b17023SJohn Marino __detail::_Map_base<_Key, _Value, _ExtractKey, __uk, _Hashtable>(),
730e4b17023SJohn Marino _M_node_allocator(__a),
731e4b17023SJohn Marino _M_bucket_count(0),
732e4b17023SJohn Marino _M_element_count(0),
733e4b17023SJohn Marino _M_rehash_policy()
734e4b17023SJohn Marino {
735e4b17023SJohn Marino _M_bucket_count = _M_rehash_policy._M_next_bkt(__bucket_hint);
736e4b17023SJohn Marino // We don't want the rehash policy to ask for the hashtable to shrink
737e4b17023SJohn Marino // on the first insertion so we need to reset its previous resize level.
738e4b17023SJohn Marino _M_rehash_policy._M_prev_resize = 0;
739e4b17023SJohn Marino _M_buckets = _M_allocate_buckets(_M_bucket_count);
740e4b17023SJohn Marino }
741e4b17023SJohn Marino
742e4b17023SJohn Marino template<typename _Key, typename _Value,
743e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
744e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
745e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
746e4b17023SJohn Marino template<typename _InputIterator>
747e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
748e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
749e4b17023SJohn Marino _Hashtable(_InputIterator __f, _InputIterator __l,
750e4b17023SJohn Marino size_type __bucket_hint,
751e4b17023SJohn Marino const _H1& __h1, const _H2& __h2, const _Hash& __h,
752e4b17023SJohn Marino const _Equal& __eq, const _ExtractKey& __exk,
753e4b17023SJohn Marino const allocator_type& __a)
754e4b17023SJohn Marino : __detail::_Rehash_base<_RehashPolicy, _Hashtable>(),
755e4b17023SJohn Marino __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
756e4b17023SJohn Marino _H1, _H2, _Hash, __chc>(__exk, __h1, __h2, __h,
757e4b17023SJohn Marino __eq),
758e4b17023SJohn Marino __detail::_Map_base<_Key, _Value, _ExtractKey, __uk, _Hashtable>(),
759e4b17023SJohn Marino _M_node_allocator(__a),
760e4b17023SJohn Marino _M_bucket_count(0),
761e4b17023SJohn Marino _M_element_count(0),
762e4b17023SJohn Marino _M_rehash_policy()
763e4b17023SJohn Marino {
764e4b17023SJohn Marino _M_bucket_count =
765e4b17023SJohn Marino _M_rehash_policy._M_bkt_for_elements(__detail::__distance_fw(__f,
766e4b17023SJohn Marino __l));
767e4b17023SJohn Marino if (_M_bucket_count <= __bucket_hint)
768e4b17023SJohn Marino _M_bucket_count = _M_rehash_policy._M_next_bkt(__bucket_hint);
769e4b17023SJohn Marino
770e4b17023SJohn Marino // We don't want the rehash policy to ask for the hashtable to shrink
771e4b17023SJohn Marino // on the first insertion so we need to reset its previous resize
772e4b17023SJohn Marino // level.
773e4b17023SJohn Marino _M_rehash_policy._M_prev_resize = 0;
774e4b17023SJohn Marino _M_buckets = _M_allocate_buckets(_M_bucket_count);
775e4b17023SJohn Marino __try
776e4b17023SJohn Marino {
777e4b17023SJohn Marino for (; __f != __l; ++__f)
778e4b17023SJohn Marino this->insert(*__f);
779e4b17023SJohn Marino }
780e4b17023SJohn Marino __catch(...)
781e4b17023SJohn Marino {
782e4b17023SJohn Marino clear();
783e4b17023SJohn Marino _M_deallocate_buckets(_M_buckets, _M_bucket_count);
784e4b17023SJohn Marino __throw_exception_again;
785e4b17023SJohn Marino }
786e4b17023SJohn Marino }
787e4b17023SJohn Marino
788e4b17023SJohn Marino template<typename _Key, typename _Value,
789e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
790e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
791e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
792e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
793e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
794e4b17023SJohn Marino _Hashtable(const _Hashtable& __ht)
795e4b17023SJohn Marino : __detail::_Rehash_base<_RehashPolicy, _Hashtable>(__ht),
796e4b17023SJohn Marino __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
797e4b17023SJohn Marino _H1, _H2, _Hash, __chc>(__ht),
798e4b17023SJohn Marino __detail::_Map_base<_Key, _Value, _ExtractKey, __uk, _Hashtable>(__ht),
799e4b17023SJohn Marino _M_node_allocator(__ht._M_node_allocator),
800e4b17023SJohn Marino _M_bucket_count(__ht._M_bucket_count),
801e4b17023SJohn Marino _M_element_count(__ht._M_element_count),
802e4b17023SJohn Marino _M_rehash_policy(__ht._M_rehash_policy)
803e4b17023SJohn Marino {
804e4b17023SJohn Marino _M_buckets = _M_allocate_buckets(_M_bucket_count);
805e4b17023SJohn Marino __try
806e4b17023SJohn Marino {
807e4b17023SJohn Marino if (!__ht._M_before_begin._M_nxt)
808e4b17023SJohn Marino return;
809e4b17023SJohn Marino
810e4b17023SJohn Marino // First deal with the special first node pointed to by
811e4b17023SJohn Marino // _M_before_begin.
812e4b17023SJohn Marino const _Node* __ht_n = __ht._M_begin();
813e4b17023SJohn Marino _Node* __this_n = _M_allocate_node(__ht_n->_M_v);
814e4b17023SJohn Marino this->_M_copy_code(__this_n, __ht_n);
815e4b17023SJohn Marino _M_before_begin._M_nxt = __this_n;
816e4b17023SJohn Marino _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin;
817e4b17023SJohn Marino
818e4b17023SJohn Marino // Then deal with other nodes.
819e4b17023SJohn Marino _BaseNode* __prev_n = __this_n;
820e4b17023SJohn Marino for (__ht_n = __ht_n->_M_next(); __ht_n; __ht_n = __ht_n->_M_next())
821e4b17023SJohn Marino {
822e4b17023SJohn Marino __this_n = _M_allocate_node(__ht_n->_M_v);
823e4b17023SJohn Marino __prev_n->_M_nxt = __this_n;
824e4b17023SJohn Marino this->_M_copy_code(__this_n, __ht_n);
825e4b17023SJohn Marino size_type __bkt = _M_bucket_index(__this_n);
826e4b17023SJohn Marino if (!_M_buckets[__bkt])
827e4b17023SJohn Marino _M_buckets[__bkt] = __prev_n;
828e4b17023SJohn Marino __prev_n = __this_n;
829e4b17023SJohn Marino }
830e4b17023SJohn Marino }
831e4b17023SJohn Marino __catch(...)
832e4b17023SJohn Marino {
833e4b17023SJohn Marino clear();
834e4b17023SJohn Marino _M_deallocate_buckets(_M_buckets, _M_bucket_count);
835e4b17023SJohn Marino __throw_exception_again;
836e4b17023SJohn Marino }
837e4b17023SJohn Marino }
838e4b17023SJohn Marino
839e4b17023SJohn Marino template<typename _Key, typename _Value,
840e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
841e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
842e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
843e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
844e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
845e4b17023SJohn Marino _Hashtable(_Hashtable&& __ht)
846e4b17023SJohn Marino : __detail::_Rehash_base<_RehashPolicy, _Hashtable>(__ht),
847e4b17023SJohn Marino __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,
848e4b17023SJohn Marino _H1, _H2, _Hash, __chc>(__ht),
849e4b17023SJohn Marino __detail::_Map_base<_Key, _Value, _ExtractKey, __uk, _Hashtable>(__ht),
850e4b17023SJohn Marino _M_node_allocator(std::move(__ht._M_node_allocator)),
851e4b17023SJohn Marino _M_buckets(__ht._M_buckets),
852e4b17023SJohn Marino _M_bucket_count(__ht._M_bucket_count),
853e4b17023SJohn Marino _M_before_begin(__ht._M_before_begin._M_nxt),
854e4b17023SJohn Marino _M_element_count(__ht._M_element_count),
855e4b17023SJohn Marino _M_rehash_policy(__ht._M_rehash_policy)
856e4b17023SJohn Marino {
857e4b17023SJohn Marino // Update, if necessary, bucket pointing to before begin that hasn't move.
858e4b17023SJohn Marino if (_M_begin())
859e4b17023SJohn Marino _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
860e4b17023SJohn Marino __ht._M_rehash_policy = _RehashPolicy();
861e4b17023SJohn Marino __ht._M_bucket_count = __ht._M_rehash_policy._M_next_bkt(0);
862e4b17023SJohn Marino __ht._M_buckets = __ht._M_allocate_buckets(__ht._M_bucket_count);
863e4b17023SJohn Marino __ht._M_before_begin._M_nxt = nullptr;
864e4b17023SJohn Marino __ht._M_element_count = 0;
865e4b17023SJohn Marino }
866e4b17023SJohn Marino
867e4b17023SJohn Marino template<typename _Key, typename _Value,
868e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
869e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
870e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
871e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
872e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
873e4b17023SJohn Marino ~_Hashtable() noexcept
874e4b17023SJohn Marino {
875e4b17023SJohn Marino clear();
876e4b17023SJohn Marino _M_deallocate_buckets(_M_buckets, _M_bucket_count);
877e4b17023SJohn Marino }
878e4b17023SJohn Marino
879e4b17023SJohn Marino template<typename _Key, typename _Value,
880e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
881e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
882e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
883e4b17023SJohn Marino void
884e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
885e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
886e4b17023SJohn Marino swap(_Hashtable& __x)
887e4b17023SJohn Marino {
888e4b17023SJohn Marino // The only base class with member variables is hash_code_base. We
889e4b17023SJohn Marino // define _Hash_code_base::_M_swap because different specializations
890e4b17023SJohn Marino // have different members.
891e4b17023SJohn Marino this->_M_swap(__x);
892e4b17023SJohn Marino
893e4b17023SJohn Marino // _GLIBCXX_RESOLVE_LIB_DEFECTS
894e4b17023SJohn Marino // 431. Swapping containers with unequal allocators.
895e4b17023SJohn Marino std::__alloc_swap<_Node_allocator_type>::_S_do_it(_M_node_allocator,
896e4b17023SJohn Marino __x._M_node_allocator);
897e4b17023SJohn Marino
898e4b17023SJohn Marino std::swap(_M_rehash_policy, __x._M_rehash_policy);
899e4b17023SJohn Marino std::swap(_M_buckets, __x._M_buckets);
900e4b17023SJohn Marino std::swap(_M_bucket_count, __x._M_bucket_count);
901e4b17023SJohn Marino std::swap(_M_before_begin._M_nxt, __x._M_before_begin._M_nxt);
902e4b17023SJohn Marino std::swap(_M_element_count, __x._M_element_count);
903e4b17023SJohn Marino // Fix buckets containing the _M_before_begin pointers that can't be
904e4b17023SJohn Marino // swapped.
905e4b17023SJohn Marino if (_M_begin())
906e4b17023SJohn Marino _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
907e4b17023SJohn Marino if (__x._M_begin())
908e4b17023SJohn Marino __x._M_buckets[__x._M_bucket_index(__x._M_begin())]
909e4b17023SJohn Marino = &(__x._M_before_begin);
910e4b17023SJohn Marino }
911e4b17023SJohn Marino
912e4b17023SJohn Marino template<typename _Key, typename _Value,
913e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
914e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
915e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
916e4b17023SJohn Marino void
917e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
918e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
919e4b17023SJohn Marino __rehash_policy(const _RehashPolicy& __pol)
920e4b17023SJohn Marino {
921e4b17023SJohn Marino size_type __n_bkt = __pol._M_bkt_for_elements(_M_element_count);
922e4b17023SJohn Marino if (__n_bkt != _M_bucket_count)
923e4b17023SJohn Marino _M_rehash(__n_bkt, _M_rehash_policy._M_state());
924e4b17023SJohn Marino _M_rehash_policy = __pol;
925e4b17023SJohn Marino }
926e4b17023SJohn Marino
927e4b17023SJohn Marino template<typename _Key, typename _Value,
928e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
929e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
930e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
931e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
932e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
933e4b17023SJohn Marino __chc, __cit, __uk>::iterator
934e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
935e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
936e4b17023SJohn Marino find(const key_type& __k)
937e4b17023SJohn Marino {
938e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k);
939e4b17023SJohn Marino std::size_t __n = _M_bucket_index(__k, __code);
940e4b17023SJohn Marino _Node* __p = _M_find_node(__n, __k, __code);
941e4b17023SJohn Marino return __p ? iterator(__p) : this->end();
942e4b17023SJohn Marino }
943e4b17023SJohn Marino
944e4b17023SJohn Marino template<typename _Key, typename _Value,
945e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
946e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
947e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
948e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
949e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
950e4b17023SJohn Marino __chc, __cit, __uk>::const_iterator
951e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
952e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
953e4b17023SJohn Marino find(const key_type& __k) const
954e4b17023SJohn Marino {
955e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k);
956e4b17023SJohn Marino std::size_t __n = _M_bucket_index(__k, __code);
957e4b17023SJohn Marino _Node* __p = _M_find_node(__n, __k, __code);
958e4b17023SJohn Marino return __p ? const_iterator(__p) : this->end();
959e4b17023SJohn Marino }
960e4b17023SJohn Marino
961e4b17023SJohn Marino template<typename _Key, typename _Value,
962e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
963e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
964e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
965e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
966e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
967e4b17023SJohn Marino __chc, __cit, __uk>::size_type
968e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
969e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
970e4b17023SJohn Marino count(const key_type& __k) const
971e4b17023SJohn Marino {
972e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k);
973e4b17023SJohn Marino std::size_t __n = _M_bucket_index(__k, __code);
974e4b17023SJohn Marino _Node* __p = _M_bucket_begin(__n);
975e4b17023SJohn Marino if (!__p)
976e4b17023SJohn Marino return 0;
977e4b17023SJohn Marino
978e4b17023SJohn Marino std::size_t __result = 0;
979e4b17023SJohn Marino for (;; __p = __p->_M_next())
980e4b17023SJohn Marino {
981e4b17023SJohn Marino if (this->_M_equals(__k, __code, __p))
982e4b17023SJohn Marino ++__result;
983e4b17023SJohn Marino else if (__result)
984e4b17023SJohn Marino // All equivalent values are next to each other, if we found a not
985e4b17023SJohn Marino // equivalent value after an equivalent one it means that we won't
986*5ce9237cSJohn Marino // find any more equivalent values.
987e4b17023SJohn Marino break;
988e4b17023SJohn Marino if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n)
989e4b17023SJohn Marino break;
990e4b17023SJohn Marino }
991e4b17023SJohn Marino return __result;
992e4b17023SJohn Marino }
993e4b17023SJohn Marino
994e4b17023SJohn Marino template<typename _Key, typename _Value,
995e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
996e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
997e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
998e4b17023SJohn Marino std::pair<typename _Hashtable<_Key, _Value, _Allocator,
999e4b17023SJohn Marino _ExtractKey, _Equal, _H1,
1000e4b17023SJohn Marino _H2, _Hash, _RehashPolicy,
1001e4b17023SJohn Marino __chc, __cit, __uk>::iterator,
1002e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator,
1003e4b17023SJohn Marino _ExtractKey, _Equal, _H1,
1004e4b17023SJohn Marino _H2, _Hash, _RehashPolicy,
1005e4b17023SJohn Marino __chc, __cit, __uk>::iterator>
1006e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1007e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1008e4b17023SJohn Marino equal_range(const key_type& __k)
1009e4b17023SJohn Marino {
1010e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k);
1011e4b17023SJohn Marino std::size_t __n = _M_bucket_index(__k, __code);
1012e4b17023SJohn Marino _Node* __p = _M_find_node(__n, __k, __code);
1013e4b17023SJohn Marino
1014e4b17023SJohn Marino if (__p)
1015e4b17023SJohn Marino {
1016e4b17023SJohn Marino _Node* __p1 = __p->_M_next();
1017e4b17023SJohn Marino while (__p1 && _M_bucket_index(__p1) == __n
1018e4b17023SJohn Marino && this->_M_equals(__k, __code, __p1))
1019e4b17023SJohn Marino __p1 = __p1->_M_next();
1020e4b17023SJohn Marino
1021e4b17023SJohn Marino return std::make_pair(iterator(__p), iterator(__p1));
1022e4b17023SJohn Marino }
1023e4b17023SJohn Marino else
1024e4b17023SJohn Marino return std::make_pair(this->end(), this->end());
1025e4b17023SJohn Marino }
1026e4b17023SJohn Marino
1027e4b17023SJohn Marino template<typename _Key, typename _Value,
1028e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1029e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1030e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1031e4b17023SJohn Marino std::pair<typename _Hashtable<_Key, _Value, _Allocator,
1032e4b17023SJohn Marino _ExtractKey, _Equal, _H1,
1033e4b17023SJohn Marino _H2, _Hash, _RehashPolicy,
1034e4b17023SJohn Marino __chc, __cit, __uk>::const_iterator,
1035e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator,
1036e4b17023SJohn Marino _ExtractKey, _Equal, _H1,
1037e4b17023SJohn Marino _H2, _Hash, _RehashPolicy,
1038e4b17023SJohn Marino __chc, __cit, __uk>::const_iterator>
1039e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1040e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1041e4b17023SJohn Marino equal_range(const key_type& __k) const
1042e4b17023SJohn Marino {
1043e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k);
1044e4b17023SJohn Marino std::size_t __n = _M_bucket_index(__k, __code);
1045e4b17023SJohn Marino _Node* __p = _M_find_node(__n, __k, __code);
1046e4b17023SJohn Marino
1047e4b17023SJohn Marino if (__p)
1048e4b17023SJohn Marino {
1049e4b17023SJohn Marino _Node* __p1 = __p->_M_next();
1050e4b17023SJohn Marino while (__p1 && _M_bucket_index(__p1) == __n
1051e4b17023SJohn Marino && this->_M_equals(__k, __code, __p1))
1052e4b17023SJohn Marino __p1 = __p1->_M_next();
1053e4b17023SJohn Marino
1054e4b17023SJohn Marino return std::make_pair(const_iterator(__p), const_iterator(__p1));
1055e4b17023SJohn Marino }
1056e4b17023SJohn Marino else
1057e4b17023SJohn Marino return std::make_pair(this->end(), this->end());
1058e4b17023SJohn Marino }
1059e4b17023SJohn Marino
1060e4b17023SJohn Marino // Find the node whose key compares equal to k in the bucket n. Return nullptr
1061e4b17023SJohn Marino // if no node is found.
1062e4b17023SJohn Marino template<typename _Key, typename _Value,
1063e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1064e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1065e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1066e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey,
1067e4b17023SJohn Marino _Equal, _H1, _H2, _Hash, _RehashPolicy,
1068e4b17023SJohn Marino __chc, __cit, __uk>::_BaseNode*
1069e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1070e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1071e4b17023SJohn Marino _M_find_before_node(size_type __n, const key_type& __k,
1072e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code) const
1073e4b17023SJohn Marino {
1074e4b17023SJohn Marino _BaseNode* __prev_p = _M_buckets[__n];
1075e4b17023SJohn Marino if (!__prev_p)
1076e4b17023SJohn Marino return nullptr;
1077e4b17023SJohn Marino _Node* __p = static_cast<_Node*>(__prev_p->_M_nxt);
1078e4b17023SJohn Marino for (;; __p = __p->_M_next())
1079e4b17023SJohn Marino {
1080e4b17023SJohn Marino if (this->_M_equals(__k, __code, __p))
1081e4b17023SJohn Marino return __prev_p;
1082e4b17023SJohn Marino if (!(__p->_M_nxt) || _M_bucket_index(__p->_M_next()) != __n)
1083e4b17023SJohn Marino break;
1084e4b17023SJohn Marino __prev_p = __p;
1085e4b17023SJohn Marino }
1086e4b17023SJohn Marino return nullptr;
1087e4b17023SJohn Marino }
1088e4b17023SJohn Marino
1089e4b17023SJohn Marino template<typename _Key, typename _Value,
1090e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1091e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1092e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1093e4b17023SJohn Marino void
1094e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1095e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1096e4b17023SJohn Marino _M_insert_bucket_begin(size_type __bkt, _Node* __new_node)
1097e4b17023SJohn Marino {
1098e4b17023SJohn Marino if (_M_buckets[__bkt])
1099e4b17023SJohn Marino {
1100e4b17023SJohn Marino // Bucket is not empty, we just need to insert the new node after the
1101e4b17023SJohn Marino // bucket before begin.
1102e4b17023SJohn Marino __new_node->_M_nxt = _M_buckets[__bkt]->_M_nxt;
1103e4b17023SJohn Marino _M_buckets[__bkt]->_M_nxt = __new_node;
1104e4b17023SJohn Marino }
1105e4b17023SJohn Marino else
1106e4b17023SJohn Marino {
1107e4b17023SJohn Marino // The bucket is empty, the new node is inserted at the beginning of
1108*5ce9237cSJohn Marino // the singly-linked list and the bucket will contain _M_before_begin
1109e4b17023SJohn Marino // pointer.
1110e4b17023SJohn Marino __new_node->_M_nxt = _M_before_begin._M_nxt;
1111e4b17023SJohn Marino _M_before_begin._M_nxt = __new_node;
1112e4b17023SJohn Marino if (__new_node->_M_nxt)
1113e4b17023SJohn Marino // We must update former begin bucket that is pointing to
1114e4b17023SJohn Marino // _M_before_begin.
1115e4b17023SJohn Marino _M_buckets[_M_bucket_index(__new_node->_M_next())] = __new_node;
1116e4b17023SJohn Marino _M_buckets[__bkt] = &_M_before_begin;
1117e4b17023SJohn Marino }
1118e4b17023SJohn Marino }
1119e4b17023SJohn Marino
1120e4b17023SJohn Marino template<typename _Key, typename _Value,
1121e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1122e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1123e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1124e4b17023SJohn Marino void
1125e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1126e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1127e4b17023SJohn Marino _M_remove_bucket_begin(size_type __bkt, _Node* __next, size_type __next_bkt)
1128e4b17023SJohn Marino {
1129e4b17023SJohn Marino if (!__next || __next_bkt != __bkt)
1130e4b17023SJohn Marino {
1131e4b17023SJohn Marino // Bucket is now empty
1132e4b17023SJohn Marino // First update next bucket if any
1133e4b17023SJohn Marino if (__next)
1134e4b17023SJohn Marino _M_buckets[__next_bkt] = _M_buckets[__bkt];
1135e4b17023SJohn Marino // Second update before begin node if necessary
1136e4b17023SJohn Marino if (&_M_before_begin == _M_buckets[__bkt])
1137e4b17023SJohn Marino _M_before_begin._M_nxt = __next;
1138e4b17023SJohn Marino _M_buckets[__bkt] = nullptr;
1139e4b17023SJohn Marino }
1140e4b17023SJohn Marino }
1141e4b17023SJohn Marino
1142e4b17023SJohn Marino template<typename _Key, typename _Value,
1143e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1144e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1145e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1146e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey,
1147e4b17023SJohn Marino _Equal, _H1, _H2, _Hash, _RehashPolicy,
1148e4b17023SJohn Marino __chc, __cit, __uk>::_BaseNode*
1149e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1150e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1151e4b17023SJohn Marino _M_get_previous_node(size_type __bkt, _BaseNode* __n)
1152e4b17023SJohn Marino {
1153e4b17023SJohn Marino _BaseNode* __prev_n = _M_buckets[__bkt];
1154e4b17023SJohn Marino while (__prev_n->_M_nxt != __n)
1155e4b17023SJohn Marino __prev_n = __prev_n->_M_nxt;
1156e4b17023SJohn Marino return __prev_n;
1157e4b17023SJohn Marino }
1158e4b17023SJohn Marino
1159e4b17023SJohn Marino template<typename _Key, typename _Value,
1160e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1161e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1162e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1163e4b17023SJohn Marino template<typename... _Args>
1164e4b17023SJohn Marino std::pair<typename _Hashtable<_Key, _Value, _Allocator,
1165e4b17023SJohn Marino _ExtractKey, _Equal, _H1,
1166e4b17023SJohn Marino _H2, _Hash, _RehashPolicy,
1167e4b17023SJohn Marino __chc, __cit, __uk>::iterator, bool>
1168e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1169e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1170e4b17023SJohn Marino _M_emplace(std::true_type, _Args&&... __args)
1171e4b17023SJohn Marino {
1172e4b17023SJohn Marino // First build the node to get access to the hash code
1173e4b17023SJohn Marino _Node* __new_node = _M_allocate_node(std::forward<_Args>(__args)...);
1174e4b17023SJohn Marino __try
1175e4b17023SJohn Marino {
1176e4b17023SJohn Marino const key_type& __k = this->_M_extract()(__new_node->_M_v);
1177e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code
1178e4b17023SJohn Marino = this->_M_hash_code(__k);
1179e4b17023SJohn Marino size_type __bkt = _M_bucket_index(__k, __code);
1180e4b17023SJohn Marino
1181e4b17023SJohn Marino if (_Node* __p = _M_find_node(__bkt, __k, __code))
1182e4b17023SJohn Marino {
1183e4b17023SJohn Marino // There is already an equivalent node, no insertion
1184e4b17023SJohn Marino _M_deallocate_node(__new_node);
1185e4b17023SJohn Marino return std::make_pair(iterator(__p), false);
1186e4b17023SJohn Marino }
1187e4b17023SJohn Marino
1188e4b17023SJohn Marino // We are going to insert this node
1189e4b17023SJohn Marino this->_M_store_code(__new_node, __code);
1190e4b17023SJohn Marino const _RehashPolicyState& __saved_state
1191e4b17023SJohn Marino = _M_rehash_policy._M_state();
1192e4b17023SJohn Marino std::pair<bool, std::size_t> __do_rehash
1193e4b17023SJohn Marino = _M_rehash_policy._M_need_rehash(_M_bucket_count,
1194e4b17023SJohn Marino _M_element_count, 1);
1195e4b17023SJohn Marino
1196e4b17023SJohn Marino if (__do_rehash.first)
1197e4b17023SJohn Marino {
1198e4b17023SJohn Marino _M_rehash(__do_rehash.second, __saved_state);
1199e4b17023SJohn Marino __bkt = _M_bucket_index(__k, __code);
1200e4b17023SJohn Marino }
1201e4b17023SJohn Marino
1202e4b17023SJohn Marino _M_insert_bucket_begin(__bkt, __new_node);
1203e4b17023SJohn Marino ++_M_element_count;
1204e4b17023SJohn Marino return std::make_pair(iterator(__new_node), true);
1205e4b17023SJohn Marino }
1206e4b17023SJohn Marino __catch(...)
1207e4b17023SJohn Marino {
1208e4b17023SJohn Marino _M_deallocate_node(__new_node);
1209e4b17023SJohn Marino __throw_exception_again;
1210e4b17023SJohn Marino }
1211e4b17023SJohn Marino }
1212e4b17023SJohn Marino
1213e4b17023SJohn Marino template<typename _Key, typename _Value,
1214e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1215e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1216e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1217e4b17023SJohn Marino template<typename... _Args>
1218e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1219e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
1220e4b17023SJohn Marino __chc, __cit, __uk>::iterator
1221e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1222e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1223e4b17023SJohn Marino _M_emplace(std::false_type, _Args&&... __args)
1224e4b17023SJohn Marino {
1225e4b17023SJohn Marino const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state();
1226e4b17023SJohn Marino std::pair<bool, std::size_t> __do_rehash
1227e4b17023SJohn Marino = _M_rehash_policy._M_need_rehash(_M_bucket_count,
1228e4b17023SJohn Marino _M_element_count, 1);
1229e4b17023SJohn Marino
1230e4b17023SJohn Marino // First build the node to get its hash code.
1231e4b17023SJohn Marino _Node* __new_node = _M_allocate_node(std::forward<_Args>(__args)...);
1232e4b17023SJohn Marino __try
1233e4b17023SJohn Marino {
1234e4b17023SJohn Marino const key_type& __k = this->_M_extract()(__new_node->_M_v);
1235e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code
1236e4b17023SJohn Marino = this->_M_hash_code(__k);
1237e4b17023SJohn Marino this->_M_store_code(__new_node, __code);
1238e4b17023SJohn Marino
1239e4b17023SJohn Marino // Second, do rehash if necessary.
1240e4b17023SJohn Marino if (__do_rehash.first)
1241e4b17023SJohn Marino _M_rehash(__do_rehash.second, __saved_state);
1242e4b17023SJohn Marino
1243e4b17023SJohn Marino // Third, find the node before an equivalent one.
1244e4b17023SJohn Marino size_type __bkt = _M_bucket_index(__k, __code);
1245e4b17023SJohn Marino _BaseNode* __prev = _M_find_before_node(__bkt, __k, __code);
1246e4b17023SJohn Marino
1247e4b17023SJohn Marino if (__prev)
1248e4b17023SJohn Marino {
1249e4b17023SJohn Marino // Insert after the node before the equivalent one.
1250e4b17023SJohn Marino __new_node->_M_nxt = __prev->_M_nxt;
1251e4b17023SJohn Marino __prev->_M_nxt = __new_node;
1252e4b17023SJohn Marino }
1253e4b17023SJohn Marino else
1254e4b17023SJohn Marino // The inserted node has no equivalent in the hashtable. We must
1255e4b17023SJohn Marino // insert the new node at the beginning of the bucket to preserve
1256*5ce9237cSJohn Marino // equivalent elements' relative positions.
1257e4b17023SJohn Marino _M_insert_bucket_begin(__bkt, __new_node);
1258e4b17023SJohn Marino ++_M_element_count;
1259e4b17023SJohn Marino return iterator(__new_node);
1260e4b17023SJohn Marino }
1261e4b17023SJohn Marino __catch(...)
1262e4b17023SJohn Marino {
1263e4b17023SJohn Marino _M_deallocate_node(__new_node);
1264e4b17023SJohn Marino __throw_exception_again;
1265e4b17023SJohn Marino }
1266e4b17023SJohn Marino }
1267e4b17023SJohn Marino
1268e4b17023SJohn Marino // Insert v in bucket n (assumes no element with its key already present).
1269e4b17023SJohn Marino template<typename _Key, typename _Value,
1270e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1271e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1272e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1273e4b17023SJohn Marino template<typename _Arg>
1274e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1275e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
1276e4b17023SJohn Marino __chc, __cit, __uk>::iterator
1277e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1278e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1279e4b17023SJohn Marino _M_insert_bucket(_Arg&& __v, size_type __n,
1280e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code)
1281e4b17023SJohn Marino {
1282e4b17023SJohn Marino const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state();
1283e4b17023SJohn Marino std::pair<bool, std::size_t> __do_rehash
1284e4b17023SJohn Marino = _M_rehash_policy._M_need_rehash(_M_bucket_count,
1285e4b17023SJohn Marino _M_element_count, 1);
1286e4b17023SJohn Marino
1287e4b17023SJohn Marino if (__do_rehash.first)
1288e4b17023SJohn Marino {
1289e4b17023SJohn Marino const key_type& __k = this->_M_extract()(__v);
1290e4b17023SJohn Marino __n = _HCBase::_M_bucket_index(__k, __code, __do_rehash.second);
1291e4b17023SJohn Marino }
1292e4b17023SJohn Marino
1293e4b17023SJohn Marino _Node* __new_node = nullptr;
1294e4b17023SJohn Marino __try
1295e4b17023SJohn Marino {
1296e4b17023SJohn Marino // Allocate the new node before doing the rehash so that we
1297e4b17023SJohn Marino // don't do a rehash if the allocation throws.
1298e4b17023SJohn Marino __new_node = _M_allocate_node(std::forward<_Arg>(__v));
1299e4b17023SJohn Marino this->_M_store_code(__new_node, __code);
1300e4b17023SJohn Marino if (__do_rehash.first)
1301e4b17023SJohn Marino _M_rehash(__do_rehash.second, __saved_state);
1302e4b17023SJohn Marino
1303e4b17023SJohn Marino _M_insert_bucket_begin(__n, __new_node);
1304e4b17023SJohn Marino ++_M_element_count;
1305e4b17023SJohn Marino return iterator(__new_node);
1306e4b17023SJohn Marino }
1307e4b17023SJohn Marino __catch(...)
1308e4b17023SJohn Marino {
1309e4b17023SJohn Marino if (!__new_node)
1310e4b17023SJohn Marino _M_rehash_policy._M_reset(__saved_state);
1311e4b17023SJohn Marino else
1312e4b17023SJohn Marino _M_deallocate_node(__new_node);
1313e4b17023SJohn Marino __throw_exception_again;
1314e4b17023SJohn Marino }
1315e4b17023SJohn Marino }
1316e4b17023SJohn Marino
1317e4b17023SJohn Marino // Insert v if no element with its key is already present.
1318e4b17023SJohn Marino template<typename _Key, typename _Value,
1319e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1320e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1321e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1322e4b17023SJohn Marino template<typename _Arg>
1323e4b17023SJohn Marino std::pair<typename _Hashtable<_Key, _Value, _Allocator,
1324e4b17023SJohn Marino _ExtractKey, _Equal, _H1,
1325e4b17023SJohn Marino _H2, _Hash, _RehashPolicy,
1326e4b17023SJohn Marino __chc, __cit, __uk>::iterator, bool>
1327e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1328e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1329e4b17023SJohn Marino _M_insert(_Arg&& __v, std::true_type)
1330e4b17023SJohn Marino {
1331e4b17023SJohn Marino const key_type& __k = this->_M_extract()(__v);
1332e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k);
1333e4b17023SJohn Marino size_type __n = _M_bucket_index(__k, __code);
1334e4b17023SJohn Marino
1335e4b17023SJohn Marino if (_Node* __p = _M_find_node(__n, __k, __code))
1336e4b17023SJohn Marino return std::make_pair(iterator(__p), false);
1337e4b17023SJohn Marino return std::make_pair(_M_insert_bucket(std::forward<_Arg>(__v),
1338e4b17023SJohn Marino __n, __code), true);
1339e4b17023SJohn Marino }
1340e4b17023SJohn Marino
1341e4b17023SJohn Marino // Insert v unconditionally.
1342e4b17023SJohn Marino template<typename _Key, typename _Value,
1343e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1344e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1345e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1346e4b17023SJohn Marino template<typename _Arg>
1347e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1348e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
1349e4b17023SJohn Marino __chc, __cit, __uk>::iterator
1350e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1351e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1352e4b17023SJohn Marino _M_insert(_Arg&& __v, std::false_type)
1353e4b17023SJohn Marino {
1354e4b17023SJohn Marino const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state();
1355e4b17023SJohn Marino std::pair<bool, std::size_t> __do_rehash
1356e4b17023SJohn Marino = _M_rehash_policy._M_need_rehash(_M_bucket_count,
1357e4b17023SJohn Marino _M_element_count, 1);
1358e4b17023SJohn Marino
1359e4b17023SJohn Marino // First compute the hash code so that we don't do anything if it throws.
1360e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code
1361e4b17023SJohn Marino = this->_M_hash_code(this->_M_extract()(__v));
1362e4b17023SJohn Marino
1363e4b17023SJohn Marino _Node* __new_node = nullptr;
1364e4b17023SJohn Marino __try
1365e4b17023SJohn Marino {
1366e4b17023SJohn Marino // Second allocate new node so that we don't rehash if it throws.
1367e4b17023SJohn Marino __new_node = _M_allocate_node(std::forward<_Arg>(__v));
1368e4b17023SJohn Marino this->_M_store_code(__new_node, __code);
1369e4b17023SJohn Marino if (__do_rehash.first)
1370e4b17023SJohn Marino _M_rehash(__do_rehash.second, __saved_state);
1371e4b17023SJohn Marino
1372e4b17023SJohn Marino // Third, find the node before an equivalent one.
1373e4b17023SJohn Marino size_type __bkt = _M_bucket_index(__new_node);
1374e4b17023SJohn Marino _BaseNode* __prev
1375e4b17023SJohn Marino = _M_find_before_node(__bkt, this->_M_extract()(__new_node->_M_v),
1376e4b17023SJohn Marino __code);
1377e4b17023SJohn Marino if (__prev)
1378e4b17023SJohn Marino {
1379e4b17023SJohn Marino // Insert after the node before the equivalent one.
1380e4b17023SJohn Marino __new_node->_M_nxt = __prev->_M_nxt;
1381e4b17023SJohn Marino __prev->_M_nxt = __new_node;
1382e4b17023SJohn Marino }
1383e4b17023SJohn Marino else
1384e4b17023SJohn Marino // The inserted node has no equivalent in the hashtable. We must
1385e4b17023SJohn Marino // insert the new node at the beginning of the bucket to preserve
1386e4b17023SJohn Marino // equivalent elements relative positions.
1387e4b17023SJohn Marino _M_insert_bucket_begin(__bkt, __new_node);
1388e4b17023SJohn Marino ++_M_element_count;
1389e4b17023SJohn Marino return iterator(__new_node);
1390e4b17023SJohn Marino }
1391e4b17023SJohn Marino __catch(...)
1392e4b17023SJohn Marino {
1393e4b17023SJohn Marino if (!__new_node)
1394e4b17023SJohn Marino _M_rehash_policy._M_reset(__saved_state);
1395e4b17023SJohn Marino else
1396e4b17023SJohn Marino _M_deallocate_node(__new_node);
1397e4b17023SJohn Marino __throw_exception_again;
1398e4b17023SJohn Marino }
1399e4b17023SJohn Marino }
1400e4b17023SJohn Marino
1401e4b17023SJohn Marino template<typename _Key, typename _Value,
1402e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1403e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1404e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1405e4b17023SJohn Marino template<typename _InputIterator>
1406e4b17023SJohn Marino void
1407e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1408e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1409e4b17023SJohn Marino insert(_InputIterator __first, _InputIterator __last)
1410e4b17023SJohn Marino {
1411e4b17023SJohn Marino size_type __n_elt = __detail::__distance_fw(__first, __last);
1412e4b17023SJohn Marino const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state();
1413e4b17023SJohn Marino std::pair<bool, std::size_t> __do_rehash
1414e4b17023SJohn Marino = _M_rehash_policy._M_need_rehash(_M_bucket_count,
1415e4b17023SJohn Marino _M_element_count, __n_elt);
1416e4b17023SJohn Marino if (__do_rehash.first)
1417e4b17023SJohn Marino _M_rehash(__do_rehash.second, __saved_state);
1418e4b17023SJohn Marino
1419e4b17023SJohn Marino for (; __first != __last; ++__first)
1420e4b17023SJohn Marino this->insert(*__first);
1421e4b17023SJohn Marino }
1422e4b17023SJohn Marino
1423e4b17023SJohn Marino template<typename _Key, typename _Value,
1424e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1425e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1426e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1427e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1428e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
1429e4b17023SJohn Marino __chc, __cit, __uk>::iterator
1430e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1431e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1432e4b17023SJohn Marino erase(const_iterator __it)
1433e4b17023SJohn Marino {
1434e4b17023SJohn Marino _Node* __n = __it._M_cur;
1435e4b17023SJohn Marino std::size_t __bkt = _M_bucket_index(__n);
1436e4b17023SJohn Marino
1437e4b17023SJohn Marino // Look for previous node to unlink it from the erased one, this is why
1438*5ce9237cSJohn Marino // we need buckets to contain the before begin to make this search fast.
1439e4b17023SJohn Marino _BaseNode* __prev_n = _M_get_previous_node(__bkt, __n);
1440e4b17023SJohn Marino if (__n == _M_bucket_begin(__bkt))
1441e4b17023SJohn Marino _M_remove_bucket_begin(__bkt, __n->_M_next(),
1442e4b17023SJohn Marino __n->_M_nxt ? _M_bucket_index(__n->_M_next()) : 0);
1443e4b17023SJohn Marino else if (__n->_M_nxt)
1444e4b17023SJohn Marino {
1445e4b17023SJohn Marino size_type __next_bkt = _M_bucket_index(__n->_M_next());
1446e4b17023SJohn Marino if (__next_bkt != __bkt)
1447e4b17023SJohn Marino _M_buckets[__next_bkt] = __prev_n;
1448e4b17023SJohn Marino }
1449e4b17023SJohn Marino
1450e4b17023SJohn Marino __prev_n->_M_nxt = __n->_M_nxt;
1451e4b17023SJohn Marino iterator __result(__n->_M_next());
1452e4b17023SJohn Marino _M_deallocate_node(__n);
1453e4b17023SJohn Marino --_M_element_count;
1454e4b17023SJohn Marino
1455e4b17023SJohn Marino return __result;
1456e4b17023SJohn Marino }
1457e4b17023SJohn Marino
1458e4b17023SJohn Marino template<typename _Key, typename _Value,
1459e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1460e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1461e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1462e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1463e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
1464e4b17023SJohn Marino __chc, __cit, __uk>::size_type
1465e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1466e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1467e4b17023SJohn Marino erase(const key_type& __k)
1468e4b17023SJohn Marino {
1469e4b17023SJohn Marino typename _Hashtable::_Hash_code_type __code = this->_M_hash_code(__k);
1470e4b17023SJohn Marino std::size_t __bkt = _M_bucket_index(__k, __code);
1471e4b17023SJohn Marino // Look for the node before the first matching node.
1472e4b17023SJohn Marino _BaseNode* __prev_n = _M_find_before_node(__bkt, __k, __code);
1473e4b17023SJohn Marino if (!__prev_n)
1474e4b17023SJohn Marino return 0;
1475e4b17023SJohn Marino _Node* __n = static_cast<_Node*>(__prev_n->_M_nxt);
1476e4b17023SJohn Marino bool __is_bucket_begin = _M_buckets[__bkt] == __prev_n;
1477e4b17023SJohn Marino
1478e4b17023SJohn Marino // We found a matching node, start deallocation loop from it
1479e4b17023SJohn Marino std::size_t __next_bkt = __bkt;
1480e4b17023SJohn Marino _Node* __next_n = __n;
1481e4b17023SJohn Marino size_type __result = 0;
1482e4b17023SJohn Marino _Node* __saved_n = nullptr;
1483e4b17023SJohn Marino do
1484e4b17023SJohn Marino {
1485e4b17023SJohn Marino _Node* __p = __next_n;
1486e4b17023SJohn Marino __next_n = __p->_M_next();
1487e4b17023SJohn Marino // _GLIBCXX_RESOLVE_LIB_DEFECTS
1488e4b17023SJohn Marino // 526. Is it undefined if a function in the standard changes
1489e4b17023SJohn Marino // in parameters?
1490e4b17023SJohn Marino if (std::__addressof(this->_M_extract()(__p->_M_v))
1491e4b17023SJohn Marino != std::__addressof(__k))
1492e4b17023SJohn Marino _M_deallocate_node(__p);
1493e4b17023SJohn Marino else
1494e4b17023SJohn Marino __saved_n = __p;
1495e4b17023SJohn Marino --_M_element_count;
1496e4b17023SJohn Marino ++__result;
1497e4b17023SJohn Marino if (!__next_n)
1498e4b17023SJohn Marino break;
1499e4b17023SJohn Marino __next_bkt = _M_bucket_index(__next_n);
1500e4b17023SJohn Marino }
1501e4b17023SJohn Marino while (__next_bkt == __bkt && this->_M_equals(__k, __code, __next_n));
1502e4b17023SJohn Marino
1503e4b17023SJohn Marino if (__saved_n)
1504e4b17023SJohn Marino _M_deallocate_node(__saved_n);
1505e4b17023SJohn Marino if (__is_bucket_begin)
1506e4b17023SJohn Marino _M_remove_bucket_begin(__bkt, __next_n, __next_bkt);
1507e4b17023SJohn Marino else if (__next_n && __next_bkt != __bkt)
1508e4b17023SJohn Marino _M_buckets[__next_bkt] = __prev_n;
1509e4b17023SJohn Marino if (__prev_n)
1510e4b17023SJohn Marino __prev_n->_M_nxt = __next_n;
1511e4b17023SJohn Marino return __result;
1512e4b17023SJohn Marino }
1513e4b17023SJohn Marino
1514e4b17023SJohn Marino template<typename _Key, typename _Value,
1515e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1516e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1517e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1518e4b17023SJohn Marino typename _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1519e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy,
1520e4b17023SJohn Marino __chc, __cit, __uk>::iterator
1521e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1522e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1523e4b17023SJohn Marino erase(const_iterator __first, const_iterator __last)
1524e4b17023SJohn Marino {
1525e4b17023SJohn Marino _Node* __n = __first._M_cur;
1526e4b17023SJohn Marino _Node* __last_n = __last._M_cur;
1527e4b17023SJohn Marino if (__n == __last_n)
1528e4b17023SJohn Marino return iterator(__n);
1529e4b17023SJohn Marino
1530e4b17023SJohn Marino std::size_t __bkt = _M_bucket_index(__n);
1531e4b17023SJohn Marino
1532e4b17023SJohn Marino _BaseNode* __prev_n = _M_get_previous_node(__bkt, __n);
1533e4b17023SJohn Marino bool __is_bucket_begin = __n == _M_bucket_begin(__bkt);
1534e4b17023SJohn Marino std::size_t __n_bkt = __bkt;
1535e4b17023SJohn Marino for (;;)
1536e4b17023SJohn Marino {
1537e4b17023SJohn Marino do
1538e4b17023SJohn Marino {
1539e4b17023SJohn Marino _Node* __tmp = __n;
1540e4b17023SJohn Marino __n = __n->_M_next();
1541e4b17023SJohn Marino _M_deallocate_node(__tmp);
1542e4b17023SJohn Marino --_M_element_count;
1543e4b17023SJohn Marino if (!__n)
1544e4b17023SJohn Marino break;
1545e4b17023SJohn Marino __n_bkt = _M_bucket_index(__n);
1546e4b17023SJohn Marino }
1547e4b17023SJohn Marino while (__n != __last_n && __n_bkt == __bkt);
1548e4b17023SJohn Marino if (__is_bucket_begin)
1549e4b17023SJohn Marino _M_remove_bucket_begin(__bkt, __n, __n_bkt);
1550e4b17023SJohn Marino if (__n == __last_n)
1551e4b17023SJohn Marino break;
1552e4b17023SJohn Marino __is_bucket_begin = true;
1553e4b17023SJohn Marino __bkt = __n_bkt;
1554e4b17023SJohn Marino }
1555e4b17023SJohn Marino
1556e4b17023SJohn Marino if (__n && (__n_bkt != __bkt || __is_bucket_begin))
1557e4b17023SJohn Marino _M_buckets[__n_bkt] = __prev_n;
1558e4b17023SJohn Marino __prev_n->_M_nxt = __n;
1559e4b17023SJohn Marino return iterator(__n);
1560e4b17023SJohn Marino }
1561e4b17023SJohn Marino
1562e4b17023SJohn Marino template<typename _Key, typename _Value,
1563e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1564e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1565e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1566e4b17023SJohn Marino void
1567e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1568e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1569e4b17023SJohn Marino clear() noexcept
1570e4b17023SJohn Marino {
1571e4b17023SJohn Marino _M_deallocate_nodes(_M_begin());
1572e4b17023SJohn Marino __builtin_memset(_M_buckets, 0, _M_bucket_count * sizeof(_Bucket));
1573e4b17023SJohn Marino _M_element_count = 0;
1574e4b17023SJohn Marino _M_before_begin._M_nxt = nullptr;
1575e4b17023SJohn Marino }
1576e4b17023SJohn Marino
1577e4b17023SJohn Marino template<typename _Key, typename _Value,
1578e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1579e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1580e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1581e4b17023SJohn Marino void
1582e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1583e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1584e4b17023SJohn Marino rehash(size_type __n)
1585e4b17023SJohn Marino {
1586e4b17023SJohn Marino const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state();
1587e4b17023SJohn Marino std::size_t __buckets
1588e4b17023SJohn Marino = _M_rehash_policy._M_bkt_for_elements(_M_element_count + 1);
1589e4b17023SJohn Marino if (__buckets <= __n)
1590e4b17023SJohn Marino __buckets = _M_rehash_policy._M_next_bkt(__n);
1591e4b17023SJohn Marino
1592e4b17023SJohn Marino if (__buckets != _M_bucket_count)
1593e4b17023SJohn Marino {
1594e4b17023SJohn Marino _M_rehash(__buckets, __saved_state);
1595e4b17023SJohn Marino
1596e4b17023SJohn Marino // We don't want the rehash policy to ask for the hashtable to shrink
1597e4b17023SJohn Marino // on the next insertion so we need to reset its previous resize
1598e4b17023SJohn Marino // level.
1599e4b17023SJohn Marino _M_rehash_policy._M_prev_resize = 0;
1600e4b17023SJohn Marino }
1601*5ce9237cSJohn Marino else
1602*5ce9237cSJohn Marino // No rehash, restore previous state to keep a consistent state.
1603*5ce9237cSJohn Marino _M_rehash_policy._M_reset(__saved_state);
1604e4b17023SJohn Marino }
1605e4b17023SJohn Marino
1606e4b17023SJohn Marino template<typename _Key, typename _Value,
1607e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1608e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1609e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1610e4b17023SJohn Marino void
1611e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1612e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1613e4b17023SJohn Marino _M_rehash(size_type __n, const _RehashPolicyState& __state)
1614e4b17023SJohn Marino {
1615e4b17023SJohn Marino __try
1616e4b17023SJohn Marino {
1617e4b17023SJohn Marino _M_rehash_aux(__n, integral_constant<bool, __uk>());
1618e4b17023SJohn Marino }
1619e4b17023SJohn Marino __catch(...)
1620e4b17023SJohn Marino {
1621e4b17023SJohn Marino // A failure here means that buckets allocation failed. We only
1622e4b17023SJohn Marino // have to restore hash policy previous state.
1623e4b17023SJohn Marino _M_rehash_policy._M_reset(__state);
1624e4b17023SJohn Marino __throw_exception_again;
1625e4b17023SJohn Marino }
1626e4b17023SJohn Marino }
1627e4b17023SJohn Marino
1628e4b17023SJohn Marino // Rehash when there is no equivalent elements.
1629e4b17023SJohn Marino template<typename _Key, typename _Value,
1630e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1631e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1632e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1633e4b17023SJohn Marino void
1634e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1635e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1636e4b17023SJohn Marino _M_rehash_aux(size_type __n, std::true_type)
1637e4b17023SJohn Marino {
1638e4b17023SJohn Marino _Bucket* __new_buckets = _M_allocate_buckets(__n);
1639e4b17023SJohn Marino _Node* __p = _M_begin();
1640e4b17023SJohn Marino _M_before_begin._M_nxt = nullptr;
1641*5ce9237cSJohn Marino std::size_t __bbegin_bkt = 0;
1642e4b17023SJohn Marino while (__p)
1643e4b17023SJohn Marino {
1644e4b17023SJohn Marino _Node* __next = __p->_M_next();
1645e4b17023SJohn Marino std::size_t __bkt = _HCBase::_M_bucket_index(__p, __n);
1646e4b17023SJohn Marino if (!__new_buckets[__bkt])
1647e4b17023SJohn Marino {
1648e4b17023SJohn Marino __p->_M_nxt = _M_before_begin._M_nxt;
1649e4b17023SJohn Marino _M_before_begin._M_nxt = __p;
1650e4b17023SJohn Marino __new_buckets[__bkt] = &_M_before_begin;
1651e4b17023SJohn Marino if (__p->_M_nxt)
1652e4b17023SJohn Marino __new_buckets[__bbegin_bkt] = __p;
1653e4b17023SJohn Marino __bbegin_bkt = __bkt;
1654e4b17023SJohn Marino }
1655e4b17023SJohn Marino else
1656e4b17023SJohn Marino {
1657e4b17023SJohn Marino __p->_M_nxt = __new_buckets[__bkt]->_M_nxt;
1658e4b17023SJohn Marino __new_buckets[__bkt]->_M_nxt = __p;
1659e4b17023SJohn Marino }
1660e4b17023SJohn Marino __p = __next;
1661e4b17023SJohn Marino }
1662e4b17023SJohn Marino _M_deallocate_buckets(_M_buckets, _M_bucket_count);
1663e4b17023SJohn Marino _M_bucket_count = __n;
1664e4b17023SJohn Marino _M_buckets = __new_buckets;
1665e4b17023SJohn Marino }
1666e4b17023SJohn Marino
1667e4b17023SJohn Marino // Rehash when there can be equivalent elements, preserve their relative
1668e4b17023SJohn Marino // order.
1669e4b17023SJohn Marino template<typename _Key, typename _Value,
1670e4b17023SJohn Marino typename _Allocator, typename _ExtractKey, typename _Equal,
1671e4b17023SJohn Marino typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
1672e4b17023SJohn Marino bool __chc, bool __cit, bool __uk>
1673e4b17023SJohn Marino void
1674e4b17023SJohn Marino _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
1675e4b17023SJohn Marino _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
1676e4b17023SJohn Marino _M_rehash_aux(size_type __n, std::false_type)
1677e4b17023SJohn Marino {
1678e4b17023SJohn Marino _Bucket* __new_buckets = _M_allocate_buckets(__n);
1679e4b17023SJohn Marino
1680e4b17023SJohn Marino _Node* __p = _M_begin();
1681e4b17023SJohn Marino _M_before_begin._M_nxt = nullptr;
1682*5ce9237cSJohn Marino std::size_t __bbegin_bkt = 0;
1683*5ce9237cSJohn Marino std::size_t __prev_bkt = 0;
1684e4b17023SJohn Marino _Node* __prev_p = nullptr;
1685e4b17023SJohn Marino bool __check_bucket = false;
1686e4b17023SJohn Marino
1687e4b17023SJohn Marino while (__p)
1688e4b17023SJohn Marino {
1689e4b17023SJohn Marino _Node* __next = __p->_M_next();
1690e4b17023SJohn Marino std::size_t __bkt = _HCBase::_M_bucket_index(__p, __n);
1691e4b17023SJohn Marino
1692e4b17023SJohn Marino if (__prev_p && __prev_bkt == __bkt)
1693e4b17023SJohn Marino {
1694e4b17023SJohn Marino // Previous insert was already in this bucket, we insert after
1695e4b17023SJohn Marino // the previously inserted one to preserve equivalent elements
1696e4b17023SJohn Marino // relative order.
1697e4b17023SJohn Marino __p->_M_nxt = __prev_p->_M_nxt;
1698e4b17023SJohn Marino __prev_p->_M_nxt = __p;
1699e4b17023SJohn Marino
1700e4b17023SJohn Marino // Inserting after a node in a bucket require to check that we
1701e4b17023SJohn Marino // haven't change the bucket last node, in this case next
1702e4b17023SJohn Marino // bucket containing its before begin node must be updated. We
1703e4b17023SJohn Marino // schedule a check as soon as we move out of the sequence of
1704e4b17023SJohn Marino // equivalent nodes to limit the number of checks.
1705e4b17023SJohn Marino __check_bucket = true;
1706e4b17023SJohn Marino }
1707e4b17023SJohn Marino else
1708e4b17023SJohn Marino {
1709e4b17023SJohn Marino if (__check_bucket)
1710e4b17023SJohn Marino {
1711*5ce9237cSJohn Marino // Check if we shall update the next bucket because of
1712*5ce9237cSJohn Marino // insertions into __prev_bkt bucket.
1713e4b17023SJohn Marino if (__prev_p->_M_nxt)
1714e4b17023SJohn Marino {
1715e4b17023SJohn Marino std::size_t __next_bkt
1716e4b17023SJohn Marino = _HCBase::_M_bucket_index(__prev_p->_M_next(), __n);
1717e4b17023SJohn Marino if (__next_bkt != __prev_bkt)
1718e4b17023SJohn Marino __new_buckets[__next_bkt] = __prev_p;
1719e4b17023SJohn Marino }
1720e4b17023SJohn Marino __check_bucket = false;
1721e4b17023SJohn Marino }
1722e4b17023SJohn Marino if (!__new_buckets[__bkt])
1723e4b17023SJohn Marino {
1724e4b17023SJohn Marino __p->_M_nxt = _M_before_begin._M_nxt;
1725e4b17023SJohn Marino _M_before_begin._M_nxt = __p;
1726e4b17023SJohn Marino __new_buckets[__bkt] = &_M_before_begin;
1727e4b17023SJohn Marino if (__p->_M_nxt)
1728e4b17023SJohn Marino __new_buckets[__bbegin_bkt] = __p;
1729e4b17023SJohn Marino __bbegin_bkt = __bkt;
1730e4b17023SJohn Marino }
1731e4b17023SJohn Marino else
1732e4b17023SJohn Marino {
1733e4b17023SJohn Marino __p->_M_nxt = __new_buckets[__bkt]->_M_nxt;
1734e4b17023SJohn Marino __new_buckets[__bkt]->_M_nxt = __p;
1735e4b17023SJohn Marino }
1736e4b17023SJohn Marino }
1737e4b17023SJohn Marino
1738e4b17023SJohn Marino __prev_p = __p;
1739e4b17023SJohn Marino __prev_bkt = __bkt;
1740e4b17023SJohn Marino __p = __next;
1741e4b17023SJohn Marino }
1742e4b17023SJohn Marino
1743e4b17023SJohn Marino if (__check_bucket && __prev_p->_M_nxt)
1744e4b17023SJohn Marino {
1745e4b17023SJohn Marino std::size_t __next_bkt
1746e4b17023SJohn Marino = _HCBase::_M_bucket_index(__prev_p->_M_next(), __n);
1747e4b17023SJohn Marino if (__next_bkt != __prev_bkt)
1748e4b17023SJohn Marino __new_buckets[__next_bkt] = __prev_p;
1749e4b17023SJohn Marino }
1750e4b17023SJohn Marino
1751e4b17023SJohn Marino _M_deallocate_buckets(_M_buckets, _M_bucket_count);
1752e4b17023SJohn Marino _M_bucket_count = __n;
1753e4b17023SJohn Marino _M_buckets = __new_buckets;
1754e4b17023SJohn Marino }
1755e4b17023SJohn Marino
1756e4b17023SJohn Marino _GLIBCXX_END_NAMESPACE_VERSION
1757e4b17023SJohn Marino } // namespace std
1758e4b17023SJohn Marino
1759e4b17023SJohn Marino #endif // _HASHTABLE_H
1760