#![allow(dead_code)]
pub const RECENT_OFFSETS: usize = 4;
#[derive(Debug, Clone)]
pub struct OffsetHistory {
ring: [u32; RECENT_OFFSETS],
write_idx: u8,
last_offset: u32,
last_length: u32,
}
impl OffsetHistory {
pub const fn new() -> Self {
Self {
ring: [0u32; RECENT_OFFSETS],
write_idx: 0,
last_offset: 0,
last_length: 0,
}
}
pub fn push(&mut self, offset: u32, length: u32) {
self.ring[self.write_idx as usize] = offset;
self.write_idx = (self.write_idx + 1) & (RECENT_OFFSETS as u8 - 1);
self.last_offset = offset;
self.last_length = length;
}
pub fn peek_back(&self, back: u8) -> u32 {
debug_assert!((1..=RECENT_OFFSETS as u8).contains(&back));
let idx = (self.write_idx + RECENT_OFFSETS as u8 - back) & (RECENT_OFFSETS as u8 - 1);
self.ring[idx as usize]
}
pub fn last_offset(&self) -> u32 {
self.last_offset
}
pub fn last_length(&self) -> u32 {
self.last_length
}
pub fn reset(&mut self) {
*self = Self::new();
}
}
impl Default for OffsetHistory {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct RepeatLastTracker {
pub repeats: u8,
}
impl RepeatLastTracker {
pub const fn new() -> Self {
Self { repeats: 0 }
}
pub fn observe_repeat(&mut self) -> bool {
self.repeats = self.repeats.saturating_add(1);
self.repeats <= 2
}
pub fn reset(&mut self) {
self.repeats = 0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ring_records_recent() {
let mut h = OffsetHistory::new();
h.push(10, 3);
h.push(20, 4);
h.push(30, 5);
h.push(40, 6);
assert_eq!(h.peek_back(1), 40);
assert_eq!(h.peek_back(2), 30);
assert_eq!(h.peek_back(3), 20);
assert_eq!(h.peek_back(4), 10);
assert_eq!(h.last_offset(), 40);
assert_eq!(h.last_length(), 6);
}
#[test]
fn ring_wraps_after_four_pushes() {
let mut h = OffsetHistory::new();
for v in [1u32, 2, 3, 4, 5] {
h.push(v, v);
}
assert_eq!(h.peek_back(1), 5);
assert_eq!(h.peek_back(2), 4);
assert_eq!(h.peek_back(3), 3);
assert_eq!(h.peek_back(4), 2);
}
#[test]
fn last_offset_and_length_update() {
let mut h = OffsetHistory::new();
h.push(42, 7);
assert_eq!(h.last_offset(), 42);
assert_eq!(h.last_length(), 7);
h.push(99, 11);
assert_eq!(h.last_offset(), 99);
assert_eq!(h.last_length(), 11);
}
#[test]
fn reset_clears_ring() {
let mut h = OffsetHistory::new();
h.push(1, 2);
h.reset();
assert_eq!(h.last_offset(), 0);
assert_eq!(h.last_length(), 0);
for back in 1..=RECENT_OFFSETS as u8 {
assert_eq!(h.peek_back(back), 0);
}
}
#[test]
fn repeat_tracker_first_two_implicit() {
let mut r = RepeatLastTracker::new();
assert!(r.observe_repeat()); assert!(r.observe_repeat()); assert!(!r.observe_repeat()); assert!(!r.observe_repeat()); r.reset();
assert!(r.observe_repeat()); }
}