mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #152621 - petrochenkov:graph2, r=Zalathar
LinkedGraph: support adding nodes and edges in arbitrary order If an edge uses some not-yet-known node, we just leave the node's data empty, that data can be added later. Use this support to avoid skipping edges in RetainedDepGraph. This is continuation of https://github.com/rust-lang/rust/pull/152590, that PR just fixes the ICE, this PR also preserves all the edges in debug dumps. This is also a minimized version of https://github.com/rust-lang/rust/pull/151821 with a smaller amount of data structure hacks.
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use tracing::debug;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -45,13 +46,13 @@
|
||||
/// and does not implement those traits, so it has its own implementations of a
|
||||
/// few basic graph algorithms.
|
||||
pub struct LinkedGraph<N, E> {
|
||||
nodes: Vec<Node<N>>,
|
||||
nodes: IndexVec<NodeIndex, Node<N>>,
|
||||
edges: Vec<Edge<E>>,
|
||||
}
|
||||
|
||||
pub struct Node<N> {
|
||||
first_edge: [EdgeIndex; 2], // see module comment
|
||||
pub data: N,
|
||||
pub data: Option<N>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -62,7 +63,7 @@ pub struct Edge<E> {
|
||||
pub data: E,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct NodeIndex(pub usize);
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
@@ -87,19 +88,29 @@ pub fn node_id(self) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
impl Idx for NodeIndex {
|
||||
fn new(idx: usize) -> NodeIndex {
|
||||
NodeIndex(idx)
|
||||
}
|
||||
|
||||
fn index(self) -> usize {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Debug, E: Debug> LinkedGraph<N, E> {
|
||||
pub fn new() -> Self {
|
||||
Self { nodes: Vec::new(), edges: Vec::new() }
|
||||
Self { nodes: IndexVec::new(), edges: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn with_capacity(nodes: usize, edges: usize) -> Self {
|
||||
Self { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) }
|
||||
Self { nodes: IndexVec::with_capacity(nodes), edges: Vec::with_capacity(edges) }
|
||||
}
|
||||
|
||||
// # Simple accessors
|
||||
|
||||
#[inline]
|
||||
pub fn all_nodes(&self) -> &[Node<N>] {
|
||||
pub fn all_nodes(&self) -> &IndexSlice<NodeIndex, Node<N>> {
|
||||
&self.nodes
|
||||
}
|
||||
|
||||
@@ -124,22 +135,34 @@ pub fn next_node_index(&self) -> NodeIndex {
|
||||
NodeIndex(self.nodes.len())
|
||||
}
|
||||
|
||||
fn ensure_node(&mut self, idx: NodeIndex) -> &mut Node<N> {
|
||||
self.nodes.ensure_contains_elem(idx, || Node {
|
||||
first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX],
|
||||
data: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_node_with_idx(&mut self, idx: NodeIndex, data: N) {
|
||||
let old_data = self.ensure_node(idx).data.replace(data);
|
||||
debug_assert!(old_data.is_none());
|
||||
}
|
||||
|
||||
pub fn add_node(&mut self, data: N) -> NodeIndex {
|
||||
let idx = self.next_node_index();
|
||||
self.nodes.push(Node { first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], data });
|
||||
self.add_node_with_idx(idx, data);
|
||||
idx
|
||||
}
|
||||
|
||||
pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N {
|
||||
&mut self.nodes[idx.0].data
|
||||
self.nodes[idx].data.as_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn node_data(&self, idx: NodeIndex) -> &N {
|
||||
&self.nodes[idx.0].data
|
||||
self.nodes[idx].data.as_ref().unwrap()
|
||||
}
|
||||
|
||||
pub fn node(&self, idx: NodeIndex) -> &Node<N> {
|
||||
&self.nodes[idx.0]
|
||||
&self.nodes[idx]
|
||||
}
|
||||
|
||||
// # Edge construction and queries
|
||||
@@ -154,16 +177,16 @@ pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> Edg
|
||||
let idx = self.next_edge_index();
|
||||
|
||||
// read current first of the list of edges from each node
|
||||
let source_first = self.nodes[source.0].first_edge[OUTGOING.repr];
|
||||
let target_first = self.nodes[target.0].first_edge[INCOMING.repr];
|
||||
let source_first = self.ensure_node(source).first_edge[OUTGOING.repr];
|
||||
let target_first = self.ensure_node(target).first_edge[INCOMING.repr];
|
||||
|
||||
// create the new edge, with the previous firsts from each node
|
||||
// as the next pointers
|
||||
self.edges.push(Edge { next_edge: [source_first, target_first], source, target, data });
|
||||
|
||||
// adjust the firsts for each node target be the next object.
|
||||
self.nodes[source.0].first_edge[OUTGOING.repr] = idx;
|
||||
self.nodes[target.0].first_edge[INCOMING.repr] = idx;
|
||||
self.nodes[source].first_edge[OUTGOING.repr] = idx;
|
||||
self.nodes[target].first_edge[INCOMING.repr] = idx;
|
||||
|
||||
idx
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ fn each_node() {
|
||||
let expected = ["A", "B", "C", "D", "E", "F"];
|
||||
graph.each_node(|idx, node| {
|
||||
assert_eq!(&expected[idx.0], graph.node_data(idx));
|
||||
assert_eq!(expected[idx.0], node.data);
|
||||
assert_eq!(expected[idx.0], node.data.unwrap());
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::graph::linked_graph::{Direction, INCOMING, LinkedGraph, NodeIndex};
|
||||
use rustc_index::IndexVec;
|
||||
|
||||
use super::{DepNode, DepNodeIndex};
|
||||
|
||||
@@ -13,7 +12,6 @@
|
||||
pub struct RetainedDepGraph {
|
||||
pub inner: LinkedGraph<DepNode, ()>,
|
||||
pub indices: FxHashMap<DepNode, NodeIndex>,
|
||||
pub dep_index_to_index: IndexVec<DepNodeIndex, Option<NodeIndex>>,
|
||||
}
|
||||
|
||||
impl RetainedDepGraph {
|
||||
@@ -23,27 +21,22 @@ pub fn new(prev_node_count: usize) -> Self {
|
||||
|
||||
let inner = LinkedGraph::with_capacity(node_count, edge_count);
|
||||
let indices = FxHashMap::default();
|
||||
let dep_index_to_index = IndexVec::new();
|
||||
|
||||
Self { inner, indices, dep_index_to_index }
|
||||
Self { inner, indices }
|
||||
}
|
||||
|
||||
pub fn push(&mut self, index: DepNodeIndex, node: DepNode, edges: &[DepNodeIndex]) {
|
||||
let source = self.inner.add_node(node);
|
||||
self.dep_index_to_index.insert(index, source);
|
||||
let source = NodeIndex(index.as_usize());
|
||||
self.inner.add_node_with_idx(source, node);
|
||||
self.indices.insert(node, source);
|
||||
|
||||
for &target in edges.iter() {
|
||||
// We may miss the edges that are pushed while the `DepGraphQuery` is being accessed.
|
||||
// Skip them to issues.
|
||||
if let Some(&Some(target)) = self.dep_index_to_index.get(target) {
|
||||
self.inner.add_edge(source, target, ());
|
||||
}
|
||||
self.inner.add_edge(source, NodeIndex(target.as_usize()), ());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nodes(&self) -> Vec<&DepNode> {
|
||||
self.inner.all_nodes().iter().map(|n| &n.data).collect()
|
||||
self.inner.all_nodes().iter().map(|n| n.data.as_ref().unwrap()).collect()
|
||||
}
|
||||
|
||||
pub fn edges(&self) -> Vec<(&DepNode, &DepNode)> {
|
||||
|
||||
Reference in New Issue
Block a user