use std::cell::RefCell;
use implicit_predicates_core::{Mark, Scratch};
pub(crate) const INITIAL: usize = 16_384;
struct Arena {
scratch: Scratch<'static>,
empty: Mark,
}
thread_local! {
static ARENA: RefCell<Arena> = RefCell::new({
let scratch = Scratch::growable(INITIAL);
let empty = scratch.mark();
Arena { scratch, empty }
});
}
pub(crate) fn with<R>(f: impl FnOnce(&mut Scratch<'_>) -> R) -> R {
let mut f = Some(f);
let shared = ARENA.try_with(|arena| {
let mut arena = arena.try_borrow_mut().ok()?;
let f = f.take()?;
let Arena { scratch, empty } = &mut *arena;
scratch.reset(*empty);
let result = f(scratch);
scratch.reset(*empty);
Some(result)
});
match (shared, f) {
(Ok(Some(result)), _) => result,
(_, Some(f)) => f(&mut Scratch::growable(INITIAL)),
(_, None) => unreachable!("the arena of the thread ran `f` without a result"),
}
}