-
-
Notifications
You must be signed in to change notification settings - Fork 15.4k
Implement VecDeque::truncate_to_range
#156220
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: main
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 |
|---|---|---|
|
|
@@ -133,21 +133,21 @@ impl<T: Clone, A: Allocator + Clone> Clone for VecDeque<T, A> { | |
| } | ||
| } | ||
|
|
||
| #[stable(feature = "rust1", since = "1.0.0")] | ||
| unsafe impl<#[may_dangle] T, A: Allocator> Drop for VecDeque<T, A> { | ||
| fn drop(&mut self) { | ||
| /// Runs the destructor for all items in the slice when it gets dropped (normally or | ||
| /// during unwinding). | ||
| struct Dropper<'a, T>(&'a mut [T]); | ||
| /// Runs the destructor for all items in the slice when it gets dropped (normally or | ||
| /// during unwinding). | ||
| struct Dropper<'a, T>(&'a mut [T]); | ||
|
|
||
| impl<'a, T> Drop for Dropper<'a, T> { | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| ptr::drop_in_place(self.0); | ||
| } | ||
| } | ||
| impl<T> Drop for Dropper<'_, T> { | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| ptr::drop_in_place(self.0); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[stable(feature = "rust1", since = "1.0.0")] | ||
| unsafe impl<#[may_dangle] T, A: Allocator> Drop for VecDeque<T, A> { | ||
| fn drop(&mut self) { | ||
| let (front, back) = self.as_mut_slices(); | ||
| unsafe { | ||
| let _back_dropper = Dropper(back); | ||
|
|
@@ -1433,18 +1433,6 @@ impl<T, A: Allocator> VecDeque<T, A> { | |
| #[doc(alias = "retain_front")] | ||
| #[stable(feature = "deque_extras", since = "1.16.0")] | ||
| pub fn truncate(&mut self, len: usize) { | ||
| /// Runs the destructor for all items in the slice when it gets dropped (normally or | ||
| /// during unwinding). | ||
| struct Dropper<'a, T>(&'a mut [T]); | ||
|
|
||
| impl<'a, T> Drop for Dropper<'a, T> { | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| ptr::drop_in_place(self.0); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Safe because: | ||
| // | ||
| // * Any slice passed to `drop_in_place` is valid; the second case has | ||
|
|
@@ -1499,18 +1487,6 @@ impl<T, A: Allocator> VecDeque<T, A> { | |
| #[doc(alias = "truncate_front")] | ||
| #[stable(feature = "vec_deque_truncate_front", since = "CURRENT_RUSTC_VERSION")] | ||
| pub fn retain_back(&mut self, len: usize) { | ||
| /// Runs the destructor for all items in the slice when it gets dropped (normally or | ||
| /// during unwinding). | ||
| struct Dropper<'a, T>(&'a mut [T]); | ||
|
|
||
| impl<'a, T> Drop for Dropper<'a, T> { | ||
| fn drop(&mut self) { | ||
| unsafe { | ||
| ptr::drop_in_place(self.0); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| unsafe { | ||
| if len >= self.len { | ||
| // No action is taken | ||
|
|
@@ -1543,6 +1519,92 @@ impl<T, A: Allocator> VecDeque<T, A> { | |
| } | ||
| } | ||
|
|
||
| /// Shortens the deque to the elements within `range`, dropping the rest. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// Panics if the starting point is greater than the end point or if | ||
| /// the end point is greater than the length of the deque. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// ``` | ||
| /// # #![feature(vec_deque_retain_range)] | ||
| /// use std::collections::VecDeque; | ||
| /// | ||
| /// let mut buf: VecDeque<_> = (0..6).collect(); | ||
| /// buf.truncate_to_range(2..5); | ||
| /// assert_eq!(buf, [2, 3, 4]); | ||
| /// ``` | ||
| #[unstable(feature = "vec_deque_retain_range", issue = "156215")] | ||
| pub fn truncate_to_range<R>(&mut self, range: R) | ||
| where | ||
| R: RangeBounds<usize>, | ||
| { | ||
| let Range { start, end } = slice::range(range, ..self.len); | ||
|
|
||
| if start == 0 && end == self.len { | ||
| return; | ||
| } else if start == end { | ||
| self.clear(); | ||
| return; | ||
| } else if start == 0 { | ||
| self.truncate(end); | ||
| return; | ||
| } else if end == self.len { | ||
| self.retain_back(self.len - start); | ||
| return; | ||
| } | ||
|
|
||
| // Both the dropped prefix [0..start) and the dropped suffix [end..self.len) are | ||
| // non-empty. Plan up to three physical slices to drop, then update head/len, then | ||
| // drop. Only one of the dropped prefix or dropped suffix can cross between slices. | ||
| let (front, back) = self.as_mut_slices(); | ||
| let flen = front.len(); | ||
| let blen = back.len(); | ||
| let fptr = front.as_mut_ptr(); | ||
| let bptr = back.as_mut_ptr(); | ||
|
|
||
| unsafe { | ||
| let (drop_a, drop_b, drop_c) = if end <= flen { | ||
| // Kept range lies in `front`. The dropped suffix is the rest of `front` | ||
| // plus all of `back`. | ||
| let pre = ptr::slice_from_raw_parts_mut(fptr, start); | ||
| let mid = ptr::slice_from_raw_parts_mut(fptr.add(end), flen - end); | ||
| (pre, mid, Some(back as *mut [T])) | ||
| } else if start >= flen { | ||
| // Kept range lies in `back`. The dropped prefix is all of `front` plus the | ||
| // start of `back`. | ||
| let mid = ptr::slice_from_raw_parts_mut(bptr, start - flen); | ||
| let suf = ptr::slice_from_raw_parts_mut(bptr.add(end - flen), blen - (end - flen)); | ||
| (front as *mut [T], mid, Some(suf)) | ||
| } else { | ||
| // Kept range straddles the boundary. The dropped prefix is in `front`, the | ||
| // dropped suffix is in `back`. Only two regions to drop. | ||
| let pre = ptr::slice_from_raw_parts_mut(fptr, start); | ||
| let suf = ptr::slice_from_raw_parts_mut(bptr.add(end - flen), blen - (end - flen)); | ||
| (pre, suf, None) | ||
| }; | ||
|
|
||
| // Set these once only, then drop. If we called truncate + retain_back, a panic in | ||
| // a destructor could leave this truncation in a half completed state. | ||
| self.head = self.to_wrapped_index(start); | ||
| self.len = end - start; | ||
|
|
||
| match drop_c { | ||
| Some(c) => { | ||
| let _g_a = Dropper(&mut *drop_a); | ||
| let _g_b = Dropper(&mut *drop_b); | ||
| ptr::drop_in_place(c); | ||
|
Contributor
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. without dropper, won't this leak on panic ? same for line 1537
Member
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. Where would it panic?
Contributor
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. Right, i see |
||
| } | ||
| None => { | ||
| let _g_a = Dropper(&mut *drop_a); | ||
| ptr::drop_in_place(drop_b); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Returns a reference to the underlying allocator. | ||
| #[unstable(feature = "allocator_api", issue = "32838")] | ||
| #[inline] | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
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.
Would it make sense to add a fast path for types that don’t need dropping? Something like:
around line 1493
what do you think ?
View changes since the review