# HG changeset patch # User Jun Wu # Date 1487467423 28800 # Node ID 2d1bf84046f6fcf59bdaae7a0390246b09ce85f6 # Parent 74f77f1c22153499266dd5d8022accf445ee94ec 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 -r 74f77f1c2215 -r 2d1bf84046f6 mercurial/smartset.py --- a/mercurial/smartset.py Sat Feb 18 16:30:07 2017 -0800 +++ b/mercurial/smartset.py Sat Feb 18 17:23:43 2017 -0800 @@ -171,7 +171,7 @@ >>> [list(i) for i in [xs + ys, xs & ys, xs - ys]] [[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: >>> xs = baseset(x) @@ -191,18 +191,18 @@ >>> [type(i).__name__ for i in [xs + ys, xs & ys, xs - ys]] ['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() >>> [list(i) for i in [xs + ys, xs & ys, xs - ys]] [[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): """ @@ -322,6 +322,22 @@ return self._asclist[0] 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] s = _formatsetrepr(self._datarepr)