21
21
#include < __memory/addressof.h>
22
22
#include < __memory/allocator_traits.h>
23
23
#include < __memory/compressed_pair.h>
24
+ #include < __memory/construct_at.h>
24
25
#include < __memory/pointer_traits.h>
25
26
#include < __memory/swap_allocator.h>
26
27
#include < __memory/unique_ptr.h>
45
46
#include < cmath>
46
47
#include < cstring>
47
48
#include < initializer_list>
49
+ #include < new> // __launder
48
50
49
51
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
50
52
# pragma GCC system_header
@@ -107,19 +109,44 @@ struct __hash_node_base
107
109
}
108
110
109
111
_LIBCPP_INLINE_VISIBILITY __hash_node_base () _NOEXCEPT : __next_(nullptr ) {}
112
+ _LIBCPP_HIDE_FROM_ABI explicit __hash_node_base (__next_pointer __next) _NOEXCEPT : __next_(__next) {}
110
113
};
111
114
112
115
template <class _Tp , class _VoidPtr >
113
- struct _LIBCPP_STANDALONE_DEBUG __hash_node
116
+ struct __hash_node
114
117
: public __hash_node_base
115
118
<
116
119
__rebind_pointer_t <_VoidPtr, __hash_node<_Tp, _VoidPtr> >
117
120
>
118
121
{
119
122
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;
120
125
121
126
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 () {}
123
150
};
124
151
125
152
inline _LIBCPP_INLINE_VISIBILITY
@@ -311,12 +338,12 @@ public:
311
338
312
339
_LIBCPP_INLINE_VISIBILITY
313
340
reference operator *() const {
314
- return __node_->__upcast ()->__value_ ;
341
+ return __node_->__upcast ()->__get_value () ;
315
342
}
316
343
317
344
_LIBCPP_INLINE_VISIBILITY
318
345
pointer operator ->() const {
319
- return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__value_ );
346
+ return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__get_value () );
320
347
}
321
348
322
349
_LIBCPP_INLINE_VISIBILITY
@@ -387,11 +414,11 @@ public:
387
414
388
415
_LIBCPP_INLINE_VISIBILITY
389
416
reference operator *() const {
390
- return __node_->__upcast ()->__value_ ;
417
+ return __node_->__upcast ()->__get_value () ;
391
418
}
392
419
_LIBCPP_INLINE_VISIBILITY
393
420
pointer operator ->() const {
394
- return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__value_ );
421
+ return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__get_value () );
395
422
}
396
423
397
424
_LIBCPP_INLINE_VISIBILITY
@@ -453,12 +480,12 @@ public:
453
480
454
481
_LIBCPP_INLINE_VISIBILITY
455
482
reference operator *() const {
456
- return __node_->__upcast ()->__value_ ;
483
+ return __node_->__upcast ()->__get_value () ;
457
484
}
458
485
459
486
_LIBCPP_INLINE_VISIBILITY
460
487
pointer operator ->() const {
461
- return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__value_ );
488
+ return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__get_value () );
462
489
}
463
490
464
491
_LIBCPP_INLINE_VISIBILITY
@@ -543,12 +570,12 @@ public:
543
570
544
571
_LIBCPP_INLINE_VISIBILITY
545
572
reference operator *() const {
546
- return __node_->__upcast ()->__value_ ;
573
+ return __node_->__upcast ()->__get_value () ;
547
574
}
548
575
549
576
_LIBCPP_INLINE_VISIBILITY
550
577
pointer operator ->() const {
551
- return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__value_ );
578
+ return pointer_traits<pointer>::pointer_to (__node_->__upcast ()->__get_value () );
552
579
}
553
580
554
581
_LIBCPP_INLINE_VISIBILITY
@@ -670,8 +697,10 @@ public:
670
697
_LIBCPP_INLINE_VISIBILITY
671
698
void operator ()(pointer __p) _NOEXCEPT
672
699
{
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
+ }
675
704
if (__p)
676
705
__alloc_traits::deallocate (__na_, __p, 1 );
677
706
}
@@ -1365,7 +1394,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__deallocate_node(__next_pointer __np)
1365
1394
{
1366
1395
__next_pointer __next = __np->__next_ ;
1367
1396
__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));
1369
1399
__node_traits::deallocate (__na, __real_np, 1 );
1370
1400
__np = __next;
1371
1401
}
@@ -1434,8 +1464,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(
1434
1464
const_iterator __i = __u.begin ();
1435
1465
while (__cache != nullptr && __u.size () != 0 )
1436
1466
{
1437
- __cache->__upcast ()->__value_ =
1438
- _VSTD::move (__u.remove (__i++)->__value_ );
1467
+ __cache->__upcast ()->__get_value () =
1468
+ _VSTD::move (__u.remove (__i++)->__get_value () );
1439
1469
__next_pointer __next = __cache->__next_ ;
1440
1470
__node_insert_multi (__cache->__upcast ());
1441
1471
__cache = __next;
@@ -1453,7 +1483,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(
1453
1483
const_iterator __i = __u.begin ();
1454
1484
while (__u.size () != 0 )
1455
1485
{
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 () ));
1457
1487
__node_insert_multi (__h.get ());
1458
1488
__h.release ();
1459
1489
}
@@ -1495,7 +1525,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __first
1495
1525
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
1496
1526
for (; __cache != nullptr && __first != __last; ++__first)
1497
1527
{
1498
- __cache->__upcast ()->__value_ = *__first;
1528
+ __cache->__upcast ()->__get_value () = *__first;
1499
1529
__next_pointer __next = __cache->__next_ ;
1500
1530
__node_insert_unique (__cache->__upcast ());
1501
1531
__cache = __next;
@@ -1535,7 +1565,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __first,
1535
1565
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
1536
1566
for (; __cache != nullptr && __first != __last; ++__first)
1537
1567
{
1538
- __cache->__upcast ()->__value_ = *__first;
1568
+ __cache->__upcast ()->__get_value () = *__first;
1539
1569
__next_pointer __next = __cache->__next_ ;
1540
1570
__node_insert_multi (__cache->__upcast ());
1541
1571
__cache = __next;
@@ -1629,7 +1659,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique_prepare(
1629
1659
__ndptr = __ndptr->__next_ )
1630
1660
{
1631
1661
if ((__ndptr->__hash () == __hash) &&
1632
- key_eq ()(__ndptr->__upcast ()->__value_ , __value))
1662
+ key_eq ()(__ndptr->__upcast ()->__get_value () , __value))
1633
1663
return __ndptr;
1634
1664
}
1635
1665
}
@@ -1678,9 +1708,9 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
1678
1708
pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool >
1679
1709
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_unique (__node_pointer __nd)
1680
1710
{
1681
- __nd->__hash_ = hash_function ()(__nd->__value_ );
1711
+ __nd->__hash_ = hash_function ()(__nd->__get_value () );
1682
1712
__next_pointer __existing_node =
1683
- __node_insert_unique_prepare (__nd->__hash (), __nd->__value_ );
1713
+ __node_insert_unique_prepare (__nd->__hash (), __nd->__get_value () );
1684
1714
1685
1715
// Insert the node, unless it already exists in the container.
1686
1716
bool __inserted = false ;
@@ -1726,7 +1756,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi_prepare(
1726
1756
// false true set __found to true
1727
1757
// true false break
1728
1758
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)))
1730
1760
{
1731
1761
if (!__found)
1732
1762
__found = true ;
@@ -1780,8 +1810,8 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc>
1780
1810
typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1781
1811
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi (__node_pointer __cp)
1782
1812
{
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 () );
1785
1815
__node_insert_multi_perform (__cp, __pn);
1786
1816
1787
1817
return iterator (__cp->__ptr ());
@@ -1792,7 +1822,7 @@ typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator
1792
1822
__hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi (
1793
1823
const_iterator __p, __node_pointer __cp)
1794
1824
{
1795
- if (__p != end () && key_eq ()(*__p, __cp->__value_ ))
1825
+ if (__p != end () && key_eq ()(*__p, __cp->__get_value () ))
1796
1826
{
1797
1827
__next_pointer __np = __p.__node_ ;
1798
1828
__cp->__hash_ = __np->__hash ();
@@ -1839,7 +1869,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_key_args(_Key const&
1839
1869
__nd = __nd->__next_ )
1840
1870
{
1841
1871
if ((__nd->__hash () == __hash) &&
1842
- key_eq ()(__nd->__upcast ()->__value_ , __k))
1872
+ key_eq ()(__nd->__upcast ()->__get_value () , __k))
1843
1873
goto __done;
1844
1874
}
1845
1875
}
@@ -1983,9 +2013,9 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_merge_unique(
1983
2013
__it != __source.end ();)
1984
2014
{
1985
2015
__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 () );
1987
2017
__next_pointer __existing_node =
1988
- __node_insert_unique_prepare (__hash, __src_ptr->__value_ );
2018
+ __node_insert_unique_prepare (__hash, __src_ptr->__get_value () );
1989
2019
auto __prev_iter = __it++;
1990
2020
if (__existing_node == nullptr )
1991
2021
{
@@ -2037,9 +2067,9 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_handle_merge_multi(
2037
2067
__it != __source.end ();)
2038
2068
{
2039
2069
__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 () );
2041
2071
__next_pointer __pn =
2042
- __node_insert_multi_prepare (__src_hash, __src_ptr->__value_ );
2072
+ __node_insert_multi_prepare (__src_hash, __src_ptr->__get_value () );
2043
2073
(void )__source.remove (__it++).release ();
2044
2074
__src_ptr->__hash_ = __src_hash;
2045
2075
__node_insert_multi_perform (__src_ptr, __pn);
@@ -2113,8 +2143,8 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __nbc)
2113
2143
if _LIBCPP_CONSTEXPR_SINCE_CXX17 (!_UniqueKeys)
2114
2144
{
2115
2145
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 () );
2118
2148
__np = __np->__next_ )
2119
2149
;
2120
2150
}
@@ -2148,7 +2178,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k)
2148
2178
__nd = __nd->__next_ )
2149
2179
{
2150
2180
if ((__nd->__hash () == __hash)
2151
- && key_eq ()(__nd->__upcast ()->__value_ , __k))
2181
+ && key_eq ()(__nd->__upcast ()->__get_value () , __k))
2152
2182
return iterator (__nd);
2153
2183
}
2154
2184
}
@@ -2175,7 +2205,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::find(const _Key& __k) const
2175
2205
__nd = __nd->__next_ )
2176
2206
{
2177
2207
if ((__nd->__hash () == __hash)
2178
- && key_eq ()(__nd->__upcast ()->__value_ , __k))
2208
+ && key_eq ()(__nd->__upcast ()->__get_value () , __k))
2179
2209
return const_iterator (__nd);
2180
2210
}
2181
2211
}
@@ -2193,10 +2223,20 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&& ...__args)
2193
2223
" Construct cannot be called with a hash value type" );
2194
2224
__node_allocator& __na = __node_alloc ();
2195
2225
__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)...);
2197
2237
__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 ()) ;
2200
2240
return __h;
2201
2241
}
2202
2242
@@ -2210,12 +2250,11 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(
2210
2250
" Construct cannot be called with a hash value type" );
2211
2251
__node_allocator& __na = __node_alloc ();
2212
2252
__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 ()),
2214
2255
_VSTD::forward<_First>(__f),
2215
2256
_VSTD::forward<_Rest>(__rest)...);
2216
2257
__h.get_deleter ().__value_constructed = true ;
2217
- __h->__hash_ = __hash;
2218
- __h->__next_ = nullptr ;
2219
2258
return __h;
2220
2259
}
2221
2260
0 commit comments