use crate::error::{Error, Result};
#[inline]
pub const fn is_power_of_two(n: usize) -> bool {
n > 0 && (n & (n - 1)) == 0
}
#[inline]
pub fn validate_alignment(alignment: usize) -> Result<()> {
if is_power_of_two(alignment) {
Ok(())
} else {
Err(Error::InvalidAlignment { alignment })
}
}
#[inline]
#[allow(dead_code)]
pub const fn align_up(size: usize, alignment: usize) -> usize {
(size + alignment - 1) & !(alignment - 1)
}
#[inline]
#[allow(dead_code)]
pub const fn aligned_size<T>(alignment: usize) -> usize {
align_up(core::mem::size_of::<T>(), alignment)
}
#[inline]
#[allow(dead_code)]
pub const fn padding_needed(size: usize, alignment: usize) -> usize {
let aligned = align_up(size, alignment);
aligned - size
}
#[inline]
pub fn compute_exponential_growth(current: usize, factor: f64) -> usize {
let growth = (current as f64 * factor) as usize;
growth.max(1) }
#[inline]
#[allow(dead_code)]
pub const fn compute_linear_growth(amount: usize) -> usize {
amount
}
#[inline]
#[allow(dead_code)]
pub fn clamp_capacity(value: usize, min: usize, max: Option<usize>) -> usize {
let clamped = value.max(min);
if let Some(max_val) = max {
clamped.min(max_val)
} else {
clamped
}
}
#[allow(dead_code)]
pub fn next_chunk_size(
current_capacity: usize,
growth_strategy: &crate::config::GrowthStrategy,
) -> usize {
match growth_strategy {
crate::config::GrowthStrategy::None => 0,
crate::config::GrowthStrategy::Linear { amount } => *amount,
crate::config::GrowthStrategy::Exponential { factor } => {
compute_exponential_growth(current_capacity, *factor)
}
crate::config::GrowthStrategy::Custom { compute } => compute(current_capacity),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_power_of_two() {
assert!(is_power_of_two(1));
assert!(is_power_of_two(2));
assert!(is_power_of_two(4));
assert!(is_power_of_two(8));
assert!(is_power_of_two(64));
assert!(is_power_of_two(1024));
assert!(!is_power_of_two(0));
assert!(!is_power_of_two(3));
assert!(!is_power_of_two(7));
assert!(!is_power_of_two(100));
}
#[test]
fn test_validate_alignment() {
assert!(validate_alignment(1).is_ok());
assert!(validate_alignment(2).is_ok());
assert!(validate_alignment(4).is_ok());
assert!(validate_alignment(64).is_ok());
assert!(validate_alignment(0).is_err());
assert!(validate_alignment(3).is_err());
assert!(validate_alignment(7).is_err());
}
#[test]
fn test_align_up() {
assert_eq!(align_up(0, 4), 0);
assert_eq!(align_up(1, 4), 4);
assert_eq!(align_up(4, 4), 4);
assert_eq!(align_up(5, 4), 8);
assert_eq!(align_up(7, 8), 8);
assert_eq!(align_up(9, 8), 16);
assert_eq!(align_up(100, 64), 128);
}
#[test]
fn test_padding_needed() {
assert_eq!(padding_needed(0, 4), 0);
assert_eq!(padding_needed(1, 4), 3);
assert_eq!(padding_needed(4, 4), 0);
assert_eq!(padding_needed(5, 4), 3);
assert_eq!(padding_needed(7, 8), 1);
assert_eq!(padding_needed(9, 8), 7);
}
#[test]
fn test_compute_exponential_growth() {
assert_eq!(compute_exponential_growth(100, 2.0), 200);
assert_eq!(compute_exponential_growth(100, 1.5), 150);
assert_eq!(compute_exponential_growth(0, 2.0), 1); }
#[test]
fn test_clamp_capacity() {
assert_eq!(clamp_capacity(50, 10, Some(100)), 50);
assert_eq!(clamp_capacity(5, 10, Some(100)), 10);
assert_eq!(clamp_capacity(150, 10, Some(100)), 100);
assert_eq!(clamp_capacity(150, 10, None), 150);
}
}