2121#include < __memory/addressof.h>
2222#include < __memory/allocator_traits.h>
2323#include < __memory/compressed_pair.h>
24+ #include < __memory/construct_at.h>
2425#include < __memory/pointer_traits.h>
2526#include < __memory/swap_allocator.h>
2627#include < __memory/unique_ptr.h>
4546#include < cmath>
4647#include < cstring>
4748#include < initializer_list>
49+ #include < new> // __launder
4850
4951#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
5052# pragma GCC system_header
@@ -107,19 +109,44 @@ struct __hash_node_base
107109 }
108110
109111 _LIBCPP_INLINE_VISIBILITY __hash_node_base () _NOEXCEPT : __next_(nullptr ) {}
112+ _LIBCPP_HIDE_FROM_ABI explicit __hash_node_base (__next_pointer __next) _NOEXCEPT : __next_(__next) {}
110113};
111114
112115template <class _Tp , class _VoidPtr >
113- struct _LIBCPP_STANDALONE_DEBUG __hash_node
116+ struct __hash_node
114117 : public __hash_node_base
115118 <
116119 __rebind_pointer_t <_VoidPtr, __hash_node<_Tp, _VoidPtr> >
117120 >
118121{
119122 typedef _Tp __node_value_type;
123+ using _Base = __hash_node_base<__rebind_pointer_t <_VoidPtr, __hash_node<_Tp, _VoidPtr> > >;
124+ using __next_pointer = typename _Base::__next_pointer;
120125
121126 size_t __hash_;
122- __node_value_type __value_;
127+
128+ // We allow starting the lifetime of nodes without initializing the value held by the node,
129+ // since that is handled by the hash table itself in order to be allocator-aware.
130+ #ifndef _LIBCPP_CXX03_LANG
131+ private:
132+ union {
133+ _Tp __value_;
134+ };
135+
136+ public:
137+ _LIBCPP_HIDE_FROM_ABI _Tp& __get_value () { return __value_; }
138+ #else
139+ private:
140+ _ALIGNAS_TYPE (_Tp) char __buffer_[sizeof(_Tp)];
141+
142+ public:
143+ _LIBCPP_HIDE_FROM_ABI _Tp& __get_value () {
144+ return *std::__launder (reinterpret_cast <_Tp*>(&__buffer_));
145+ }
146+ #endif
147+
148+ _LIBCPP_HIDE_FROM_ABI explicit __hash_node (__next_pointer __next, size_t __hash) : _Base(__next), __hash_(__hash) {}
149+ _LIBCPP_HIDE_FROM_ABI ~__hash_node () {}
123150};
124151
125152inline _LIBCPP_INLINE_VISIBILITY
@@ -311,12 +338,12 @@ public:
311338
312339 _LIBCPP_INLINE_VISIBILITY
313340 reference operator *() const {
314- return __node_->__upcast ()->__value_ ;
341+ return __node_->__upcast ()->__get_value () ;
315342 }
316343
317344 _LIBCPP_INLINE_VISIBILITY
318345 pointer operator ->() const {
319- return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__value_ );
346+ return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__get_value () );
320347 }
321348
322349 _LIBCPP_INLINE_VISIBILITY
@@ -387,11 +414,11 @@ public:
387414
388415 _LIBCPP_INLINE_VISIBILITY
389416 reference operator *() const {
390- return __node_->__upcast ()->__value_ ;
417+ return __node_->__upcast ()->__get_value () ;
391418 }
392419 _LIBCPP_INLINE_VISIBILITY
393420 pointer operator ->() const {
394- return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__value_ );
421+ return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__get_value () );
395422 }
396423
397424 _LIBCPP_INLINE_VISIBILITY
@@ -453,12 +480,12 @@ public:
453480
454481 _LIBCPP_INLINE_VISIBILITY
455482 reference operator *() const {
456- return __node_->__upcast ()->__value_ ;
483+ return __node_->__upcast ()->__get_value () ;
457484 }
458485
459486 _LIBCPP_INLINE_VISIBILITY
460487 pointer operator ->() const {
461- return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__value_ );
488+ return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__get_value () );
462489 }
463490
464491 _LIBCPP_INLINE_VISIBILITY
@@ -543,12 +570,12 @@ public:
543570
544571 _LIBCPP_INLINE_VISIBILITY
545572 reference operator *() const {
546- return __node_->__upcast ()->__value_ ;
573+ return __node_->__upcast ()->__get_value () ;
547574 }
548575
549576 _LIBCPP_INLINE_VISIBILITY
550577 pointer operator ->() const {
551- return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__value_ );
578+ return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__get_value () );
552579 }
553580
554581 _LIBCPP_INLINE_VISIBILITY
@@ -670,8 +697,10 @@ public:
670697 _LIBCPP_INLINE_VISIBILITY
671698 void operator ()(pointer __p) _NOEXCEPT
672699 {
673- if (__value_constructed)
674- __alloc_traits::destroy (__na_, _NodeTypes::__get_ptr (__p->__value_ ));
700+ if (__value_constructed) {
701+ __alloc_traits::destroy (__na_, _NodeTypes::__get_ptr (__p->__get_value ()));
702+ std::__destroy_at (std::addressof (*__p));
703+ }
675704 if (__p)
676705 __alloc_traits::deallocate (__na_, __p, 1 );
677706 }
@@ -1365,7 +1394,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__deallocate_node(__next_pointer __np)
13651394 {
13661395 __next_pointer __next = __np->__next_ ;
13671396 __node_pointer __real_np = __np->__upcast ();
1368- __node_traits::destroy (__na, _NodeTypes::__get_ptr (__real_np->__value_ ));
1397+ __node_traits::destroy (__na, _NodeTypes::__get_ptr (__real_np->__get_value ()));
1398+ std::__destroy_at (std::addressof (*__real_np));
13691399 __node_traits::deallocate (__na, __real_np, 1 );
13701400 __np = __next;
13711401 }
@@ -1434,8 +1464,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(
14341464 const_iterator __i = __u.begin ();
14351465 while (__cache != nullptr && __u.size () != 0 )
14361466 {
1437- __cache->__upcast ()->__value_ =
1438- _VSTD::move (__u.remove (__i++)->__value_ );
1467+ __cache->__upcast ()->__get_value () =
1468+ _VSTD::move (__u.remove (__i++)->__get_value () );
14391469 __next_pointer __next = __cache->__next_ ;
14401470 __node_insert_multi (__cache->__upcast ());
14411471 __cache = __next;
@@ -1453,7 +1483,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(
14531483 const_iterator __i = __u.begin ();
14541484 while (__u.size () != 0 )
14551485 {
1456- __node_holder __h = __construct_node (_NodeTypes::__move (__u.remove (__i++)->__value_ ));
1486+ __node_holder __h = __construct_node (_NodeTypes::__move (__u.remove (__i++)->__get_value () ));
14571487 __node_insert_multi (__h.get ());
14581488 __h.release ();
14591489 }
@@ -1495,7 +1525,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __first
14951525#endif // _LIBCPP_HAS_NO_EXCEPTIONS
14961526 for (; __cache != nullptr && __first != __last; ++__first)
14971527 {
1498- __cache->__upcast ()->__value_ = *__first;
1528+ __cache->__upcast ()->__get_value () = *__first;
14991529 __next_pointer __next = __cache->__next_ ;
15001530 __node_insert_unique (__cache->__upcast ());
15011531 __cache = __next;
@@ -1535,7 +1565,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __first,
15351565#endif // _LIBCPP_HAS_NO_EXCEPTIONS
15361566 for (; __cache != nullptr && __first != __last; ++__first)
15371567 {
1538- __cache->__upcast ()->__value_ = *__first;
1568+ __cache->__upcast ()->__get_value () = *__first;
15391569 __next_pointer __next = __cache->__next_ ;
15401570 __node_insert_multi (__cache->__upcast ());
15411571 __cache = __next;
@@ -1629,7 +1659,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique_prepare(
16291659 __ndptr = __ndptr->__next_ )
16301660 {
16311661 if ((__ndptr->__hash () == __hash) &&
1632- key_eq ()(__ndptr->__upcast ()->__value_ , __value))
1662+ key_eq ()(__ndptr->__upcast ()->__get_value () , __value))
16331663 return __ndptr;
16341664 }
16351665 }
@@ -1678,9 +1708,9 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
16781708pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool >
16791709__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique (__node_pointer __nd)
16801710{
1681- __nd->__hash_ = hash_function ()(__nd->__value_ );
1711+ __nd->__hash_ = hash_function ()(__nd->__get_value () );
16821712 __next_pointer __existing_node =
1683- __node_insert_unique_prepare (__nd->__hash (), __nd->__value_ );
1713+ __node_insert_unique_prepare (__nd->__hash (), __nd->__get_value () );
16841714
16851715 // Insert the node, unless it already exists in the container.
16861716 bool __inserted = false ;
@@ -1726,7 +1756,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi_prepare(
17261756 // false true set __found to true
17271757 // true false break
17281758 if (__found != (__pn->__next_ ->__hash () == __cp_hash &&
1729- key_eq ()(__pn->__next_ ->__upcast ()->__value_ , __cp_val)))
1759+ key_eq ()(__pn->__next_ ->__upcast ()->__get_value () , __cp_val)))
17301760 {
17311761 if (!__found)
17321762 __found = true ;
@@ -1780,8 +1810,8 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
17801810typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
17811811__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi (__node_pointer __cp)
17821812{
1783- __cp->__hash_ = hash_function ()(__cp->__value_ );
1784- __next_pointer __pn = __node_insert_multi_prepare (__cp->__hash (), __cp->__value_ );
1813+ __cp->__hash_ = hash_function ()(__cp->__get_value () );
1814+ __next_pointer __pn = __node_insert_multi_prepare (__cp->__hash (), __cp->__get_value () );
17851815 __node_insert_multi_perform (__cp, __pn);
17861816
17871817 return iterator (__cp->__ptr ());
@@ -1792,7 +1822,7 @@ typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
17921822__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi (
17931823 const_iterator __p, __node_pointer __cp)
17941824{
1795- if (__p != end () && key_eq ()(*__p, __cp->__value_ ))
1825+ if (__p != end () && key_eq ()(*__p, __cp->__get_value () ))
17961826 {
17971827 __next_pointer __np = __p.__node_ ;
17981828 __cp->__hash_ = __np->__hash ();
@@ -1839,7 +1869,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_key_args(_Key const&
18391869 __nd = __nd->__next_ )
18401870 {
18411871 if ((__nd->__hash () == __hash) &&
1842- key_eq ()(__nd->__upcast ()->__value_ , __k))
1872+ key_eq ()(__nd->__upcast ()->__get_value () , __k))
18431873 goto __done;
18441874 }
18451875 }
@@ -1983,9 +2013,9 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_merge_unique(
19832013 __it != __source.end ();)
19842014 {
19852015 __node_pointer __src_ptr = __it.__node_ ->__upcast ();
1986- size_t __hash = hash_function ()(__src_ptr->__value_ );
2016+ size_t __hash = hash_function ()(__src_ptr->__get_value () );
19872017 __next_pointer __existing_node =
1988- __node_insert_unique_prepare (__hash, __src_ptr->__value_ );
2018+ __node_insert_unique_prepare (__hash, __src_ptr->__get_value () );
19892019 auto __prev_iter = __it++;
19902020 if (__existing_node == nullptr )
19912021 {
@@ -2037,9 +2067,9 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_merge_multi(
20372067 __it != __source.end ();)
20382068 {
20392069 __node_pointer __src_ptr = __it.__node_ ->__upcast ();
2040- size_t __src_hash = hash_function ()(__src_ptr->__value_ );
2070+ size_t __src_hash = hash_function ()(__src_ptr->__get_value () );
20412071 __next_pointer __pn =
2042- __node_insert_multi_prepare (__src_hash, __src_ptr->__value_ );
2072+ __node_insert_multi_prepare (__src_hash, __src_ptr->__get_value () );
20432073 (void )__source.remove (__it++).release ();
20442074 __src_ptr->__hash_ = __src_hash;
20452075 __node_insert_multi_perform (__src_ptr, __pn);
@@ -2113,8 +2143,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __nbc)
21132143 if _LIBCPP_CONSTEXPR_SINCE_CXX17 (!_UniqueKeys)
21142144 {
21152145 for (; __np->__next_ != nullptr &&
2116- key_eq ()(__cp->__upcast ()->__value_ ,
2117- __np->__next_ ->__upcast ()->__value_ );
2146+ key_eq ()(__cp->__upcast ()->__get_value () ,
2147+ __np->__next_ ->__upcast ()->__get_value () );
21182148 __np = __np->__next_ )
21192149 ;
21202150 }
@@ -2148,7 +2178,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k)
21482178 __nd = __nd->__next_ )
21492179 {
21502180 if ((__nd->__hash () == __hash)
2151- && key_eq ()(__nd->__upcast ()->__value_ , __k))
2181+ && key_eq ()(__nd->__upcast ()->__get_value () , __k))
21522182 return iterator (__nd);
21532183 }
21542184 }
@@ -2175,7 +2205,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) const
21752205 __nd = __nd->__next_ )
21762206 {
21772207 if ((__nd->__hash () == __hash)
2178- && key_eq ()(__nd->__upcast ()->__value_ , __k))
2208+ && key_eq ()(__nd->__upcast ()->__get_value () , __k))
21792209 return const_iterator (__nd);
21802210 }
21812211 }
@@ -2193,10 +2223,20 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&& ...__args)
21932223 " Construct cannot be called with a hash value type" );
21942224 __node_allocator& __na = __node_alloc ();
21952225 __node_holder __h (__node_traits::allocate (__na, 1 ), _Dp (__na));
2196- __node_traits::construct (__na, _NodeTypes::__get_ptr (__h->__value_ ), _VSTD::forward<_Args>(__args)...);
2226+
2227+ // Begin the lifetime of the node itself. Note that this doesn't begin the lifetime of the value
2228+ // held inside the node, since we need to use the allocator's construct() method for that.
2229+ //
2230+ // We don't use the allocator's construct() method to construct the node itself since the
2231+ // Cpp17FooInsertable named requirements don't require the allocator's construct() method
2232+ // to work on anything other than the value_type.
2233+ std::__construct_at (std::addressof (*__h), /* next = */ nullptr , /* hash = */ 0 );
2234+
2235+ // Now construct the value_type using the allocator's construct() method.
2236+ __node_traits::construct (__na, _NodeTypes::__get_ptr (__h->__get_value ()), _VSTD::forward<_Args>(__args)...);
21972237 __h.get_deleter ().__value_constructed = true ;
2198- __h-> __hash_ = hash_function ()(__h-> __value_ );
2199- __h->__next_ = nullptr ;
2238+
2239+ __h->__hash_ = hash_function ()(__h-> __get_value ()) ;
22002240 return __h;
22012241}
22022242
@@ -2210,12 +2250,11 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(
22102250 " Construct cannot be called with a hash value type" );
22112251 __node_allocator& __na = __node_alloc ();
22122252 __node_holder __h (__node_traits::allocate (__na, 1 ), _Dp (__na));
2213- __node_traits::construct (__na, _NodeTypes::__get_ptr (__h->__value_ ),
2253+ std::__construct_at (std::addressof (*__h), /* next = */ nullptr , /* hash = */ __hash);
2254+ __node_traits::construct (__na, _NodeTypes::__get_ptr (__h->__get_value ()),
22142255 _VSTD::forward<_First>(__f),
22152256 _VSTD::forward<_Rest>(__rest)...);
22162257 __h.get_deleter ().__value_constructed = true ;
2217- __h->__hash_ = __hash;
2218- __h->__next_ = nullptr ;
22192258 return __h;
22202259}
22212260
0 commit comments