@@ -1193,7 +1193,60 @@ impl<T, const CAP: usize> Clone for ArrayVec<T, CAP>
11931193 where T : Clone
11941194{
11951195 fn clone ( & self ) -> Self {
1196- self . iter ( ) . cloned ( ) . collect ( )
1196+ let mut array: ArrayVec < T , CAP > = ArrayVec :: new ( ) ;
1197+ {
1198+ let mut guard = ScopeExitGuard {
1199+ value : & mut array. len ,
1200+ data : 0 ,
1201+ f : move |& len, self_len| {
1202+ * * self_len = len as LenUint ;
1203+ }
1204+ } ;
1205+
1206+ for i in 0 ..CAP {
1207+ if i < self . len ( ) {
1208+ let val = unsafe { & * self . xs [ i] . as_ptr ( ) } . clone ( ) ;
1209+ if mem:: size_of :: < T > ( ) != 0 {
1210+ unsafe { array. xs [ i] . as_mut_ptr ( ) . write ( val) } ;
1211+ } else {
1212+ // The ZST element has logically been moved into the vector.
1213+ // There is no memory to write, but dropping `elt` here would
1214+ // drop it once now and once again when the vector is dropped.
1215+ mem:: forget ( val) ;
1216+ }
1217+ guard. data += 1 ;
1218+ } else {
1219+ // we are done copying all the elements.
1220+ // we continue to copy uninitialized elements past len up to CAP. This seems
1221+ // weird and counter intuitive, but when T is trivial (like i8/i32), copying the
1222+ // whole array is faster as the compiler doesnt have to loop up to len, and the
1223+ // generated code is branchless copy of the whole struct (like Copy).
1224+ //
1225+ // We only do it if;
1226+ // - size_of > 0, to avoid reading self.xs[i].as_ptr()
1227+ // - T does not requires drop, which we take as an indication that T::clone()
1228+ // is not trivial and therefore the loop will not be optimized away by the
1229+ // compiler.
1230+ // - the total array is less or equal to 128 bytes. An arbitrary threshold to
1231+ // avoid unnecessary copying of large arrays.
1232+ if mem:: size_of :: < T > ( ) == 0 || std:: mem:: needs_drop :: < T > ( ) || CAP > 128 / mem:: size_of :: < T > ( ) {
1233+ break ;
1234+ }
1235+ // Safety: copy of MaybeUninit to MaybeUninit
1236+ unsafe {
1237+ std:: ptr:: copy_nonoverlapping ( self . xs [ i] . as_ptr ( ) , array. xs [ i] . as_mut_ptr ( ) , 1 )
1238+ } ;
1239+ }
1240+ }
1241+ }
1242+
1243+ // This assignment seems redundant as guard.data is already equal to len and will set the
1244+ // array len on drop, but setting it here explicitly helps the compiler understand it
1245+ // can just copy the len instead of accumulating it in the guard. This is especially
1246+ // useful for T::clone() that can not panic.
1247+ array. len = self . len ;
1248+
1249+ array
11971250 }
11981251
11991252 fn clone_from ( & mut self , rhs : & Self ) {
0 commit comments