Implement VecDeque::truncate_front()
Tracking issue: #140667 Signed-off-by: Vladimir Krivopalov <vladimir.krivopalov@gmail.com>
This commit is contained in:
parent
0eb0b8cb67
commit
cdf4143eb8
3 changed files with 137 additions and 0 deletions
|
|
@ -1188,6 +1188,73 @@ impl<T, A: Allocator> VecDeque<T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Shortens the deque, keeping the last `len` elements and dropping
|
||||
/// the rest.
|
||||
///
|
||||
/// If `len` is greater or equal to the deque's current length, this has
|
||||
/// no effect.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(vec_deque_truncate_front)]
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut buf = VecDeque::new();
|
||||
/// buf.push_front(5);
|
||||
/// buf.push_front(10);
|
||||
/// buf.push_front(15);
|
||||
/// assert_eq!(buf, [15, 10, 5]);
|
||||
/// assert_eq!(buf.as_slices(), (&[15, 10, 5][..], &[][..]));
|
||||
/// buf.truncate_front(1);
|
||||
/// assert_eq!(buf.as_slices(), (&[5][..], &[][..]));
|
||||
/// ```
|
||||
#[unstable(feature = "vec_deque_truncate_front", issue = "140667")]
|
||||
pub fn truncate_front(&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
|
||||
return;
|
||||
}
|
||||
|
||||
let (front, back) = self.as_mut_slices();
|
||||
if len > back.len() {
|
||||
// The 'back' slice remains unchanged.
|
||||
// front.len() + back.len() == self.len, so 'end' is non-negative
|
||||
// and end < front.len()
|
||||
let end = front.len() - (len - back.len());
|
||||
let drop_front = front.get_unchecked_mut(..end) as *mut _;
|
||||
self.head += end;
|
||||
self.len = len;
|
||||
ptr::drop_in_place(drop_front);
|
||||
} else {
|
||||
let drop_front = front as *mut _;
|
||||
// 'end' is non-negative by the condition above
|
||||
let end = back.len() - len;
|
||||
let drop_back = back.get_unchecked_mut(..end) as *mut _;
|
||||
self.head = self.to_physical_idx(self.len - len);
|
||||
self.len = len;
|
||||
|
||||
// Make sure the second half is dropped even when a destructor
|
||||
// in the first one panics.
|
||||
let _back_dropper = Dropper(&mut *drop_back);
|
||||
ptr::drop_in_place(drop_front);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the underlying allocator.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#![feature(str_as_str)]
|
||||
#![feature(strict_provenance_lints)]
|
||||
#![feature(vec_deque_pop_if)]
|
||||
#![feature(vec_deque_truncate_front)]
|
||||
#![feature(unique_rc_arc)]
|
||||
#![feature(macro_metavar_expr_concat)]
|
||||
#![allow(internal_features)]
|
||||
|
|
|
|||
|
|
@ -1686,6 +1686,40 @@ fn truncate_leak() {
|
|||
assert_eq!(unsafe { DROPS }, 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn truncate_front_leak() {
|
||||
static mut DROPS: i32 = 0;
|
||||
|
||||
struct D(bool);
|
||||
|
||||
impl Drop for D {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROPS += 1;
|
||||
}
|
||||
|
||||
if self.0 {
|
||||
panic!("panic in `drop`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut q = VecDeque::new();
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_back(D(false));
|
||||
q.push_front(D(true));
|
||||
q.push_front(D(false));
|
||||
q.push_front(D(false));
|
||||
|
||||
catch_unwind(AssertUnwindSafe(|| q.truncate_front(1))).ok();
|
||||
|
||||
assert_eq!(unsafe { DROPS }, 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
|
||||
fn test_drain_leak() {
|
||||
|
|
@ -1863,3 +1897,38 @@ fn test_collect_from_into_iter_keeps_allocation() {
|
|||
assert_eq!(v.capacity(), 13);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate_front() {
|
||||
let mut v = VecDeque::with_capacity(13);
|
||||
v.extend(0..7);
|
||||
assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
|
||||
v.truncate_front(10);
|
||||
assert_eq!(v.len(), 7);
|
||||
assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
|
||||
v.truncate_front(7);
|
||||
assert_eq!(v.len(), 7);
|
||||
assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
|
||||
v.truncate_front(3);
|
||||
assert_eq!(v.as_slices(), ([4, 5, 6].as_slice(), [].as_slice()));
|
||||
assert_eq!(v.len(), 3);
|
||||
v.truncate_front(0);
|
||||
assert_eq!(v.as_slices(), ([].as_slice(), [].as_slice()));
|
||||
assert_eq!(v.len(), 0);
|
||||
|
||||
v.clear();
|
||||
v.extend(0..7);
|
||||
assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
|
||||
v.push_front(9);
|
||||
v.push_front(8);
|
||||
v.push_front(7);
|
||||
assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice()));
|
||||
v.truncate_front(12);
|
||||
assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice()));
|
||||
v.truncate_front(10);
|
||||
assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice()));
|
||||
v.truncate_front(8);
|
||||
assert_eq!(v.as_slices(), ([9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice()));
|
||||
v.truncate_front(5);
|
||||
assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice()));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue