use core::{iter::FusedIterator, marker::PhantomData};
use oxgraph_topology::{
ContainsElement, ElementId, ElementIndex, ElementPredecessors, ElementSuccessors,
};
use crate::bfs::{
BfsError,
core::{Bfs, EpochCounter, Forward, Reverse, SeededEpochFrontier, ValidatedScratch},
};
pub struct BfsEpochScratch<'scratch, G>
where
G: ContainsElement + ElementIndex,
{
marks: &'scratch mut [u32],
queue: &'scratch mut [ElementId<G>],
epoch: EpochCounter,
_graph: PhantomData<fn() -> G>,
}
impl<'scratch, G> BfsEpochScratch<'scratch, G>
where
G: ContainsElement + ElementIndex,
{
pub fn new(marks: &'scratch mut [u32], queue: &'scratch mut [ElementId<G>]) -> Self {
marks.fill(0);
Self {
marks,
queue,
epoch: EpochCounter::default(),
_graph: PhantomData,
}
}
pub fn for_graph(
_graph: &G,
marks: &'scratch mut [u32],
queue: &'scratch mut [ElementId<G>],
) -> Self {
Self::new(marks, queue)
}
#[must_use]
pub const fn mark_capacity(&self) -> usize {
self.marks.len()
}
#[must_use]
pub const fn queue_capacity(&self) -> usize {
self.queue.len()
}
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct BreadthFirstSearchEpochScratch<'graph, 'borrow, G>
where
G: ContainsElement + ElementSuccessors + ElementIndex,
{
inner: Bfs<'graph, G, SeededEpochFrontier<'borrow, G>, Forward>,
}
impl<G> Iterator for BreadthFirstSearchEpochScratch<'_, '_, G>
where
G: ContainsElement + ElementSuccessors + ElementIndex,
{
type Item = ElementId<G>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl<G> FusedIterator for BreadthFirstSearchEpochScratch<'_, '_, G> where
G: ContainsElement + ElementSuccessors + ElementIndex
{
}
pub fn breadth_first_search_with_epoch_scratch<'graph, 'borrow, 'scratch, G>(
graph: &'graph G,
start: ElementId<G>,
scratch: &'borrow mut BfsEpochScratch<'scratch, G>,
) -> Result<BreadthFirstSearchEpochScratch<'graph, 'borrow, G>, BfsError>
where
'scratch: 'borrow,
G: ContainsElement + ElementSuccessors + ElementIndex,
{
let witness = ValidatedScratch::new(graph, start, scratch.marks.len(), scratch.queue.len())?;
let epoch = scratch.epoch.advance(scratch.marks);
let frontier = SeededEpochFrontier::new(scratch.marks, scratch.queue, epoch, start, witness);
Ok(BreadthFirstSearchEpochScratch {
inner: Bfs::new(graph, frontier),
})
}
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ReverseBreadthFirstSearchEpochScratch<'graph, 'borrow, G>
where
G: ContainsElement + ElementPredecessors + ElementIndex,
{
inner: Bfs<'graph, G, SeededEpochFrontier<'borrow, G>, Reverse>,
}
impl<G> Iterator for ReverseBreadthFirstSearchEpochScratch<'_, '_, G>
where
G: ContainsElement + ElementPredecessors + ElementIndex,
{
type Item = ElementId<G>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl<G> FusedIterator for ReverseBreadthFirstSearchEpochScratch<'_, '_, G> where
G: ContainsElement + ElementPredecessors + ElementIndex
{
}
pub fn reverse_breadth_first_search_with_epoch_scratch<'graph, 'borrow, 'scratch, G>(
graph: &'graph G,
start: ElementId<G>,
scratch: &'borrow mut BfsEpochScratch<'scratch, G>,
) -> Result<ReverseBreadthFirstSearchEpochScratch<'graph, 'borrow, G>, BfsError>
where
'scratch: 'borrow,
G: ContainsElement + ElementPredecessors + ElementIndex,
{
let witness = ValidatedScratch::new(graph, start, scratch.marks.len(), scratch.queue.len())?;
let epoch = scratch.epoch.advance(scratch.marks);
let frontier = SeededEpochFrontier::new(scratch.marks, scratch.queue, epoch, start, witness);
Ok(ReverseBreadthFirstSearchEpochScratch {
inner: Bfs::new(graph, frontier),
})
}