#[derive(Debug, Clone)]
pub struct NumDiff<const M: usize> {
m: usize,
level: usize,
buf: [i64; M],
}
impl<const M: usize> NumDiff<M> {
pub fn new(data: i64, level: usize) -> Self {
if level > 6 {
panic!("M=6 is the compression limit");
}
let mut buf = [0; M]; buf[0] = data;
Self { buf, m: 0, level }
}
pub fn force_init(&mut self, data: i64, level: usize) {
if level > 6 {
panic!("M=6 is the compression limit");
}
self.m = 0;
self.level = level;
self.rotate_history(data);
}
fn rotate_history(&mut self, data: i64) {
self.buf.copy_within(0..M - 2, 1);
self.buf[0] = data;
}
pub fn decompress(&mut self, data: i64) -> i64 {
if self.m < self.level {
self.m += 1;
}
let new: i64 = match self.m {
1 => data + self.buf[0],
2 => data + 2 * self.buf[0] - self.buf[1],
3 => data + 3 * self.buf[0] - 3 * self.buf[1] + self.buf[2],
4 => data + 4 * self.buf[0] - 6 * self.buf[1] + 4 * self.buf[2] - self.buf[3],
5 => {
data + 5 * self.buf[0] - 10 * self.buf[1] + 10 * self.buf[2] - 5 * self.buf[3]
+ self.buf[4]
},
6 => {
data + 6 * self.buf[0] - 15 * self.buf[1] + 20 * self.buf[2] - 15 * self.buf[3]
+ 6 * self.buf[4]
- self.buf[5]
},
_ => panic!("numdiff is limited to M < 7"),
};
self.rotate_history(new);
new
}
pub fn compress(&mut self, data: i64) -> i64 {
if self.m < self.level {
self.m += 1;
}
self.rotate_history(data);
match self.m {
1 => self.buf[0] - self.buf[1],
2 => self.buf[0] - 2 * self.buf[1] + self.buf[2],
3 => self.buf[0] - 3 * self.buf[1] + 3 * self.buf[2] - self.buf[3],
4 => self.buf[0] - 4 * self.buf[1] + 6 * self.buf[2] - 4 * self.buf[3] + self.buf[4],
5 => {
self.buf[0] - 5 * self.buf[1] + 10 * self.buf[2] - 10 * self.buf[3]
+ 5 * self.buf[4]
- self.buf[5]
},
6 => {
self.buf[0] - 6 * self.buf[1] + 15 * self.buf[2] - 20 * self.buf[3]
+ 15 * self.buf[4]
- 6 * self.buf[5]
+ self.buf[6]
},
_ => panic!("numdiff is limited to M < 7"),
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_decompression() {
let mut diff = NumDiff::<6>::new(126298057858, 3);
assert_eq!(diff.decompress(-15603288), 126282454570);
assert_eq!(diff.decompress(521089), 126267372371);
assert_eq!(diff.decompress(-752), 126252810509);
assert_eq!(diff.decompress(1575419284), 127814188268);
assert_eq!(diff.decompress(-3150848707), 127800656941);
assert_eq!(diff.decompress(1575424909), 127787641437);
assert_eq!(diff.decompress(-135), 127775141621);
diff.force_init(111982965979, 3);
assert_eq!(diff.decompress(-16266911), 111966699068);
assert_eq!(diff.decompress(609858), 111951042015);
assert_eq!(diff.decompress(-213), 111935994607);
assert_eq!(diff.decompress(1575419307), 113496976151);
assert_eq!(diff.decompress(-3150848442), 113483138205);
assert_eq!(diff.decompress(1575425367), 113469906136);
assert_eq!(diff.decompress(146), 113457280090);
}
#[test]
fn test_compression() {
let mut diff = NumDiff::<6>::new(126298057858, 3);
assert_eq!(diff.compress(126282454570), -15603288);
assert_eq!(diff.compress(126267372371), 521089);
assert_eq!(diff.compress(126252810509), -752);
assert_eq!(diff.compress(127814188268), 1575419284);
assert_eq!(diff.compress(127800656941), -3150848707);
assert_eq!(diff.compress(127787641437), 1575424909);
assert_eq!(diff.compress(127775141621), -135);
diff.force_init(111982965979, 3);
assert_eq!(diff.compress(111966699068), -16266911);
assert_eq!(diff.compress(111951042015), 609858);
assert_eq!(diff.compress(111935994607), -213);
assert_eq!(diff.compress(113496976151), 1575419307);
assert_eq!(diff.compress(113483138205), -3150848442);
assert_eq!(diff.compress(113469906136), 1575425367);
assert_eq!(diff.compress(113457280090), 146);
}
}