mercurial/revset.py
changeset 29932 09a84e747c88
parent 29931 d2d1be3009ca
child 29933 91a95ad985d8
equal deleted inserted replaced
29931:d2d1be3009ca 29932:09a84e747c88
   358     if (x in subset
   358     if (x in subset
   359         or x == node.nullrev and isinstance(subset, fullreposet)):
   359         or x == node.nullrev and isinstance(subset, fullreposet)):
   360         return baseset([x])
   360         return baseset([x])
   361     return baseset()
   361     return baseset()
   362 
   362 
   363 def rangeset(repo, subset, x, y):
   363 def rangeset(repo, subset, x, y, order):
   364     m = getset(repo, fullreposet(repo), x)
   364     m = getset(repo, fullreposet(repo), x)
   365     n = getset(repo, fullreposet(repo), y)
   365     n = getset(repo, fullreposet(repo), y)
   366 
   366 
   367     if not m or not n:
   367     if not m or not n:
   368         return baseset()
   368         return baseset()
   383     #
   383     #
   384     # This has performance implication, carrying the sorting over when possible
   384     # This has performance implication, carrying the sorting over when possible
   385     # would be more efficient.
   385     # would be more efficient.
   386     return r & subset
   386     return r & subset
   387 
   387 
   388 def dagrange(repo, subset, x, y):
   388 def dagrange(repo, subset, x, y, order):
   389     r = fullreposet(repo)
   389     r = fullreposet(repo)
   390     xs = reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
   390     xs = reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
   391                          includepath=True)
   391                          includepath=True)
   392     return subset & xs
   392     return subset & xs
   393 
   393 
   394 def andset(repo, subset, x, y):
   394 def andset(repo, subset, x, y, order):
   395     return getset(repo, getset(repo, subset, x), y)
   395     return getset(repo, getset(repo, subset, x), y)
   396 
   396 
   397 def differenceset(repo, subset, x, y):
   397 def differenceset(repo, subset, x, y, order):
   398     return getset(repo, subset, x) - getset(repo, subset, y)
   398     return getset(repo, subset, x) - getset(repo, subset, y)
   399 
   399 
   400 def _orsetlist(repo, subset, xs):
   400 def _orsetlist(repo, subset, xs):
   401     assert xs
   401     assert xs
   402     if len(xs) == 1:
   402     if len(xs) == 1:
   404     p = len(xs) // 2
   404     p = len(xs) // 2
   405     a = _orsetlist(repo, subset, xs[:p])
   405     a = _orsetlist(repo, subset, xs[:p])
   406     b = _orsetlist(repo, subset, xs[p:])
   406     b = _orsetlist(repo, subset, xs[p:])
   407     return a + b
   407     return a + b
   408 
   408 
   409 def orset(repo, subset, x):
   409 def orset(repo, subset, x, order):
   410     return _orsetlist(repo, subset, getlist(x))
   410     return _orsetlist(repo, subset, getlist(x))
   411 
   411 
   412 def notset(repo, subset, x):
   412 def notset(repo, subset, x, order):
   413     return subset - getset(repo, subset, x)
   413     return subset - getset(repo, subset, x)
   414 
   414 
   415 def listset(repo, subset, *xs):
   415 def listset(repo, subset, *xs):
   416     raise error.ParseError(_("can't use a list in this context"),
   416     raise error.ParseError(_("can't use a list in this context"),
   417                            hint=_('see hg help "revsets.x or y"'))
   417                            hint=_('see hg help "revsets.x or y"'))
   418 
   418 
   419 def keyvaluepair(repo, subset, k, v):
   419 def keyvaluepair(repo, subset, k, v):
   420     raise error.ParseError(_("can't use a key-value pair in this context"))
   420     raise error.ParseError(_("can't use a key-value pair in this context"))
   421 
   421 
   422 def func(repo, subset, a, b):
   422 def func(repo, subset, a, b, order):
   423     f = getsymbol(a)
   423     f = getsymbol(a)
   424     if f in symbols:
   424     if f in symbols:
   425         return symbols[f](repo, subset, b)
   425         return symbols[f](repo, subset, b)
   426 
   426 
   427     keep = lambda fn: getattr(fn, '__doc__', None) is not None
   427     keep = lambda fn: getattr(fn, '__doc__', None) is not None
   514 def _firstancestors(repo, subset, x):
   514 def _firstancestors(repo, subset, x):
   515     # ``_firstancestors(set)``
   515     # ``_firstancestors(set)``
   516     # Like ``ancestors(set)`` but follows only the first parents.
   516     # Like ``ancestors(set)`` but follows only the first parents.
   517     return _ancestors(repo, subset, x, followfirst=True)
   517     return _ancestors(repo, subset, x, followfirst=True)
   518 
   518 
   519 def ancestorspec(repo, subset, x, n):
   519 def ancestorspec(repo, subset, x, n, order):
   520     """``set~n``
   520     """``set~n``
   521     Changesets that are the Nth ancestor (first parents only) of a changeset
   521     Changesets that are the Nth ancestor (first parents only) of a changeset
   522     in set.
   522     in set.
   523     """
   523     """
   524     try:
   524     try:
  1526     ps -= set([node.nullrev])
  1526     ps -= set([node.nullrev])
  1527     # XXX we should turn this into a baseset instead of a set, smartset may do
  1527     # XXX we should turn this into a baseset instead of a set, smartset may do
  1528     # some optimisations from the fact this is a baseset.
  1528     # some optimisations from the fact this is a baseset.
  1529     return subset & ps
  1529     return subset & ps
  1530 
  1530 
  1531 def parentpost(repo, subset, x):
  1531 def parentpost(repo, subset, x, order):
  1532     return p1(repo, subset, x)
  1532     return p1(repo, subset, x)
  1533 
  1533 
  1534 @predicate('parents([set])', safe=True)
  1534 @predicate('parents([set])', safe=True)
  1535 def parents(repo, subset, x):
  1535 def parents(repo, subset, x):
  1536     """
  1536     """
  1579     # i18n: "secret" is a keyword
  1579     # i18n: "secret" is a keyword
  1580     getargs(x, 0, 0, _("secret takes no arguments"))
  1580     getargs(x, 0, 0, _("secret takes no arguments"))
  1581     target = phases.secret
  1581     target = phases.secret
  1582     return _phase(repo, subset, target)
  1582     return _phase(repo, subset, target)
  1583 
  1583 
  1584 def parentspec(repo, subset, x, n):
  1584 def parentspec(repo, subset, x, n, order):
  1585     """``set^0``
  1585     """``set^0``
  1586     The set.
  1586     The set.
  1587     ``set^1`` (or ``set^``), ``set^2``
  1587     ``set^1`` (or ``set^``), ``set^2``
  1588     First or second parent, respectively, of all changesets in set.
  1588     First or second parent, respectively, of all changesets in set.
  1589     """
  1589     """
  2424     elif op in ('string', 'symbol'):
  2424     elif op in ('string', 'symbol'):
  2425         return x
  2425         return x
  2426     elif op == 'and':
  2426     elif op == 'and':
  2427         ta = _analyze(x[1], order)
  2427         ta = _analyze(x[1], order)
  2428         tb = _analyze(x[2], _tofolloworder[order])
  2428         tb = _analyze(x[2], _tofolloworder[order])
  2429         return (op, ta, tb)
  2429         return (op, ta, tb, order)
  2430     elif op == 'or':
  2430     elif op == 'or':
  2431         return (op, _analyze(x[1], order))
  2431         return (op, _analyze(x[1], order), order)
  2432     elif op == 'not':
  2432     elif op == 'not':
  2433         return (op, _analyze(x[1], anyorder))
  2433         return (op, _analyze(x[1], anyorder), order)
  2434     elif op == 'parentpost':
  2434     elif op == 'parentpost':
  2435         return (op, _analyze(x[1], defineorder))
  2435         return (op, _analyze(x[1], defineorder), order)
  2436     elif op == 'group':
  2436     elif op == 'group':
  2437         return _analyze(x[1], order)
  2437         return _analyze(x[1], order)
  2438     elif op in ('dagrange', 'range', 'parent', 'ancestor'):
  2438     elif op in ('dagrange', 'range', 'parent', 'ancestor'):
  2439         ta = _analyze(x[1], defineorder)
  2439         ta = _analyze(x[1], defineorder)
  2440         tb = _analyze(x[2], defineorder)
  2440         tb = _analyze(x[2], defineorder)
  2441         return (op, ta, tb)
  2441         return (op, ta, tb, order)
  2442     elif op == 'list':
  2442     elif op == 'list':
  2443         return (op,) + tuple(_analyze(y, order) for y in x[1:])
  2443         return (op,) + tuple(_analyze(y, order) for y in x[1:])
  2444     elif op == 'keyvalue':
  2444     elif op == 'keyvalue':
  2445         return (op, x[1], _analyze(x[2], order))
  2445         return (op, x[1], _analyze(x[2], order))
  2446     elif op == 'func':
  2446     elif op == 'func':
  2447         return (op, x[1], _analyze(x[2], defineorder))
  2447         return (op, x[1], _analyze(x[2], defineorder), order)
  2448     raise ValueError('invalid operator %r' % op)
  2448     raise ValueError('invalid operator %r' % op)
  2449 
  2449 
  2450 def analyze(x, order=defineorder):
  2450 def analyze(x, order=defineorder):
  2451     """Transform raw parsed tree to evaluatable tree which can be fed to
  2451     """Transform raw parsed tree to evaluatable tree which can be fed to
  2452     optimize() or getset()
  2452     optimize() or getset()
  2471     if op in ('string', 'symbol'):
  2471     if op in ('string', 'symbol'):
  2472         return smallbonus, x # single revisions are small
  2472         return smallbonus, x # single revisions are small
  2473     elif op == 'and':
  2473     elif op == 'and':
  2474         wa, ta = _optimize(x[1], True)
  2474         wa, ta = _optimize(x[1], True)
  2475         wb, tb = _optimize(x[2], True)
  2475         wb, tb = _optimize(x[2], True)
       
  2476         order = x[3]
  2476         w = min(wa, wb)
  2477         w = min(wa, wb)
  2477 
  2478 
  2478         # (::x and not ::y)/(not ::y and ::x) have a fast path
  2479         # (::x and not ::y)/(not ::y and ::x) have a fast path
  2479         tm = _matchonly(ta, tb) or _matchonly(tb, ta)
  2480         tm = _matchonly(ta, tb) or _matchonly(tb, ta)
  2480         if tm:
  2481         if tm:
  2481             return w, ('func', ('symbol', 'only'), tm)
  2482             return w, ('func', ('symbol', 'only'), tm, order)
  2482 
  2483 
  2483         if tb is not None and tb[0] == 'not':
  2484         if tb is not None and tb[0] == 'not':
  2484             return wa, ('difference', ta, tb[1])
  2485             return wa, ('difference', ta, tb[1], order)
  2485 
  2486 
  2486         if wa > wb:
  2487         if wa > wb:
  2487             return w, (op, tb, ta)
  2488             return w, (op, tb, ta, order)
  2488         return w, (op, ta, tb)
  2489         return w, (op, ta, tb, order)
  2489     elif op == 'or':
  2490     elif op == 'or':
  2490         # fast path for machine-generated expression, that is likely to have
  2491         # fast path for machine-generated expression, that is likely to have
  2491         # lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()'
  2492         # lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()'
       
  2493         order = x[2]
  2492         ws, ts, ss = [], [], []
  2494         ws, ts, ss = [], [], []
  2493         def flushss():
  2495         def flushss():
  2494             if not ss:
  2496             if not ss:
  2495                 return
  2497                 return
  2496             if len(ss) == 1:
  2498             if len(ss) == 1:
  2497                 w, t = ss[0]
  2499                 w, t = ss[0]
  2498             else:
  2500             else:
  2499                 s = '\0'.join(t[1] for w, t in ss)
  2501                 s = '\0'.join(t[1] for w, t in ss)
  2500                 y = ('func', ('symbol', '_list'), ('string', s))
  2502                 y = ('func', ('symbol', '_list'), ('string', s), order)
  2501                 w, t = _optimize(y, False)
  2503                 w, t = _optimize(y, False)
  2502             ws.append(w)
  2504             ws.append(w)
  2503             ts.append(t)
  2505             ts.append(t)
  2504             del ss[:]
  2506             del ss[:]
  2505         for y in getlist(x[1]):
  2507         for y in getlist(x[1]):
  2514         if len(ts) == 1:
  2516         if len(ts) == 1:
  2515             return ws[0], ts[0] # 'or' operation is fully optimized out
  2517             return ws[0], ts[0] # 'or' operation is fully optimized out
  2516         # we can't reorder trees by weight because it would change the order.
  2518         # we can't reorder trees by weight because it would change the order.
  2517         # ("sort(a + b)" == "sort(b + a)", but "a + b" != "b + a")
  2519         # ("sort(a + b)" == "sort(b + a)", but "a + b" != "b + a")
  2518         #   ts = tuple(t for w, t in sorted(zip(ws, ts), key=lambda wt: wt[0]))
  2520         #   ts = tuple(t for w, t in sorted(zip(ws, ts), key=lambda wt: wt[0]))
  2519         return max(ws), (op, ('list',) + tuple(ts))
  2521         return max(ws), (op, ('list',) + tuple(ts), order)
  2520     elif op == 'not':
  2522     elif op == 'not':
  2521         # Optimize not public() to _notpublic() because we have a fast version
  2523         # Optimize not public() to _notpublic() because we have a fast version
  2522         if x[1] == ('func', ('symbol', 'public'), None):
  2524         if x[1][:3] == ('func', ('symbol', 'public'), None):
  2523             newsym = ('func', ('symbol', '_notpublic'), None)
  2525             order = x[1][3]
       
  2526             newsym = ('func', ('symbol', '_notpublic'), None, order)
  2524             o = _optimize(newsym, not small)
  2527             o = _optimize(newsym, not small)
  2525             return o[0], o[1]
  2528             return o[0], o[1]
  2526         else:
  2529         else:
  2527             o = _optimize(x[1], not small)
  2530             o = _optimize(x[1], not small)
  2528             return o[0], (op, o[1])
  2531             order = x[2]
       
  2532             return o[0], (op, o[1], order)
  2529     elif op == 'parentpost':
  2533     elif op == 'parentpost':
  2530         o = _optimize(x[1], small)
  2534         o = _optimize(x[1], small)
  2531         return o[0], (op, o[1])
  2535         order = x[2]
       
  2536         return o[0], (op, o[1], order)
  2532     elif op in ('dagrange', 'range', 'parent', 'ancestor'):
  2537     elif op in ('dagrange', 'range', 'parent', 'ancestor'):
  2533         wa, ta = _optimize(x[1], small)
  2538         wa, ta = _optimize(x[1], small)
  2534         wb, tb = _optimize(x[2], small)
  2539         wb, tb = _optimize(x[2], small)
  2535         return wa + wb, (op, ta, tb)
  2540         order = x[3]
       
  2541         return wa + wb, (op, ta, tb, order)
  2536     elif op == 'list':
  2542     elif op == 'list':
  2537         ws, ts = zip(*(_optimize(y, small) for y in x[1:]))
  2543         ws, ts = zip(*(_optimize(y, small) for y in x[1:]))
  2538         return sum(ws), (op,) + ts
  2544         return sum(ws), (op,) + ts
  2539     elif op == 'keyvalue':
  2545     elif op == 'keyvalue':
  2540         w, t = _optimize(x[2], small)
  2546         w, t = _optimize(x[2], small)
  2555             w = 0
  2561             w = 0
  2556         elif f == "sort":
  2562         elif f == "sort":
  2557             w = 10 # assume most sorts look at changelog
  2563             w = 10 # assume most sorts look at changelog
  2558         else:
  2564         else:
  2559             w = 1
  2565             w = 1
  2560         return w + wa, (op, x[1], ta)
  2566         order = x[3]
       
  2567         return w + wa, (op, x[1], ta, order)
  2561     raise ValueError('invalid operator %r' % op)
  2568     raise ValueError('invalid operator %r' % op)
  2562 
  2569 
  2563 def optimize(tree):
  2570 def optimize(tree):
  2564     """Optimize evaluatable tree
  2571     """Optimize evaluatable tree
  2565 
  2572