2929#include < __memory/unique_ptr.h>
3030#include < __new/launder.h>
3131#include < __type_traits/can_extract_key.h>
32+ #include < __type_traits/copy_cvref.h>
3233#include < __type_traits/enable_if.h>
3334#include < __type_traits/invoke.h>
3435#include < __type_traits/is_const.h>
@@ -108,9 +109,22 @@ struct __hash_node_base {
108109 _LIBCPP_HIDE_FROM_ABI explicit __hash_node_base (__next_pointer __next) _NOEXCEPT : __next_(__next) {}
109110};
110111
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+
111125template <class _Tp , class _VoidPtr >
112126struct __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> ;
114128 using _Base _LIBCPP_NODEBUG = __hash_node_base<__rebind_pointer_t <_VoidPtr, __hash_node<_Tp, _VoidPtr> > >;
115129 using __next_pointer _LIBCPP_NODEBUG = typename _Base::__next_pointer;
116130
@@ -122,18 +136,20 @@ struct __hash_node : public __hash_node_base< __rebind_pointer_t<_VoidPtr, __has
122136
123137private:
124138 union {
125- _Tp __value_;
139+ __node_value_type __value_;
126140 };
127141
128142public:
129- _LIBCPP_HIDE_FROM_ABI _Tp & __get_value () { return __value_; }
143+ _LIBCPP_HIDE_FROM_ABI __node_value_type & __get_value () { return __value_; }
130144#else
131145
132146private:
133- _ALIGNAS_TYPE (_Tp ) char __buffer_[sizeof(_Tp )];
147+ _ALIGNAS_TYPE (__node_value_type ) char __buffer_[sizeof(__node_value_type )];
134148
135149public:
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+ }
137153#endif
138154
139155 _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> > {
201217 return __t ;
202218 }
203219
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);
206222 }
207223 _LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move (__node_value_type& __v) { return __v.__move (); }
208224};
@@ -242,7 +258,7 @@ public:
242258
243259 typedef typename __node_base_type::__next_pointer __next_pointer;
244260
245- typedef _Tp __node_value_type;
261+ using __node_value_type _LIBCPP_NODEBUG = __get_hash_node_value_type_t <_Tp> ;
246262 typedef __rebind_pointer_t <_VoidPtr, __node_value_type> __node_value_type_pointer;
247263 typedef __rebind_pointer_t <_VoidPtr, const __node_value_type> __const_node_value_type_pointer;
248264
@@ -667,14 +683,14 @@ int __diagnose_unordered_container_requirements(void*);
667683template <class _Tp , class _Hash , class _Equal , class _Alloc >
668684class __hash_table {
669685public:
670- typedef _Tp value_type;
686+ using value_type = __get_hash_node_value_type_t <_Tp> ;
671687 typedef _Hash hasher;
672688 typedef _Equal key_equal;
673689 typedef _Alloc allocator_type;
674690
675691private:
676692 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;
678694
679695public:
680696 typedef typename _NodeTypes::__node_value_type __node_value_type;
@@ -855,6 +871,22 @@ public:
855871 return __emplace_hint_multi (__p, std::forward<_Pp>(__x));
856872 }
857873
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+
858890 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool > __insert_unique (const __container_value_type& __x) {
859891 return __emplace_unique_key_args (_NodeTypes::__get_key (__x), __x);
860892 }
@@ -1020,6 +1052,21 @@ private:
10201052 _LIBCPP_HIDE_FROM_ABI void __deallocate_node (__next_pointer __np) _NOEXCEPT;
10211053 _LIBCPP_HIDE_FROM_ABI __next_pointer __detach () _NOEXCEPT;
10221054
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+
10231070 template <class , class , class , class , class >
10241071 friend class unordered_map ;
10251072 template <class , class , class , class , class >
@@ -1216,8 +1263,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
12161263#endif // _LIBCPP_HAS_EXCEPTIONS
12171264 const_iterator __i = __u.begin ();
12181265 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_ ;
12211268 __node_insert_multi (__cache->__upcast ());
12221269 __cache = __next;
12231270 }
@@ -1230,11 +1277,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
12301277 __deallocate_node (__cache);
12311278 }
12321279 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 ()));
12381282 }
12391283}
12401284
@@ -1262,8 +1306,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __
12621306 try {
12631307#endif // _LIBCPP_HAS_EXCEPTIONS
12641308 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_ ;
12671311 __node_insert_unique (__cache->__upcast ());
12681312 __cache = __next;
12691313 }
@@ -1294,7 +1338,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __f
12941338 try {
12951339#endif // _LIBCPP_HAS_EXCEPTIONS
12961340 for (; __cache != nullptr && __first != __last; ++__first) {
1297- __cache->__upcast ()->__get_value () = *__first;
1341+ __assign_value ( __cache->__upcast ()->__get_value (), *__first) ;
12981342 __next_pointer __next = __cache->__next_ ;
12991343 __node_insert_multi (__cache->__upcast ());
13001344 __cache = __next;
0 commit comments