use super::plane::Cell;
const MAX_CELL_POOL_SIZE: usize = 100_000;
#[derive(Debug, Clone, Copy)]
pub struct PoolConfig {
pub max_cells: usize,
pub initial_capacity: usize,
}
impl Default for PoolConfig {
fn default() -> Self {
Self {
max_cells: MAX_CELL_POOL_SIZE,
initial_capacity: 64,
}
}
}
#[derive(Debug)]
pub struct CellPool {
config: PoolConfig,
free: Vec<CellBlock>,
}
#[derive(Debug)]
#[allow(dead_code)]
struct CellBlock {
width: u16,
height: u16,
cells: Vec<Cell>,
}
impl CellPool {
pub fn new() -> Self {
Self::with_config(PoolConfig::default())
}
pub fn with_config(config: PoolConfig) -> Self {
Self {
config,
free: Vec::with_capacity(config.initial_capacity),
}
}
#[inline]
pub fn total_cells(&self) -> usize {
self.free.iter().map(|b| b.cells.len()).sum()
}
pub fn acquire_cells(&mut self, count: usize) -> Vec<Cell> {
let mut acquired = Vec::with_capacity(count);
let mut remaining = count;
while remaining > 0 {
let best_idx = self
.free
.iter()
.enumerate()
.filter(|(_, b)| b.cells.len() >= remaining)
.min_by_key(|(_, b)| b.cells.len())
.map(|(idx, _)| idx)
.or_else(|| {
self.free
.iter()
.enumerate()
.max_by_key(|(_, b)| b.cells.len())
.map(|(idx, _)| idx)
});
match best_idx {
Some(idx) => {
let block_len = self.free[idx].cells.len();
if block_len >= remaining {
let split = self.free[idx].cells.split_off(block_len - remaining);
acquired.extend(split);
if self.free[idx].cells.is_empty() {
self.free.swap_remove(idx);
}
remaining = 0;
} else {
let mut cells = std::mem::take(&mut self.free[idx].cells);
acquired.append(&mut cells);
self.free.swap_remove(idx);
remaining -= block_len;
}
}
None => {
for _ in 0..remaining {
acquired.push(Cell::default());
}
break;
}
}
}
acquired
}
pub fn release_cells(&mut self, _width: u16, _height: u16, cells: Vec<Cell>) {
if cells.is_empty() {
return;
}
let total = self.total_cells();
if total + cells.len() > self.config.max_cells {
return;
}
self.free.push(CellBlock {
width: _width,
height: _height,
cells,
});
}
pub fn shrink_to_fit(&mut self) {
for block in &mut self.free {
block.cells.shrink_to_fit();
}
self.free.shrink_to_fit();
}
}
impl Default for CellPool {
fn default() -> Self {
Self::new()
}
}
#[inline]
pub fn acquire_plane_cells(pool: &mut CellPool, width: u16, height: u16) -> Vec<Cell> {
let count = (width.max(1) as usize) * (height.max(1) as usize);
pool.acquire_cells(count)
}
#[inline]
pub fn release_plane_cells(pool: &mut CellPool, width: u16, height: u16, cells: Vec<Cell>) {
pool.release_cells(width, height, cells)
}