Skip to content

Commit 8cab6b8

Browse files
committed
Implement VecDeque::truncate_to_range
1 parent d4aeea3 commit 8cab6b8

3 files changed

Lines changed: 202 additions & 0 deletions

File tree

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

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,92 @@ impl<T, A: Allocator> VecDeque<T, A> {
14541454
}
14551455
}
14561456

1457+
/// Shortens the deque to the elements within `range`, dropping the rest.
1458+
///
1459+
/// # Panics
1460+
///
1461+
/// Panics if the starting point is greater than the end point or if
1462+
/// the end point is greater than the length of the deque.
1463+
///
1464+
/// # Examples
1465+
///
1466+
/// ```
1467+
/// # #![feature(vec_deque_truncate_to_range)]
1468+
/// use std::collections::VecDeque;
1469+
///
1470+
/// let mut buf: VecDeque<_> = (0..6).collect();
1471+
/// buf.truncate_to_range(2..5);
1472+
/// assert_eq!(buf, [2, 3, 4]);
1473+
/// ```
1474+
#[unstable(feature = "vec_deque_truncate_to_range", issue = "156215")]
1475+
pub fn truncate_to_range<R>(&mut self, range: R)
1476+
where
1477+
R: RangeBounds<usize>,
1478+
{
1479+
let Range { start, end } = slice::range(range, ..self.len);
1480+
1481+
if start == 0 && end == self.len {
1482+
return;
1483+
} else if start == end {
1484+
self.clear();
1485+
return;
1486+
} else if start == 0 {
1487+
self.truncate(end);
1488+
return;
1489+
} else if end == self.len {
1490+
self.truncate_front(self.len - start);
1491+
return;
1492+
}
1493+
1494+
// Both the dropped prefix [0..start) and the dropped suffix [end..self.len) are
1495+
// non-empty. Plan up to three physical slices to drop, then update head/len, then
1496+
// drop. Only one of the dropped prefix or dropped suffix can cross between slices.
1497+
let (front, back) = self.as_mut_slices();
1498+
let flen = front.len();
1499+
let blen = back.len();
1500+
let fptr = front.as_mut_ptr();
1501+
let bptr = back.as_mut_ptr();
1502+
1503+
unsafe {
1504+
let (drop_a, drop_b, drop_c) = if end <= flen {
1505+
// Kept range lies in `front`. The dropped suffix is the rest of `front`
1506+
// plus all of `back`.
1507+
let pre = ptr::slice_from_raw_parts_mut(fptr, start);
1508+
let mid = ptr::slice_from_raw_parts_mut(fptr.add(end), flen - end);
1509+
(pre, mid, Some(back as *mut [T]))
1510+
} else if start >= flen {
1511+
// Kept range lies in `back`. The dropped prefix is all of `front` plus the
1512+
// start of `back`.
1513+
let mid = ptr::slice_from_raw_parts_mut(bptr, start - flen);
1514+
let suf = ptr::slice_from_raw_parts_mut(bptr.add(end - flen), blen - (end - flen));
1515+
(front as *mut [T], mid, Some(suf))
1516+
} else {
1517+
// Kept range straddles the boundary. The dropped prefix is in `front`, the
1518+
// dropped suffix is in `back`. Only two regions to drop.
1519+
let pre = ptr::slice_from_raw_parts_mut(fptr, start);
1520+
let suf = ptr::slice_from_raw_parts_mut(bptr.add(end - flen), blen - (end - flen));
1521+
(pre, suf, None)
1522+
};
1523+
1524+
// Set these once only, then drop. If we called truncate + truncate_front, a panic in
1525+
// a destructor could leave this truncation in a half completed state.
1526+
self.head = self.to_physical_idx(start);
1527+
self.len = end - start;
1528+
1529+
match drop_c {
1530+
Some(c) => {
1531+
let _g_a = Dropper(&mut *drop_a);
1532+
let _g_b = Dropper(&mut *drop_b);
1533+
ptr::drop_in_place(c);
1534+
}
1535+
None => {
1536+
let _g_a = Dropper(&mut *drop_a);
1537+
ptr::drop_in_place(drop_b);
1538+
}
1539+
}
1540+
}
1541+
}
1542+
14571543
/// Returns a reference to the underlying allocator.
14581544
#[unstable(feature = "allocator_api", issue = "32838")]
14591545
#[inline]

library/alloctests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#![feature(strict_provenance_lints)]
3838
#![feature(string_replace_in_place)]
3939
#![feature(vec_deque_truncate_front)]
40+
#![feature(vec_deque_truncate_to_range)]
4041
#![feature(unique_rc_arc)]
4142
#![feature(macro_metavar_expr_concat)]
4243
#![feature(vec_peek_mut)]

library/alloctests/tests/vec_deque.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,3 +2360,118 @@ fn test_splice_wrapping_and_resize() {
23602360

23612361
assert_eq!(Vec::from(vec), [1, 2, 3, 4, 1, 1, 1, 1, 1])
23622362
}
2363+
2364+
#[test]
2365+
fn truncate_to_range_basic() {
2366+
// no-op
2367+
let mut v: VecDeque<_> = (0..6).collect();
2368+
v.truncate_to_range(..);
2369+
assert_eq!(v, [0, 1, 2, 3, 4, 5]);
2370+
2371+
// clear
2372+
let mut v: VecDeque<_> = (0..6).collect();
2373+
v.truncate_to_range(3..3);
2374+
assert_eq!(v, [] as [i32; 0]);
2375+
2376+
// truncate
2377+
let mut v: VecDeque<_> = (0..6).collect();
2378+
v.truncate_to_range(..3);
2379+
assert_eq!(v, [0, 1, 2]);
2380+
2381+
// truncate front
2382+
let mut v: VecDeque<_> = (0..6).collect();
2383+
v.truncate_to_range(2..);
2384+
assert_eq!(v, [2, 3, 4, 5]);
2385+
2386+
let mut v: VecDeque<_> = (0..6).collect();
2387+
v.truncate_to_range(2..5);
2388+
assert_eq!(v, [2, 3, 4]);
2389+
2390+
let mut v: VecDeque<_> = (0..6).collect();
2391+
v.truncate_to_range(3..=5);
2392+
assert_eq!(v, [3, 4, 5]);
2393+
2394+
let mut v: VecDeque<_> = (0..6).collect();
2395+
v.truncate_to_range(..=3);
2396+
assert_eq!(v, [0, 1, 2, 3]);
2397+
}
2398+
2399+
fn make_wrapped() -> VecDeque<i32> {
2400+
let mut v = VecDeque::new();
2401+
v.extend(0..5);
2402+
v.push_front(-1);
2403+
v.push_front(-2);
2404+
v.push_front(-3);
2405+
assert_eq!(v.as_slices(), ([-3, -2, -1].as_slice(), [0, 1, 2, 3, 4].as_slice()));
2406+
v
2407+
}
2408+
2409+
#[test]
2410+
fn truncate_to_range_kept_in_front() {
2411+
let mut v = make_wrapped();
2412+
v.truncate_to_range(1..3);
2413+
assert_eq!(v, [-2, -1]);
2414+
}
2415+
2416+
#[test]
2417+
fn truncate_to_range_kept_in_back() {
2418+
let mut v = make_wrapped();
2419+
v.truncate_to_range(4..7);
2420+
assert_eq!(v, [1, 2, 3]);
2421+
}
2422+
2423+
#[test]
2424+
fn truncate_to_range_kept_straddles() {
2425+
let mut v = make_wrapped();
2426+
v.truncate_to_range(1..6);
2427+
assert_eq!(v, [-2, -1, 0, 1, 2]);
2428+
}
2429+
2430+
#[test]
2431+
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
2432+
fn truncate_to_range_leak() {
2433+
struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } );
2434+
2435+
let mut q = VecDeque::new();
2436+
q.push_back(D(true));
2437+
q.push_back(D(false));
2438+
q.push_back(D(false));
2439+
q.push_back(D(false));
2440+
q.push_back(D(false));
2441+
q.push_front(D(false));
2442+
q.push_front(D(false));
2443+
q.push_front(D(false));
2444+
2445+
catch_unwind(AssertUnwindSafe(|| q.truncate_to_range(4..7))).ok();
2446+
2447+
assert_eq!(DROPS.get(), 5);
2448+
}
2449+
2450+
#[test]
2451+
#[should_panic]
2452+
fn truncate_to_range_start_greater_than_end() {
2453+
let mut v: VecDeque<_> = (0..6).collect();
2454+
#[allow(clippy::reversed_empty_ranges)]
2455+
v.truncate_to_range(4..2);
2456+
}
2457+
2458+
#[test]
2459+
#[should_panic]
2460+
fn truncate_to_range_end_past_len() {
2461+
let mut v: VecDeque<_> = (0..6).collect();
2462+
v.truncate_to_range(2..7);
2463+
}
2464+
2465+
#[test]
2466+
#[should_panic]
2467+
fn truncate_to_range_start_past_len() {
2468+
let mut v: VecDeque<_> = (0..6).collect();
2469+
v.truncate_to_range(7..8);
2470+
}
2471+
2472+
#[test]
2473+
#[should_panic]
2474+
fn truncate_to_range_inclusive_end_overflow() {
2475+
let mut v: VecDeque<_> = (0..6).collect();
2476+
v.truncate_to_range(0..=usize::MAX);
2477+
}

0 commit comments

Comments
 (0)