alloc/vec/
extract_if.rs

1use core::ops::{Range, RangeBounds};
2use core::{fmt, ptr, slice};
3
4use super::Vec;
5use crate::alloc::{Allocator, Global};
6
7/// An iterator which uses a closure to determine if an element should be removed.
8///
9/// This struct is created by [`Vec::extract_if`].
10/// See its documentation for more.
11///
12/// # Example
13///
14/// ```
15/// let mut v = vec![0, 1, 2];
16/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0);
17/// ```
18#[stable(feature = "extract_if", since = "1.87.0")]
19#[must_use = "iterators are lazy and do nothing unless consumed"]
20pub struct ExtractIf<
21    'a,
22    T,
23    F,
24    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
25> {
26    vec: &'a mut Vec<T, A>,
27    /// The index of the item that will be inspected by the next call to `next`.
28    idx: usize,
29    /// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`.
30    end: usize,
31    /// The number of items that have been drained (removed) thus far.
32    del: usize,
33    /// The original length of `vec` prior to draining.
34    old_len: usize,
35    /// The filter test predicate.
36    pred: F,
37}
38
39impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> {
40    pub(super) fn new<R: RangeBounds<usize>>(vec: &'a mut Vec<T, A>, pred: F, range: R) -> Self {
41        let old_len = vec.len();
42        let Range { start, end } = slice::range(range, ..old_len);
43
44        // Guard against the vec getting leaked (leak amplification)
45        unsafe {
46            vec.set_len(0);
47        }
48        ExtractIf { vec, idx: start, del: 0, end, old_len, pred }
49    }
50
51    /// Returns a reference to the underlying allocator.
52    #[unstable(feature = "allocator_api", issue = "32838")]
53    #[inline]
54    pub fn allocator(&self) -> &A {
55        self.vec.allocator()
56    }
57}
58
59#[stable(feature = "extract_if", since = "1.87.0")]
60impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
61where
62    F: FnMut(&mut T) -> bool,
63{
64    type Item = T;
65
66    fn next(&mut self) -> Option<T> {
67        unsafe {
68            while self.idx < self.end {
69                let i = self.idx;
70                let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
71                let drained = (self.pred)(&mut v[i]);
72                // Update the index *after* the predicate is called. If the index
73                // is updated prior and the predicate panics, the element at this
74                // index would be leaked.
75                self.idx += 1;
76                if drained {
77                    self.del += 1;
78                    return Some(ptr::read(&v[i]));
79                } else if self.del > 0 {
80                    let del = self.del;
81                    let src: *const T = &v[i];
82                    let dst: *mut T = &mut v[i - del];
83                    ptr::copy_nonoverlapping(src, dst, 1);
84                }
85            }
86            None
87        }
88    }
89
90    fn size_hint(&self) -> (usize, Option<usize>) {
91        (0, Some(self.end - self.idx))
92    }
93}
94
95#[stable(feature = "extract_if", since = "1.87.0")]
96impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> {
97    fn drop(&mut self) {
98        unsafe {
99            if self.idx < self.old_len && self.del > 0 {
100                let ptr = self.vec.as_mut_ptr();
101                let src = ptr.add(self.idx);
102                let dst = src.sub(self.del);
103                let tail_len = self.old_len - self.idx;
104                src.copy_to(dst, tail_len);
105            }
106            self.vec.set_len(self.old_len - self.del);
107        }
108    }
109}
110
111#[stable(feature = "extract_if", since = "1.87.0")]
112impl<T, F, A> fmt::Debug for ExtractIf<'_, T, F, A>
113where
114    T: fmt::Debug,
115    A: Allocator,
116{
117    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118        let peek = if self.idx < self.end { self.vec.get(self.idx) } else { None };
119        f.debug_struct("ExtractIf").field("peek", &peek).finish_non_exhaustive()
120    }
121}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy