#![allow(static_mut_refs)]
#[cfg(not(feature = "arena-alloc"))]
use crate::libc;
use core::alloc::Layout;
#[cfg(not(feature = "arena-alloc"))]
use core::ffi::c_void;
#[cfg(feature = "panic-on-realloc")]
static mut IS_FIRST_REALLOC: bool = true;
#[cfg(feature = "arena-alloc")]
use core::sync::atomic::{AtomicUsize, Ordering};
#[cfg(feature = "print-allocations")]
use crate::common::utils::to_ascii;
#[cfg(feature = "arena-alloc")]
const ALIGN: usize = 16;
#[cfg(feature = "arena-alloc")]
const MEM_SIZE: usize = 2 * 1024 * 1024;
#[cfg(feature = "arena-alloc")]
#[repr(align(16))]
struct Heap(pub [u8; MEM_SIZE]);
#[cfg(feature = "arena-alloc")]
static mut HEAP: Heap = Heap([0u8; MEM_SIZE]);
#[cfg(feature = "arena-alloc")]
static mut OFFSET: AtomicUsize = AtomicUsize::new(0);
pub struct LibcAlloc;
unsafe impl core::alloc::GlobalAlloc for LibcAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
#[cfg(feature = "print-allocations")]
{
let mut buf = [0u8; 16];
buf[0] = b'+';
let len = to_ascii(layout.size(), &mut buf[1..]);
unsafe { crate::libc::write(2, buf.as_ptr().cast(), len) };
}
#[cfg(not(feature = "arena-alloc"))]
unsafe {
libc::malloc(layout.size().max(layout.align())) as *mut u8
}
#[cfg(feature = "arena-alloc")]
{
let next_offset = layout.size().next_multiple_of(ALIGN);
unsafe {
HEAP.0
.as_mut_ptr()
.add(OFFSET.fetch_add(next_offset, Ordering::Relaxed))
}
}
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
#[cfg(feature = "print-allocations")]
{
let mut buf = [0u8; 16];
buf[0] = b'+';
let len = to_ascii(layout.size(), &mut buf[1..]);
unsafe { crate::libc::write(2, buf.as_ptr().cast(), len) };
}
#[cfg(not(feature = "arena-alloc"))]
unsafe {
libc::calloc(1, layout.size().max(layout.align())) as *mut u8
}
#[cfg(feature = "arena-alloc")]
{
let next_offset = layout.size().next_multiple_of(ALIGN);
unsafe {
HEAP.0
.as_mut_ptr()
.add(OFFSET.fetch_add(next_offset, Ordering::Relaxed))
}
}
}
#[allow(unused_variables)]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
#[cfg(feature = "print-allocations")]
{
let mut buf = [0u8; 16];
buf[0] = b'-';
let len = to_ascii(layout.size(), &mut buf[1..]);
unsafe { crate::libc::write(2, buf.as_ptr().cast(), len) };
}
#[cfg(not(feature = "arena-alloc"))]
unsafe {
libc::free(ptr as *mut c_void)
}
}
#[cfg(not(feature = "arena-alloc"))]
#[allow(unused_variables)]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
#[cfg(feature = "print-allocations")]
{
let mut buf = [0u8; 16];
buf[0] = b'\\';
let len = to_ascii(layout.size(), &mut buf[1..]);
unsafe { crate::libc::write(2, buf.as_ptr().cast(), len) };
buf[0] = b'/';
let len = to_ascii(new_size, &mut buf[1..]);
unsafe { crate::libc::write(2, buf.as_ptr().cast(), len) };
}
#[cfg(feature = "panic-on-realloc")]
unsafe {
if IS_FIRST_REALLOC {
IS_FIRST_REALLOC = false;
panic!("realloc {} -> {}", layout.size(), new_size);
}
}
unsafe { libc::realloc(ptr as *mut c_void, new_size) as *mut u8 }
}
}