Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Graph Changes #37535

Merged
merged 4 commits into from
Nov 12, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 84 additions & 15 deletions src/librustc_data_structures/graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,18 +231,30 @@ impl<N: Debug, E: Debug> Graph<N, E> {

// # Iterating over nodes, edges

pub fn enumerated_nodes(&self) -> EnumeratedNodes<N> {
EnumeratedNodes {
iter: self.nodes.iter().enumerate()
}
}

pub fn enumerated_edges(&self) -> EnumeratedEdges<E> {
EnumeratedEdges {
iter: self.edges.iter().enumerate()
}
}

pub fn each_node<'a, F>(&'a self, mut f: F) -> bool
where F: FnMut(NodeIndex, &'a Node<N>) -> bool
{
//! Iterates over all edges defined in the graph.
self.nodes.iter().enumerate().all(|(i, node)| f(NodeIndex(i), node))
self.enumerated_nodes().all(|(node_idx, node)| f(node_idx, node))
}

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

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

// # Fixed-point iteration
//
// A common use for graphs in our compiler is to perform
// fixed-point iteration. In this case, each edge represents a
// constraint, and the nodes themselves are associated with
// variables or other bitsets. This method facilitates such a
// computation.

/// A common use for graphs in our compiler is to perform
/// fixed-point iteration. In this case, each edge represents a
/// constraint, and the nodes themselves are associated with
/// variables or other bitsets. This method facilitates such a
/// computation.
pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F)
where F: FnMut(usize, EdgeIndex, &'a Edge<E>) -> bool
{
Expand All @@ -286,8 +295,8 @@ impl<N: Debug, E: Debug> Graph<N, E> {
while changed {
changed = false;
iteration += 1;
for (i, edge) in self.edges.iter().enumerate() {
changed |= op(iteration, EdgeIndex(i), edge);
for (edge_index, edge) in self.enumerated_edges() {
changed |= op(iteration, edge_index, edge);
}
}
}
Expand All @@ -298,10 +307,67 @@ impl<N: Debug, E: Debug> Graph<N, E> {
-> DepthFirstTraversal<'a, N, E> {
DepthFirstTraversal::with_start_node(self, start, direction)
}

/// Whether or not a node can be reached from itself.
pub fn is_node_cyclic(&self, starting_node_index: NodeIndex) -> bool {
// This is similar to depth traversal below, but we
// can't use that, because depth traversal doesn't show
// the starting node a second time.
let mut visited = BitVector::new(self.len_nodes());
let mut stack = vec![starting_node_index];

while let Some(current_node_index) = stack.pop() {
visited.insert(current_node_index.0);

// Directionality doesn't change the answer,
// so just use outgoing edges.
for (_, edge) in self.outgoing_edges(current_node_index) {
let target_node_index = edge.target();

if target_node_index == starting_node_index {
return true;
}

if !visited.contains(target_node_index.0) {
stack.push(target_node_index);
}
}
}

false
}
}

// # Iterators

pub struct EnumeratedNodes<'g, N>
where N: 'g,
{
iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Node<N>>>
}

impl<'g, N: Debug> Iterator for EnumeratedNodes<'g, N> {
type Item = (NodeIndex, &'g Node<N>);

fn next(&mut self) -> Option<(NodeIndex, &'g Node<N>)> {
self.iter.next().map(|(idx, n)| (NodeIndex(idx), n))
}
}

pub struct EnumeratedEdges<'g, E>
where E: 'g,
{
iter: ::std::iter::Enumerate<::std::slice::Iter<'g, Edge<E>>>
}

impl<'g, E: Debug> Iterator for EnumeratedEdges<'g, E> {
type Item = (EdgeIndex, &'g Edge<E>);

fn next(&mut self) -> Option<(EdgeIndex, &'g Edge<E>)> {
self.iter.next().map(|(idx, e)| (EdgeIndex(idx), e))
}
}

pub struct AdjacentEdges<'g, N, E>
where N: 'g,
E: 'g
Expand Down Expand Up @@ -336,7 +402,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> {
}
}

pub struct AdjacentTargets<'g, N: 'g, E: 'g>
pub struct AdjacentTargets<'g, N, E>
where N: 'g,
E: 'g
{
Expand All @@ -351,7 +417,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentTargets<'g, N, E> {
}
}

pub struct AdjacentSources<'g, N: 'g, E: 'g>
pub struct AdjacentSources<'g, N, E>
where N: 'g,
E: 'g
{
Expand All @@ -366,7 +432,10 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentSources<'g, N, E> {
}
}

pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> {
pub struct DepthFirstTraversal<'g, N, E>
where N: 'g,
E: 'g
{
graph: &'g Graph<N, E>,
stack: Vec<NodeIndex>,
visited: BitVector,
Expand Down
46 changes: 42 additions & 4 deletions src/librustc_data_structures/graph/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ fn create_graph() -> TestGraph {

// Create a simple graph
//
// A -+> B --> C
// | | ^
// | v |
// F D --> E
// F
// |
// V
// A --> B --> C
// | ^
// v |
// D --> E

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

fn create_graph_with_cycle() -> TestGraph {
let mut graph = Graph::new();

// Create a graph with a cycle.
//
// A --> B <-- +
// | |
// v |
// C --> D

let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
let d = graph.add_node("D");

graph.add_edge(a, b, "AB");
graph.add_edge(b, c, "BC");
graph.add_edge(c, d, "CD");
graph.add_edge(d, b, "DB");

return graph;
}

#[test]
fn each_node() {
let graph = create_graph();
Expand Down Expand Up @@ -139,3 +165,15 @@ fn each_adjacent_from_d() {
let graph = create_graph();
test_adjacent_edges(&graph, NodeIndex(3), "D", &[("BD", "B")], &[("DE", "E")]);
}

#[test]
fn is_node_cyclic_a() {
let graph = create_graph_with_cycle();
assert!(!graph.is_node_cyclic(NodeIndex(0)));
}

#[test]
fn is_node_cyclic_b() {
let graph = create_graph_with_cycle();
assert!(graph.is_node_cyclic(NodeIndex(1)));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing newline at the end of the file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added newline.