Skip to content

Commit 3bfeffd

Browse files
committed
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](https://github.com/rust-lang/rust/blob/027a232755fa9728e9699337267f6675dfd0a8ba/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 KillingSpark/zstd-rs#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) ```
2 parents 71cd460 + c126f7f commit 3bfeffd

File tree

5 files changed

+109
-20
lines changed

5 files changed

+109
-20
lines changed

library/alloc/benches/vec_deque.rs

+24
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,27 @@ fn bench_from_array_1000(b: &mut Bencher) {
6767
black_box(deq);
6868
})
6969
}
70+
71+
#[bench]
72+
fn bench_extend_bytes(b: &mut Bencher) {
73+
let mut ring: VecDeque<u8> = VecDeque::with_capacity(1000);
74+
let input: &[u8] = &[128; 512];
75+
76+
b.iter(|| {
77+
ring.clear();
78+
ring.extend(black_box(input));
79+
});
80+
}
81+
82+
#[bench]
83+
fn bench_extend_vec(b: &mut Bencher) {
84+
let mut ring: VecDeque<u8> = VecDeque::with_capacity(1000);
85+
let input = vec![128; 512];
86+
87+
b.iter(|| {
88+
ring.clear();
89+
90+
let input = input.clone();
91+
ring.extend(black_box(input));
92+
});
93+
}

library/alloc/src/collections/vec_deque/mod.rs

+6-19
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ use self::ring_slices::RingSlices;
5454

5555
mod ring_slices;
5656

57+
use self::spec_extend::SpecExtend;
58+
59+
mod spec_extend;
60+
5761
#[cfg(test)]
5862
mod tests;
5963

@@ -2970,24 +2974,7 @@ impl<'a, T, A: Allocator> IntoIterator for &'a mut VecDeque<T, A> {
29702974
#[stable(feature = "rust1", since = "1.0.0")]
29712975
impl<T, A: Allocator> Extend<T> for VecDeque<T, A> {
29722976
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
2973-
// This function should be the moral equivalent of:
2974-
//
2975-
// for item in iter.into_iter() {
2976-
// self.push_back(item);
2977-
// }
2978-
let mut iter = iter.into_iter();
2979-
while let Some(element) = iter.next() {
2980-
if self.len() == self.capacity() {
2981-
let (lower, _) = iter.size_hint();
2982-
self.reserve(lower.saturating_add(1));
2983-
}
2984-
2985-
let head = self.head;
2986-
self.head = self.wrap_add(self.head, 1);
2987-
unsafe {
2988-
self.buffer_write(head, element);
2989-
}
2990-
}
2977+
<Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter());
29912978
}
29922979

29932980
#[inline]
@@ -3004,7 +2991,7 @@ impl<T, A: Allocator> Extend<T> for VecDeque<T, A> {
30042991
#[stable(feature = "extend_ref", since = "1.2.0")]
30052992
impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for VecDeque<T, A> {
30062993
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
3007-
self.extend(iter.into_iter().cloned());
2994+
self.spec_extend(iter.into_iter());
30082995
}
30092996

30102997
#[inline]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use crate::alloc::Allocator;
2+
use crate::vec;
3+
use core::slice;
4+
5+
use super::VecDeque;
6+
7+
// Specialization trait used for VecDeque::extend
8+
pub(super) trait SpecExtend<T, I> {
9+
fn spec_extend(&mut self, iter: I);
10+
}
11+
12+
impl<T, I, A: Allocator> SpecExtend<T, I> for VecDeque<T, A>
13+
where
14+
I: Iterator<Item = T>,
15+
{
16+
default fn spec_extend(&mut self, mut iter: I) {
17+
// This function should be the moral equivalent of:
18+
//
19+
// for item in iter {
20+
// self.push_back(item);
21+
// }
22+
while let Some(element) = iter.next() {
23+
if self.len() == self.capacity() {
24+
let (lower, _) = iter.size_hint();
25+
self.reserve(lower.saturating_add(1));
26+
}
27+
28+
let head = self.head;
29+
self.head = self.wrap_add(self.head, 1);
30+
unsafe {
31+
self.buffer_write(head, element);
32+
}
33+
}
34+
}
35+
}
36+
37+
impl<T, A: Allocator> SpecExtend<T, vec::IntoIter<T>> for VecDeque<T, A> {
38+
fn spec_extend(&mut self, mut iterator: vec::IntoIter<T>) {
39+
let slice = iterator.as_slice();
40+
self.reserve(slice.len());
41+
42+
unsafe {
43+
self.copy_slice(self.head, slice);
44+
self.head = self.wrap_add(self.head, slice.len());
45+
}
46+
iterator.forget_remaining_elements();
47+
}
48+
}
49+
50+
impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for VecDeque<T, A>
51+
where
52+
I: Iterator<Item = &'a T>,
53+
T: Copy,
54+
{
55+
default fn spec_extend(&mut self, iterator: I) {
56+
self.spec_extend(iterator.copied())
57+
}
58+
}
59+
60+
impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for VecDeque<T, A>
61+
where
62+
T: Copy,
63+
{
64+
fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) {
65+
let slice = iterator.as_slice();
66+
self.reserve(slice.len());
67+
68+
unsafe {
69+
self.copy_slice(self.head, slice);
70+
self.head = self.wrap_add(self.head, slice.len());
71+
}
72+
}
73+
}

library/alloc/src/vec/into_iter.rs

+5
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ impl<T, A: Allocator> IntoIter<T, A> {
121121
ptr::drop_in_place(remaining);
122122
}
123123
}
124+
125+
/// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed.
126+
pub(crate) fn forget_remaining_elements(&mut self) {
127+
self.ptr = self.end;
128+
}
124129
}
125130

126131
#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]

library/alloc/src/vec/spec_extend.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl<T, A: Allocator> SpecExtend<T, IntoIter<T>> for Vec<T, A> {
6262
unsafe {
6363
self.append_elements(iterator.as_slice() as _);
6464
}
65-
iterator.ptr = iterator.end;
65+
iterator.forget_remaining_elements();
6666
}
6767
}
6868

0 commit comments

Comments
 (0)