use rustc_hash::FxHashMap as HashMap;
use std::cell::{Cell, RefCell};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub(crate) enum Reading {
RefitDetection,
OldTracking,
SignContribution,
}
const CAPACITY: usize = 1 << 16;
thread_local! {
static MEMO: RefCell<HashMap<(Reading, [u64; 2]), Option<f64>>> = RefCell::new(HashMap::default());
static HITS: Cell<u64> = const { Cell::new(0) };
static MISSES: Cell<u64> = const { Cell::new(0) };
}
thread_local! {
static HATCH_OFF: std::cell::OnceCell<bool> = const { std::cell::OnceCell::new() };
}
fn memo_on() -> bool {
!HATCH_OFF.with(|cell| *cell.get_or_init(|| std::env::var("BREP_READING_MEMO").as_deref() == Ok("0")))
}
pub(crate) fn memoized(reading: Reading, key: [u64; 2], read: impl FnOnce() -> Option<f64>) -> Option<f64> {
if !memo_on() {
return read();
}
if let Some(value) = MEMO.with(|memo| memo.borrow().get(&(reading, key)).copied()) {
HITS.with(|hits| hits.set(hits.get() + 1));
return value;
}
MISSES.with(|misses| misses.set(misses.get() + 1));
let value = read();
MEMO.with(|memo| {
let mut memo = memo.borrow_mut();
if memo.len() >= CAPACITY {
memo.clear();
}
memo.insert((reading, key), value);
});
value
}
pub(crate) fn clear() {
MEMO.with(|memo| memo.borrow_mut().clear());
}
pub(crate) fn counts() -> (u64, u64) {
(HITS.with(|hits| hits.get()), MISSES.with(|misses| misses.get()))
}