use super::{AllocError, tlsf::Tlsf};
use std::sync::Arc;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum PlacementStrategy {
#[default]
Default,
MinMemory,
MinTime,
MinOffset,
}
pub struct VirtualAllocation {
owner: Arc<()>,
index: usize,
serial: u64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct VirtualAllocationInfo {
pub offset: u64,
pub size: u64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct VirtualBlockStats {
pub size: u64,
pub allocation_count: usize,
pub allocated_bytes: u64,
pub free_bytes: u64,
pub free_region_count: usize,
pub largest_free_region: u64,
}
pub struct VirtualBlock {
owner: Arc<()>,
metadata: Tlsf,
}
impl VirtualBlock {
pub fn new(size: u64) -> Result<Self, AllocError> {
Ok(Self {
owner: Arc::new(()),
metadata: Tlsf::new(size)?,
})
}
pub fn allocate(
&mut self,
size: u64,
alignment: u64,
strategy: PlacementStrategy,
) -> Result<VirtualAllocation, AllocError> {
allocate(self, size, alignment, strategy)
}
pub fn free(&mut self, allocation: &mut VirtualAllocation) -> Result<(), AllocError> {
free(self, allocation)
}
pub fn allocation_info(
&self,
allocation: &VirtualAllocation,
) -> Result<VirtualAllocationInfo, AllocError> {
allocation_info(self, allocation)
}
pub fn clear(&mut self) {
clear(self)
}
pub fn statistics(&self) -> VirtualBlockStats {
statistics(self)
}
}
pub fn allocate(
block: &mut VirtualBlock,
size: u64,
alignment: u64,
strategy: PlacementStrategy,
) -> Result<VirtualAllocation, AllocError> {
let (index, serial) = block.metadata.allocate(size, alignment, strategy)?;
Ok(VirtualAllocation {
owner: block.owner.clone(),
index,
serial,
})
}
pub fn allocation_info(
block: &VirtualBlock,
allocation: &VirtualAllocation,
) -> Result<VirtualAllocationInfo, AllocError> {
if !Arc::ptr_eq(&block.owner, &allocation.owner) {
return Err(AllocError::WrongAllocator);
}
block.metadata.info(allocation.index, allocation.serial)
}
pub fn free(
block: &mut VirtualBlock,
allocation: &mut VirtualAllocation,
) -> Result<(), AllocError> {
allocation_info(block, allocation)?;
block.metadata.free(allocation.index, allocation.serial)?;
allocation.index = usize::MAX;
Ok(())
}
pub fn clear(block: &mut VirtualBlock) {
block.metadata.clear()
}
pub fn statistics(block: &VirtualBlock) -> VirtualBlockStats {
block.metadata.statistics()
}