[PATCH 2 of 4] Do not use str.startswith or str.endswith to find a single character

Nicolas Dumazet nicdumz at gmail.com
Sat Aug 22 13:39:43 CDT 2009


# HG changeset patch
# User Nicolas Dumazet <nicdumz.commits at gmail.com>
# Date 1250960622 -7200
# Node ID 51f0751ed3681aee75842e2351445ff30054062b
# Parent  f7a1dd3fa57b6be41c0c5535a16531b710571bb7
Do not use str.startswith or str.endswith to find a single character

When startswith (resp. endswith) is called on a single character, it is two times
faster to directly compare that single character with str[0] (resp. str[-1]).

* str.startswith(char) -> (str and) str[0] == char
* str.endswith(char) -> (str and) str[-1] == char

diff --git a/hgext/churn.py b/hgext/churn.py
--- a/hgext/churn.py
+++ b/hgext/churn.py
@@ -27,8 +27,8 @@
     fmatch = cmdutil.matchfiles(repo, fns)
     diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch))
     for l in diff.split('\n'):
-        if (l.startswith("+") and not l.startswith("+++ ") or
-            l.startswith("-") and not l.startswith("--- ")):
+        if l and (l[0] == "+" and not l.startswith("+++ ") or
+            l[0] == "-" and not l.startswith("--- ")):
             lines += 1
     return lines
 
diff --git a/hgext/convert/convcmd.py b/hgext/convert/convcmd.py
--- a/hgext/convert/convcmd.py
+++ b/hgext/convert/convcmd.py
@@ -240,7 +240,7 @@
         for line in afile:
 
             line = line.strip()
-            if not line or line.startswith('#'):
+            if not line or line[0] == '#':
                 continue
 
             try:
diff --git a/hgext/convert/cvs.py b/hgext/convert/cvs.py
--- a/hgext/convert/cvs.py
+++ b/hgext/convert/cvs.py
@@ -328,7 +328,7 @@
                 mode = self.readp.readline()[:-1]
                 count = int(self.readp.readline()[:-1])
                 data = chunkedread(self.readp, count)
-            elif line.startswith(" "):
+            elif line and line[0] == " ":
                 data += line[1:]
             elif line.startswith("M "):
                 pass
diff --git a/hgext/convert/cvsps.py b/hgext/convert/cvsps.py
--- a/hgext/convert/cvsps.py
+++ b/hgext/convert/cvsps.py
@@ -130,7 +130,7 @@
         except IOError:
             raise logerror('Not a CVS sandbox')
 
-        if prefix and not prefix.endswith(os.sep):
+        if prefix and prefix[-1] != os.sep:
             prefix += os.sep
 
         # Use the Root file in the sandbox, if it exists
@@ -182,7 +182,7 @@
     if root:
         cmd.append('-d%s' % root)
         p = util.normpath(getrepopath(root))
-        if not p.endswith('/'):
+        if p != '/':
             p += '/'
         prefix = p + util.normpath(prefix)
     cmd.append(['log', 'rlog'][rlog])
@@ -208,7 +208,7 @@
         if line == '':
             break
         peek = pfp.readline()
-        if line.endswith('\n'):
+        if line[-1] == '\n':
             line = line[:-1]
         #ui.debug('state=%d line=%r\n' % (state, line))
 
@@ -222,7 +222,7 @@
                     filename = util.normpath(rcs[:-2])
                     if filename.startswith(prefix):
                         filename = filename[len(prefix):]
-                    if filename.startswith('/'):
+                    if filename[0] == '/':
                         filename = filename[1:]
                     if filename.startswith('Attic/'):
                         filename = filename[6:]
diff --git a/hgext/convert/git.py b/hgext/convert/git.py
--- a/hgext/convert/git.py
+++ b/hgext/convert/git.py
@@ -67,7 +67,7 @@
         entry = None
         for l in fh.read().split('\x00'):
             if not entry:
-                if not l.startswith(':'):
+                if not l or l[0] != ':':
                     continue
                 entry = l
                 continue
diff --git a/hgext/convert/gnuarch.py b/hgext/convert/gnuarch.py
--- a/hgext/convert/gnuarch.py
+++ b/hgext/convert/gnuarch.py
@@ -293,12 +293,12 @@
         for l in data:
             l = l.strip()
             # Added file (ignore added directory)
-            if l.startswith('A') and not l.startswith('A/'):
+            if l[0] == 'A' and not l.startswith('A/'):
                 file = self._stripbasepath(l[1:].strip())
                 if not self._exclude(file):
                     self.changes[rev].add_files.append(file)
             # Deleted file (ignore deleted directory)
-            elif l.startswith('D') and not l.startswith('D/'):
+            elif l[0] == 'D' and not l.startswith('D/'):
                 file = self._stripbasepath(l[1:].strip())
                 if not self._exclude(file):
                     self.changes[rev].del_files.append(file)
@@ -313,7 +313,7 @@
                 if not self._exclude(file):
                     self.changes[rev].mod_files.append(file)
             # Modified file
-            elif l.startswith('M'):
+            elif l[0] == 'M':
                 file = self._stripbasepath(l[1:].strip())
                 if not self._exclude(file):
                     self.changes[rev].mod_files.append(file)
diff --git a/hgext/convert/p4.py b/hgext/convert/p4.py
--- a/hgext/convert/p4.py
+++ b/hgext/convert/p4.py
@@ -184,7 +184,7 @@
 
         if keywords:
             contents = keywords.sub("$\\1$", contents)
-        if mode == "l" and contents.endswith("\n"):
+        if mode == "l" and contents and contents[-1] == "\n":
             contents = contents[:-1]
 
         return contents
diff --git a/hgext/convert/subversion.py b/hgext/convert/subversion.py
--- a/hgext/convert/subversion.py
+++ b/hgext/convert/subversion.py
@@ -861,10 +861,10 @@
         # that is to say "tests/PloneTestCase.py"
         if path.startswith(module):
             relative = path.rstrip('/')[len(module):]
-            if relative.startswith('/'):
+            if relative == '':
+                return relative
+            elif relative[0] == '/':
                 return relative[1:]
-            elif relative == '':
-                return relative
 
         # The path is outside our tracked tree...
         self.ui.debug(_('%r is not under %r, ignoring\n') % (path, module))
@@ -881,7 +881,7 @@
         # supplied URL
         relpaths = []
         for p in paths:
-            if not p.startswith('/'):
+            if not p or p[0] != '/':
                 p = self.module + '/' + p
             relpaths.append(p.strip('/'))
         args = [self.baseurl, relpaths, start, end, limit, discover_changed_paths,
@@ -956,7 +956,7 @@
                     commandline(ui, 'svnadmin').run0('create', path)
                     created = path
                 path = util.normpath(path)
-                if not path.startswith('/'):
+                if not path or path[0] != '/':
                     path = '/' + path
                 path = 'file://' + path
 
diff --git a/hgext/patchbomb.py b/hgext/patchbomb.py
--- a/hgext/patchbomb.py
+++ b/hgext/patchbomb.py
@@ -98,7 +98,7 @@
         ui.write(summary, '\n')
         ui.write(s, '\n')
     ans = prompt(ui, _('does the diffstat above look okay? '), 'y')
-    if not ans.lower().startswith('y'):
+    if ans.lower()[0] != 'y':
         raise util.Abort(_('diffstat rejected'))
     return s
 
@@ -109,7 +109,7 @@
     body = ''
 
     for line in patch:
-        if line.startswith('#'):
+        if line and line[0] == '#':
             if line.startswith('# Node ID'):
                 node = line.split()[-1]
             continue
@@ -399,9 +399,9 @@
     parent = opts.get('in_reply_to') or None
     # angle brackets may be omitted, they're not semantically part of the msg-id
     if parent is not None:
-        if not parent.startswith('<'):
+        if parent[0] != '<':
             parent = '<' + parent
-        if not parent.endswith('>'):
+        if parent[-1] != '>':
             parent += '>'
 
     first = True
diff --git a/hgext/transplant.py b/hgext/transplant.py
--- a/hgext/transplant.py
+++ b/hgext/transplant.py
@@ -343,7 +343,7 @@
                 node = revlog.bin(line[10:])
             elif line.startswith('# Parent '):
                 parents.append(revlog.bin(line[9:]))
-            elif not line.startswith('#'):
+            elif not line or line[0] != '#':
                 inmsg = True
                 message.append(line)
         return (node, user, date, '\n'.join(message), parents)
diff --git a/mercurial/archival.py b/mercurial/archival.py
--- a/mercurial/archival.py
+++ b/mercurial/archival.py
@@ -28,7 +28,7 @@
                 break
     lpfx = os.path.normpath(util.localpath(prefix))
     prefix = util.pconvert(lpfx)
-    if not prefix.endswith('/'):
+    if prefix[-1] != '/':
         prefix += '/'
     if prefix.startswith('../') or os.path.isabs(lpfx) or '/../' in prefix:
         raise util.Abort(_('archive prefix contains illegal components'))
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1495,7 +1495,7 @@
             if (not select and name != 'shortlist' and
                 e[0].__module__ != __name__):
                 continue
-            if name == "shortlist" and not f.startswith("^"):
+            if name == "shortlist" and f[0] != "^":
                 continue
             f = f.lstrip("^")
             if not ui.debugflag and f.startswith("debug"):
diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -86,7 +86,7 @@
         # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
 
         req.url = req.env['SCRIPT_NAME']
-        if not req.url.endswith('/'):
+        if not req.url or req.url[-1] != '/':
             req.url += '/'
         if 'REPO_NAME' in req.env:
             req.url += req.env['REPO_NAME'] + '/'
@@ -216,7 +216,7 @@
         port = port != default_port and (":" + port) or ""
         urlbase = '%s://%s%s' % (proto, req.env['SERVER_NAME'], port)
         staticurl = self.config("web", "staticurl") or req.url + 'static/'
-        if not staticurl.endswith('/'):
+        if staticurl[-1] != '/':
             staticurl += '/'
 
         # some functions for the templater
diff --git a/mercurial/hgweb/hgwebdir_mod.py b/mercurial/hgweb/hgwebdir_mod.py
--- a/mercurial/hgweb/hgwebdir_mod.py
+++ b/mercurial/hgweb/hgwebdir_mod.py
@@ -312,7 +312,7 @@
             req.env['SCRIPT_NAME'] = self._baseurl
 
         url = req.env.get('SCRIPT_NAME', '')
-        if not url.endswith('/'):
+        if not url or url[-1] != '/':
             url += '/'
 
         vars = {}
@@ -323,7 +323,7 @@
         sessionvars = webutil.sessionvars(vars, start)
 
         staticurl = config('web', 'staticurl') or url + 'static/'
-        if not staticurl.endswith('/'):
+        if staticurl[-1] != '/':
             staticurl += '/'
 
         style = 'style' in req.form and req.form['style'][0] or self.style
diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py
--- a/mercurial/hgweb/webutil.py
+++ b/mercurial/hgweb/webutil.py
@@ -166,14 +166,15 @@
         blockno = blockcount.next()
         for lineno, l in enumerate(diff.splitlines(True)):
             lineno = "%d.%d" % (blockno, lineno + 1)
-            if l.startswith('+'):
-                ltype = "difflineplus"
-            elif l.startswith('-'):
-                ltype = "difflineminus"
-            elif l.startswith('@'):
-                ltype = "difflineat"
-            else:
-                ltype = "diffline"
+            ltype = "diffline"
+            if l:
+                first = l[0]
+                if first == '+':
+                    ltype = "difflineplus"
+                elif first == '-':
+                    ltype = "difflineminus"
+                elif first == '@':
+                    ltype = "difflineat"
             yield tmpl(ltype,
                        line=l,
                        lineid="l%s" % lineno,
diff --git a/mercurial/match.py b/mercurial/match.py
--- a/mercurial/match.py
+++ b/mercurial/match.py
@@ -187,7 +187,7 @@
     elif kind == 'relpath':
         return re.escape(name) + '(?:/|$)'
     elif kind == 'relre':
-        if name.startswith('^'):
+        if name[0] == '^':
             return name
         return '.*' + name
     return _globre(name) + tail
diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -124,7 +124,7 @@
                 message = cfp.getvalue()
                 if tmpfp:
                     tmpfp.write(payload)
-                    if not payload.endswith('\n'):
+                    if payload[-1] != '\n':
                         tmpfp.write('\n')
             elif not diffs_seen and message and content_type == 'text/plain':
                 message += '\n' + payload
@@ -579,7 +579,7 @@
                 hunki += 1
                 if h == u:
                     break
-                elif h.startswith('-'):
+                elif h and h[0] == '-':
                     continue
                 else:
                     self.hunk.insert(hunki-1, u)
@@ -588,12 +588,12 @@
         if not self.a:
             # this happens when lines were only added to the hunk
             for x in self.hunk:
-                if x.startswith('-') or x.startswith(' '):
+                if x and x[0] in '- ':
                     self.a.append(x)
         if not self.b:
             # this happens when lines were only deleted from the hunk
             for x in self.hunk:
-                if x.startswith('+') or x.startswith(' '):
+                if x and x[0] in '+ ':
                     self.b.append(x[1:])
         # @@ -start,len +start,len @@
         self.desc = "@@ -%d,%d +%d,%d @@\n" % (self.starta, self.lena,
@@ -613,10 +613,10 @@
         # self.hunk[0] is the @@ description
         for x in xrange(1, len(self.hunk)):
             o = self.hunk[x]
-            if o.startswith('-'):
+            if o[0] == '-':
                 n = '+' + o[1:]
                 self.b.append(o[1:])
-            elif o.startswith('+'):
+            elif o[0] == '+':
                 n = '-' + o[1:]
                 self.a.append(n)
             else:
@@ -1399,6 +1399,8 @@
 def diffstatdata(lines):
     filename, adds, removes = None, 0, 0
     for line in lines:
+        if not line:
+            continue
         if line.startswith('diff'):
             if filename:
                 yield (filename, adds, removes)
@@ -1409,9 +1411,9 @@
             else:
                 # format: "diff -r ... -r ... filename"
                 filename = line.split(None, 5)[-1]
-        elif line.startswith('+') and not line.startswith('+++'):
+        elif line[0] == '+' and not line.startswith('+++'):
             adds += 1
-        elif line.startswith('-') and not line.startswith('---'):
+        elif line[0] == '-' and not line.startswith('---'):
             removes += 1
     if filename:
         yield (filename, adds, removes)
diff --git a/mercurial/posix.py b/mercurial/posix.py
--- a/mercurial/posix.py
+++ b/mercurial/posix.py
@@ -52,7 +52,7 @@
         if pf[0] == '`':
             pf = pf[1:-1] # Remove the quotes
     else:
-        if pf.startswith("'") and pf.endswith("'") and " " in pf:
+        if pf[0] == "'" and pf[-1] == "'" and " " in pf:
             pf = pf[1:-1] # Remove the quotes
     return pf
 
diff --git a/mercurial/pure/osutil.py b/mercurial/pure/osutil.py
--- a/mercurial/pure/osutil.py
+++ b/mercurial/pure/osutil.py
@@ -36,7 +36,7 @@
     '''
     result = []
     prefix = path
-    if not prefix.endswith(os.sep):
+    if prefix[-1] != os.sep:
         prefix += os.sep
     names = os.listdir(path)
     names.sort()
diff --git a/mercurial/repo.py b/mercurial/repo.py
--- a/mercurial/repo.py
+++ b/mercurial/repo.py
@@ -38,6 +38,6 @@
 
     def rjoin(self, path):
         url = self.url()
-        if url.endswith('/'):
+        if url[-1] == '/':
             return url + path
         return url + '/' + path
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -206,7 +206,7 @@
     else:
         module = __file__
     for f in path:
-        if f.startswith('/'):
+        if f[0] == '/':
             p = f
         else:
             fl = f.split('/')
diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -717,7 +717,7 @@
 
 def endswithsep(path):
     '''Check path ends with os.sep or os.altsep.'''
-    return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
+    return path and (path[-1] == os.sep or os.altsep and path[-1] == os.altsep)
 
 def splitpath(path):
     '''Split path by os.sep.


More information about the Mercurial-devel mailing list