use std::mem::MaybeUninit;
use crate::{table::NUM_DATA, AsView, Prefix, TrieView};
use super::{reconstruct_prefix, ViewIter};
pub struct FilterView<'a, V: TrieView<'a>, F> {
view: V,
f: F,
mask: u32,
owned: u32,
cache: [MaybeUninit<V::T>; NUM_DATA],
}
impl<'a, V, F> Clone for FilterView<'a, V, F>
where
V: TrieView<'a> + Clone,
V::T: Clone,
F: Clone,
{
fn clone(&self) -> Self {
let mut cache: [MaybeUninit<V::T>; NUM_DATA] =
std::array::from_fn(|_| MaybeUninit::uninit());
let mut bits = self.owned;
while bits != 0 {
let b = bits.trailing_zeros() as usize;
bits &= bits - 1;
cache[b] = MaybeUninit::new(
unsafe { self.cache[b].assume_init_ref().clone() },
);
}
Self {
view: self.view.clone(),
f: self.f.clone(),
mask: self.mask,
owned: self.owned,
cache,
}
}
}
impl<'a, V: TrieView<'a>, F> Drop for FilterView<'a, V, F> {
fn drop(&mut self) {
let mut bits = self.owned;
while bits != 0 {
let b = bits.trailing_zeros() as usize;
bits &= bits - 1;
unsafe { self.cache[b].assume_init_drop() };
}
}
}
impl<'a, V, F> FilterView<'a, V, F>
where
V: TrieView<'a>,
F: Fn(V::P, &V::T) -> bool,
{
pub(super) fn new(mut view: V, f: F) -> Self {
let (mask, cache) = Self::build_cache(&mut view, &f);
Self {
view,
f,
mask,
owned: mask,
cache,
}
}
fn build_cache(view: &mut V, f: &F) -> (u32, [MaybeUninit<V::T>; NUM_DATA]) {
let mut cache: [MaybeUninit<V::T>; NUM_DATA] =
std::array::from_fn(|_| MaybeUninit::uninit());
let mut mask = 0u32;
let mut bits = view.data_bitmap();
while bits != 0 {
let b = bits.trailing_zeros();
bits &= bits - 1;
let prefix = reconstruct_prefix::<V::P>(view.depth(), view.key(), b);
let value = unsafe { view.get_data(b) };
if f(prefix, &value) {
cache[b as usize] = MaybeUninit::new(value);
mask |= 1 << b;
}
}
(mask, cache)
}
}
impl<'a, V, F> TrieView<'a> for FilterView<'a, V, F>
where
V: TrieView<'a>,
F: Fn(V::P, &V::T) -> bool + Clone,
{
type P = V::P;
type T = V::T;
#[inline]
fn depth(&self) -> u32 {
self.view.depth()
}
#[inline]
fn key(&self) -> <Self::P as Prefix>::R {
self.view.key()
}
#[inline]
fn prefix_len(&self) -> u32 {
self.view.prefix_len()
}
#[inline]
fn data_bitmap(&self) -> u32 {
self.mask
}
#[inline]
fn child_bitmap(&self) -> u32 {
self.view.child_bitmap()
}
unsafe fn get_data(&mut self, data_bit: u32) -> Self::T {
debug_assert_ne!(self.mask & (1 << data_bit), 0, "data_bit not set in mask");
self.owned &= !(1 << data_bit);
std::mem::replace(&mut self.cache[data_bit as usize], MaybeUninit::uninit()).assume_init()
}
unsafe fn get_child(&mut self, child_bit: u32) -> Self {
let mut view = unsafe { self.view.get_child(child_bit) };
let (mask, cache) = Self::build_cache(&mut view, &self.f);
Self {
view,
f: self.f.clone(),
mask,
owned: mask,
cache,
}
}
unsafe fn reposition(&mut self, key: <Self::P as Prefix>::R, prefix_len: u32) {
unsafe { self.view.reposition(key, prefix_len) };
let new_scope = self.view.data_bitmap();
let mut abandoned = self.owned & !new_scope;
while abandoned != 0 {
let b = abandoned.trailing_zeros() as usize;
abandoned &= abandoned - 1;
unsafe { self.cache[b].assume_init_drop() };
}
self.owned &= new_scope;
self.mask = self.owned;
}
}
impl<'a, V, F> AsView<'a> for FilterView<'a, V, F>
where
V: TrieView<'a>,
F: Fn(V::P, &V::T) -> bool + Clone,
{
type P = V::P;
type View = Self;
fn view(self) -> Self {
self
}
}
impl<'a, V, F> IntoIterator for FilterView<'a, V, F>
where
V: TrieView<'a>,
F: Fn(V::P, &V::T) -> bool + Clone,
{
type Item = (V::P, V::T);
type IntoIter = ViewIter<'a, Self>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[cfg(test)]
mod tests {
use crate::{
trieview::{AsView, TrieView},
Prefix, PrefixMap,
};
type P = (u32, u8);
fn p(repr: u32, len: u8) -> P {
P::from_repr_len(repr, len)
}
fn map_from(entries: &[(u32, u8, i32)]) -> PrefixMap<P, i32> {
let mut m = PrefixMap::new();
for &(repr, len, val) in entries {
m.insert(p(repr, len), val);
}
m
}
#[test]
fn filter_view_iter_and_as_view() {
let m = map_from(&[
(0x0a000000, 8, 1),
(0x0a010000, 16, 2),
(0x0a010100, 24, 3),
(0x0a020000, 16, 4),
]);
let filtered = m.view().filter(|_, x| *x % 2 == 0).copied();
let got: Vec<(P, i32)> = filtered.view().into_iter().collect();
assert_eq!(got, vec![(p(0x0a010000, 16), 2), (p(0x0a020000, 16), 4)]);
}
#[test]
fn filter_view_uses_prefix() {
let m = map_from(&[(0x0a000000, 8, 1), (0x0a010000, 16, 2), (0x0a010100, 24, 3)]);
let filtered = m
.view()
.filter(|prefix, _| prefix.prefix_len() == 16)
.copied();
let got: Vec<(P, i32)> = filtered.view().into_iter().collect();
assert_eq!(got, vec![(p(0x0a010000, 16), 2)]);
}
#[test]
fn filter_view_none_match() {
let m = map_from(&[(0x0a000000, 8, 1), (0x0a010000, 16, 2), (0x0a010100, 24, 3)]);
let filtered = m.view().filter(|_, _| false).copied();
let got: Vec<(P, i32)> = filtered.view().into_iter().collect();
assert_eq!(got, Vec::<(P, i32)>::new());
}
#[test]
fn filter_view_mut_mutates_only_matching() {
let mut m = map_from(&[
(0x0a000000, 8, 1),
(0x0a010000, 16, 2),
(0x0a010100, 24, 3),
(0x0a020000, 16, 4),
]);
for v in (&mut m).view().filter(|_, x| **x % 2 == 0).values() {
*v += 100;
}
assert_eq!(
m.into_iter().collect::<Vec<_>>(),
vec![
(p(0x0a000000, 8), 1),
(p(0x0a010000, 16), 102),
(p(0x0a010100, 24), 3),
(p(0x0a020000, 16), 104),
]
);
}
#[test]
fn filter_view_over_union() {
let left = map_from(&[(0x0a000000, 8, 1), (0x0a010000, 16, 2)]);
let right = map_from(&[(0x0a010000, 16, 20), (0x0a020000, 16, 30)]);
let both: Vec<P> = left
.view()
.union(&right)
.filter(|_, item| item.both().is_some())
.keys()
.collect();
assert_eq!(both, vec![p(0x0a010000, 16)]);
}
#[test]
fn filter_view_over_covering_difference() {
let left = map_from(&[(0x0a000000, 8, 1), (0x0a010000, 16, 2), (0x0a010100, 24, 3)]);
let right = map_from(&[(0x0a010000, 20, 99)]);
let got: Vec<P> = left
.view()
.copied()
.covering_difference(&right)
.filter(|prefix, x| {
assert_ne!(prefix, p(0x0a010100, 24));
*x != 1
})
.keys()
.collect();
assert_eq!(got, vec![p(0x0a010000, 16)]);
}
use std::{cell::RefCell, rc::Rc};
#[derive(Clone)]
struct DropProbe(i32, Rc<RefCell<Vec<i32>>>);
impl Drop for DropProbe {
fn drop(&mut self) {
self.1.borrow_mut().push(self.0);
}
}
fn probe_map(
entries: &[(u32, u8, i32)],
log: &Rc<RefCell<Vec<i32>>>,
) -> PrefixMap<P, DropProbe> {
let mut m = PrefixMap::new();
for &(repr, len, id) in entries {
m.insert(p(repr, len), DropProbe(id, log.clone()));
}
m
}
fn sorted(mut v: Vec<i32>) -> Vec<i32> {
v.sort_unstable();
v
}
#[test]
fn filter_view_drops_filtered_out_value_immediately() {
let log = Rc::new(RefCell::new(Vec::new()));
let m = probe_map(&[(0x0a000000, 8, 1), (0x0a010000, 16, 2)], &log);
let filtered = m.view().cloned().filter(|_, x| x.0 % 2 == 0);
assert_eq!(*log.borrow(), Vec::<i32>::new());
assert!(filtered.find(&p(0x0a000000, 8)).is_some());
assert_eq!(*log.borrow(), vec![1]);
drop(m);
}
#[test]
fn filter_view_dropped_without_iterating_drops_only_the_current_node() {
let log = Rc::new(RefCell::new(Vec::new()));
let m = probe_map(&[(0, 1, 1), (0, 2, 2), (0x0a000000, 8, 3)], &log);
let filtered = m.view().cloned().filter(|_, x| x.0 % 2 == 0);
assert_eq!(*log.borrow(), vec![1]);
drop(filtered);
assert_eq!(sorted(log.borrow().clone()), vec![1, 2]);
drop(m);
}
#[test]
fn filter_view_full_iteration_drops_each_value_exactly_once() {
let log = Rc::new(RefCell::new(Vec::new()));
let m = probe_map(
&[(0x0a000000, 8, 1), (0x0a010000, 16, 2), (0x0a010100, 24, 3)],
&log,
);
let got: Vec<(P, DropProbe)> = m
.view()
.cloned()
.filter(|_, x| x.0 % 2 == 0)
.into_iter()
.collect();
assert_eq!(*log.borrow(), vec![1, 3]);
drop(got);
assert_eq!(sorted(log.borrow().clone()), vec![1, 2, 3]);
drop(m);
}
#[test]
fn filter_view_get_child_drops_abandoned_ancestor_values() {
let log = Rc::new(RefCell::new(Vec::new()));
let m = probe_map(
&[(0x0a000000, 8, 1), (0x0a010000, 16, 2), (0x0a010100, 24, 4)],
&log,
);
let got = m
.view()
.cloned()
.filter(|_, x| x.0 % 2 == 0)
.find_exact_value(&p(0x0a010100, 24));
assert_eq!(sorted(log.borrow().clone()), vec![1, 2]);
assert_eq!(got.as_ref().unwrap().1 .0, 4);
drop(got);
assert_eq!(sorted(log.borrow().clone()), vec![1, 2, 4]);
drop(m);
}
#[test]
fn filter_view_reposition_drops_abandoned_ancestor_within_same_node() {
let log = Rc::new(RefCell::new(Vec::new()));
let m = probe_map(&[(0, 6, 2), (0, 8, 4)], &log);
let got = m
.view()
.cloned()
.filter(|_, x| x.0 % 2 == 0)
.find_exact_value(&p(0, 8));
assert_eq!(*log.borrow(), vec![2]);
assert_eq!(got.as_ref().unwrap().1 .0, 4);
drop(got);
assert_eq!(sorted(log.borrow().clone()), vec![2, 4]);
drop(m);
}
#[test]
fn filter_view_clone_after_reposition_drops_hidden_owned_value_once() {
let log = Rc::new(RefCell::new(Vec::new()));
let m = probe_map(&[(0, 6, 2), (0, 7, 3), (0, 8, 4)], &log);
let view = m
.view()
.cloned()
.filter(|_, x| x.0 % 2 == 0)
.find(&p(0, 8))
.unwrap();
assert_eq!(sorted(log.borrow().clone()), vec![2, 3]);
let cloned = view.clone();
assert_eq!(sorted(log.borrow().clone()), vec![2, 3]);
drop(view);
drop(cloned);
assert_eq!(sorted(log.borrow().clone()), vec![2, 3, 4, 4]);
drop(m);
}
#[test]
fn filter_view_clone_then_diverge_navigates_independently() {
let log = Rc::new(RefCell::new(Vec::new()));
let m = probe_map(
&[
(0x00000000, 1, 1),
(0x00000000, 2, 2),
(0x00000000, 7, 3),
(0x00000000, 10, 4),
(0x80000000, 7, 5),
(0x80000000, 10, 6),
],
&log,
);
let root = m.view().cloned().filter(|_, x| x.0 % 2 == 0);
assert_eq!(*log.borrow(), vec![1]);
let cloned = root.clone();
assert_eq!(*log.borrow(), vec![1]);
let got_left = root.find_exact_value(&p(0x00000000, 10));
let got_right = cloned.find_exact_value(&p(0x80000000, 10));
assert_eq!(sorted(log.borrow().clone()), vec![1, 2, 2, 3, 5]);
assert_eq!(got_left.as_ref().unwrap().1 .0, 4);
assert_eq!(got_right.as_ref().unwrap().1 .0, 6);
drop(got_left);
drop(got_right);
assert_eq!(sorted(log.borrow().clone()), vec![1, 2, 2, 3, 4, 5, 6]);
drop(m);
}
}