use core::alloc::Layout;
use core::ptr::NonNull;
use crate::MAX_ALIGN_T as MAX_ALIGN;
use crate::{Alignment, Allocator};
pub struct MaxHeapAllocator {
ptr: Option<NonNull<u8>>,
capacity: usize,
len: usize,
}
unsafe impl Send for MaxHeapAllocator {}
unsafe impl Sync for MaxHeapAllocator {}
impl MaxHeapAllocator {
pub fn alloc(&mut self, len: usize, alignment: Alignment, _ret_addr: usize) -> Option<*mut u8> {
debug_assert!(alignment.to_byte_units() <= MAX_ALIGN);
self.len = 0;
if self.capacity < len {
let new_layout = Layout::from_size_align(len, MAX_ALIGN).ok()?;
let new_ptr = unsafe {
if let Some(old) = self.ptr {
let old_layout = Layout::from_size_align_unchecked(self.capacity, MAX_ALIGN);
std::alloc::realloc(old.as_ptr(), old_layout, len)
} else {
std::alloc::alloc(new_layout)
}
};
let new_ptr = NonNull::new(new_ptr)?;
self.ptr = Some(new_ptr);
self.capacity = len;
}
self.len = len;
Some(self.ptr?.as_ptr())
}
pub fn resize(
&mut self,
_buf: &mut [u8],
_alignment: Alignment,
_new_len: usize,
_ret_addr: usize,
) -> bool {
panic!("not implemented");
}
pub fn free(&mut self, _buf: &mut [u8], _alignment: Alignment, _ret_addr: usize) {}
pub fn reset(&mut self) {
self.len = 0;
}
pub fn scope(&mut self) -> MaxHeapScope<'_> {
MaxHeapScope { inner: self }
}
pub fn init() -> Self {
Self {
ptr: None,
capacity: 0,
len: 0,
}
}
pub fn is_instance(alloc: &dyn Allocator) -> bool {
alloc.is::<Self>()
}
}
pub struct MaxHeapScope<'a> {
inner: &'a mut MaxHeapAllocator,
}
impl core::ops::Deref for MaxHeapScope<'_> {
type Target = MaxHeapAllocator;
fn deref(&self) -> &Self::Target {
self.inner
}
}
impl core::ops::DerefMut for MaxHeapScope<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner
}
}
impl Drop for MaxHeapScope<'_> {
fn drop(&mut self) {
self.inner.reset();
}
}
impl Allocator for MaxHeapAllocator {}
impl Drop for MaxHeapAllocator {
fn drop(&mut self) {
if let Some(ptr) = self.ptr.take() {
unsafe {
std::alloc::dealloc(
ptr.as_ptr(),
Layout::from_size_align_unchecked(self.capacity, MAX_ALIGN),
);
}
}
}
}