[pypy-commit] pypy default: switch struct to use StringBuilder internally

alex_gaynor noreply at buildbot.pypy.org
Mon Mar 5 19:22:15 CET 2012


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: 
Changeset: r53239:73cc3b2ca760
Date: 2012-03-05 13:21 -0500
http://bitbucket.org/pypy/pypy/changeset/73cc3b2ca760/

Log:	switch struct to use StringBuilder internally

diff --git a/pypy/interpreter/buffer.py b/pypy/interpreter/buffer.py
--- a/pypy/interpreter/buffer.py
+++ b/pypy/interpreter/buffer.py
@@ -20,6 +20,7 @@
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.error import OperationError
 from pypy.rlib.objectmodel import compute_hash
+from pypy.rlib.rstring import StringBuilder
 
 
 class Buffer(Wrappable):
@@ -152,12 +153,13 @@
     if space.isinstance_w(w_object, space.w_unicode):
         # unicode objects support the old buffer interface
         # but not the new buffer interface (change in python  2.7)
-        from pypy.rlib.rstruct.unichar import pack_unichar
-        charlist = []
-        for unich in space.unicode_w(w_object):
-            pack_unichar(unich, charlist)
+        from pypy.rlib.rstruct.unichar import pack_unichar, UNICODE_SIZE
+        unistr = space.unicode_w(w_object)
+        builder = StringBuilder(len(unistr) * UNICODE_SIZE)
+        for unich in unistr:
+            pack_unichar(unich, builder)
         from pypy.interpreter.buffer import StringBuffer
-        w_buffer = space.wrap(StringBuffer(''.join(charlist)))
+        w_buffer = space.wrap(StringBuffer(builder.build()))
     else:
         w_buffer = space.buffer(w_object)
 
diff --git a/pypy/module/struct/formatiterator.py b/pypy/module/struct/formatiterator.py
--- a/pypy/module/struct/formatiterator.py
+++ b/pypy/module/struct/formatiterator.py
@@ -1,5 +1,6 @@
 from pypy.rlib import jit
 from pypy.rlib.objectmodel import specialize
+from pypy.rlib.rstring import StringBuilder
 from pypy.rlib.rstruct.error import StructError
 from pypy.rlib.rstruct.formatiterator import FormatIterator
 from pypy.rlib.rstruct.standardfmttable import PACK_ACCEPTS_BROKEN_INPUT
@@ -8,11 +9,11 @@
 
 class PackFormatIterator(FormatIterator):
 
-    def __init__(self, space, args_w):
+    def __init__(self, space, args_w, size):
         self.space = space
         self.args_w = args_w
         self.args_index = 0
-        self.result = []      # list of characters
+        self.result = StringBuilder(size)
 
     # This *should* be always unroll safe, the only way to get here is by
     # unroll the interpret function, which means the fmt is const, and thus
@@ -29,9 +30,8 @@
 
     @jit.unroll_safe
     def align(self, mask):
-        pad = (-len(self.result)) & mask
-        for i in range(pad):
-            self.result.append('\x00')
+        pad = (-self.result.getlength()) & mask
+        self.result.append_multiple_char('\x00', pad)
 
     def finished(self):
         if self.args_index != len(self.args_w):
diff --git a/pypy/module/struct/interp_struct.py b/pypy/module/struct/interp_struct.py
--- a/pypy/module/struct/interp_struct.py
+++ b/pypy/module/struct/interp_struct.py
@@ -1,28 +1,34 @@
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.module.struct.formatiterator import PackFormatIterator, UnpackFormatIterator
+from pypy.rlib import jit
 from pypy.rlib.rstruct.error import StructError
 from pypy.rlib.rstruct.formatiterator import CalcSizeFormatIterator
 
 
 @unwrap_spec(format=str)
 def calcsize(space, format):
+    return space.wrap(_calcsize(space, format))
+
+def _calcsize(space, format):
     fmtiter = CalcSizeFormatIterator()
     try:
         fmtiter.interpret(format)
     except StructError, e:
         raise e.at_applevel(space)
-    return space.wrap(fmtiter.totalsize)
-
+    return fmtiter.totalsize
 
 @unwrap_spec(format=str)
 def pack(space, format, args_w):
-    fmtiter = PackFormatIterator(space, args_w)
+    if jit.isconstant(format):
+        size = _calcsize(space, format)
+    else:
+        size = 8
+    fmtiter = PackFormatIterator(space, args_w, size)
     try:
         fmtiter.interpret(format)
     except StructError, e:
         raise e.at_applevel(space)
-    result = ''.join(fmtiter.result)
-    return space.wrap(result)
+    return space.wrap(fmtiter.result.build())
 
 
 @unwrap_spec(format=str, input='bufferstr')
diff --git a/pypy/module/struct/test/test_ztranslation.py b/pypy/module/struct/test/test_ztranslation.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/struct/test/test_ztranslation.py
@@ -0,0 +1,6 @@
+from pypy.objspace.fake.checkmodule import checkmodule
+
+
+def test_checkmodule():
+    checkmodule('struct')
+
diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py
--- a/pypy/objspace/std/marshal_impl.py
+++ b/pypy/objspace/std/marshal_impl.py
@@ -16,6 +16,7 @@
 from pypy.interpreter.pycode import PyCode
 from pypy.interpreter import gateway, unicodehelper
 from pypy.rlib.rstruct import ieee
+from pypy.rlib.rstring import StringBuilder
 
 from pypy.objspace.std.boolobject    import W_BoolObject
 from pypy.objspace.std.complexobject import W_ComplexObject
@@ -153,9 +154,9 @@
 register(TYPE_INT64, unmarshal_Int64)
 
 def pack_float(f):
-    result = []
+    result = StringBuilder(8)
     ieee.pack_float(result, f, 8, False)
-    return ''.join(result)
+    return result.build()
 
 def unpack_float(s):
     return ieee.unpack_float(s, False)
diff --git a/pypy/objspace/std/ropeunicodeobject.py b/pypy/objspace/std/ropeunicodeobject.py
--- a/pypy/objspace/std/ropeunicodeobject.py
+++ b/pypy/objspace/std/ropeunicodeobject.py
@@ -8,6 +8,7 @@
 from pypy.objspace.std.ropeobject import W_RopeObject
 from pypy.objspace.std.noneobject import W_NoneObject
 from pypy.rlib import rope
+from pypy.rlib.rstring import StringBuilder
 from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
 from pypy.objspace.std import unicodeobject, slicetype, iterobject
 from pypy.objspace.std.tupleobject import W_TupleObject
@@ -946,15 +947,16 @@
     return mod_format(space, w_format, w_values, do_unicode=True)
 
 def buffer__RopeUnicode(space, w_unicode):
-    from pypy.rlib.rstruct.unichar import pack_unichar
-    charlist = []
+    from pypy.rlib.rstruct.unichar import pack_unichar, UNICODE_SIZE
     node = w_unicode._node
     iter = rope.ItemIterator(node)
-    for idx in range(node.length()):
+    length = node.length()
+    builder = StringBuilder(length * UNICODE_SIZE)
+    for idx in range(length):
         unich = unichr(iter.nextint())
-        pack_unichar(unich, charlist)
+        pack_unichar(unich, builder)
     from pypy.interpreter.buffer import StringBuffer
-    return space.wrap(StringBuffer(''.join(charlist)))
+    return space.wrap(StringBuffer(builder.build()))
 
 
 # methods of the iterator
diff --git a/pypy/rlib/rstruct/ieee.py b/pypy/rlib/rstruct/ieee.py
--- a/pypy/rlib/rstruct/ieee.py
+++ b/pypy/rlib/rstruct/ieee.py
@@ -136,13 +136,13 @@
 
 
 def pack_float(result, x, size, be):
-    l = [] if be else result
+    l = []
     unsigned = float_pack(x, size)
     for i in range(size):
         l.append(chr((unsigned >> (i * 8)) & 0xFF))
     if be:
         l.reverse()
-        result.extend(l)
+    result.append("".join(l))
 
 
 def unpack_float(s, be):
diff --git a/pypy/rlib/rstruct/nativefmttable.py b/pypy/rlib/rstruct/nativefmttable.py
--- a/pypy/rlib/rstruct/nativefmttable.py
+++ b/pypy/rlib/rstruct/nativefmttable.py
@@ -29,8 +29,7 @@
     doubleval = fmtiter.accept_float_arg()
     double_buf[0] = doubleval
     p = rffi.cast(rffi.CCHARP, double_buf)
-    for i in range(sizeof_double):
-        fmtiter.result.append(p[i])
+    fmtiter.result.append_charpsize(p, rffi.sizeof(rffi.DOUBLE))
 
 @specialize.argtype(0)
 def unpack_double(fmtiter):
@@ -46,8 +45,7 @@
     floatval = r_singlefloat(doubleval)
     float_buf[0] = floatval
     p = rffi.cast(rffi.CCHARP, float_buf)
-    for i in range(sizeof_float):
-        fmtiter.result.append(p[i])
+    fmtiter.result.append_charpsize(p, rffi.sizeof(rffi.FLOAT))
 
 @specialize.argtype(0)
 def unpack_float(fmtiter):
diff --git a/pypy/rlib/rstruct/standardfmttable.py b/pypy/rlib/rstruct/standardfmttable.py
--- a/pypy/rlib/rstruct/standardfmttable.py
+++ b/pypy/rlib/rstruct/standardfmttable.py
@@ -21,8 +21,7 @@
 # ____________________________________________________________
 
 def pack_pad(fmtiter, count):
-    for i in range(count):
-        fmtiter.result.append('\x00')
+    fmtiter.result.append_multiple_char('\x00', count)
 
 def pack_char(fmtiter):
     string = fmtiter.accept_str_arg()
@@ -38,11 +37,10 @@
 def pack_string(fmtiter, count):
     string = fmtiter.accept_str_arg()
     if len(string) < count:
-        fmtiter.result += string
-        for i in range(len(string), count):
-            fmtiter.result.append('\x00')
+        fmtiter.result.append(string)
+        fmtiter.result.append_multiple_char('\x00', count - len(string))
     else:
-        fmtiter.result += string[:count]
+        fmtiter.result.append_slice(string, 0, count)
 
 def pack_pascal(fmtiter, count):
     string = fmtiter.accept_str_arg()
@@ -56,9 +54,8 @@
     else:
         prefixchar = chr(prefix)
     fmtiter.result.append(prefixchar)
-    fmtiter.result += string[:prefix]
-    for i in range(1 + prefix, count):
-        fmtiter.result.append('\x00')
+    fmtiter.result.append_slice(string, 0, prefix)
+    fmtiter.result.append_multiple_char('\x00', count - (1 + prefix))
 
 def make_float_packer(size):
     def packer(fmtiter):


More information about the pypy-commit mailing list