mod hole;
pub(crate) mod layout;
use self::layout::Layout;
use core::mem;
#[cfg(feature = "use_spin")]
use core::ops::Deref;
use core::ptr::NonNull;
use hole::{Hole, HoleList};
#[cfg(feature = "use_spin")]
use spinning_top::Spinlock;
pub struct Heap {
bottom: usize,
size: usize,
used: usize,
holes: HoleList,
}
impl Heap {
pub fn empty() -> Heap {
Heap {
bottom: 0,
size: 0,
used: 0,
holes: HoleList::empty(),
}
}
pub unsafe fn init(&mut self, heap_bottom: usize, heap_size: usize) {
self.bottom = heap_bottom;
self.size = heap_size;
self.used = 0;
self.holes = HoleList::new(heap_bottom, heap_size);
}
pub unsafe fn new(heap_bottom: usize, heap_size: usize) -> Heap {
if heap_size < HoleList::min_size() {
Self::empty()
} else {
Heap {
bottom: heap_bottom,
size: heap_size,
used: 0,
holes: HoleList::new(heap_bottom, heap_size),
}
}
}
fn align_layout(layout: Layout) -> Layout {
let mut size = layout.size();
if size < HoleList::min_size() {
size = HoleList::min_size();
}
let size = align_up(size, mem::align_of::<Hole>());
Layout::from_size_align(size, layout.align()).unwrap()
}
pub fn allocate_first_fit(&mut self, layout: Layout) -> Result<NonNull<u8>, ()> {
let aligned_layout = Self::align_layout(layout);
let res = self.holes.allocate_first_fit(aligned_layout);
if res.is_ok() {
self.used += aligned_layout.size();
}
res
}
pub unsafe fn deallocate(&mut self, ptr: NonNull<u8>, layout: Layout) {
let aligned_layout = Self::align_layout(layout);
self.holes.deallocate(ptr, aligned_layout);
self.used -= aligned_layout.size();
}
pub fn bottom(&self) -> usize {
self.bottom
}
pub fn size(&self) -> usize {
self.size
}
pub fn top(&self) -> usize {
self.bottom + self.size
}
pub fn used(&self) -> usize {
self.used
}
pub fn free(&self) -> usize {
self.size - self.used
}
pub unsafe fn extend(&mut self, by: usize) {
let top = self.top();
let layout = Layout::from_size_align(by, 1).unwrap();
self.holes
.deallocate(NonNull::new_unchecked(top as *mut u8), layout);
self.size += by;
}
}
pub fn align_down(addr: usize, align: usize) -> usize {
if align.is_power_of_two() {
addr & !(align - 1)
} else if align == 0 {
addr
} else {
panic!("`align` must be a power of 2");
}
}
pub fn align_up(addr: usize, align: usize) -> usize {
align_down(addr + align - 1, align)
}