use super::tables::{CLASS_TO_DIV_MULT, CLASS_TO_MAX_BLOCKS, CLASS_TO_SIZE, LEMIRE_DIV_SHIFT};
use super::{class_to_size, size_to_class};
use crate::constants::{MAX_SMALL_ALLOC_SIZE, NUM_SIZE_CLASSES};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SizeClassInfo {
pub block_size: usize,
pub max_blocks: usize,
pub div_mult: u32,
pub class: usize,
}
impl SizeClassInfo {
#[must_use]
pub const fn for_class(class: usize) -> Option<Self> {
if class >= NUM_SIZE_CLASSES {
return None;
}
Some(Self {
block_size: CLASS_TO_SIZE[class] as usize,
max_blocks: CLASS_TO_MAX_BLOCKS[class] as usize,
div_mult: CLASS_TO_DIV_MULT[class],
class,
})
}
#[must_use]
#[inline]
pub const fn for_size(size: usize) -> Option<Self> {
match size_to_class(size) {
Some(class) => Self::for_class(class),
None => None,
}
}
#[inline(always)]
pub const fn block_index(&self, offset: usize) -> usize {
((offset as u64 * self.div_mult as u64) >> LEMIRE_DIV_SHIFT) as usize
}
#[inline]
pub fn fragmentation_for(&self, requested: usize) -> f64 {
if self.block_size == 0 || requested >= self.block_size {
return 0.0;
}
(self.block_size - requested) as f64 / self.block_size as f64
}
}
#[must_use]
pub fn all_class_info() -> [SizeClassInfo; NUM_SIZE_CLASSES] {
core::array::from_fn(|class| SizeClassInfo::for_class(class).expect("class in range"))
}
const _: () = assert!(
class_to_size(NUM_SIZE_CLASSES - 1) == MAX_SMALL_ALLOC_SIZE,
"class_to_size(NUM_SIZE_CLASSES - 1) must reach MAX_SMALL_ALLOC_SIZE exactly"
);
const _: () = assert!(
class_to_size(NUM_SIZE_CLASSES) == 0,
"class_to_size(NUM_SIZE_CLASSES) must return the 0 sentinel"
);