cleanup: use the deque type where appropriate
There have been quite a few places where we pop elements off the
front of a list. This can turn O(n) algorithms into something more
like O(n**2). Python has provided a deque type that can do this
efficiently since at least 2.4.
As an example of the difference a deque can make, it improves
perfancestors performance on a Linux repo from 0.50 seconds to 0.36.
--- a/mercurial/hbisect.py Tue May 15 10:44:17 2012 -0700
+++ b/mercurial/hbisect.py Tue May 15 10:46:23 2012 -0700
@@ -11,7 +11,7 @@
import os, error
from i18n import _
from node import short, hex
-import util
+import collections, util
def bisect(changelog, state):
"""find the next node (if any) for testing during a bisect search.
@@ -69,10 +69,10 @@
# build children dict
children = {}
- visit = [badrev]
+ visit = collections.deque([badrev])
candidates = []
while visit:
- rev = visit.pop(0)
+ rev = visit.popleft()
if ancestors[rev] == []:
candidates.append(rev)
for prev in clparents(rev):
--- a/mercurial/patch.py Tue May 15 10:44:17 2012 -0700
+++ b/mercurial/patch.py Tue May 15 10:46:23 2012 -0700
@@ -12,7 +12,7 @@
from i18n import _
from node import hex, nullid, short
import base85, mdiff, scmutil, util, diffhelpers, copies, encoding, error
-import context
+import collections, context
gitre = re.compile('diff --git a/(.*) b/(.*)')
@@ -1588,12 +1588,12 @@
def lrugetfilectx():
cache = {}
- order = []
+ order = collections.deque()
def getfilectx(f, ctx):
fctx = ctx.filectx(f, filelog=cache.get(f))
if f not in cache:
if len(cache) > 20:
- del cache[order.pop(0)]
+ del cache[order.popleft()]
cache[f] = fctx.filelog()
else:
order.remove(f)
--- a/mercurial/revlog.py Tue May 15 10:44:17 2012 -0700
+++ b/mercurial/revlog.py Tue May 15 10:46:23 2012 -0700
@@ -15,7 +15,7 @@
from node import bin, hex, nullid, nullrev
from i18n import _
import ancestor, mdiff, parsers, error, util, dagutil
-import struct, zlib, errno
+import struct, zlib, errno, collections
_pack = struct.pack
_unpack = struct.unpack
@@ -362,13 +362,13 @@
"""return the set of all nodes ancestral to a given node, including
the node itself, stopping when stop is matched"""
reachable = set((node,))
- visit = [node]
+ visit = collections.deque([node])
if stop:
stopn = self.rev(stop)
else:
stopn = 0
while visit:
- n = visit.pop(0)
+ n = visit.popleft()
if n == stop:
continue
if n == nullid:
@@ -389,10 +389,10 @@
an ancestor of itself. Results are in breadth-first order:
parents of each rev in revs, then parents of those, etc. Result
does not include the null revision."""
- visit = list(revs)
+ visit = collections.deque(revs)
seen = set([nullrev])
while visit:
- for parent in self.parentrevs(visit.pop(0)):
+ for parent in self.parentrevs(visit.popleft()):
if parent not in seen:
visit.append(parent)
seen.add(parent)
@@ -447,9 +447,9 @@
# take all ancestors from heads that aren't in has
missing = set()
- visit = [r for r in heads if r not in has]
+ visit = collections.deque(r for r in heads if r not in has)
while visit:
- r = visit.pop(0)
+ r = visit.popleft()
if r in missing:
continue
else:
--- a/mercurial/revset.py Tue May 15 10:44:17 2012 -0700
+++ b/mercurial/revset.py Tue May 15 10:46:23 2012 -0700
@@ -5,7 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import re
+import re, collections
import parser, util, error, discovery, hbisect, phases
import node
import bookmarks as bookmarksmod
@@ -17,10 +17,10 @@
"""Like revlog.ancestors(), but supports followfirst."""
cut = followfirst and 1 or None
cl = repo.changelog
- visit = list(revs)
+ visit = collections.deque(revs)
seen = set([node.nullrev])
while visit:
- for parent in cl.parentrevs(visit.pop(0))[:cut]:
+ for parent in cl.parentrevs(visit.popleft())[:cut]:
if parent not in seen:
visit.append(parent)
seen.add(parent)
--- a/mercurial/treediscovery.py Tue May 15 10:44:17 2012 -0700
+++ b/mercurial/treediscovery.py Tue May 15 10:46:23 2012 -0700
@@ -7,7 +7,7 @@
from node import nullid, short
from i18n import _
-import util, error
+import util, error, collections
def findcommonincoming(repo, remote, heads=None, force=False):
"""Return a tuple (common, fetch, heads) used to identify the common
@@ -56,11 +56,11 @@
# a 'branch' here is a linear segment of history, with four parts:
# head, root, first parent, second parent
# (a branch always has two parents (or none) by definition)
- unknown = remote.branches(unknown)
+ unknown = collections.deque(remote.branches(unknown))
while unknown:
r = []
while unknown:
- n = unknown.pop(0)
+ n = unknown.popleft()
if n[0] in seen:
continue
--- a/mercurial/util.py Tue May 15 10:44:17 2012 -0700
+++ b/mercurial/util.py Tue May 15 10:46:23 2012 -0700
@@ -14,7 +14,7 @@
"""
from i18n import _
-import error, osutil, encoding
+import error, osutil, encoding, collections
import errno, re, shutil, sys, tempfile, traceback
import os, time, datetime, calendar, textwrap, signal
import imp, socket, urllib
@@ -205,12 +205,12 @@
def lrucachefunc(func):
'''cache most recent results of function calls'''
cache = {}
- order = []
+ order = collections.deque()
if func.func_code.co_argcount == 1:
def f(arg):
if arg not in cache:
if len(cache) > 20:
- del cache[order.pop(0)]
+ del cache[order.popleft()]
cache[arg] = func(arg)
else:
order.remove(arg)
@@ -220,7 +220,7 @@
def f(*args):
if args not in cache:
if len(cache) > 20:
- del cache[order.pop(0)]
+ del cache[order.popleft()]
cache[args] = func(*args)
else:
order.remove(args)
@@ -865,7 +865,7 @@
Returns less than L bytes if the iterator runs dry."""
left = l
buf = ''
- queue = self._queue
+ queue = collections.deque(self._queue)
while left > 0:
# refill the queue
if not queue:
@@ -878,13 +878,14 @@
if not queue:
break
- chunk = queue.pop(0)
+ chunk = queue.popleft()
left -= len(chunk)
if left < 0:
- queue.insert(0, chunk[left:])
+ queue.appendleft(chunk[left:])
buf += chunk[:left]
else:
buf += chunk
+ self._queue = list(queue)
return buf