#![no_std]
extern crate alloc;
use core::{ptr, cmp};
use core::cell::{Cell, UnsafeCell};
use alloc::alloc::{alloc, Layout};
use alloc::{boxed::Box, vec::Vec};
pub struct Arena {
slabs: UnsafeCell<Vec<Box<[u8]>>>,
next: Cell<*mut u8>,
end: Cell<*mut u8>,
}
const SLAB_SIZE: usize = 0x1000;
impl Default for Arena {
#[inline]
fn default() -> Self {
let slabs = UnsafeCell::new(Vec::default());
let next = Cell::new(ptr::dangling_mut());
let end = Cell::new(ptr::dangling_mut());
Arena { slabs, next, end }
}
}
impl Arena {
#[inline]
pub unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let next = self.next.get();
let end = self.end.get();
let offset = align_offset(next as usize, layout.align());
if offset + layout.size() <= end as usize - next as usize {
let ptr = next.add(offset);
self.next.set(ptr.add(layout.size()));
return ptr;
}
self.alloc_new_slab(layout)
}
#[cold]
unsafe fn alloc_new_slab(&self, layout: Layout) -> *mut u8 {
let padded = layout.size() + layout.align() - 1;
if padded > SLAB_SIZE {
let next = self.alloc_slab(padded);
if next == ptr::null_mut() { return ptr::null_mut(); }
let offset = align_offset(next as usize, layout.align());
return next.add(offset);
}
let slabs = &*self.slabs.get();
let size = SLAB_SIZE * (1 << cmp::min(30, slabs.len() / 128));
let next = self.alloc_slab(size);
if next == ptr::null_mut() { return ptr::null_mut(); }
let offset = align_offset(next as usize, layout.align());
let ptr = next.add(offset);
self.next.set(ptr.add(layout.size()));
self.end.set(next.add(size));
ptr
}
unsafe fn alloc_slab(&self, size: usize) -> *mut u8 {
let slabs = &mut *self.slabs.get();
let next = alloc(Layout::from_size_align_unchecked(size, 1));
if next == ptr::null_mut() { return ptr::null_mut(); }
let slab = Box::from_raw(ptr::slice_from_raw_parts_mut(next, size));
slabs.push(slab);
slabs.last_mut().unwrap().as_mut_ptr()
}
}
fn align_offset(size: usize, align: usize) -> usize {
align_to(size, align) - size
}
fn align_to(size: usize, align: usize) -> usize {
(size + align - 1) & !(align - 1)
}