Bug 1383880: add Graph.visit_preorder; r=ahal

MozReview-Commit-ID: BWGqLUuWlN9

--HG--
extra : rebase_source : 84321e62d789faa7972ac92486e9831684f7d50d
This commit is contained in:
Dustin J. Mitchell 2017-08-20 16:29:12 +00:00
parent 7e084ff0ae
commit 553b0d0e71
2 changed files with 44 additions and 9 deletions

View File

@ -78,16 +78,9 @@ class Graph(object):
new_edges = edges | add_edges
return Graph(new_nodes, new_edges)
def visit_postorder(self):
"""
Generate a sequence of nodes in postorder, such that every node is
visited *after* any nodes it links to.
Behavior is undefined (read: it will hang) if the graph contains a
cycle.
"""
def _visit(self, reverse):
queue = collections.deque(sorted(self.nodes))
links_by_node = self.links_dict()
links_by_node = self.reverse_links_dict() if reverse else self.links_dict()
seen = set()
while queue:
node = queue.popleft()
@ -101,6 +94,23 @@ class Graph(object):
queue.extend(n for n in links if n not in seen)
queue.append(node)
def visit_postorder(self):
"""
Generate a sequence of nodes in postorder, such that every node is
visited *after* any nodes it links to.
Behavior is undefined (read: it will hang) if the graph contains a
cycle.
"""
return self._visit(False)
def visit_preorder(self):
"""
Like visit_postorder, but in reverse: evrey node is visited *before*
any nodes it links to.
"""
return self._visit(True)
def links_dict(self):
"""
Return a dictionary mapping each node to a set of the nodes it links to

View File

@ -129,6 +129,31 @@ class TestGraph(unittest.TestCase):
"postorder visit of a disjoint graph satisfies invariant"
self.assert_postorder(self.disjoint.visit_postorder(), self.disjoint.nodes)
def assert_preorder(self, seq, all_nodes):
seen = set()
for e in seq:
for l, r, n in self.tree.edges:
if r == e:
self.failUnless(l in seen)
seen.add(e)
self.assertEqual(seen, all_nodes)
def test_visit_preorder_tree(self):
"preorder visit of a tree satisfies invariant"
self.assert_preorder(self.tree.visit_preorder(), self.tree.nodes)
def test_visit_preorder_diamonds(self):
"preorder visit of a graph full of diamonds satisfies invariant"
self.assert_preorder(self.diamonds.visit_preorder(), self.diamonds.nodes)
def test_visit_preorder_multi_edges(self):
"preorder visit of a graph with duplicate edges satisfies invariant"
self.assert_preorder(self.multi_edges.visit_preorder(), self.multi_edges.nodes)
def test_visit_preorder_disjoint(self):
"preorder visit of a disjoint graph satisfies invariant"
self.assert_preorder(self.disjoint.visit_preorder(), self.disjoint.nodes)
def test_links_dict(self):
"link dict for a graph with multiple edges is correct"
self.assertEqual(self.multi_edges.links_dict(), {