use crate::prelude::*;
#[derive(Debug)]
pub struct Smooth {
small: usize, large: usize, data: Vec<Vec<u8>>, jump: usize, pos: usize, size: usize, }
impl Smooth {
pub fn new(sz: usize) -> Self {
let small = sz.max(2);
let large = small * 2 - 2;
let mut data = Vec::new();
data.reserve(large);
for _ in 0..large {
data.push(Vec::new());
}
Self {
small,
large,
data,
jump: 1,
pos: 0,
size: 0,
}
}
fn verify(&self) -> bool {
debug_assert!(self.data.len() == self.large);
debug_assert!(self.size <= self.large);
debug_assert!(self.size <= self.large);
true
}
pub fn add(&mut self, x: &[u8]) {
debug_assert!(self.verify());
if self.pos == 0 {
if self.size >= self.large {
self.jump *= 2;
self.collapse();
}
self.data[self.size].clear();
self.data[self.size].extend(x);
self.size += 1;
if self.jump > 1 {
self.pos += 1;
}
} else {
self.data[self.size - 1].clear();
self.data[self.size - 1].extend(x);
self.pos += 1;
debug_assert!(self.verify());
let limit = if self.size == self.large {
2 * self.jump
} else {
self.jump
};
if self.pos >= limit {
self.pos = 0;
}
}
debug_assert!(self.verify());
}
fn collapse(&mut self) {
debug_assert!(self.verify());
let old_size = self.size;
let new_size = self.small;
if old_size <= new_size {
return;
}
if new_size == 2 {
self.data.swap(1, self.size - 1);
self.size = 2;
return;
}
let new_end = new_size - 1;
let ratio = (old_size - 2) as f64 / (new_size - 2) as f64;
for i in 1..new_end {
let pos = ((i as f64) * ratio) as usize;
self.data.swap(i, pos);
}
self.data.swap(new_end, self.size - 1);
self.size = new_size;
}
pub fn finalize(&mut self, w: &mut impl Write) -> Result<()> {
self.collapse();
self.write(w)
}
pub fn write(&self, w: &mut impl Write) -> Result<()> {
for i in 0..self.size {
w.write_all(&self.data[i])?;
}
Ok(())
}
}