2023-12-15 14:13:32 +00:00
|
|
|
use std::{
|
|
|
|
alloc,
|
2023-12-15 17:30:32 +00:00
|
|
|
cell::Cell,
|
|
|
|
ops::{Deref, DerefMut},
|
2023-12-20 15:20:00 +00:00
|
|
|
ptr,
|
2023-12-15 17:30:32 +00:00
|
|
|
rc::Rc,
|
2023-12-15 14:13:32 +00:00
|
|
|
};
|
|
|
|
|
2023-12-15 17:30:32 +00:00
|
|
|
struct ArenaElement {
|
2023-12-20 15:20:00 +00:00
|
|
|
value: *mut u8,
|
|
|
|
drop: unsafe fn(*mut u8),
|
2023-12-15 17:30:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for ArenaElement {
|
2023-12-18 09:41:20 +00:00
|
|
|
#[inline(always)]
|
2023-12-15 17:30:32 +00:00
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
(self.drop)(self.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-15 14:13:32 +00:00
|
|
|
pub struct Arena {
|
2023-12-20 15:20:00 +00:00
|
|
|
start: *mut u8,
|
|
|
|
end: *mut u8,
|
|
|
|
offset: *mut u8,
|
2023-12-15 14:13:32 +00:00
|
|
|
elements: Vec<ArenaElement>,
|
2023-12-15 17:30:32 +00:00
|
|
|
valid: Rc<Cell<bool>>,
|
2023-12-15 14:13:32 +00:00
|
|
|
}
|
|
|
|
|
2023-12-15 17:30:32 +00:00
|
|
|
impl Arena {
|
|
|
|
pub fn new(size_in_bytes: usize) -> Self {
|
2023-12-15 14:13:32 +00:00
|
|
|
unsafe {
|
2023-12-15 17:30:32 +00:00
|
|
|
let layout = alloc::Layout::from_size_align(size_in_bytes, 1).unwrap();
|
2023-12-20 15:20:00 +00:00
|
|
|
let start = alloc::alloc(layout);
|
|
|
|
let end = start.add(size_in_bytes);
|
2023-12-15 14:13:32 +00:00
|
|
|
Self {
|
2023-12-20 15:20:00 +00:00
|
|
|
start,
|
|
|
|
end,
|
|
|
|
offset: start,
|
2023-12-15 14:13:32 +00:00
|
|
|
elements: Vec::new(),
|
2023-12-15 17:30:32 +00:00
|
|
|
valid: Rc::new(Cell::new(true)),
|
2023-12-15 14:13:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn clear(&mut self) {
|
2023-12-15 17:30:32 +00:00
|
|
|
self.valid.set(false);
|
|
|
|
self.valid = Rc::new(Cell::new(true));
|
|
|
|
self.elements.clear();
|
2023-12-20 15:20:00 +00:00
|
|
|
self.offset = self.start;
|
2023-12-15 14:13:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
2023-12-21 08:41:48 +00:00
|
|
|
pub fn alloc<T>(&mut self, f: impl FnOnce() -> T) -> ArenaBox<T> {
|
2023-12-18 09:41:20 +00:00
|
|
|
#[inline(always)]
|
|
|
|
unsafe fn inner_writer<T, F>(ptr: *mut T, f: F)
|
|
|
|
where
|
|
|
|
F: FnOnce() -> T,
|
|
|
|
{
|
|
|
|
ptr::write(ptr, f());
|
|
|
|
}
|
|
|
|
|
2023-12-20 15:20:00 +00:00
|
|
|
unsafe fn drop<T>(ptr: *mut u8) {
|
|
|
|
std::ptr::drop_in_place(ptr.cast::<T>());
|
2023-12-15 14:13:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
2023-12-18 09:41:20 +00:00
|
|
|
let layout = alloc::Layout::new::<T>().pad_to_align();
|
2023-12-20 15:20:00 +00:00
|
|
|
let next_offset = self.offset.add(layout.size());
|
|
|
|
assert!(next_offset <= self.end);
|
2023-12-15 14:13:32 +00:00
|
|
|
|
2023-12-21 08:41:48 +00:00
|
|
|
let result = ArenaBox {
|
2023-12-20 15:20:00 +00:00
|
|
|
ptr: self.offset.cast(),
|
|
|
|
valid: self.valid.clone(),
|
|
|
|
};
|
|
|
|
|
|
|
|
inner_writer(result.ptr, f);
|
2023-12-15 14:13:32 +00:00
|
|
|
self.elements.push(ArenaElement {
|
2023-12-20 15:20:00 +00:00
|
|
|
value: self.offset,
|
2023-12-15 14:13:32 +00:00
|
|
|
drop: drop::<T>,
|
|
|
|
});
|
2023-12-20 15:20:00 +00:00
|
|
|
self.offset = next_offset;
|
|
|
|
|
|
|
|
result
|
2023-12-15 14:13:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-15 17:30:32 +00:00
|
|
|
impl Drop for Arena {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.clear();
|
|
|
|
}
|
|
|
|
}
|
2023-12-15 14:13:32 +00:00
|
|
|
|
2023-12-21 08:41:48 +00:00
|
|
|
pub struct ArenaBox<T: ?Sized> {
|
2023-12-20 15:20:00 +00:00
|
|
|
ptr: *mut T,
|
2023-12-15 17:30:32 +00:00
|
|
|
valid: Rc<Cell<bool>>,
|
|
|
|
}
|
2023-12-15 14:13:32 +00:00
|
|
|
|
2023-12-21 08:41:48 +00:00
|
|
|
impl<T: ?Sized> ArenaBox<T> {
|
2023-12-18 09:41:20 +00:00
|
|
|
#[inline(always)]
|
2023-12-21 08:41:48 +00:00
|
|
|
pub fn map<U: ?Sized>(mut self, f: impl FnOnce(&mut T) -> &mut U) -> ArenaBox<U> {
|
|
|
|
ArenaBox {
|
2023-12-20 15:20:00 +00:00
|
|
|
ptr: f(&mut self),
|
2023-12-15 17:30:32 +00:00
|
|
|
valid: self.valid,
|
|
|
|
}
|
2023-12-15 14:13:32 +00:00
|
|
|
}
|
|
|
|
|
2023-12-15 17:30:32 +00:00
|
|
|
fn validate(&self) {
|
|
|
|
assert!(
|
|
|
|
self.valid.get(),
|
|
|
|
"attempted to dereference an ArenaRef after its Arena was cleared"
|
|
|
|
);
|
2023-12-15 15:18:05 +00:00
|
|
|
}
|
2023-12-15 17:30:32 +00:00
|
|
|
}
|
|
|
|
|
2023-12-21 08:41:48 +00:00
|
|
|
impl<T: ?Sized> Deref for ArenaBox<T> {
|
2023-12-15 17:30:32 +00:00
|
|
|
type Target = T;
|
|
|
|
|
2023-12-18 09:41:20 +00:00
|
|
|
#[inline(always)]
|
2023-12-15 17:30:32 +00:00
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
self.validate();
|
2023-12-20 15:20:00 +00:00
|
|
|
unsafe { &*self.ptr }
|
2023-12-15 17:30:32 +00:00
|
|
|
}
|
|
|
|
}
|
2023-12-15 15:18:05 +00:00
|
|
|
|
2023-12-21 08:41:48 +00:00
|
|
|
impl<T: ?Sized> DerefMut for ArenaBox<T> {
|
2023-12-18 09:41:20 +00:00
|
|
|
#[inline(always)]
|
2023-12-15 17:30:32 +00:00
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
self.validate();
|
2023-12-20 15:20:00 +00:00
|
|
|
unsafe { &mut *self.ptr }
|
2023-12-15 14:13:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-21 08:41:48 +00:00
|
|
|
pub struct ArenaRef<T: ?Sized>(ArenaBox<T>);
|
|
|
|
|
|
|
|
impl<T: ?Sized> From<ArenaBox<T>> for ArenaRef<T> {
|
|
|
|
fn from(value: ArenaBox<T>) -> Self {
|
|
|
|
ArenaRef(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: ?Sized> Clone for ArenaRef<T> {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
Self(ArenaBox {
|
|
|
|
ptr: self.0.ptr,
|
|
|
|
valid: self.0.valid.clone(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: ?Sized> Deref for ArenaRef<T> {
|
|
|
|
type Target = T;
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
self.0.deref()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-15 14:13:32 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use std::{cell::Cell, rc::Rc};
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_arena() {
|
2023-12-15 17:30:32 +00:00
|
|
|
let mut arena = Arena::new(1024);
|
2023-12-18 09:41:20 +00:00
|
|
|
let a = arena.alloc(|| 1u64);
|
|
|
|
let b = arena.alloc(|| 2u32);
|
|
|
|
let c = arena.alloc(|| 3u16);
|
|
|
|
let d = arena.alloc(|| 4u8);
|
2023-12-15 17:30:32 +00:00
|
|
|
assert_eq!(*a, 1);
|
|
|
|
assert_eq!(*b, 2);
|
|
|
|
assert_eq!(*c, 3);
|
|
|
|
assert_eq!(*d, 4);
|
2023-12-15 14:13:32 +00:00
|
|
|
|
|
|
|
arena.clear();
|
2023-12-18 09:41:20 +00:00
|
|
|
let a = arena.alloc(|| 5u64);
|
|
|
|
let b = arena.alloc(|| 6u32);
|
|
|
|
let c = arena.alloc(|| 7u16);
|
|
|
|
let d = arena.alloc(|| 8u8);
|
2023-12-15 17:30:32 +00:00
|
|
|
assert_eq!(*a, 5);
|
|
|
|
assert_eq!(*b, 6);
|
|
|
|
assert_eq!(*c, 7);
|
|
|
|
assert_eq!(*d, 8);
|
2023-12-15 14:13:32 +00:00
|
|
|
|
|
|
|
// Ensure drop gets called.
|
|
|
|
let dropped = Rc::new(Cell::new(false));
|
|
|
|
struct DropGuard(Rc<Cell<bool>>);
|
|
|
|
impl Drop for DropGuard {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.0.set(true);
|
|
|
|
}
|
|
|
|
}
|
2023-12-18 09:41:20 +00:00
|
|
|
arena.alloc(|| DropGuard(dropped.clone()));
|
2023-12-15 14:13:32 +00:00
|
|
|
arena.clear();
|
|
|
|
assert!(dropped.get());
|
|
|
|
}
|
|
|
|
}
|