use core::marker::Copy;
use hashbrown::HashMap;
use hashbrown::hash_map::Entry::{Occupied, Vacant};
use std::collections::BinaryHeap;
use crate::prelude::*;
use super::{MinScored, measures::BoundedMeasure};
pub fn dijkstra<'a, G: ?Sized, F, K, T: GraphType>(
graph: &'a G,
start: G::NodeIndex,
goal: Option<G::NodeIndex>,
edge_cost: F,
) -> Result<HashMap<G::NodeIndex, K>, HypergraphErrors>
where
G: CommonProperties<'a, T>,
F: Fn(G::EdgeIndex) -> K,
K: BoundedMeasure + Copy,
{
let mut visited = graph.visit_map();
let mut scores = HashMap::new();
let mut visit_next = BinaryHeap::new();
let zero_score = K::default();
scores.insert(start, zero_score);
visit_next.push(MinScored(zero_score, start));
while let Some(MinScored(node_score, node)) = visit_next.pop() {
if visited.contains(node.into()) {
continue;
}
if goal.as_ref() == Some(&node) {
break;
}
for (next_score, nodes) in
graph.costed_neighbours(node, |edge_index| node_score + edge_cost(edge_index))
{
for next in nodes {
if visited.contains(next.into()) {
continue;
}
match scores.entry(next) {
Occupied(ent) => {
if next_score < *ent.get() {
*ent.into_mut() = next_score;
visit_next.push(MinScored(next_score, next));
}
}
Vacant(ent) => {
ent.insert(next_score);
visit_next.push(MinScored(next_score, next));
}
}
}
}
visited.insert(node.into());
}
Ok(scores)
}