Skip to content

Commit 7d7e665

Browse files
committed
Implement VecDeque::truncate_front()
Tracking issue: #140667 Signed-off-by: Vladimir Krivopalov <[email protected]>
1 parent 0eb0b8c commit 7d7e665

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

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

+66
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,72 @@ impl<T, A: Allocator> VecDeque<T, A> {
11881188
}
11891189
}
11901190

1191+
/// Shortens the deque, keeping the last `len` elements and dropping
1192+
/// the rest.
1193+
///
1194+
/// If `len` is greater or equal to the deque's current length, this has
1195+
/// no effect.
1196+
///
1197+
/// # Examples
1198+
///
1199+
/// ```
1200+
/// use std::collections::VecDeque;
1201+
///
1202+
/// let mut buf = VecDeque::new();
1203+
/// buf.push_front(5);
1204+
/// buf.push_front(10);
1205+
/// buf.push_front(15);
1206+
/// assert_eq!(buf, [15, 10, 5]);
1207+
/// assert_eq!(buf.as_slices(), (&[15, 10, 5][..], &[][..]));
1208+
/// buf.truncate_front(1);
1209+
/// assert_eq!(buf.as_slices(), (&[5][..], &[][..]));
1210+
/// ```
1211+
#[unstable(feature = "vec_deque_truncate_front", issue = "140667")]
1212+
pub fn truncate_front(&mut self, len: usize) {
1213+
/// Runs the destructor for all items in the slice when it gets dropped (normally or
1214+
/// during unwinding).
1215+
struct Dropper<'a, T>(&'a mut [T]);
1216+
1217+
impl<'a, T> Drop for Dropper<'a, T> {
1218+
fn drop(&mut self) {
1219+
unsafe {
1220+
ptr::drop_in_place(self.0);
1221+
}
1222+
}
1223+
}
1224+
1225+
unsafe {
1226+
if len >= self.len {
1227+
// No action is taken
1228+
return;
1229+
}
1230+
1231+
let (front, back) = self.as_mut_slices();
1232+
if len > back.len() {
1233+
// The 'back' slice remains unchanged.
1234+
// front.len() + back.len() == self.len, so 'end' is non-negative
1235+
// and end < front.len()
1236+
let end = front.len() - (len - back.len());
1237+
let drop_front = front.get_unchecked_mut(..end) as *mut _;
1238+
self.head += end;
1239+
self.len = len;
1240+
ptr::drop_in_place(drop_front);
1241+
} else {
1242+
let drop_front = front as *mut _;
1243+
// 'end' is non-negative by the condition above
1244+
let end = back.len() - len;
1245+
let drop_back = back.get_unchecked_mut(..end) as *mut _;
1246+
self.head = self.to_physical_idx(self.len - len);
1247+
self.len = len;
1248+
1249+
// Make sure the second half is dropped even when a destructor
1250+
// in the first one panics.
1251+
let _back_dropper = Dropper(&mut *drop_back);
1252+
ptr::drop_in_place(drop_front);
1253+
}
1254+
}
1255+
}
1256+
11911257
/// Returns a reference to the underlying allocator.
11921258
#[unstable(feature = "allocator_api", issue = "32838")]
11931259
#[inline]

library/alloctests/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#![feature(str_as_str)]
3838
#![feature(strict_provenance_lints)]
3939
#![feature(vec_deque_pop_if)]
40+
#![feature(vec_deque_truncate_front)]
4041
#![feature(unique_rc_arc)]
4142
#![feature(macro_metavar_expr_concat)]
4243
#![allow(internal_features)]

library/alloctests/tests/vec_deque.rs

+69
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,40 @@ fn truncate_leak() {
16861686
assert_eq!(unsafe { DROPS }, 7);
16871687
}
16881688

1689+
#[test]
1690+
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
1691+
fn truncate_front_leak() {
1692+
static mut DROPS: i32 = 0;
1693+
1694+
struct D(bool);
1695+
1696+
impl Drop for D {
1697+
fn drop(&mut self) {
1698+
unsafe {
1699+
DROPS += 1;
1700+
}
1701+
1702+
if self.0 {
1703+
panic!("panic in `drop`");
1704+
}
1705+
}
1706+
}
1707+
1708+
let mut q = VecDeque::new();
1709+
q.push_back(D(false));
1710+
q.push_back(D(false));
1711+
q.push_back(D(false));
1712+
q.push_back(D(false));
1713+
q.push_back(D(false));
1714+
q.push_front(D(true));
1715+
q.push_front(D(false));
1716+
q.push_front(D(false));
1717+
1718+
catch_unwind(AssertUnwindSafe(|| q.truncate_front(1))).ok();
1719+
1720+
assert_eq!(unsafe { DROPS }, 7);
1721+
}
1722+
16891723
#[test]
16901724
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
16911725
fn test_drain_leak() {
@@ -1863,3 +1897,38 @@ fn test_collect_from_into_iter_keeps_allocation() {
18631897
assert_eq!(v.capacity(), 13);
18641898
}
18651899
}
1900+
1901+
#[test]
1902+
fn test_truncate_front() {
1903+
let mut v = VecDeque::with_capacity(13);
1904+
v.extend(0..7);
1905+
assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
1906+
v.truncate_front(10);
1907+
assert_eq!(v.len(), 7);
1908+
assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
1909+
v.truncate_front(7);
1910+
assert_eq!(v.len(), 7);
1911+
assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
1912+
v.truncate_front(3);
1913+
assert_eq!(v.as_slices(), ([4, 5, 6].as_slice(), [].as_slice()));
1914+
assert_eq!(v.len(), 3);
1915+
v.truncate_front(0);
1916+
assert_eq!(v.as_slices(), ([].as_slice(), [].as_slice()));
1917+
assert_eq!(v.len(), 0);
1918+
1919+
v.clear();
1920+
v.extend(0..7);
1921+
assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice()));
1922+
v.push_front(9);
1923+
v.push_front(8);
1924+
v.push_front(7);
1925+
assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice()));
1926+
v.truncate_front(12);
1927+
assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice()));
1928+
v.truncate_front(10);
1929+
assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice()));
1930+
v.truncate_front(8);
1931+
assert_eq!(v.as_slices(), ([9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice()));
1932+
v.truncate_front(5);
1933+
assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice()));
1934+
}

0 commit comments

Comments
 (0)