45
45
void Py_INCREF(object)
48
from bzrlib import revision
48
from bzrlib import errors, revision
50
50
cdef object NULL_REVISION
51
51
NULL_REVISION = revision.NULL_REVISION
55
cdef Py_ssize_t last_tip, pos
56
cdef PyObject *temp_key, *temp_value
59
# this is the stack storing on which the sorted nodes are pushed.
62
# count the number of children for every node in the graph
63
num_children = dict.fromkeys(graph.iterkeys(), 0)
65
while PyDict_Next(graph, &pos, NULL, &temp_value):
66
parents = <object>temp_value
67
for parent in parents: # pretty sure this is a tuple
68
temp_value = PyDict_GetItem(num_children, parent)
69
if temp_value != NULL: # Ignore ghosts
70
n = (<object>temp_value) + 1
71
PyDict_SetItem(num_children, parent, n)
72
# keep track of nodes without children in a separate list
75
while PyDict_Next(num_children, &pos, &temp_key, &temp_value):
76
value = <object>temp_value
78
node_name = <object>temp_key
79
PyList_Append(tips, node_name)
82
last_tip = len(tips) - 1
84
# pick a node without a child and add it to the stack.
85
temp_key = PyList_GET_ITEM(tips, last_tip)
86
node_name = <object>temp_key
88
PyList_Append(node_name_stack, node_name)
90
# the parents of the node lose it as a child; if it was the last
91
# child, add the parent to the list of childless nodes.
92
parents = graph_pop(node_name)
93
for parent in parents:
94
temp_value = PyDict_GetItem(num_children, parent)
95
if temp_value == NULL:
96
# Ghost parent, skip it
98
n = (<object>temp_value) - 1
99
PyDict_SetItem(num_children, parent, n)
102
if PyList_GET_SIZE(tips) > last_tip:
104
PyList_SetItem(tips, last_tip, parent)
106
PyList_Append(tips, parent)
108
# if there are still nodes left in the graph,
109
# that means that there is a cycle
111
raise errors.GraphCycleError(graph)
113
# the nodes where pushed on the stack child first, so this list needs to be
114
# reversed before returning it.
115
node_name_stack.reverse()
116
return node_name_stack
54
119
cdef class _KnownGraphNode:
55
120
"""Represents a single object in the known graph."""
339
404
def topo_sort(self):
340
cdef _KnownGraphNode node, parent
341
from bzrlib import tsort
343
for node in self._nodes.itervalues():
344
if node.parents is None:
347
for parent in node.parents:
348
parent_keys.append(parent.key)
349
as_parent_map[node.key] = parent_keys
350
return tsort.topo_sort(as_parent_map)
405
"""Return the nodes in topological order.
407
All parents must occur before all children.
409
# This is, for the most part, the same iteration order that we used for
410
# _find_gdfo, consider finding a way to remove the duplication
411
# In general, we find the 'tails' (nodes with no parents), and then
412
# walk to the children. For children that have all of their parents
413
# yielded, we queue up the child to be yielded as well.
414
cdef _KnownGraphNode node
415
cdef _KnownGraphNode child
419
cdef Py_ssize_t last_item
421
pending = self._find_tails()
422
if PyList_GET_SIZE(pending) == 0 and len(self._nodes) > 0:
423
raise errors.GraphCycleError(self._nodes)
427
last_item = PyList_GET_SIZE(pending) - 1
428
while last_item >= 0:
429
# Avoid pop followed by push, instead, peek, and replace
430
# timing shows this is 930ms => 770ms for OOo
431
node = _get_list_node(pending, last_item)
432
last_item = last_item - 1
433
if node.parents is not None:
434
# We don't include ghost parents
435
PyList_Append(topo_order, node.key)
436
for pos from 0 <= pos < PyList_GET_SIZE(node.children):
437
child = _get_list_node(node.children, pos)
439
# We know we have a graph cycle because a node has a parent
440
# which we couldn't find
441
raise errors.GraphCycleError(self._nodes)
442
child.seen = child.seen + 1
443
if child.seen == PyTuple_GET_SIZE(child.parents):
444
# All parents of this child have been yielded, queue this
445
# one to be yielded as well
446
last_item = last_item + 1
447
if last_item < PyList_GET_SIZE(pending):
448
Py_INCREF(child) # SetItem steals a ref
449
PyList_SetItem(pending, last_item, child)
451
PyList_Append(pending, child)
452
# We have queued this node, we don't need to track it
455
# We started from the parents, so we don't need to do anymore work