[pypy-commit] pypy default: startswith and endswith implementations

cfbolz noreply at buildbot.pypy.org
Mon Jun 17 14:35:29 CEST 2013


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: 
Changeset: r64913:3e0a1d3ed9e0
Date: 2013-06-16 09:50 +0200
http://bitbucket.org/pypy/pypy/changeset/3e0a1d3ed9e0/

Log:	startswith and endswith implementations

diff --git a/rpython/rlib/rstring.py b/rpython/rlib/rstring.py
--- a/rpython/rlib/rstring.py
+++ b/rpython/rlib/rstring.py
@@ -1,5 +1,6 @@
 """ String builder interface and string functions
 """
+import sys
 
 from rpython.annotator.model import (SomeObject, SomeString, s_None, SomeChar,
     SomeInteger, SomeUnicodeCodePoint, SomeUnicodeString, SomePtr, SomePBC)
@@ -7,6 +8,7 @@
 from rpython.rlib.rarithmetic import ovfcheck
 from rpython.rtyper.extregistry import ExtRegistryEntry
 from rpython.tool.pairtype import pairtype
+from rpython.rlib import jit
 
 
 # -------------- public API for string functions -----------------------
@@ -145,6 +147,45 @@
 
     return builder.build()
 
+def _normalize_start_end(length, start, end):
+    if start < 0:
+        start += length
+        if start < 0:
+            start = 0
+    if end < 0:
+        end += length
+        if end < 0:
+            end = 0
+    elif end > length:
+        end = length
+    return start, end
+
+ at specialize.argtype(0)
+ at jit.elidable
+def startswith(u_self, prefix, start=0, end=sys.maxint):
+    length = len(u_self)
+    start, end = _normalize_start_end(length, start, end)
+    stop = start + len(prefix)
+    if stop > end:
+        return False
+    for i in range(len(prefix)):
+        if u_self[start+i] != prefix[i]:
+            return False
+    return True
+
+ at specialize.argtype(0)
+ at jit.elidable
+def endswith(u_self, suffix, start=0, end=sys.maxint):
+    length = len(u_self)
+    start, end = _normalize_start_end(length, start, end)
+    begin = end - len(suffix)
+    if begin < start:
+        return False
+    for i in range(len(suffix)):
+        if u_self[begin+i] != suffix[i]:
+            return False
+    return True
+
 
 # -------------- public API ---------------------------------
 
diff --git a/rpython/rlib/test/test_rstring.py b/rpython/rlib/test/test_rstring.py
--- a/rpython/rlib/test/test_rstring.py
+++ b/rpython/rlib/test/test_rstring.py
@@ -1,7 +1,7 @@
 import sys, py
 
 from rpython.rlib.rstring import StringBuilder, UnicodeBuilder, split, rsplit
-from rpython.rlib.rstring import replace
+from rpython.rlib.rstring import replace, startswith, endswith
 from rpython.rtyper.test.tool import BaseRtypingTest, LLRtypeMixin
 
 def test_split():
@@ -111,6 +111,37 @@
     with py.test.raises(OverflowError):
         replace(s, u"a", s, len(s) - 10)
 
+def test_startswith():
+    assert startswith('ab', 'ab') is True
+    assert startswith('ab', 'a') is True
+    assert startswith('ab', '') is True
+    assert startswith('x', 'a') is False
+    assert startswith('x', 'x') is True
+    assert startswith('', '') is True
+    assert startswith('', 'a') is False
+    assert startswith('x', 'xx') is False
+    assert startswith('y', 'xx') is False
+    assert startswith('ab', 'a', 0) is True
+    assert startswith('ab', 'a', 1) is False
+    assert startswith('ab', 'b', 1) is True
+    assert startswith('abc', 'bc', 1, 2) is False
+    assert startswith('abc', 'c', -1, 4) is True
+
+def test_endswith():
+    assert endswith('ab', 'ab') is True
+    assert endswith('ab', 'b') is True
+    assert endswith('ab', '') is True
+    assert endswith('x', 'a') is False
+    assert endswith('x', 'x') is True
+    assert endswith('', '') is True
+    assert endswith('', 'a') is False
+    assert endswith('x', 'xx') is False
+    assert endswith('y', 'xx') is False
+    assert endswith('abc', 'ab', 0, 2) is True
+    assert endswith('abc', 'bc', 1) is True
+    assert endswith('abc', 'bc', 2) is False
+    assert endswith('abc', 'b', -3, -1) is True
+
 def test_string_builder():
     s = StringBuilder()
     s.append("a")


More information about the pypy-commit mailing list