Add GraphTopology.incidence_cursor() for certain use-cases where the iterator is problematic

Also add raw_incidences() and step_incidence() to AppendGraph analogously to
Graph, which allows to remove RawIncidenceIterator and simplify its call sites.
This commit is contained in:
2026-06-26 23:36:41 +02:00
parent c197766229
commit f009a86f1e
3 changed files with 54 additions and 27 deletions
+27 -25
View File
@@ -1,5 +1,5 @@
use crate::maps::{EdgeMap, VertexMap};
use crate::traits::GraphTopology;
use crate::traits::{GraphTopology, IncidenceCursor};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Vertex(usize);
@@ -18,24 +18,20 @@ struct VertexIncidenceHeader {
first_incidence: Option<Incidence>,
}
#[derive(Copy, Clone)]
struct IncidenceEntry {
next: Option<Incidence>,
adjacent: Vertex,
}
struct RawIncidenceIterator<'a> {
graph: &'a AppendGraph,
#[derive(Copy, Clone)]
pub struct AppendGraphIncidenceCursor {
incidence: Option<Incidence>,
}
impl<'a> Iterator for RawIncidenceIterator<'a> {
type Item = (Vertex, Incidence);
fn next(&mut self) -> Option<Self::Item> {
let current = self.incidence?;
let entry = &self.graph.incidences[current.0];
self.incidence = entry.next;
Some((entry.adjacent, current))
impl IncidenceCursor<AppendGraph> for AppendGraphIncidenceCursor {
fn next(&mut self, graph: &AppendGraph) -> Option<(Vertex, Incidence)> {
graph.step_incidence(&mut self.incidence)
}
}
@@ -62,6 +58,18 @@ impl AppendGraph {
self.vertices[v1.0].incidence_count += 1;
self.vertices[v1.0].first_incidence = Some(Incidence(self.incidences.len() - 1));
}
fn raw_incidences(&self, v: Vertex) -> impl Iterator<Item = (Vertex, Incidence)> {
let mut incidence = self.vertices[v.0].first_incidence;
std::iter::from_fn(move || self.step_incidence(&mut incidence))
}
fn step_incidence(&self, incidence: &mut Option<Incidence>) -> Option<(Vertex, Incidence)> {
let current = (*incidence)?;
let entry = self.incidences[current.0];
*incidence = entry.next;
Some((entry.adjacent, current))
}
}
impl Default for AppendGraph {
@@ -72,8 +80,8 @@ impl Default for AppendGraph {
impl GraphTopology for AppendGraph {
type Vertex = Vertex;
type Edge = Incidence;
type IncidenceCursor = AppendGraphIncidenceCursor;
fn vertex_count(&self) -> usize {
self.vertices.len()
@@ -112,11 +120,7 @@ impl GraphTopology for AppendGraph {
}
fn adjacent_vertices(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Vertex> {
RawIncidenceIterator {
graph: self,
incidence: self.vertices[v.0].first_incidence,
}
.map(|(v, _)| v)
self.raw_incidences(v).map(|(v, _)| v)
}
fn incident_vertices(&self, e: Self::Edge) -> (Self::Vertex, Self::Vertex) {
@@ -130,19 +134,17 @@ impl GraphTopology for AppendGraph {
}
fn incident_edges(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Edge> {
RawIncidenceIterator {
graph: self,
incidence: self.vertices[v.0].first_incidence,
}
.map(|(_, e)| e.normalize())
self.raw_incidences(v).map(|(_, e)| e.normalize())
}
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)> {
RawIncidenceIterator {
graph: self,
self.raw_incidences(v).map(|(v, e)| (v, e.normalize()))
}
fn incidence_cursor(&self, v: Self::Vertex) -> Self::IncidenceCursor {
AppendGraphIncidenceCursor {
incidence: self.vertices[v.0].first_incidence,
}
.map(|(v, e)| (v, e.normalize()))
}
fn add_vertex(&mut self) -> Self::Vertex {