[pypy-svn] r77785 - in pypy/trunk/pypy: config objspace/std objspace/std/test rlib rlib/test rpython rpython/lltypesystem rpython/test

arigo at codespeak.net arigo at codespeak.net
Mon Oct 11 14:35:17 CEST 2010


Author: arigo
Date: Mon Oct 11 14:35:15 2010
New Revision: 77785

Added:
   pypy/trunk/pypy/objspace/std/strbufobject.py
   pypy/trunk/pypy/objspace/std/test/test_strbufobject.py
Modified:
   pypy/trunk/pypy/config/pypyoption.py
   pypy/trunk/pypy/objspace/std/model.py
   pypy/trunk/pypy/objspace/std/stringobject.py
   pypy/trunk/pypy/objspace/std/stringtype.py
   pypy/trunk/pypy/rlib/rstring.py
   pypy/trunk/pypy/rlib/test/test_rstring.py
   pypy/trunk/pypy/rpython/lltypesystem/rbuilder.py
   pypy/trunk/pypy/rpython/rbuilder.py
   pypy/trunk/pypy/rpython/test/test_rbuilder.py
Log:
Experimental (disabled by default): add a W_StringBufferObject,
similar to W_StringJoinObject but based on the StringBuilder class.


Modified: pypy/trunk/pypy/config/pypyoption.py
==============================================================================
--- pypy/trunk/pypy/config/pypyoption.py	(original)
+++ pypy/trunk/pypy/config/pypyoption.py	Mon Oct 11 14:35:15 2010
@@ -198,6 +198,9 @@
         BoolOption("withstrslice", "use strings optimized for slicing",
                    default=False),
 
+        BoolOption("withstrbuf", "use strings optimized for addition (ver 2)",
+                   default=False),
+
         BoolOption("withprebuiltchar",
                    "use prebuilt single-character string objects",
                    default=False),
@@ -210,7 +213,8 @@
         BoolOption("withrope", "use ropes as the string implementation",
                    default=False,
                    requires=[("objspace.std.withstrslice", False),
-                             ("objspace.std.withstrjoin", False)],
+                             ("objspace.std.withstrjoin", False),
+                             ("objspace.std.withstrbuf", False)],
                    suggests=[("objspace.std.withprebuiltchar", True),
                              ("objspace.std.sharesmallstr", True)]),
 

Modified: pypy/trunk/pypy/objspace/std/model.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/model.py	(original)
+++ pypy/trunk/pypy/objspace/std/model.py	Mon Oct 11 14:35:15 2010
@@ -18,6 +18,7 @@
     "withsmallint"   : ["smallintobject.W_SmallIntObject"],
     "withstrslice"   : ["strsliceobject.W_StringSliceObject"],
     "withstrjoin"    : ["strjoinobject.W_StringJoinObject"],
+    "withstrbuf"     : ["strbufobject.W_StringBufferObject"],
     "withrope"       : ["ropeobject.W_RopeObject",
                         "ropeobject.W_RopeIterObject"],
     "withropeunicode": ["ropeunicodeobject.W_RopeUnicodeObject",
@@ -75,6 +76,7 @@
         from pypy.objspace.std import ropeunicodeobject
         from pypy.objspace.std import strsliceobject
         from pypy.objspace.std import strjoinobject
+        from pypy.objspace.std import strbufobject
         from pypy.objspace.std import typeobject
         from pypy.objspace.std import sliceobject
         from pypy.objspace.std import longobject
@@ -222,6 +224,13 @@
                 (unicodeobject.W_UnicodeObject,
                                        strjoinobject.delegate_join2unicode)
                 ]
+        elif config.objspace.std.withstrbuf:
+            self.typeorder[strbufobject.W_StringBufferObject] += [
+                (stringobject.W_StringObject,
+                                       strbufobject.delegate_buf2str),
+                (unicodeobject.W_UnicodeObject,
+                                       strbufobject.delegate_buf2unicode)
+                ]
         if config.objspace.std.withrangelist:
             self.typeorder[rangeobject.W_RangeListObject] += [
                 (listobject.W_ListObject,

Added: pypy/trunk/pypy/objspace/std/strbufobject.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/objspace/std/strbufobject.py	Mon Oct 11 14:35:15 2010
@@ -0,0 +1,76 @@
+from pypy.objspace.std.model import registerimplementation, W_Object
+from pypy.objspace.std.register_all import register_all
+from pypy.objspace.std.stringobject import W_StringObject
+from pypy.objspace.std.unicodeobject import delegate_String2Unicode
+from pypy.rlib.rstring import StringBuilder
+from pypy.interpreter.buffer import Buffer
+
+class W_StringBufferObject(W_Object):
+    from pypy.objspace.std.stringtype import str_typedef as typedef
+
+    w_str = None
+
+    def __init__(self, builder):
+        self.builder = builder             # StringBuilder
+        self.length = builder.getlength()
+
+    def force(self):
+        if self.w_str is None:
+            s = self.builder.build()
+            if self.length < len(s):
+                s = s[:self.length]
+            self.w_str = W_StringObject(s)
+            return s
+        else:
+            return self.w_str._value
+
+    def __repr__(w_self):
+        """ representation for debugging purposes """
+        return "%s(%r[:%d])" % (
+            w_self.__class__.__name__, w_self.builder, w_self.length)
+
+    def unwrap(self, space):
+        return self.force()
+
+registerimplementation(W_StringBufferObject)
+
+# ____________________________________________________________
+
+def joined2(str1, str2):
+    builder = StringBuilder()
+    builder.append(str1)
+    builder.append(str2)
+    return W_StringBufferObject(builder)
+
+# ____________________________________________________________
+
+def delegate_buf2str(space, w_strbuf):
+    w_strbuf.force()
+    return w_strbuf.w_str
+
+def delegate_buf2unicode(space, w_strbuf):
+    w_strbuf.force()
+    return delegate_String2Unicode(space, w_strbuf.w_str)
+
+def len__StringBuffer(space, w_self):
+    return space.wrap(w_self.length)
+
+def str_w__StringBuffer(space, w_strbuf):
+    return w_strbuf.force()
+
+def add__StringBuffer_String(space, w_self, w_other):
+    if w_self.builder.getlength() != w_self.length:
+        builder = StringBuilder()
+        builder.append(w_self.force())
+    else:
+        builder = w_self.builder
+    builder.append(w_other._value)
+    return W_StringBufferObject(builder)
+
+def str__StringBuffer(space, w_self):
+    # you cannot get subclasses of W_StringBufferObject here
+    assert type(w_self) is W_StringBufferObject
+    return w_self
+
+from pypy.objspace.std import stringtype
+register_all(vars(), stringtype)

Modified: pypy/trunk/pypy/objspace/std/stringobject.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/stringobject.py	(original)
+++ pypy/trunk/pypy/objspace/std/stringobject.py	Mon Oct 11 14:35:15 2010
@@ -14,7 +14,7 @@
 from pypy.rlib.rstring import StringBuilder, string_repeat
 from pypy.interpreter.buffer import StringBuffer
 
-from pypy.objspace.std.stringtype import sliced, joined, wrapstr, wrapchar, \
+from pypy.objspace.std.stringtype import sliced, wrapstr, wrapchar, \
      stringendswith, stringstartswith, joined2
 
 from pypy.objspace.std.formatting import mod_format

Modified: pypy/trunk/pypy/objspace/std/stringtype.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/stringtype.py	(original)
+++ pypy/trunk/pypy/objspace/std/stringtype.py	Mon Oct 11 14:35:15 2010
@@ -55,19 +55,14 @@
             return W_StringSliceObject(s, start, stop)
     return wrapstr(space, s[start:stop])
 
-def joined(space, strlist):
-    assert not space.config.objspace.std.withrope
-    if space.config.objspace.std.withstrjoin:
-        from pypy.objspace.std.strjoinobject import W_StringJoinObject
-        return W_StringJoinObject(strlist)
-    else:
-        return wrapstr(space, "".join(strlist))
-
 def joined2(space, str1, str2):
     assert not space.config.objspace.std.withrope
     if space.config.objspace.std.withstrjoin:
         from pypy.objspace.std.strjoinobject import W_StringJoinObject
         return W_StringJoinObject([str1, str2])
+    elif space.config.objspace.std.withstrbuf:
+        from pypy.objspace.std.strbufobject import joined2
+        return joined2(str1, str2)
     else:
         return wrapstr(space, str1 + str2)
 

Added: pypy/trunk/pypy/objspace/std/test/test_strbufobject.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/objspace/std/test/test_strbufobject.py	Mon Oct 11 14:35:15 2010
@@ -0,0 +1,78 @@
+import py
+
+from pypy.objspace.std.test import test_stringobject
+from pypy.conftest import gettestobjspace
+
+class AppTestStringObject(test_stringobject.AppTestStringObject):
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withstrbuf": True})
+
+    def test_basic(self):
+        import __pypy__
+        # cannot do "Hello, " + "World!" because cpy2.5 optimises this
+        # away on AST level
+        s = "Hello, ".__add__("World!")
+        assert type(s) is str
+        assert 'W_StringBufferObject' in __pypy__.internal_repr(s)
+
+    def test_add_twice(self):
+        x = "a".__add__("b")
+        y = x + "c"
+        c = x + "d"
+        assert y == "abc"
+        assert c == "abd"
+
+    def test_add(self):
+        import __pypy__
+        all = ""
+        for i in range(20):
+            all += str(i)
+        assert 'W_StringBufferObject' in __pypy__.internal_repr(all)
+        assert all == "012345678910111213141516171819"
+
+    def test_hash(self):
+        import __pypy__
+        def join(s): return s[:len(s) // 2] + s[len(s) // 2:]
+        t = 'a' * 101
+        s = join(t)
+        assert 'W_StringBufferObject' in __pypy__.internal_repr(s)
+        assert hash(s) == hash(t)
+
+    def test_len(self):
+        s = "a".__add__("b")
+        r = "c".__add__("d")
+        t = s + r
+        assert len(s) == 2
+        assert len(r) == 2
+        assert len(t) == 4
+
+    def test_add_strbuf(self):
+        # make three strbuf objects
+        s = 'a'.__add__('b')
+        t = 'x'.__add__('c')
+        u = 'y'.__add__('d')
+
+        # add two different strbufs to the same string
+        v = s + t
+        w = s + u
+
+        # check that insanity hasn't resulted.
+        assert v == "abxc"
+        assert w == "abyd"
+
+    def test_more_adding_fun(self):
+        s = 'a'.__add__('b') # s is a strbuf now
+        t = s + 'c'
+        u = s + 'd'
+        v = s + 'e'
+        assert v == 'abe'
+        assert u == 'abd'
+        assert t == 'abc'
+
+    def test_buh_even_more(self):
+        a = 'a'.__add__('b')
+        b = a + 'c'
+        c = '0'.__add__('1')
+        x = c + a
+        assert x == '01ab'

Modified: pypy/trunk/pypy/rlib/rstring.py
==============================================================================
--- pypy/trunk/pypy/rlib/rstring.py	(original)
+++ pypy/trunk/pypy/rlib/rstring.py	Mon Oct 11 14:35:15 2010
@@ -54,6 +54,7 @@
         self.l = []
 
     def append(self, s):
+        assert isinstance(s, self._type)
         self.l.append(s)
 
     def append_slice(self, s, start, end):
@@ -63,11 +64,16 @@
     def append_multiple_char(self, c, times):
         self.l.append(c * times)
 
+    def getlength(self):
+        return len(self.build())
+
 class StringBuilder(AbstractStringBuilder):
+    _type = str
     def build(self):
         return "".join(self.l)
 
 class UnicodeBuilder(AbstractStringBuilder):
+    _type = unicode
     def build(self):
         return u''.join(self.l)
 
@@ -121,9 +127,12 @@
         assert s_times.nonneg
         return s_None
 
+    def method_getlength(self):
+        return SomeInteger(nonneg=True)
+
     def method_build(self):
         return SomeString()
-    
+
     def rtyper_makerepr(self, rtyper):
         return rtyper.type_system.rbuilder.stringbuilder_repr
 
@@ -146,6 +155,9 @@
         assert s_times.nonneg
         return s_None
 
+    def method_getlength(self):
+        return SomeInteger(nonneg=True)
+
     def method_build(self):
         return SomeUnicodeString()
     

Modified: pypy/trunk/pypy/rlib/test/test_rstring.py
==============================================================================
--- pypy/trunk/pypy/rlib/test/test_rstring.py	(original)
+++ pypy/trunk/pypy/rlib/test/test_rstring.py	Mon Oct 11 14:35:15 2010
@@ -29,6 +29,7 @@
     s = StringBuilder()
     s.append("a")
     s.append("abc")
+    assert s.getlength() == len('aabc')
     s.append("a")
     s.append_slice("abc", 1, 2)
     s.append_multiple_char('d', 4)
@@ -39,6 +40,7 @@
     s.append(u'a')
     s.append(u'abc')
     s.append_slice(u'abcdef', 1, 2)
+    assert s.getlength() == len('aabcb')
     s.append_multiple_char('d', 4)
     assert s.build() == 'aabcbdddd'
     assert isinstance(s.build(), unicode)

Modified: pypy/trunk/pypy/rpython/lltypesystem/rbuilder.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/rbuilder.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/rbuilder.py	Mon Oct 11 14:35:15 2010
@@ -100,6 +100,10 @@
         ll_builder.used = used
 
     @staticmethod
+    def ll_getlength(ll_builder):
+        return ll_builder.used
+
+    @staticmethod
     def ll_build(ll_builder):
         final_size = ll_builder.used
         assert final_size >= 0

Modified: pypy/trunk/pypy/rpython/rbuilder.py
==============================================================================
--- pypy/trunk/pypy/rpython/rbuilder.py	(original)
+++ pypy/trunk/pypy/rpython/rbuilder.py	Mon Oct 11 14:35:15 2010
@@ -36,8 +36,12 @@
         hop.exception_cannot_occur()
         return hop.gendirectcall(self.ll_append_multiple_char, *vlist)
 
+    def rtype_method_getlength(self, hop):
+        vlist = hop.inputargs(self)
+        hop.exception_cannot_occur()
+        return hop.gendirectcall(self.ll_getlength, *vlist)
+
     def rtype_method_build(self, hop):
         vlist = hop.inputargs(self)
         hop.exception_cannot_occur()
         return hop.gendirectcall(self.ll_build, *vlist)
-

Modified: pypy/trunk/pypy/rpython/test/test_rbuilder.py
==============================================================================
--- pypy/trunk/pypy/rpython/test/test_rbuilder.py	(original)
+++ pypy/trunk/pypy/rpython/test/test_rbuilder.py	Mon Oct 11 14:35:15 2010
@@ -1,4 +1,4 @@
-
+import py
 from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
 from pypy.rpython.lltypesystem.rbuilder import *
 from pypy.rpython.annlowlevel import llstr, hlstr
@@ -55,8 +55,29 @@
         assert res == 'aabcabcdefbuuuu'
         assert isinstance(res, unicode)
 
+    def test_string_getlength(self):
+        def func():
+            s = StringBuilder()
+            s.append("a")
+            s.append("abc")
+            return s.getlength()
+        res = self.interpret(func, [])
+        assert res == 4
+
+    def test_unicode_getlength(self):
+        def func():
+            s = UnicodeBuilder()
+            s.append(u"a")
+            s.append(u"abc")
+            return s.getlength()
+        res = self.interpret(func, [])
+        assert res == 4
+
 class TestLLtype(BaseTestStringBuilder, LLRtypeMixin):
     pass
 
 class TestOOtype(BaseTestStringBuilder, OORtypeMixin):
-    pass
+    def test_string_getlength(self):
+        py.test.skip("getlength(): not implemented on ootype")
+    def test_unicode_getlength(self):
+        py.test.skip("getlength(): not implemented on ootype")



More information about the Pypy-commit mailing list