[pypy-svn] r46939 - in pypy/dist/pypy/module/struct: . test

arigo at codespeak.net arigo at codespeak.net
Thu Sep 27 11:54:15 CEST 2007


Author: arigo
Date: Thu Sep 27 11:54:15 2007
New Revision: 46939

Modified:
   pypy/dist/pypy/module/struct/formatiterator.py
   pypy/dist/pypy/module/struct/nativefmttable.py
   pypy/dist/pypy/module/struct/test/test_struct.py
Log:
Native floats and doubles in the struct module.


Modified: pypy/dist/pypy/module/struct/formatiterator.py
==============================================================================
--- pypy/dist/pypy/module/struct/formatiterator.py	(original)
+++ pypy/dist/pypy/module/struct/formatiterator.py	Thu Sep 27 11:54:15 2007
@@ -142,6 +142,10 @@
         w_obj = self.accept_obj_arg()
         return self.space.str_w(w_obj)
 
+    def accept_float_arg(self):
+        w_obj = self.accept_obj_arg()
+        return self.space.float_w(w_obj)
+
 
 class UnpackFormatIterator(FormatIterator):
 

Modified: pypy/dist/pypy/module/struct/nativefmttable.py
==============================================================================
--- pypy/dist/pypy/module/struct/nativefmttable.py	(original)
+++ pypy/dist/pypy/module/struct/nativefmttable.py	Thu Sep 27 11:54:15 2007
@@ -2,6 +2,7 @@
 from pypy.module.struct import standardfmttable as std
 from pypy.rpython.tool import rffi_platform
 from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.rarithmetic import r_singlefloat
 
 native_is_bigendian = struct.pack("=i", 1) == struct.pack(">i", 1)
 
@@ -13,49 +14,113 @@
     }
 
 # ____________________________________________________________
+
+def pack_double(fmtiter):
+    doubleval = fmtiter.accept_float_arg()
+    buf = lltype.malloc(rffi.DOUBLEP.TO, 1, flavor='raw')
+    try:
+        buf[0] = doubleval
+        p = rffi.cast(rffi.CCHARP, buf)
+        for i in range(sizeof_double):
+            fmtiter.result.append(p[i])
+    finally:
+        lltype.free(buf, flavor='raw')
+
+def unpack_double(fmtiter):
+    input = fmtiter.read(sizeof_double)
+    buf = lltype.malloc(rffi.DOUBLEP.TO, 1, flavor='raw')
+    try:
+        p = rffi.cast(rffi.CCHARP, buf)
+        for i in range(sizeof_double):
+            p[i] = input[i]
+        doubleval = buf[0]
+    finally:
+        lltype.free(buf, flavor='raw')
+    fmtiter.appendobj(doubleval)
+
+def pack_float(fmtiter):
+    doubleval = fmtiter.accept_float_arg()
+    floatval = r_singlefloat(doubleval)
+    buf = lltype.malloc(rffi.FLOATP.TO, 1, flavor='raw')
+    try:
+        buf[0] = floatval
+        p = rffi.cast(rffi.CCHARP, buf)
+        for i in range(sizeof_float):
+            fmtiter.result.append(p[i])
+    finally:
+        lltype.free(buf, flavor='raw')
+
+def unpack_float(fmtiter):
+    input = fmtiter.read(sizeof_float)
+    buf = lltype.malloc(rffi.FLOATP.TO, 1, flavor='raw')
+    try:
+        p = rffi.cast(rffi.CCHARP, buf)
+        for i in range(sizeof_float):
+            p[i] = input[i]
+        floatval = buf[0]
+    finally:
+        lltype.free(buf, flavor='raw')
+    doubleval = float(floatval)
+    fmtiter.appendobj(doubleval)
+
+# ____________________________________________________________
 #
 # Use rffi_platform to get the native sizes and alignments from the C compiler
 
-INSPECT = {'b': 'signed char',
-           'h': 'signed short',
-           'i': 'signed int',
-           'l': 'signed long',
-           'q': 'signed long long',
-           'B': 'unsigned char',
-           'H': 'unsigned short',
-           'I': 'unsigned int',
-           'L': 'unsigned long',
-           'Q': 'unsigned long long',
-           'P': 'char *',
-           'f': 'float',
-           'd': 'double',
-           }
-
-class CConfig:
-    _header_ = ""
-
-for fmtchar, ctype in INSPECT.items():
-    CConfig._header_ += """
-        struct about_%s {
-            char pad;
-            %s field;
-        };
-    """ % (fmtchar, ctype)
-    setattr(CConfig, fmtchar, rffi_platform.Struct(
-        "struct about_%s" % (fmtchar,),
-        [('field', lltype.FixedSizeArray(rffi.CHAR, 1))]))
-
-cConfig = rffi_platform.configure(CConfig)
-
-for fmtchar, ctype in INSPECT.items():
-    S = cConfig[fmtchar]
-    alignment = rffi.offsetof(S, 'c_field')
-    size = rffi.sizeof(S.c_field)
-    signed = 'a' <= fmtchar <= 'z'
-
-    native_fmttable[fmtchar] = {
-        'size': size,
-        'alignment': alignment,
-        'pack': std.make_int_packer(size, signed),     # XXX 'f', 'd'
-        'unpack': std.make_int_unpacker(size, signed),
-        }
+def setup():
+    INSPECT = {'b': 'signed char',
+               'h': 'signed short',
+               'i': 'signed int',
+               'l': 'signed long',
+               'q': 'signed long long',
+               'B': 'unsigned char',
+               'H': 'unsigned short',
+               'I': 'unsigned int',
+               'L': 'unsigned long',
+               'Q': 'unsigned long long',
+               'P': 'char *',
+               'f': 'float',
+               'd': 'double',
+               }
+
+    class CConfig:
+        _header_ = ""
+
+    for fmtchar, ctype in INSPECT.items():
+        CConfig._header_ += """
+            struct about_%s {
+                char pad;
+                %s field;
+            };
+        """ % (fmtchar, ctype)
+        setattr(CConfig, fmtchar, rffi_platform.Struct(
+            "struct about_%s" % (fmtchar,),
+            [('field', lltype.FixedSizeArray(rffi.CHAR, 1))]))
+
+    cConfig = rffi_platform.configure(CConfig)
+
+    for fmtchar, ctype in INSPECT.items():
+        S = cConfig[fmtchar]
+        alignment = rffi.offsetof(S, 'c_field')
+        size = rffi.sizeof(S.c_field)
+        signed = 'a' <= fmtchar <= 'z'
+
+        if fmtchar == 'f':
+            pack = pack_float
+            unpack = unpack_float
+        elif fmtchar == 'd':
+            pack = pack_double
+            unpack = unpack_double
+        else:
+            pack = std.make_int_packer(size, signed)
+            unpack = std.make_int_unpacker(size, signed)
+
+        native_fmttable[fmtchar] = {'size': size,
+                                    'alignment': alignment,
+                                    'pack': pack,
+                                    'unpack': unpack}
+
+setup()
+
+sizeof_double = native_fmttable['d']['size']
+sizeof_float  = native_fmttable['f']['size']

Modified: pypy/dist/pypy/module/struct/test/test_struct.py
==============================================================================
--- pypy/dist/pypy/module/struct/test/test_struct.py	(original)
+++ pypy/dist/pypy/module/struct/test/test_struct.py	Thu Sep 27 11:54:15 2007
@@ -221,6 +221,37 @@
         assert unpack("5x", "hello") == ()
 
 
+    def test_native_floats(self):
+        """
+        Check the 'd' and 'f' format characters on native packing.
+        """
+        calcsize = self.struct.calcsize
+        pack = self.struct.pack
+        unpack = self.struct.unpack
+        data = pack("d", 12.34)
+        assert len(data) == calcsize("d")
+        assert unpack("d", data) == (12.34,)     # no precision lost
+        data = pack("f", 12.34)
+        assert len(data) == calcsize("f")
+        res, = unpack("f", data)
+        assert res != 12.34                      # precision lost
+        assert abs(res - 12.34) < 1E-6
+
+
+    def test_standard_floats(self):
+        """
+        Check the 'd' and 'f' format characters on standard packing.
+        """
+        skip("in-progress")
+        pack = self.struct.pack
+        unpack = self.struct.unpack
+        assert pack("!d", 12.5) == '@)\x00\x00\x00\x00\x00\x00'
+        assert pack("<d", 12.5) == '\x00\x00\x00\x00\x00\x00)@'
+        assert unpack("!d", '@)\x00\x00\x00\x00\x00\x00') == (12.5,)
+        assert unpack("<d", '\x00\x00\x00\x00\x00\x00)@') == (12.5,)
+        XXX # "f"
+
+
     def test_struct_error(self):
         """
         Check the various ways to get a struct.error.  Note that CPython



More information about the Pypy-commit mailing list