Auto merge of #95904 - paolobarbolini:vecdeque-specextend, r=the8472
Add VecDeque::extend from vec::IntoIter and slice::Iter specializations
Inspired from the [`Vec` `SpecExtend` implementation](027a232755/library/alloc/src/vec/spec_extend.rs
), but without the specialization for `TrustedLen` which I'll look into in the future.
Should help #95632 and https://github.com/KillingSpark/zstd-rs/pull/17
## Benchmarks
Before
```
test vec_deque::bench_extend_bytes ... bench: 862 ns/iter (+/- 10)
test vec_deque::bench_extend_vec ... bench: 883 ns/iter (+/- 19)
```
After
```
test vec_deque::bench_extend_bytes ... bench: 8 ns/iter (+/- 0)
test vec_deque::bench_extend_vec ... bench: 24 ns/iter (+/- 1)
```
This commit is contained in:
commit
3bfeffd55b
@ -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<u8> = 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<u8> = VecDeque::with_capacity(1000);
|
||||
let input = vec![128; 512];
|
||||
|
||||
b.iter(|| {
|
||||
ring.clear();
|
||||
|
||||
let input = input.clone();
|
||||
ring.extend(black_box(input));
|
||||
});
|
||||
}
|
||||
|
@ -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<T, A> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T, A: Allocator> Extend<T> for VecDeque<T, A> {
|
||||
fn extend<I: IntoIterator<Item = T>>(&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);
|
||||
}
|
||||
}
|
||||
<Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -3004,7 +2991,7 @@ impl<T, A: Allocator> Extend<T> for VecDeque<T, A> {
|
||||
#[stable(feature = "extend_ref", since = "1.2.0")]
|
||||
impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque<T, A> {
|
||||
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||
self.extend(iter.into_iter().cloned());
|
||||
self.spec_extend(iter.into_iter());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
73
library/alloc/src/collections/vec_deque/spec_extend.rs
Normal file
73
library/alloc/src/collections/vec_deque/spec_extend.rs
Normal file
@ -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<T, I> {
|
||||
fn spec_extend(&mut self, iter: I);
|
||||
}
|
||||
|
||||
impl<T, I, A: Allocator> SpecExtend<T, I> for VecDeque<T, A>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
{
|
||||
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<T, A: Allocator> SpecExtend<T, vec::IntoIter<T>> for VecDeque<T, A> {
|
||||
fn spec_extend(&mut self, mut iterator: vec::IntoIter<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());
|
||||
}
|
||||
iterator.forget_remaining_elements();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for VecDeque<T, A>
|
||||
where
|
||||
I: Iterator<Item = &'a T>,
|
||||
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<T, A>
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
@ -121,6 +121,11 @@ impl<T, A: Allocator> IntoIter<T, A> {
|
||||
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")]
|
||||
|
@ -62,7 +62,7 @@ impl<T, A: Allocator> SpecExtend<T, IntoIter<T>> for Vec<T, A> {
|
||||
unsafe {
|
||||
self.append_elements(iterator.as_slice() as _);
|
||||
}
|
||||
iterator.ptr = iterator.end;
|
||||
iterator.forget_remaining_elements();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user