revset: changed _iterator() method on addset to work with a given order
authorLucas Moscovicz <lmoscovicz@fb.com>
Thu, 13 Mar 2014 13:29:04 -0700
changeset 20722 6894223ebc38
parent 20721 d642f176df52
child 20723 fb9852c46a42
revset: changed _iterator() method on addset to work with a given order If the two collections are in ascending order, yield their values in an ordered way by iterating both at the same time and picking the values to yield.
mercurial/revset.py
--- a/mercurial/revset.py	Thu Mar 13 14:51:04 2014 -0700
+++ b/mercurial/revset.py	Thu Mar 13 13:29:04 2014 -0700
@@ -2340,14 +2340,60 @@
         return self._genlist
 
     def _iterator(self):
+        """Iterate over both collections without repeating elements
+
+        If the ascending attribute is not set, iterate over the first one and
+        then over the second one checking for membership on the first one so we
+        dont yield any duplicates.
+
+        If the ascending attribute is set, iterate over both collections at the
+        same time, yielding only one value at a time in the given order.
+        """
         if not self._iter:
             def gen():
-                for r in self._r1:
-                    yield r
-                s = self._r1.set()
-                for r in self._r2:
-                    if r not in s:
+                if self._ascending is None:
+                    for r in self._r1:
                         yield r
+                    s = self._r1.set()
+                    for r in self._r2:
+                        if r not in s:
+                            yield r
+                else:
+                    iter1 = iter(self._r1)
+                    iter2 = iter(self._r2)
+
+                    val1 = None
+                    val2 = None
+
+                    choice = max
+                    if self._ascending:
+                        choice = min
+                    try:
+                        # Consume both iterators in an ordered way until one is
+                        # empty
+                        while True:
+                            if val1 is None:
+                                val1 = iter1.next()
+                            if val2 is None:
+                                val2 = iter2.next()
+                            next = choice(val1, val2)
+                            yield next
+                            if val1 == next:
+                                val1 = None
+                            if val2 == next:
+                                val2 = None
+                    except StopIteration:
+                        # Flush any remaining values and consume the other one
+                        it = iter2
+                        if val1 is not None:
+                            yield val1
+                            it = iter1
+                        elif val2 is not None:
+                            # might have been equality and both are empty
+                            yield val2
+                        for val in it:
+                            yield val
+
             self._iter = _generatorset(gen())
 
         return self._iter