#![forbid(unsafe_code)]
use super::{BBTreeSet, Iter};
use crate::allocator::Allocator;
use crate::inline_key::InlineKeyStrategy;
#[derive(Clone, Copy, Default)]
pub(super) struct LookupsAhead {
found: u32,
looked_up: u8,
}
impl LookupsAhead {
const BATCH: usize = 32;
#[inline]
pub(super) fn next<'a, T, S, A>(
&mut self,
elements: &mut Iter<'a, T, S>,
set: &BBTreeSet<T, S, A>,
) -> Option<(&'a T, bool)>
where
T: Ord,
S: InlineKeyStrategy<T>,
A: Allocator + Clone,
{
if self.looked_up == 0 && elements.len() >= Self::BATCH && set.map.batches() {
self.look_up(elements.clone(), set);
}
let element = elements.next()?;
if self.looked_up == 0 {
return Some((element, set.contains(element)));
}
let found = self.found & 1 != 0;
self.found >>= 1;
self.looked_up -= 1;
Some((element, found))
}
#[inline(never)]
fn look_up<T, S, A>(&mut self, mut ahead: Iter<'_, T, S>, set: &BBTreeSet<T, S, A>)
where
T: Ord,
S: InlineKeyStrategy<T>,
A: Allocator + Clone,
{
let batch: [&T; Self::BATCH] =
core::array::from_fn(|_| ahead.next().expect("a whole batch is left"));
self.found = (set.contains_many(batch).into_iter().enumerate())
.fold(0, |bits, (index, found)| bits | u32::from(found) << index);
self.looked_up = Self::BATCH as u8;
}
}