rustc_data_structures/
thinvec.rs

1//! This is a copy-paste of `Vec::extract_if` for `ThinVec`.
2//!
3//! FIXME: <https://github.com/Gankra/thin-vec/pull/66> is merged, this can be removed.
4
5use std::{ptr, slice};
6
7use thin_vec::ThinVec;
8
9/// An iterator for [`ThinVec`] which uses a closure to determine if an element should be removed.
10#[must_use = "iterators are lazy and do nothing unless consumed"]
11pub struct ExtractIf<'a, T, F> {
12    vec: &'a mut ThinVec<T>,
13    /// The index of the item that will be inspected by the next call to `next`.
14    idx: usize,
15    /// The number of items that have been drained (removed) thus far.
16    del: usize,
17    /// The original length of `vec` prior to draining.
18    old_len: usize,
19    /// The filter test predicate.
20    pred: F,
21}
22
23impl<'a, T, F> ExtractIf<'a, T, F>
24where
25    F: FnMut(&mut T) -> bool,
26{
27    pub fn new(vec: &'a mut ThinVec<T>, filter: F) -> Self {
28        let old_len = vec.len();
29
30        // Guard against us getting leaked (leak amplification)
31        unsafe {
32            vec.set_len(0);
33        }
34
35        ExtractIf { vec, idx: 0, del: 0, old_len, pred: filter }
36    }
37}
38
39impl<T, F> Iterator for ExtractIf<'_, T, F>
40where
41    F: FnMut(&mut T) -> bool,
42{
43    type Item = T;
44    fn next(&mut self) -> Option<Self::Item> {
45        unsafe {
46            while self.idx < self.old_len {
47                let i = self.idx;
48                let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
49                let drained = (self.pred)(&mut v[i]);
50                // Update the index *after* the predicate is called. If the index
51                // is updated prior and the predicate panics, the element at this
52                // index would be leaked.
53                self.idx += 1;
54                if drained {
55                    self.del += 1;
56                    return Some(ptr::read(&v[i]));
57                } else if self.del > 0 {
58                    let del = self.del;
59                    let src: *const T = &v[i];
60                    let dst: *mut T = &mut v[i - del];
61                    ptr::copy_nonoverlapping(src, dst, 1);
62                }
63            }
64            None
65        }
66    }
67
68    fn size_hint(&self) -> (usize, Option<usize>) {
69        (0, Some(self.old_len - self.idx))
70    }
71}
72
73impl<A, F> Drop for ExtractIf<'_, A, F> {
74    fn drop(&mut self) {
75        unsafe {
76            if self.idx < self.old_len && self.del > 0 {
77                // This is a pretty messed up state, and there isn't really an
78                // obviously right thing to do. We don't want to keep trying
79                // to execute `pred`, so we just backshift all the unprocessed
80                // elements and tell the vec that they still exist. The backshift
81                // is required to prevent a double-drop of the last successfully
82                // drained item prior to a panic in the predicate.
83                let ptr = self.vec.as_mut_ptr();
84                let src = ptr.add(self.idx);
85                let dst = src.sub(self.del);
86                let tail_len = self.old_len - self.idx;
87                src.copy_to(dst, tail_len);
88            }
89            self.vec.set_len(self.old_len - self.del);
90        }
91    }
92}