use std::ops::{AddAssign, Shl, Sub, SubAssign};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CumulFreqTable<F = usize> {
tree: Box<[F]>,
}
impl<F> super::CumulFreqTable<F> for CumulFreqTable<F>
where
F: std::convert::From<u8>
+ Copy
+ AddAssign
+ SubAssign
+ Sub<Output = F>
+ Shl<u32, Output = F>
+ PartialOrd,
{
fn new(len: usize) -> Self {
assert!(len > 0, "table must be non-empty");
Self {
tree: vec![0.into(); len].into_boxed_slice(),
}
}
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 {
tree: (0..len)
.map(|i| {
if i == 0 {
init
} else {
init << i.trailing_zeros()
}
})
.collect::<Vec<F>>()
.into_boxed_slice(),
}
}
fn len(&self) -> usize {
self.tree.len()
}
fn add(&mut self, mut pos: usize, val: F) {
assert!(pos < self.tree.len(), "pos out of bounds");
if pos == 0 {
self.tree[0] += val;
} else {
while pos < self.tree.len() {
self.tree[pos] += val;
pos += 1 << pos.trailing_zeros();
}
}
}
fn sub(&mut self, mut pos: usize, val: F) {
assert!(pos < self.tree.len(), "pos out of bounds");
if pos == 0 {
self.tree[0] -= val;
} else {
while pos < self.tree.len() {
self.tree[pos] -= val;
pos += 1 << pos.trailing_zeros();
}
}
}
fn sum(&self, mut pos: usize) -> F {
assert!(pos < self.tree.len(), "pos out of bounds");
let mut sum = self.tree[0];
while pos > 0 {
sum += self.tree[pos];
pos -= 1 << pos.trailing_zeros();
}
sum
}
fn total(&self) -> F {
self.sum(self.len() - 1)
}
fn freq(&self, mut pos: usize) -> F {
assert!(pos < self.tree.len(), "pos out of bounds");
let mut freq = self.tree[pos];
if pos > 0 {
let parent = pos - (1 << pos.trailing_zeros());
pos -= 1;
while parent != pos {
freq -= self.tree[pos];
pos -= 1 << pos.trailing_zeros();
}
}
freq
}
fn find_by_sum(&self, mut sum: F) -> usize {
let mut pos = 0;
if sum > self.tree[0] {
sum -= self.tree[0];
let mut mid = (((self.len() - 1) / 2) + 1).next_power_of_two();
while mid != 0 {
let hi = pos + mid;
if hi < self.len() && sum >= self.tree[hi] {
pos = hi;
sum -= self.tree[pos];
}
mid /= 2;
}
}
pos
}
fn scale<C: Fn(F) -> F>(&mut self, scale_freq: C) {
for pos in (1..self.tree.len()).rev() {
let freq = self.freq(pos);
let sfreq = scale_freq(freq);
if sfreq < freq {
self.sub(pos, freq - sfreq);
} else if sfreq > freq {
self.add(pos, sfreq - freq);
}
}
self.tree[0] = scale_freq(self.tree[0]);
}
}