#![no_std]
#![cfg_attr(feature = "allocator_api", feature(allocator_api))]
#[cfg(feature = "bitmap")]
mod bitmap;
#[cfg(feature = "bitmap")]
pub use bitmap::BitmapPageAllocator;
#[cfg(feature = "buddy")]
mod buddy;
#[cfg(feature = "buddy")]
pub use buddy::BuddyByteAllocator;
#[cfg(feature = "slab")]
mod slab;
#[cfg(feature = "slab")]
pub use slab::SlabByteAllocator;
#[cfg(feature = "tlsf")]
mod tlsf;
use core::{alloc::Layout, ptr::NonNull};
#[cfg(feature = "axerrno")]
use axerrno::AxError;
#[cfg(feature = "tlsf")]
pub use tlsf::TlsfByteAllocator;
#[derive(Debug)]
pub enum AllocError {
InvalidParam,
MemoryOverlap,
NoMemory,
NotAllocated,
}
#[cfg(feature = "axerrno")]
impl From<AllocError> for AxError {
fn from(value: AllocError) -> Self {
match value {
AllocError::NoMemory => AxError::NoMemory,
_ => AxError::InvalidInput,
}
}
}
pub type AllocResult<T = ()> = Result<T, AllocError>;
pub trait BaseAllocator {
fn init(&mut self, start: usize, size: usize);
fn add_memory(&mut self, start: usize, size: usize) -> AllocResult;
}
pub trait ByteAllocator: BaseAllocator {
fn alloc(&mut self, layout: Layout) -> AllocResult<NonNull<u8>>;
fn dealloc(&mut self, pos: NonNull<u8>, layout: Layout);
fn total_bytes(&self) -> usize;
fn used_bytes(&self) -> usize;
fn available_bytes(&self) -> usize;
}
pub trait PageAllocator: BaseAllocator {
const PAGE_SIZE: usize;
fn alloc_pages(&mut self, num_pages: usize, align_pow2: usize) -> AllocResult<usize>;
fn dealloc_pages(&mut self, pos: usize, num_pages: usize);
fn alloc_pages_at(
&mut self,
base: usize,
num_pages: usize,
align_pow2: usize,
) -> AllocResult<usize>;
fn total_pages(&self) -> usize;
fn used_pages(&self) -> usize;
fn available_pages(&self) -> usize;
}
pub trait IdAllocator: BaseAllocator {
fn alloc_id(&mut self, count: usize, align_pow2: usize) -> AllocResult<usize>;
fn dealloc_id(&mut self, start_id: usize, count: usize);
fn is_allocated(&self, id: usize) -> bool;
fn alloc_fixed_id(&mut self, id: usize) -> AllocResult;
fn size(&self) -> usize;
fn used(&self) -> usize;
fn available(&self) -> usize;
}
#[inline]
#[allow(dead_code)]
const fn align_down(pos: usize, align: usize) -> usize {
pos & !(align - 1)
}
#[inline]
#[allow(dead_code)]
const fn align_up(pos: usize, align: usize) -> usize {
(pos + align - 1) & !(align - 1)
}
#[inline]
#[allow(dead_code)]
const fn is_aligned(base_addr: usize, align: usize) -> bool {
base_addr & (align - 1) == 0
}
#[cfg(feature = "allocator_api")]
mod allocator_api {
extern crate alloc;
use alloc::rc::Rc;
use core::{
alloc::{AllocError, Allocator, Layout},
cell::RefCell,
ptr::NonNull,
};
use super::ByteAllocator;
pub struct AllocatorRc<A: ByteAllocator>(Rc<RefCell<A>>);
impl<A: ByteAllocator> AllocatorRc<A> {
pub fn new(mut inner: A, pool: &mut [u8]) -> Self {
inner.init(pool.as_mut_ptr() as usize, pool.len());
Self(Rc::new(RefCell::new(inner)))
}
}
unsafe impl<A: ByteAllocator> Allocator for AllocatorRc<A> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(NonNull::dangling(), 0)),
size => {
let raw_addr = self.0.borrow_mut().alloc(layout).map_err(|_| AllocError)?;
Ok(NonNull::slice_from_raw_parts(raw_addr, size))
}
}
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
self.0.borrow_mut().dealloc(ptr, layout)
}
}
impl<A: ByteAllocator> Clone for AllocatorRc<A> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
}
#[cfg(feature = "allocator_api")]
pub use allocator_api::AllocatorRc;