use alloc::fmt::format;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter};
use core::ops::{Index, IndexMut};
#[derive(Clone)]
pub(crate) struct CountMinRow(Vec<u8>);
impl CountMinRow {
pub(crate) fn new(width: u64) -> Self {
Self(vec![0; width as usize])
}
pub(crate) fn get(&self, i: u64) -> u8 {
(self[(i / 2) as usize] >> ((i & 1) * 4)) & 0x0f
}
pub(crate) fn increment(&mut self, i: u64) {
let idx = (i / 2) as usize;
let shift = (i & 1) * 4;
let v = (self[idx] >> shift) & 0x0f;
if v < 15 {
self.0[idx] += 1 << shift;
}
}
pub(crate) fn reset(&mut self) {
self.0.iter_mut().for_each(|v| *v = (*v >> 1) & 0x77)
}
pub(crate) fn clear(&mut self) {
self.0.iter_mut().for_each(|v| *v = 0)
}
}
impl Index<usize> for CountMinRow {
type Output = u8;
fn index(&self, index: usize) -> &Self::Output {
self.0.index(index)
}
}
impl IndexMut<usize> for CountMinRow {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.0.index_mut(index)
}
}
impl Debug for CountMinRow {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut s = String::new();
for i in 0..(self.0.len() * 2) {
s.push_str(&format(format_args!(
"{:02} ",
(self[i / 2] >> ((i & 1) * 4)) & 0x0f
)));
}
write!(f, "{}", s)
}
}
#[cfg(test)]
mod test {
use crate::lfu::tinylfu::sketch::count_min_row::CountMinRow;
#[test]
fn test_count_min_row() {
let mut cmr = CountMinRow::new(8);
cmr.increment(0);
assert_eq!(cmr[0], 0x01);
assert_eq!(cmr.get(0), 1);
assert_eq!(cmr.get(1), 0);
cmr.increment(1);
assert_eq!(cmr[0], 0x11);
assert_eq!(cmr.get(0), 1);
assert_eq!(cmr.get(1), 1);
(0..14).for_each(|_| cmr.increment(1));
assert_eq!(cmr[0], 0xf1);
assert_eq!(cmr.get(1), 15);
assert_eq!(cmr.get(0), 1);
(0..3).for_each(|_| {
cmr.increment(1);
assert_eq!(cmr[0], 0xf1);
});
cmr.reset();
assert_eq!(cmr[0], 0x70);
}
}