Skip to content

Commit 34ed582

Browse files
committed
Add a range argument to vec.extract_if
1 parent ee612c4 commit 34ed582

File tree

3 files changed

+81
-30
lines changed

3 files changed

+81
-30
lines changed

Diff for: library/alloc/src/vec/extract_if.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::alloc::{Allocator, Global};
1414
/// #![feature(extract_if)]
1515
///
1616
/// let mut v = vec![0, 1, 2];
17-
/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0);
17+
/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0);
1818
/// ```
1919
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
2020
#[derive(Debug)]
@@ -30,6 +30,8 @@ pub struct ExtractIf<
3030
pub(super) vec: &'a mut Vec<T, A>,
3131
/// The index of the item that will be inspected by the next call to `next`.
3232
pub(super) idx: usize,
33+
/// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`.
34+
pub(super) end: usize,
3335
/// The number of items that have been drained (removed) thus far.
3436
pub(super) del: usize,
3537
/// The original length of `vec` prior to draining.
@@ -42,6 +44,17 @@ impl<T, F, A: Allocator> ExtractIf<'_, T, F, A>
4244
where
4345
F: FnMut(&mut T) -> bool,
4446
{
47+
pub(super) fn new(vec: &mut Vec<T, A>, pred: F, range: core::ops::RangeFull) -> Self {
48+
let old_len = vec.len();
49+
let Range { start, end } = slice::range(range, ..old_len);
50+
51+
// Guard against the vec getting leaked (leak amplification)
52+
unsafe {
53+
vec.set_len(0);
54+
}
55+
ExtractIf { vec: self, idx: start, del: 0, end, old_len, pred: filter }
56+
}
57+
4558
/// Returns a reference to the underlying allocator.
4659
#[unstable(feature = "allocator_api", issue = "32838")]
4760
#[inline]
@@ -59,7 +72,7 @@ where
5972

6073
fn next(&mut self) -> Option<T> {
6174
unsafe {
62-
while self.idx < self.old_len {
75+
while self.idx < self.end {
6376
let i = self.idx;
6477
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
6578
let drained = (self.pred)(&mut v[i]);
@@ -82,7 +95,7 @@ where
8295
}
8396

8497
fn size_hint(&self) -> (usize, Option<usize>) {
85-
(0, Some(self.old_len - self.idx))
98+
(0, Some(self.end - self.idx))
8699
}
87100
}
88101

Diff for: library/alloc/src/vec/mod.rs

+28-15
Original file line numberDiff line numberDiff line change
@@ -3610,12 +3610,15 @@ impl<T, A: Allocator> Vec<T, A> {
36103610
Splice { drain: self.drain(range), replace_with: replace_with.into_iter() }
36113611
}
36123612

3613-
/// Creates an iterator which uses a closure to determine if an element should be removed.
3613+
/// Creates an iterator which uses a closure to determine if element in the range should be removed.
36143614
///
36153615
/// If the closure returns true, then the element is removed and yielded.
36163616
/// If the closure returns false, the element will remain in the vector and will not be yielded
36173617
/// by the iterator.
36183618
///
3619+
/// Only elements that fall in the provided range are considered for extraction, but any elements
3620+
/// after the range will still have to be moved if any element has been extracted.
3621+
///
36193622
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
36203623
/// or the iteration short-circuits, then the remaining elements will be retained.
36213624
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
@@ -3625,10 +3628,12 @@ impl<T, A: Allocator> Vec<T, A> {
36253628
/// Using this method is equivalent to the following code:
36263629
///
36273630
/// ```
3631+
/// # use std::cmp::min;
36283632
/// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 };
36293633
/// # let mut vec = vec![1, 2, 3, 4, 5, 6];
3630-
/// let mut i = 0;
3631-
/// while i < vec.len() {
3634+
/// # let range = 1..4;
3635+
/// let mut i = range.start;
3636+
/// while i < min(vec.len(), range.end) {
36323637
/// if some_predicate(&mut vec[i]) {
36333638
/// let val = vec.remove(i);
36343639
/// // your code here
@@ -3643,8 +3648,12 @@ impl<T, A: Allocator> Vec<T, A> {
36433648
/// But `extract_if` is easier to use. `extract_if` is also more efficient,
36443649
/// because it can backshift the elements of the array in bulk.
36453650
///
3646-
/// Note that `extract_if` also lets you mutate every element in the filter closure,
3647-
/// regardless of whether you choose to keep or remove it.
3651+
/// Note that `extract_if` also lets you mutate the elements passed to the filter closure,
3652+
/// regardless of whether you choose to keep or remove them.
3653+
///
3654+
/// # Panics
3655+
///
3656+
/// If `range`` is out of bounds.
36483657
///
36493658
/// # Examples
36503659
///
@@ -3654,25 +3663,29 @@ impl<T, A: Allocator> Vec<T, A> {
36543663
/// #![feature(extract_if)]
36553664
/// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
36563665
///
3657-
/// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
3666+
/// let evens = numbers.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>();
36583667
/// let odds = numbers;
36593668
///
36603669
/// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
36613670
/// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
36623671
/// ```
3672+
///
3673+
/// Using the range argument to only process a part of the vector:
3674+
///
3675+
/// ```
3676+
/// #![feature(extract_if)]
3677+
/// let mut items = vec![0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2];
3678+
/// let ones = items.extract_if(7.., |x| *x == 1).collect::<Vec<_>>();
3679+
/// assert_eq!(items, vec![0, 0, 0, 0, 0, 0, 0, 2, 2, 2]);
3680+
/// assert_eq!(ones.len(), 3);
3681+
/// ```
36633682
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
3664-
pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F, A>
3683+
pub fn extract_if<F, R>(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, A>
36653684
where
36663685
F: FnMut(&mut T) -> bool,
3686+
R: RangeBounds<usize>,
36673687
{
3668-
let old_len = self.len();
3669-
3670-
// Guard against us getting leaked (leak amplification)
3671-
unsafe {
3672-
self.set_len(0);
3673-
}
3674-
3675-
ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter }
3688+
ExtractIf::new(self, pred, range)
36763689
}
36773690
}
36783691

Diff for: library/alloc/tests/vec.rs

+37-12
Original file line numberDiff line numberDiff line change
@@ -1414,7 +1414,7 @@ fn extract_if_empty() {
14141414
let mut vec: Vec<i32> = vec![];
14151415

14161416
{
1417-
let mut iter = vec.extract_if(|_| true);
1417+
let mut iter = vec.extract_if(.., |_| true);
14181418
assert_eq!(iter.size_hint(), (0, Some(0)));
14191419
assert_eq!(iter.next(), None);
14201420
assert_eq!(iter.size_hint(), (0, Some(0)));
@@ -1431,7 +1431,7 @@ fn extract_if_zst() {
14311431
let initial_len = vec.len();
14321432
let mut count = 0;
14331433
{
1434-
let mut iter = vec.extract_if(|_| true);
1434+
let mut iter = vec.extract_if(.., |_| true);
14351435
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
14361436
while let Some(_) = iter.next() {
14371437
count += 1;
@@ -1454,7 +1454,7 @@ fn extract_if_false() {
14541454
let initial_len = vec.len();
14551455
let mut count = 0;
14561456
{
1457-
let mut iter = vec.extract_if(|_| false);
1457+
let mut iter = vec.extract_if(.., |_| false);
14581458
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
14591459
for _ in iter.by_ref() {
14601460
count += 1;
@@ -1476,7 +1476,7 @@ fn extract_if_true() {
14761476
let initial_len = vec.len();
14771477
let mut count = 0;
14781478
{
1479-
let mut iter = vec.extract_if(|_| true);
1479+
let mut iter = vec.extract_if(.., |_| true);
14801480
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
14811481
while let Some(_) = iter.next() {
14821482
count += 1;
@@ -1492,6 +1492,31 @@ fn extract_if_true() {
14921492
assert_eq!(vec, vec![]);
14931493
}
14941494

1495+
#[test]
1496+
fn extract_if_ranges() {
1497+
let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1498+
1499+
let mut count = 0;
1500+
let it = vec.extract_if(1..=3, |_| {
1501+
count += 1;
1502+
true
1503+
});
1504+
assert_eq!(it.collect::<Vec<_>>(), vec![1, 2, 3]);
1505+
assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]);
1506+
assert_eq!(count, 3);
1507+
1508+
let it = vec.extract_if(1..=3, |_| false);
1509+
assert_eq!(it.collect::<Vec<_>>(), vec![]);
1510+
assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]);
1511+
}
1512+
1513+
#[test]
1514+
#[should_panic]
1515+
fn extraxt_if_out_of_bounds() {
1516+
let mut vec = vec![0, 1];
1517+
let _ = vec.extract_if(5.., |_| true).for_each(drop);
1518+
}
1519+
14951520
#[test]
14961521
fn extract_if_complex() {
14971522
{
@@ -1501,7 +1526,7 @@ fn extract_if_complex() {
15011526
39,
15021527
];
15031528

1504-
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
1529+
let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>();
15051530
assert_eq!(removed.len(), 10);
15061531
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
15071532

@@ -1515,7 +1540,7 @@ fn extract_if_complex() {
15151540
2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39,
15161541
];
15171542

1518-
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
1543+
let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>();
15191544
assert_eq!(removed.len(), 10);
15201545
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
15211546

@@ -1528,7 +1553,7 @@ fn extract_if_complex() {
15281553
let mut vec =
15291554
vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36];
15301555

1531-
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
1556+
let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>();
15321557
assert_eq!(removed.len(), 10);
15331558
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
15341559

@@ -1540,7 +1565,7 @@ fn extract_if_complex() {
15401565
// [xxxxxxxxxx+++++++++++]
15411566
let mut vec = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
15421567

1543-
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
1568+
let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>();
15441569
assert_eq!(removed.len(), 10);
15451570
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
15461571

@@ -1552,7 +1577,7 @@ fn extract_if_complex() {
15521577
// [+++++++++++xxxxxxxxxx]
15531578
let mut vec = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20];
15541579

1555-
let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
1580+
let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>();
15561581
assert_eq!(removed.len(), 10);
15571582
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
15581583

@@ -1600,7 +1625,7 @@ fn extract_if_consumed_panic() {
16001625
}
16011626
c.index < 6
16021627
};
1603-
let drain = data.extract_if(filter);
1628+
let drain = data.extract_if(.., filter);
16041629

16051630
// NOTE: The ExtractIf is explicitly consumed
16061631
drain.for_each(drop);
@@ -1653,7 +1678,7 @@ fn extract_if_unconsumed_panic() {
16531678
}
16541679
c.index < 6
16551680
};
1656-
let _drain = data.extract_if(filter);
1681+
let _drain = data.extract_if(.., filter);
16571682

16581683
// NOTE: The ExtractIf is dropped without being consumed
16591684
});
@@ -1669,7 +1694,7 @@ fn extract_if_unconsumed_panic() {
16691694
#[test]
16701695
fn extract_if_unconsumed() {
16711696
let mut vec = vec![1, 2, 3, 4];
1672-
let drain = vec.extract_if(|&mut x| x % 2 != 0);
1697+
let drain = vec.extract_if(.., |&mut x| x % 2 != 0);
16731698
drop(drain);
16741699
assert_eq!(vec, [1, 2, 3, 4]);
16751700
}

0 commit comments

Comments
 (0)