Mercurial > public > mercurial-scm > hg
comparison mercurial/revset.py @ 20365:bc770ee6a351
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.
author | Lucas Moscovicz <lmoscovicz@fb.com> |
---|---|
date | Wed, 22 Jan 2014 10:46:02 -0800 |
parents | a6cf48b2880d |
children | 5ec6321f49a9 |
comparison
equal
deleted
inserted
replaced
20364:a6cf48b2880d | 20365:bc770ee6a351 |
---|---|
233 | 233 |
234 if m < n: | 234 if m < n: |
235 r = range(m, n + 1) | 235 r = range(m, n + 1) |
236 else: | 236 else: |
237 r = range(m, n - 1, -1) | 237 r = range(m, n - 1, -1) |
238 s = set(subset) | 238 s = subset.set() |
239 return baseset([x for x in r if x in s]) | 239 return baseset([x for x in r if x in s]) |
240 | 240 |
241 def dagrange(repo, subset, x, y): | 241 def dagrange(repo, subset, x, y): |
242 r = baseset(repo) | 242 r = baseset(repo) |
243 xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y)) | 243 xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y)) |
244 s = set(subset) | 244 s = subset.set() |
245 return baseset([r for r in xs if r in s]) | 245 return baseset([r for r in xs if r in s]) |
246 | 246 |
247 def andset(repo, subset, x, y): | 247 def andset(repo, subset, x, y): |
248 return getset(repo, getset(repo, subset, x), y) | 248 return getset(repo, getset(repo, subset, x), y) |
249 | 249 |
250 def orset(repo, subset, x, y): | 250 def orset(repo, subset, x, y): |
251 xl = getset(repo, subset, x) | 251 xl = getset(repo, subset, x) |
252 s = set(xl) | 252 s = xl.set() |
253 yl = getset(repo, [r for r in subset if r not in s], y) | 253 yl = getset(repo, baseset([r for r in subset if r not in s]), y) |
254 return baseset(xl + yl) | 254 return baseset(xl + yl) |
255 | 255 |
256 def notset(repo, subset, x): | 256 def notset(repo, subset, x): |
257 s = set(getset(repo, subset, x)) | 257 s = getset(repo, subset, x).set() |
258 return baseset([r for r in subset if r not in s]) | 258 return baseset([r for r in subset if r not in s]) |
259 | 259 |
260 def listset(repo, subset, a, b): | 260 def listset(repo, subset, a, b): |
261 raise error.ParseError(_("can't use a list in this context")) | 261 raise error.ParseError(_("can't use a list in this context")) |
262 | 262 |
310 def _ancestors(repo, subset, x, followfirst=False): | 310 def _ancestors(repo, subset, x, followfirst=False): |
311 args = getset(repo, baseset(repo), x) | 311 args = getset(repo, baseset(repo), x) |
312 if not args: | 312 if not args: |
313 return baseset([]) | 313 return baseset([]) |
314 s = set(_revancestors(repo, args, followfirst)) | set(args) | 314 s = set(_revancestors(repo, args, followfirst)) | set(args) |
315 return baseset([r for r in subset if r in s]) | 315 ss = subset.set() |
316 return baseset([r for r in ss if r in s]) | |
316 | 317 |
317 def ancestors(repo, subset, x): | 318 def ancestors(repo, subset, x): |
318 """``ancestors(set)`` | 319 """``ancestors(set)`` |
319 Changesets that are ancestors of a changeset in set. | 320 Changesets that are ancestors of a changeset in set. |
320 """ | 321 """ |
338 cl = repo.changelog | 339 cl = repo.changelog |
339 for r in getset(repo, cl, x): | 340 for r in getset(repo, cl, x): |
340 for i in range(n): | 341 for i in range(n): |
341 r = cl.parentrevs(r)[0] | 342 r = cl.parentrevs(r)[0] |
342 ps.add(r) | 343 ps.add(r) |
343 return baseset([r for r in subset if r in ps]) | 344 s = subset.set() |
345 return baseset([r for r in s if r in ps]) | |
344 | 346 |
345 def author(repo, subset, x): | 347 def author(repo, subset, x): |
346 """``author(string)`` | 348 """``author(string)`` |
347 Alias for ``user(string)``. | 349 Alias for ``user(string)``. |
348 """ | 350 """ |
365 - ``current`` : the cset currently being bisected | 367 - ``current`` : the cset currently being bisected |
366 """ | 368 """ |
367 # i18n: "bisect" is a keyword | 369 # i18n: "bisect" is a keyword |
368 status = getstring(x, _("bisect requires a string")).lower() | 370 status = getstring(x, _("bisect requires a string")).lower() |
369 state = set(hbisect.get(repo, status)) | 371 state = set(hbisect.get(repo, status)) |
370 return baseset([r for r in subset if r in state]) | 372 s = subset.set() |
373 return baseset([r for r in s if r in state]) | |
371 | 374 |
372 # Backward-compatibility | 375 # Backward-compatibility |
373 # - no help entry so that we do not advertise it any more | 376 # - no help entry so that we do not advertise it any more |
374 def bisected(repo, subset, x): | 377 def bisected(repo, subset, x): |
375 return bisect(repo, subset, x) | 378 return bisect(repo, subset, x) |
404 raise util.Abort(_("no bookmarks exist that match '%s'") | 407 raise util.Abort(_("no bookmarks exist that match '%s'") |
405 % pattern) | 408 % pattern) |
406 bmrevs = set() | 409 bmrevs = set() |
407 for bmrev in matchrevs: | 410 for bmrev in matchrevs: |
408 bmrevs.add(repo[bmrev].rev()) | 411 bmrevs.add(repo[bmrev].rev()) |
409 return baseset([r for r in subset if r in bmrevs]) | 412 s = subset.set() |
413 return baseset([r for r in s if r in bmrevs]) | |
410 | 414 |
411 bms = set([repo[r].rev() | 415 bms = set([repo[r].rev() |
412 for r in repo._bookmarks.values()]) | 416 for r in repo._bookmarks.values()]) |
413 return baseset([r for r in subset if r in bms]) | 417 s = subset.set() |
418 return baseset([r for r in s if r in bms]) | |
414 | 419 |
415 def branch(repo, subset, x): | 420 def branch(repo, subset, x): |
416 """``branch(string or set)`` | 421 """``branch(string or set)`` |
417 All changesets belonging to the given branch or the branches of the given | 422 All changesets belonging to the given branch or the branches of the given |
418 changesets. | 423 changesets. |
438 | 443 |
439 s = getset(repo, baseset(repo), x) | 444 s = getset(repo, baseset(repo), x) |
440 b = set() | 445 b = set() |
441 for r in s: | 446 for r in s: |
442 b.add(repo[r].branch()) | 447 b.add(repo[r].branch()) |
443 s = set(s) | 448 s = s.set() |
444 return baseset([r for r in subset if r in s or repo[r].branch() in b]) | 449 return baseset([r for r in subset if r in s or repo[r].branch() in b]) |
445 | 450 |
446 def bumped(repo, subset, x): | 451 def bumped(repo, subset, x): |
447 """``bumped()`` | 452 """``bumped()`` |
448 Mutable changesets marked as successors of public changesets. | 453 Mutable changesets marked as successors of public changesets. |
513 | 518 |
514 def children(repo, subset, x): | 519 def children(repo, subset, x): |
515 """``children(set)`` | 520 """``children(set)`` |
516 Child changesets of changesets in set. | 521 Child changesets of changesets in set. |
517 """ | 522 """ |
518 s = set(getset(repo, baseset(repo), x)) | 523 s = getset(repo, baseset(repo), x).set() |
519 cs = _children(repo, subset, s) | 524 cs = _children(repo, subset, s) |
520 return baseset([r for r in subset if r in cs]) | 525 return baseset([r for r in subset if r in cs]) |
521 | 526 |
522 def closed(repo, subset, x): | 527 def closed(repo, subset, x): |
523 """``closed()`` | 528 """``closed()`` |
603 def _descendants(repo, subset, x, followfirst=False): | 608 def _descendants(repo, subset, x, followfirst=False): |
604 args = getset(repo, baseset(repo), x) | 609 args = getset(repo, baseset(repo), x) |
605 if not args: | 610 if not args: |
606 return baseset([]) | 611 return baseset([]) |
607 s = set(_revdescendants(repo, args, followfirst)) | set(args) | 612 s = set(_revdescendants(repo, args, followfirst)) | set(args) |
608 return baseset([r for r in subset if r in s]) | 613 ss = subset.set() |
614 return baseset([r for r in ss if r in s]) | |
609 | 615 |
610 def descendants(repo, subset, x): | 616 def descendants(repo, subset, x): |
611 """``descendants(set)`` | 617 """``descendants(set)`` |
612 Changesets which are descendants of changesets in set. | 618 Changesets which are descendants of changesets in set. |
613 """ | 619 """ |
623 Changesets that were created by a graft, transplant or rebase operation, | 629 Changesets that were created by a graft, transplant or rebase operation, |
624 with the given revisions specified as the source. Omitting the optional set | 630 with the given revisions specified as the source. Omitting the optional set |
625 is the same as passing all(). | 631 is the same as passing all(). |
626 """ | 632 """ |
627 if x is not None: | 633 if x is not None: |
628 args = set(getset(repo, baseset(repo), x)) | 634 args = getset(repo, baseset(repo), x).set() |
629 else: | 635 else: |
630 args = set(getall(repo, baseset(repo), x)) | 636 args = getall(repo, baseset(repo), x).set() |
631 | 637 |
632 dests = set() | 638 dests = set() |
633 | 639 |
634 # subset contains all of the possible destinations that can be returned, so | 640 # subset contains all of the possible destinations that can be returned, so |
635 # iterate over them and see if their source(s) were provided in the args. | 641 # iterate over them and see if their source(s) were provided in the args. |
743 if m(f): | 749 if m(f): |
744 fl = repo.file(f) | 750 fl = repo.file(f) |
745 for fr in fl: | 751 for fr in fl: |
746 s.add(fl.linkrev(fr)) | 752 s.add(fl.linkrev(fr)) |
747 | 753 |
748 return baseset([r for r in subset if r in s]) | 754 ss = subset.set() |
755 return baseset([r for r in ss if r in s]) | |
749 | 756 |
750 def first(repo, subset, x): | 757 def first(repo, subset, x): |
751 """``first(set, [n])`` | 758 """``first(set, [n])`` |
752 An alias for limit(). | 759 An alias for limit(). |
753 """ | 760 """ |
766 else: | 773 else: |
767 return baseset([]) | 774 return baseset([]) |
768 else: | 775 else: |
769 s = set(_revancestors(repo, [c.rev()], followfirst)) | set([c.rev()]) | 776 s = set(_revancestors(repo, [c.rev()], followfirst)) | set([c.rev()]) |
770 | 777 |
771 return baseset([r for r in subset if r in s]) | 778 ss = subset.set() |
779 return baseset([r for r in ss if r in s]) | |
772 | 780 |
773 def follow(repo, subset, x): | 781 def follow(repo, subset, x): |
774 """``follow([file])`` | 782 """``follow([file])`` |
775 An alias for ``::.`` (ancestors of the working copy's first parent). | 783 An alias for ``::.`` (ancestors of the working copy's first parent). |
776 If a filename is specified, the history of the given file is followed, | 784 If a filename is specified, the history of the given file is followed, |
895 # i18n: "head" is a keyword | 903 # i18n: "head" is a keyword |
896 getargs(x, 0, 0, _("head takes no arguments")) | 904 getargs(x, 0, 0, _("head takes no arguments")) |
897 hs = set() | 905 hs = set() |
898 for b, ls in repo.branchmap().iteritems(): | 906 for b, ls in repo.branchmap().iteritems(): |
899 hs.update(repo[h].rev() for h in ls) | 907 hs.update(repo[h].rev() for h in ls) |
900 return baseset([r for r in subset if r in hs]) | 908 s = subset.set() |
909 return baseset([r for r in s if r in hs]) | |
901 | 910 |
902 def heads(repo, subset, x): | 911 def heads(repo, subset, x): |
903 """``heads(set)`` | 912 """``heads(set)`` |
904 Members of set with no children in set. | 913 Members of set with no children in set. |
905 """ | 914 """ |
906 s = getset(repo, subset, x) | 915 s = getset(repo, subset, x).set() |
907 ps = set(parents(repo, subset, x)) | 916 ps = parents(repo, subset, x).set() |
908 return baseset([r for r in s if r not in ps]) | 917 return baseset([r for r in s if r not in ps]) |
909 | 918 |
910 def hidden(repo, subset, x): | 919 def hidden(repo, subset, x): |
911 """``hidden()`` | 920 """``hidden()`` |
912 Hidden changesets. | 921 Hidden changesets. |
943 # i18n: "limit" is a keyword | 952 # i18n: "limit" is a keyword |
944 lim = int(getstring(l[1], _("limit requires a number"))) | 953 lim = int(getstring(l[1], _("limit requires a number"))) |
945 except (TypeError, ValueError): | 954 except (TypeError, ValueError): |
946 # i18n: "limit" is a keyword | 955 # i18n: "limit" is a keyword |
947 raise error.ParseError(_("limit expects a number")) | 956 raise error.ParseError(_("limit expects a number")) |
948 ss = set(subset) | 957 ss = subset.set() |
949 os = getset(repo, baseset(repo), l[0])[:lim] | 958 os = getset(repo, baseset(repo), l[0])[:lim] |
950 return baseset([r for r in os if r in ss]) | 959 return baseset([r for r in os if r in ss]) |
951 | 960 |
952 def last(repo, subset, x): | 961 def last(repo, subset, x): |
953 """``last(set, [n])`` | 962 """``last(set, [n])`` |
961 # i18n: "last" is a keyword | 970 # i18n: "last" is a keyword |
962 lim = int(getstring(l[1], _("last requires a number"))) | 971 lim = int(getstring(l[1], _("last requires a number"))) |
963 except (TypeError, ValueError): | 972 except (TypeError, ValueError): |
964 # i18n: "last" is a keyword | 973 # i18n: "last" is a keyword |
965 raise error.ParseError(_("last expects a number")) | 974 raise error.ParseError(_("last expects a number")) |
966 ss = set(subset) | 975 ss = subset.set() |
967 os = getset(repo, baseset(repo), l[0])[-lim:] | 976 os = getset(repo, baseset(repo), l[0])[-lim:] |
968 return baseset([r for r in os if r in ss]) | 977 return baseset([r for r in os if r in ss]) |
969 | 978 |
970 def maxrev(repo, subset, x): | 979 def maxrev(repo, subset, x): |
971 """``max(set)`` | 980 """``max(set)`` |
1060 same as passing all(). If a changeset created by these operations is itself | 1069 same as passing all(). If a changeset created by these operations is itself |
1061 specified as a source for one of these operations, only the source changeset | 1070 specified as a source for one of these operations, only the source changeset |
1062 for the first operation is selected. | 1071 for the first operation is selected. |
1063 """ | 1072 """ |
1064 if x is not None: | 1073 if x is not None: |
1065 args = set(getset(repo, baseset(repo), x)) | 1074 args = getset(repo, baseset(repo), x).set() |
1066 else: | 1075 else: |
1067 args = set(getall(repo, baseset(repo), x)) | 1076 args = getall(repo, baseset(repo), x).set() |
1068 | 1077 |
1069 def _firstsrc(rev): | 1078 def _firstsrc(rev): |
1070 src = _getrevsource(repo, rev) | 1079 src = _getrevsource(repo, rev) |
1071 if src is None: | 1080 if src is None: |
1072 return None | 1081 return None |
1077 if prev is None: | 1086 if prev is None: |
1078 return src | 1087 return src |
1079 src = prev | 1088 src = prev |
1080 | 1089 |
1081 o = set([_firstsrc(r) for r in args]) | 1090 o = set([_firstsrc(r) for r in args]) |
1082 return baseset([r for r in subset if r in o]) | 1091 s = subset.set() |
1092 return baseset([r for r in s if r in o]) | |
1083 | 1093 |
1084 def outgoing(repo, subset, x): | 1094 def outgoing(repo, subset, x): |
1085 """``outgoing([path])`` | 1095 """``outgoing([path])`` |
1086 Changesets not found in the specified destination repository, or the | 1096 Changesets not found in the specified destination repository, or the |
1087 default push location. | 1097 default push location. |
1100 repo.ui.pushbuffer() | 1110 repo.ui.pushbuffer() |
1101 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs) | 1111 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs) |
1102 repo.ui.popbuffer() | 1112 repo.ui.popbuffer() |
1103 cl = repo.changelog | 1113 cl = repo.changelog |
1104 o = set([cl.rev(r) for r in outgoing.missing]) | 1114 o = set([cl.rev(r) for r in outgoing.missing]) |
1105 return baseset([r for r in subset if r in o]) | 1115 s = subset.set() |
1116 return baseset([r for r in s if r in o]) | |
1106 | 1117 |
1107 def p1(repo, subset, x): | 1118 def p1(repo, subset, x): |
1108 """``p1([set])`` | 1119 """``p1([set])`` |
1109 First parent of changesets in set, or the working directory. | 1120 First parent of changesets in set, or the working directory. |
1110 """ | 1121 """ |
1114 | 1125 |
1115 ps = set() | 1126 ps = set() |
1116 cl = repo.changelog | 1127 cl = repo.changelog |
1117 for r in getset(repo, baseset(repo), x): | 1128 for r in getset(repo, baseset(repo), x): |
1118 ps.add(cl.parentrevs(r)[0]) | 1129 ps.add(cl.parentrevs(r)[0]) |
1119 return baseset([r for r in subset if r in ps]) | 1130 s = subset.set() |
1131 return baseset([r for r in s if r in ps]) | |
1120 | 1132 |
1121 def p2(repo, subset, x): | 1133 def p2(repo, subset, x): |
1122 """``p2([set])`` | 1134 """``p2([set])`` |
1123 Second parent of changesets in set, or the working directory. | 1135 Second parent of changesets in set, or the working directory. |
1124 """ | 1136 """ |
1132 | 1144 |
1133 ps = set() | 1145 ps = set() |
1134 cl = repo.changelog | 1146 cl = repo.changelog |
1135 for r in getset(repo, baseset(repo), x): | 1147 for r in getset(repo, baseset(repo), x): |
1136 ps.add(cl.parentrevs(r)[1]) | 1148 ps.add(cl.parentrevs(r)[1]) |
1137 return baseset([r for r in subset if r in ps]) | 1149 s = subset.set() |
1150 return baseset([r for r in s if r in ps]) | |
1138 | 1151 |
1139 def parents(repo, subset, x): | 1152 def parents(repo, subset, x): |
1140 """``parents([set])`` | 1153 """``parents([set])`` |
1141 The set of all parents for all changesets in set, or the working directory. | 1154 The set of all parents for all changesets in set, or the working directory. |
1142 """ | 1155 """ |
1146 | 1159 |
1147 ps = set() | 1160 ps = set() |
1148 cl = repo.changelog | 1161 cl = repo.changelog |
1149 for r in getset(repo, baseset(repo), x): | 1162 for r in getset(repo, baseset(repo), x): |
1150 ps.update(cl.parentrevs(r)) | 1163 ps.update(cl.parentrevs(r)) |
1151 return baseset([r for r in subset if r in ps]) | 1164 s = subset.set() |
1165 return baseset([r for r in s if r in ps]) | |
1152 | 1166 |
1153 def parentspec(repo, subset, x, n): | 1167 def parentspec(repo, subset, x, n): |
1154 """``set^0`` | 1168 """``set^0`` |
1155 The set. | 1169 The set. |
1156 ``set^1`` (or ``set^``), ``set^2`` | 1170 ``set^1`` (or ``set^``), ``set^2`` |
1171 ps.add(cl.parentrevs(r)[0]) | 1185 ps.add(cl.parentrevs(r)[0]) |
1172 elif n == 2: | 1186 elif n == 2: |
1173 parents = cl.parentrevs(r) | 1187 parents = cl.parentrevs(r) |
1174 if len(parents) > 1: | 1188 if len(parents) > 1: |
1175 ps.add(parents[1]) | 1189 ps.add(parents[1]) |
1176 return baseset([r for r in subset if r in ps]) | 1190 s = subset.set() |
1191 return baseset([r for r in s if r in ps]) | |
1177 | 1192 |
1178 def present(repo, subset, x): | 1193 def present(repo, subset, x): |
1179 """``present(set)`` | 1194 """``present(set)`` |
1180 An empty set, if any revision in set isn't found; otherwise, | 1195 An empty set, if any revision in set isn't found; otherwise, |
1181 all revisions in set. | 1196 all revisions in set. |
1373 def reverse(repo, subset, x): | 1388 def reverse(repo, subset, x): |
1374 """``reverse(set)`` | 1389 """``reverse(set)`` |
1375 Reverse order of set. | 1390 Reverse order of set. |
1376 """ | 1391 """ |
1377 l = getset(repo, subset, x) | 1392 l = getset(repo, subset, x) |
1378 if not isinstance(l, list): | |
1379 l = baseset(l) | |
1380 l.reverse() | 1393 l.reverse() |
1381 return l | 1394 return l |
1382 | 1395 |
1383 def roots(repo, subset, x): | 1396 def roots(repo, subset, x): |
1384 """``roots(set)`` | 1397 """``roots(set)`` |
1385 Changesets in set with no parent changeset in set. | 1398 Changesets in set with no parent changeset in set. |
1386 """ | 1399 """ |
1387 s = set(getset(repo, baseset(repo.changelog), x)) | 1400 s = getset(repo, baseset(repo.changelog), x).set() |
1388 subset = baseset([r for r in subset if r in s]) | 1401 subset = baseset([r for r in subset if r in s]) |
1389 cs = _children(repo, subset, s) | 1402 cs = _children(repo, subset, s) |
1390 return baseset([r for r in subset if r not in cs]) | 1403 return baseset([r for r in subset if r not in cs]) |
1391 | 1404 |
1392 def secret(repo, subset, x): | 1405 def secret(repo, subset, x): |
1548 # for internal use | 1561 # for internal use |
1549 def _list(repo, subset, x): | 1562 def _list(repo, subset, x): |
1550 s = getstring(x, "internal error") | 1563 s = getstring(x, "internal error") |
1551 if not s: | 1564 if not s: |
1552 return baseset([]) | 1565 return baseset([]) |
1553 if not isinstance(subset, set): | |
1554 subset = set(subset) | |
1555 ls = [repo[r].rev() for r in s.split('\0')] | 1566 ls = [repo[r].rev() for r in s.split('\0')] |
1556 return baseset([r for r in ls if r in subset]) | 1567 s = subset.set() |
1568 return baseset([r for r in ls if r in s]) | |
1557 | 1569 |
1558 symbols = { | 1570 symbols = { |
1559 "adds": adds, | 1571 "adds": adds, |
1560 "all": getall, | 1572 "all": getall, |
1561 "ancestor": ancestor, | 1573 "ancestor": ancestor, |
2046 if tree[0] == 'func': | 2058 if tree[0] == 'func': |
2047 funcs.add(tree[1][1]) | 2059 funcs.add(tree[1][1]) |
2048 return funcs | 2060 return funcs |
2049 | 2061 |
2050 class baseset(list): | 2062 class baseset(list): |
2051 pass | 2063 def __init__(self, data): |
2064 super(baseset, self).__init__(data) | |
2065 self._set = None | |
2066 | |
2067 def set(self): | |
2068 if not self._set: | |
2069 self._set = set(self) | |
2070 return self._set | |
2052 | 2071 |
2053 # tell hggettext to extract docstrings from these functions: | 2072 # tell hggettext to extract docstrings from these functions: |
2054 i18nfunctions = symbols.values() | 2073 i18nfunctions = symbols.values() |