Rev 4583: Implement KnownGraph.topo_sort. in http://bazaar.launchpad.net/~jameinel/bzr/1.18-topo_sort
John Arbash Meinel
john at arbash-meinel.com
Wed Aug 5 15:05:52 BST 2009
At http://bazaar.launchpad.net/~jameinel/bzr/1.18-topo_sort
------------------------------------------------------------
revno: 4583
revision-id: john at arbash-meinel.com-20090805140544-7prpni18c6dnlqnn
parent: john at arbash-meinel.com-20090805135409-njfyfwg41juu615d
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 1.18-topo_sort
timestamp: Wed 2009-08-05 09:05:44 -0500
message:
Implement KnownGraph.topo_sort.
This shows some pretty massive gains by having the 'num_children' information
be contained in the _KnownGraphNode.seen field.
Also, not having to do dict lookups to walk to parents and children.
-------------- next part --------------
=== modified file 'bzrlib/_known_graph_pyx.pyx'
--- a/bzrlib/_known_graph_pyx.pyx 2009-08-05 13:54:09 +0000
+++ b/bzrlib/_known_graph_pyx.pyx 2009-08-05 14:05:44 +0000
@@ -400,3 +400,49 @@
if self.do_cache:
PyDict_SetItem(self._known_heads, heads_key, heads)
return heads
+
+ def topo_sort(self):
+ """Return the nodes in topological order.
+
+ All parents must occur before all children.
+ """
+ # This is, for the most part, the same iteration order that we used for
+ # _find_gdfo, consider finding a way to remove the duplication
+ # In general, we find the 'tails' (nodes with no parents), and then
+ # walk to the children. For children that have all of their parents
+ # yielded, we queue up the child to be yielded as well.
+ cdef _KnownGraphNode node
+ cdef _KnownGraphNode child
+ cdef PyObject *temp
+ cdef Py_ssize_t pos
+ cdef int replace
+ cdef Py_ssize_t last_item
+
+ pending = self._find_tails()
+
+ topo_order = []
+
+ last_item = PyList_GET_SIZE(pending) - 1
+ while last_item >= 0:
+ # Avoid pop followed by push, instead, peek, and replace
+ # timing shows this is 930ms => 770ms for OOo
+ node = _get_list_node(pending, last_item)
+ PyList_Append(topo_order, node.key)
+ last_item = last_item - 1
+ for pos from 0 <= pos < PyList_GET_SIZE(node.children):
+ child = _get_list_node(node.children, pos)
+ child.seen = child.seen + 1
+ if child.seen == PyTuple_GET_SIZE(child.parents):
+ # All parents of this child have been yielded, queue this
+ # one to be yielded as well
+ last_item = last_item + 1
+ if last_item < PyList_GET_SIZE(pending):
+ Py_INCREF(child) # SetItem steals a ref
+ PyList_SetItem(pending, last_item, child)
+ else:
+ PyList_Append(pending, child)
+ # We have queued this node, we don't need to track it
+ # anymore
+ child.seen = 0
+ # We started from the parents, so we don't need to do anymore work
+ return topo_order
More information about the bazaar-commits
mailing list