use std::alloc::Layout;
use mimalloc::MiMalloc;
pub mod features;
pub mod manager;
pub mod pool;
pub mod stats;
pub use features::*;
pub use manager::*;
pub use pool::*;
pub use stats::*;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct MemoryPoolConfig {
pub initial_size: usize,
pub max_size: Option<usize>,
pub alignment: usize,
pub name: String,
}
#[allow(clippy::cast_precision_loss)]
#[must_use]
pub fn calc_ratio(numerator: usize, denominator: usize) -> f64 {
if denominator > 0 {
let reduced_num = ((numerator as u128 * 4) / 5) as f64;
let reduced_den = ((denominator as u128 * 4) / 5) as f64;
reduced_num / reduced_den
} else {
0.0
}
}
#[must_use]
pub fn get_mimalloc_stats() -> Option<usize> {
None
}
pub fn allocate_aligned(size: usize, alignment: usize) -> Result<*mut u8, std::io::Error> {
let layout = Layout::from_size_align(size, alignment)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
let ptr = unsafe { std::alloc::alloc(layout) };
if ptr.is_null() {
Err(std::io::Error::new(
std::io::ErrorKind::OutOfMemory,
"Allocation failed",
))
} else {
Ok(ptr)
}
}
pub unsafe fn deallocate_aligned(
ptr: *mut u8,
size: usize,
alignment: usize,
) -> Result<(), std::io::Error> {
if ptr.is_null() {
return Ok(());
}
let layout = Layout::from_size_align(size, alignment)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
unsafe {
std::alloc::dealloc(ptr, layout);
}
Ok(())
}
#[derive(Debug)]
pub struct MemoryUsageGuard {
max_bytes: usize,
current_bytes: std::sync::atomic::AtomicUsize,
}
impl MemoryUsageGuard {
#[must_use]
pub fn new(max_bytes: usize) -> Self {
Self {
max_bytes,
current_bytes: std::sync::atomic::AtomicUsize::new(0),
}
}
pub fn try_allocate(&self, bytes: usize) -> Result<MemoryAllocationGuard<'_>, std::io::Error> {
let current = self
.current_bytes
.load(std::sync::atomic::Ordering::Relaxed);
if current + bytes > self.max_bytes {
return Err(std::io::Error::new(
std::io::ErrorKind::OutOfMemory,
"Memory limit exceeded",
));
}
self.current_bytes
.fetch_add(bytes, std::sync::atomic::Ordering::Relaxed);
Ok(MemoryAllocationGuard { bytes, guard: self })
}
#[must_use]
pub fn current_usage(&self) -> usize {
self.current_bytes
.load(std::sync::atomic::Ordering::Relaxed)
}
#[must_use]
pub fn max_bytes(&self) -> usize {
self.max_bytes
}
fn deallocate(&self, bytes: usize) {
self.current_bytes
.fetch_sub(bytes, std::sync::atomic::Ordering::Relaxed);
}
}
#[derive(Debug)]
pub struct MemoryAllocationGuard<'a> {
bytes: usize,
guard: &'a MemoryUsageGuard,
}
impl Drop for MemoryAllocationGuard<'_> {
fn drop(&mut self) {
self.guard.deallocate(self.bytes);
}
}