use super::block::Block;
use super::Region;
use std::alloc::Layout;
pub struct Chunks<H> {
min_chunk_size: usize,
chunks: Vec<Block<H>>,
}
impl<H> Chunks<H> {
pub fn new(min_chunk_size: usize) -> Self {
Self {
min_chunk_size,
chunks: Vec::new(),
}
}
pub fn with_chuncks(min_chunk_size: usize, chunk_count: usize) -> Self {
Self {
min_chunk_size,
chunks: (0..chunk_count)
.map(|_| Block::new(min_chunk_size))
.collect(),
}
}
}
impl<H> Region<H> for Chunks<H> {
type Pointers = std::iter::Flatten<std::vec::IntoIter<<Block<H> as Region<H>>::Pointers>>;
fn allocate(&mut self, layout: Layout, mut header: H) -> Result<*mut u8, H> {
for chunk in &mut self.chunks {
match chunk.allocate(layout, header) {
Ok(ptr) => return Ok(ptr),
Err(h) => header = h,
}
}
let size = self.min_chunk_size.max(layout.size() + layout.align() - 1);
self.chunks.push(Block::new(size));
self.chunks.last_mut().unwrap().allocate(layout, header)
}
fn deallocate(&mut self, ptr: *mut u8) -> Option<H> {
for chunk in &mut self.chunks {
if let Some(header) = chunk.deallocate(ptr) {
return Some(header);
}
}
None
}
fn has_allocated(&self, ptr: *mut u8) -> bool {
self.chunks.iter().any(|chunk| chunk.has_allocated(ptr))
}
fn count(&self) -> usize {
self.chunks.iter().map(|chunk| chunk.count()).sum()
}
fn allocations(&self) -> Self::Pointers {
self.chunks
.iter()
.map(|chunk| chunk.allocations())
.collect::<Vec<<Block<H> as Region<H>>::Pointers>>()
.into_iter()
.flatten()
}
}
#[cfg(test)]
#[test]
fn allocate_new_chunk() {
let mut chunks = Chunks::new(5);
assert_eq!(chunks.chunks.len(), 0);
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
assert_eq!(chunks.chunks.len(), 1);
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
assert_eq!(chunks.chunks.len(), 2);
}
#[cfg(test)]
#[test]
fn allocate_chunk_large_enough() {
let mut chunks = Chunks::new(2);
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u32>(), ()).unwrap();
}
#[cfg(test)]
#[test]
fn has_allocated() {
let mut chunks = Chunks::new(4);
let vec: Vec<*mut u8> = (0..100)
.map(|_| chunks.allocate(Layout::new::<u8>(), ()).unwrap())
.collect();
for ptr in vec {
assert!(chunks.has_allocated(ptr));
}
}
#[cfg(test)]
#[test]
fn allocations_count() {
let mut chunks = Chunks::new(4);
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u8>(), ()).unwrap();
chunks.allocate(Layout::new::<u32>(), ()).unwrap();
chunks.allocate(Layout::new::<u32>(), ()).unwrap();
chunks.allocate(Layout::new::<u32>(), ()).unwrap();
assert_eq!(chunks.count(), 11);
}