@@ -987,43 +987,169 @@ impl<T: Clone> Clone for RawTable<T> {
987987 . unwrap_or_else ( |_| hint:: unreachable_unchecked ( ) ) ,
988988 ) ;
989989
990- // Copy the control bytes unchanged. We do this in a single pass
991- self . ctrl ( 0 )
992- . copy_to_nonoverlapping ( new_table. ctrl ( 0 ) , self . num_ctrl_bytes ( ) ) ;
993-
994- {
995- // The cloning of elements may panic, in which case we need
996- // to make sure we drop only the elements that have been
997- // cloned so far.
998- let mut guard = guard ( ( 0 , & mut new_table) , |( index, new_table) | {
999- if mem:: needs_drop :: < T > ( ) {
1000- for i in 0 ..=* index {
1001- if is_full ( * new_table. ctrl ( i) ) {
1002- new_table. bucket ( i) . drop ( ) ;
1003- }
1004- }
1005- }
1006- new_table. free_buckets ( ) ;
1007- } ) ;
990+ new_table. clone_from_spec ( self , |new_table| {
991+ // We need to free the memory allocated for the new table.
992+ new_table. free_buckets ( ) ;
993+ } ) ;
1008994
1009- for from in self . iter ( ) {
1010- let index = self . bucket_index ( & from) ;
1011- let to = guard. 1 . bucket ( index) ;
1012- to. write ( from. as_ref ( ) . clone ( ) ) ;
995+ // Return the newly created table.
996+ ManuallyDrop :: into_inner ( new_table)
997+ }
998+ }
999+ }
10131000
1014- // Update the index in case we need to unwind.
1015- guard. 0 = index;
1001+ fn clone_from ( & mut self , source : & Self ) {
1002+ if source. is_empty_singleton ( ) {
1003+ * self = Self :: new ( ) ;
1004+ } else {
1005+ unsafe {
1006+ // First, drop all our elements without clearing the control bytes.
1007+ if mem:: needs_drop :: < T > ( ) {
1008+ for item in self . iter ( ) {
1009+ item. drop ( ) ;
10161010 }
1011+ }
10171012
1018- // Successfully cloned all items, no need to clean up.
1019- mem:: forget ( guard) ;
1013+ // If necessary, resize our table to match the source.
1014+ if self . buckets ( ) != source. buckets ( ) {
1015+ // Skip our drop by using ptr::write.
1016+ if !self . is_empty_singleton ( ) {
1017+ self . free_buckets ( ) ;
1018+ }
1019+ ( self as * mut Self ) . write (
1020+ Self :: new_uninitialized ( source. buckets ( ) , Fallibility :: Infallible )
1021+ . unwrap_or_else ( |_| hint:: unreachable_unchecked ( ) ) ,
1022+ ) ;
10201023 }
10211024
1022- // Return the newly created table.
1023- new_table. items = self . items ;
1024- new_table. growth_left = self . growth_left ;
1025- ManuallyDrop :: into_inner ( new_table)
1025+ self . clone_from_spec ( source, |self_| {
1026+ // We need to leave the table in an empty state.
1027+ self_. clear_no_drop ( )
1028+ } ) ;
1029+ }
1030+ }
1031+ }
1032+ }
1033+
1034+ /// Specialization of `clone_from` for `Copy` types
1035+ trait RawTableClone {
1036+ unsafe fn clone_from_spec ( & mut self , source : & Self , on_panic : impl FnMut ( & mut Self ) ) ;
1037+ }
1038+ impl < T : Clone > RawTableClone for RawTable < T > {
1039+ #[ cfg( feature = "nightly" ) ]
1040+ #[ cfg_attr( feature = "inline-more" , inline) ]
1041+ default unsafe fn clone_from_spec ( & mut self , source : & Self , on_panic : impl FnMut ( & mut Self ) ) {
1042+ self . clone_from_impl ( source, on_panic) ;
1043+ }
1044+
1045+ #[ cfg( not( feature = "nightly" ) ) ]
1046+ #[ cfg_attr( feature = "inline-more" , inline) ]
1047+ unsafe fn clone_from_spec ( & mut self , source : & Self , on_panic : impl FnMut ( & mut Self ) ) {
1048+ self . clone_from_impl ( source, on_panic) ;
1049+ }
1050+ }
1051+ #[ cfg( feature = "nightly" ) ]
1052+ impl < T : Copy > RawTableClone for RawTable < T > {
1053+ #[ cfg_attr( feature = "inline-more" , inline) ]
1054+ unsafe fn clone_from_spec ( & mut self , source : & Self , _on_panic : impl FnMut ( & mut Self ) ) {
1055+ source
1056+ . ctrl ( 0 )
1057+ . copy_to_nonoverlapping ( self . ctrl ( 0 ) , self . num_ctrl_bytes ( ) ) ;
1058+ source
1059+ . data
1060+ . as_ptr ( )
1061+ . copy_to_nonoverlapping ( self . data . as_ptr ( ) , self . buckets ( ) ) ;
1062+
1063+ self . items = source. items ;
1064+ self . growth_left = source. growth_left ;
1065+ }
1066+ }
1067+
1068+ impl < T : Clone > RawTable < T > {
1069+ /// Common code for clone and clone_from. Assumes `self.buckets() == source.buckets()`.
1070+ #[ cfg_attr( feature = "inline-more" , inline) ]
1071+ unsafe fn clone_from_impl ( & mut self , source : & Self , mut on_panic : impl FnMut ( & mut Self ) ) {
1072+ // Copy the control bytes unchanged. We do this in a single pass
1073+ source
1074+ . ctrl ( 0 )
1075+ . copy_to_nonoverlapping ( self . ctrl ( 0 ) , self . num_ctrl_bytes ( ) ) ;
1076+
1077+ // The cloning of elements may panic, in which case we need
1078+ // to make sure we drop only the elements that have been
1079+ // cloned so far.
1080+ let mut guard = guard ( ( 0 , & mut * self ) , |( index, self_) | {
1081+ if mem:: needs_drop :: < T > ( ) {
1082+ for i in 0 ..=* index {
1083+ if is_full ( * self_. ctrl ( i) ) {
1084+ self_. bucket ( i) . drop ( ) ;
1085+ }
1086+ }
10261087 }
1088+
1089+ // Depending on whether we were called from clone or clone_from, we
1090+ // either need to free the memory for the destination table or just
1091+ // clear the control bytes.
1092+ on_panic ( self_) ;
1093+ } ) ;
1094+
1095+ for from in source. iter ( ) {
1096+ let index = source. bucket_index ( & from) ;
1097+ let to = guard. 1 . bucket ( index) ;
1098+ to. write ( from. as_ref ( ) . clone ( ) ) ;
1099+
1100+ // Update the index in case we need to unwind.
1101+ guard. 0 = index;
1102+ }
1103+
1104+ // Successfully cloned all items, no need to clean up.
1105+ mem:: forget ( guard) ;
1106+
1107+ self . items = source. items ;
1108+ self . growth_left = source. growth_left ;
1109+ }
1110+
1111+ /// Variant of `clone_from` to use when a hasher is available.
1112+ #[ cfg( any( feature = "nightly" , feature = "raw" ) ) ]
1113+ pub fn clone_from_with_hasher ( & mut self , source : & Self , hasher : impl Fn ( & T ) -> u64 ) {
1114+ // If we have enough capacity in the table, just clear it and insert
1115+ // elements one by one. We don't do this if we have the same number of
1116+ // buckets as the source since we can just copy the contents directly
1117+ // in that case.
1118+ if self . buckets ( ) != source. buckets ( )
1119+ && bucket_mask_to_capacity ( self . bucket_mask ) >= source. len ( )
1120+ {
1121+ self . clear ( ) ;
1122+
1123+ let guard_self = guard ( & mut * self , |self_| {
1124+ // Clear the partially copied table if a panic occurs, otherwise
1125+ // items and growth_left will be out of sync with the contents
1126+ // of the table.
1127+ self_. clear ( ) ;
1128+ } ) ;
1129+
1130+ unsafe {
1131+ for item in source. iter ( ) {
1132+ // This may panic.
1133+ let item = item. as_ref ( ) . clone ( ) ;
1134+ let hash = hasher ( & item) ;
1135+
1136+ // We can use a simpler version of insert() here since:
1137+ // - there are no DELETED entries.
1138+ // - we know there is enough space in the table.
1139+ // - all elements are unique.
1140+ let index = guard_self. find_insert_slot ( hash) ;
1141+ guard_self. set_ctrl ( index, h2 ( hash) ) ;
1142+ guard_self. bucket ( index) . write ( item) ;
1143+ }
1144+ }
1145+
1146+ // Successfully cloned all items, no need to clean up.
1147+ mem:: forget ( guard_self) ;
1148+
1149+ self . items = source. items ;
1150+ self . growth_left -= source. items ;
1151+ } else {
1152+ self . clone_from ( source) ;
10271153 }
10281154 }
10291155}
0 commit comments