Skip to content

Commit 6da1b60

Browse files
committed
add extend_front to VecDeque with specialization like extend (unfinished)
1 parent 1d23da6 commit 6da1b60

File tree

3 files changed

+92
-1
lines changed

3 files changed

+92
-1
lines changed

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

Lines changed: 34 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

@@ -176,6 +176,21 @@ impl<T, A: Allocator> VecDeque<T, A> {
176176
self.len += 1;
177177
}
178178

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

1986+
/// Prepends all elements from the iterator to the front of the deque, as if [`push_front`][VecDeque::push_front] was called with the elements of the iterator.
1987+
///
1988+
/// # Examples
1989+
///
1990+
/// ```
1991+
/// #![feature(deque_extend_front)]
1992+
/// use std::collections::VecDeque;
1993+
///
1994+
/// let mut deque = VecDeque::from([4, 5, 6]);
1995+
/// deque.extend_front([3, 2, 1]);
1996+
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
1997+
/// ```
1998+
#[unstable(feature = "deque_extend_front", issue = "none")]
1999+
#[track_caller]
2000+
pub fn extend_front<I: IntoIterator<Item = T>>(&mut self, iter: I) {
2001+
<Self as SpecExtendFront<T, I::IntoIter>>::spec_extend_front(self, iter.into_iter());
2002+
}
2003+
19712004
#[inline]
19722005
fn is_contiguous(&self) -> bool {
19732006
// Do the calculation like this to avoid overflowing if len + head > usize::MAX

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

Lines changed: 57 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

@@ -120,3 +122,58 @@ where
120122
}
121123
}
122124
}
125+
126+
// Specialization trait used for VecDeque::extend_front
127+
pub(super) trait SpecExtendFront<T, I> {
128+
#[track_caller]
129+
fn spec_extend_front(&mut self, iter: I);
130+
}
131+
132+
impl<T, I, A: Allocator> SpecExtendFront<T, I> for VecDeque<T, A>
133+
where
134+
I: Iterator<Item = T>,
135+
{
136+
#[track_caller]
137+
default fn spec_extend_front(&mut self, mut iter: I) {
138+
// This function should be the moral equivalent of:
139+
//
140+
// for item in iter {
141+
// self.push_front(item);
142+
// }
143+
144+
while let Some(element) = iter.next() {
145+
let (lower, _) = iter.size_hint();
146+
self.reserve(lower.saturating_add(1));
147+
148+
// SAFETY: We just reserved space for at least one element.
149+
unsafe { self.push_front_unchecked(element) };
150+
151+
// Inner loop to avoid repeatedly calling `reserve`.
152+
while self.len < self.capacity() {
153+
let Some(element) = iter.next() else {
154+
return;
155+
};
156+
// SAFETY: The loop condition guarantees that `self.len() < self.capacity()`.
157+
unsafe { self.push_front_unchecked(element) };
158+
}
159+
}
160+
}
161+
}
162+
163+
#[cfg(not(test))]
164+
impl<T, A: Allocator> SpecExtendFront<T, Rev<vec::IntoIter<T>>> for VecDeque<T, A> {
165+
#[track_caller]
166+
fn spec_extend_front(&mut self, iterator: Rev<vec::IntoIter<T>>) {
167+
let mut iterator = iterator.into_inner();
168+
169+
let slice = iterator.as_slice();
170+
self.reserve(slice.len());
171+
172+
unsafe {
173+
self.head = self.wrap_sub(self.head, slice.len());
174+
self.copy_slice(self.head, slice);
175+
self.len += slice.len();
176+
}
177+
iterator.forget_remaining_elements();
178+
}
179+
}

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
#![feature(ptr_alignment_type)]
140140
#![feature(ptr_internals)]
141141
#![feature(ptr_metadata)]
142+
#![feature(rev_into_inner)]
142143
#![feature(set_ptr_value)]
143144
#![feature(sized_type_properties)]
144145
#![feature(slice_from_ptr_range)]

0 commit comments

Comments
 (0)