use super::BlockId;
#[derive(Debug)]
pub struct CoverageMemoryView<'a> {
memory: &'a [u8],
counter_base: usize,
block_count: usize,
}
impl<'a> CoverageMemoryView<'a> {
#[must_use]
pub fn new(memory: &'a [u8], counter_base: usize, block_count: usize) -> Self {
Self {
memory,
counter_base,
block_count,
}
}
#[inline]
#[must_use]
pub fn read_counter(&self, block: BlockId) -> u64 {
let idx = block.as_u32() as usize;
if idx >= self.block_count {
return 0;
}
let offset = self.counter_base + idx * 8;
if offset + 8 > self.memory.len() {
return 0;
}
let bytes = &self.memory[offset..offset + 8];
u64::from_le_bytes(bytes.try_into().unwrap_or([0; 8]))
}
#[must_use]
pub fn read_all_counters(&self) -> Vec<u64> {
let slice = &self.memory[self.counter_base..];
slice
.chunks_exact(8)
.take(self.block_count)
.map(|b| u64::from_le_bytes(b.try_into().unwrap_or([0; 8])))
.collect()
}
#[inline]
#[must_use]
pub fn block_count(&self) -> usize {
self.block_count
}
#[inline]
#[must_use]
pub fn counter_base(&self) -> usize {
self.counter_base
}
#[inline]
#[must_use]
pub fn memory_size(&self) -> usize {
self.memory.len()
}
#[inline]
#[must_use]
pub fn is_covered(&self, block: BlockId) -> bool {
self.read_counter(block) > 0
}
#[must_use]
pub fn covered_count(&self) -> usize {
self.read_all_counters().iter().filter(|&&c| c > 0).count()
}
#[must_use]
pub fn coverage_percent(&self) -> f64 {
if self.block_count == 0 {
return 100.0; }
(self.covered_count() as f64 / self.block_count as f64) * 100.0
}
}