use std::{
iter::Sum,
ops::{AddAssign, Mul, SubAssign},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FreqTable<F = usize> {
freqs: Box<[F]>,
total: F,
}
impl<F> super::CumulFreqTable<F> for FreqTable<F>
where
F: From<u8> + Copy + AddAssign + SubAssign + Sum + Mul<Output = F> + PartialOrd,
{
fn new(len: usize) -> Self {
assert!(len > 0, "table must be non-empty");
Self {
freqs: vec![0.into(); len].into_boxed_slice(),
total: 0.into(),
}
}
fn with_freq(len: usize, init: F) -> Self
where
usize: TryInto<F>,
<usize as TryInto<F>>::Error: std::fmt::Debug,
{
assert!(len > 0, "table must be non-empty");
Self {
freqs: vec![init; len].into_boxed_slice(),
total: init * len.try_into().unwrap(),
}
}
fn len(&self) -> usize {
self.freqs.len()
}
fn add(&mut self, pos: usize, val: F) {
assert!(pos < self.freqs.len(), "pos out of bounds");
self.freqs[pos] += val;
self.total += val;
}
fn sub(&mut self, pos: usize, val: F) {
assert!(pos < self.freqs.len(), "pos out of bounds");
self.freqs[pos] -= val;
self.total -= val;
}
fn sum(&self, pos: usize) -> F {
assert!(pos < self.freqs.len(), "pos out of bounds");
self.freqs[..=pos].iter().copied().sum()
}
fn total(&self) -> F {
self.total
}
fn freq(&self, pos: usize) -> F {
assert!(pos < self.freqs.len(), "pos out of bounds");
self.freqs[pos]
}
fn find_by_sum(&self, sum: F) -> usize {
let mut r_sum: F = 0.into();
let r = self.freqs.iter().position(|&freq| {
r_sum += freq;
r_sum >= sum
});
unsafe { r.unwrap_unchecked() }
}
fn scale<C: Fn(F) -> F>(&mut self, scale_freq: C) {
let mut sum: F = 0.into();
for freq in self.freqs.iter_mut() {
*freq = scale_freq(*freq);
sum += *freq;
}
self.total = sum;
}
}