#![forbid(unsafe_code)]
use core::fmt;
use core::iter::FusedIterator;
use core::ops::{Bound, RangeBounds};
use super::BBTreeMap;
use crate::allocator::{Allocator, Global};
use crate::inline_key::{Auto, InlineKeyStrategy};
use crate::tree::node_stack::NodeStackMut;
#[must_use = "iterators are lazy and do nothing unless consumed; \
use `retain` to remove and drop elements"]
pub struct ExtractIf<'a, K, V, R, F, S: InlineKeyStrategy<K> = Auto, A: Allocator + Clone = Global>
{
walk: ExtractionWalk<'a, K, V, R, S, A>,
pred: F,
}
pub(crate) struct ExtractionWalk<'a, K, V, R, S: InlineKeyStrategy<K>, A: Allocator> {
stack: NodeStackMut<'a, K, V, S>,
length: &'a mut usize,
alloc: &'a A,
range: R,
}
impl<'a, K: Ord, V, R: RangeBounds<K>, S: InlineKeyStrategy<K>, A: Allocator + Clone>
ExtractionWalk<'a, K, V, R, S, A>
{
pub(crate) fn new(map: &'a mut BBTreeMap<K, V, S, A>, range: R) -> Self {
let has_root = map.tree.has_root();
let mut stack = NodeStackMut::new(&mut map.tree);
if has_root {
stack.go_to_first_entry_from(range.start_bound());
}
Self {
stack,
length: &mut map.length,
alloc: &map.alloc,
range,
}
}
}
impl<K, V, R, S: InlineKeyStrategy<K>, A: Allocator + Clone> ExtractionWalk<'_, K, V, R, S, A> {
pub(crate) fn next(&mut self, pick: &mut impl FnMut(&K, &mut V) -> bool) -> Option<(K, V)>
where
K: PartialOrd,
R: RangeBounds<K>,
{
loop {
let (key, value) = self.stack.key_value_mut()?;
let in_range = match self.range.end_bound() {
Bound::Included(end) => key <= end,
Bound::Excluded(end) => key < end,
Bound::Unbounded => true,
};
if !in_range {
self.stack.detach();
return None;
}
if pick(key, value) {
return Some(self.stack.remove_and_go_to_next(self.alloc, self.length));
}
self.stack.go_past_entry();
}
}
pub(crate) fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(*self.length))
}
pub(crate) fn peek(&self) -> Option<(&K, &V)> {
self.stack.key_value()
}
}
impl<K, V, R, F, S, A> Iterator for ExtractIf<'_, K, V, R, F, S, A>
where
K: PartialOrd,
R: RangeBounds<K>,
F: FnMut(&K, &mut V) -> bool,
S: InlineKeyStrategy<K>,
A: Allocator + Clone,
{
type Item = (K, V);
fn next(&mut self) -> Option<(K, V)> {
self.walk.next(&mut self.pred)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.walk.size_hint()
}
}
impl<K, V, R, F, S, A> FusedIterator for ExtractIf<'_, K, V, R, F, S, A>
where
K: PartialOrd,
R: RangeBounds<K>,
F: FnMut(&K, &mut V) -> bool,
S: InlineKeyStrategy<K>,
A: Allocator + Clone,
{
}
impl<K: fmt::Debug, V: fmt::Debug, R, F, S: InlineKeyStrategy<K>, A: Allocator + Clone> fmt::Debug
for ExtractIf<'_, K, V, R, F, S, A>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ExtractIf")
.field("peek", &self.walk.peek())
.finish_non_exhaustive()
}
}
impl<K: Ord, V, S: InlineKeyStrategy<K>, A: Allocator + Clone> BBTreeMap<K, V, S, A> {
pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, K, V, R, F, S, A>
where
R: RangeBounds<K>,
F: FnMut(&K, &mut V) -> bool,
{
ExtractIf {
walk: ExtractionWalk::new(self, range),
pred,
}
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&K, &mut V) -> bool,
{
self.extract_if(.., |key, value| !f(key, value))
.for_each(drop);
}
}