475
464
# Current performance numbers for merge_sort(bzr_dev_parent_map):
476
465
# 310ms tsort.merge_sort()
477
# 103ms graph.KnownGraph().merge_sort()
478
# 55ms kg.merge_sort()
466
# 92ms graph.KnownGraph().merge_sort()
467
# 42ms kg.merge_sort()
480
469
cdef KnownGraph graph
481
470
cdef object _depth_first_stack # list
482
471
cdef Py_ssize_t _last_stack_item # offset to last item on stack
483
cdef object _ms_nodes # dict of key => _MergeSortNode
472
# cdef object _ms_nodes # dict of key => _MergeSortNode
484
473
cdef object _revno_to_branch_count # {revno => num child branches}
485
474
cdef object _scheduled_nodes # List of nodes ready to be yielded
487
476
def __init__(self, known_graph, tip_key):
488
477
cdef _KnownGraphNode node
489
cdef _MergeSortNode ms_node
490
479
self.graph = known_graph
480
# self._ms_nodes = {}
492
481
self._revno_to_branch_count = {}
493
482
self._depth_first_stack = []
494
483
self._last_stack_item = -1
495
484
self._scheduled_nodes = []
496
485
if tip_key is not None and tip_key != NULL_REVISION:
497
486
node = self.graph._nodes[tip_key]
498
ms_node = self._get_or_create_node(node)
499
self._push_node(ms_node, 0)
487
self._push_node(node, 0)
501
489
cdef _MergeSortNode _get_or_create_node(self, _KnownGraphNode node):
502
490
cdef PyObject *temp_node
503
491
cdef _MergeSortNode ms_node
505
temp_node = PyDict_GetItem(self._ms_nodes, node.key)
506
if temp_node == NULL:
507
ms_node = _MergeSortNode(node)
508
PyDict_SetItem(self._ms_nodes, node.key, ms_node)
493
if node.extra is None:
494
ms_node = _MergeSortNode()
510
ms_node = <_MergeSortNode>temp_node
497
ms_node = <_MergeSortNode>node.extra
513
cdef _push_node(self, _MergeSortNode ms_node, Py_ssize_t merge_depth):
500
cdef _push_node(self, _KnownGraphNode node, Py_ssize_t merge_depth):
514
501
cdef _KnownGraphNode parent_node
515
cdef _MergeSortNode ms_parent_node
502
cdef _MergeSortNode ms_node, ms_parent_node
516
503
cdef Py_ssize_t pos
505
ms_node = self._get_or_create_node(node)
518
506
ms_node.merge_depth = merge_depth
519
if PyTuple_GET_SIZE(ms_node.node.parents) > 0:
520
parent_node = _get_parent(ms_node.node.parents, 0)
521
ms_node.left_ms_parent = self._get_or_create_node(
523
ms_node.left_pending_parent = ms_node.left_ms_parent
524
if PyTuple_GET_SIZE(ms_node.node.parents) > 1:
525
ms_node.pending_parents = []
526
for pos from 1 <= pos < PyTuple_GET_SIZE(ms_node.node.parents):
527
parent_node = _get_parent(ms_node.node.parents, pos)
528
PyList_Append(ms_node.pending_parents,
529
self._get_or_create_node(parent_node))
507
if PyTuple_GET_SIZE(node.parents) > 0:
508
parent_node = _get_parent(node.parents, 0)
509
ms_node.left_parent = parent_node
510
ms_node.left_pending_parent = parent_node
511
if PyTuple_GET_SIZE(node.parents) > 1:
512
ms_node.pending_parents = list(node.parents[1:])
513
# ms_node.pending_parents = []
514
# for pos from 1 <= pos < PyTuple_GET_SIZE(node.parents):
515
# parent_node = _get_parent(node.parents, pos)
516
# PyList_Append(ms_node.pending_parents, parent_node)
531
518
ms_node.is_first_child = 1
532
if ms_node.left_ms_parent is not None:
533
if ms_node.left_ms_parent.seen_by_child:
519
if ms_node.left_parent is not None:
520
ms_parent_node = self._get_or_create_node(ms_node.left_parent)
521
if ms_parent_node.seen_by_child:
534
522
ms_node.is_first_child = 0
535
ms_node.left_ms_parent.seen_by_child = 1
523
ms_parent_node.seen_by_child = 1
536
524
self._last_stack_item = self._last_stack_item + 1
537
525
if self._last_stack_item < PyList_GET_SIZE(self._depth_first_stack):
538
Py_INCREF(ms_node) # SetItem steals a ref
526
Py_INCREF(node) # SetItem steals a ref
539
527
PyList_SetItem(self._depth_first_stack, self._last_stack_item,
542
PyList_Append(self._depth_first_stack, ms_node)
530
PyList_Append(self._depth_first_stack, node)
543
531
# print 'pushed: %s' % (ms_node,)
545
533
cdef _pop_node(self):
546
534
cdef PyObject *temp
547
cdef _MergeSortNode ms_node
548
cdef _KnownGraphNode parent_node
535
cdef _MergeSortNode ms_node, ms_parent_node
536
cdef _KnownGraphNode node, parent_node
550
538
assert self._last_stack_item >= 0
551
ms_node = _get_ms_node(self._depth_first_stack, self._last_stack_item)
539
node = _get_list_node(self._depth_first_stack, self._last_stack_item)
540
ms_node = <_MergeSortNode>node.extra
552
541
self._last_stack_item = self._last_stack_item - 1
553
542
# print 'popping: %s' % (ms_node,)
554
if ms_node.left_ms_parent is not None:
543
if ms_node.left_parent is not None:
555
544
# Assign the revision number for *this* node, from its left-hand
546
ms_parent_node = <_MergeSortNode>ms_node.left_parent.extra
557
547
if ms_node.is_first_child:
558
548
# First child just increments the final digit
559
ms_node.revno_first = ms_node.left_ms_parent.revno_first
560
ms_node.revno_second = ms_node.left_ms_parent.revno_second
561
ms_node.revno_last = ms_node.left_ms_parent.revno_last + 1
549
ms_node.revno_first = ms_parent_node.revno_first
550
ms_node.revno_second = ms_parent_node.revno_second
551
ms_node.revno_last = ms_parent_node.revno_last + 1
563
553
# Not the first child, make a new branch
564
if ms_node.left_ms_parent.revno_first == -1:
554
if ms_parent_node.revno_first == -1:
565
555
# Mainline ancestor, the increment is on the last digit
566
base_revno = ms_node.left_ms_parent.revno_last
556
base_revno = ms_parent_node.revno_last
568
base_revno = ms_node.left_ms_parent.revno_first
558
base_revno = ms_parent_node.revno_first
569
559
temp = PyDict_GetItem(self._revno_to_branch_count,