rust/src/libstd/arena.rs
Niko Matsakis 34b42eeb65 change list so that it must be used in a purely boxed fashion
The old way was inconsistent---the head was unboxed but the
tail was boxed.  This resulted in numerous needless copies and
also made the borrow check unhappy, because the head tended to be
stored in mutable memory.
2012-05-21 09:37:34 -07:00

57 lines
1.4 KiB
Rust

// Dynamic arenas.
export arena, arena_with_size;
import list;
import list::{list, cons, nil};
type chunk = {data: [u8], mut fill: uint};
type arena = {mut chunks: @list<@chunk>};
fn chunk(size: uint) -> @chunk {
let mut v = [];
vec::reserve(v, size);
@{ data: v, mut fill: 0u }
}
fn arena_with_size(initial_size: uint) -> arena {
ret {mut chunks: @cons(chunk(initial_size), @nil)};
}
fn arena() -> arena {
arena_with_size(32u)
}
impl arena for arena {
fn alloc_grow(n_bytes: uint, align: uint) -> *() {
// Allocate a new chunk.
let mut head = list::head(self.chunks);
let chunk_size = vec::capacity(head.data);
let new_min_chunk_size = uint::max(n_bytes, chunk_size);
head = chunk(uint::next_power_of_two(new_min_chunk_size + 1u));
self.chunks = @cons(head, self.chunks);
ret self.alloc(n_bytes, align);
}
#[inline(always)]
fn alloc(n_bytes: uint, align: uint) -> *() {
let alignm1 = align - 1u;
let mut head = list::head(self.chunks);
let mut start = head.fill;
start = (start + alignm1) & !alignm1;
let end = start + n_bytes;
if end > vec::capacity(head.data) {
ret self.alloc_grow(n_bytes, align);
}
unsafe {
let p = ptr::offset(vec::unsafe::to_ptr(head.data), start);
head.fill = end;
ret unsafe::reinterpret_cast(p);
}
}
}