use core::alloc::{GlobalAlloc, Layout};
use core::mem::size_of;
use core::ptr;
use cty::c_void;
pub struct CAllocator;
const MIN_ALIGN: usize = size_of::<usize>();
unsafe impl GlobalAlloc for CAllocator {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
ndless_sys::malloc(layout.size()) as *mut u8
} else {
malloc_aligned(layout.align(), layout.size()) as *mut u8
}
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
ndless_sys::calloc(layout.size(), 1) as *mut u8
} else {
let ptr = self.alloc(layout.clone());
if !ptr.is_null() {
ptr::write_bytes(ptr, 0, layout.size());
}
ptr
}
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
ndless_sys::free(ptr as *mut c_void);
} else {
free_aligned(ptr as *mut c_void);
}
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
ndless_sys::realloc(ptr as *mut c_void, new_size) as *mut u8
} else {
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
let new_ptr = GlobalAlloc::alloc(self, new_layout);
if !new_ptr.is_null() {
let size = core::cmp::min(layout.size(), new_size);
ptr::copy_nonoverlapping(ptr, new_ptr, size);
GlobalAlloc::dealloc(self, ptr, layout);
}
new_ptr
}
}
}
const USIZE_SIZE: usize = size_of::<usize>();
unsafe fn malloc_aligned(alignment: usize, bytes: usize) -> *mut c_void {
let total_size = bytes + (2 * alignment) + USIZE_SIZE;
let data = ndless_sys::malloc(total_size);
if !data.is_null() {
let data_start = data as *const c_void;
let data = data.add(USIZE_SIZE);
let offset = alignment - ((data as usize) % alignment);
let data = data.add(offset);
let book_keeping = (data.sub(USIZE_SIZE)) as *mut usize;
*book_keeping = data_start as usize;
data
} else {
data
}
}
unsafe fn free_aligned(raw_data: *mut c_void) {
if !raw_data.is_null() {
let data = raw_data as *mut i8;
let data = data.sub(USIZE_SIZE);
let data = (*(data as *mut usize)) as *mut i8;
ndless_sys::free(data as *mut c_void);
}
}