use std::collections::VecDeque;
struct ArenaMemoryInstance {
free_blocks: VecDeque<Box<[u8]>>,
max_free_blocks_to_initialize_or_cleanup_to: i32,
min_free_blocks_before_allocating_new: i32,
new_block_size: usize,
}
impl ArenaMemoryInstance {
pub fn new(options: &MemoryBuilder) -> ArenaMemoryInstance {
let mut i = ArenaMemoryInstance {
free_blocks: VecDeque::with_capacity(1024),
max_free_blocks_to_initialize_or_cleanup_to: options.max_free_blocks_to_initialize_or_cleanup_to,
min_free_blocks_before_allocating_new: options.min_free_blocks_before_allocating_new,
new_block_size: options.new_block_size,
};
i.check_if_not_enough_blocks_and_initialize();
i
}
fn check_if_not_enough_blocks_and_initialize(&mut self) {
if self.free_blocks.len() < self.min_free_blocks_before_allocating_new as usize {
while self.free_blocks.len() < self.max_free_blocks_to_initialize_or_cleanup_to as usize {
debug!("-- init block of size {}", self.new_block_size);
self.free_blocks.push_front(vec![0u8; self.new_block_size as usize].into_boxed_slice());
}
}
}
pub fn cleanup(&mut self) -> usize {
let mut cleaned_up_size = 0;
while self.free_blocks.len() > self.max_free_blocks_to_initialize_or_cleanup_to as usize {
if let Some(block) = self.free_blocks.pop_front() {
cleaned_up_size += block.len();
debug!("-- clean block of size {}", block.len());
}
}
cleaned_up_size
}
pub fn take_block(&mut self) -> Box<[u8]> {
self.check_if_not_enough_blocks_and_initialize();
let block = self.free_blocks.pop_back().expect("no allocated memory");
debug!("-- take block of size {}", block.len());
block
}
pub fn return_block(&mut self, block: Box<[u8]>) {
debug!("-- return block of size {}", block.len());
self.free_blocks.push_back(block);
}
}
pub struct MemoryBuilder {
max_free_blocks_to_initialize_or_cleanup_to: i32,
min_free_blocks_before_allocating_new: i32,
new_block_size: usize,
}
impl MemoryBuilder {
pub fn with_min_max_blocks(mut self, min: i32, max: i32) -> MemoryBuilder {
self.min_free_blocks_before_allocating_new = min;
self.max_free_blocks_to_initialize_or_cleanup_to = max;
self
}
pub fn with_block_size(mut self, size: usize) -> MemoryBuilder {
self.new_block_size = size;
self
}
pub fn build(self) -> Memory {
Memory {
shared: std::sync::Arc::new(std::sync::Mutex::new(ArenaMemoryInstance::new(&self)))
}
}
}
#[derive(Clone)]
pub struct Memory {
shared: std::sync::Arc<std::sync::Mutex<ArenaMemoryInstance>>,
}
impl Memory {
pub fn builder() -> MemoryBuilder {
MemoryBuilder {
max_free_blocks_to_initialize_or_cleanup_to: 4,
min_free_blocks_before_allocating_new: 2,
new_block_size: 1024*64,
}
}
pub fn new() -> Memory {
let builder = MemoryBuilder {
max_free_blocks_to_initialize_or_cleanup_to: 4,
min_free_blocks_before_allocating_new: 2,
new_block_size: 1024*64,
};
Memory {
shared: std::sync::Arc::new(std::sync::Mutex::new(ArenaMemoryInstance::new(&builder)))
}
}
#[inline(always)]
pub fn cleanup(&self) -> usize {
self.shared.lock().expect("lock").cleanup()
}
#[inline(always)]
pub fn take_block(&mut self) -> Box<[u8]> {
self.shared.lock().expect("lock").take_block()
}
#[inline(always)]
pub fn return_block(&mut self, block: Box<[u8]>) {
self.shared.lock().expect("lock").return_block(block)
}
}