Patchwork [1,of,4] revset: make generatorset.__nonzero__ lazy

login
register
mail settings
Submitter Pierre-Yves David
Date May 4, 2015, 10:25 p.m.
Message ID <78d36b8dfc8e5565b254.1430778352@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/8879/
State Accepted
Headers show

Comments

Pierre-Yves David - May 4, 2015, 10:25 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1430768208 25200
#      Mon May 04 12:36:48 2015 -0700
# Node ID 78d36b8dfc8e5565b2544a27a828953435435d6f
# Parent  e5b507efb36e2b9ad8edb1a38459d26c934d74dd
revset: make generatorset.__nonzero__ lazy

The 'for r in self:' call could trigger full consumption of the generator while
we only need a single value. We also fast path if a single value got already
computed. See inline comment for more details.

This provide massive speedup for lazy operation using boolean testing.

max(::tip)
e5b507efb36e) wall 0.055609 comb 0.060000 user 0.060000 sys 0.000000 (best of 100)
after change) wall 0.000109 comb 0.000000 user 0.000000 sys 0.000000 (best of 19146)

Patch

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -3140,11 +3140,16 @@  class generatorset(abstractsmartset):
             else:
                 self.fastdesc = self._iterator
                 self.__contains__ = self._desccontains
 
     def __nonzero__(self):
-        for r in self:
+        # Do not use 'for r in self' because it will enforce the iteration
+        # order (default ascending), possibly unrolling a whole descending
+        # iterator.
+        if self._genlist:
+            return True
+        for r in self._consumegen():
             return True
         return False
 
     def __contains__(self, x):
         if x in self._cache: