# HG changeset patch # User Lucas Moscovicz # Date 2014-02-10 20:26:45 # Node ID 7af341082b7685641a65aa809a76d4e54bb35a98 # Parent c1f666e273451d3b184b4b14e5ce7ed532f50675 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 diff --git a/mercurial/revset.py b/mercurial/revset.py --- a/mercurial/revset.py +++ b/mercurial/revset.py @@ -51,23 +51,26 @@ def _revancestors(repo, revs, followfirs 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 @@ def _descendants(repo, subset, x, follow 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)``