29
29
#include < __memory/unique_ptr.h>
30
30
#include < __new/launder.h>
31
31
#include < __type_traits/can_extract_key.h>
32
+ #include < __type_traits/copy_cvref.h>
32
33
#include < __type_traits/enable_if.h>
33
34
#include < __type_traits/invoke.h>
34
35
#include < __type_traits/is_const.h>
@@ -108,9 +109,22 @@ struct __hash_node_base {
108
109
_LIBCPP_HIDE_FROM_ABI explicit __hash_node_base (__next_pointer __next) _NOEXCEPT : __next_(__next) {}
109
110
};
110
111
112
+ template <class _Tp >
113
+ struct __get_hash_node_value_type {
114
+ using type _LIBCPP_NODEBUG = _Tp;
115
+ };
116
+
117
+ template <class _Key , class _Tp >
118
+ struct __get_hash_node_value_type <__hash_value_type<_Key, _Tp> > {
119
+ using type _LIBCPP_NODEBUG = pair<const _Key, _Tp>;
120
+ };
121
+
122
+ template <class _Tp >
123
+ using __get_hash_node_value_type_t _LIBCPP_NODEBUG = typename __get_hash_node_value_type<_Tp>::type;
124
+
111
125
template <class _Tp , class _VoidPtr >
112
126
struct __hash_node : public __hash_node_base < __rebind_pointer_t <_VoidPtr, __hash_node<_Tp, _VoidPtr> > > {
113
- typedef _Tp __node_value_type;
127
+ using __node_value_type _LIBCPP_NODEBUG = __get_hash_node_value_type_t <_Tp> ;
114
128
using _Base _LIBCPP_NODEBUG = __hash_node_base<__rebind_pointer_t <_VoidPtr, __hash_node<_Tp, _VoidPtr> > >;
115
129
using __next_pointer _LIBCPP_NODEBUG = typename _Base::__next_pointer;
116
130
@@ -122,18 +136,20 @@ struct __hash_node : public __hash_node_base< __rebind_pointer_t<_VoidPtr, __has
122
136
123
137
private:
124
138
union {
125
- _Tp __value_;
139
+ __node_value_type __value_;
126
140
};
127
141
128
142
public:
129
- _LIBCPP_HIDE_FROM_ABI _Tp & __get_value () { return __value_; }
143
+ _LIBCPP_HIDE_FROM_ABI __node_value_type & __get_value () { return __value_; }
130
144
#else
131
145
132
146
private:
133
- _ALIGNAS_TYPE (_Tp ) char __buffer_[sizeof(_Tp )];
147
+ _ALIGNAS_TYPE (__node_value_type ) char __buffer_[sizeof(__node_value_type )];
134
148
135
149
public:
136
- _LIBCPP_HIDE_FROM_ABI _Tp& __get_value () { return *std::__launder (reinterpret_cast <_Tp*>(&__buffer_)); }
150
+ _LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value () {
151
+ return *std::__launder (reinterpret_cast <__node_value_type*>(&__buffer_));
152
+ }
137
153
#endif
138
154
139
155
_LIBCPP_HIDE_FROM_ABI explicit __hash_node (__next_pointer __next, size_t __hash) : _Base(__next), __hash_(__hash) {}
@@ -201,8 +217,8 @@ struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > {
201
217
return __t ;
202
218
}
203
219
204
- _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr (__node_value_type & __n) {
205
- return std::addressof (__n. __get_value () );
220
+ _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr (__container_value_type & __n) {
221
+ return std::addressof (__n);
206
222
}
207
223
_LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move (__node_value_type& __v) { return __v.__move (); }
208
224
};
@@ -242,7 +258,7 @@ public:
242
258
243
259
typedef typename __node_base_type::__next_pointer __next_pointer;
244
260
245
- typedef _Tp __node_value_type;
261
+ using __node_value_type _LIBCPP_NODEBUG = __get_hash_node_value_type_t <_Tp> ;
246
262
typedef __rebind_pointer_t <_VoidPtr, __node_value_type> __node_value_type_pointer;
247
263
typedef __rebind_pointer_t <_VoidPtr, const __node_value_type> __const_node_value_type_pointer;
248
264
@@ -667,14 +683,14 @@ int __diagnose_unordered_container_requirements(void*);
667
683
template <class _Tp , class _Hash , class _Equal , class _Alloc >
668
684
class __hash_table {
669
685
public:
670
- typedef _Tp value_type;
686
+ using value_type = __get_hash_node_value_type_t <_Tp> ;
671
687
typedef _Hash hasher;
672
688
typedef _Equal key_equal;
673
689
typedef _Alloc allocator_type;
674
690
675
691
private:
676
692
typedef allocator_traits<allocator_type> __alloc_traits;
677
- typedef typename __make_hash_node_types<value_type , typename __alloc_traits::void_pointer>::type _NodeTypes;
693
+ typedef typename __make_hash_node_types<_Tp , typename __alloc_traits::void_pointer>::type _NodeTypes;
678
694
679
695
public:
680
696
typedef typename _NodeTypes::__node_value_type __node_value_type;
@@ -855,6 +871,22 @@ public:
855
871
return __emplace_hint_multi (__p, std::forward<_Pp>(__x));
856
872
}
857
873
874
+ template <class _ValueT = _Tp, __enable_if_t <__is_hash_value_type<_ValueT>::value, int > = 0 >
875
+ _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node (value_type&& __value) {
876
+ using __key_type = typename _NodeTypes::key_type;
877
+
878
+ __node_holder __h = __construct_node (const_cast <__key_type&&>(__value.first ), std::move (__value.second ));
879
+ __node_insert_multi (__h.get ());
880
+ __h.release ();
881
+ }
882
+
883
+ template <class _ValueT = _Tp, __enable_if_t <!__is_hash_value_type<_ValueT>::value, int > = 0 >
884
+ _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node (value_type&& __value) {
885
+ __node_holder __h = __construct_node (std::move (__value));
886
+ __node_insert_multi (__h.get ());
887
+ __h.release ();
888
+ }
889
+
858
890
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool > __insert_unique (const __container_value_type& __x) {
859
891
return __emplace_unique_key_args (_NodeTypes::__get_key (__x), __x);
860
892
}
@@ -1020,6 +1052,21 @@ private:
1020
1052
_LIBCPP_HIDE_FROM_ABI void __deallocate_node (__next_pointer __np) _NOEXCEPT;
1021
1053
_LIBCPP_HIDE_FROM_ABI __next_pointer __detach () _NOEXCEPT;
1022
1054
1055
+ template <class _From , class _ValueT = _Tp, __enable_if_t <__is_hash_value_type<_ValueT>::value, int > = 0 >
1056
+ _LIBCPP_HIDE_FROM_ABI void __assign_value (__get_hash_node_value_type_t <_Tp>& __lhs, _From&& __rhs) {
1057
+ using __key_type = typename _NodeTypes::key_type;
1058
+
1059
+ // This is technically UB, since the object was constructed as `const`.
1060
+ // Clang doesn't optimize on this currently though.
1061
+ const_cast <__key_type&>(__lhs.first ) = const_cast <__copy_cvref_t <_From, __key_type>&&>(__rhs.first );
1062
+ __lhs.second = std::forward<_From>(__rhs).second ;
1063
+ }
1064
+
1065
+ template <class _From , class _ValueT = _Tp, __enable_if_t <!__is_hash_value_type<_ValueT>::value, int > = 0 >
1066
+ _LIBCPP_HIDE_FROM_ABI void __assign_value (_Tp& __lhs, _From&& __rhs) {
1067
+ __lhs = std::forward<_From>(__rhs);
1068
+ }
1069
+
1023
1070
template <class , class , class , class , class >
1024
1071
friend class unordered_map ;
1025
1072
template <class , class , class , class , class >
@@ -1216,8 +1263,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
1216
1263
#endif // _LIBCPP_HAS_EXCEPTIONS
1217
1264
const_iterator __i = __u.begin ();
1218
1265
while (__cache != nullptr && __u.size () != 0 ) {
1219
- __cache->__upcast ()->__get_value () = std::move (__u.remove (__i++)->__get_value ());
1220
- __next_pointer __next = __cache->__next_ ;
1266
+ __assign_value ( __cache->__upcast ()->__get_value (), std::move (__u.remove (__i++)->__get_value () ));
1267
+ __next_pointer __next = __cache->__next_ ;
1221
1268
__node_insert_multi (__cache->__upcast ());
1222
1269
__cache = __next;
1223
1270
}
@@ -1230,11 +1277,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
1230
1277
__deallocate_node (__cache);
1231
1278
}
1232
1279
const_iterator __i = __u.begin ();
1233
- while (__u.size () != 0 ) {
1234
- __node_holder __h = __construct_node (_NodeTypes::__move (__u.remove (__i++)->__get_value ()));
1235
- __node_insert_multi (__h.get ());
1236
- __h.release ();
1237
- }
1280
+ while (__u.size () != 0 )
1281
+ __insert_multi_from_orphaned_node (std::move (__u.remove (__i++)->__get_value ()));
1238
1282
}
1239
1283
}
1240
1284
@@ -1262,8 +1306,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __
1262
1306
try {
1263
1307
#endif // _LIBCPP_HAS_EXCEPTIONS
1264
1308
for (; __cache != nullptr && __first != __last; ++__first) {
1265
- __cache->__upcast ()->__get_value () = *__first;
1266
- __next_pointer __next = __cache->__next_ ;
1309
+ __assign_value ( __cache->__upcast ()->__get_value (), *__first) ;
1310
+ __next_pointer __next = __cache->__next_ ;
1267
1311
__node_insert_unique (__cache->__upcast ());
1268
1312
__cache = __next;
1269
1313
}
@@ -1294,7 +1338,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __f
1294
1338
try {
1295
1339
#endif // _LIBCPP_HAS_EXCEPTIONS
1296
1340
for (; __cache != nullptr && __first != __last; ++__first) {
1297
- __cache->__upcast ()->__get_value () = *__first;
1341
+ __assign_value ( __cache->__upcast ()->__get_value (), *__first) ;
1298
1342
__next_pointer __next = __cache->__next_ ;
1299
1343
__node_insert_multi (__cache->__upcast ());
1300
1344
__cache = __next;
0 commit comments