Commits

Carl Friedrich Bolz committed 3e0a1d3

startswith and endswith implementations

Comments (0)

Files changed (2)

rpython/rlib/rstring.py

 """ String builder interface and string functions
 """
+import sys
 
 from rpython.annotator.model import (SomeObject, SomeString, s_None, SomeChar,
     SomeInteger, SomeUnicodeCodePoint, SomeUnicodeString, SomePtr, SomePBC)
 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 -----------------------
 
     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
+
+@specialize.argtype(0)
+@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
+
+@specialize.argtype(0)
+@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 ---------------------------------
 

rpython/rlib/test/test_rstring.py

 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():
     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")
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.