#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LogScaleConfig {
width: usize,
group_size: usize,
mask: u64,
buckets: usize,
small_value_cache_size: usize,
}
impl LogScaleConfig {
pub const MIN_WIDTH: usize = 1;
pub const MAX_WIDTH: usize = 16;
pub(crate) fn validate_width(width: usize) {
assert!(
(Self::MIN_WIDTH..=Self::MAX_WIDTH).contains(&width),
"width must be {}..={}, got {}",
Self::MIN_WIDTH,
Self::MAX_WIDTH,
width
);
}
pub fn new(width: usize) -> Self {
Self::validate_width(width);
let group_size = 1 << (width - 1);
let mask = (group_size - 1) as u64;
let buckets = group_size * (66 - width);
Self {
width,
group_size,
mask,
buckets,
small_value_cache_size: 4096,
}
}
pub fn width(&self) -> usize {
self.width
}
pub fn group_size(&self) -> usize {
self.group_size
}
pub fn mask(&self) -> u64 {
self.mask
}
pub fn buckets(&self) -> usize {
self.buckets
}
pub fn small_value_cache_size(&self) -> usize {
self.small_value_cache_size
}
}
#[cfg(test)]
mod tests {
use super::LogScaleConfig;
#[test]
fn test_new_accepts_supported_widths() {
assert_eq!(LogScaleConfig::new(1).width(), 1);
assert_eq!(LogScaleConfig::new(16).width(), 16);
}
#[test]
#[should_panic(expected = "width must be 1..=16, got 0")]
fn test_new_rejects_zero_width() {
let _ = LogScaleConfig::new(0);
}
#[test]
#[should_panic(expected = "width must be 1..=16, got 17")]
fn test_new_rejects_width_above_max() {
let _ = LogScaleConfig::new(17);
}
}