048855d5405b399bfdcc86f9c246d09092591485
[gcc.git] / libstdc++-v3 / include / bits / hashtable_policy.h
1 // Internal policy header for unordered_set and unordered_map -*- C++ -*-
2
3 // Copyright (C) 2010-2025 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24
25 /** @file bits/hashtable_policy.h
26  *  This is an internal header file, included by other library headers.
27  *  Do not attempt to use it directly.
28  *  @headername{unordered_map,unordered_set}
29  */
30
31 #ifndef _HASHTABLE_POLICY_H
32 #define _HASHTABLE_POLICY_H 1
33
34 #include <tuple>                // for std::tuple, std::forward_as_tuple
35 #include <bits/functional_hash.h> // for __is_fast_hash
36 #include <bits/stl_algobase.h>  // for std::min
37 #include <bits/stl_pair.h>      // for std::pair
38 #include <ext/aligned_buffer.h> // for __gnu_cxx::__aligned_buffer
39 #include <ext/alloc_traits.h>   // for std::__alloc_rebind
40 #include <ext/numeric_traits.h> // for __gnu_cxx::__int_traits
41
42 namespace std _GLIBCXX_VISIBILITY(default)
43 {
44 _GLIBCXX_BEGIN_NAMESPACE_VERSION
45 /// @cond undocumented
46
47   template<typename _Key, typename _Value, typename _Alloc,
48            typename _ExtractKey, typename _Equal,
49            typename _Hash, typename _RangeHash, typename _Unused,
50            typename _RehashPolicy, typename _Traits>
51     class _Hashtable;
52
53 namespace __detail
54 {
55   /**
56    *  @defgroup hashtable-detail Base and Implementation Classes
57    *  @ingroup unordered_associative_containers
58    *  @{
59    */
60   template<typename _Key, typename _Value, typename _ExtractKey,
61            typename _Equal, typename _Hash, typename _RangeHash,
62            typename _Unused, typename _Traits>
63     struct _Hashtable_base;
64
65 #pragma GCC diagnostic push
66 #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
67   // Helper function: return distance(first, last) for forward
68   // iterators, or 0/1 for input iterators.
69   template<typename _Iterator>
70     inline typename std::iterator_traits<_Iterator>::difference_type
71     __distance_fw(_Iterator __first, _Iterator __last)
72     {
73       using _Cat = typename std::iterator_traits<_Iterator>::iterator_category;
74       if constexpr (is_convertible<_Cat, forward_iterator_tag>::value)
75         return std::distance(__first, __last);
76       else
77         return __first != __last ? 1 : 0;
78     }
79 #pragma GCC diagnostic pop
80
81   struct _Identity
82   {
83     template<typename _Tp>
84       _Tp&&
85       operator()(_Tp&& __x) const noexcept
86       { return std::forward<_Tp>(__x); }
87   };
88
89   struct _Select1st
90   {
91     template<typename _Pair>
92       struct __1st_type;
93
94     template<typename _Tp, typename _Up>
95       struct __1st_type<pair<_Tp, _Up>>
96       { using type = _Tp; };
97
98     template<typename _Tp, typename _Up>
99       struct __1st_type<const pair<_Tp, _Up>>
100       { using type = const _Tp; };
101
102     template<typename _Pair>
103       struct __1st_type<_Pair&>
104       { using type = typename __1st_type<_Pair>::type&; };
105
106     template<typename _Tp>
107       typename __1st_type<_Tp>::type&&
108       operator()(_Tp&& __x) const noexcept
109       { return std::forward<_Tp>(__x).first; }
110   };
111
112   template<typename _ExKey>
113     struct _NodeBuilder;
114
115   template<>
116     struct _NodeBuilder<_Select1st>
117     {
118       template<typename _Kt, typename _Arg, typename _NodeGenerator>
119         static auto
120         _S_build(_Kt&& __k, _Arg&& __arg, _NodeGenerator& __node_gen)
121         -> typename _NodeGenerator::__node_ptr
122         {
123           return __node_gen(std::forward<_Kt>(__k),
124                             std::forward<_Arg>(__arg).second);
125         }
126     };
127
128   template<>
129     struct _NodeBuilder<_Identity>
130     {
131       template<typename _Kt, typename _Arg, typename _NodeGenerator>
132         static auto
133         _S_build(_Kt&& __k, _Arg&&, _NodeGenerator& __node_gen)
134         -> typename _NodeGenerator::__node_ptr
135         { return __node_gen(std::forward<_Kt>(__k)); }
136     };
137
138   template<typename _HashtableAlloc, typename _NodePtr>
139     struct _NodePtrGuard
140     {
141       _HashtableAlloc& _M_h;
142       _NodePtr _M_ptr;
143
144       ~_NodePtrGuard()
145       {
146         if (_M_ptr)
147           _M_h._M_deallocate_node_ptr(_M_ptr);
148       }
149     };
150
151   template<typename _NodeAlloc>
152     struct _Hashtable_alloc;
153
154   // Functor recycling a pool of nodes and using allocation once the pool is
155   // empty.
156   template<typename _NodeAlloc>
157     struct _ReuseOrAllocNode
158     {
159     private:
160       using __node_alloc_type = _NodeAlloc;
161       using __hashtable_alloc = _Hashtable_alloc<__node_alloc_type>;
162       using __node_alloc_traits =
163         typename __hashtable_alloc::__node_alloc_traits;
164
165     public:
166       using __node_ptr = typename __hashtable_alloc::__node_ptr;
167
168       _ReuseOrAllocNode(__node_ptr __nodes, __hashtable_alloc& __h)
169       : _M_nodes(__nodes), _M_h(__h) { }
170       _ReuseOrAllocNode(const _ReuseOrAllocNode&) = delete;
171
172       ~_ReuseOrAllocNode()
173       { _M_h._M_deallocate_nodes(_M_nodes); }
174
175 #pragma GCC diagnostic push
176 #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
177       template<typename _Arg>
178         __node_ptr
179         operator()(_Arg&& __arg)
180         {
181           if (!_M_nodes)
182             return _M_h._M_allocate_node(std::forward<_Arg>(__arg));
183
184           using value_type = typename _NodeAlloc::value_type::value_type;
185
186           __node_ptr __node = _M_nodes;
187           if constexpr (is_assignable<value_type&, _Arg>::value)
188             {
189               __node->_M_v() = std::forward<_Arg>(__arg);
190               _M_nodes = _M_nodes->_M_next();
191               __node->_M_nxt = nullptr;
192             }
193           else
194             {
195               _M_nodes = _M_nodes->_M_next();
196               __node->_M_nxt = nullptr;
197               auto& __a = _M_h._M_node_allocator();
198               __node_alloc_traits::destroy(__a, __node->_M_valptr());
199               _NodePtrGuard<__hashtable_alloc, __node_ptr>
200                 __guard{ _M_h, __node };
201               __node_alloc_traits::construct(__a, __node->_M_valptr(),
202                                              std::forward<_Arg>(__arg));
203               __guard._M_ptr = nullptr;
204             }
205           return __node;
206         }
207 #pragma GCC diagnostic pop
208
209     private:
210       __node_ptr _M_nodes;
211       __hashtable_alloc& _M_h;
212     };
213
214   // Functor similar to the previous one but without any pool of nodes to
215   // recycle.
216   template<typename _NodeAlloc>
217     struct _AllocNode
218     {
219     private:
220       using __hashtable_alloc = _Hashtable_alloc<_NodeAlloc>;
221
222     public:
223       using __node_ptr = typename __hashtable_alloc::__node_ptr;
224
225       _AllocNode(__hashtable_alloc& __h)
226       : _M_h(__h) { }
227
228       template<typename... _Args>
229         __node_ptr
230         operator()(_Args&&... __args) const
231         { return _M_h._M_allocate_node(std::forward<_Args>(__args)...); }
232
233     private:
234       __hashtable_alloc& _M_h;
235     };
236
237   // Auxiliary types used for all instantiations of _Hashtable nodes
238   // and iterators.
239
240   /**
241    *  struct _Hashtable_traits
242    *
243    *  Important traits for hash tables.
244    *
245    *  @tparam _Cache_hash_code  Boolean value. True if the value of
246    *  the hash function is stored along with the value. This is a
247    *  time-space tradeoff.  Storing it may improve lookup speed by
248    *  reducing the number of times we need to call the _Hash or _Equal
249    *  functors.
250    *
251    *  @tparam _Constant_iterators  Boolean value. True if iterator and
252    *  const_iterator are both constant iterator types. This is true
253    *  for unordered_set and unordered_multiset, false for
254    *  unordered_map and unordered_multimap.
255    *
256    *  @tparam _Unique_keys  Boolean value. True if the return value
257    *  of _Hashtable::count(k) is always at most one, false if it may
258    *  be an arbitrary number. This is true for unordered_set and
259    *  unordered_map, false for unordered_multiset and
260    *  unordered_multimap.
261    */
262   template<bool _Cache_hash_code, bool _Constant_iterators, bool _Unique_keys>
263     struct _Hashtable_traits
264     {
265       using __hash_cached = __bool_constant<_Cache_hash_code>;
266       using __constant_iterators = __bool_constant<_Constant_iterators>;
267       using __unique_keys = __bool_constant<_Unique_keys>;
268     };
269
270   /**
271    *  struct _Hashtable_hash_traits
272    *
273    *  Important traits for hash tables depending on associated hasher.
274    *
275    */
276   template<typename _Hash>
277     struct _Hashtable_hash_traits
278     {
279       static constexpr size_t
280       __small_size_threshold() noexcept
281       { return std::__is_fast_hash<_Hash>::value ? 0 : 20; }
282     };
283
284   /**
285    *  struct _Hash_node_base
286    *
287    *  Nodes, used to wrap elements stored in the hash table.  A policy
288    *  template parameter of class template _Hashtable controls whether
289    *  nodes also store a hash code. In some cases (e.g. strings) this
290    *  may be a performance win.
291    */
292   struct _Hash_node_base
293   {
294     _Hash_node_base* _M_nxt;
295
296     _Hash_node_base() noexcept : _M_nxt() { }
297
298     _Hash_node_base(_Hash_node_base* __next) noexcept : _M_nxt(__next) { }
299   };
300
301   /**
302    *  struct _Hash_node_value_base
303    *
304    *  Node type with the value to store.
305    */
306   template<typename _Value>
307     struct _Hash_node_value_base
308     {
309       using value_type = _Value;
310
311       __gnu_cxx::__aligned_buffer<_Value> _M_storage;
312
313       // These member functions must be always_inline, see PR 111050
314
315       [[__gnu__::__always_inline__]]
316       _Value*
317       _M_valptr() noexcept
318       { return _M_storage._M_ptr(); }
319
320       [[__gnu__::__always_inline__]]
321       const _Value*
322       _M_valptr() const noexcept
323       { return _M_storage._M_ptr(); }
324
325       [[__gnu__::__always_inline__]]
326       _Value&
327       _M_v() noexcept
328       { return *_M_valptr(); }
329
330       [[__gnu__::__always_inline__]]
331       const _Value&
332       _M_v() const noexcept
333       { return *_M_valptr(); }
334     };
335
336   /**
337    *  Primary template struct _Hash_node_code_cache.
338    */
339   template<bool _Cache_hash_code>
340     struct _Hash_node_code_cache
341     { };
342
343   /**
344    *  Specialization for node with cache, struct _Hash_node_code_cache.
345    */
346   template<>
347     struct _Hash_node_code_cache<true>
348     { size_t  _M_hash_code; };
349
350   template<typename _Value, bool _Cache_hash_code>
351     struct _Hash_node_value
352     : _Hash_node_value_base<_Value>
353     , _Hash_node_code_cache<_Cache_hash_code>
354     { };
355
356   /**
357    *  Primary template struct _Hash_node.
358    */
359   template<typename _Value, bool _Cache_hash_code>
360     struct _Hash_node
361     : _Hash_node_base
362     , _Hash_node_value<_Value, _Cache_hash_code>
363     {
364       _Hash_node*
365       _M_next() const noexcept
366       { return static_cast<_Hash_node*>(this->_M_nxt); }
367     };
368
369   /// Base class for node iterators.
370   template<typename _Value, bool _Cache_hash_code>
371     struct _Node_iterator_base
372     {
373       using __node_type = _Hash_node<_Value, _Cache_hash_code>;
374
375       __node_type* _M_cur;
376
377       _Node_iterator_base() : _M_cur(nullptr) { }
378       _Node_iterator_base(__node_type* __p) noexcept
379       : _M_cur(__p) { }
380
381       void
382       _M_incr() noexcept
383       { _M_cur = _M_cur->_M_next(); }
384
385       friend bool
386       operator==(const _Node_iterator_base& __x, const _Node_iterator_base& __y)
387       noexcept
388       { return __x._M_cur == __y._M_cur; }
389
390 #if __cpp_impl_three_way_comparison < 201907L
391       friend bool
392       operator!=(const _Node_iterator_base& __x, const _Node_iterator_base& __y)
393       noexcept
394       { return __x._M_cur != __y._M_cur; }
395 #endif
396     };
397
398   /// Node iterators, used to iterate through all the hashtable.
399   template<typename _Value, bool __constant_iterators, bool __cache>
400     struct _Node_iterator
401     : public _Node_iterator_base<_Value, __cache>
402     {
403     private:
404       using __base_type = _Node_iterator_base<_Value, __cache>;
405       using __node_type = typename __base_type::__node_type;
406
407     public:
408       using value_type        = _Value;
409       using difference_type   = ptrdiff_t;
410       using iterator_category = forward_iterator_tag;
411
412       using pointer = __conditional_t<__constant_iterators,
413                                       const value_type*, value_type*>;
414
415       using reference = __conditional_t<__constant_iterators,
416                                         const value_type&, value_type&>;
417
418       _Node_iterator() = default;
419
420       explicit
421       _Node_iterator(__node_type* __p) noexcept
422       : __base_type(__p) { }
423
424       reference
425       operator*() const noexcept
426       { return this->_M_cur->_M_v(); }
427
428       pointer
429       operator->() const noexcept
430       { return this->_M_cur->_M_valptr(); }
431
432       _Node_iterator&
433       operator++() noexcept
434       {
435         this->_M_incr();
436         return *this;
437       }
438
439       _Node_iterator
440       operator++(int) noexcept
441       {
442         _Node_iterator __tmp(*this);
443         this->_M_incr();
444         return __tmp;
445       }
446
447 #if __cpp_impl_three_way_comparison >= 201907L
448       friend bool
449       operator==(const _Node_iterator&, const _Node_iterator&) = default;
450 #else
451       friend bool
452       operator==(const _Node_iterator& __x, const _Node_iterator& __y) noexcept
453       {
454         const __base_type& __bx = __x;
455         const __base_type& __by = __y;
456         return __bx == __by;
457       }
458
459       friend bool
460       operator!=(const _Node_iterator& __x, const _Node_iterator& __y) noexcept
461       { return !(__x == __y); }
462 #endif
463     };
464
465   /// Node const_iterators, used to iterate through all the hashtable.
466   template<typename _Value, bool __constant_iterators, bool __cache>
467     struct _Node_const_iterator
468     : public _Node_iterator_base<_Value, __cache>
469     {
470     private:
471       using __base_type = _Node_iterator_base<_Value, __cache>;
472       using __node_type = typename __base_type::__node_type;
473
474       // The corresponding non-const iterator.
475       using __iterator
476         = _Node_iterator<_Value, __constant_iterators, __cache>;
477
478     public:
479       using value_type        = _Value;
480       using difference_type   = ptrdiff_t;
481       using iterator_category = forward_iterator_tag;
482
483       using pointer = const value_type*;
484       using reference = const value_type&;
485
486       _Node_const_iterator() = default;
487
488       explicit
489       _Node_const_iterator(__node_type* __p) noexcept
490       : __base_type(__p) { }
491
492       _Node_const_iterator(const __iterator& __x) noexcept
493       : __base_type(__x._M_cur) { }
494
495       reference
496       operator*() const noexcept
497       { return this->_M_cur->_M_v(); }
498
499       pointer
500       operator->() const noexcept
501       { return this->_M_cur->_M_valptr(); }
502
503       _Node_const_iterator&
504       operator++() noexcept
505       {
506         this->_M_incr();
507         return *this;
508       }
509
510       _Node_const_iterator
511       operator++(int) noexcept
512       {
513         _Node_const_iterator __tmp(*this);
514         this->_M_incr();
515         return __tmp;
516       }
517
518 #if __cpp_impl_three_way_comparison >= 201907L
519       friend bool
520       operator==(const _Node_const_iterator&,
521                  const _Node_const_iterator&) = default;
522
523       friend bool
524       operator==(const _Node_const_iterator& __x, const __iterator& __y)
525       {
526         const __base_type& __bx = __x;
527         const __base_type& __by = __y;
528         return __bx == __by;
529       }
530 #else
531       friend bool
532       operator==(const _Node_const_iterator& __x,
533                  const _Node_const_iterator& __y) noexcept
534       {
535         const __base_type& __bx = __x;
536         const __base_type& __by = __y;
537         return __bx == __by;
538       }
539
540       friend bool
541       operator!=(const _Node_const_iterator& __x,
542                  const _Node_const_iterator& __y) noexcept
543       { return !(__x == __y); }
544
545       friend bool
546       operator==(const _Node_const_iterator& __x,
547                  const __iterator& __y) noexcept
548       {
549         const __base_type& __bx = __x;
550         const __base_type& __by = __y;
551         return __bx == __by;
552       }
553
554       friend bool
555       operator!=(const _Node_const_iterator& __x,
556                  const __iterator& __y) noexcept
557       { return !(__x == __y); }
558
559       friend bool
560       operator==(const __iterator& __x,
561                  const _Node_const_iterator& __y) noexcept
562       {
563         const __base_type& __bx = __x;
564         const __base_type& __by = __y;
565         return __bx == __by;
566       }
567
568       friend bool
569       operator!=(const __iterator& __x,
570                  const _Node_const_iterator& __y) noexcept
571       { return !(__x == __y); }
572 #endif
573     };
574
575   // Many of class template _Hashtable's template parameters are policy
576   // classes.  These are defaults for the policies.
577
578   /// Default range hashing function: use division to fold a large number
579   /// into the range [0, N).
580   struct _Mod_range_hashing
581   {
582     size_t
583     operator()(size_t __num, size_t __den) const noexcept
584     { return __num % __den; }
585   };
586
587   /// Default ranged hash function H.  In principle it should be a
588   /// function object composed from objects of type H1 and H2 such that
589   /// h(k, N) = h2(h1(k), N), but that would mean making extra copies of
590   /// h1 and h2.  So instead we'll just use a tag to tell class template
591   /// hashtable to do that composition.
592   struct _Default_ranged_hash { };
593
594   /// Default value for rehash policy.  Bucket size is (usually) the
595   /// smallest prime that keeps the load factor small enough.
596   struct _Prime_rehash_policy
597   {
598     using __has_load_factor = true_type;
599
600     _Prime_rehash_policy(float __z = 1.0) noexcept
601     : _M_max_load_factor(__z), _M_next_resize(0) { }
602
603     float
604     max_load_factor() const noexcept
605     { return _M_max_load_factor; }
606
607     // Return a bucket size no smaller than n.
608     // TODO: 'const' qualifier is kept for abi compatibility reason.
609     size_t
610     _M_next_bkt(size_t __n) const;
611
612     // Return a bucket count appropriate for n elements
613     size_t
614     _M_bkt_for_elements(size_t __n) const
615     { return __builtin_ceil(__n / (double)_M_max_load_factor); }
616
617     // __n_bkt is current bucket count, __n_elt is current element count,
618     // and __n_ins is number of elements to be inserted.  Do we need to
619     // increase bucket count?  If so, return make_pair(true, n), where n
620     // is the new bucket count.  If not, return make_pair(false, 0).
621     // TODO: 'const' qualifier is kept for abi compatibility reason.
622     std::pair<bool, size_t>
623     _M_need_rehash(size_t __n_bkt, size_t __n_elt,
624                    size_t __n_ins) const;
625
626     using _State = size_t;
627
628     _State
629     _M_state() const
630     { return _M_next_resize; }
631
632     void
633     _M_reset() noexcept
634     { _M_next_resize = 0; }
635
636     void
637     _M_reset(_State __state)
638     { _M_next_resize = __state; }
639
640     static const size_t _S_growth_factor = 2;
641
642     float               _M_max_load_factor;
643
644     // TODO: 'mutable' kept for abi compatibility reason.
645     mutable size_t      _M_next_resize;
646   };
647
648   /// Range hashing function assuming that second arg is a power of 2.
649   struct _Mask_range_hashing
650   {
651     size_t
652     operator()(size_t __num, size_t __den) const noexcept
653     { return __num & (__den - 1); }
654   };
655
656   /// Compute closest power of 2 not less than __n
657   inline size_t
658   __clp2(size_t __n) noexcept
659   {
660     using __gnu_cxx::__int_traits;
661     // Equivalent to return __n ? std::bit_ceil(__n) : 0;
662     if (__n < 2)
663       return __n;
664     const unsigned __lz = sizeof(size_t) > sizeof(long)
665       ? __builtin_clzll(__n - 1ull)
666       : __builtin_clzl(__n - 1ul);
667     // Doing two shifts avoids undefined behaviour when __lz == 0.
668     return (size_t(1) << (__int_traits<size_t>::__digits - __lz - 1)) << 1;
669   }
670
671   /// Rehash policy providing power of 2 bucket numbers. Avoids modulo
672   /// operations.
673   struct _Power2_rehash_policy
674   {
675     using __has_load_factor = true_type;
676
677     _Power2_rehash_policy(float __z = 1.0) noexcept
678     : _M_max_load_factor(__z), _M_next_resize(0) { }
679
680     float
681     max_load_factor() const noexcept
682     { return _M_max_load_factor; }
683
684     // Return a bucket size no smaller than n (as long as n is not above the
685     // highest power of 2).
686     size_t
687     _M_next_bkt(size_t __n) noexcept
688     {
689       if (__n == 0)
690         // Special case on container 1st initialization with 0 bucket count
691         // hint. We keep _M_next_resize to 0 to make sure that next time we
692         // want to add an element allocation will take place.
693         return 1;
694
695       const auto __max_width = std::min<size_t>(sizeof(size_t), 8);
696       const auto __max_bkt = size_t(1) << (__max_width * __CHAR_BIT__ - 1);
697       size_t __res = __clp2(__n);
698
699       if (__res == 0)
700         __res = __max_bkt;
701       else if (__res == 1)
702         // If __res is 1 we force it to 2 to make sure there will be an
703         // allocation so that nothing need to be stored in the initial
704         // single bucket
705         __res = 2;
706
707       if (__res == __max_bkt)
708         // Set next resize to the max value so that we never try to rehash again
709         // as we already reach the biggest possible bucket number.
710         // Note that it might result in max_load_factor not being respected.
711         _M_next_resize = size_t(-1);
712       else
713         _M_next_resize
714           = __builtin_floor(__res * (double)_M_max_load_factor);
715
716       return __res;
717     }
718
719     // Return a bucket count appropriate for n elements
720     size_t
721     _M_bkt_for_elements(size_t __n) const noexcept
722     { return __builtin_ceil(__n / (double)_M_max_load_factor); }
723
724     // __n_bkt is current bucket count, __n_elt is current element count,
725     // and __n_ins is number of elements to be inserted.  Do we need to
726     // increase bucket count?  If so, return make_pair(true, n), where n
727     // is the new bucket count.  If not, return make_pair(false, 0).
728     std::pair<bool, size_t>
729     _M_need_rehash(size_t __n_bkt, size_t __n_elt, size_t __n_ins) noexcept
730     {
731       if (__n_elt + __n_ins > _M_next_resize)
732         {
733           // If _M_next_resize is 0 it means that we have nothing allocated so
734           // far and that we start inserting elements. In this case we start
735           // with an initial bucket size of 11.
736           double __min_bkts
737             = std::max<size_t>(__n_elt + __n_ins, _M_next_resize ? 0 : 11)
738               / (double)_M_max_load_factor;
739           if (__min_bkts >= __n_bkt)
740             return { true,
741               _M_next_bkt(std::max<size_t>(__builtin_floor(__min_bkts) + 1,
742                                            __n_bkt * _S_growth_factor)) };
743
744           _M_next_resize
745             = __builtin_floor(__n_bkt * (double)_M_max_load_factor);
746           return { false, 0 };
747         }
748       else
749         return { false, 0 };
750     }
751
752     using _State = size_t;
753
754     _State
755     _M_state() const noexcept
756     { return _M_next_resize; }
757
758     void
759     _M_reset() noexcept
760     { _M_next_resize = 0; }
761
762     void
763     _M_reset(_State __state) noexcept
764     { _M_next_resize = __state; }
765
766     static const size_t _S_growth_factor = 2;
767
768     float       _M_max_load_factor;
769     size_t      _M_next_resize;
770   };
771
772   template<typename _RehashPolicy>
773     struct _RehashStateGuard
774     {
775       _RehashPolicy* _M_guarded_obj;
776       typename _RehashPolicy::_State _M_prev_state;
777
778       _RehashStateGuard(_RehashPolicy& __policy)
779       : _M_guarded_obj(std::__addressof(__policy))
780       , _M_prev_state(__policy._M_state())
781       { }
782       _RehashStateGuard(const _RehashStateGuard&) = delete;
783
784       ~_RehashStateGuard()
785       {
786         if (_M_guarded_obj)
787           _M_guarded_obj->_M_reset(_M_prev_state);
788       }
789     };
790
791   // Base classes for std::_Hashtable.  We define these base classes
792   // because in some cases we want to do different things depending on
793   // the value of a policy class.  In some cases the policy class
794   // affects which member functions and nested typedefs are defined;
795   // we handle that by specializing base class templates.  Several of
796   // the base class templates need to access other members of class
797   // template _Hashtable, so we use a variant of the "Curiously
798   // Recurring Template Pattern" (CRTP) technique.
799
800   /**
801    *  Primary class template _Map_base.
802    *
803    *  If the hashtable has a value type of the form pair<const T1, T2> and
804    *  a key extraction policy (_ExtractKey) that returns the first part
805    *  of the pair, the hashtable gets a mapped_type typedef.  If it
806    *  satisfies those criteria and also has unique keys, then it also
807    *  gets an operator[].
808    */
809   template<typename _Key, typename _Value, typename _Alloc,
810            typename _ExtractKey, typename _Equal,
811            typename _Hash, typename _RangeHash, typename _Unused,
812            typename _RehashPolicy, typename _Traits,
813            bool _Unique_keys = _Traits::__unique_keys::value>
814     struct _Map_base { };
815
816   /// Partial specialization, __unique_keys set to false, std::pair value type.
817   template<typename _Key, typename _Val, typename _Alloc, typename _Equal,
818            typename _Hash, typename _RangeHash, typename _Unused,
819            typename _RehashPolicy, typename _Traits>
820     struct _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal,
821                      _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, false>
822     {
823       using mapped_type = _Val;
824     };
825
826   /// Partial specialization, __unique_keys set to true.
827   template<typename _Key, typename _Val, typename _Alloc, typename _Equal,
828            typename _Hash, typename _RangeHash, typename _Unused,
829            typename _RehashPolicy, typename _Traits>
830     struct _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal,
831                      _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, true>
832     {
833     private:
834       using __hashtable_base = _Hashtable_base<_Key, pair<const _Key, _Val>,
835                                                _Select1st, _Equal, _Hash,
836                                                _RangeHash, _Unused,
837                                                _Traits>;
838
839       using __hashtable = _Hashtable<_Key, pair<const _Key, _Val>, _Alloc,
840                                      _Select1st, _Equal, _Hash, _RangeHash,
841                                      _Unused, _RehashPolicy, _Traits>;
842
843       using __hash_code = typename __hashtable_base::__hash_code;
844
845     public:
846       using key_type = typename __hashtable_base::key_type;
847       using mapped_type = _Val;
848
849       mapped_type&
850       operator[](const key_type& __k);
851
852       mapped_type&
853       operator[](key_type&& __k);
854
855       // _GLIBCXX_RESOLVE_LIB_DEFECTS
856       // DR 761. unordered_map needs an at() member function.
857       mapped_type&
858       at(const key_type& __k)
859       {
860         auto __ite = static_cast<__hashtable*>(this)->find(__k);
861         if (!__ite._M_cur)
862           __throw_out_of_range(__N("unordered_map::at"));
863         return __ite->second;
864       }
865
866       const mapped_type&
867       at(const key_type& __k) const
868       {
869         auto __ite = static_cast<const __hashtable*>(this)->find(__k);
870         if (!__ite._M_cur)
871           __throw_out_of_range(__N("unordered_map::at"));
872         return __ite->second;
873       }
874     };
875
876   template<typename _Key, typename _Val, typename _Alloc, typename _Equal,
877            typename _Hash, typename _RangeHash, typename _Unused,
878            typename _RehashPolicy, typename _Traits>
879     auto
880     _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal,
881               _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, true>::
882     operator[](const key_type& __k)
883     -> mapped_type&
884     {
885       __hashtable* __h = static_cast<__hashtable*>(this);
886       __hash_code __code = __h->_M_hash_code(__k);
887       size_t __bkt = __h->_M_bucket_index(__code);
888       if (auto __node = __h->_M_find_node(__bkt, __k, __code))
889         return __node->_M_v().second;
890
891       typename __hashtable::_Scoped_node __node {
892         __h,
893         std::piecewise_construct,
894         std::tuple<const key_type&>(__k),
895         std::tuple<>()
896       };
897       auto __pos
898         = __h->_M_insert_unique_node(__bkt, __code, __node._M_node);
899       __node._M_node = nullptr;
900       return __pos->second;
901     }
902
903   template<typename _Key, typename _Val, typename _Alloc, typename _Equal,
904            typename _Hash, typename _RangeHash, typename _Unused,
905            typename _RehashPolicy, typename _Traits>
906     auto
907     _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal,
908               _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits, true>::
909     operator[](key_type&& __k)
910     -> mapped_type&
911     {
912       __hashtable* __h = static_cast<__hashtable*>(this);
913       __hash_code __code = __h->_M_hash_code(__k);
914       size_t __bkt = __h->_M_bucket_index(__code);
915       if (auto __node = __h->_M_find_node(__bkt, __k, __code))
916         return __node->_M_v().second;
917
918       typename __hashtable::_Scoped_node __node {
919         __h,
920         std::piecewise_construct,
921         std::forward_as_tuple(std::move(__k)),
922         std::tuple<>()
923       };
924       auto __pos
925         = __h->_M_insert_unique_node(__bkt, __code, __node._M_node);
926       __node._M_node = nullptr;
927       return __pos->second;
928     }
929
930   // Partial specialization for unordered_map<const T, U>, see PR 104174.
931   template<typename _Key, typename _Val, typename _Alloc, typename _Equal,
932            typename _Hash, typename _RangeHash, typename _Unused,
933            typename _RehashPolicy, typename _Traits, bool __uniq>
934     struct _Map_base<const _Key, pair<const _Key, _Val>,
935                      _Alloc, _Select1st, _Equal, _Hash,
936                      _RangeHash, _Unused, _RehashPolicy, _Traits, __uniq>
937     : _Map_base<_Key, pair<const _Key, _Val>, _Alloc, _Select1st, _Equal, _Hash,
938                 _RangeHash, _Unused, _RehashPolicy, _Traits, __uniq>
939     { };
940
941   template<typename _Policy>
942     using __has_load_factor = typename _Policy::__has_load_factor;
943
944   /**
945    *  Primary class template  _Rehash_base.
946    *
947    *  Give hashtable the max_load_factor functions and reserve iff the
948    *  rehash policy supports it.
949   */
950   template<typename _Key, typename _Value, typename _Alloc,
951            typename _ExtractKey, typename _Equal,
952            typename _Hash, typename _RangeHash, typename _Unused,
953            typename _RehashPolicy, typename _Traits,
954            typename =
955              __detected_or_t<false_type, __has_load_factor, _RehashPolicy>>
956     struct _Rehash_base;
957
958   /// Specialization when rehash policy doesn't provide load factor management.
959   template<typename _Key, typename _Value, typename _Alloc,
960            typename _ExtractKey, typename _Equal,
961            typename _Hash, typename _RangeHash, typename _Unused,
962            typename _RehashPolicy, typename _Traits>
963     struct _Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
964                         _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits,
965                         false_type /* Has load factor */>
966     {
967     };
968
969   /// Specialization when rehash policy provide load factor management.
970   template<typename _Key, typename _Value, typename _Alloc,
971            typename _ExtractKey, typename _Equal,
972            typename _Hash, typename _RangeHash, typename _Unused,
973            typename _RehashPolicy, typename _Traits>
974     struct _Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,
975                         _Hash, _RangeHash, _Unused, _RehashPolicy, _Traits,
976                         true_type /* Has load factor */>
977     {
978     private:
979       using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey,
980                                      _Equal, _Hash, _RangeHash, _Unused,
981                                      _RehashPolicy, _Traits>;
982
983     public:
984       float
985       max_load_factor() const noexcept
986       {
987         const __hashtable* __this = static_cast<const __hashtable*>(this);
988         return __this->__rehash_policy().max_load_factor();
989       }
990
991       void
992       max_load_factor(float __z)
993       {
994         __hashtable* __this = static_cast<__hashtable*>(this);
995         __this->__rehash_policy(_RehashPolicy(__z));
996       }
997
998       void
999       reserve(size_t __n)
1000       {
1001         __hashtable* __this = static_cast<__hashtable*>(this);
1002         __this->rehash(__this->__rehash_policy()._M_bkt_for_elements(__n));
1003       }
1004     };
1005
1006   /**
1007    *  Primary class template _Hashtable_ebo_helper.
1008    *
1009    *  Helper class using [[no_unique_address]] to reduce object size.
1010    */
1011   template<typename _Tp,
1012            bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
1013     struct _Hashtable_ebo_helper
1014     {
1015       [[__no_unique_address__]] _Tp _M_obj;
1016     };
1017
1018 #if ! _GLIBCXX_INLINE_VERSION
1019   // For ABI compatibility reasons, [[no_unique_address]] is only used
1020   // for empty non-final types.
1021   template<typename _Tp>
1022     struct _Hashtable_ebo_helper<_Tp, false>
1023     {
1024       _Tp _M_obj;
1025     };
1026 #endif
1027
1028   /**
1029    *  Primary class template _Local_iterator_base.
1030    *
1031    *  Base class for local iterators, used to iterate within a bucket
1032    *  but not between buckets.
1033    */
1034   template<typename _Key, typename _Value, typename _ExtractKey,
1035            typename _Hash, typename _RangeHash, typename _Unused,
1036            bool __cache_hash_code>
1037     struct _Local_iterator_base;
1038
1039   // Wraps the _Hash object and provides some utility functions for using it.
1040   template<typename _Key, typename _Value, typename _ExtractKey,
1041            typename _Hash, typename _RangeHash, typename _Unused,
1042            bool /* __cache_hash_code */>
1043     struct _Hash_code_base
1044     {
1045       // Gives the local iterator implementation access to _M_bucket_index().
1046       friend struct _Local_iterator_base<_Key, _Value, _ExtractKey,
1047                                          _Hash, _RangeHash, _Unused, false>;
1048     public:
1049       using hasher = _Hash;
1050
1051       hasher
1052       hash_function() const
1053       { return _M_hash._M_obj; }
1054
1055     protected:
1056       [[__no_unique_address__]] _Hashtable_ebo_helper<_Hash> _M_hash{};
1057
1058       using __hash_code = size_t;
1059
1060       // We need the default constructor for the local iterators and _Hashtable
1061       // default constructor.
1062       _Hash_code_base() = default;
1063
1064       _Hash_code_base(const _Hash& __hash) : _M_hash{__hash} { }
1065
1066       __hash_code
1067       _M_hash_code(const _Key& __k) const
1068       {
1069         static_assert(__is_invocable<const _Hash&, const _Key&>{},
1070             "hash function must be invocable with an argument of key type");
1071         return _M_hash._M_obj(__k);
1072       }
1073
1074       template<typename _Kt>
1075         __hash_code
1076         _M_hash_code_tr(const _Kt& __k) const
1077         {
1078           static_assert(__is_invocable<const _Hash&, const _Kt&>{},
1079             "hash function must be invocable with an argument of key type");
1080           return _M_hash._M_obj(__k);
1081         }
1082
1083       __hash_code
1084       _M_hash_code(const _Hash_node_value<_Value, false>& __n) const
1085       { return _M_hash_code(_ExtractKey{}(__n._M_v())); }
1086
1087       __hash_code
1088       _M_hash_code(const _Hash_node_value<_Value, true>& __n) const
1089       { return __n._M_hash_code; }
1090
1091       size_t
1092       _M_bucket_index(__hash_code __c, size_t __bkt_count) const
1093       { return _RangeHash{}(__c, __bkt_count); }
1094
1095       size_t
1096       _M_bucket_index(const _Hash_node_value<_Value, false>& __n,
1097                       size_t __bkt_count) const
1098       noexcept( noexcept(declval<const _Hash&>()(declval<const _Key&>())) )
1099       {
1100         return _RangeHash{}(_M_hash_code(_ExtractKey{}(__n._M_v())),
1101                             __bkt_count);
1102       }
1103
1104       size_t
1105       _M_bucket_index(const _Hash_node_value<_Value, true>& __n,
1106                       size_t __bkt_count) const noexcept
1107       { return _RangeHash{}(__n._M_hash_code, __bkt_count); }
1108     };
1109
1110   /// Partial specialization used when nodes contain a cached hash code.
1111   template<typename _Key, typename _Value, typename _ExtractKey,
1112            typename _Hash, typename _RangeHash, typename _Unused>
1113     struct _Local_iterator_base<_Key, _Value, _ExtractKey,
1114                                 _Hash, _RangeHash, _Unused, true>
1115     : public _Node_iterator_base<_Value, true>
1116     {
1117     protected:
1118       using __base_node_iter = _Node_iterator_base<_Value, true>;
1119       using __hash_code_base = _Hash_code_base<_Key, _Value, _ExtractKey,
1120                                               _Hash, _RangeHash, _Unused, true>;
1121
1122       _Local_iterator_base() = default;
1123
1124       _Local_iterator_base(const __hash_code_base&,
1125                            _Hash_node<_Value, true>* __p,
1126                            size_t __bkt, size_t __bkt_count)
1127       : __base_node_iter(__p), _M_bucket(__bkt), _M_bucket_count(__bkt_count)
1128       { }
1129
1130       void
1131       _M_incr()
1132       {
1133         __base_node_iter::_M_incr();
1134         if (this->_M_cur)
1135           {
1136             size_t __bkt
1137               = _RangeHash{}(this->_M_cur->_M_hash_code, _M_bucket_count);
1138             if (__bkt != _M_bucket)
1139               this->_M_cur = nullptr;
1140           }
1141       }
1142
1143       size_t _M_bucket = 0;
1144       size_t _M_bucket_count = 0;
1145
1146     public:
1147       size_t
1148       _M_get_bucket() const { return _M_bucket; }  // for debug mode
1149     };
1150
1151   // Uninitialized storage for a _Hash object in a local iterator.
1152   // This type is DefaultConstructible even if the _Hash type isn't,
1153   // so that _Local_iterator_base<..., false> can be DefaultConstructible.
1154   template<typename _Hash>
1155     struct _Hash_obj_storage
1156     {
1157       union _Uninit_storage
1158       {
1159         _Uninit_storage() noexcept { }
1160         ~_Uninit_storage() { }
1161
1162         [[__no_unique_address__]] _Hash _M_h;
1163       };
1164
1165       [[__no_unique_address__]] _Uninit_storage _M_u;
1166     };
1167
1168   // Partial specialization used when hash codes are not cached
1169   template<typename _Key, typename _Value, typename _ExtractKey,
1170            typename _Hash, typename _RangeHash, typename _Unused>
1171     struct _Local_iterator_base<_Key, _Value, _ExtractKey,
1172                                 _Hash, _RangeHash, _Unused, false>
1173     : _Hash_obj_storage<_Hash>, _Node_iterator_base<_Value, false>
1174     {
1175     protected:
1176       using __hash_code_base = _Hash_code_base<_Key, _Value, _ExtractKey,
1177                                              _Hash, _RangeHash, _Unused, false>;
1178       using __hash_obj_storage = _Hash_obj_storage<_Hash>;
1179       using __node_iter_base = _Node_iterator_base<_Value, false>;
1180
1181       _Local_iterator_base() = default;
1182
1183       _Local_iterator_base(const __hash_code_base& __base,
1184                            _Hash_node<_Value, false>* __p,
1185                            size_t __bkt, size_t __bkt_count)
1186       : __node_iter_base(__p), _M_bucket(__bkt), _M_bucket_count(__bkt_count)
1187       { _M_init(__base._M_hash._M_obj); }
1188
1189       ~_Local_iterator_base()
1190       {
1191         if (_M_bucket_count != size_t(-1))
1192           _M_destroy();
1193       }
1194
1195       _Local_iterator_base(const _Local_iterator_base& __iter)
1196       : __node_iter_base(__iter._M_cur), _M_bucket(__iter._M_bucket)
1197       , _M_bucket_count(__iter._M_bucket_count)
1198       {
1199         if (_M_bucket_count != size_t(-1))
1200           _M_init(__iter._M_h());
1201       }
1202
1203       _Local_iterator_base&
1204       operator=(const _Local_iterator_base& __iter)
1205       {
1206         if (_M_bucket_count != size_t(-1))
1207           _M_destroy();
1208         this->_M_cur = __iter._M_cur;
1209         _M_bucket = __iter._M_bucket;
1210         _M_bucket_count = __iter._M_bucket_count;
1211         if (_M_bucket_count != size_t(-1))
1212           _M_init(__iter._M_h());
1213         return *this;
1214       }
1215
1216       void
1217       _M_incr()
1218       {
1219         __node_iter_base::_M_incr();
1220         if (this->_M_cur)
1221           {
1222             const auto __code = _M_h()(_ExtractKey{}(this->_M_cur->_M_v()));
1223             size_t __bkt = _RangeHash{}(__code, _M_bucket_count);
1224             if (__bkt != _M_bucket)
1225               this->_M_cur = nullptr;
1226           }
1227       }
1228
1229       size_t _M_bucket = 0;
1230       size_t _M_bucket_count = -1;
1231
1232       void
1233       _M_init(const _Hash& __h)
1234       { std::_Construct(std::__addressof(__hash_obj_storage::_M_u._M_h), __h); }
1235
1236       void
1237       _M_destroy() { __hash_obj_storage::_M_u._M_h.~_Hash(); }
1238
1239       const _Hash&
1240       _M_h() const { return __hash_obj_storage::_M_u._M_h; }
1241
1242     public:
1243       size_t
1244       _M_get_bucket() const { return _M_bucket; }  // for debug mode
1245     };
1246
1247   /// local iterators
1248   template<typename _Key, typename _Value, typename _ExtractKey,
1249            typename _Hash, typename _RangeHash, typename _Unused,
1250            bool __constant_iterators, bool __cache>
1251     struct _Local_iterator
1252     : public _Local_iterator_base<_Key, _Value, _ExtractKey,
1253                                   _Hash, _RangeHash, _Unused, __cache>
1254     {
1255     private:
1256       using __base_type = _Local_iterator_base<_Key, _Value, _ExtractKey,
1257                                            _Hash, _RangeHash, _Unused, __cache>;
1258       using __hash_code_base = typename __base_type::__hash_code_base;
1259
1260     public:
1261       using value_type = _Value;
1262       using pointer = __conditional_t<__constant_iterators,
1263                                       const value_type*, value_type*>;
1264       using reference = __conditional_t<__constant_iterators,
1265                                         const value_type&, value_type&>;
1266       using difference_type = ptrdiff_t;
1267       using iterator_category = forward_iterator_tag;
1268
1269       _Local_iterator() = default;
1270
1271       _Local_iterator(const __hash_code_base& __base,
1272                       _Hash_node<_Value, __cache>* __n,
1273                       size_t __bkt, size_t __bkt_count)
1274       : __base_type(__base, __n, __bkt, __bkt_count)
1275       { }
1276
1277       reference
1278       operator*() const
1279       { return this->_M_cur->_M_v(); }
1280
1281       pointer
1282       operator->() const
1283       { return this->_M_cur->_M_valptr(); }
1284
1285       _Local_iterator&
1286       operator++()
1287       {
1288         this->_M_incr();
1289         return *this;
1290       }
1291
1292       _Local_iterator
1293       operator++(int)
1294       {
1295         _Local_iterator __tmp(*this);
1296         this->_M_incr();
1297         return __tmp;
1298       }
1299     };
1300
1301   /// local const_iterators
1302   template<typename _Key, typename _Value, typename _ExtractKey,
1303            typename _Hash, typename _RangeHash, typename _Unused,
1304            bool __constant_iterators, bool __cache>
1305     struct _Local_const_iterator
1306     : public _Local_iterator_base<_Key, _Value, _ExtractKey,
1307                                   _Hash, _RangeHash, _Unused, __cache>
1308     {
1309     private:
1310       using __base_type = _Local_iterator_base<_Key, _Value, _ExtractKey,
1311                                            _Hash, _RangeHash, _Unused, __cache>;
1312       using __hash_code_base = typename __base_type::__hash_code_base;
1313
1314     public:
1315       using value_type        = _Value;
1316       using pointer           = const value_type*;
1317       using reference         = const value_type&;
1318       using difference_type   = ptrdiff_t;
1319       using iterator_category = forward_iterator_tag;
1320
1321       _Local_const_iterator() = default;
1322
1323       _Local_const_iterator(const __hash_code_base& __base,
1324                             _Hash_node<_Value, __cache>* __n,
1325                             size_t __bkt, size_t __bkt_count)
1326       : __base_type(__base, __n, __bkt, __bkt_count)
1327       { }
1328
1329       _Local_const_iterator(const _Local_iterator<_Key, _Value, _ExtractKey,
1330                                                   _Hash, _RangeHash, _Unused,
1331                                                   __constant_iterators,
1332                                                   __cache>& __x)
1333       : __base_type(__x)
1334       { }
1335
1336       reference
1337       operator*() const
1338       { return this->_M_cur->_M_v(); }
1339
1340       pointer
1341       operator->() const
1342       { return this->_M_cur->_M_valptr(); }
1343
1344       _Local_const_iterator&
1345       operator++()
1346       {
1347         this->_M_incr();
1348         return *this;
1349       }
1350
1351       _Local_const_iterator
1352       operator++(int)
1353       {
1354         _Local_const_iterator __tmp(*this);
1355         this->_M_incr();
1356         return __tmp;
1357       }
1358     };
1359
1360   /**
1361    *  Primary class template _Hashtable_base.
1362    *
1363    *  Helper class adding management of _Equal functor to
1364    *  _Hash_code_base type.
1365    *
1366    *  Base class templates are:
1367    *    - __detail::_Hash_code_base
1368    */
1369   template<typename _Key, typename _Value, typename _ExtractKey,
1370            typename _Equal, typename _Hash, typename _RangeHash,
1371            typename _Unused, typename _Traits>
1372     struct _Hashtable_base
1373     : public _Hash_code_base<_Key, _Value, _ExtractKey, _Hash, _RangeHash,
1374                              _Unused, _Traits::__hash_cached::value>
1375     {
1376     public:
1377       using key_type        = _Key;
1378       using value_type      = _Value;
1379       using key_equal       = _Equal;
1380       using size_type       = size_t;
1381       using difference_type = ptrdiff_t;
1382
1383       using __traits_type = _Traits;
1384       using __hash_cached = typename __traits_type::__hash_cached;
1385
1386       using __hash_code_base = _Hash_code_base<_Key, _Value, _ExtractKey,
1387                                                _Hash, _RangeHash, _Unused,
1388                                                __hash_cached::value>;
1389
1390       using __hash_code = typename __hash_code_base::__hash_code;
1391
1392     protected:
1393       [[__no_unique_address__]] _Hashtable_ebo_helper<_Equal> _M_equal{};
1394
1395       _Hashtable_base() = default;
1396
1397       _Hashtable_base(const _Hash& __hash, const _Equal& __eq)
1398       : __hash_code_base(__hash), _M_equal{__eq}
1399       { }
1400
1401       bool
1402       _M_key_equals(const _Key& __k,
1403                     const _Hash_node_value<_Value,
1404                                            __hash_cached::value>& __n) const
1405       {
1406         static_assert(__is_invocable<const _Equal&, const _Key&, const _Key&>{},
1407           "key equality predicate must be invocable with two arguments of "
1408           "key type");
1409         return _M_eq()(__k, _ExtractKey{}(__n._M_v()));
1410       }
1411
1412       template<typename _Kt>
1413         bool
1414         _M_key_equals_tr(const _Kt& __k,
1415                          const _Hash_node_value<_Value,
1416                                              __hash_cached::value>& __n) const
1417         {
1418           static_assert(
1419             __is_invocable<const _Equal&, const _Kt&, const _Key&>{},
1420             "key equality predicate must be invocable with the argument type "
1421             "and the key type");
1422           return _M_eq()(__k, _ExtractKey{}(__n._M_v()));
1423         }
1424
1425 #pragma GCC diagnostic push
1426 #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr
1427       bool
1428       _M_equals(const _Key& __k, __hash_code __c,
1429                 const _Hash_node_value<_Value, __hash_cached::value>& __n) const
1430       {
1431         if constexpr (__hash_cached::value)
1432           if (__c != __n._M_hash_code)
1433             return false;
1434
1435         return _M_key_equals(__k, __n);
1436       }
1437
1438       template<typename _Kt>
1439         bool
1440         _M_equals_tr(const _Kt& __k, __hash_code __c,
1441                      const _Hash_node_value<_Value,
1442                                             __hash_cached::value>& __n) const
1443         {
1444           if constexpr (__hash_cached::value)
1445             if (__c != __n._M_hash_code)
1446               return false;
1447
1448           return _M_key_equals_tr(__k, __n);
1449         }
1450
1451       bool
1452       _M_node_equals(
1453         const _Hash_node_value<_Value, __hash_cached::value>& __lhn,
1454         const _Hash_node_value<_Value, __hash_cached::value>& __rhn) const
1455       {
1456         if constexpr (__hash_cached::value)
1457           if (__lhn._M_hash_code != __rhn._M_hash_code)
1458             return false;
1459
1460         return _M_key_equals(_ExtractKey{}(__lhn._M_v()), __rhn);
1461       }
1462 #pragma GCC diagnostic pop
1463
1464       const _Equal&
1465       _M_eq() const noexcept { return _M_equal._M_obj; }
1466     };
1467
1468   /**
1469    * This type deals with all allocation and keeps an allocator instance.
1470    */
1471   template<typename _NodeAlloc>
1472     struct _Hashtable_alloc
1473     {
1474     private:
1475       [[__no_unique_address__]] _Hashtable_ebo_helper<_NodeAlloc> _M_alloc{};
1476
1477       template<typename>
1478         struct __get_value_type;
1479       template<typename _Val, bool _Cache_hash_code>
1480         struct __get_value_type<_Hash_node<_Val, _Cache_hash_code>>
1481         { using type = _Val; };
1482
1483     public:
1484       using __node_type = typename _NodeAlloc::value_type;
1485       using __node_alloc_type = _NodeAlloc;
1486       // Use __gnu_cxx to benefit from _S_always_equal and al.
1487       using __node_alloc_traits = __gnu_cxx::__alloc_traits<__node_alloc_type>;
1488
1489       using __value_alloc_traits = typename __node_alloc_traits::template
1490         rebind_traits<typename __get_value_type<__node_type>::type>;
1491
1492       using __node_ptr = __node_type*;
1493       using __node_base = _Hash_node_base;
1494       using __node_base_ptr = __node_base*;
1495       using __buckets_alloc_type =
1496         __alloc_rebind<__node_alloc_type, __node_base_ptr>;
1497       using __buckets_alloc_traits = std::allocator_traits<__buckets_alloc_type>;
1498       using __buckets_ptr = __node_base_ptr*;
1499
1500       _Hashtable_alloc() = default;
1501       _Hashtable_alloc(const _Hashtable_alloc&) = default;
1502       _Hashtable_alloc(_Hashtable_alloc&&) = default;
1503
1504       template<typename _Alloc>
1505         _Hashtable_alloc(_Alloc&& __a)
1506         : _M_alloc{std::forward<_Alloc>(__a)}
1507         { }
1508
1509       __node_alloc_type&
1510       _M_node_allocator()
1511       { return _M_alloc._M_obj; }
1512
1513       const __node_alloc_type&
1514       _M_node_allocator() const
1515       { return _M_alloc._M_obj; }
1516
1517       // Allocate a node and construct an element within it.
1518       template<typename... _Args>
1519         __node_ptr
1520         _M_allocate_node(_Args&&... __args);
1521
1522       // Destroy the element within a node and deallocate the node.
1523       void
1524       _M_deallocate_node(__node_ptr __n);
1525
1526       // Deallocate a node.
1527       void
1528       _M_deallocate_node_ptr(__node_ptr __n);
1529
1530       // Deallocate the linked list of nodes pointed to by __n.
1531       // The elements within the nodes are destroyed.
1532       void
1533       _M_deallocate_nodes(__node_ptr __n);
1534
1535       __buckets_ptr
1536       _M_allocate_buckets(size_t __bkt_count);
1537
1538       void
1539       _M_deallocate_buckets(__buckets_ptr, size_t __bkt_count);
1540     };
1541
1542   // Definitions of class template _Hashtable_alloc's out-of-line member
1543   // functions.
1544   template<typename _NodeAlloc>
1545     template<typename... _Args>
1546       auto
1547       _Hashtable_alloc<_NodeAlloc>::_M_allocate_node(_Args&&... __args)
1548       -> __node_ptr
1549       {
1550         auto& __alloc = _M_node_allocator();
1551         auto __nptr = __node_alloc_traits::allocate(__alloc, 1);
1552         __node_ptr __n = std::__to_address(__nptr);
1553         __try
1554           {
1555             ::new ((void*)__n) __node_type;
1556             __node_alloc_traits::construct(__alloc, __n->_M_valptr(),
1557                                            std::forward<_Args>(__args)...);
1558             return __n;
1559           }
1560         __catch(...)
1561           {
1562             __n->~__node_type();
1563             __node_alloc_traits::deallocate(__alloc, __nptr, 1);
1564             __throw_exception_again;
1565           }
1566       }
1567
1568   template<typename _NodeAlloc>
1569     void
1570     _Hashtable_alloc<_NodeAlloc>::_M_deallocate_node(__node_ptr __n)
1571     {
1572       __node_alloc_traits::destroy(_M_node_allocator(), __n->_M_valptr());
1573       _M_deallocate_node_ptr(__n);
1574     }
1575
1576   template<typename _NodeAlloc>
1577     void
1578     _Hashtable_alloc<_NodeAlloc>::_M_deallocate_node_ptr(__node_ptr __n)
1579     {
1580       using _Ptr = typename __node_alloc_traits::pointer;
1581       auto __ptr = std::pointer_traits<_Ptr>::pointer_to(*__n);
1582       __n->~__node_type();
1583       __node_alloc_traits::deallocate(_M_node_allocator(), __ptr, 1);
1584     }
1585
1586   template<typename _NodeAlloc>
1587     void
1588     _Hashtable_alloc<_NodeAlloc>::_M_deallocate_nodes(__node_ptr __n)
1589     {
1590       while (__n)
1591         {
1592           __node_ptr __tmp = __n;
1593           __n = __n->_M_next();
1594           _M_deallocate_node(__tmp);
1595         }
1596     }
1597
1598   template<typename _NodeAlloc>
1599     auto
1600     _Hashtable_alloc<_NodeAlloc>::_M_allocate_buckets(size_t __bkt_count)
1601     -> __buckets_ptr
1602     {
1603       __buckets_alloc_type __alloc(_M_node_allocator());
1604
1605       auto __ptr = __buckets_alloc_traits::allocate(__alloc, __bkt_count);
1606       __buckets_ptr __p = std::__to_address(__ptr);
1607       __builtin_memset(__p, 0, __bkt_count * sizeof(__node_base_ptr));
1608       return __p;
1609     }
1610
1611   template<typename _NodeAlloc>
1612     void
1613     _Hashtable_alloc<_NodeAlloc>::
1614     _M_deallocate_buckets(__buckets_ptr __bkts, size_t __bkt_count)
1615     {
1616       using _Ptr = typename __buckets_alloc_traits::pointer;
1617       auto __ptr = std::pointer_traits<_Ptr>::pointer_to(*__bkts);
1618       __buckets_alloc_type __alloc(_M_node_allocator());
1619       __buckets_alloc_traits::deallocate(__alloc, __ptr, __bkt_count);
1620     }
1621
1622  ///@} hashtable-detail
1623 } // namespace __detail
1624 /// @endcond
1625 _GLIBCXX_END_NAMESPACE_VERSION
1626 } // namespace std
1627
1628 #endif // _HASHTABLE_POLICY_H
This page took 0.111513 seconds and 5 git commands to generate.