use crate::common::NumStdDev;
use crate::hll::COUPON_RSE;
use crate::hll::coupon_mapping::X_ARR;
use crate::hll::coupon_mapping::Y_ARR;
use crate::hll::cubic_interpolation::using_x_and_y_tables;
pub const COUPON_EMPTY: u32 = 0;
#[derive(Debug, Clone)]
pub struct Container {
lg_size: usize,
pub coupons: Box<[u32]>,
pub len: usize,
}
impl PartialEq for Container {
fn eq(&self, other: &Self) -> bool {
if self.len != other.len {
return false;
}
let mut coupons1: Vec<u32> = self
.coupons
.iter()
.filter(|&&c| c != COUPON_EMPTY)
.copied()
.collect();
let mut coupons2: Vec<u32> = other
.coupons
.iter()
.filter(|&&c| c != COUPON_EMPTY)
.copied()
.collect();
coupons1.sort_unstable();
coupons2.sort_unstable();
coupons1 == coupons2
}
}
impl Container {
pub fn new(lg_size: usize) -> Self {
Self {
lg_size,
coupons: vec![COUPON_EMPTY; 1 << lg_size].into_boxed_slice(),
len: 0,
}
}
pub fn from_coupons(lg_size: usize, coupons: Box<[u32]>, len: usize) -> Self {
Self {
lg_size,
coupons,
len,
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn lg_size(&self) -> usize {
self.lg_size
}
pub fn is_full(&self) -> bool {
self.len == self.coupons.len()
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
self.coupons.len()
}
pub fn estimate(&self) -> f64 {
let len = self.len as f64;
let est = using_x_and_y_tables(&X_ARR, &Y_ARR, len);
len.max(est)
}
pub fn upper_bound(&self, num_std_dev: NumStdDev) -> f64 {
let len = self.len as f64;
let est = using_x_and_y_tables(&X_ARR, &Y_ARR, len);
let rse = -(num_std_dev as u8 as f64) * COUPON_RSE;
let bound = est / (1.0 + rse);
len.max(bound)
}
pub fn lower_bound(&self, num_std_dev: NumStdDev) -> f64 {
let len = self.len as f64;
let est = using_x_and_y_tables(&X_ARR, &Y_ARR, len);
let rse = (num_std_dev as u8 as f64) * COUPON_RSE;
let bound = est / (1.0 + rse);
len.max(bound)
}
pub fn iter(&self) -> impl Iterator<Item = u32> + '_ {
self.coupons.iter().filter(|&&c| c != COUPON_EMPTY).copied()
}
}