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) |