revset: record if a set is in topographical order
A later revision adds actual topographical sorting. Recording if a set is in
this order allows hg log -G to avoid re-sorting the revset.
--- a/mercurial/cmdutil.py Mon Jun 13 21:30:14 2016 +0100
+++ b/mercurial/cmdutil.py Tue Jun 14 11:05:36 2016 +0100
@@ -2147,7 +2147,7 @@
if opts.get('rev'):
# User-specified revs might be unsorted, but don't sort before
# _makelogrevset because it might depend on the order of revs
- if not revs.isdescending():
+ if not (revs.isdescending() or revs.istopo()):
revs.sort(reverse=True)
if expr:
# Revset matchers often operate faster on revisions in changelog
--- a/mercurial/revset.py Mon Jun 13 21:30:14 2016 +0100
+++ b/mercurial/revset.py Tue Jun 14 11:05:36 2016 +0100
@@ -2508,6 +2508,10 @@
"""True if the set will iterate in descending order"""
raise NotImplementedError()
+ def istopo(self):
+ """True if the set will iterate in topographical order"""
+ raise NotImplementedError()
+
@util.cachefunc
def min(self):
"""return the minimum element in the set"""
@@ -2593,12 +2597,13 @@
Every method in this class should be implemented by any smartset class.
"""
- def __init__(self, data=(), datarepr=None):
+ def __init__(self, data=(), datarepr=None, istopo=False):
"""
datarepr: a tuple of (format, obj, ...), a function or an object that
provides a printable representation of the given data.
"""
self._ascending = None
+ self._istopo = istopo
if not isinstance(data, list):
if isinstance(data, set):
self._set = data
@@ -2641,12 +2646,14 @@
def sort(self, reverse=False):
self._ascending = not bool(reverse)
+ self._istopo = False
def reverse(self):
if self._ascending is None:
self._list.reverse()
else:
self._ascending = not self._ascending
+ self._istopo = False
def __len__(self):
return len(self._list)
@@ -2667,6 +2674,14 @@
return True
return self._ascending is not None and not self._ascending
+ def istopo(self):
+ """Is the collection is in topographical order or not.
+
+ This is part of the mandatory API for smartset."""
+ if len(self) <= 1:
+ return True
+ return self._istopo
+
def first(self):
if self:
if self._ascending is None:
@@ -2782,6 +2797,9 @@
def isdescending(self):
return self._subset.isdescending()
+ def istopo(self):
+ return self._subset.istopo()
+
def first(self):
for x in self:
return x
@@ -3028,6 +3046,12 @@
def isdescending(self):
return self._ascending is not None and not self._ascending
+ def istopo(self):
+ # not worth the trouble asserting if the two sets combined are still
+ # in topographical order. Use the sort() predicate to explicitly sort
+ # again instead.
+ return False
+
def reverse(self):
if self._ascending is None:
self._list.reverse()
@@ -3195,6 +3219,12 @@
def isdescending(self):
return not self._ascending
+ def istopo(self):
+ # not worth the trouble asserting if the two sets combined are still
+ # in topographical order. Use the sort() predicate to explicitly sort
+ # again instead.
+ return False
+
def first(self):
if self._ascending:
it = self.fastasc
@@ -3257,6 +3287,12 @@
def reverse(self):
self._ascending = not self._ascending
+ def istopo(self):
+ # not worth the trouble asserting if the two sets combined are still
+ # in topographical order. Use the sort() predicate to explicitly sort
+ # again instead.
+ return False
+
def _iterfilter(self, iterrange):
s = self._hiddenrevs
for r in iterrange: