annotate: optimize line counting
authorMatt Mackall <mpm@selenic.com>
Wed, 18 May 2016 16:37:32 -0500
changeset 29223 c04ad3d3c651
parent 29222 ed4bd789fc55
child 29224 7424f4294199
annotate: optimize line counting We used len(text.splitlines()) to count lines. This allocates, copies, and deallocates an object for every line in a file. Instead, we use count("\n") to count newlines and adjust based on whether there's a trailing newline. This improves the speed of annotating localrepo.py from 4.2 to 4.0 seconds.
mercurial/context.py
--- a/mercurial/context.py	Mon May 16 14:21:39 2016 -0700
+++ b/mercurial/context.py	Wed May 18 16:37:32 2016 -0500
@@ -930,16 +930,20 @@
         this returns fixed value(False is used) as linenumber,
         if "linenumber" parameter is "False".'''
 
+        def lines(text):
+            if text.endswith("\n"):
+                return text.count("\n")
+            return text.count("\n") + 1
+
         if linenumber is None:
             def decorate(text, rev):
-                return ([rev] * len(text.splitlines()), text)
+                return ([rev] * lines(text), text)
         elif linenumber:
             def decorate(text, rev):
-                size = len(text.splitlines())
-                return ([(rev, i) for i in xrange(1, size + 1)], text)
+                return ([(rev, i) for i in xrange(1, lines(text) + 1)], text)
         else:
             def decorate(text, rev):
-                return ([(rev, False)] * len(text.splitlines()), text)
+                return ([(rev, False)] * lines(text), text)
 
         def pair(parent, child):
             blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts,