revset: implemented set caching for revset evaluation
authorLucas Moscovicz <lmoscovicz@fb.com>
Wed, 22 Jan 2014 10:46:02 -0800
changeset 20365 bc770ee6a351
parent 20364 a6cf48b2880d
child 20366 5ec6321f49a9
revset: implemented set caching for revset evaluation Added set caching to the baseset class. It lazily builds the set whenever it's needed and keeps a reference which is returned when the set is requested instead of being built again.
mercurial/revset.py
--- a/mercurial/revset.py	Tue Jan 21 11:39:26 2014 -0800
+++ b/mercurial/revset.py	Wed Jan 22 10:46:02 2014 -0800
@@ -235,13 +235,13 @@
         r = range(m, n + 1)
     else:
         r = range(m, n - 1, -1)
-    s = set(subset)
+    s = subset.set()
     return baseset([x for x in r if x in s])
 
 def dagrange(repo, subset, x, y):
     r = baseset(repo)
     xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
-    s = set(subset)
+    s = subset.set()
     return baseset([r for r in xs if r in s])
 
 def andset(repo, subset, x, y):
@@ -249,12 +249,12 @@
 
 def orset(repo, subset, x, y):
     xl = getset(repo, subset, x)
-    s = set(xl)
-    yl = getset(repo, [r for r in subset if r not in s], y)
+    s = xl.set()
+    yl = getset(repo, baseset([r for r in subset if r not in s]), y)
     return baseset(xl + yl)
 
 def notset(repo, subset, x):
-    s = set(getset(repo, subset, x))
+    s = getset(repo, subset, x).set()
     return baseset([r for r in subset if r not in s])
 
 def listset(repo, subset, a, b):
@@ -312,7 +312,8 @@
     if not args:
         return baseset([])
     s = set(_revancestors(repo, args, followfirst)) | set(args)
-    return baseset([r for r in subset if r in s])
+    ss = subset.set()
+    return baseset([r for r in ss if r in s])
 
 def ancestors(repo, subset, x):
     """``ancestors(set)``
@@ -340,7 +341,8 @@
         for i in range(n):
             r = cl.parentrevs(r)[0]
         ps.add(r)
-    return baseset([r for r in subset if r in ps])
+    s = subset.set()
+    return baseset([r for r in s if r in ps])
 
 def author(repo, subset, x):
     """``author(string)``
@@ -367,7 +369,8 @@
     # i18n: "bisect" is a keyword
     status = getstring(x, _("bisect requires a string")).lower()
     state = set(hbisect.get(repo, status))
-    return baseset([r for r in subset if r in state])
+    s = subset.set()
+    return baseset([r for r in s if r in state])
 
 # Backward-compatibility
 # - no help entry so that we do not advertise it any more
@@ -406,11 +409,13 @@
             bmrevs = set()
             for bmrev in matchrevs:
                 bmrevs.add(repo[bmrev].rev())
-            return baseset([r for r in subset if r in bmrevs])
+            s = subset.set()
+            return baseset([r for r in s if r in bmrevs])
 
     bms = set([repo[r].rev()
                for r in repo._bookmarks.values()])
-    return baseset([r for r in subset if r in bms])
+    s = subset.set()
+    return baseset([r for r in s if r in bms])
 
 def branch(repo, subset, x):
     """``branch(string or set)``
@@ -440,7 +445,7 @@
     b = set()
     for r in s:
         b.add(repo[r].branch())
-    s = set(s)
+    s = s.set()
     return baseset([r for r in subset if r in s or repo[r].branch() in b])
 
 def bumped(repo, subset, x):
@@ -515,7 +520,7 @@
     """``children(set)``
     Child changesets of changesets in set.
     """
-    s = set(getset(repo, baseset(repo), x))
+    s = getset(repo, baseset(repo), x).set()
     cs = _children(repo, subset, s)
     return baseset([r for r in subset if r in cs])
 
@@ -605,7 +610,8 @@
     if not args:
         return baseset([])
     s = set(_revdescendants(repo, args, followfirst)) | set(args)
-    return baseset([r for r in subset if r in s])
+    ss = subset.set()
+    return baseset([r for r in ss if r in s])
 
 def descendants(repo, subset, x):
     """``descendants(set)``
@@ -625,9 +631,9 @@
     is the same as passing all().
     """
     if x is not None:
-        args = set(getset(repo, baseset(repo), x))
+        args = getset(repo, baseset(repo), x).set()
     else:
-        args = set(getall(repo, baseset(repo), x))
+        args = getall(repo, baseset(repo), x).set()
 
     dests = set()
 
@@ -745,7 +751,8 @@
                 for fr in fl:
                     s.add(fl.linkrev(fr))
 
-    return baseset([r for r in subset if r in s])
+    ss = subset.set()
+    return baseset([r for r in ss if r in s])
 
 def first(repo, subset, x):
     """``first(set, [n])``
@@ -768,7 +775,8 @@
     else:
         s = set(_revancestors(repo, [c.rev()], followfirst)) | set([c.rev()])
 
-    return baseset([r for r in subset if r in s])
+    ss = subset.set()
+    return baseset([r for r in ss if r in s])
 
 def follow(repo, subset, x):
     """``follow([file])``
@@ -897,14 +905,15 @@
     hs = set()
     for b, ls in repo.branchmap().iteritems():
         hs.update(repo[h].rev() for h in ls)
-    return baseset([r for r in subset if r in hs])
+    s = subset.set()
+    return baseset([r for r in s if r in hs])
 
 def heads(repo, subset, x):
     """``heads(set)``
     Members of set with no children in set.
     """
-    s = getset(repo, subset, x)
-    ps = set(parents(repo, subset, x))
+    s = getset(repo, subset, x).set()
+    ps = parents(repo, subset, x).set()
     return baseset([r for r in s if r not in ps])
 
 def hidden(repo, subset, x):
@@ -945,7 +954,7 @@
     except (TypeError, ValueError):
         # i18n: "limit" is a keyword
         raise error.ParseError(_("limit expects a number"))
-    ss = set(subset)
+    ss = subset.set()
     os = getset(repo, baseset(repo), l[0])[:lim]
     return baseset([r for r in os if r in ss])
 
@@ -963,7 +972,7 @@
     except (TypeError, ValueError):
         # i18n: "last" is a keyword
         raise error.ParseError(_("last expects a number"))
-    ss = set(subset)
+    ss = subset.set()
     os = getset(repo, baseset(repo), l[0])[-lim:]
     return baseset([r for r in os if r in ss])
 
@@ -1062,9 +1071,9 @@
     for the first operation is selected.
     """
     if x is not None:
-        args = set(getset(repo, baseset(repo), x))
+        args = getset(repo, baseset(repo), x).set()
     else:
-        args = set(getall(repo, baseset(repo), x))
+        args = getall(repo, baseset(repo), x).set()
 
     def _firstsrc(rev):
         src = _getrevsource(repo, rev)
@@ -1079,7 +1088,8 @@
             src = prev
 
     o = set([_firstsrc(r) for r in args])
-    return baseset([r for r in subset if r in o])
+    s = subset.set()
+    return baseset([r for r in s if r in o])
 
 def outgoing(repo, subset, x):
     """``outgoing([path])``
@@ -1102,7 +1112,8 @@
     repo.ui.popbuffer()
     cl = repo.changelog
     o = set([cl.rev(r) for r in outgoing.missing])
-    return baseset([r for r in subset if r in o])
+    s = subset.set()
+    return baseset([r for r in s if r in o])
 
 def p1(repo, subset, x):
     """``p1([set])``
@@ -1116,7 +1127,8 @@
     cl = repo.changelog
     for r in getset(repo, baseset(repo), x):
         ps.add(cl.parentrevs(r)[0])
-    return baseset([r for r in subset if r in ps])
+    s = subset.set()
+    return baseset([r for r in s if r in ps])
 
 def p2(repo, subset, x):
     """``p2([set])``
@@ -1134,7 +1146,8 @@
     cl = repo.changelog
     for r in getset(repo, baseset(repo), x):
         ps.add(cl.parentrevs(r)[1])
-    return baseset([r for r in subset if r in ps])
+    s = subset.set()
+    return baseset([r for r in s if r in ps])
 
 def parents(repo, subset, x):
     """``parents([set])``
@@ -1148,7 +1161,8 @@
     cl = repo.changelog
     for r in getset(repo, baseset(repo), x):
         ps.update(cl.parentrevs(r))
-    return baseset([r for r in subset if r in ps])
+    s = subset.set()
+    return baseset([r for r in s if r in ps])
 
 def parentspec(repo, subset, x, n):
     """``set^0``
@@ -1173,7 +1187,8 @@
             parents = cl.parentrevs(r)
             if len(parents) > 1:
                 ps.add(parents[1])
-    return baseset([r for r in subset if r in ps])
+    s = subset.set()
+    return baseset([r for r in s if r in ps])
 
 def present(repo, subset, x):
     """``present(set)``
@@ -1375,8 +1390,6 @@
     Reverse order of set.
     """
     l = getset(repo, subset, x)
-    if not isinstance(l, list):
-        l = baseset(l)
     l.reverse()
     return l
 
@@ -1384,7 +1397,7 @@
     """``roots(set)``
     Changesets in set with no parent changeset in set.
     """
-    s = set(getset(repo, baseset(repo.changelog), x))
+    s = getset(repo, baseset(repo.changelog), x).set()
     subset = baseset([r for r in subset if r in s])
     cs = _children(repo, subset, s)
     return baseset([r for r in subset if r not in cs])
@@ -1550,10 +1563,9 @@
     s = getstring(x, "internal error")
     if not s:
         return baseset([])
-    if not isinstance(subset, set):
-        subset = set(subset)
     ls = [repo[r].rev() for r in s.split('\0')]
-    return baseset([r for r in ls if r in subset])
+    s = subset.set()
+    return baseset([r for r in ls if r in s])
 
 symbols = {
     "adds": adds,
@@ -2048,7 +2060,14 @@
         return funcs
 
 class baseset(list):
-    pass
+    def __init__(self, data):
+        super(baseset, self).__init__(data)
+        self._set = None
+
+    def set(self):
+        if not self._set:
+            self._set = set(self)
+        return self._set
 
 # tell hggettext to extract docstrings from these functions:
 i18nfunctions = symbols.values()