generic_arraydeque/unstable/
extract_if.rs

1use core::{
2  fmt,
3  ops::{Range, RangeBounds},
4  ptr,
5};
6
7use super::{ArrayLength, GenericArrayDeque};
8
9impl<T, N> GenericArrayDeque<T, N>
10where
11  N: ArrayLength,
12{
13  /// Creates an iterator which uses a closure to determine if an element in the range should be removed.
14  ///
15  /// If the closure returns `true`, the element is removed from the deque and yielded. If the closure
16  /// returns `false`, or panics, the element remains in the deque and will not be yielded.
17  ///
18  /// Only elements that fall in the provided range are considered for extraction, but any elements
19  /// after the range will still have to be moved if any element has been extracted.
20  ///
21  /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
22  /// or the iteration short-circuits, then the remaining elements will be retained.
23  /// Use [`retain_mut`] with a negated predicate if you do not need the returned iterator.
24  ///
25  /// [`retain_mut`]: GenericArrayDeque::retain_mut
26  ///
27  /// Using this method is equivalent to the following code:
28  ///
29  /// ```
30  /// # use generic_arraydeque::{GenericArrayDeque, typenum::U16};
31  /// # let some_predicate = |x: &mut i32| { *x % 2 == 1 };
32  /// # let mut deq = GenericArrayDeque::<_, U16>::try_from_iter(0..10).unwrap();
33  /// # let mut deq2 = deq.clone();
34  /// # let range = 1..5;
35  /// let mut i = range.start;
36  /// let end_items = deq.len() - range.end;
37  /// # let mut extracted = vec![];
38  ///
39  /// while i < deq.len() - end_items {
40  ///     if some_predicate(&mut deq[i]) {
41  ///         let val = deq.remove(i).unwrap();
42  ///         // your code here
43  /// #         extracted.push(val);
44  ///     } else {
45  ///         i += 1;
46  ///     }
47  /// }
48  ///
49  /// # let extracted2: Vec<_> = deq2.extract_if(range, some_predicate).collect();
50  /// # assert_eq!(deq, deq2);
51  /// # assert_eq!(extracted, extracted2);
52  /// ```
53  ///
54  /// But `extract_if` is easier to use. `extract_if` is also more efficient,
55  /// because it can backshift the elements of the array in bulk.
56  ///
57  /// The iterator also lets you mutate the value of each element in the
58  /// closure, regardless of whether you choose to keep or remove it.
59  ///
60  /// # Panics
61  ///
62  /// If `range` is out of bounds.
63  ///
64  /// # Examples
65  ///
66  /// Splitting a deque into even and odd values, reusing the original deque:
67  ///
68  /// ```
69  /// use generic_arraydeque::{GenericArrayDeque, typenum::U16};
70  ///
71  /// let mut numbers = GenericArrayDeque::<_, U16>::try_from_iter([
72  ///     1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15,
73  /// ]).unwrap();
74  ///
75  /// let mut evens = GenericArrayDeque::<_, U16>::new();
76  /// numbers.extract_if(.., |x| *x % 2 == 0).for_each(|value| {
77  ///     assert!(evens.push_back(value).is_none());
78  /// });
79  /// let odds = numbers;
80  ///
81  /// assert_eq!(
82  ///     evens,
83  ///     GenericArrayDeque::<_, U16>::try_from_iter([2, 4, 6, 8, 14]).unwrap()
84  /// );
85  /// assert_eq!(
86  ///     odds,
87  ///     GenericArrayDeque::<_, U16>::try_from_iter([1, 3, 5, 9, 11, 13, 15]).unwrap()
88  /// );
89  /// ```
90  ///
91  /// Using the range argument to only process a part of the deque:
92  ///
93  /// ```
94  /// use generic_arraydeque::{GenericArrayDeque, typenum::U16};
95  ///
96  /// let mut items = GenericArrayDeque::<_, U16>::try_from_iter([
97  ///     0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2,
98  /// ]).unwrap();
99  /// let mut ones = GenericArrayDeque::<_, U16>::new();
100  /// items.extract_if(7.., |x| *x == 1).for_each(|value| {
101  ///     assert!(ones.push_back(value).is_none());
102  /// });
103  /// assert_eq!(
104  ///     items,
105  ///     GenericArrayDeque::<_, U16>::try_from_iter([0, 0, 0, 0, 0, 0, 0, 2, 2, 2]).unwrap()
106  /// );
107  /// assert_eq!(ones.len(), 3);
108  /// ```
109  pub fn extract_if<F, R>(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, N>
110  where
111    F: FnMut(&mut T) -> bool,
112    R: RangeBounds<usize>,
113  {
114    ExtractIf::new(self, filter, range)
115  }
116}
117
118/// An iterator which uses a closure to determine if an element should be removed.
119///
120/// This struct is created by [`GenericArrayDeque::extract_if`].
121/// See its documentation for more.
122///
123/// # Example
124///
125/// ```
126/// use generic_arraydeque::{ExtractIf, GenericArrayDeque, typenum::U3};
127///
128/// let mut v = GenericArrayDeque::<_, U3>::try_from_array([0, 1, 2]).unwrap();
129/// let iter: ExtractIf<'_, _, _, U3> = v.extract_if(.., |x| *x % 2 == 0);
130/// ```
131#[must_use = "iterators are lazy and do nothing unless consumed"]
132pub struct ExtractIf<'a, T, F, N: ArrayLength> {
133  vec: &'a mut GenericArrayDeque<T, N>,
134  /// The index of the item that will be inspected by the next call to `next`.
135  idx: usize,
136  /// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`.
137  end: usize,
138  /// The number of items that have been drained (removed) thus far.
139  del: usize,
140  /// The original length of `vec` prior to draining.
141  old_len: usize,
142  /// The filter test predicate.
143  pred: F,
144}
145
146impl<'a, T, F, N: ArrayLength> ExtractIf<'a, T, F, N> {
147  pub(super) fn new<R: RangeBounds<usize>>(
148    vec: &'a mut GenericArrayDeque<T, N>,
149    pred: F,
150    range: R,
151  ) -> Self {
152    let old_len = vec.len();
153    let Range { start, end } = super::range(range, ..old_len);
154
155    // Guard against the deque getting leaked (leak amplification)
156    vec.len = 0;
157    ExtractIf {
158      vec,
159      idx: start,
160      del: 0,
161      end,
162      old_len,
163      pred,
164    }
165  }
166}
167
168impl<T, F, N: ArrayLength> Iterator for ExtractIf<'_, T, F, N>
169where
170  F: FnMut(&mut T) -> bool,
171{
172  type Item = T;
173
174  fn next(&mut self) -> Option<T> {
175    while self.idx < self.end {
176      let i = self.idx;
177      // SAFETY:
178      //  We know that `i < self.end` from the if guard and that `self.end <= self.old_len` from
179      //  the validity of `Self`. Therefore `i` points to an element within `vec`.
180      //
181      //  Additionally, the i-th element is valid because each element is visited at most once
182      //  and it is the first time we access vec[i].
183      //
184      //  Note: we can't use `vec.get_mut(i).unwrap()` here since the precondition for that
185      //  function is that i < vec.len, but we've set vec's length to zero.
186      let idx = self.vec.to_physical_idx(i);
187      let cur = unsafe { (&mut *self.vec.ptr_mut().add(idx)).assume_init_mut() };
188      let drained = (self.pred)(cur);
189      // Update the index *after* the predicate is called. If the index
190      // is updated prior and the predicate panics, the element at this
191      // index would be leaked.
192      self.idx += 1;
193      if drained {
194        self.del += 1;
195        // SAFETY: We never touch this element again after returning it.
196        return Some(unsafe { ptr::read(cur) });
197      } else if self.del > 0 {
198        let hole_slot = self.vec.to_physical_idx(i - self.del);
199        // SAFETY: `self.del` > 0, so the hole slot must not overlap with current element.
200        // We use copy for move, and never touch this element again.
201        unsafe { self.vec.wrap_copy(idx, hole_slot, 1) };
202      }
203    }
204    None
205  }
206
207  fn size_hint(&self) -> (usize, Option<usize>) {
208    (0, Some(self.end - self.idx))
209  }
210}
211
212impl<T, F, N: ArrayLength> Drop for ExtractIf<'_, T, F, N> {
213  fn drop(&mut self) {
214    if self.del > 0 {
215      let src = self.vec.to_physical_idx(self.idx);
216      let dst = self.vec.to_physical_idx(self.idx - self.del);
217      let len = self.old_len - self.idx;
218      // SAFETY: Trailing unchecked items must be valid since we never touch them.
219      unsafe { self.vec.wrap_copy(src, dst, len) };
220    }
221    self.vec.len = self.old_len - self.del;
222  }
223}
224
225impl<T, F, N> fmt::Debug for ExtractIf<'_, T, F, N>
226where
227  T: fmt::Debug,
228  N: ArrayLength,
229{
230  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231    let peek = if self.idx < self.end {
232      let idx = self.vec.to_physical_idx(self.idx);
233      // This has to use pointer arithmetic as `self.vec[self.idx]` or
234      // `self.vec.get_unchecked(self.idx)` wouldn't work since we
235      // temporarily set the length of `self.vec` to zero.
236      //
237      // SAFETY:
238      // Since `self.idx` is smaller than `self.end` and `self.end` is
239      // smaller than `self.old_len`, `idx` is valid for indexing the
240      // buffer. Also, per the invariant of `self.idx`, this element
241      // has not been inspected/moved out yet.
242      Some(unsafe { &*self.vec.ptr().add(idx) })
243    } else {
244      None
245    };
246    f.debug_struct("ExtractIf")
247      .field("peek", &peek)
248      .finish_non_exhaustive()
249  }
250}