[pypy-commit] pypy default: move an optimization from stringobject.py to rstring.py

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


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: 
Changeset: r64904:70f3823a6ba8
Date: 2013-06-13 22:33 +0200
http://bitbucket.org/pypy/pypy/changeset/70f3823a6ba8/

Log:	move an optimization from stringobject.py to rstring.py

diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -16,7 +16,7 @@
 from rpython.rlib.objectmodel import (
     compute_hash, compute_unique_id, specialize)
 from rpython.rlib.rarithmetic import ovfcheck
-from rpython.rlib.rstring import StringBuilder, split
+from rpython.rlib.rstring import StringBuilder, split, rsplit
 
 
 class W_AbstractStringObject(W_Object):
@@ -287,31 +287,12 @@
     bylen = len(by)
     if bylen == 0:
         raise OperationError(space.w_ValueError, space.wrap("empty separator"))
-
-    if bylen == 1 and maxsplit < 0:
-        res = []
-        start = 0
-        # fast path: uses str.rfind(character) and str.count(character)
-        by = by[0]    # annotator hack: string -> char
-        count = value.count(by)
-        res = [None] * (count + 1)
-        end = len(value)
-        while count >= 0:
-            assert end >= 0
-            prev = value.rfind(by, 0, end)
-            start = prev + 1
-            assert start >= 0
-            res[count] = value[start:end]
-            count -= 1
-            end = prev
-    else:
-        res = split(value, by, maxsplit)
-
+    res = split(value, by, maxsplit)
     return space.newlist_str(res)
 
 def str_rsplit__String_None_ANY(space, w_self, w_none, w_maxsplit=-1):
     maxsplit = space.int_w(w_maxsplit)
-    res_w = []
+    res = []
     value = w_self._value
     i = len(value)-1
     while True:
@@ -336,20 +317,19 @@
         # the word is value[j+1:i+1]
         j1 = j + 1
         assert j1 >= 0
-        res_w.append(sliced(space, value, j1, i+1, w_self))
+        res.append(value[j1:i+1])
 
         # continue to look from the character before the space before the word
         i = j - 1
 
-    res_w.reverse()
-    return space.newlist(res_w)
+    res.reverse()
+    return space.newlist_str(res)
 
 def make_rsplit_with_delim(funcname, sliced):
     from rpython.tool.sourcetools import func_with_new_name
 
     def fn(space, w_self, w_by, w_maxsplit=-1):
         maxsplit = space.int_w(w_maxsplit)
-        res_w = []
         value = w_self._value
         end = len(value)
         by = w_by._value
@@ -357,6 +337,7 @@
         if bylen == 0:
             raise OperationError(space.w_ValueError, space.wrap("empty separator"))
 
+        res_w = []
         while maxsplit != 0:
             next = value.rfind(by, 0, end)
             if next < 0:
@@ -371,8 +352,13 @@
 
     return func_with_new_name(fn, funcname)
 
-str_rsplit__String_String_ANY = make_rsplit_with_delim('str_rsplit__String_String_ANY',
-                                                       sliced)
+def str_rsplit__String_String_ANY(space, w_self, w_by, w_maxsplit=-1):
+    maxsplit = space.int_w(w_maxsplit)
+    value = w_self._value
+    by = w_by._value
+    if not by:
+        raise OperationError(space.w_ValueError, space.wrap("empty separator"))
+    return space.newlist_str(rsplit(value, by, maxsplit))
 
 def str_join__String_ANY(space, w_self, w_list):
     l = space.listview_str(w_list)
diff --git a/pypy/objspace/std/test/test_liststrategies.py b/pypy/objspace/std/test/test_liststrategies.py
--- a/pypy/objspace/std/test/test_liststrategies.py
+++ b/pypy/objspace/std/test/test_liststrategies.py
@@ -555,10 +555,14 @@
         try:
             w_l = space.call_method(w_s, "split")
             w_l2 = space.call_method(w_s, "split", space.wrap(" "))
+            w_l3 = space.call_method(w_s, "rsplit")
+            w_l4 = space.call_method(w_s, "rsplit", space.wrap(" "))
         finally:
             del space.newlist
         assert space.listview_str(w_l) == ["a", "b", "c"]
         assert space.listview_str(w_l2) == ["a", "b", "c"]
+        assert space.listview_str(w_l3) == ["a", "b", "c"]
+        assert space.listview_str(w_l4) == ["a", "b", "c"]
 
     def test_unicode_uses_newlist_unicode(self):
         space = self.space
@@ -567,10 +571,14 @@
         try:
             w_l = space.call_method(w_u, "split")
             w_l2 = space.call_method(w_u, "split", space.wrap(" "))
+            w_l3 = space.call_method(w_u, "rsplit")
+            w_l4 = space.call_method(w_u, "rsplit", space.wrap(" "))
         finally:
             del space.newlist
         assert space.listview_unicode(w_l) == [u"a", u"b", u"c"]
         assert space.listview_unicode(w_l2) == [u"a", u"b", u"c"]
+        assert space.listview_unicode(w_l3) == [u"a", u"b", u"c"]
+        assert space.listview_unicode(w_l4) == [u"a", u"b", u"c"]
 
     def test_pop_without_argument_is_fast(self):
         space = self.space
diff --git a/rpython/rlib/rstring.py b/rpython/rlib/rstring.py
--- a/rpython/rlib/rstring.py
+++ b/rpython/rlib/rstring.py
@@ -18,11 +18,27 @@
     if bylen == 0:
         raise ValueError("empty separator")
 
+    start = 0
+    if bylen == 1:
+        # fast path: uses str.rfind(character) and str.count(character)
+        by = by[0]    # annotator hack: string -> char
+        count = value.count(by)
+        if 0 <= maxsplit < count:
+            count = maxsplit
+        res = newlist_hint(count + 1)
+        while count > 0:
+            next = value.find(by, start)
+            res.append(value[start:next])
+            start = next + bylen
+            count -= 1
+        res.append(value[start:len(value)])
+        return res
+
     if maxsplit > 0:
         res = newlist_hint(min(maxsplit + 1, len(value)))
     else:
         res = []
-    start = 0
+
     while maxsplit != 0:
         next = value.find(by, start)
         if next < 0:
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
@@ -10,6 +10,7 @@
     assert split('a|b|c|d', '|') == ['a', 'b', 'c', 'd']
     assert split('a|b|c|d', '|', 2) == ['a', 'b', 'c|d']
     assert split('a//b//c//d', '//') == ['a', 'b', 'c', 'd']
+    assert split('a//b//c//d', '//', 2) == ['a', 'b', 'c//d']
     assert split('endcase test', 'test') == ['endcase ', '']
     py.test.raises(ValueError, split, 'abc', '')
 


More information about the pypy-commit mailing list