pub const NUM_SIZE_CLASSES: usize = 16;
pub const SIZE_CLASSES: [usize; NUM_SIZE_CLASSES] = [
8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144,
];
pub const BAG_SIZE: usize = 32 * 1024;
pub const SMALL_LIMIT: usize = 262144;
pub fn size_class_index(size: usize) -> Option<usize> {
if size == 0 || size > SMALL_LIMIT {
return None;
}
if size <= 8 {
return Some(0);
}
let bits = usize::BITS - (size - 1).leading_zeros();
Some((bits as usize).saturating_sub(3))
}
pub const fn size_for_class(index: usize) -> usize {
SIZE_CLASSES[index]
}
pub const fn bag_size_for_class(class_index: usize) -> usize {
let obj = SIZE_CLASSES[class_index];
if obj > BAG_SIZE { obj } else { BAG_SIZE }
}
#[cfg(test)]
pub const fn objects_per_bag(class_index: usize) -> usize {
bag_size_for_class(class_index) / SIZE_CLASSES[class_index]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_size_class_index_boundaries() {
assert_eq!(size_class_index(0), None);
assert_eq!(size_class_index(1), Some(0)); assert_eq!(size_class_index(8), Some(0)); assert_eq!(size_class_index(9), Some(1)); assert_eq!(size_class_index(16), Some(1)); assert_eq!(size_class_index(17), Some(2)); assert_eq!(size_class_index(32), Some(2)); assert_eq!(size_class_index(33), Some(3)); assert_eq!(size_class_index(64), Some(3));
assert_eq!(size_class_index(128), Some(4));
assert_eq!(size_class_index(256), Some(5));
assert_eq!(size_class_index(512), Some(6));
assert_eq!(size_class_index(1024), Some(7));
assert_eq!(size_class_index(2048), Some(8));
assert_eq!(size_class_index(4096), Some(9));
assert_eq!(size_class_index(8192), Some(10));
assert_eq!(size_class_index(16384), Some(11));
assert_eq!(size_class_index(32768), Some(12));
assert_eq!(size_class_index(65536), Some(13));
assert_eq!(size_class_index(131072), Some(14));
assert_eq!(size_class_index(262144), Some(15));
assert_eq!(size_class_index(262145), None);
}
#[test]
fn test_size_class_covers_request() {
for size in 1..=SMALL_LIMIT {
let idx = size_class_index(size).unwrap();
assert!(
size_for_class(idx) >= size,
"size_class {} ({}B) too small for {}B",
idx,
size_for_class(idx),
size
);
}
}
#[test]
fn test_objects_per_bag() {
assert_eq!(objects_per_bag(0), BAG_SIZE / 8); assert_eq!(objects_per_bag(11), BAG_SIZE / 16384); assert_eq!(objects_per_bag(12), 1); assert_eq!(objects_per_bag(13), 1); assert_eq!(objects_per_bag(14), 1); assert_eq!(objects_per_bag(15), 1); }
}