Mercurial > public > mercurial-scm > hg
comparison mercurial/revsetlang.py @ 41222:8aca89a694d4
revset: introduce an API that avoids `formatspec` input serialization
Instead of having the data fully serialized, the input can be directly inserted
in the tree at a later stage.
Just using it for simple "%ld" case provide a significant boost. For example
here are the impact on a sample discovery run between two pypy repositories
with arbitrary differences (using hg perfdiscovery).
$ hg perfdiscovery
before: ! wall 0.700435 comb 0.710000 user 0.700000 sys 0.010000 (median of 15)
after: ! wall 0.501305 comb 0.510000 user 0.490000 sys 0.020000 (median of 20)
author | Boris Feld <boris.feld@octobus.net> |
---|---|
date | Fri, 04 Jan 2019 13:41:21 +0100 |
parents | 73203cdfe3fe |
children | 26b0a7514f01 |
comparison
equal
deleted
inserted
replaced
41221:73203cdfe3fe | 41222:8aca89a694d4 |
---|---|
331 elif op == 'dagrangepost': | 331 elif op == 'dagrangepost': |
332 return _analyze(_build('descendants(_)', x[1])) | 332 return _analyze(_build('descendants(_)', x[1])) |
333 elif op == 'negate': | 333 elif op == 'negate': |
334 s = getstring(x[1], _("can't negate that")) | 334 s = getstring(x[1], _("can't negate that")) |
335 return _analyze(('string', '-' + s)) | 335 return _analyze(('string', '-' + s)) |
336 elif op in ('string', 'symbol'): | 336 elif op in ('string', 'symbol', 'smartset'): |
337 return x | 337 return x |
338 elif op == 'rangeall': | 338 elif op == 'rangeall': |
339 return (op, None) | 339 return (op, None) |
340 elif op in {'or', 'not', 'rangepre', 'rangepost', 'parentpost'}: | 340 elif op in {'or', 'not', 'rangepre', 'rangepost', 'parentpost'}: |
341 return (op, _analyze(x[1])) | 341 return (op, _analyze(x[1])) |
371 def _optimize(x): | 371 def _optimize(x): |
372 if x is None: | 372 if x is None: |
373 return 0, x | 373 return 0, x |
374 | 374 |
375 op = x[0] | 375 op = x[0] |
376 if op in ('string', 'symbol'): | 376 if op in ('string', 'symbol', 'smartset'): |
377 return 0.5, x # single revisions are small | 377 return 0.5, x # single revisions are small |
378 elif op == 'and': | 378 elif op == 'and': |
379 wa, ta = _optimize(x[1]) | 379 wa, ta = _optimize(x[1]) |
380 wb, tb = _optimize(x[2]) | 380 wb, tb = _optimize(x[2]) |
381 w = min(wa, wb) | 381 w = min(wa, wb) |
533 return tree | 533 return tree |
534 | 534 |
535 def foldconcat(tree): | 535 def foldconcat(tree): |
536 """Fold elements to be concatenated by `##` | 536 """Fold elements to be concatenated by `##` |
537 """ | 537 """ |
538 if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'): | 538 if (not isinstance(tree, tuple) |
539 or tree[0] in ('string', 'symbol', 'smartset')): | |
539 return tree | 540 return tree |
540 if tree[0] == '_concat': | 541 if tree[0] == '_concat': |
541 pending = [tree] | 542 pending = [tree] |
542 l = [] | 543 l = [] |
543 while pending: | 544 while pending: |
688 arg = sorted(arg) | 689 arg = sorted(arg) |
689 ret.append(_formatintlist(list(arg))) | 690 ret.append(_formatintlist(list(arg))) |
690 else: | 691 else: |
691 raise error.ProgrammingError("unknown revspec item type: %r" % t) | 692 raise error.ProgrammingError("unknown revspec item type: %r" % t) |
692 return b''.join(ret) | 693 return b''.join(ret) |
694 | |
695 def spectree(expr, *args): | |
696 """similar to formatspec but return a parsed and optimized tree""" | |
697 parsed = _parseargs(expr, args) | |
698 ret = [] | |
699 inputs = [] | |
700 for t, arg in parsed: | |
701 if t is None: | |
702 ret.append(arg) | |
703 elif t == 'baseset': | |
704 newtree = ('smartset', smartset.baseset(arg)) | |
705 inputs.append(newtree) | |
706 ret.append("$") | |
707 else: | |
708 raise error.ProgrammingError("unknown revspec item type: %r" % t) | |
709 expr = b''.join(ret) | |
710 tree = _parsewith(expr, syminitletters=_aliassyminitletters) | |
711 tree = parser.buildtree(tree, ('symbol', '$'), *inputs) | |
712 tree = foldconcat(tree) | |
713 tree = analyze(tree) | |
714 tree = optimize(tree) | |
715 return tree | |
693 | 716 |
694 def _parseargs(expr, args): | 717 def _parseargs(expr, args): |
695 """parse the expression and replace all inexpensive args | 718 """parse the expression and replace all inexpensive args |
696 | 719 |
697 return a list of tuple [(arg-type, arg-value)] | 720 return a list of tuple [(arg-type, arg-value)] |