#[cfg(test)]
use std::vec::Vec;
#[cfg(test)]
use std::iter::FromIterator;
#[cfg(test)]
use core::mem;
use core::default::Default;
use core::fmt;
use super::types::*;
use super::raw_pool::*;
#[repr(C, packed)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Free {
pub _blocks: BlockLoc, pub _block: BlockLoc, pub _prev: BlockLoc, pub _next: BlockLoc, }
impl fmt::Debug for Free {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let prev: isize = if self._prev == BLOCK_NULL {
-1
} else {
self._prev as isize
};
let next = if self._next == BLOCK_NULL {
-1
} else {
self._next as isize
};
let isvalid = if self.is_valid() { " " } else { "!" };
write!(f,
"Free{}{{blocks: {}, block: {}, prev: {}, next: {}}}{}",
isvalid,
self._blocks & BLOCK_BITMAP,
self._block & BLOCK_BITMAP,
prev,
next,
isvalid)
}
}
impl Default for Free {
fn default() -> Free {
Free {
_blocks: 0,
_block: BLOCK_NULL,
_prev: BLOCK_NULL,
_next: BLOCK_NULL,
}
}
}
impl Free {
pub fn block(&self) -> BlockLoc {
self.assert_valid();
self._block
}
pub fn blocks(&self) -> BlockLoc {
self.assert_valid();
self._blocks
}
pub fn prev(&self) -> Option<BlockLoc> {
self.assert_valid();
if self._prev == BLOCK_NULL {
None
} else {
Some(self._prev)
}
}
pub fn next(&self) -> Option<BlockLoc> {
self.assert_valid();
if self._next == BLOCK_NULL {
None
} else {
Some(self._next)
}
}
pub unsafe fn set_prev(&mut self, pool: &mut RawPool, prev: Option<&mut Free>) {
self.assert_valid();
match prev {
Some(p) => {
self._prev = p.block();
p._next = self.block();
}
None => {
self._prev = BLOCK_NULL;
let pool = pool as *mut RawPool;
let bin = (*pool).freed_bins.get_insert_bin(self.blocks());
(*pool).freed_bins.bins[bin as usize]._root = self.block();
}
}
}
pub unsafe fn set_next(&mut self, next: Option<&mut Free>) {
self.assert_valid();
match next {
Some(n) => {
self._next = n.block();
n._prev = self.block();
}
None => self._next = BLOCK_NULL,
}
}
pub unsafe fn remove(&mut self, pool: &mut RawPool) {
self.assert_valid();
unsafe fn get_freed(pool: &mut RawPool, block: Option<BlockLoc>) -> Option<&mut Free> {
match block {
Some(b) => {
assert!(b < pool.len_blocks() - 1);
Some(pool.freed_mut(b))
}
None => None,
}
}
pool.freed_bins.len -= 1;
let poolp = pool as *mut RawPool;
match get_freed(&mut *poolp, self.prev()) {
Some(p) => p.set_next(get_freed(&mut *poolp, self.next())),
None => {
let bin = pool.freed_bins.get_insert_bin(self.blocks());
match get_freed(&mut *poolp, self.next()) {
Some(next) => {
next.set_prev(&mut *poolp, None);
assert_eq!(pool.freed_bins.bins[bin as usize]._root, next.block());
}
None => {
pool.freed_bins.bins[bin as usize]._root = BLOCK_NULL;
}
}
}
}
}
pub unsafe fn join(&mut self, pool: &mut RawPool, right: &mut Free) -> &mut Free {
self.assert_valid();
right.assert_valid();
self.remove(pool);
right.remove(pool);
self._blocks += right.blocks();
self.assert_valid();
(*(pool as *mut RawPool)).freed_bins.insert(pool, self);
self
}
fn assert_valid(&self) {
assert!(self.is_valid(), "{:?}", self);
}
fn is_valid(&self) -> bool {
self._blocks & BLOCK_HIGH_BIT == 0 && self._blocks != 0
}
}
#[repr(C, packed)]
pub struct FreedRoot {
pub _root: BlockLoc,
}
impl Default for FreedRoot {
fn default() -> FreedRoot {
FreedRoot { _root: BLOCK_NULL }
}
}
impl FreedRoot {
pub unsafe fn root<'a>(&self, pool: &'a RawPool) -> Option<&'a Free> {
if self._root == BLOCK_NULL {
None
} else {
Some(pool.freed(self._root))
}
}
unsafe fn root_mut<'a>(&mut self, pool: &'a mut RawPool) -> Option<&'a mut Free> {
if self._root == BLOCK_NULL {
None
} else {
Some(pool.freed_mut(self._root))
}
}
unsafe fn insert_root(&mut self, pool: &mut RawPool, freed: &mut Free) {
freed._prev = BLOCK_NULL;
if let Some(cur_root) = self.root_mut(&mut *(pool as *mut RawPool)) {
cur_root.set_prev(pool, Some(freed));
} else {
freed._next = BLOCK_NULL;
}
self._root = freed.block();
}
}
pub const NUM_BINS: u8 = 7;
#[derive(Default)]
pub struct FreedBins {
pub len: BlockLoc,
pub bins: [FreedRoot; NUM_BINS as usize],
}
impl FreedBins {
pub fn get_insert_bin(&self, blocks: BlockLoc) -> u8 {
match blocks {
1...3 => 0,
4...15 => 1,
16...63 => 2,
64...255 => 3,
256...1023 => 4,
1024...4095 => 5,
_ => 6,
}
}
pub fn bin_repr(bin: u8) -> &'static str {
match bin {
0 => "1 ...3 ",
1 => "4 ...15 ",
2 => "16 ...63 ",
3 => "64 ...255 ",
4 => "256 ...1023",
5 => "1024...4095",
6 => "4096... ",
_ => "INVALID",
}
}
pub unsafe fn insert(&mut self, pool: &mut RawPool, freed: &mut Free) {
assert!(freed.block() + freed.blocks() <= pool.heap_block,
"{:?}",
freed);
self.len += 1;
let bin = self.get_insert_bin(freed.blocks());
self.bins[bin as usize].insert_root(pool, freed);
}
pub unsafe fn pop_slow(&mut self, pool: &mut RawPool, blocks: BlockLoc) -> Option<BlockLoc> {
assert_ne!(blocks, 0);
if self.len == 0 {
return None;
}
let bin = self.get_insert_bin(blocks);
let poolptr = pool as *mut RawPool;
for b in bin..(NUM_BINS - 1) {
if let Some(mut current_free) = self.bins[b as usize].root(&*poolptr) {
let mut best = current_free;
loop {
if best.blocks() == blocks {
break;
}
let next = match current_free.next() {
Some(ref f) => (*poolptr).freed_mut(*f),
None => break,
};
if next.blocks() >= blocks && next.blocks() < best.blocks() {
best = next;
}
current_free = next;
}
if best.blocks() >= blocks {
let out = (*poolptr).freed_mut(best.block());
self.consume_partof(pool, out, blocks);
return Some(out.block());
}
}
}
None
}
pub unsafe fn pop_fast(&mut self, pool: &mut RawPool, blocks: BlockLoc) -> Option<BlockLoc> {
assert_ne!(blocks, 0);
if self.len == 0 {
return None;
}
let bin: u8 = match blocks {
1 => 0,
2...4 => 1,
5...16 => 2,
17...64 => 3,
65...256 => 4,
257...1024 => 5,
_ => 6,
};
let poolptr = pool as *mut RawPool;
for b in bin..(NUM_BINS - 1) {
if let Some(out) = self.bins[b as usize].root_mut(&mut *poolptr) {
self.consume_partof(pool, out, blocks);
return Some(out.block());
}
}
if let Some(mut out) = self.bins[(NUM_BINS - 1) as usize].root_mut(&mut *poolptr) {
loop {
if out.blocks() >= blocks {
self.consume_partof(pool, out, blocks);
return Some(out.block());
}
out = match out.next() {
Some(o) => (*poolptr).freed_mut(o),
None => return None,
};
}
}
None
}
unsafe fn consume_partof(&mut self, pool: &mut RawPool, freed: &mut Free, blocks: BlockLoc) {
let old_blocks = freed.blocks();
if old_blocks == blocks {
freed.remove(pool);
} else {
assert!(old_blocks > blocks);
let old_block = freed.block();
let new_block = old_block + blocks;
let new_freed = pool.freed_mut(new_block) as *mut Free;
(*new_freed) = Free {
_blocks: old_blocks - blocks,
_block: new_block,
_prev: BLOCK_NULL,
_next: BLOCK_NULL,
};
freed.remove(pool); self.insert(pool, &mut *new_freed);
}
}
}
#[test]
fn test_bins() {
use core::slice;
use cbuf::CBuf;
unsafe {
let (mut indexes, mut blocks): ([Index; 256], [Block; 4096]) = ([Index::default(); 256],
mem::zeroed());
let iptr: *mut Index = mem::transmute(&mut indexes[..][0]);
let bptr: *mut Block = mem::transmute(&mut blocks[..][0]);
let mut cptr = [IndexLoc::default(); 16];
let cache_buf: &'static mut [IndexLoc] =
slice::from_raw_parts_mut(&mut cptr[0] as *mut IndexLoc, 16);
let cache = CBuf::new(cache_buf);
let mut pool = RawPool::new(iptr,
indexes.len() as IndexLoc,
bptr,
blocks.len() as BlockLoc,
cache);
let p = &mut pool as *mut RawPool;
let bin1 = Vec::from_iter((0..5).map(|_| pool.alloc_index(10, true).unwrap()));
let bin2 = Vec::from_iter((0..5).map(|_| pool.alloc_index(20, true).unwrap()));
let f1_i = pool.alloc_index(1, true).unwrap();
let f1_index = (*p).index(f1_i);
assert_eq!(f1_index.block(), 150);
assert_eq!(f1_i, 10);
for (i1, i2) in bin1.iter().zip(bin2.iter()) {
pool.dealloc_index(*i2);
pool.dealloc_index(*i1);
}
assert_eq!(pool.freed_bins.len, 10);
let b1_0 = pool.freed_mut(0);
let b1_1 = pool.freed_mut(10);
let b1_2 = pool.freed_mut(20);
let b1_3 = pool.freed_mut(30);
let b1_4 = pool.freed_mut(40);
let b2_0 = pool.freed_mut(50);
let b2_3 = pool.freed_mut(110);
let b2_4 = pool.freed_mut(130);
assert_eq!(pool.freed_bins.bins[1]._root, b1_4.block());
assert_eq!(b1_4.prev(), None);
assert_eq!(b1_4.next(), Some(b1_3.block()));
assert_eq!(b1_3.prev(), Some(b1_4.block()));
assert_eq!(b1_3.next(), Some(b1_2.block()));
assert_eq!(b1_2.prev(), Some(b1_3.block()));
assert_eq!(b1_2.next(), Some(b1_1.block()));
assert_eq!(b1_1.prev(), Some(b1_2.block()));
assert_eq!(b1_1.next(), Some(b1_0.block()));
assert_eq!(b1_0.prev(), Some(b1_1.block()));
assert_eq!(b1_0.next(), None);
b1_4.remove(&mut *p);
assert_eq!(pool.freed_bins.len, 9);
assert_eq!(pool.freed_bins.bins[1]._root, b1_3.block());
assert_eq!(b1_3.prev(), None);
assert_eq!(b1_3.next(), Some(b1_2.block()));
(*p).freed_bins.insert(&mut *p, b1_4);
assert_eq!(pool.freed_bins.len, 10);
assert_eq!(pool.freed_bins.bins[1]._root, b1_4.block());
assert_eq!(b1_4.prev(), None);
assert_eq!(b1_4.next(), Some(b1_3.block()));
assert_eq!(b1_3.prev(), Some(b1_4.block()));
assert_eq!(b1_3.next(), Some(b1_2.block()));
b1_0.join(&mut *p, b1_1);
let b2_5 = pool.freed_mut(b1_0.block());
assert_eq!(pool.freed_bins.len, 9);
assert_eq!(b2_5.blocks(), 20);
assert_eq!(pool.freed_bins.bins[2]._root, b2_5.block());
assert_eq!(b2_5.prev(), None);
assert_eq!(b2_5.next(), Some(b2_4.block()));
b2_5.join(&mut *p, b1_2);
assert_eq!(pool.freed_bins.len, 8);
assert_eq!(b2_5.blocks(), 30);
assert_eq!(pool.freed_bins.bins[2]._root, b2_5.block());
assert_eq!(b2_5.prev(), None);
assert_eq!(b2_5.next(), Some(b2_4.block()));
b2_5.join(&mut *p, b1_3);
b2_5.join(&mut *p, b1_4);
assert_eq!(pool.freed_bins.len, 6);
assert_eq!(b2_5.blocks(), 50);
assert_eq!(pool.freed_bins.bins[2]._root, b2_5.block());
assert_eq!(b2_5.prev(), None);
assert_eq!(b2_5.next(), Some(b2_4.block()));
b2_5.join(&mut *p, b2_0);
let b3_0 = pool.freed_mut(b2_5.block());
assert_eq!(pool.freed_bins.len, 5);
assert_eq!(b2_5.blocks(), 70);
assert_eq!(pool.freed_bins.bins[2]._root, b2_4.block());
assert_eq!(pool.freed_bins.bins[3]._root, b3_0.block());
assert_eq!(b3_0.prev(), None);
assert_eq!(b3_0.next(), None);
assert_eq!(b2_4.prev(), None);
assert_eq!(b2_4.next(), Some(b2_3.block()));
(*p).clean();
assert_eq!(pool.freed_bins.len, 1);
assert_eq!(b1_0.blocks(), 150);
(*p).defrag();
assert_eq!(pool.freed_bins.len, 0);
assert_eq!(pool.heap_block, 1);
let f1_0 = pool.full(0);
f1_0.assert_valid();
assert_eq!(f1_0.blocks(), 1);
assert_eq!(f1_0.index(), f1_i);
assert_eq!(f1_index.block(), 0);
}
}