use alloc::collections::BTreeMap;
use miden_air::trace::and8_lookup::{
BYTE_LOOKUP_COUNT_LEN, BYTE_PAIR_ROWS, RANGE_CHECK_COUNT_OFFSET,
};
#[cfg(test)]
mod tests;
pub struct RangeChecker {
lookups: BTreeMap<u16, usize>,
}
impl RangeChecker {
pub fn new() -> Self {
Self { lookups: BTreeMap::new() }
}
pub fn add_value(&mut self, value: u16) {
self.add_value_repeated(value, 1);
}
pub fn add_value_repeated(&mut self, value: u16, count: usize) {
if count == 0 {
return;
}
self.lookups.entry(value).and_modify(|v| *v += count).or_insert(count);
}
pub fn add_range_checks(&mut self, values: &[u16]) {
debug_assert!(matches!(values.len(), 2 | 4 | 5));
for value in values.iter() {
self.add_value(*value);
}
}
pub fn write_range_counts(self, counts: &mut [u64]) {
debug_assert_eq!(counts.len(), BYTE_LOOKUP_COUNT_LEN);
debug_assert_eq!(BYTE_PAIR_ROWS, usize::from(u16::MAX) + 1);
for (value, count) in self.lookups {
counts[RANGE_CHECK_COUNT_OFFSET + usize::from(value)] +=
u64::try_from(count).expect("range-check multiplicity exceeds u64");
}
}
#[cfg(test)]
pub fn count(&self, value: u16) -> usize {
self.lookups.get(&value).copied().unwrap_or(0)
}
}
impl Default for RangeChecker {
fn default() -> Self {
Self::new()
}
}