Skip to content

Commit cdf4143

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

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

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

+67
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,73 @@ 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+
/// # #![feature(vec_deque_truncate_front)]
1201+
/// use std::collections::VecDeque;
1202+
///
1203+
/// let mut buf = VecDeque::new();
1204+
/// buf.push_front(5);
1205+
/// buf.push_front(10);
1206+
/// buf.push_front(15);
1207+
/// assert_eq!(buf, [15, 10, 5]);
1208+
/// assert_eq!(buf.as_slices(), (&[15, 10, 5][..], &[][..]));
1209+
/// buf.truncate_front(1);
1210+
/// assert_eq!(buf.as_slices(), (&[5][..], &[][..]));
1211+
/// ```
1212+
#[unstable(feature = "vec_deque_truncate_front", issue = "140667")]
1213+
pub fn truncate_front(&mut self, len: usize) {
1214+
/// Runs the destructor for all items in the slice when it gets dropped (normally or
1215+
/// during unwinding).
1216+
struct Dropper<'a, T>(&'a mut [T]);
1217+
1218+
impl<'a, T> Drop for Dropper<'a, T> {
1219+
fn drop(&mut self) {
1220+
unsafe {
1221+
ptr::drop_in_place(self.0);
1222+
}
1223+
}
1224+
}
1225+
1226+
unsafe {
1227+
if len >= self.len {
1228+
// No action is taken
1229+
return;
1230+
}
1231+
1232+
let (front, back) = self.as_mut_slices();
1233+
if len > back.len() {
1234+
// The 'back' slice remains unchanged.
1235+
// front.len() + back.len() == self.len, so 'end' is non-negative
1236+
// and end < front.len()
1237+
let end = front.len() - (len - back.len());
1238+
let drop_front = front.get_unchecked_mut(..end) as *mut _;
1239+
self.head += end;
1240+
self.len = len;
1241+
ptr::drop_in_place(drop_front);
1242+
} else {
1243+
let drop_front = front as *mut _;
1244+
// 'end' is non-negative by the condition above
1245+
let end = back.len() - len;
1246+
let drop_back = back.get_unchecked_mut(..end) as *mut _;
1247+
self.head = self.to_physical_idx(self.len - len);
1248+
self.len = len;
1249+
1250+
// Make sure the second half is dropped even when a destructor
1251+
// in the first one panics.
1252+
let _back_dropper = Dropper(&mut *drop_back);
1253+
ptr::drop_in_place(drop_front);
1254+
}
1255+
}
1256+
}
1257+
11911258
/// Returns a reference to the underlying allocator.
11921259
#[unstable(feature = "allocator_api", issue = "32838")]
11931260
#[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)