Skip to content

Commit 5b96677

Browse files
committed
add specialization for extend_front and prepend with copied slice iterator
1 parent e23c155 commit 5b96677

File tree

6 files changed

+118
-34
lines changed

6 files changed

+118
-34
lines changed

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,35 @@ impl<T, A: Allocator> VecDeque<T, A> {
520520
}
521521
}
522522

523+
/// Copies all values from `src` to `dst` in reversed order, wrapping around if needed.
524+
/// Assumes capacity is sufficient.
525+
/// Equivalent to calling [`VecDeque::copy_slice`] with a [reversed](https://doc.rust-lang.org/std/primitive.slice.html#method.reverse) slice.
526+
#[inline]
527+
unsafe fn copy_slice_reversed(&mut self, dst: usize, src: &[T]) {
528+
/// # Safety
529+
///
530+
/// See [`ptr::copy_nonoverlapping`].
531+
unsafe fn copy_nonoverlapping_reversed<T>(src: *const T, dst: *mut T, count: usize) {
532+
for i in 0..count {
533+
unsafe { ptr::copy_nonoverlapping(src.add(count - 1 - i), dst.add(i), 1) };
534+
}
535+
}
536+
537+
debug_assert!(src.len() <= self.capacity());
538+
let head_room = self.capacity() - dst;
539+
if src.len() <= head_room {
540+
unsafe {
541+
copy_nonoverlapping_reversed(src.as_ptr(), self.ptr().add(dst), src.len());
542+
}
543+
} else {
544+
let (left, right) = src.split_at(src.len() - head_room);
545+
unsafe {
546+
copy_nonoverlapping_reversed(right.as_ptr(), self.ptr().add(dst), right.len());
547+
copy_nonoverlapping_reversed(left.as_ptr(), self.ptr(), left.len());
548+
}
549+
}
550+
}
551+
523552
/// Writes all values from `iter` to `dst`.
524553
///
525554
/// # Safety

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

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
#[cfg(not(test))]
2-
use core::iter::Rev;
3-
use core::iter::TrustedLen;
1+
use core::iter::{Copied, Rev, TrustedLen};
42
use core::slice;
53

64
use super::VecDeque;
@@ -158,9 +156,9 @@ where
158156
impl<T, A: Allocator> SpecExtendFront<T, vec::IntoIter<T>> for VecDeque<T, A> {
159157
#[track_caller]
160158
fn spec_extend_front(&mut self, mut iterator: vec::IntoIter<T>) {
161-
let slice = iterator.as_mut_slice();
162-
slice.reverse();
163-
unsafe { prepend(self, slice) };
159+
let slice = iterator.as_slice();
160+
// SAFETY: elements in the slice are forgotten after this call
161+
unsafe { prepend_reversed(self, slice) };
164162
iterator.forget_remaining_elements();
165163
}
166164
}
@@ -170,36 +168,40 @@ impl<T, A: Allocator> SpecExtendFront<T, Rev<vec::IntoIter<T>>> for VecDeque<T,
170168
#[track_caller]
171169
fn spec_extend_front(&mut self, iterator: Rev<vec::IntoIter<T>>) {
172170
let mut iterator = iterator.into_inner();
173-
unsafe { prepend(self, iterator.as_slice()) };
171+
let slice = iterator.as_slice();
172+
// SAFETY: elements in the slice are forgotten after this call
173+
unsafe { prepend(self, slice) };
174174
iterator.forget_remaining_elements();
175175
}
176176
}
177177

178-
// impl<T, A: Allocator> SpecExtendFront<T, Copied<slice::Iter<'_, T>>> for VecDeque<T, A>
179-
// where
180-
// T: Copy,
181-
// {
182-
// #[track_caller]
183-
// fn spec_extend_front(&mut self, _iter: Copied<slice::Iter<'_, T>>) {
184-
// // unsafe { prepend(self, slice) };
185-
// // reverse in place?
186-
// }
187-
// }
188-
189-
// impl<T, A: Allocator> SpecExtendFront<T, Rev<Copied<slice::Iter<'_, T>>>> for VecDeque<T, A>
190-
// where
191-
// T: Copy,
192-
// {
193-
// #[track_caller]
194-
// fn spec_extend_front(&mut self, iter: Rev<Copied<slice::Iter<'_, T>>>) {
195-
// unsafe { prepend(self, iter.into_inner().it.as_slice()) };
196-
// }
197-
// }
178+
impl<'a, T, A: Allocator> SpecExtendFront<T, Copied<slice::Iter<'a, T>>> for VecDeque<T, A>
179+
where
180+
Copied<slice::Iter<'a, T>>: Iterator<Item = T>,
181+
{
182+
#[track_caller]
183+
fn spec_extend_front(&mut self, iter: Copied<slice::Iter<'a, T>>) {
184+
let slice = iter.into_inner().as_slice();
185+
// SAFETY: T is Copy because Copied<slice::Iter<'a, T>> is Iterator
186+
unsafe { prepend_reversed(self, slice) };
187+
}
188+
}
189+
190+
impl<'a, T, A: Allocator> SpecExtendFront<T, Rev<Copied<slice::Iter<'a, T>>>> for VecDeque<T, A>
191+
where
192+
Rev<Copied<slice::Iter<'a, T>>>: Iterator<Item = T>,
193+
{
194+
#[track_caller]
195+
fn spec_extend_front(&mut self, iter: Rev<Copied<slice::Iter<'a, T>>>) {
196+
let slice = iter.into_inner().into_inner().as_slice();
197+
// SAFETY: T is Copy because Rev<Copied<slice::Iter<'a, T>>> is Iterator
198+
unsafe { prepend(self, slice) };
199+
}
200+
}
198201

199202
/// # Safety
200203
///
201-
/// `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`.
202-
#[cfg(not(test))]
204+
/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`.
203205
unsafe fn prepend<T, A: Allocator>(deque: &mut VecDeque<T, A>, slice: &[T]) {
204206
deque.reserve(slice.len());
205207

@@ -209,3 +211,16 @@ unsafe fn prepend<T, A: Allocator>(deque: &mut VecDeque<T, A>, slice: &[T]) {
209211
deque.len += slice.len();
210212
}
211213
}
214+
215+
/// # Safety
216+
///
217+
/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`.
218+
unsafe fn prepend_reversed<T, A: Allocator>(deque: &mut VecDeque<T, A>, slice: &[T]) {
219+
deque.reserve(slice.len());
220+
221+
unsafe {
222+
deque.head = deque.wrap_sub(deque.head, slice.len());
223+
deque.copy_slice_reversed(deque.head, slice);
224+
deque.len += slice.len();
225+
}
226+
}

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
#![feature(const_default)]
107107
#![feature(const_eval_select)]
108108
#![feature(const_heap)]
109+
#![feature(copied_into_inner)]
109110
#![feature(core_intrinsics)]
110111
#![feature(deprecated_suggestion)]
111112
#![feature(deref_pure_trait)]

library/alloctests/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#![feature(assert_matches)]
2121
#![feature(char_internals)]
2222
#![feature(char_max_len)]
23+
#![feature(copied_into_inner)]
2324
#![feature(core_intrinsics)]
2425
#![feature(exact_size_is_empty)]
2526
#![feature(extend_one)]
@@ -32,6 +33,7 @@
3233
#![feature(maybe_uninit_uninit_array_transpose)]
3334
#![feature(ptr_alignment_type)]
3435
#![feature(ptr_internals)]
36+
#![feature(rev_into_inner)]
3537
#![feature(sized_type_properties)]
3638
#![feature(slice_iter_mut_as_mut_slice)]
3739
#![feature(slice_ptr_get)]

library/alloctests/tests/vec_deque.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2113,14 +2113,45 @@ fn test_extend_front() {
21132113
}
21142114

21152115
#[test]
2116-
fn test_extend_front_specialization() {
2116+
fn test_extend_front_specialization_vec_into_iter() {
2117+
// trigger 4 code paths: all combinations of prepend and extend_front, wrap and no wrap
21172118
let mut v = VecDeque::with_capacity(4);
21182119
v.prepend(vec![1, 2, 3]);
21192120
assert_eq!(v, [1, 2, 3]);
2120-
v.pop_front();
2121-
v.prepend((-4..2).collect::<Vec<_>>());
2122-
assert_eq!(v, (-4..=3).collect::<Vec<_>>());
2123-
v.clear();
2121+
v.pop_back();
2122+
// this should wrap around the physical buffer
2123+
v.prepend(vec![-1, 0]);
2124+
// check it really wrapped
2125+
assert_eq!(v.as_slices(), ([-1].as_slice(), [0, 1, 2].as_slice()));
2126+
2127+
let mut v = VecDeque::with_capacity(4);
21242128
v.extend_front(vec![1, 2, 3]);
21252129
assert_eq!(v, [3, 2, 1]);
2130+
v.pop_back();
2131+
// this should wrap around the physical buffer
2132+
v.extend_front(vec![4, 5]);
2133+
// check it really wrapped
2134+
assert_eq!(v.as_slices(), ([5].as_slice(), [4, 3, 2].as_slice()));
2135+
}
2136+
2137+
#[test]
2138+
fn test_extend_front_specialization_copy_slice() {
2139+
// trigger 4 code paths: all combinations of prepend and extend_front, wrap and no wrap
2140+
let mut v = VecDeque::with_capacity(4);
2141+
v.prepend([1, 2, 3].as_slice().iter().copied());
2142+
assert_eq!(v, [1, 2, 3]);
2143+
v.pop_back();
2144+
// this should wrap around the physical buffer
2145+
v.prepend([-1, 0].as_slice().iter().copied());
2146+
// check it really wrapped
2147+
assert_eq!(v.as_slices(), ([-1].as_slice(), [0, 1, 2].as_slice()));
2148+
2149+
let mut v = VecDeque::with_capacity(4);
2150+
v.extend_front([1, 2, 3].as_slice().iter().copied());
2151+
assert_eq!(v, [3, 2, 1]);
2152+
v.pop_back();
2153+
// this should wrap around the physical buffer
2154+
v.extend_front([4, 5].as_slice().iter().copied());
2155+
// check it really wrapped
2156+
assert_eq!(v.as_slices(), ([5].as_slice(), [4, 3, 2].as_slice()));
21262157
}

library/core/src/iter/adapters/copied.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ impl<I> Copied<I> {
2424
pub(in crate::iter) fn new(it: I) -> Copied<I> {
2525
Copied { it }
2626
}
27+
28+
#[doc(hidden)]
29+
#[unstable(feature = "copied_into_inner", issue = "none")]
30+
pub fn into_inner(self) -> I {
31+
self.it
32+
}
2733
}
2834

2935
fn copy_fold<T: Copy, Acc>(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, &T) -> Acc {

0 commit comments

Comments
 (0)