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;
@@ -845,6 +861,22 @@ public:
845
861
return __emplace_unique (std::forward<_Pp>(__x));
846
862
}
847
863
864
+ template <class _ValueT = _Tp, __enable_if_t <__is_hash_value_type<_ValueT>::value, int > = 0 >
865
+ _LIBCPP_HIDE_FROM_ABI void __insert_unique_from_orphaned_node (value_type&& __value) {
866
+ using __key_type = typename _NodeTypes::key_type;
867
+
868
+ __node_holder __h = __construct_node (const_cast <__key_type&&>(__value.first ), std::move (__value.second ));
869
+ __node_insert_unique (__h.get ());
870
+ __h.release ();
871
+ }
872
+
873
+ template <class _ValueT = _Tp, __enable_if_t <!__is_hash_value_type<_ValueT>::value, int > = 0 >
874
+ _LIBCPP_HIDE_FROM_ABI void __insert_unique_from_orphaned_node (value_type&& __value) {
875
+ __node_holder __h = __construct_node (std::move (__value));
876
+ __node_insert_unique (__h.get ());
877
+ __h.release ();
878
+ }
879
+
848
880
template <class _Pp >
849
881
_LIBCPP_HIDE_FROM_ABI iterator __insert_multi (_Pp&& __x) {
850
882
return __emplace_multi (std::forward<_Pp>(__x));
@@ -855,6 +887,22 @@ public:
855
887
return __emplace_hint_multi (__p, std::forward<_Pp>(__x));
856
888
}
857
889
890
+ template <class _ValueT = _Tp, __enable_if_t <__is_hash_value_type<_ValueT>::value, int > = 0 >
891
+ _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node (value_type&& __value) {
892
+ using __key_type = typename _NodeTypes::key_type;
893
+
894
+ __node_holder __h = __construct_node (const_cast <__key_type&&>(__value.first ), std::move (__value.second ));
895
+ __node_insert_multi (__h.get ());
896
+ __h.release ();
897
+ }
898
+
899
+ template <class _ValueT = _Tp, __enable_if_t <!__is_hash_value_type<_ValueT>::value, int > = 0 >
900
+ _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node (value_type&& __value) {
901
+ __node_holder __h = __construct_node (std::move (__value));
902
+ __node_insert_multi (__h.get ());
903
+ __h.release ();
904
+ }
905
+
858
906
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool > __insert_unique (const __container_value_type& __x) {
859
907
return __emplace_unique_key_args (_NodeTypes::__get_key (__x), __x);
860
908
}
@@ -1020,6 +1068,21 @@ private:
1020
1068
_LIBCPP_HIDE_FROM_ABI void __deallocate_node (__next_pointer __np) _NOEXCEPT;
1021
1069
_LIBCPP_HIDE_FROM_ABI __next_pointer __detach () _NOEXCEPT;
1022
1070
1071
+ template <class _From , class _ValueT = _Tp, __enable_if_t <__is_hash_value_type<_ValueT>::value, int > = 0 >
1072
+ _LIBCPP_HIDE_FROM_ABI void __assign_value (__get_hash_node_value_type_t <_Tp>& __lhs, _From&& __rhs) {
1073
+ using __key_type = typename _NodeTypes::key_type;
1074
+
1075
+ // This is technically UB, since the object was constructed as `const`.
1076
+ // Clang doesn't optimize on this currently though.
1077
+ const_cast <__key_type&>(__lhs.first ) = const_cast <__copy_cvref_t <_From, __key_type>&&>(__rhs.first );
1078
+ __lhs.second = std::forward<_From>(__rhs).second ;
1079
+ }
1080
+
1081
+ template <class _From , class _ValueT = _Tp, __enable_if_t <!__is_hash_value_type<_ValueT>::value, int > = 0 >
1082
+ _LIBCPP_HIDE_FROM_ABI void __assign_value (_Tp& __lhs, _From&& __rhs) {
1083
+ __lhs = std::forward<_From>(__rhs);
1084
+ }
1085
+
1023
1086
template <class , class , class , class , class >
1024
1087
friend class unordered_map ;
1025
1088
template <class , class , class , class , class >
@@ -1216,8 +1279,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
1216
1279
#endif // _LIBCPP_HAS_EXCEPTIONS
1217
1280
const_iterator __i = __u.begin ();
1218
1281
while (__cache != nullptr && __u.size () != 0 ) {
1219
- __cache->__upcast ()->__get_value () = std::move (__u.remove (__i++)->__get_value ());
1220
- __next_pointer __next = __cache->__next_ ;
1282
+ __assign_value ( __cache->__upcast ()->__get_value (), std::move (__u.remove (__i++)->__get_value () ));
1283
+ __next_pointer __next = __cache->__next_ ;
1221
1284
__node_insert_multi (__cache->__upcast ());
1222
1285
__cache = __next;
1223
1286
}
@@ -1230,11 +1293,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
1230
1293
__deallocate_node (__cache);
1231
1294
}
1232
1295
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
- }
1296
+ while (__u.size () != 0 )
1297
+ __insert_multi_from_orphaned_node (std::move (__u.remove (__i++)->__get_value ()));
1238
1298
}
1239
1299
}
1240
1300
@@ -1262,8 +1322,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __
1262
1322
try {
1263
1323
#endif // _LIBCPP_HAS_EXCEPTIONS
1264
1324
for (; __cache != nullptr && __first != __last; ++__first) {
1265
- __cache->__upcast ()->__get_value () = *__first;
1266
- __next_pointer __next = __cache->__next_ ;
1325
+ __assign_value ( __cache->__upcast ()->__get_value (), *__first) ;
1326
+ __next_pointer __next = __cache->__next_ ;
1267
1327
__node_insert_unique (__cache->__upcast ());
1268
1328
__cache = __next;
1269
1329
}
@@ -1294,7 +1354,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __f
1294
1354
try {
1295
1355
#endif // _LIBCPP_HAS_EXCEPTIONS
1296
1356
for (; __cache != nullptr && __first != __last; ++__first) {
1297
- __cache->__upcast ()->__get_value () = *__first;
1357
+ __assign_value ( __cache->__upcast ()->__get_value (), *__first) ;
1298
1358
__next_pointer __next = __cache->__next_ ;
1299
1359
__node_insert_multi (__cache->__upcast ());
1300
1360
__cache = __next;
0 commit comments