From 91e88a4976cf4d61026a3ed8d7589cb18f8e9d18 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 25 Nov 2018 16:33:07 +0100 Subject: [PATCH 1/3] FEAT: Simplify stack guard in extend This simplification -- borrowing self.len instead of self, leads to an improvement in the extend_from_slice benchmark. It's also guided by the discussion of stacked borrows; the old code would be invalid, because the whole self is borrowed while ptr is derived from self. --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 75860dd0..fb40456a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -890,10 +890,10 @@ impl Extend for ArrayVec { // We update the length to handle panic in the iteration of the // user's iterator, without dropping any elements on the floor. let mut guard = ScopeExitGuard { - value: self, + value: &mut self.len, data: len, - f: |&len, self_| { - self_.set_len(len) + f: move |&len, self_len| { + **self_len = Index::from(len); } }; for elt in iter.into_iter().take(take) { From 23128275ee9b4c2fe5f14914c506a823c7685572 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 25 Nov 2018 16:34:47 +0100 Subject: [PATCH 2/3] TEST: Update benchmark for extend_from_slice The benchmark was optimized out totally. We think of that as a good sign, the new extend became transparent to the compiler and we had to get smarter in how to fool it. --- benches/extend.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benches/extend.rs b/benches/extend.rs index d380a7ed..0ae7ce32 100644 --- a/benches/extend.rs +++ b/benches/extend.rs @@ -5,6 +5,7 @@ extern crate arrayvec; use arrayvec::ArrayVec; use bencher::Bencher; +use bencher::black_box; fn extend_with_constant(b: &mut Bencher) { let mut v = ArrayVec::<[u8; 512]>::new(); @@ -33,7 +34,7 @@ fn extend_with_slice(b: &mut Bencher) { let data = [1; 512]; b.iter(|| { v.clear(); - v.extend(data.iter().cloned()); + v.extend(black_box(data.iter()).cloned()); v[0] }); b.bytes = v.capacity() as u64; From f40e708f7c2afa6fcd4a3fc509916757e053d142 Mon Sep 17 00:00:00 2001 From: bluss Date: Sun, 25 Nov 2018 16:37:29 +0100 Subject: [PATCH 3/3] FIX: In truncate, don't access self while holding raw pointer derived from self Again, stacked borrows model makes the `self.set_len()` call illegal because we are holding (and are going to use) another raw pointer derived from self, `tail`. --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fb40456a..e40b0a5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -461,11 +461,11 @@ impl ArrayVec { /// array.truncate(4); /// assert_eq!(&array[..], &[1, 2, 3]); /// ``` - pub fn truncate(&mut self, len: usize) { + pub fn truncate(&mut self, new_len: usize) { unsafe { - if len < self.len() { - let tail: *mut [_] = &mut self[len..]; - self.set_len(len); + if new_len < self.len() { + let tail: *mut [_] = &mut self[new_len..]; + self.len = Index::from(new_len); ptr::drop_in_place(tail); } }