diff --git a/mercurial/revset.py b/mercurial/revset.py --- a/mercurial/revset.py +++ b/mercurial/revset.py @@ -1169,18 +1169,7 @@ def limit(repo, subset, x, order): if ofs < 0: raise error.ParseError(_("negative offset")) os = getset(repo, fullreposet(repo), args['set']) - result = [] - it = iter(os) - for x in xrange(ofs): - y = next(it, None) - if y is None: - break - for x in xrange(lim): - y = next(it, None) - if y is None: - break - result.append(y) - ls = baseset(result, datarepr=('', lim, ofs, os)) + ls = os.slice(ofs, ofs + lim) if order == followorder and lim > 1: return subset & ls return ls & subset @@ -1199,14 +1188,7 @@ def last(repo, subset, x, order): raise error.ParseError(_("negative number to select")) os = getset(repo, fullreposet(repo), l[0]) os.reverse() - result = [] - it = iter(os) - for x in xrange(lim): - y = next(it, None) - if y is None: - break - result.append(y) - ls = baseset(result, datarepr=('', lim, os)) + ls = os.slice(0, lim) if order == followorder and lim > 1: return subset & ls ls.reverse() diff --git a/mercurial/smartset.py b/mercurial/smartset.py --- a/mercurial/smartset.py +++ b/mercurial/smartset.py @@ -8,6 +8,7 @@ from __future__ import absolute_import from . import ( + error, util, ) @@ -155,6 +156,28 @@ class abstractsmartset(object): condition = util.cachefunc(condition) return filteredset(self, condition, condrepr) + def slice(self, start, stop): + """Return new smartset that contains selected elements from this set""" + if start < 0 or stop < 0: + raise error.ProgrammingError('negative index not allowed') + return self._slice(start, stop) + + def _slice(self, start, stop): + # sub classes may override this. start and stop must not be negative, + # but start > stop is allowed, which should be an empty set. + ys = [] + it = iter(self) + for x in xrange(start): + y = next(it, None) + if y is None: + break + for x in xrange(stop - start): + y = next(it, None) + if y is None: + break + ys.append(y) + return baseset(ys, datarepr=('slice=%d:%d %r', start, stop, self)) + class baseset(abstractsmartset): """Basic data structure that represents a revset and contains the basic operation that it should be able to perform. diff --git a/tests/test-revset.t b/tests/test-revset.t --- a/tests/test-revset.t +++ b/tests/test-revset.t @@ -1016,14 +1016,34 @@ Test first (=limit) and last 8 9 +Test smartset.slice() by first/last() + + (using unoptimized set, filteredset as example) + + $ hg debugrevspec --no-show-revs -s '0:7 & branch("re:")' + * set: + , + > + $ log 'limit(0:7 & branch("re:"), 3, 4)' + 4 + 5 + 6 + $ log 'limit(7:0 & branch("re:"), 3, 4)' + 3 + 2 + 1 + $ log 'last(0:7 & branch("re:"), 2)' + 6 + 7 + Test order of first/last revisions $ hg debugrevspec -s 'first(4:0, 3) & 3:' * set: >>, + >, > 4 3 @@ -1032,18 +1052,16 @@ Test order of first/last revisions * set: , - >>> + >> 3 4 $ hg debugrevspec -s 'last(4:0, 3) & :1' * set: >>, + >, > 1 0 @@ -1052,9 +1070,8 @@ Test order of first/last revisions * set: , - >>> + >> 0 1 @@ -1950,9 +1967,8 @@ ordering defined by it. define) * set: >>, + >, > 1 @@ -1987,9 +2003,8 @@ ordering defined by it. , >>>> + >>> 2 0 @@ -3613,9 +3628,8 @@ issue2549 - correct optimizations ('symbol', '2'))) * set: >>, + >, >> 1 @@ -3669,9 +3683,8 @@ issue2549 - correct optimizations ('symbol', '2'))) * set: >>, + >, >>