@@ -987,43 +987,169 @@ impl<T: Clone> Clone for RawTable<T> {
987
987
. unwrap_or_else ( |_| hint:: unreachable_unchecked ( ) ) ,
988
988
) ;
989
989
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
+ } ) ;
1008
994
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
+ }
1013
1000
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 ( ) ;
1016
1010
}
1011
+ }
1017
1012
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
+ ) ;
1020
1023
}
1021
1024
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
+ }
1026
1087
}
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) ;
1027
1153
}
1028
1154
}
1029
1155
}
0 commit comments