use super::REPLAY_WINDOW_SIZE;
use std::fmt;
#[derive(Clone)]
pub struct ReplayWindow {
highest: u64,
bitmap: [u64; REPLAY_WINDOW_SIZE / 64],
}
impl ReplayWindow {
pub fn new() -> Self {
Self {
highest: 0,
bitmap: [0; REPLAY_WINDOW_SIZE / 64],
}
}
pub fn check(&self, counter: u64) -> bool {
if counter > self.highest {
return true;
}
let diff = self.highest - counter;
if diff as usize >= REPLAY_WINDOW_SIZE {
return false;
}
let (word_idx, mask) = Self::bit_position(counter);
(self.bitmap[word_idx] & mask) == 0
}
pub fn accept(&mut self, counter: u64) {
if counter > self.highest {
let shift = counter - self.highest;
if shift as usize >= REPLAY_WINDOW_SIZE {
self.bitmap = [0; REPLAY_WINDOW_SIZE / 64];
} else {
self.clear_counter_range(self.highest + 1, counter);
}
self.highest = counter;
}
let (word_idx, mask) = Self::bit_position(counter);
self.bitmap[word_idx] |= mask;
}
fn clear_counter_range(&mut self, start: u64, end: u64) {
debug_assert!(start <= end);
for counter in start..=end {
let (word_idx, mask) = Self::bit_position(counter);
self.bitmap[word_idx] &= !mask;
}
}
#[inline]
fn bit_position(counter: u64) -> (usize, u64) {
let bit = (counter as usize) % REPLAY_WINDOW_SIZE;
(bit / 64, 1u64 << (bit % 64))
}
pub fn highest(&self) -> u64 {
self.highest
}
pub fn reset(&mut self) {
self.highest = 0;
self.bitmap = [0; REPLAY_WINDOW_SIZE / 64];
}
}
impl Default for ReplayWindow {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for ReplayWindow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplayWindow")
.field("highest", &self.highest)
.field("window_size", &REPLAY_WINDOW_SIZE)
.finish()
}
}