use std::ops::Range;
pub(crate) struct FinishedIds {
range: Range<u32>,
words: Vec<u64>,
}
impl FinishedIds {
pub(crate) fn new(range: Range<u32>) -> Self {
Self {
range,
words: Vec::new(),
}
}
pub(crate) fn is_finished(&self, id: u32) -> bool {
let Some((word, mask)) = self.bit(id) else {
return false;
};
self.words.get(word).is_some_and(|bits| bits & mask != 0)
}
pub(crate) fn mark_finished(&mut self, id: u32) -> bool {
let Some((word, mask)) = self.bit(id) else {
return false;
};
if self.words.len() <= word {
self.words.resize(word + 1, 0);
}
self.words[word] |= mask;
true
}
fn bit(&self, id: u32) -> Option<(usize, u64)> {
if !self.range.contains(&id) {
return None;
}
let offset = usize::try_from(id.checked_sub(self.range.start)?).ok()?;
Some((
offset / u64::BITS as usize,
1u64 << (offset % u64::BITS as usize),
))
}
}