use crate::adjacencies::Adjacencies;
use crate::collections::{ItemMap, ItemStack};
use crate::traits::{GraphIterator, GraphType};
use std::collections::HashMap;
use std::hash::Hash;
use std::marker::PhantomData;
pub type DFSDefault<'a, A> = DFS<
'a,
A,
HashMap<<A as GraphType<'a>>::Node, <A as GraphType<'a>>::Edge>,
Vec<<A as Adjacencies<'a>>::IncidenceIt>,
>;
pub type DefaultData<N, E, I> = (HashMap<N, E>, Vec<I>);
pub fn start<'a, A>(adj: A, src: A::Node) -> DFSDefault<'a, A>
where
A: Adjacencies<'a>,
A::Node: Hash,
{
start_with_data(adj, src, DefaultData::default())
}
pub fn start_with_data<'a, A, S, St>(adj: A, src: A::Node, data: (S, St)) -> DFS<'a, A, S, St>
where
A: Adjacencies<'a>,
S: ItemMap<A::Node, A::Edge>,
St: ItemStack<A::IncidenceIt>,
{
let (mut seen, mut stack) = data;
seen.clear();
stack.clear();
stack.push(adj.neigh_iter(src));
DFS {
adj,
src,
seen,
stack,
phantom: PhantomData,
}
}
pub struct DFS<'a, A, S, St>
where
A: Adjacencies<'a>,
S: ItemMap<A::Node, A::Edge>,
St: ItemStack<A::IncidenceIt>,
{
adj: A,
src: A::Node,
seen: S,
stack: St,
phantom: PhantomData<&'a ()>,
}
impl<'a, A, S, St> Iterator for DFS<'a, A, S, St>
where
A: Adjacencies<'a>,
S: ItemMap<A::Node, A::Edge>,
St: ItemStack<A::IncidenceIt>,
{
type Item = (A::Node, A::Edge);
fn next(&mut self) -> Option<Self::Item> {
while let Some(mut it) = self.stack.pop() {
if let Some((e, v)) = it.next(&self.adj) {
self.stack.push(it);
if v != self.src && self.seen.insert(v, e) {
self.stack.push(self.adj.neigh_iter(v));
return Some((v, e));
}
}
}
None
}
}
impl<'a, A, S, St> DFS<'a, A, S, St>
where
A: Adjacencies<'a>,
S: ItemMap<A::Node, A::Edge>,
St: ItemStack<A::IncidenceIt>,
{
pub fn run(&mut self) {
while self.next().is_some() {}
}
pub fn into_data(self) -> (S, St) {
(self.seen, self.stack)
}
pub fn incoming_edge(&self, u: A::Node) -> Option<A::Edge> {
self.seen.get(u).cloned()
}
}