use core::{
fmt,
ops::{Range, RangeBounds},
ptr,
};
use super::{ArrayLength, GenericArrayDeque};
impl<T, N> GenericArrayDeque<T, N>
where
N: ArrayLength,
{
pub fn extract_if<F, R>(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, N>
where
F: FnMut(&mut T) -> bool,
R: RangeBounds<usize>,
{
ExtractIf::new(self, filter, range)
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ExtractIf<'a, T, F, N: ArrayLength> {
vec: &'a mut GenericArrayDeque<T, N>,
idx: usize,
end: usize,
del: usize,
old_len: usize,
pred: F,
}
impl<'a, T, F, N: ArrayLength> ExtractIf<'a, T, F, N> {
pub(super) fn new<R: RangeBounds<usize>>(
vec: &'a mut GenericArrayDeque<T, N>,
pred: F,
range: R,
) -> Self {
let old_len = vec.len();
let Range { start, end } = super::range(range, ..old_len);
vec.len = 0;
ExtractIf {
vec,
idx: start,
del: 0,
end,
old_len,
pred,
}
}
}
impl<T, F, N: ArrayLength> Iterator for ExtractIf<'_, T, F, N>
where
F: FnMut(&mut T) -> bool,
{
type Item = T;
fn next(&mut self) -> Option<T> {
while self.idx < self.end {
let i = self.idx;
let idx = self.vec.to_physical_idx(i);
let cur = unsafe { (&mut *self.vec.ptr_mut().add(idx)).assume_init_mut() };
let drained = (self.pred)(cur);
self.idx += 1;
if drained {
self.del += 1;
return Some(unsafe { ptr::read(cur) });
} else if self.del > 0 {
let hole_slot = self.vec.to_physical_idx(i - self.del);
unsafe { self.vec.wrap_copy(idx, hole_slot, 1) };
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.end - self.idx))
}
}
impl<T, F, N: ArrayLength> Drop for ExtractIf<'_, T, F, N> {
fn drop(&mut self) {
if self.del > 0 {
let src = self.vec.to_physical_idx(self.idx);
let dst = self.vec.to_physical_idx(self.idx - self.del);
let len = self.old_len - self.idx;
unsafe { self.vec.wrap_copy(src, dst, len) };
}
self.vec.len = self.old_len - self.del;
}
}
impl<T, F, N> fmt::Debug for ExtractIf<'_, T, F, N>
where
T: fmt::Debug,
N: ArrayLength,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let peek = if self.idx < self.end {
let idx = self.vec.to_physical_idx(self.idx);
Some(unsafe { &*self.vec.ptr().add(idx) })
} else {
None
};
f.debug_struct("ExtractIf")
.field("peek", &peek)
.finish_non_exhaustive()
}
}