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}