From 84b8898d6357810472a01038bde7b1788615aa8a Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Mon, 11 Apr 2022 08:12:14 +0200 Subject: [PATCH 1/2] Add VecDeque::extend benchmark --- library/alloc/benches/vec_deque.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/alloc/benches/vec_deque.rs b/library/alloc/benches/vec_deque.rs index 404cfa6addb73..6660380e4beb0 100644 --- a/library/alloc/benches/vec_deque.rs +++ b/library/alloc/benches/vec_deque.rs @@ -67,3 +67,27 @@ fn bench_from_array_1000(b: &mut Bencher) { black_box(deq); }) } + +#[bench] +fn bench_extend_bytes(b: &mut Bencher) { + let mut ring: VecDeque = VecDeque::with_capacity(1000); + let input: &[u8] = &[128; 512]; + + b.iter(|| { + ring.clear(); + ring.extend(black_box(input)); + }); +} + +#[bench] +fn bench_extend_vec(b: &mut Bencher) { + let mut ring: VecDeque = VecDeque::with_capacity(1000); + let input = vec![128; 512]; + + b.iter(|| { + ring.clear(); + + let input = input.clone(); + ring.extend(black_box(input)); + }); +} From c126f7fc8bf9e2abc0cac1fae40d04f4cf21e4d0 Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Mon, 11 Apr 2022 00:00:03 +0200 Subject: [PATCH 2/2] Add VecDeque::extend from vec::IntoIter and slice::Iter specializations --- .../alloc/src/collections/vec_deque/mod.rs | 25 ++----- .../src/collections/vec_deque/spec_extend.rs | 73 +++++++++++++++++++ library/alloc/src/vec/into_iter.rs | 5 ++ library/alloc/src/vec/spec_extend.rs | 2 +- 4 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 library/alloc/src/collections/vec_deque/spec_extend.rs diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index ab14a43fb9379..5f1a6848ae62a 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -54,6 +54,10 @@ use self::ring_slices::RingSlices; mod ring_slices; +use self::spec_extend::SpecExtend; + +mod spec_extend; + #[cfg(test)] mod tests; @@ -2970,24 +2974,7 @@ impl<'a, T, A: Allocator> IntoIterator for &'a mut VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Extend for VecDeque { fn extend>(&mut self, iter: I) { - // This function should be the moral equivalent of: - // - // for item in iter.into_iter() { - // self.push_back(item); - // } - let mut iter = iter.into_iter(); - while let Some(element) = iter.next() { - if self.len() == self.capacity() { - let (lower, _) = iter.size_hint(); - self.reserve(lower.saturating_add(1)); - } - - let head = self.head; - self.head = self.wrap_add(self.head, 1); - unsafe { - self.buffer_write(head, element); - } - } + >::spec_extend(self, iter.into_iter()); } #[inline] @@ -3004,7 +2991,7 @@ impl Extend for VecDeque { #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque { fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); + self.spec_extend(iter.into_iter()); } #[inline] diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs new file mode 100644 index 0000000000000..172f2e9068fe6 --- /dev/null +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -0,0 +1,73 @@ +use crate::alloc::Allocator; +use crate::vec; +use core::slice; + +use super::VecDeque; + +// Specialization trait used for VecDeque::extend +pub(super) trait SpecExtend { + fn spec_extend(&mut self, iter: I); +} + +impl SpecExtend for VecDeque +where + I: Iterator, +{ + default fn spec_extend(&mut self, mut iter: I) { + // This function should be the moral equivalent of: + // + // for item in iter { + // self.push_back(item); + // } + while let Some(element) = iter.next() { + if self.len() == self.capacity() { + let (lower, _) = iter.size_hint(); + self.reserve(lower.saturating_add(1)); + } + + let head = self.head; + self.head = self.wrap_add(self.head, 1); + unsafe { + self.buffer_write(head, element); + } + } + } +} + +impl SpecExtend> for VecDeque { + fn spec_extend(&mut self, mut iterator: vec::IntoIter) { + let slice = iterator.as_slice(); + self.reserve(slice.len()); + + unsafe { + self.copy_slice(self.head, slice); + self.head = self.wrap_add(self.head, slice.len()); + } + iterator.forget_remaining_elements(); + } +} + +impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for VecDeque +where + I: Iterator, + T: Copy, +{ + default fn spec_extend(&mut self, iterator: I) { + self.spec_extend(iterator.copied()) + } +} + +impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for VecDeque +where + T: Copy, +{ + fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { + let slice = iterator.as_slice(); + self.reserve(slice.len()); + + unsafe { + self.copy_slice(self.head, slice); + self.head = self.wrap_add(self.head, slice.len()); + } + } +} diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 03c532bb69769..8134eea570ad7 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -121,6 +121,11 @@ impl IntoIter { ptr::drop_in_place(remaining); } } + + /// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed. + pub(crate) fn forget_remaining_elements(&mut self) { + self.ptr = self.end; + } } #[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index c3b4534096de5..506ee0ecfa279 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -62,7 +62,7 @@ impl SpecExtend> for Vec { unsafe { self.append_elements(iterator.as_slice() as _); } - iterator.ptr = iterator.end; + iterator.forget_remaining_elements(); } }