diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index fc0220022dbb..a85c874d54de 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -520,6 +520,35 @@ impl VecDeque { } } + /// Copies all values from `src` to `dst` in reversed order, wrapping around if needed. + /// Assumes capacity is sufficient. + /// Equivalent to calling [`VecDeque::copy_slice`] with a [reversed](https://doc.rust-lang.org/std/primitive.slice.html#method.reverse) slice. + #[inline] + unsafe fn copy_slice_reversed(&mut self, dst: usize, src: &[T]) { + /// # Safety + /// + /// See [`ptr::copy_nonoverlapping`]. + unsafe fn copy_nonoverlapping_reversed(src: *const T, dst: *mut T, count: usize) { + for i in 0..count { + unsafe { ptr::copy_nonoverlapping(src.add(count - 1 - i), dst.add(i), 1) }; + } + } + + debug_assert!(src.len() <= self.capacity()); + let head_room = self.capacity() - dst; + if src.len() <= head_room { + unsafe { + copy_nonoverlapping_reversed(src.as_ptr(), self.ptr().add(dst), src.len()); + } + } else { + let (left, right) = src.split_at(src.len() - head_room); + unsafe { + copy_nonoverlapping_reversed(right.as_ptr(), self.ptr().add(dst), right.len()); + copy_nonoverlapping_reversed(left.as_ptr(), self.ptr(), left.len()); + } + } + } + /// Writes all values from `iter` to `dst`. /// /// # Safety diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index 3e830d2afe67..f73ba795cbea 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -1,6 +1,4 @@ -#[cfg(not(test))] -use core::iter::Rev; -use core::iter::TrustedLen; +use core::iter::{Copied, Rev, TrustedLen}; use core::slice; use super::VecDeque; @@ -158,9 +156,9 @@ where impl SpecExtendFront> for VecDeque { #[track_caller] fn spec_extend_front(&mut self, mut iterator: vec::IntoIter) { - let slice = iterator.as_mut_slice(); - slice.reverse(); - unsafe { prepend(self, slice) }; + let slice = iterator.as_slice(); + // SAFETY: elements in the slice are forgotten after this call + unsafe { prepend_reversed(self, slice) }; iterator.forget_remaining_elements(); } } @@ -170,36 +168,40 @@ impl SpecExtendFront>> for VecDeque>) { let mut iterator = iterator.into_inner(); - unsafe { prepend(self, iterator.as_slice()) }; + let slice = iterator.as_slice(); + // SAFETY: elements in the slice are forgotten after this call + unsafe { prepend(self, slice) }; iterator.forget_remaining_elements(); } } -// impl SpecExtendFront>> for VecDeque -// where -// T: Copy, -// { -// #[track_caller] -// fn spec_extend_front(&mut self, _iter: Copied>) { -// // unsafe { prepend(self, slice) }; -// // reverse in place? -// } -// } +impl<'a, T, A: Allocator> SpecExtendFront>> for VecDeque +where + Copied>: Iterator, +{ + #[track_caller] + fn spec_extend_front(&mut self, iter: Copied>) { + let slice = iter.into_inner().as_slice(); + // SAFETY: T is Copy because Copied> is Iterator + unsafe { prepend_reversed(self, slice) }; + } +} -// impl SpecExtendFront>>> for VecDeque -// where -// T: Copy, -// { -// #[track_caller] -// fn spec_extend_front(&mut self, iter: Rev>>) { -// unsafe { prepend(self, iter.into_inner().it.as_slice()) }; -// } -// } +impl<'a, T, A: Allocator> SpecExtendFront>>> for VecDeque +where + Rev>>: Iterator, +{ + #[track_caller] + fn spec_extend_front(&mut self, iter: Rev>>) { + let slice = iter.into_inner().into_inner().as_slice(); + // SAFETY: T is Copy because Rev>> is Iterator + unsafe { prepend(self, slice) }; + } +} /// # Safety /// -/// `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`. -#[cfg(not(test))] +/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`. unsafe fn prepend(deque: &mut VecDeque, slice: &[T]) { deque.reserve(slice.len()); @@ -209,3 +211,16 @@ unsafe fn prepend(deque: &mut VecDeque, slice: &[T]) { deque.len += slice.len(); } } + +/// # Safety +/// +/// Elements of `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`. +unsafe fn prepend_reversed(deque: &mut VecDeque, slice: &[T]) { + deque.reserve(slice.len()); + + unsafe { + deque.head = deque.wrap_sub(deque.head, slice.len()); + deque.copy_slice_reversed(deque.head, slice); + deque.len += slice.len(); + } +} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 81feb1cfc3f2..73197d021f1a 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -106,6 +106,7 @@ #![feature(const_default)] #![feature(const_eval_select)] #![feature(const_heap)] +#![feature(copied_into_inner)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index 0201c8752210..efdcb893bfee 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -20,6 +20,7 @@ #![feature(assert_matches)] #![feature(char_internals)] #![feature(char_max_len)] +#![feature(copied_into_inner)] #![feature(core_intrinsics)] #![feature(exact_size_is_empty)] #![feature(extend_one)] @@ -32,6 +33,7 @@ #![feature(maybe_uninit_uninit_array_transpose)] #![feature(ptr_alignment_type)] #![feature(ptr_internals)] +#![feature(rev_into_inner)] #![feature(sized_type_properties)] #![feature(slice_iter_mut_as_mut_slice)] #![feature(slice_ptr_get)] diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index 6442ee536fb5..cf31613577f7 100644 --- a/library/alloctests/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs @@ -2113,14 +2113,45 @@ fn test_extend_front() { } #[test] -fn test_extend_front_specialization() { +fn test_extend_front_specialization_vec_into_iter() { + // trigger 4 code paths: all combinations of prepend and extend_front, wrap and no wrap let mut v = VecDeque::with_capacity(4); v.prepend(vec![1, 2, 3]); assert_eq!(v, [1, 2, 3]); - v.pop_front(); - v.prepend((-4..2).collect::>()); - assert_eq!(v, (-4..=3).collect::>()); - v.clear(); + v.pop_back(); + // this should wrap around the physical buffer + v.prepend(vec![-1, 0]); + // check it really wrapped + assert_eq!(v.as_slices(), ([-1].as_slice(), [0, 1, 2].as_slice())); + + let mut v = VecDeque::with_capacity(4); v.extend_front(vec![1, 2, 3]); assert_eq!(v, [3, 2, 1]); + v.pop_back(); + // this should wrap around the physical buffer + v.extend_front(vec![4, 5]); + // check it really wrapped + assert_eq!(v.as_slices(), ([5].as_slice(), [4, 3, 2].as_slice())); +} + +#[test] +fn test_extend_front_specialization_copy_slice() { + // trigger 4 code paths: all combinations of prepend and extend_front, wrap and no wrap + let mut v = VecDeque::with_capacity(4); + v.prepend([1, 2, 3].as_slice().iter().copied()); + assert_eq!(v, [1, 2, 3]); + v.pop_back(); + // this should wrap around the physical buffer + v.prepend([-1, 0].as_slice().iter().copied()); + // check it really wrapped + assert_eq!(v.as_slices(), ([-1].as_slice(), [0, 1, 2].as_slice())); + + let mut v = VecDeque::with_capacity(4); + v.extend_front([1, 2, 3].as_slice().iter().copied()); + assert_eq!(v, [3, 2, 1]); + v.pop_back(); + // this should wrap around the physical buffer + v.extend_front([4, 5].as_slice().iter().copied()); + // check it really wrapped + assert_eq!(v.as_slices(), ([5].as_slice(), [4, 3, 2].as_slice())); } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 23e4e25ab538..9627ace29795 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -24,6 +24,12 @@ impl Copied { pub(in crate::iter) fn new(it: I) -> Copied { Copied { it } } + + #[doc(hidden)] + #[unstable(feature = "copied_into_inner", issue = "none")] + pub fn into_inner(self) -> I { + self.it + } } fn copy_fold(mut f: impl FnMut(Acc, T) -> Acc) -> impl FnMut(Acc, &T) -> Acc {