140 lines
3.4 KiB
Rust
140 lines
3.4 KiB
Rust
use crate::maps::VertexMap;
|
|
use crate::traits::GraphTopology;
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
pub struct Vertex(usize);
|
|
|
|
impl From<Vertex> for usize {
|
|
fn from(v: Vertex) -> usize {
|
|
v.0
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
pub struct Incidence(usize);
|
|
|
|
struct VertexIncidenceHeader {
|
|
incidence_count: usize,
|
|
first_incidence: Option<Incidence>,
|
|
}
|
|
|
|
struct IncidenceEntry {
|
|
next: Option<Incidence>,
|
|
neighbor: Vertex,
|
|
}
|
|
|
|
struct VertexNeighborIterator<'a> {
|
|
graph: &'a AppendGraph,
|
|
incidence: Option<Incidence>,
|
|
}
|
|
|
|
impl<'a> Iterator for VertexNeighborIterator<'a> {
|
|
type Item = Vertex;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let incidence = self.incidence?;
|
|
let entry = &self.graph.incidences[incidence.0];
|
|
self.incidence = entry.next;
|
|
Some(entry.neighbor)
|
|
}
|
|
}
|
|
|
|
pub struct AppendGraph {
|
|
// TODO: Index 'vertices' by a 'Vertex' instead of 'Vertex.0'?
|
|
vertices: Vec<VertexIncidenceHeader>,
|
|
incidences: Vec<IncidenceEntry>,
|
|
}
|
|
|
|
impl AppendGraph {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
vertices: vec![],
|
|
incidences: vec![],
|
|
}
|
|
}
|
|
|
|
// Adds a single incidence of an edge, which is composed by two such incidences, to the
|
|
// incidences vector.
|
|
fn add_incidence(&mut self, v1: Vertex, v2: Vertex) {
|
|
self.incidences.push(IncidenceEntry {
|
|
next: self.vertices[v1.0].first_incidence.take(),
|
|
neighbor: v2,
|
|
});
|
|
self.vertices[v1.0].incidence_count += 1;
|
|
self.vertices[v1.0].first_incidence = Some(Incidence(self.incidences.len() - 1));
|
|
}
|
|
}
|
|
|
|
impl Default for AppendGraph {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl GraphTopology for AppendGraph {
|
|
type Vertex = Vertex;
|
|
|
|
type Edge = Incidence;
|
|
|
|
fn vertex_count(&self) -> usize {
|
|
self.vertices.len()
|
|
}
|
|
|
|
fn edge_count(&self) -> usize {
|
|
self.incidences.len() / 2
|
|
}
|
|
|
|
fn vertex_capacity(&self) -> usize {
|
|
self.vertices.len()
|
|
}
|
|
|
|
fn vertex_map<T: Clone>(&self, default: T) -> VertexMap<Self::Vertex, T> {
|
|
VertexMap::new(default, |v| v.0, self.vertex_capacity())
|
|
}
|
|
|
|
fn degree(&self, v: Self::Vertex) -> usize {
|
|
self.vertices[v.0].incidence_count
|
|
}
|
|
|
|
fn are_adjacent(&self, v1: Self::Vertex, v2: Self::Vertex) -> bool {
|
|
self.neighbors(v1).any(|x| x == v2)
|
|
}
|
|
|
|
fn vertices(&self) -> impl Iterator<Item = Self::Vertex> {
|
|
(0..self.vertices.len()).map(Vertex)
|
|
}
|
|
|
|
fn neighbors(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Vertex> {
|
|
VertexNeighborIterator {
|
|
graph: self,
|
|
incidence: self.vertices[v.0].first_incidence,
|
|
}
|
|
}
|
|
|
|
fn edges(&self) -> impl Iterator<Item = Self::Edge> {
|
|
(0..self.incidences.len()).step_by(2).map(Incidence)
|
|
}
|
|
|
|
fn add_vertex(&mut self) -> Self::Vertex {
|
|
self.vertices.push(VertexIncidenceHeader {
|
|
incidence_count: 0,
|
|
first_incidence: None,
|
|
});
|
|
Vertex(self.vertices.len() - 1)
|
|
}
|
|
|
|
fn add_edge(&mut self, v1: Self::Vertex, v2: Self::Vertex) -> Self::Edge {
|
|
self.add_incidence(v1, v2);
|
|
self.add_incidence(v2, v1);
|
|
Incidence(self.incidences.len() - 2)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
crate::graph_topology_test_fixtures!(AppendGraph);
|
|
crate::graph_topology_tests!(AppendGraph);
|
|
}
|