Rev 4638: Move the topo_sort implementation into KnownGraph, rather than calling back to it. in http://bazaar.launchpad.net/~jameinel/bzr/1.19-known-graph-sorted

John Arbash Meinel john at arbash-meinel.com
Mon Aug 17 19:36:26 BST 2009


At http://bazaar.launchpad.net/~jameinel/bzr/1.19-known-graph-sorted

------------------------------------------------------------
revno: 4638
revision-id: john at arbash-meinel.com-20090817183614-ss5shqo00p002imm
parent: john at arbash-meinel.com-20090817181706-gm0g0k0ag9dnhowp
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 1.19-known-graph-sorted
timestamp: Mon 2009-08-17 13:36:14 -0500
message:
  Move the topo_sort implementation into KnownGraph, rather than calling back to it.
-------------- next part --------------
=== modified file 'bzrlib/_known_graph_py.py'
--- a/bzrlib/_known_graph_py.py	2009-08-17 16:35:07 +0000
+++ b/bzrlib/_known_graph_py.py	2009-08-17 18:36:14 +0000
@@ -18,6 +18,7 @@
 """
 
 from bzrlib import (
+    errors,
     revision,
     tsort,
     )
@@ -173,10 +174,38 @@
         return heads
 
     def topo_sort(self):
-        as_parent_map = dict((node.key, node.parent_keys)
-                             for node in self._nodes.itervalues()
-                              if node.parent_keys is not None)
-        return tsort.topo_sort(as_parent_map)
+        """Return the nodes in topological order.
+
+        All parents must occur before all children.
+        """
+        for node in self._nodes.itervalues():
+            if node.gdfo is None:
+                raise errors.GraphCycleError(self._nodes)
+        pending = self._find_tails()
+        pending_pop = pending.pop
+        pending_append = pending.append
+
+        topo_order = []
+        topo_order_append = topo_order.append
+
+        num_seen_parents = dict.fromkeys(self._nodes, 0)
+        while pending:
+            node = pending_pop()
+            if node.parent_keys is not None:
+                # We don't include ghost parents
+                topo_order_append(node.key)
+            for child_key in node.child_keys:
+                child_node = self._nodes[child_key]
+                seen_parents = num_seen_parents[child_key] + 1
+                if seen_parents == len(child_node.parent_keys):
+                    # All parents have been processed, enqueue this child
+                    pending_append(child_node)
+                    # This has been queued up, stop tracking it
+                    del num_seen_parents[child_key]
+                else:
+                    num_seen_parents[child_key] = seen_parents
+        # We started from the parents, so we don't need to do anymore work
+        return topo_order
 
     def merge_sort(self, tip_key):
         """Compute the merge sorted graph output."""

=== modified file 'bzrlib/graph.py'
--- a/bzrlib/graph.py	2009-08-04 04:36:34 +0000
+++ b/bzrlib/graph.py	2009-08-17 18:36:14 +0000
@@ -21,7 +21,6 @@
     errors,
     revision,
     trace,
-    tsort,
     )
 from bzrlib.symbol_versioning import deprecated_function, deprecated_in
 
@@ -926,6 +925,7 @@
         An ancestor may sort after a descendant if the relationship is not
         visible in the supplied list of revisions.
         """
+        from bzrlib import tsort
         sorter = tsort.TopoSorter(self.get_parent_map(revisions))
         return sorter.iter_topo_order()
 

=== modified file 'bzrlib/tsort.py'
--- a/bzrlib/tsort.py	2009-08-17 16:35:07 +0000
+++ b/bzrlib/tsort.py	2009-08-17 18:36:14 +0000
@@ -18,8 +18,11 @@
 """Topological sorting routines."""
 
 
-from bzrlib import errors
-import bzrlib.revision as _mod_revision
+from bzrlib import (
+    errors,
+    graph as _mod_graph,
+    revision as _mod_revision,
+    )
 from collections import deque
 
 
@@ -44,50 +47,8 @@
     topo_sort is faster when the whole list is needed, while when iterating
     over a part of the list, TopoSorter.iter_topo_order should be used.
     """
-    # store a dict of the graph.
-    graph = dict(graph)
-    # this is the stack storing on which the sorted nodes are pushed.
-    node_stack = []
-
-    # count the number of children for every node in the graph
-    node_child_count = dict.fromkeys(graph.iterkeys(), 0)
-    for parents in graph.itervalues():
-        for parent in parents:
-            # don't count the parent if it's a ghost
-            if parent in node_child_count:
-                node_child_count[parent] += 1
-    # keep track of nodes without children in a separate list
-    nochild_nodes = deque([node for (node, n) in node_child_count.iteritems()
-                                 if n == 0])
-
-    graph_pop = graph.pop
-    node_stack_append = node_stack.append
-    nochild_nodes_pop = nochild_nodes.pop
-    nochild_nodes_append = nochild_nodes.append
-
-    while nochild_nodes:
-        # pick a node without a child and add it to the stack.
-        node_name = nochild_nodes_pop()
-        node_stack_append(node_name)
-
-        # the parents of the node lose it as a child; if it was the last
-        # child, add the parent to the list of childless nodes.
-        parents = graph_pop(node_name)
-        for parent in parents:
-            if parent in node_child_count:
-                node_child_count[parent] -= 1
-                if node_child_count[parent] == 0:
-                    nochild_nodes_append(parent)
-
-    # if there are still nodes left in the graph,
-    # that means that there is a cycle
-    if graph:
-        raise errors.GraphCycleError(graph)
-
-    # the nodes where pushed on the stack child first, so this list needs to be
-    # reversed before returning it.
-    node_stack.reverse()
-    return node_stack
+    kg = _mod_graph.KnownGraph(graph)
+    return kg.topo_sort()
 
 
 class TopoSorter(object):



More information about the bazaar-commits mailing list