use std::collections::VecDeque;
#[derive(Debug, Clone)]
pub struct DoubleBuffer {
buf: VecDeque<i64>,
capacity: usize,
}
impl DoubleBuffer {
pub fn new(capacity: usize) -> Self {
Self {
buf: VecDeque::with_capacity(capacity),
capacity,
}
}
pub fn add(&mut self, value: i64) {
if self.buf.len() >= self.capacity {
self.buf.pop_front();
}
self.buf.push_back(value);
}
pub fn median(&self, mean_count: usize) -> i64 {
if self.buf.is_empty() {
return 0;
}
let mut sorted: Vec<i64> = self.buf.iter().copied().collect();
sorted.sort_unstable();
if mean_count <= 1 || sorted.len() < mean_count {
sorted[sorted.len() / 2]
} else {
let mid = sorted.len() / 2;
let half = mean_count / 2;
let low = mid - half;
let high = mid + half;
let sum: i64 = sorted[low..=high].iter().sum();
sum / mean_count as i64
}
}
pub fn median_simple(&self) -> i64 {
self.median(1)
}
pub fn clear(&mut self) {
self.buf.clear();
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn full(&self) -> bool {
self.buf.len() >= self.capacity
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_median_is_zero() {
let db = DoubleBuffer::new(10);
assert_eq!(db.median_simple(), 0);
}
#[test]
fn single_element() {
let mut db = DoubleBuffer::new(10);
db.add(42);
assert_eq!(db.median_simple(), 42);
}
#[test]
fn odd_count_median() {
let mut db = DoubleBuffer::new(10);
for v in [3, 1, 4, 1, 5] {
db.add(v);
}
assert_eq!(db.median_simple(), 3);
}
#[test]
fn even_count_median() {
let mut db = DoubleBuffer::new(10);
for v in [10, 20, 30, 40] {
db.add(v);
}
assert_eq!(db.median_simple(), 30);
}
#[test]
fn capacity_evicts_oldest() {
let mut db = DoubleBuffer::new(3);
db.add(100);
db.add(200);
db.add(300);
assert!(db.full());
db.add(400); assert_eq!(db.len(), 3);
assert_eq!(db.median_simple(), 300);
}
#[test]
fn median_with_mean() {
let mut db = DoubleBuffer::new(10);
for v in [1, 2, 3, 4, 5, 6, 7] {
db.add(v);
}
assert_eq!(db.median(3), 4);
}
#[test]
fn clear_resets() {
let mut db = DoubleBuffer::new(10);
db.add(1);
db.add(2);
db.clear();
assert!(db.is_empty());
assert_eq!(db.median_simple(), 0);
}
#[test]
fn negative_values() {
let mut db = DoubleBuffer::new(5);
for v in [-100, -50, 0, 50, 100] {
db.add(v);
}
assert_eq!(db.median_simple(), 0);
}
}