use std::alloc::Layout;
use std::sync::Arc;
use crate::config::MkConfig;
use crate::container::{MkFrameBox, MkFrameSlice, MkFrameVec, MkPoolBox, MkHeapBox};
use crate::core::global::GlobalState;
use crate::core::tls;
use crate::lifecycle::MkScope;
pub mod handle;
pub use handle::{MkHandle, MkHandleAllocator};
#[derive(Clone)]
pub struct MkAllocator {
global: Arc<GlobalState>,
}
impl MkAllocator {
pub fn new(config: MkConfig) -> Self {
let global = Arc::new(GlobalState::new(config));
Self { global }
}
pub fn with_defaults() -> Self {
Self::new(MkConfig::default())
}
pub fn config(&self) -> &MkConfig {
self.global.config()
}
fn ensure_tls(&self) {
if !tls::is_tls_initialized() {
tls::init_tls(self.global.config().frame_arena_size, Arc::clone(&self.global));
}
}
#[inline]
pub fn begin_frame(&self) {
self.ensure_tls();
self.global.next_frame();
tls::with_tls_mut(|tls| tls.begin_frame());
}
#[inline]
pub fn end_frame(&self) {
self.ensure_tls();
tls::with_tls_mut(|tls| tls.end_frame());
}
pub fn frame(&self) -> u64 {
self.global.frame()
}
#[inline(always)]
pub fn frame_alloc<T>(&self) -> *mut T {
self.ensure_tls();
tls::with_tls_mut(|tls| tls.frame_alloc::<T>())
}
#[inline(always)]
pub fn frame_box<T>(&self, value: T) -> Option<MkFrameBox<'_, T>> {
self.ensure_tls();
let ptr = tls::with_tls_mut(|tls| tls.frame_alloc_value(value));
if ptr.is_null() {
None
} else {
unsafe { MkFrameBox::from_raw(ptr) }
}
}
#[inline(always)]
pub fn frame_slice<T>(&self, len: usize) -> Option<MkFrameSlice<'_, T>> {
self.ensure_tls();
let ptr = tls::with_tls_mut(|tls| tls.frame_alloc_slice::<T>(len));
if ptr.is_null() {
None
} else {
unsafe { MkFrameSlice::from_raw_parts(ptr, len) }
}
}
pub fn frame_vec<T>(&self, capacity: usize) -> Option<MkFrameVec<'_, T>> {
self.ensure_tls();
let ptr = tls::with_tls_mut(|tls| tls.frame_alloc_slice::<T>(capacity));
if ptr.is_null() {
None
} else {
Some(unsafe { MkFrameVec::from_raw_parts(ptr, capacity) })
}
}
pub fn pool_box<T>(&self, value: T) -> Option<MkPoolBox<T>> {
let layout = Layout::new::<T>();
let ptr = self.global.heap_alloc(layout) as *mut T;
if ptr.is_null() {
None
} else {
unsafe {
ptr.write(value);
MkPoolBox::from_raw(ptr, self.global.clone())
}
}
}
pub fn heap_box<T>(&self, value: T) -> Option<MkHeapBox<T>> {
let layout = Layout::new::<T>();
let ptr = unsafe { std::alloc::alloc(layout) as *mut T };
if ptr.is_null() {
None
} else {
unsafe {
ptr.write(value);
MkHeapBox::from_raw(ptr)
}
}
}
pub fn scope(&self) -> MkScope<'_> {
self.ensure_tls();
MkScope::new(self)
}
pub fn frame_head(&self) -> usize {
self.ensure_tls();
tls::with_tls(|tls| tls.frame_head())
}
pub fn reset_frame_to(&self, pos: usize) {
self.ensure_tls();
tls::with_tls(|tls| tls.reset_frame_to(pos));
}
pub fn stats(&self) -> crate::core::global::GlobalStats {
self.global.stats()
}
pub fn begin_phase(&self, name: &'static str) -> crate::lifecycle::MkPhase {
self.ensure_tls();
crate::lifecycle::MkPhase::begin(name)
}
pub unsafe fn deferred_free<T>(&self, ptr: *mut T, drop_fn: Option<unsafe fn(*mut T)>) {
let layout = std::alloc::Layout::new::<T>();
let drop_fn_u8 = std::mem::transmute::<Option<unsafe fn(*mut T)>, Option<unsafe fn(*mut u8)>>(drop_fn);
self.global.deferred_queue().push(ptr as *mut u8, layout, drop_fn_u8);
}
pub fn reclaim(&self) -> usize {
let global = Arc::clone(&self.global);
self.global.deferred_queue().reclaim(|ptr, layout| {
global.heap_free(ptr, layout);
})
}
pub fn handle_alloc(&self, ptr: *mut u8) -> MkHandle {
self.global.handle_allocator().allocate(ptr)
}
pub fn handle_resolve(&self, handle: MkHandle) -> Option<*mut u8> {
self.global.handle_allocator().resolve(handle)
}
pub fn handle_update(&self, handle: MkHandle, new_ptr: *mut u8) -> bool {
self.global.handle_allocator().update(handle, new_ptr)
}
pub fn handle_free(&self, handle: MkHandle) -> bool {
self.global.handle_allocator().deallocate(handle)
}
}