Author: Antonio Cuni <[email protected]>
Branch: faster-rstruct
Changeset: r80670:9972a7f270d5
Date: 2015-11-13 19:01 +0100
http://bitbucket.org/pypy/pypy/changeset/9972a7f270d5/

Log:    use the fast raw_storage unpacking also for integer types, when
        possible

diff --git a/rpython/rlib/rstruct/nativefmttable.py 
b/rpython/rlib/rstruct/nativefmttable.py
--- a/rpython/rlib/rstruct/nativefmttable.py
+++ b/rpython/rlib/rstruct/nativefmttable.py
@@ -8,6 +8,7 @@
 from rpython.rlib.objectmodel import specialize
 from rpython.rlib.rarithmetic import r_singlefloat, widen
 from rpython.rlib.rstruct import standardfmttable as std
+from rpython.rlib.rstruct.standardfmttable import native_is_bigendian
 from rpython.rlib.rstruct.error import StructError
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rlib.rawstorage import str_storage_getitem
@@ -16,8 +17,6 @@
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
 
 
-native_is_bigendian = struct.pack("=i", 1) == struct.pack(">i", 1)
-
 native_fmttable = {
     'x': std.standard_fmttable['x'],
     'c': std.standard_fmttable['c'],
diff --git a/rpython/rlib/rstruct/standardfmttable.py 
b/rpython/rlib/rstruct/standardfmttable.py
--- a/rpython/rlib/rstruct/standardfmttable.py
+++ b/rpython/rlib/rstruct/standardfmttable.py
@@ -12,7 +12,11 @@
 from rpython.rlib.rstruct import ieee
 from rpython.rlib.rstruct.error import StructError, StructOverflowError
 from rpython.rlib.unroll import unrolling_iterable
+from rpython.rlib.rawstorage import str_storage_getitem
+from rpython.rlib import rarithmetic
+from rpython.rtyper.lltypesystem import rffi
 
+native_is_bigendian = struct.pack("=i", 1) == struct.pack(">i", 1)
 
 def pack_pad(fmtiter, count):
     fmtiter.result.append_multiple_char('\x00', count)
@@ -162,6 +166,15 @@
 
 # ____________________________________________________________
 
+def get_rffi_int_type(size, signed):
+    for TYPE in rffi.platform.numbertype_to_rclass:
+        if (rffi.sizeof(TYPE) == size and
+            rarithmetic.is_signed_integer_type(TYPE) == signed):
+            return TYPE
+    raise KeyError("Cannot find an int type size=%d, signed=%d" % (size, 
signed))
+
+UNPACK_ALLOW_RAW_STORAGE = True
+
 def make_int_unpacker(size, signed, _memo={}):
     try:
         return _memo[size, signed]
@@ -180,13 +193,20 @@
         else:
             inttype = r_ulonglong
     unroll_range_size = unrolling_iterable(range(size))
+    TYPE = get_rffi_int_type(size, signed)
 
     @specialize.argtype(0)
     def unpack_int(fmtiter):
         intvalue = inttype(0)
         s = fmtiter.read(size)
         idx = 0
-        if fmtiter.bigendian:
+        if UNPACK_ALLOW_RAW_STORAGE and fmtiter.bigendian == 
native_is_bigendian:
+            # fast path, using the native raw_storage
+            intvalue = str_storage_getitem(TYPE, s, 0)
+            if not signed and size < native_int_size:
+                intvalue = rarithmetic.intmask(intvalue)
+            intvalue = inttype(intvalue)
+        elif fmtiter.bigendian:
             for i in unroll_range_size:
                 x = ord(s[idx])
                 if signed and i == 0 and x >= 128:
diff --git a/rpython/rlib/rstruct/test/test_runpack.py 
b/rpython/rlib/rstruct/test/test_runpack.py
--- a/rpython/rlib/rstruct/test/test_runpack.py
+++ b/rpython/rlib/rstruct/test/test_runpack.py
@@ -1,5 +1,6 @@
 from rpython.rtyper.test.tool import BaseRtypingTest
 from rpython.rlib.rstruct.runpack import runpack
+from rpython.rlib.rstruct import standardfmttable
 from rpython.rlib.rarithmetic import LONG_BIT
 import struct
 
@@ -55,3 +56,37 @@
         assert d == 12.34     # no precision lost
         assert f != 12.34     # precision lost
         assert abs(f - 12.34) < 1E-6
+
+    def test_unpack_standard_little(self):
+        def unpack(fmt, data):
+            def fn():
+                return runpack(fmt, data)
+            return self.interpret(fn, [])
+        #
+        assert unpack("<i", 'DCBA') == 0x41424344
+        assert unpack("<i", '\xfd\xff\xff\xff') == -3
+        assert unpack("<i", '\x00\x00\x00\x80') == -2147483648
+        assert unpack("<I", 'DCB\x81') == 0x81424344
+        assert unpack("<q", 'HGFEDCBA') == 0x4142434445464748
+        assert unpack("<q", 'HHIJKLM\xbe') == -0x41B2B3B4B5B6B7B8
+        assert unpack("<Q", 'HGFEDCB\x81') == 0x8142434445464748
+
+    def test_unpack_standard_big(self):
+        def unpack(fmt, data):
+            def fn():
+                return runpack(fmt, data)
+            return self.interpret(fn, [])
+        #
+        assert unpack(">i", 'ABCD') == 0x41424344
+        assert unpack(">i", '\xff\xff\xff\xfd') == -3
+        assert unpack(">i", '\x80\x00\x00\x00') == -2147483648
+        assert unpack(">I", '\x81BCD') == 0x81424344
+        assert unpack(">q", 'ABCDEFGH') == 0x4142434445464748
+        assert unpack(">q", '\xbeMLKJIHH') == -0x41B2B3B4B5B6B7B8
+        assert unpack(">Q", '\x81BCDEFGH') == 0x8142434445464748
+
+    def test_unpack_standard_no_raw_storage(self, monkeypatch):
+        monkeypatch.setattr(standardfmttable, 'UNPACK_ALLOW_RAW_STORAGE', 
False)
+        self.test_unpack_standard_little()
+        self.test_unpack_standard_big()
+
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to