[PATCH 2 of 2 V2] smartset: use native set operations as fast paths

Jun Wu quark at fb.com
Sat Feb 18 20:27:31 EST 2017


# HG changeset patch
# User Jun Wu <quark at fb.com>
# Date 1487467423 28800
#      Sat Feb 18 17:23:43 2017 -0800
# Node ID 6f57ef05c74567db95f42426499640ad29bc878f
# Parent  deb48622b857d621606a1cdda4adc868b1c663d4
# Available At https://bitbucket.org/quark-zju/hg-draft
#              hg pull https://bitbucket.org/quark-zju/hg-draft -r 6f57ef05c745
smartset: use native set operations as fast paths

For set operations like "&" and "-", where we know both basesets have their
sets ready, and the first set is sorted, use the native Python set
operations as a fast path.

Note: "+" is not optimized as that will break the ordering.

This leads to noticeable improvements on performance:

  revset                                | before | after | delta
  ----------------------------------------------------------------
  draft() & draft() & draft() & draft() |    776 |   477 | -39%
  draft() + draft() + draft() + draft() |   2849 |  2864 |
  draft() - draft() + draft() - draft() |    943 |   240 | -75%
  draft() - draft() - draft() - draft() |    557 |   197 | -64%

  (time measured in microseconds)

diff --git a/mercurial/smartset.py b/mercurial/smartset.py
--- a/mercurial/smartset.py
+++ b/mercurial/smartset.py
@@ -172,5 +172,5 @@ class baseset(abstractsmartset):
     [[0, 4, 6, 7, 3, 5], [6, 7], [0, 4]]
     >>> [type(i).__name__ for i in [xs + ys, xs & ys, xs - ys]]
-    ['addset', 'filteredset', 'filteredset']
+    ['addset', 'baseset', 'baseset']
 
     Construct by a list-like:
@@ -192,10 +192,10 @@ class baseset(abstractsmartset):
     ['addset', 'filteredset', 'filteredset']
 
-    With sort():
+    With sort(), set optimization could be used:
     >>> xs.sort(reverse=True)
     >>> [list(i) for i in [xs + ys, xs & ys, xs - ys]]
     [[7, 6, 4, 0, 5, 3], [7, 6], [4, 0]]
     >>> [type(i).__name__ for i in [xs + ys, xs & ys, xs - ys]]
-    ['addset', 'filteredset', 'filteredset']
+    ['addset', 'baseset', 'baseset']
 
     >>> ys.sort()
@@ -203,5 +203,5 @@ class baseset(abstractsmartset):
     [[7, 6, 4, 0, 3, 5], [7, 6], [4, 0]]
     >>> [type(i).__name__ for i in [xs + ys, xs & ys, xs - ys]]
-    ['addset', 'filteredset', 'filteredset']
+    ['addset', 'baseset', 'baseset']
     """
     def __init__(self, data=(), datarepr=None, istopo=False):
@@ -323,4 +323,20 @@ class baseset(abstractsmartset):
         return None
 
+    def _fastsetop(self, other, op):
+        # try to use native set operations as fast paths
+        if (type(other) is baseset and '_set' in other.__dict__ and '_set' in
+            self.__dict__ and self._ascending is not None):
+            s = baseset(data=getattr(self._set, op)(other._set))
+            s._ascending = self._ascending
+        else:
+            s = getattr(super(baseset, self), op)(other)
+        return s
+
+    def __and__(self, other):
+        return self._fastsetop(other, '__and__')
+
+    def __sub__(self, other):
+        return self._fastsetop(other, '__sub__')
+
     def __repr__(self):
         d = {None: '', False: '-', True: '+'}[self._ascending]


More information about the Mercurial-devel mailing list