Patchwork [8,of,9] dagop: make walk direction switchable so it can track descendants

login
register
mail settings
Submitter Yuya Nishihara
Date June 25, 2017, 3:26 a.m.
Message ID <c3d660d2185847c26885.1498361177@mimosa>
Download mbox | patch
Permalink /patch/21689/
State Accepted
Headers show

Comments

Yuya Nishihara - June 25, 2017, 3:26 a.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1498314903 -32400
#      Sat Jun 24 23:35:03 2017 +0900
# Node ID c3d660d2185847c26885b3467819c3c24ac769c6
# Parent  63b200dd478b6be7665d02c40a7c7ed62e2df6d1
dagop: make walk direction switchable so it can track descendants

  # ancestors(tip) using hg repo
  2) 0.068527
  3) 0.069097

Patch

diff --git a/mercurial/dagop.py b/mercurial/dagop.py
--- a/mercurial/dagop.py
+++ b/mercurial/dagop.py
@@ -23,10 +23,11 @@  generatorset = smartset.generatorset
 # possible maximum depth between null and wdir()
 _maxlogdepth = 0x80000000
 
-def _walkrevtree(pfunc, revs, startdepth, stopdepth):
+def _walkrevtree(pfunc, revs, startdepth, stopdepth, reverse):
     """Walk DAG using 'pfunc' from the given 'revs' nodes
 
-    'pfunc(rev)' should return the parent revisions of the given 'rev'.
+    'pfunc(rev)' should return the parent/child revisions of the given 'rev'
+    if 'reverse' is True/False respectively.
 
     Scan ends at the stopdepth (exlusive) if specified. Revisions found
     earlier than the startdepth are omitted.
@@ -39,25 +40,29 @@  def _walkrevtree(pfunc, revs, startdepth
         return
     if stopdepth < 0:
         raise error.ProgrammingError('negative stopdepth')
+    if reverse:
+        heapsign = -1  # max heap
+    else:
+        heapsign = +1  # min heap
 
     # load input revs lazily to heap so earlier revisions can be yielded
     # without fully computing the input revs
-    revs.sort(reverse=True)
+    revs.sort(reverse)
     irevs = iter(revs)
-    pendingheap = []  # [(-rev, depth), ...] (i.e. lower depth first)
+    pendingheap = []  # [(heapsign * rev, depth), ...] (i.e. lower depth first)
 
     inputrev = next(irevs, None)
     if inputrev is not None:
-        heapq.heappush(pendingheap, (-inputrev, 0))
+        heapq.heappush(pendingheap, (heapsign * inputrev, 0))
 
     lastrev = None
     while pendingheap:
         currev, curdepth = heapq.heappop(pendingheap)
-        currev = -currev
+        currev = heapsign * currev
         if currev == inputrev:
             inputrev = next(irevs, None)
             if inputrev is not None:
-                heapq.heappush(pendingheap, (-inputrev, 0))
+                heapq.heappush(pendingheap, (heapsign * inputrev, 0))
         # rescan parents until curdepth >= startdepth because queued entries
         # of the same revision are iterated from the lowest depth
         foundnew = (currev != lastrev)
@@ -68,7 +73,7 @@  def _walkrevtree(pfunc, revs, startdepth
         if foundnew and pdepth < stopdepth:
             for prev in pfunc(currev):
                 if prev != node.nullrev:
-                    heapq.heappush(pendingheap, (-prev, pdepth))
+                    heapq.heappush(pendingheap, (heapsign * prev, pdepth))
 
 def _genrevancestors(repo, revs, followfirst, startdepth, stopdepth):
     if followfirst:
@@ -81,7 +86,7 @@  def _genrevancestors(repo, revs, followf
             return cl.parentrevs(rev)[:cut]
         except error.WdirUnsupported:
             return (pctx.rev() for pctx in repo[rev].parents()[:cut])
-    return _walkrevtree(pfunc, revs, startdepth, stopdepth)
+    return _walkrevtree(pfunc, revs, startdepth, stopdepth, reverse=True)
 
 def revancestors(repo, revs, followfirst, startdepth=None, stopdepth=None):
     """Like revlog.ancestors(), but supports additional options, includes