use std::alloc::{GlobalAlloc, Layout, System};
pub(crate) struct LeakyBumpAlloc {
layout: Layout,
start: *mut u8,
end: *mut u8,
ptr: *mut u8,
}
impl LeakyBumpAlloc {
pub fn new(capacity: usize, alignment: usize) -> LeakyBumpAlloc {
let layout = Layout::from_size_align(capacity, alignment).unwrap();
let start = unsafe { System.alloc(layout) };
if start.is_null() {
panic!("oom");
}
let end = unsafe { start.add(layout.size()) };
let ptr = end;
LeakyBumpAlloc {
layout,
start,
end,
ptr,
}
}
#[doc(hidden)]
pub unsafe fn clear(&mut self) {
System.dealloc(self.start, self.layout);
}
pub unsafe fn allocate(&mut self, num_bytes: usize) -> *mut u8 {
let ptr = self.ptr as usize;
let new_ptr = ptr.checked_sub(num_bytes).expect("ptr sub overflowed");
let new_ptr = new_ptr & !(self.layout.align() - 1);
let start = self.start as usize;
if new_ptr < start {
eprintln!(
"Allocator asked to bump to {} bytes with a capacity of {}",
self.end as usize - new_ptr,
self.capacity()
);
std::process::abort();
}
self.ptr = self.ptr.sub(ptr - new_ptr);
self.ptr
}
pub fn allocated(&self) -> usize {
self.end as usize - self.ptr as usize
}
pub fn capacity(&self) -> usize {
self.layout.size()
}
pub(crate) fn end(&self) -> *const u8 {
self.end
}
pub(crate) fn ptr(&self) -> *const u8 {
self.ptr
}
}