Skip to content

Commit 1fbeacf

Browse files
committed
add extend_front to VecDeque with specialization like extend (unfinished)
1 parent 21a13b8 commit 1fbeacf

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

@@ -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,24 @@ impl<T, A: Allocator> VecDeque<T, A> {
19561971
unsafe { self.buffer_write(self.to_physical_idx(len), value) }
19571972
}
19581973

1974+
/// 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.
1975+
///
1976+
/// # Examples
1977+
///
1978+
/// ```
1979+
/// #![feature(deque_extend_front)]
1980+
/// use std::collections::VecDeque;
1981+
///
1982+
/// let mut deque = VecDeque::from([4, 5, 6]);
1983+
/// deque.extend_front([3, 2, 1]);
1984+
/// assert_eq!(deque, [1, 2, 3, 4, 5, 6]);
1985+
/// ```
1986+
#[unstable(feature = "deque_extend_front", issue = "none")]
1987+
#[track_caller]
1988+
pub fn extend_front<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1989+
<Self as SpecExtendFront<T, I::IntoIter>>::spec_extend_front(self, iter.into_iter());
1990+
}
1991+
19591992
#[inline]
19601993
fn is_contiguous(&self) -> bool {
19611994
// 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

@@ -114,3 +116,58 @@ 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, Rev<vec::IntoIter<T>>> for VecDeque<T, A> {
159+
#[track_caller]
160+
fn spec_extend_front(&mut self, iterator: Rev<vec::IntoIter<T>>) {
161+
let mut iterator = iterator.into_inner();
162+
163+
let slice = iterator.as_slice();
164+
self.reserve(slice.len());
165+
166+
unsafe {
167+
self.head = self.wrap_sub(self.head, slice.len());
168+
self.copy_slice(self.head, slice);
169+
self.len += slice.len();
170+
}
171+
iterator.forget_remaining_elements();
172+
}
173+
}

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)]

0 commit comments

Comments
 (0)