use super::reverse_path;
use crate::{FxIndexMap, FxIndexSet};
use indexmap::map::Entry::Vacant;
use std::hash::Hash;
use std::iter::FusedIterator;
use std::usize;
pub fn bfs<N, FN, IN, FS>(start: &N, successors: FN, success: FS) -> Option<Vec<N>>
where
N: Eq + Hash + Clone,
FN: FnMut(&N) -> IN,
IN: IntoIterator<Item = N>,
FS: FnMut(&N) -> bool,
{
bfs_core(start, successors, success, true)
}
fn bfs_core<N, FN, IN, FS>(
start: &N,
mut successors: FN,
mut success: FS,
check_first: bool,
) -> Option<Vec<N>>
where
N: Eq + Hash + Clone,
FN: FnMut(&N) -> IN,
IN: IntoIterator<Item = N>,
FS: FnMut(&N) -> bool,
{
if check_first && success(start) {
return Some(vec![start.clone()]);
}
let mut i = 0;
let mut parents: FxIndexMap<N, usize> = FxIndexMap::default();
parents.insert(start.clone(), usize::max_value());
while let Some((node, _)) = parents.get_index(i) {
for successor in successors(node) {
if success(&successor) {
let mut path = reverse_path(&parents, |&p| p, i);
path.push(successor);
return Some(path);
}
if let Vacant(e) = parents.entry(successor) {
e.insert(i);
}
}
i += 1;
}
None
}
pub fn bfs_loop<N, FN, IN>(start: &N, successors: FN) -> Option<Vec<N>>
where
N: Eq + Hash + Clone,
FN: FnMut(&N) -> IN,
IN: IntoIterator<Item = N>,
{
bfs_core(start, successors, |n| n == start, false)
}
pub fn bfs_reach<N, FN, IN>(start: N, successors: FN) -> BfsReachable<N, FN>
where
N: Eq + Hash + Clone,
FN: FnMut(&N) -> IN,
IN: IntoIterator<Item = N>,
{
let mut seen = FxIndexSet::default();
seen.insert(start);
BfsReachable {
i: 0,
seen,
successors,
}
}
pub struct BfsReachable<N, FN> {
i: usize,
seen: FxIndexSet<N>,
successors: FN,
}
impl<N, FN, IN> Iterator for BfsReachable<N, FN>
where
N: Eq + Hash + Clone,
FN: FnMut(&N) -> IN,
IN: IntoIterator<Item = N>,
{
type Item = N;
fn next(&mut self) -> Option<Self::Item> {
let n = self.seen.get_index(self.i)?.clone();
for s in (self.successors)(&n) {
self.seen.insert(s);
}
self.i += 1;
Some(n)
}
}
impl<N, FN, IN> FusedIterator for BfsReachable<N, FN>
where
N: Eq + Hash + Clone,
FN: FnMut(&N) -> IN,
IN: IntoIterator<Item = N>,
{
}