use crate::*;
use std::sync::mpsc::Receiver;
pub struct CycleDetector {
pub ids: HashMap<grader::Name, usize>,
pub edges: Vec<(usize, usize)>,
}
impl CycleDetector {
pub fn new(
loader: &Loader,
rc: Receiver<(Arc<String>, grader::Name)>
) -> CycleDetector {
let mut ids = HashMap::default();
for fun in loader.functions.keys() {
if !ids.contains_key(&(vec![], fun.clone())) {
let id = ids.len();
ids.insert((vec![], fun.clone()), id);
}
}
let mut edges = vec![];
for (a, b) in rc.iter() {
let a_id = if !ids.contains_key(&(vec![], a.clone())) {
let id = ids.len();
ids.insert((vec![], a.clone()), id);
id
} else {*ids.get(&(vec![], a.clone())).unwrap()};
let b_id = if !ids.contains_key(&b) {
let id = ids.len();
ids.insert(b, id);
id
} else {*ids.get(&b).unwrap()};
edges.push((a_id, b_id));
}
edges.sort();
edges.dedup();
CycleDetector {
ids,
edges,
}
}
pub fn cycles(&self) -> Option<Vec<(usize, usize)>> {
let mut visited = vec![false; self.ids.len()];
for &(a, b) in &self.edges {
if !self.edges.iter().any(|&(_, d)| d == a) {
visited[a] = true;
}
if !self.edges.iter().any(|&(c, _)| c == b) {
visited[b] = true;
}
}
loop {
let mut changed = false;
for &(a, b) in &self.edges {
if !visited[a] {
if self.edges.iter().all(|&(c, d)| a != c || visited[d]) {
visited[a] = true;
changed = true;
}
}
if !visited[b] {
if self.edges.iter().all(|&(c, d)| b != d || visited[c]) {
visited[b] = true;
changed = true;
}
}
}
if !changed {break}
}
let mut cycles = vec![];
for &(a, b) in &self.edges {
if !visited[a] && !visited[b] {cycles.push((a, b))}
}
if cycles.len() == 0 {None} else {Some(cycles)}
}
}