summaryrefslogtreecommitdiff
path: root/oryxc/src/arena.rs
diff options
context:
space:
mode:
Diffstat (limited to 'oryxc/src/arena.rs')
-rw-r--r--oryxc/src/arena.rs265
1 files changed, 0 insertions, 265 deletions
diff --git a/oryxc/src/arena.rs b/oryxc/src/arena.rs
deleted file mode 100644
index cb05908..0000000
--- a/oryxc/src/arena.rs
+++ /dev/null
@@ -1,265 +0,0 @@
-use std::alloc::{
- self,
- Layout,
-};
-use std::cell::{
- Cell,
- RefCell,
-};
-use std::ptr::{
- self,
- NonNull,
-};
-use std::slice;
-use std::sync::Mutex;
-
-use crate::err;
-
-#[derive(Copy, Clone)]
-struct RawBlock {
- ptr: NonNull<u8>,
- layout: Layout,
-}
-
-unsafe impl Send for RawBlock {}
-unsafe impl Sync for RawBlock {}
-
-pub struct GlobalArena {
- blksz: usize,
- blocks: Mutex<Vec<RawBlock>>,
-}
-
-impl GlobalArena {
- pub fn new(blksz: usize) -> Self {
- return Self {
- blksz,
- blocks: Mutex::new(Vec::new()),
- };
- }
-
- fn allocate_block(&self, layout: Layout) -> RawBlock {
- let layout = Layout::from_size_align(
- layout.size().max(self.blksz),
- layout.align().max(16),
- )
- .unwrap_or_else(|e| err!(e, "allocation error"));
- let ptr = NonNull::new(unsafe { alloc::alloc(layout) })
- .unwrap_or_else(|| alloc::handle_alloc_error(layout));
-
- let block = RawBlock { ptr, layout };
- self.blocks.lock().unwrap().push(block.clone());
- return block;
- }
-}
-
-impl Drop for GlobalArena {
- fn drop(&mut self) {
- for block in self.blocks.lock().unwrap().iter() {
- unsafe {
- alloc::dealloc(block.ptr.as_ptr(), block.layout);
- }
- }
- }
-}
-
-#[derive(Clone, Copy)]
-pub struct Mark {
- blk: usize,
- beg: *mut u8,
- end: *mut u8,
-}
-
-pub struct LocalArena<'a> {
- parent: &'a GlobalArena,
- beg: Cell<*mut u8>,
- end: Cell<*mut u8>,
- curblk: Cell<usize>,
- blks: RefCell<Vec<RawBlock>>,
- #[cfg(debug_assertions)]
- pub waterline: Cell<usize>,
-}
-
-impl<'a> LocalArena<'a> {
- pub fn new(parent: &'a GlobalArena) -> Self {
- return Self {
- parent,
- beg: Cell::new(ptr::null_mut()),
- end: Cell::new(ptr::null_mut()),
- curblk: Cell::new(usize::MAX),
- blks: RefCell::new(Vec::new()),
- #[cfg(debug_assertions)]
- waterline: Cell::new(0),
- };
- }
-
- fn alloc_raw(&self, layout: Layout) -> NonNull<u8> {
- if cfg!(debug_assertions) {
- self.waterline.update(|x| x + layout.size());
- }
-
- let beg = self.beg.get() as usize;
-
- let align_offset =
- beg.wrapping_add(layout.align() - 1) & !(layout.align() - 1);
- let Some(next_beg) = align_offset.checked_add(layout.size()) else {
- err!("allocation overflow");
- };
-
- return if next_beg <= self.end.get() as usize {
- self.beg.set(next_beg as *mut u8);
- unsafe { NonNull::new_unchecked(align_offset as *mut u8) }
- } else {
- self.alloc_slow(layout)
- };
- }
-
- #[cold]
- fn alloc_slow(&self, layout: Layout) -> NonNull<u8> {
- let mut blks = self.blks.borrow_mut();
- let next_blk = self.curblk.get().wrapping_add(1);
-
- /* Find the next recycleable block that fits */
- let mut found_blk = None;
- let mut align_beg = 0;
- for i in next_blk..blks.len() {
- let blk = &blks[i];
- let beg = blk.ptr.as_ptr() as usize;
- let end = beg + blk.layout.size();
- let aligned =
- beg.wrapping_add(layout.align() - 1) & !(layout.align() - 1);
- if aligned.checked_add(layout.size()).unwrap_or(usize::MAX) <= end {
- found_blk = Some(i);
- align_beg = aligned;
- break;
- }
- }
-
- if let Some(i) = found_blk {
- blks.swap(next_blk, i);
-
- let blk = &blks[next_blk];
- let end = blk.ptr.as_ptr() as usize + blk.layout.size();
-
- self.curblk.set(next_blk);
- self.beg.set((align_beg + layout.size()) as *mut u8);
- self.end.set(end as *mut u8);
-
- return unsafe { NonNull::new_unchecked(align_beg as *mut u8) };
- }
-
- let blk = self.parent.allocate_block(layout);
- let beg = blk.ptr.as_ptr() as usize;
- let end = beg + blk.layout.size();
- let align_beg =
- beg.wrapping_add(layout.align() - 1) & !(layout.align() - 1);
-
- blks.push(blk);
- let last_blk = blks.len() - 1;
- blks.swap(next_blk, last_blk);
-
- self.curblk.set(next_blk);
- self.beg.set((align_beg + layout.size()) as *mut u8);
- self.end.set(end as *mut u8);
-
- unsafe { NonNull::new_unchecked(align_beg as *mut u8) }
- }
-
- pub fn alloc<T>(&self, value: T) -> &'a mut T {
- let ptr = self.alloc_raw(Layout::new::<T>()).cast::<T>().as_ptr();
- unsafe {
- ptr::write(ptr, value);
- return &mut *ptr;
- }
- }
-
- pub fn alloc_slice<T>(&self, len: usize) -> &'a mut [T] {
- let layout = Layout::array::<T>(len)
- .unwrap_or_else(|e| err!(e, "allocation error"));
- let ptr = self.alloc_raw(layout).cast::<T>().as_ptr();
- return unsafe { slice::from_raw_parts_mut(ptr, len) };
- }
-
- pub fn mark(&self) -> Mark {
- return Mark {
- blk: self.curblk.get(),
- beg: self.beg.get(),
- end: self.end.get(),
- };
- }
-
- pub fn restore(&self, mark: Mark) {
- self.curblk.set(mark.blk);
- self.beg.set(mark.beg);
- self.end.set(mark.end);
- }
-
- pub fn scope<'s, R, F>(&'s mut self, f: F) -> R
- where
- F: FnOnce(&ScopedArena<'s, 'a>) -> R,
- {
- let m = self.mark();
- let r = f(&ScopedArena { inner: self });
- self.restore(m);
- return r;
- }
-}
-
-/// A wrapper around LocalArena that bounds returned references to 's.
-pub struct ScopedArena<'s, 'a> {
- inner: &'s LocalArena<'a>,
-}
-
-impl<'s, 'a> ScopedArena<'s, 'a> {
- pub fn alloc<T>(&self, value: T) -> &'s mut T {
- return self.inner.alloc(value);
- }
-
- pub fn alloc_slice<T>(&self, len: usize) -> &'s mut [T] {
- return self.inner.alloc_slice(len);
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::{
- GlobalArena,
- LocalArena,
- };
-
- #[test]
- fn test_alloc_slice() {
- let arena_global = GlobalArena::new(8);
- let arena_local_1 = LocalArena::new(&arena_global);
- let arena_local_2 = LocalArena::new(&arena_global);
-
- let s1 = arena_local_1.alloc_slice(8);
- let s2 = arena_local_2.alloc_slice(4);
- assert_eq!(s1.len(), 8);
- assert_eq!(s2.len(), 4);
-
- for i in 0..s1.len() {
- s1[i] = i;
- }
- for i in 0..s2.len() {
- s2[i] = i;
- }
- }
-
- #[test]
- fn test_arena_grows() {
- let arena_global = GlobalArena::new(8);
- let arena_local = LocalArena::new(&arena_global);
-
- let s1 = arena_local.alloc_slice(8);
- let s2 = arena_local.alloc_slice(69);
- assert_eq!(s1.len(), 8);
- assert_eq!(s2.len(), 69);
-
- for i in 0..s1.len() {
- s1[i] = i;
- }
- for i in 0..s2.len() {
- s2[i] = i;
- }
- }
-}