Patchwork D452: revset: add an order-aware intersect helper function

login
register
mail settings
Submitter phabricator
Date Aug. 20, 2017, 7:58 p.m.
Message ID <1cc9fe84403dd92c9c8e0a225781f442@localhost.localdomain>
Download mbox | patch
Permalink /patch/23155/
State Not Applicable
Headers show

Comments

phabricator - Aug. 20, 2017, 7:58 p.m.
quark updated this revision to Diff 1109.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D452?vs=1104&id=1109

REVISION DETAIL
  https://phab.mercurial-scm.org/D452

AFFECTED FILES
  mercurial/revset.py
  tests/test-revset.t

CHANGE DETAILS




To: quark, #hg-reviewers
Cc: mercurial-devel

Patch

diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -1477,7 +1477,7 @@ 
   * set:
   <filteredset
     <spanset+ 0:2>,
-    <spanset+ 0:3>>
+    <spanset- 0:3>>
   0
   1
 
@@ -1978,7 +1978,7 @@ 
       <spanset- 0:4>,
       <spanset+ 0:4>>,
     <not
-      <spanset+ 1:3>>>
+      <spanset- 1:3>>>
   3
   0
 
@@ -2403,8 +2403,8 @@ 
         ('string', '0\x002\x001'))))
   * set:
   <filteredset
-    <spanset- 0:3>,
-    <baseset [1]>>
+    <baseset [1]>,
+    <spanset- 0:3>>
   1
 
  'A & B' can be rewritten as 'B & A' by weight. When ordering needs to be
@@ -2521,13 +2521,11 @@ 
             ('symbol', '2'))))))
   * set:
   <filteredset
-    <baseset [0, 2, 1]>,
-    <baseset+ [0, 1, 2]>>
+    <baseset+ [0, 1, 2]>,
+    <baseset [0, 2, 1]>>
   0
+  1
   2
-  1
-
- WRONG: should take dagrange order (0, 1, 2)
 
  'A + B' can be rewritten to 'B + A' by weight only when the order doesn't
  matter (e.g. 'X & (A + B)' can be 'X & (B + A)', but '(A + B) & X' can't):
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -57,6 +57,37 @@ 
         raise error.ParseError(_("missing argument"))
     return methods[x[0]](repo, subset, *x[1:], order=order)
 
+def intersect(subset, newset, order):
+    """intersect two revsets with order preserved as requested
+
+    If order is "followorder", preserve subset's order. If order is
+    "defineorder", preserve newset's order.
+
+    A typical use of this function is::
+
+        @revsetpredicate('myrevset', takeorder=True)
+        def myrevset(repo, subset, x, order):
+            newset = ...  # a smartset that implements "myrevset"
+            return revset.intersect(subset, newset, order)
+    """
+    # ordering does not matter if there are at most 1 revision (test quickly)
+    if isinstance(newset, baseset) and len(newset) <= 1:
+        return newset & subset
+
+    # "defineorder" by an unordered set is bad, enforce "followorder"
+    if not util.safehasattr(newset, 'isascending'):
+        return subset & newset
+
+    if order == followorder:
+        return subset & newset
+    elif order == defineorder:
+        return newset & subset
+
+    assert order == anyorder
+
+    # newset is usually smaller, prefer it on the left
+    return newset & subset
+
 def _getrevsource(repo, r):
     extra = repo[r].extra()
     for label in ('source', 'transplant_source', 'rebase_source'):
@@ -113,17 +144,13 @@ 
     else:
         r = spanset(repo, m, n - 1)
 
-    if order == defineorder:
-        return r & subset
-    else:
-        # carrying the sorting over when possible would be more efficient
-        return subset & r
+    return intersect(subset, r, order)
 
 def dagrange(repo, subset, x, y, order):
     r = fullreposet(repo)
     xs = dagop.reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
                               includepath=True)
-    return subset & xs
+    return intersect(subset, xs, order)
 
 def andset(repo, subset, x, y, order):
     if order == anyorder:
@@ -1143,9 +1170,7 @@ 
         raise error.ParseError(_("negative offset"))
     os = getset(repo, fullreposet(repo), args['set'], defineorder)
     ls = os.slice(ofs, ofs + lim)
-    if order == followorder and lim > 1:
-        return subset & ls
-    return ls & subset
+    return intersect(subset, ls, order)
 
 @predicate('last(set, [n])', safe=True, takeorder=True)
 def last(repo, subset, x, order):
@@ -1162,10 +1187,8 @@ 
     os = getset(repo, fullreposet(repo), l[0], defineorder)
     os.reverse()
     ls = os.slice(0, lim)
-    if order == followorder and lim > 1:
-        return subset & ls
     ls.reverse()
-    return ls & subset
+    return intersect(subset, ls, order)
 
 @predicate('max(set)', safe=True)
 def maxrev(repo, subset, x):
@@ -1523,7 +1546,7 @@ 
                 parents = repo[r].parents()
                 if len(parents) == 2:
                     ps.add(parents[1].rev())
-    return subset & ps
+    return intersect(subset, ps, order)
 
 @predicate('present(set)', safe=True, takeorder=True)
 def present(repo, subset, x, order):