Rough initial design

This commit is contained in:
Stjepan Glavina 2016-10-23 01:35:26 +02:00
parent 7d5dddfb53
commit fe7eee7359
5 changed files with 360 additions and 6 deletions

5
.gitignore vendored
View File

@ -1,7 +1,2 @@
# Generated by Cargo
# will have compiled files and executables
/target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock

18
Cargo.toml Normal file
View File

@ -0,0 +1,18 @@
[package]
name = "vec-arena"
version = "0.0.1"
authors = ["Stjepan Glavina <stjepang@gmail.com>"]
repository = "https://github.com/stjepang/vec-arena.git"
homepage = "https://github.com/stjepang/vec-arena"
license = "MIT"
readme = "README.md"
# documentation = "TODO: url to docs on github"
description = "Fast general-purpose arena"
[lib]
name = "vec_arena"
path = "src/lib.rs"
[[bin]]
name = "bench_splay"
path = "benches/splay.rs"

View File

@ -1 +1,3 @@
# vec-arena
# VecArena
Work in progress

125
benches/splay.rs Normal file
View File

@ -0,0 +1,125 @@
extern crate vec_arena;
use vec_arena::VecArena;
struct Node<T> {
parent: usize,
children: [usize; 2],
value: T,
}
impl<T> Node<T> {
fn new(value: T) -> Node<T> {
Node {
parent: !0,
children: [!0, !0],
value: value,
}
}
}
struct Splay<T> {
arena: VecArena<Node<T>>,
root: usize,
}
impl<T> Splay<T> where T: Ord + Eq + Clone {
fn new() -> Splay<T> {
Splay {
arena: VecArena::new(),
root: !0,
}
}
fn rotate(&mut self, a: usize, b: usize) {
let x = &mut self.arena;
let p = x[a].parent;
let dir = if x[a].children[0] == b { 0 } else { 1 };
let t = x[b].children[dir ^ 1];
x[a].children[dir] = t;
if t != !0 {
x[t].parent = a;
}
x[b].children[dir ^ 1] = a;
x[a].parent = b;
if p == !0 {
self.root = b;
x[b].parent = !0;
} else {
let dir = if x[p].children[0] == a { 0 } else { 1 };
x[p].children[dir] = b;
x[b].parent = p;
}
}
fn splay(&mut self, a: usize) {
loop {
let b = self.arena[a].parent;
if b == !0 {
break;
}
let c = self.arena[b].parent;
if c == !0 {
self.rotate(b, a);
break;
}
let is_l = self.arena[c].children[0] == b && self.arena[b].children[0] == a;
let is_r = self.arena[c].children[1] == b && self.arena[b].children[1] == a;
if is_l || is_r {
self.rotate(c, b);
self.rotate(b, a);
} else {
self.rotate(b, a);
self.rotate(c, a);
}
}
}
fn insert(&mut self, value: T) {
let node = self.arena.push(Node::new(value));
if self.root == !0 {
self.root = node;
} else {
let mut curr = self.root;
loop {
let dir = if self.arena[node].value < self.arena[curr].value { 0 } else { 1 };
let next = self.arena[curr].children[dir];
if next == !0 {
self.arena[curr].children[dir] = node;
self.arena[node].parent = curr;
self.splay(node);
break;
} else {
curr = next;
}
}
}
}
fn print(&self, node: usize, depth: usize) where T: std::fmt::Display {
if node != !0 {
self.print(self.arena[node].children[0], depth + 1);
println!("{:width$}{}", "", self.arena[node].value, width = depth * 3);
self.print(self.arena[node].children[1], depth + 1);
}
}
}
fn main() {
let mut splay = Splay::new();
let mut num = 1u32;
for _ in 0..1000000 {
num = num.wrapping_mul(17).wrapping_add(255);
splay.insert(num);
}
// splay.print(splay.root, 0);
}

214
src/lib.rs Normal file
View File

@ -0,0 +1,214 @@
use std::marker::PhantomData;
use std::mem;
use std::ops::{Index, IndexMut};
use std::ptr;
// TODO: Handle ZST differently
// TODO: Test ZST, make a ZST implementing Drop
#[inline(always)]
fn bits() -> usize {
std::mem::size_of::<usize>() * 8
}
// TODO: Move into VecArena?
#[inline(always)]
fn num_blocks(cap: usize) -> usize {
(cap + bits() - 1) / bits()
}
pub struct VecArena<T> {
elems: *const T,
meta: *mut usize,
cap: usize,
head: usize,
count: usize,
marker: PhantomData<T>,
}
impl<T> VecArena<T> {
#[inline(always)]
unsafe fn get_alive(&self, block: usize) -> *mut usize {
self.meta.offset(block as isize)
}
#[inline(always)]
unsafe fn get_next(&self, block: usize) -> *mut usize {
self.meta.offset((num_blocks(self.cap) + block) as isize)
}
pub fn new() -> Self {
let elems = {
let mut v = Vec::with_capacity(0);
let ptr = v.as_mut_ptr();
mem::forget(v);
ptr
};
let meta = {
let mut v = Vec::with_capacity(0);
let ptr = v.as_mut_ptr();
mem::forget(v);
ptr
};
VecArena {
elems: elems,
meta: meta,
cap: 0,
head: !0,
count: 0,
marker: PhantomData,
}
}
pub fn push(&mut self, value: T) -> usize {
unsafe {
if self.count == self.cap {
self.grow();
}
while self.head != !0 && *self.get_alive(self.head) == !0 {
self.head = *self.get_next(self.head);
}
if self.head == !0 {
self.grow();
}
let i = (!*self.get_alive(self.head)).trailing_zeros() as usize;
let index = self.head * bits() + i;
unsafe {
ptr::write(self.elems.offset(index as isize) as *mut T, value);
}
let block = self.head;
*self.get_alive(block) |= 1 << i;
self.count += 1;
index
}
}
pub fn take(&mut self, index: usize) -> T {
self.validate_index(index);
let b = index / bits();
let i = index % bits();
unsafe {
self.count -= 1;
*self.get_alive(b) ^= 1 << i;
if *self.get_alive(b) == 0 {
*self.get_next(b) = self.head;
self.head = b;
}
ptr::read(self.elems.offset(index as isize) as *mut T)
}
}
unsafe fn grow(&mut self) {
let new_cap = if self.cap == 0 { 4 } else { self.cap * 2 };
let blocks = num_blocks(self.cap);
let new_blocks = num_blocks(new_cap);
let new_elems = {
let mut v = Vec::with_capacity(new_cap);
let ptr = v.as_mut_ptr();
mem::forget(v);
ptr
};
ptr::copy_nonoverlapping(self.elems, new_elems, self.cap);
Vec::from_raw_parts(self.elems as *mut T, 0, self.cap);
self.elems = new_elems;
let new_meta = {
let mut v = Vec::from_raw_parts(self.meta, 2 * blocks, 2 * blocks);
v.reserve_exact(new_blocks * 2 - blocks * 2);
let ptr = v.as_mut_ptr();
mem::forget(v);
ptr
};
ptr::write_bytes(new_meta.offset(blocks as isize), 0, new_blocks - blocks);
for i in blocks .. new_blocks {
ptr::write(new_meta.offset((new_blocks + i) as isize), i.wrapping_sub(1));
}
self.meta = new_meta;
self.cap = new_cap;
self.head = new_blocks - 1;
}
#[inline]
fn validate_index(&self, index: usize) {
let b = index / bits();
let i = index % bits();
unsafe {
if index >= self.cap || *self.get_alive(b) >> i & 1 == 0 {
self.panic_invalid_index(index);
}
}
}
#[inline(never)]
fn panic_invalid_index(&self, index: usize) {
if index >= self.cap {
panic!("index out of bounds: the cap is {} but the index is {}", self.cap, index);
}
panic!("uninitialized memory: the index is {} but it's not allocated", index);
}
}
impl<T> Drop for VecArena<T> {
fn drop(&mut self) {
unsafe {
for b in 0 .. num_blocks(self.cap) {
let alive = *self.get_alive(b);
if alive != 0 {
for i in 0 .. bits() {
if alive & (1 << i) != 0 {
let index = b * bits() + i;
ptr::drop_in_place(self.elems.offset(index as isize) as *mut T);
}
}
}
}
let blocks = num_blocks(self.cap);
Vec::from_raw_parts(self.elems as *mut T, 0, self.cap);
Vec::from_raw_parts(self.meta, 0, 2 * blocks);
}
}
}
impl<T> Index<usize> for VecArena<T> {
type Output = T;
fn index(&self, index: usize) -> &T {
self.validate_index(index);
unsafe {
&*self.elems.offset(index as isize)
}
}
}
impl<T> IndexMut<usize> for VecArena<T> {
fn index_mut(&mut self, index: usize) -> &mut T {
self.validate_index(index);
unsafe {
&mut *(self.elems.offset(index as isize) as *mut T)
}
}
}
// TODO: impl Default
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let mut arena = VecArena::new();
arena.alloc(1);
}
}