pub use allocator::{Allocator};
use malloc;
use core::prelude::*;
use core::ptr;
use core::mem;
use core::kinds::marker;
use core::num::Int;
use core::cmp;
use core::intrinsics;
static mut a: malloc::Malloc = malloc::Malloc;
pub struct Arena {
chunk_size: uint,
chunks: uint,
first_free: uint,
ptr: *mut Chunk,
_nosend: marker::NoSend,
_nosync: marker::NoSync,
}
impl Arena {
pub fn new(chunk_size: uint) -> Arena { Arena {
chunks: 0,
chunk_size: chunk_size,
first_free: 0,
ptr: ptr::null_mut(),
_nosend: marker::NoSend,
_nosync: marker::NoSync
}}
fn add_chunk(&mut self) -> Option<&mut Chunk> { unsafe {
let size = self.chunk_size;
self.add_custom_chunk(size, 1)
}}
fn add_custom_chunk(&mut self, size: uint, align: uint) -> Option<&mut Chunk> { unsafe {
let c = self.chunks;
try!(a.ensure::<Chunk>(&mut self.ptr, c, c+1));
let cp = self.ptr.offset(c as int);
try!(Chunk::fill(cp, self.chunk_size + align - 1));
self.chunks += 1;
Some(&mut *cp)
}}
}
#[unsafe_destructor]
impl Drop for Arena {
fn drop(&mut self) { unsafe {
for i in range(0, self.chunks as int) {
ptr::read(self.ptr.offset(i));
}
a.free::<Chunk>(self.ptr, self.chunks);
}}
}
impl Allocator for Arena {
unsafe fn alloc<T>(&mut self, count: uint) -> Option<*mut T> {
let bytes = as_bytes!(count);
let align = mem::min_align_of::<T>();
if bytes > self.chunk_size {
let chunk = try!(self.add_custom_chunk(bytes, align));
return Some(try!(chunk.alloc(bytes, align)) as *mut T);
}
if self.first_free >= self.chunks {
try!(self.add_chunk());
}
for i in range(self.first_free, self.chunks) {
let chunk: &mut Chunk = &mut *self.ptr.offset(i as int);
match chunk.alloc(bytes, align) {
None => continue,
Some(p) => {
if chunk.is_full() && i == self.first_free {
self.first_free += 1;
}
return Some(p as *mut T);
}
}
}
let chunk: &mut Chunk = try!(self.add_chunk());
let p: *mut u8 = try!(chunk.alloc(bytes, align));
Some(p as *mut T)
}
unsafe fn realloc<T>(&mut self, _buf: &mut *mut T, current: uint, items: uint) -> Option<uint> {
if current >= items {
Some(current)
} else {
None
}
}
unsafe fn ensure<T>(&mut self, _buf: &mut *mut T, current: uint, min: uint) -> Option<uint> {
if current >= min {
Some(current)
} else {
None
}
}
unsafe fn free<T>(&mut self, _buf: *mut T, _count: uint) {
}
}
struct Chunk {
ptr: *mut u8,
cap: uint,
end: uint,
_nosend: marker::NoSend,
_nosync: marker::NoSync,
}
impl Copy for Chunk {}
impl Chunk {
fn fill(c: *mut Chunk, size: uint) -> Option<()> { #![inline] unsafe {
let area = try!(a.alloc(size));
*c = Chunk { ptr: area, cap: size, end: 0,
_nosend: marker::NoSend, _nosync: marker::NoSync};
Some(())
}}
fn alloc(&mut self, size: uint, align: uint) -> Option<*mut u8> { #![inline] unsafe {
let off = (self.end + (align - 1)) & !(align - 1);
let newend = off + size;
if newend > self.cap { return None; }
self.end = newend;
Some(self.ptr.offset(off as int))
}}
fn is_full(&self) -> bool {
self.cap == self.end
}
}
#[unsafe_destructor]
impl Drop for Chunk {
fn drop(&mut self) { unsafe {
a.free(self.ptr, self.cap);
}}
}