From eed51be53ba3137dfcbf77a0d8f4ee9667ca5a80 Mon Sep 17 00:00:00 2001 From: Andreas Molzer Date: Sat, 18 Jan 2020 16:05:13 +0100 Subject: [PATCH 1/3] Switch to slice swapping for split The new slice is already initialized with default values for T due to the constructor used. Instead of using different defaulted values for replacing the split-off instances we can simply swap slices. This reduces pressure on the optimizer and uses a probably optimized method from the core library. --- src/arrayvec.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index 608312c..3b86dd5 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -544,11 +544,10 @@ impl ArrayVec { } let mut new = Self::default(); let moves = &mut self.as_mut_slice()[at..]; - let targets = new.data.as_slice_mut(); - for (m, t) in moves.iter_mut().zip(targets) { - replace(t, replace(m, A::Item::default())); - } - new.len = self.len - at; + let split_len = moves.len(); + let targets = &mut new.data.as_slice_mut()[..split_len]; + moves.swap_with_slice(targets); + new.len = split_len; self.len = at; new } From 381eacaa461717c73a3d3a4c604ac108cc3fc4d2 Mon Sep 17 00:00:00 2001 From: Andreas Molzer Date: Sat, 18 Jan 2020 16:10:12 +0100 Subject: [PATCH 2/3] Use mem::take shorthand for defaulted replace This makes the code more readable by shortening lines and avoid explicit or redundant type annotations. The core function would require a rust version of 1.40 so straightforward implementation is added to the crate. --- src/arrayvec.rs | 10 ++++------ src/lib.rs | 5 +++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index 3b86dd5..c9285ca 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -343,8 +343,7 @@ impl ArrayVec { pub fn pop(&mut self) -> Option { if self.len > 0 { self.len -= 1; - let out = - replace(&mut self.data.as_slice_mut()[self.len], A::Item::default()); + let out = take(&mut self.data.as_slice_mut()[self.len]); Some(out) } else { None @@ -759,8 +758,7 @@ impl Iterator for ArrayVecIterator { #[inline] fn next(&mut self) -> Option { if self.base < self.len { - let out = - replace(&mut self.data.as_slice_mut()[self.base], A::Item::default()); + let out = take(&mut self.data.as_slice_mut()[self.base]); self.base += 1; Some(out) } else { @@ -779,13 +777,13 @@ impl Iterator for ArrayVecIterator { } #[inline] fn last(mut self) -> Option { - Some(replace(&mut self.data.as_slice_mut()[self.len], A::Item::default())) + Some(take(&mut self.data.as_slice_mut()[self.len])) } #[inline] fn nth(&mut self, n: usize) -> Option { let i = self.base + (n - 1); if i < self.len { - let out = replace(&mut self.data.as_slice_mut()[i], A::Item::default()); + let out = take(&mut self.data.as_slice_mut()[i]); self.base = i + 1; Some(out) } else { diff --git a/src/lib.rs b/src/lib.rs index 2100b1e..7bc34a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,3 +84,8 @@ pub use arrayvec::*; mod tinyvec; #[cfg(feature = "alloc")] pub use tinyvec::*; + +// Replace with mem::take as soon as MSRV allows it +fn take(from: &mut T) -> T { + replace(from, T::default()) +} From c21132b4953274168ec879a882b1fad9eeadaf14 Mon Sep 17 00:00:00 2001 From: Andreas Molzer Date: Sat, 18 Jan 2020 16:23:35 +0100 Subject: [PATCH 3/3] Simplify resize with element or function Avoids a call to Clone of the element by using the provided instance as the one inserted last. A similar optimization is used in the standard library. Also changes the iteration to an independent iterator as the number of insert elements must be known in advance. --- src/arrayvec.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index c9285ca..1c007d9 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -414,14 +414,14 @@ impl ArrayVec { where A::Item: Clone, { - use core::cmp::Ordering; - match new_len.cmp(&self.len) { - Ordering::Less => self.truncate(new_len), - Ordering::Equal => (), - Ordering::Greater => { - while self.len < new_len { + match new_len.checked_sub(self.len) { + None => self.truncate(new_len), + Some(0) => (), + Some(new_elements) => { + for _ in 1..new_elements { self.push(new_val.clone()); } + self.push(new_val); } } } @@ -454,12 +454,10 @@ impl ArrayVec { new_len: usize, mut f: F, ) { - use core::cmp::Ordering; - match new_len.cmp(&self.len) { - Ordering::Less => self.truncate(new_len), - Ordering::Equal => (), - Ordering::Greater => { - while self.len < new_len { + match new_len.checked_sub(self.len) { + None => self.truncate(new_len), + Some(new_elements) => { + for _ in 0..new_elements { self.push(f()); } }