smartset: extract method to slice abstractsmartset
authorYuya Nishihara <yuya@tcha.org>
Tue, 24 Mar 2015 00:14:53 +0900
changeset 32838 4710cc4dac99
parent 32837 9ddb18ae342e
child 32839 653d60455dbe
smartset: extract method to slice abstractsmartset Sub classes can provide optimized implementations.
mercurial/revset.py
mercurial/smartset.py
tests/test-revset.t
--- a/mercurial/revset.py	Sun May 24 11:07:14 2015 +0900
+++ b/mercurial/revset.py	Tue Mar 24 00:14:53 2015 +0900
@@ -1169,18 +1169,7 @@
     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=('<limit n=%d, offset=%d, %r>', 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 @@
         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=('<last n=%d, %r>', lim, os))
+    ls = os.slice(0, lim)
     if order == followorder and lim > 1:
         return subset & ls
     ls.reverse()
--- a/mercurial/smartset.py	Sun May 24 11:07:14 2015 +0900
+++ b/mercurial/smartset.py	Tue Mar 24 00:14:53 2015 +0900
@@ -8,6 +8,7 @@
 from __future__ import absolute_import
 
 from . import (
+    error,
     util,
 )
 
@@ -155,6 +156,28 @@
             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.
--- a/tests/test-revset.t	Sun May 24 11:07:14 2015 +0900
+++ b/tests/test-revset.t	Tue Mar 24 00:14:53 2015 +0900
@@ -1016,14 +1016,34 @@
   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:
+  <filteredset
+    <spanset+ 0:8>,
+    <branch 're:'>>
+  $ 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:
   <filteredset
-    <baseset
-      <limit n=3, offset=0,
-        <spanset- 0:5>>>,
+    <baseset slice=0:3
+      <spanset- 0:5>>,
     <spanset+ 3:10>>
   4
   3
@@ -1032,18 +1052,16 @@
   * set:
   <filteredset
     <spanset+ 3:10>,
-    <baseset
-      <limit n=3, offset=0,
-        <spanset- 0:5>>>>
+    <baseset slice=0:3
+      <spanset- 0:5>>>
   3
   4
 
   $ hg debugrevspec -s 'last(4:0, 3) & :1'
   * set:
   <filteredset
-    <baseset
-      <last n=3,
-        <spanset+ 0:5>>>,
+    <baseset slice=0:3
+      <spanset+ 0:5>>,
     <spanset+ 0:2>>
   1
   0
@@ -1052,9 +1070,8 @@
   * set:
   <filteredset
     <spanset+ 0:2>,
-    <baseset
-      <last n=3,
-        <spanset+ 0:5>>>>
+    <baseset slice=0:3
+      <spanset+ 0:5>>>
   0
   1
 
@@ -1950,9 +1967,8 @@
     define)
   * set:
   <filteredset
-    <baseset
-      <limit n=1, offset=0,
-        <baseset [1, 0, 2]>>>,
+    <baseset slice=0:1
+      <baseset [1, 0, 2]>>,
     <spanset- 0:3>>
   1
 
@@ -1987,9 +2003,8 @@
   <filteredset
     <spanset- 0:3>,
     <not
-      <baseset
-        <last n=1,
-          <baseset [1, 2, 0]>>>>>
+      <baseset slice=0:1
+        <baseset [1, 2, 0]>>>>
   2
   0
 
@@ -3613,9 +3628,8 @@
       ('symbol', '2')))
   * set:
   <filteredset
-    <baseset
-      <limit n=2, offset=0,
-        <baseset [1, 2, 3]>>>,
+    <baseset slice=0:2
+      <baseset [1, 2, 3]>>,
     <not
       <baseset [2]>>>
   1
@@ -3669,9 +3683,8 @@
       ('symbol', '2')))
   * set:
   <filteredset
-    <baseset
-      <last n=1,
-        <baseset [2, 1]>>>,
+    <baseset slice=0:1
+      <baseset [2, 1]>>,
     <not
       <baseset [2]>>>