Initial commit
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "leaf_allocators"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
boxcar = "0.2.14"
|
||||
bumpalo = "3.19.0"
|
||||
@@ -0,0 +1,73 @@
|
||||
use crate::{AllocationEntry, Allocator, DropFn};
|
||||
use boxcar::Vec;
|
||||
use bumpalo::Bump;
|
||||
use std::{alloc::Layout, sync::Mutex};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ArenaAllocator {
|
||||
bump: Bump,
|
||||
allocations: Vec<AllocationEntry>,
|
||||
}
|
||||
|
||||
impl Allocator for ArenaAllocator {
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
unsafe {
|
||||
let ptr = self.bump.alloc_layout(layout).as_ptr();
|
||||
std::ptr::copy_nonoverlapping(data, ptr, layout.size());
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ArenaAllocator {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
for AllocationEntry { ptr, drop_fn, .. } in std::mem::take(&mut self.allocations) {
|
||||
if let Some(drop) = drop_fn {
|
||||
drop(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SyncArenaAllocator {
|
||||
bump: Mutex<Bump>,
|
||||
allocations: Vec<AllocationEntry>,
|
||||
}
|
||||
|
||||
impl Allocator for SyncArenaAllocator {
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
unsafe {
|
||||
let ptr = {
|
||||
let bump = self.bump.lock().unwrap();
|
||||
bump.alloc_layout(layout).as_ptr()
|
||||
};
|
||||
std::ptr::copy_nonoverlapping(data, ptr, layout.size());
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SyncArenaAllocator {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
for AllocationEntry { ptr, drop_fn, .. } in std::mem::take(&mut self.allocations) {
|
||||
if let Some(drop) = drop_fn {
|
||||
drop(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
use crate::{AllocationEntry, Allocator, DropFn};
|
||||
use boxcar::Vec;
|
||||
use std::alloc::Layout;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GlobalAllocator {
|
||||
allocations: Vec<AllocationEntry>,
|
||||
}
|
||||
|
||||
impl Allocator for GlobalAllocator {
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop_fn: DropFn) -> *mut u8 {
|
||||
unsafe {
|
||||
let ptr = std::alloc::alloc(layout);
|
||||
std::ptr::copy_nonoverlapping(data, ptr, layout.size());
|
||||
self.allocations.push(AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
});
|
||||
ptr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GlobalAllocator {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
for AllocationEntry {
|
||||
ptr,
|
||||
layout,
|
||||
drop_fn,
|
||||
} in std::mem::take(&mut self.allocations)
|
||||
{
|
||||
if let Some(drop) = drop_fn {
|
||||
drop(ptr);
|
||||
}
|
||||
std::alloc::dealloc(ptr, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
mod arena;
|
||||
mod global;
|
||||
|
||||
pub use arena::*;
|
||||
pub use global::*;
|
||||
use std::{alloc::Layout, mem::MaybeUninit};
|
||||
|
||||
pub type DropFn = Option<unsafe fn(*mut u8)>;
|
||||
|
||||
pub struct AllocationEntry {
|
||||
ptr: *mut u8,
|
||||
layout: Layout,
|
||||
drop_fn: DropFn,
|
||||
}
|
||||
|
||||
unsafe impl Send for AllocationEntry {}
|
||||
unsafe impl Sync for AllocationEntry {}
|
||||
|
||||
pub trait Allocator {
|
||||
unsafe fn alloc_unsafe(&self, data: *const u8, layout: Layout, drop: DropFn) -> *mut u8;
|
||||
}
|
||||
|
||||
pub trait SyncAllocator: Allocator + Send + Sync {}
|
||||
|
||||
impl<T: Allocator + Send + Sync> SyncAllocator for T {}
|
||||
|
||||
impl<'l> dyn Allocator + 'l {
|
||||
pub fn alloc<T>(&'l self, value: T) -> &'l mut T {
|
||||
unsafe {
|
||||
let value = MaybeUninit::new(value);
|
||||
let data = value.as_ptr() as *const u8;
|
||||
let layout = Layout::new::<T>();
|
||||
let drop: DropFn = match std::mem::needs_drop::<T>() {
|
||||
false => None,
|
||||
true => Some(|ptr: *mut u8| std::ptr::drop_in_place(ptr as *mut T)),
|
||||
};
|
||||
&mut *(self.alloc_unsafe(data, layout, drop) as *mut T)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l> dyn SyncAllocator + 'l {
|
||||
pub fn alloc<T: Send>(&'l self, value: T) -> &'l mut T {
|
||||
<dyn Allocator>::alloc(self, value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user