#![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))]
extern crate alloc;
extern crate object_alloc;
use SlabSystem;
use init::InitSystem;
use core::{mem, ptr};
use util::stack::Stack;
use util::color::{ColorSettings, Color};
use util::list::*;
use self::alloc::allocator;
use self::object_alloc::UntypedObjectAlloc;
pub trait ConfigData
where Self: Sized
{
#[allow(unused)]
fn post_alloc(&mut self, layout: &Layout, slab_size: usize, slab: *mut SlabHeader) {}
#[allow(unused)]
fn pre_dealloc(&mut self, layout: &Layout, slab_size: usize, slab: *mut SlabHeader) {}
fn ptr_to_slab(&self, slab_size: usize, ptr: *mut u8) -> *mut SlabHeader;
}
pub struct System<A: UntypedObjectAlloc, C: ConfigData> {
pub data: C,
layout: Layout,
alloc: A,
}
impl<A: UntypedObjectAlloc, C: ConfigData> System<A, C> {
pub fn from_config_data(data: C, layout: Layout, alloc: A) -> System<A, C> {
System {
data: data,
layout: layout,
alloc: alloc,
}
}
}
impl<I: InitSystem, A: UntypedObjectAlloc, C: ConfigData> SlabSystem<I> for System<A, C> {
type Slab = SlabHeader;
fn alloc_slab(&mut self) -> *mut SlabHeader {
unsafe {
let color = self.layout
.color_settings
.next_color(self.layout.layout.align());
let slab = match self.alloc.alloc() {
Ok(slab) => slab as *mut SlabHeader,
Err(..) => return ptr::null_mut(),
};
ptr::write(slab,
SlabHeader {
stack: Stack::new(),
color: color,
next: ptr::null_mut(),
prev: ptr::null_mut(),
});
let stack_data_ptr = self.layout.stack_begin(slab);
for i in 0..self.layout.num_obj {
let ptr = self.layout.nth_obj(slab, color, i);
(*slab)
.stack
.push(stack_data_ptr, I::pack(ptr, I::status_uninitialized()));
}
self.data
.post_alloc(&self.layout, self.alloc.layout().size(), slab);
slab
}
}
fn dealloc_slab(&mut self, slab: *mut SlabHeader) {
unsafe {
debug_assert_eq!((*slab).stack.size(), self.layout.num_obj);
self.data
.pre_dealloc(&self.layout, self.alloc.layout().size(), slab);
let stack_data_ptr = self.layout.stack_begin(slab);
for _ in 0..self.layout.num_obj {
let packed = (*slab).stack.pop(stack_data_ptr);
I::drop(I::unpack_ptr(packed), I::unpack_status(packed));
}
self.alloc.dealloc(slab as *mut u8);
}
}
fn is_full(&self, slab: *mut SlabHeader) -> bool {
unsafe { (*slab).stack.size() == self.layout.num_obj }
}
fn is_empty(&self, slab: *mut SlabHeader) -> bool {
unsafe { (*slab).stack.size() == 0 }
}
fn alloc(&self, slab: *mut SlabHeader) -> (*mut u8, I::Status) {
unsafe {
let stack_data_ptr = self.layout.stack_begin(slab);
let packed = (*slab).stack.pop(stack_data_ptr);
(I::unpack_ptr(packed), I::unpack_status(packed))
}
}
fn dealloc(&self, obj: *mut u8, init_status: I::Status) -> (*mut SlabHeader, bool) {
unsafe {
let slab = self.data.ptr_to_slab(self.alloc.layout().size(), obj);
let was_empty = (*slab).stack.size() == 0;
let stack_data_ptr = self.layout.stack_begin(slab);
(*slab)
.stack
.push(stack_data_ptr, I::pack(obj, init_status));
(slab, was_empty)
}
}
}
pub struct SlabHeader {
stack: Stack<usize>, color: Color, next: *mut SlabHeader,
prev: *mut SlabHeader,
}
impl Linkable for SlabHeader {
fn next(&self) -> *mut SlabHeader {
self.next
}
fn prev(&self) -> *mut SlabHeader {
self.prev
}
fn set_next(&mut self, next: *mut SlabHeader) {
self.next = next;
}
fn set_prev(&mut self, prev: *mut SlabHeader) {
self.prev = prev;
}
}
impl SlabHeader {
pub fn get_color(&self) -> Color {
self.color
}
}
#[derive(Clone)]
pub struct Layout {
pub num_obj: usize,
pub layout: allocator::Layout,
pub stack_begin_offset: usize,
pub array_begin_offset: usize,
pub color_settings: ColorSettings,
}
impl Layout {
pub fn for_slab_size(layout: allocator::Layout, slab_size: usize) -> Option<(Layout, usize)> {
let obj_size = layout.size();
let obj_align = layout.align();
let hdr_size = mem::size_of::<SlabHeader>();
let pre_stack_padding = Stack::<usize>::padding_after(hdr_size);
let stack_begin_offset = hdr_size + pre_stack_padding;
let (mut num_obj, mut array_begin_offset) = (0, 0);
loop {
let candidate = num_obj + 1;
let total_hdr_size = stack_begin_offset + Stack::<usize>::bytes_for(candidate);
use self::alloc::allocator::Layout;
let post_stack_padding = Layout::from_size_align(total_hdr_size, 1)
.unwrap()
.padding_needed_for(obj_align);
if total_hdr_size + post_stack_padding + (candidate * obj_size) <= slab_size {
num_obj = candidate;
array_begin_offset = total_hdr_size + post_stack_padding;
} else {
break;
}
}
if num_obj == 0 {
return None;
}
assert!(array_begin_offset > 0);
let unused_space = slab_size - array_begin_offset - (num_obj * obj_size);
let l = Layout {
num_obj: num_obj,
layout: layout,
stack_begin_offset: stack_begin_offset,
array_begin_offset: array_begin_offset,
color_settings: ColorSettings::new(obj_align, unused_space),
};
assert!(slab_size >=
l.array_begin_offset + l.color_settings.max_color().as_usize() +
(l.num_obj * obj_size));
Some((l, unused_space))
}
fn array_begin(&self, slab: *mut SlabHeader, color: Color) -> *mut u8 {
debug_assert!(color.as_usize() <= self.color_settings.max_color().as_usize());
((slab as usize) + self.array_begin_offset + color.as_usize()) as *mut u8
}
fn stack_begin(&self, slab: *mut SlabHeader) -> *mut usize {
((slab as usize) + self.stack_begin_offset) as *mut usize
}
pub fn nth_obj(&self, slab: *mut SlabHeader, color: Color, n: usize) -> *mut u8 {
debug_assert!((n as usize) < self.num_obj);
(self.array_begin(slab, color) as usize + n * self.layout.size()) as *mut u8
}
}