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;
@@ -845,6 +861,22 @@ public:
845861 return __emplace_unique (std::forward<_Pp>(__x));
846862 }
847863
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+
848880 template <class _Pp >
849881 _LIBCPP_HIDE_FROM_ABI iterator __insert_multi (_Pp&& __x) {
850882 return __emplace_multi (std::forward<_Pp>(__x));
@@ -855,6 +887,22 @@ public:
855887 return __emplace_hint_multi (__p, std::forward<_Pp>(__x));
856888 }
857889
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+
858906 _LIBCPP_HIDE_FROM_ABI pair<iterator, bool > __insert_unique (const __container_value_type& __x) {
859907 return __emplace_unique_key_args (_NodeTypes::__get_key (__x), __x);
860908 }
@@ -1020,6 +1068,21 @@ private:
10201068 _LIBCPP_HIDE_FROM_ABI void __deallocate_node (__next_pointer __np) _NOEXCEPT;
10211069 _LIBCPP_HIDE_FROM_ABI __next_pointer __detach () _NOEXCEPT;
10221070
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+
10231086 template <class , class , class , class , class >
10241087 friend class unordered_map ;
10251088 template <class , class , class , class , class >
@@ -1216,8 +1279,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
12161279#endif // _LIBCPP_HAS_EXCEPTIONS
12171280 const_iterator __i = __u.begin ();
12181281 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_ ;
12211284 __node_insert_multi (__cache->__upcast ());
12221285 __cache = __next;
12231286 }
@@ -1230,11 +1293,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u,
12301293 __deallocate_node (__cache);
12311294 }
12321295 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 ()));
12381298 }
12391299}
12401300
@@ -1262,8 +1322,8 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __
12621322 try {
12631323#endif // _LIBCPP_HAS_EXCEPTIONS
12641324 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_ ;
12671327 __node_insert_unique (__cache->__upcast ());
12681328 __cache = __next;
12691329 }
@@ -1294,7 +1354,7 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __f
12941354 try {
12951355#endif // _LIBCPP_HAS_EXCEPTIONS
12961356 for (; __cache != nullptr && __first != __last; ++__first) {
1297- __cache->__upcast ()->__get_value () = *__first;
1357+ __assign_value ( __cache->__upcast ()->__get_value (), *__first) ;
12981358 __next_pointer __next = __cache->__next_ ;
12991359 __node_insert_multi (__cache->__upcast ());
13001360 __cache = __next;
0 commit comments