use std::any::Any;
use std::cell::RefCell;
use super::matching::{Csr, NONE};
pub(super) struct GacScratch<V> {
pub(super) participants: Vec<usize>,
pub(super) has_sentinel: Vec<bool>,
pub(super) assigned_ns: Vec<V>,
pub(super) all_vals: Vec<V>,
pub(super) adj: Csr,
pub(super) match_u: Vec<u32>,
pub(super) match_v: Vec<u32>,
pub(super) dist: Vec<u32>,
pub(super) queue: Vec<u32>,
pub(super) res_adj: Csr,
pub(super) reachable: Vec<bool>,
pub(super) bfs: Vec<u32>,
pub(super) t_index: Vec<u32>,
pub(super) t_lowlink: Vec<u32>,
pub(super) t_onstack: Vec<bool>,
pub(super) t_scc: Vec<u32>,
pub(super) t_stack: Vec<u32>,
pub(super) t_call: Vec<(u32, u32)>,
pub(super) cache: Vec<Option<Vec<Option<V>>>>,
pub(super) val_index: Vec<u32>,
pub(super) val_index_gen: Vec<u32>,
pub(super) assigned_mark: Vec<u32>,
pub(super) cur_gen: u32,
}
pub(super) const MAX_FAST_INDEX: usize = 1 << 20;
pub(super) fn fast_index<V: 'static>(v: &V) -> Option<usize> {
let any = v as &dyn Any;
macro_rules! try_ints {
($($t:ty),*) => {$(
if let Some(&x) = any.downcast_ref::<$t>() {
return usize::try_from(x).ok().filter(|&k| k <= MAX_FAST_INDEX);
}
)*};
}
try_ints!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
None
}
impl<V> Default for GacScratch<V> {
fn default() -> Self {
Self {
participants: Vec::new(),
has_sentinel: Vec::new(),
assigned_ns: Vec::new(),
all_vals: Vec::new(),
adj: Csr::default(),
match_u: Vec::new(),
match_v: Vec::new(),
dist: Vec::new(),
queue: Vec::new(),
res_adj: Csr::default(),
reachable: Vec::new(),
bfs: Vec::new(),
t_index: Vec::new(),
t_lowlink: Vec::new(),
t_onstack: Vec::new(),
t_scc: Vec::new(),
t_stack: Vec::new(),
t_call: Vec::new(),
cache: Vec::new(),
val_index: Vec::new(),
val_index_gen: Vec::new(),
assigned_mark: Vec::new(),
cur_gen: 0,
}
}
}
thread_local! {
static SCRATCH: RefCell<Box<dyn Any>> = RefCell::new(Box::new(()));
}
pub(super) fn with_scratch<V, R>(f: impl FnOnce(&mut GacScratch<V>) -> R) -> R
where
V: 'static,
{
SCRATCH.with(|slot| {
let mut b = slot.borrow_mut();
if !b.is::<GacScratch<V>>() {
*b = Box::new(GacScratch::<V>::default());
}
let s = b.downcast_mut::<GacScratch<V>>().unwrap();
f(s)
})
}
pub(super) fn resize_tarjan<V>(s: &mut GacScratch<V>, n: usize) {
s.t_index.resize(n, NONE);
s.t_lowlink.resize(n, 0);
s.t_onstack.clear();
s.t_onstack.resize(n, false);
s.t_scc.resize(n, NONE);
}