use super::state::State;
#[derive(Debug)]
pub struct StatePool {
pool: Vec<State>,
allocations: usize,
reuses: usize,
}
impl StatePool {
const MAX_POOL_SIZE: usize = 32;
const INITIAL_CAPACITY: usize = 16;
pub fn new() -> Self {
const PREWARM_SIZE: usize = 4;
let mut pool = Vec::with_capacity(Self::INITIAL_CAPACITY);
for _ in 0..PREWARM_SIZE {
pool.push(State::new());
}
Self {
pool,
allocations: PREWARM_SIZE, reuses: 0,
}
}
#[inline]
pub fn acquire(&mut self) -> State {
if let Some(mut state) = self.pool.pop() {
state.clear(); self.reuses += 1;
state
} else {
self.allocations += 1;
State::new()
}
}
#[inline]
pub fn release(&mut self, state: State) {
if self.pool.len() < Self::MAX_POOL_SIZE {
self.pool.push(state);
}
}
pub fn pool_size(&self) -> usize {
self.pool.len()
}
pub fn total_allocations(&self) -> usize {
self.allocations
}
pub fn total_reuses(&self) -> usize {
self.reuses
}
pub fn reuse_rate(&self) -> f64 {
let total_acquires = self.allocations + self.reuses;
if total_acquires == 0 {
0.0
} else {
self.reuses as f64 / total_acquires as f64
}
}
}
impl Default for StatePool {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::transducer::position::Position;
#[test]
fn test_pool_new() {
let pool = StatePool::new();
assert_eq!(pool.pool_size(), 4);
assert_eq!(pool.total_allocations(), 4);
assert_eq!(pool.total_reuses(), 0);
}
#[test]
fn test_pool_acquire_allocates_when_empty() {
let mut pool = StatePool::new();
let state = pool.acquire();
assert!(state.is_empty());
assert_eq!(pool.total_allocations(), 4); assert_eq!(pool.total_reuses(), 1); }
#[test]
fn test_pool_acquire_reuses_when_available() {
let mut pool = StatePool::new();
let state = pool.acquire();
pool.release(state);
assert_eq!(pool.pool_size(), 4);
let state2 = pool.acquire();
assert!(state2.is_empty());
assert_eq!(pool.total_allocations(), 4); assert_eq!(pool.total_reuses(), 2); assert_eq!(pool.pool_size(), 3); }
#[test]
fn test_pool_release_clears_state() {
use super::super::algorithm::Algorithm;
let mut pool = StatePool::new();
let max_distance = 2;
let mut state = pool.acquire();
state.insert(Position::new(1, 0), Algorithm::Standard, max_distance);
state.insert(Position::new(2, 1), Algorithm::Standard, max_distance); assert_eq!(state.len(), 1);
pool.release(state);
let state2 = pool.acquire();
assert!(state2.is_empty());
}
#[test]
fn test_pool_respects_max_size() {
let mut pool = StatePool::new();
for _ in 0..StatePool::MAX_POOL_SIZE {
pool.release(State::new());
}
assert_eq!(pool.pool_size(), StatePool::MAX_POOL_SIZE);
pool.release(State::new());
assert_eq!(pool.pool_size(), StatePool::MAX_POOL_SIZE);
}
#[test]
fn test_pool_reuse_rate() {
let mut pool = StatePool::new();
assert_eq!(pool.reuse_rate(), 0.0);
let state1 = pool.acquire();
pool.release(state1);
let _state2 = pool.acquire();
let expected = 2.0 / 6.0;
assert!((pool.reuse_rate() - expected).abs() < 1e-6);
}
#[test]
fn test_pool_lifo_order() {
use super::super::algorithm::Algorithm;
let mut pool = StatePool::new();
let max_distance = 2;
let mut state1 = State::new();
state1.insert(Position::new(1, 0), Algorithm::Standard, max_distance);
pool.release(state1);
let mut state2 = State::new();
state2.insert(Position::new(2, 0), Algorithm::Standard, max_distance);
pool.release(state2);
let acquired = pool.acquire();
assert!(acquired.is_empty());
assert_eq!(pool.pool_size(), 5);
}
#[test]
fn test_pool_capacity_preserved() {
use super::super::algorithm::Algorithm;
let mut pool = StatePool::new();
let max_distance = 10;
let mut state = pool.acquire();
for i in 0..10 {
state.insert(Position::new(i, 0), Algorithm::Standard, max_distance);
}
pool.release(state);
let mut state2 = pool.acquire();
assert!(state2.is_empty());
for i in 0..10 {
state2.insert(Position::new(i, 0), Algorithm::Standard, max_distance);
}
assert_eq!(state2.len(), 10);
}
}