Skip to content

Commit 3074028

Browse files
committed
Copy past len in Clone for simpler asm
1 parent 92fdfdf commit 3074028

1 file changed

Lines changed: 34 additions & 1 deletion

File tree

src/arrayvec.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,40 @@ 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+
// we would prefer assume_init_ref, but its available only since 1.55
1209+
let val = unsafe { &*self.xs[i].as_ptr() };
1210+
unsafe { array.xs[i].as_mut_ptr().write(val.clone()) };
1211+
guard.data += 1;
1212+
} else {
1213+
if mem::size_of::<T>() == 0 || std::mem::needs_drop::<T>() || CAP > 32 {
1214+
break;
1215+
}
1216+
unsafe {
1217+
std::ptr::copy_nonoverlapping(self.xs[i].as_ptr(), array.xs[i].as_mut_ptr(), 1)
1218+
};
1219+
}
1220+
}
1221+
}
1222+
1223+
// This assignment seems redundant as guard.data is already equal to len and will set the
1224+
// array len on drop, but setting it here explicitly helps the compiler understand it
1225+
// can just copy the len instead of accumulating it in the guard. This is especially
1226+
// useful for T::clone() that can not panic.
1227+
array.len = self.len;
1228+
1229+
array
11971230
}
11981231

11991232
fn clone_from(&mut self, rhs: &Self) {

0 commit comments

Comments
 (0)