revset: changed descendants revset to use lazy generators
authorLucas Moscovicz <lmoscovicz@fb.com>
Mon, 10 Feb 2014 12:26:45 -0800
changeset 20692 7af341082b76
parent 20691 c1f666e27345
child 20693 d04aac468bf4
revset: changed descendants revset to use lazy generators Performance Benchmarking: $ time hg log -qr "0:: and 0:5" ... real 0m3.665s user 0m3.364s sys 0m0.289s $ time ./hg log -qr "0:: and 0:5" ... real 0m0.492s user 0m0.394s sys 0m0.097s
mercurial/revset.py
--- a/mercurial/revset.py	Fri Feb 07 13:44:57 2014 -0800
+++ b/mercurial/revset.py	Mon Feb 10 12:26:45 2014 -0800
@@ -51,23 +51,26 @@
 def _revdescendants(repo, revs, followfirst):
     """Like revlog.descendants() but supports followfirst."""
     cut = followfirst and 1 or None
-    cl = repo.changelog
-    first = min(revs)
-    nullrev = node.nullrev
-    if first == nullrev:
-        # Are there nodes with a null first parent and a non-null
-        # second one? Maybe. Do we care? Probably not.
-        for i in cl:
-            yield i
-        return
 
-    seen = set(revs)
-    for i in cl.revs(first + 1):
-        for x in cl.parentrevs(i)[:cut]:
-            if x != nullrev and x in seen:
-                seen.add(i)
+    def iterate():
+        cl = repo.changelog
+        first = min(revs)
+        nullrev = node.nullrev
+        if first == nullrev:
+            # Are there nodes with a null first parent and a non-null
+            # second one? Maybe. Do we care? Probably not.
+            for i in cl:
                 yield i
-                break
+        else:
+            seen = set(revs)
+            for i in cl.revs(first + 1):
+                for x in cl.parentrevs(i)[:cut]:
+                    if x != nullrev and x in seen:
+                        seen.add(i)
+                        yield i
+                        break
+
+    return ascgeneratorset(iterate())
 
 def _revsbetween(repo, roots, heads):
     """Return all paths between roots and heads, inclusive of both endpoint
@@ -641,8 +644,9 @@
     args = getset(repo, spanset(repo), x)
     if not args:
         return baseset([])
-    s = set(_revdescendants(repo, args, followfirst)) | set(args)
-    return subset & s
+    s = _revdescendants(repo, args, followfirst)
+    a = set(args)
+    return subset.filter(lambda r: r in s or r in a)
 
 def descendants(repo, subset, x):
     """``descendants(set)``