Skip to content

Commit d4ae120

Browse files
committed
implement VecDeque extend_front and prepend, add tests
1 parent 21a13b8 commit d4ae120

File tree

5 files changed

+223
-1
lines changed

5 files changed

+223
-1
lines changed

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

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub use self::iter::Iter;
4747

4848
mod iter;
4949

50-
use self::spec_extend::SpecExtend;
50+
use self::spec_extend::{SpecExtend, SpecExtendFront};
5151

5252
mod spec_extend;
5353

@@ -174,6 +174,21 @@ impl<T, A: Allocator> VecDeque<T, A> {
174174
self.len += 1;
175175
}
176176

177+
/// Prepends an element to the buffer.
178+
///
179+
/// # Safety
180+
///
181+
/// May only be called if `deque.len() < deque.capacity()`
182+
#[inline]
183+
unsafe fn push_front_unchecked(&mut self, element: T) {
184+
self.head = self.wrap_sub(self.head, 1);
185+
// SAFETY: Because of the precondition, it's guaranteed that there is space
186+
// in the logical array before the first element (where self.head is now).
187+
unsafe { self.buffer_write(self.head, element) };
188+
// This can't overflow because `deque.len() < deque.capacity() <= usize::MAX`.
189+
self.len += 1;
190+
}
191+
177192
/// Moves an element out of the buffer
178193
#[inline]
179194
unsafe fn buffer_read(&mut self, off: usize) -> T {
@@ -1956,6 +1971,73 @@ impl<T, A: Allocator> VecDeque<T, A> {
19561971
unsafe { self.buffer_write(self.to_physical_idx(len), value) }
19571972
}
19581973

1974+
/// Prepends all contents of the iterator to the front of the deque.
1975+
/// The order of the contents is preserved.
1976+
///
1977+
/// To get behavior like [`append`][VecDeque::append] where elements are moved
1978+
/// from the other collection to this one, use `self.prepend(other.drain(..))`.
1979+
///
1980+
/// # Examples
1981+
///
1982+
/// ```
1983+
/// #![feature(deque_extend_front)]
1984+
/// use std::collections::VecDeque;
1985+
///
1986+
/// let mut deque = VecDeque::from([4, 5, 6]);
1987+
/// deque.prepend([1, 2, 3]);
1988+
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
1989+
/// ```
1990+
///
1991+
/// Move values between collections like [`append`][VecDeque::append] does but prepend to the front:
1992+
///
1993+
/// ```
1994+
/// #![feature(deque_extend_front)]
1995+
/// use std::collections::VecDeque;
1996+
///
1997+
/// let mut deque1 = VecDeque::from([4, 5, 6]);
1998+
/// let mut deque2 = VecDeque::from([1, 2, 3]);
1999+
/// deque1.prepend(deque2.drain(..));
2000+
/// assert_eq!(deque1, [1, 2, 3, 4, 5, 6]);
2001+
/// assert!(deque2.is_empty());
2002+
/// ```
2003+
#[unstable(feature = "deque_extend_front", issue = "146975")]
2004+
#[track_caller]
2005+
pub fn prepend<I: IntoIterator<Item = T, IntoIter: DoubleEndedIterator>>(&mut self, other: I) {
2006+
self.extend_front(other.into_iter().rev())
2007+
}
2008+
2009+
/// Prepends all contents of the iterator to the front of the deque,
2010+
/// as if [`push_front`][VecDeque::push_front] was called repeatedly with
2011+
/// the values yielded by the iterator.
2012+
///
2013+
/// # Examples
2014+
///
2015+
/// ```
2016+
/// #![feature(deque_extend_front)]
2017+
/// use std::collections::VecDeque;
2018+
///
2019+
/// let mut deque = VecDeque::from([4, 5, 6]);
2020+
/// deque.extend_front([3, 2, 1]);
2021+
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
2022+
/// ```
2023+
///
2024+
/// This behaves like [`push_front`][VecDeque::push_front] was called repeatedly:
2025+
///
2026+
/// ```
2027+
/// use std::collections::VecDeque;
2028+
///
2029+
/// let mut deque = VecDeque::from([4, 5, 6]);
2030+
/// for v in [3, 2, 1] {
2031+
/// deque.push_front(v);
2032+
/// }
2033+
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
2034+
/// ```
2035+
#[unstable(feature = "deque_extend_front", issue = "146975")]
2036+
#[track_caller]
2037+
pub fn extend_front<I: IntoIterator<Item = T>>(&mut self, iter: I) {
2038+
<Self as SpecExtendFront<T, I::IntoIter>>::spec_extend_front(self, iter.into_iter());
2039+
}
2040+
19592041
#[inline]
19602042
fn is_contiguous(&self) -> bool {
19612043
// Do the calculation like this to avoid overflowing if len + head > usize::MAX

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

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(not(test))]
2+
use core::iter::Rev;
13
use core::iter::TrustedLen;
24
use core::slice;
35

@@ -114,3 +116,96 @@ where
114116
}
115117
}
116118
}
119+
120+
// Specialization trait used for VecDeque::extend_front
121+
pub(super) trait SpecExtendFront<T, I> {
122+
#[track_caller]
123+
fn spec_extend_front(&mut self, iter: I);
124+
}
125+
126+
impl<T, I, A: Allocator> SpecExtendFront<T, I> for VecDeque<T, A>
127+
where
128+
I: Iterator<Item = T>,
129+
{
130+
#[track_caller]
131+
default fn spec_extend_front(&mut self, mut iter: I) {
132+
// This function should be the moral equivalent of:
133+
//
134+
// for item in iter {
135+
// self.push_front(item);
136+
// }
137+
138+
while let Some(element) = iter.next() {
139+
let (lower, _) = iter.size_hint();
140+
self.reserve(lower.saturating_add(1));
141+
142+
// SAFETY: We just reserved space for at least one element.
143+
unsafe { self.push_front_unchecked(element) };
144+
145+
// Inner loop to avoid repeatedly calling `reserve`.
146+
while self.len < self.capacity() {
147+
let Some(element) = iter.next() else {
148+
return;
149+
};
150+
// SAFETY: The loop condition guarantees that `self.len() < self.capacity()`.
151+
unsafe { self.push_front_unchecked(element) };
152+
}
153+
}
154+
}
155+
}
156+
157+
#[cfg(not(test))]
158+
impl<T, A: Allocator> SpecExtendFront<T, vec::IntoIter<T>> for VecDeque<T, A> {
159+
#[track_caller]
160+
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) };
164+
iterator.forget_remaining_elements();
165+
}
166+
}
167+
168+
#[cfg(not(test))]
169+
impl<T, A: Allocator> SpecExtendFront<T, Rev<vec::IntoIter<T>>> for VecDeque<T, A> {
170+
#[track_caller]
171+
fn spec_extend_front(&mut self, iterator: Rev<vec::IntoIter<T>>) {
172+
let mut iterator = iterator.into_inner();
173+
unsafe { prepend(self, iterator.as_slice()) };
174+
iterator.forget_remaining_elements();
175+
}
176+
}
177+
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+
// }
198+
199+
/// # Safety
200+
///
201+
/// `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`.
202+
#[cfg(not(test))]
203+
unsafe fn prepend<T, A: Allocator>(deque: &mut VecDeque<T, A>, slice: &[T]) {
204+
deque.reserve(slice.len());
205+
206+
unsafe {
207+
deque.head = deque.wrap_sub(deque.head, slice.len());
208+
deque.copy_slice(deque.head, slice);
209+
deque.len += slice.len();
210+
}
211+
}

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@
132132
#![feature(ptr_alignment_type)]
133133
#![feature(ptr_internals)]
134134
#![feature(ptr_metadata)]
135+
#![feature(rev_into_inner)]
135136
#![feature(set_ptr_value)]
136137
#![feature(sized_type_properties)]
137138
#![feature(slice_from_ptr_range)]

library/alloctests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![feature(char_max_len)]
77
#![feature(cow_is_borrowed)]
88
#![feature(core_intrinsics)]
9+
#![feature(deque_extend_front)]
910
#![feature(downcast_unchecked)]
1011
#![feature(exact_size_is_empty)]
1112
#![feature(hashmap_internals)]

library/alloctests/tests/vec_deque.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,3 +1849,46 @@ fn test_truncate_front() {
18491849
v.truncate_front(5);
18501850
assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice()));
18511851
}
1852+
1853+
#[test]
1854+
fn test_extend_front() {
1855+
let mut v = VecDeque::new();
1856+
v.extend_front(0..3);
1857+
assert_eq!(v, [2, 1, 0]);
1858+
v.extend_front(3..6);
1859+
assert_eq!(v, [5, 4, 3, 2, 1, 0]);
1860+
v.prepend([1; 4]);
1861+
assert_eq!(v, [1, 1, 1, 1, 5, 4, 3, 2, 1, 0]);
1862+
1863+
let mut v = VecDeque::with_capacity(8);
1864+
let cap = v.capacity();
1865+
v.extend(0..4);
1866+
v.truncate_front(2);
1867+
v.extend_front(4..8);
1868+
assert_eq!(v.as_slices(), ([7, 6].as_slice(), [5, 4, 2, 3].as_slice()));
1869+
assert_eq!(v.capacity(), cap);
1870+
1871+
let mut v = VecDeque::new();
1872+
v.extend_front([]);
1873+
v.extend_front(None);
1874+
v.extend_front(vec![]);
1875+
v.prepend([]);
1876+
v.prepend(None);
1877+
v.prepend(vec![]);
1878+
assert_eq!(v.capacity(), 0);
1879+
v.extend_front(Some(123));
1880+
assert_eq!(v, [123]);
1881+
}
1882+
1883+
#[test]
1884+
fn test_extend_front_specialization() {
1885+
let mut v = VecDeque::with_capacity(4);
1886+
v.prepend(vec![1, 2, 3]);
1887+
assert_eq!(v, [1, 2, 3]);
1888+
v.pop_front();
1889+
v.prepend((-4..2).collect::<Vec<_>>());
1890+
assert_eq!(v, (-4..=3).collect::<Vec<_>>());
1891+
v.clear();
1892+
v.extend_front(vec![1, 2, 3]);
1893+
assert_eq!(v, [3, 2, 1]);
1894+
}

0 commit comments

Comments
 (0)