blob: 572d253309cee229bc78aec6c266fe747d577af3 [file] [log] [blame]
use core::alloc::{GlobalAlloc, Layout};
use core::cell::UnsafeCell;
#[global_allocator]
static ALLOCATOR: ArenaAllocator = ArenaAllocator::new();
/// Very simple allocator which never deallocates memory
///
/// Based on the example from
/// https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html
pub struct ArenaAllocator {
arena: UnsafeCell<Arena>,
}
impl ArenaAllocator {
pub const fn new() -> Self {
Self {
arena: UnsafeCell::new(Arena::new()),
}
}
}
/// Safe because we are singlethreaded
unsafe impl Sync for ArenaAllocator {}
unsafe impl GlobalAlloc for ArenaAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let arena = &mut *self.arena.get();
arena.alloc(layout)
}
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
}
const ARENA_SIZE: usize = 64 * 1024; // more than enough
#[repr(C, align(4096))]
struct Arena {
buf: [u8; ARENA_SIZE], // aligned at 4096
allocated: usize,
}
impl Arena {
pub const fn new() -> Self {
Self {
buf: [0x55; ARENA_SIZE],
allocated: 0,
}
}
pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 {
if layout.align() > 4096 || layout.size() > ARENA_SIZE {
return core::ptr::null_mut();
}
let align_minus_one = layout.align() - 1;
let start = (self.allocated + align_minus_one) & !align_minus_one; // round up
let new_cursor = start + layout.size();
if new_cursor >= ARENA_SIZE {
return core::ptr::null_mut();
}
self.allocated = new_cursor;
self.buf.as_mut_ptr().add(start)
}
}