use kevy_hash::KevyHash;
use crate::map::{EMPTY, GROUP_WIDTH, KevyMap};
impl<K: KevyHash + Eq, V> KevyMap<K, V> {
pub fn scan_step(&self, cursor: u64, mut f: impl FnMut(&K, &V)) -> u64 {
if self.cap == 0 {
return 0;
}
let ngroups = (self.cap / GROUP_WIDTH) as u64;
let gmask = ngroups - 1;
self.visit_home_group((cursor & gmask) as usize, &mut f);
let v = (cursor | !gmask).reverse_bits();
v.wrapping_add(1).reverse_bits()
}
fn visit_home_group(&self, g: usize, f: &mut impl FnMut(&K, &V)) {
let start = g * GROUP_WIDTH;
let mut past_empty: Option<usize> = None;
for off in 0..self.cap {
let p = (start + off) & self.mask;
let meta = unsafe { *self.metadata_ptr.as_ptr().add(p) };
if meta & 0x80 == 0 {
let kv = unsafe { (*self.slots_ptr.as_ptr().add(p)).assume_init_ref() };
let home = (kv.0.kevy_hash() as usize) & self.mask;
if home / GROUP_WIDTH == g {
f(&kv.0, &kv.1);
}
}
match &mut past_empty {
Some(0) => return,
Some(t) => *t -= 1,
None if meta == EMPTY && off + 1 >= GROUP_WIDTH => {
past_empty = Some(GROUP_WIDTH - 1);
}
None => {}
}
}
}
}
#[cfg(test)]
#[path = "scan_tests.rs"]
mod tests;