use crate::common::defaults::POOL_KEEP_LIMIT;
use crate::common::ext::aligned_vec::{AVec, RuntimeAlign};
use crate::common::types::ScoreType;
use parking_lot::Mutex;
use typed_arena::Arena;
#[derive(Debug)]
pub struct SearchScratchPool {
pool: Mutex<Vec<SearchScratchScores>>,
}
impl SearchScratchPool {
#[expect(clippy::new_without_default)]
pub fn new() -> SearchScratchPool {
SearchScratchPool {
pool: Mutex::new(Vec::with_capacity(*POOL_KEEP_LIMIT)),
}
}
pub fn get(&self) -> SearchScratch<'_> {
let scores = self.pool.lock().pop().unwrap_or_default();
SearchScratch {
pool: self,
scores,
arena: SearchScratchArena::new_slow(),
}
}
}
pub struct SearchScratch<'a> {
pool: &'a SearchScratchPool,
pub(crate) scores: SearchScratchScores,
pub(crate) arena: SearchScratchArena,
}
impl SearchScratch<'_> {
#[cfg(test)]
pub fn new_for_test() -> SearchScratch<'static> {
use std::sync::OnceLock;
static POOL: OnceLock<SearchScratchPool> = OnceLock::new();
POOL.get_or_init(SearchScratchPool::new).get()
}
}
type SearchScratchScores = Vec<ScoreType>;
impl Drop for SearchScratch<'_> {
fn drop(&mut self) {
let SearchScratch {
pool: SearchScratchPool { pool },
scores,
arena: _,
} = self;
let mut pool = pool.lock();
if pool.len() < *POOL_KEEP_LIMIT {
pool.push(std::mem::take(scores));
}
}
}
pub struct SearchScratchArena(Arena<AVec<u8, RuntimeAlign>>);
impl SearchScratchArena {
pub fn new_slow() -> SearchScratchArena {
SearchScratchArena(Arena::new())
}
pub fn gc(&mut self) {
const ARBITRARY_LIMIT: usize = 256;
if self.0.len() > ARBITRARY_LIMIT {
self.0 = Arena::new();
}
for vec in self.0.iter_mut() {
*vec = AVec::new(1);
}
}
}
impl std::ops::Deref for SearchScratchArena {
type Target = Arena<AVec<u8, RuntimeAlign>>;
fn deref(&self) -> &Arena<AVec<u8, RuntimeAlign>> {
&self.0
}
}