-
Notifications
You must be signed in to change notification settings - Fork 13.8k
add extend_front to VecDeque with specialization like extend (unfinished) #146861
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
#[cfg(not(test))] | ||
use core::iter::Rev; | ||
use core::iter::TrustedLen; | ||
use core::slice; | ||
|
||
|
@@ -114,3 +116,96 @@ where | |
} | ||
} | ||
} | ||
|
||
// Specialization trait used for VecDeque::extend_front | ||
pub(super) trait SpecExtendFront<T, I> { | ||
#[track_caller] | ||
fn spec_extend_front(&mut self, iter: I); | ||
} | ||
|
||
impl<T, I, A: Allocator> SpecExtendFront<T, I> for VecDeque<T, A> | ||
where | ||
I: Iterator<Item = T>, | ||
{ | ||
#[track_caller] | ||
default fn spec_extend_front(&mut self, mut iter: I) { | ||
// This function should be the moral equivalent of: | ||
// | ||
// for item in iter { | ||
// self.push_front(item); | ||
// } | ||
|
||
while let Some(element) = iter.next() { | ||
let (lower, _) = iter.size_hint(); | ||
self.reserve(lower.saturating_add(1)); | ||
|
||
// SAFETY: We just reserved space for at least one element. | ||
unsafe { self.push_front_unchecked(element) }; | ||
|
||
// Inner loop to avoid repeatedly calling `reserve`. | ||
while self.len < self.capacity() { | ||
let Some(element) = iter.next() else { | ||
return; | ||
}; | ||
// SAFETY: The loop condition guarantees that `self.len() < self.capacity()`. | ||
unsafe { self.push_front_unchecked(element) }; | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[cfg(not(test))] | ||
impl<T, A: Allocator> SpecExtendFront<T, vec::IntoIter<T>> for VecDeque<T, A> { | ||
#[track_caller] | ||
fn spec_extend_front(&mut self, mut iterator: vec::IntoIter<T>) { | ||
let slice = iterator.as_mut_slice(); | ||
slice.reverse(); | ||
unsafe { prepend(self, slice) }; | ||
iterator.forget_remaining_elements(); | ||
} | ||
} | ||
|
||
#[cfg(not(test))] | ||
impl<T, A: Allocator> SpecExtendFront<T, Rev<vec::IntoIter<T>>> for VecDeque<T, A> { | ||
#[track_caller] | ||
fn spec_extend_front(&mut self, iterator: Rev<vec::IntoIter<T>>) { | ||
let mut iterator = iterator.into_inner(); | ||
unsafe { prepend(self, iterator.as_slice()) }; | ||
iterator.forget_remaining_elements(); | ||
} | ||
} | ||
|
||
// impl<T, A: Allocator> SpecExtendFront<T, Copied<slice::Iter<'_, T>>> for VecDeque<T, A> | ||
// where | ||
// T: Copy, | ||
// { | ||
// #[track_caller] | ||
// fn spec_extend_front(&mut self, _iter: Copied<slice::Iter<'_, T>>) { | ||
// // unsafe { prepend(self, slice) }; | ||
// // reverse in place? | ||
// } | ||
// } | ||
|
||
// impl<T, A: Allocator> SpecExtendFront<T, Rev<Copied<slice::Iter<'_, T>>>> for VecDeque<T, A> | ||
// where | ||
// T: Copy, | ||
// { | ||
// #[track_caller] | ||
// fn spec_extend_front(&mut self, iter: Rev<Copied<slice::Iter<'_, T>>>) { | ||
// unsafe { prepend(self, iter.into_inner().it.as_slice()) }; | ||
// } | ||
// } | ||
Comment on lines
+189
to
+197
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to add specialization for |
||
|
||
/// # Safety | ||
/// | ||
/// `slice` will be copied into the deque, make sure to forget the items if `T` is not `Copy`. | ||
#[cfg(not(test))] | ||
unsafe fn prepend<T, A: Allocator>(deque: &mut VecDeque<T, A>, slice: &[T]) { | ||
deque.reserve(slice.len()); | ||
|
||
unsafe { | ||
deque.head = deque.wrap_sub(deque.head, slice.len()); | ||
deque.copy_slice(deque.head, slice); | ||
deque.len += slice.len(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a curious specialization. Is the expectation that people will frequently use
Rev
to prepend to a vecdeque?Anyway, specializations should have dedicated tests since they're not covered by the regular ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This depends on the design of
extend_front
, if it will act like repeatedpush_front
, specializing this can have significant performance improvements. This would be used when prepending elements from a Vec into a VecDeque, in original order, a bit like the requestedVecDeque::prepend
(#69939 (comment)).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prepend
(see tracking issue) will use this, it callsself.extend_front(other.into_iter().rev())