use std::collections::{HashMap, HashSet};
use super::answer::ProofNode;
use super::compile::TTerm;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum TableState {
Complete,
Evaluating(usize),
Incomplete,
}
#[derive(Debug, Clone)]
pub(crate) struct Table {
pub answers: Vec<TTerm>,
pub proofs: Vec<Option<Vec<ProofNode>>>,
seen: HashSet<TTerm>,
pub state: TableState,
}
#[derive(Debug, Clone, Default)]
pub(crate) struct Tables {
map: HashMap<TTerm, Table>,
pub total: usize,
}
impl Tables {
pub fn state(&self, key: &TTerm) -> Option<TableState> {
self.map.get(key).map(|t| t.state)
}
pub fn begin(&mut self, key: &TTerm, depth: usize) {
let t = self.map.entry(key.clone()).or_insert_with(|| Table {
answers: Vec::new(),
proofs: Vec::new(),
seen: HashSet::new(),
state: TableState::Evaluating(depth),
});
t.state = TableState::Evaluating(depth);
}
pub fn set_state(&mut self, key: &TTerm, state: TableState) {
if let Some(t) = self.map.get_mut(key) {
t.state = state;
}
}
pub fn add(&mut self, key: &TTerm, answer: TTerm, proof: Option<Vec<ProofNode>>) -> bool {
let Some(t) = self.map.get_mut(key) else {
return false;
};
if !t.seen.insert(answer.clone()) {
return false;
}
t.answers.push(answer);
t.proofs.push(proof);
self.total += 1;
true
}
#[cfg(test)]
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn len(&self, key: &TTerm) -> usize {
self.map.get(key).map_or(0, |t| t.answers.len())
}
pub fn answer(&self, key: &TTerm, i: usize) -> Option<(&TTerm, &Option<Vec<ProofNode>>)> {
let t = self.map.get(key)?;
Some((t.answers.get(i)?, t.proofs.get(i)?))
}
pub fn abandon(&mut self) {
self.map.retain(|_, t| t.state == TableState::Complete);
}
}