Skip to content

Commit c3ab57c

Browse files
authored
Rollup merge of rust-lang#37535 - Havvy:graph, r=eddyb
Graph Changes General cleanup and adding a few methods that I want to use in Clippy. Need somebody to bikeshed names.
2 parents 29195e2 + 9ddbb91 commit c3ab57c

File tree

2 files changed

+126
-19
lines changed

2 files changed

+126
-19
lines changed

src/librustc_data_structures/graph/mod.rs

+84-15
Original file line numberDiff line numberDiff line change
@@ -231,18 +231,30 @@ impl<N: Debug, E: Debug> Graph<N, E> {
231231

232232
// # Iterating over nodes, edges
233233

234+
pub fn enumerated_nodes(&self) -> EnumeratedNodes<N> {
235+
EnumeratedNodes {
236+
iter: self.nodes.iter().enumerate()
237+
}
238+
}
239+
240+
pub fn enumerated_edges(&self) -> EnumeratedEdges<E> {
241+
EnumeratedEdges {
242+
iter: self.edges.iter().enumerate()
243+
}
244+
}
245+
234246
pub fn each_node<'a, F>(&'a self, mut f: F) -> bool
235247
where F: FnMut(NodeIndex, &'a Node<N>) -> bool
236248
{
237249
//! Iterates over all edges defined in the graph.
238-
self.nodes.iter().enumerate().all(|(i, node)| f(NodeIndex(i), node))
250+
self.enumerated_nodes().all(|(node_idx, node)| f(node_idx, node))
239251
}
240252

241253
pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool
242254
where F: FnMut(EdgeIndex, &'a Edge<E>) -> bool
243255
{
244256
//! Iterates over all edges defined in the graph
245-
self.edges.iter().enumerate().all(|(i, edge)| f(EdgeIndex(i), edge))
257+
self.enumerated_edges().all(|(edge_idx, edge)| f(edge_idx, edge))
246258
}
247259

248260
pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges<N, E> {
@@ -270,14 +282,11 @@ impl<N: Debug, E: Debug> Graph<N, E> {
270282
self.incoming_edges(target).sources()
271283
}
272284

273-
// # Fixed-point iteration
274-
//
275-
// A common use for graphs in our compiler is to perform
276-
// fixed-point iteration. In this case, each edge represents a
277-
// constraint, and the nodes themselves are associated with
278-
// variables or other bitsets. This method facilitates such a
279-
// computation.
280-
285+
/// A common use for graphs in our compiler is to perform
286+
/// fixed-point iteration. In this case, each edge represents a
287+
/// constraint, and the nodes themselves are associated with
288+
/// variables or other bitsets. This method facilitates such a
289+
/// computation.
281290
pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F)
282291
where F: FnMut(usize, EdgeIndex, &'a Edge<E>) -> bool
283292
{
@@ -286,8 +295,8 @@ impl<N: Debug, E: Debug> Graph<N, E> {
286295
while changed {
287296
changed = false;
288297
iteration += 1;
289-
for (i, edge) in self.edges.iter().enumerate() {
290-
changed |= op(iteration, EdgeIndex(i), edge);
298+
for (edge_index, edge) in self.enumerated_edges() {
299+
changed |= op(iteration, edge_index, edge);
291300
}
292301
}
293302
}
@@ -298,10 +307,67 @@ impl<N: Debug, E: Debug> Graph<N, E> {
298307
-> DepthFirstTraversal<'a, N, E> {
299308
DepthFirstTraversal::with_start_node(self, start, direction)
300309
}
310+
311+
/// Whether or not a node can be reached from itself.
312+
pub fn is_node_cyclic(&self, starting_node_index: NodeIndex) -> bool {
313+
// This is similar to depth traversal below, but we
314+
// can't use that, because depth traversal doesn't show
315+
// the starting node a second time.
316+
let mut visited = BitVector::new(self.len_nodes());
317+
let mut stack = vec![starting_node_index];
318+
319+
while let Some(current_node_index) = stack.pop() {
320+
visited.insert(current_node_index.0);
321+
322+
// Directionality doesn't change the answer,
323+
// so just use outgoing edges.
324+
for (_, edge) in self.outgoing_edges(current_node_index) {
325+
let target_node_index = edge.target();
326+
327+
if target_node_index == starting_node_index {
328+
return true;
329+
}
330+
331+
if !visited.contains(target_node_index.0) {
332+
stack.push(target_node_index);
333+
}
334+
}
335+
}
336+
337+
false
338+
}
301339
}
302340

303341
// # Iterators
304342

343+
pub struct EnumeratedNodes<'g, N>
344+
where N: 'g,
345+
{
346+
iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Node<N>>>
347+
}
348+
349+
impl<'g, N: Debug> Iterator for EnumeratedNodes<'g, N> {
350+
type Item = (NodeIndex, &'g Node<N>);
351+
352+
fn next(&mut self) -> Option<(NodeIndex, &'g Node<N>)> {
353+
self.iter.next().map(|(idx, n)| (NodeIndex(idx), n))
354+
}
355+
}
356+
357+
pub struct EnumeratedEdges<'g, E>
358+
where E: 'g,
359+
{
360+
iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Edge<E>>>
361+
}
362+
363+
impl<'g, E: Debug> Iterator for EnumeratedEdges<'g, E> {
364+
type Item = (EdgeIndex, &'g Edge<E>);
365+
366+
fn next(&mut self) -> Option<(EdgeIndex, &'g Edge<E>)> {
367+
self.iter.next().map(|(idx, e)| (EdgeIndex(idx), e))
368+
}
369+
}
370+
305371
pub struct AdjacentEdges<'g, N, E>
306372
where N: 'g,
307373
E: 'g
@@ -336,7 +402,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> {
336402
}
337403
}
338404

339-
pub struct AdjacentTargets<'g, N: 'g, E: 'g>
405+
pub struct AdjacentTargets<'g, N, E>
340406
where N: 'g,
341407
E: 'g
342408
{
@@ -351,7 +417,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentTargets<'g, N, E> {
351417
}
352418
}
353419

354-
pub struct AdjacentSources<'g, N: 'g, E: 'g>
420+
pub struct AdjacentSources<'g, N, E>
355421
where N: 'g,
356422
E: 'g
357423
{
@@ -366,7 +432,10 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentSources<'g, N, E> {
366432
}
367433
}
368434

369-
pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> {
435+
pub struct DepthFirstTraversal<'g, N, E>
436+
where N: 'g,
437+
E: 'g
438+
{
370439
graph: &'g Graph<N, E>,
371440
stack: Vec<NodeIndex>,
372441
visited: BitVector,

src/librustc_data_structures/graph/tests.rs

+42-4
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ fn create_graph() -> TestGraph {
2020

2121
// Create a simple graph
2222
//
23-
// A -+> B --> C
24-
// | | ^
25-
// | v |
26-
// F D --> E
23+
// F
24+
// |
25+
// V
26+
// A --> B --> C
27+
// | ^
28+
// v |
29+
// D --> E
2730

2831
let a = graph.add_node("A");
2932
let b = graph.add_node("B");
@@ -42,6 +45,29 @@ fn create_graph() -> TestGraph {
4245
return graph;
4346
}
4447

48+
fn create_graph_with_cycle() -> TestGraph {
49+
let mut graph = Graph::new();
50+
51+
// Create a graph with a cycle.
52+
//
53+
// A --> B <-- +
54+
// | |
55+
// v |
56+
// C --> D
57+
58+
let a = graph.add_node("A");
59+
let b = graph.add_node("B");
60+
let c = graph.add_node("C");
61+
let d = graph.add_node("D");
62+
63+
graph.add_edge(a, b, "AB");
64+
graph.add_edge(b, c, "BC");
65+
graph.add_edge(c, d, "CD");
66+
graph.add_edge(d, b, "DB");
67+
68+
return graph;
69+
}
70+
4571
#[test]
4672
fn each_node() {
4773
let graph = create_graph();
@@ -139,3 +165,15 @@ fn each_adjacent_from_d() {
139165
let graph = create_graph();
140166
test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]);
141167
}
168+
169+
#[test]
170+
fn is_node_cyclic_a() {
171+
let graph = create_graph_with_cycle();
172+
assert!(!graph.is_node_cyclic(NodeIndex(0)));
173+
}
174+
175+
#[test]
176+
fn is_node_cyclic_b() {
177+
let graph = create_graph_with_cycle();
178+
assert!(graph.is_node_cyclic(NodeIndex(1)));
179+
}

0 commit comments

Comments
 (0)