use std::cell::UnsafeCell;
use std::mem;
use super::INITIAL_CAPACITY;
use super::job::Job;
struct BufChain {
buf: Vec<Job>,
_prev: Option<Box<BufChain>>,
}
impl BufChain {
fn new(size: usize) -> Self {
BufChain {
buf: Vec::with_capacity(size),
_prev: None,
}
}
fn alloc(&mut self, job: Job) -> Result<*mut Job, Job> {
let len = self.buf.len();
if len == self.buf.capacity() {
Err(job)
} else {
self.buf.push(job);
unsafe { Ok(self.buf.get_unchecked_mut(len) as *mut Job) }
}
}
fn grow(self) -> Self {
use std::cmp::max;
let new_size = max(self.buf.len() * 2, 4);
BufChain {
buf: Vec::with_capacity(new_size),
_prev: Some(Box::new(self)),
}
}
}
pub struct Arena {
buf: UnsafeCell<BufChain>,
}
impl Arena {
pub fn new() -> Self {
Arena {
buf: UnsafeCell::new(BufChain::new(INITIAL_CAPACITY)),
}
}
pub unsafe fn alloc(&self, job: Job) -> *mut Job {
let mut buf = self.buf.get();
match (*buf).alloc(job) {
Ok(job_ptr) => job_ptr,
Err(job) => {
let new_link = mem::replace(&mut *buf, BufChain::new(0)).grow();
*buf = new_link;
(*buf).alloc(job).ok().unwrap()
}
}
}
pub unsafe fn top(&self) -> usize {
(*self.buf.get()).buf.len()
}
pub unsafe fn set_top(&self, top: usize) {
(*self.buf.get()).buf.set_len(top);
}
}
unsafe impl Send for Arena {}
unsafe impl Sync for Arena {}