[pypy-svn] r47473 - in pypy/dist/pypy/module/_ffi: . test

fijal at codespeak.net fijal at codespeak.net
Mon Oct 15 19:12:45 CEST 2007


Author: fijal
Date: Mon Oct 15 19:12:44 2007
New Revision: 47473

Added:
   pypy/dist/pypy/module/_ffi/structure.py   (contents, props changed)
   pypy/dist/pypy/module/_ffi/test/test_struct.py   (contents, props changed)
Modified:
   pypy/dist/pypy/module/_ffi/__init__.py
   pypy/dist/pypy/module/_ffi/app_ffi.py
   pypy/dist/pypy/module/_ffi/interp_ffi.py
   pypy/dist/pypy/module/_ffi/test/test__ffi.py
Log:
Another approach to structures. This should scale to nested structures,
not rpython by now (will fix it later)


Modified: pypy/dist/pypy/module/_ffi/__init__.py
==============================================================================
--- pypy/dist/pypy/module/_ffi/__init__.py	(original)
+++ pypy/dist/pypy/module/_ffi/__init__.py	Mon Oct 15 19:12:44 2007
@@ -10,11 +10,11 @@
     applevelname = '_ffi'
 
     interpleveldefs = {
-        'CDLL'      : 'interp_ffi.W_CDLL',
-        'FuncPtr'   : 'interp_ffi.W_FuncPtr',
+        'CDLL'              : 'interp_ffi.W_CDLL',
+        'FuncPtr'           : 'interp_ffi.W_FuncPtr',
+        'StructureInstance' : 'structure.W_StructureInstance',
     }
 
     appleveldefs = {
         'Structure'         : 'app_ffi.Structure',
-        'StructureInstance' : 'app_ffi.StructureInstance',
     }

Modified: pypy/dist/pypy/module/_ffi/app_ffi.py
==============================================================================
--- pypy/dist/pypy/module/_ffi/app_ffi.py	(original)
+++ pypy/dist/pypy/module/_ffi/app_ffi.py	Mon Oct 15 19:12:44 2007
@@ -6,21 +6,4 @@
 
     def __call__(self, **kwds):
         from _ffi import StructureInstance
-        return StructureInstance(self.fields, kwds)
-
-class StructureInstance(object):
-    def __init__(self, shape, **kwds):
-        self.shape = shape
-        self.format = "".join([i[1] for i in shape])
-        for kwd, value in kwds.items():
-            setattr(self, kwd, value)
-
-    def pack(self):
-        args = [getattr(self, i[0], 0) for i in self.shape]
-        return struct.pack(self.format, *args)
-
-    def unpack(self, s):
-        values = struct.unpack(self.format, s)
-        for (name, _), value in zip(self.shape, values):
-            setattr(self, name, value)
-    
+        return StructureInstance(self, kwds)

Modified: pypy/dist/pypy/module/_ffi/interp_ffi.py
==============================================================================
--- pypy/dist/pypy/module/_ffi/interp_ffi.py	(original)
+++ pypy/dist/pypy/module/_ffi/interp_ffi.py	Mon Oct 15 19:12:44 2007
@@ -122,7 +122,7 @@
     ptr.push_arg(ll_str)
     return ll_str
 
-def push_arg(space, ptr, argnum, argtype, w_arg, to_free, to_reconsider):
+def push_arg(space, ptr, argnum, argtype, w_arg, to_free):
     w = space.wrap
     # XXX how to handle LONGLONG here?
     # they're probably long, so we'll not get them through int_w
@@ -142,11 +142,8 @@
             mod = space.getbuiltinmodule('_ffi')
             w_StructureInstance = space.getattr(mod, w('StructureInstance'))
             if space.is_true(space.isinstance(w_arg, w_StructureInstance)):
-                w_pack = space.getattr(w_arg, w('pack'))
-                w_res = space.call(w_pack, space.newtuple([]))
-                size = space.int_w(space.len(w_res))
-                ll_ptr = pack_pointer(space, w_res, ptr)
-                to_reconsider.append((argnum, ll_ptr, size))
+                #ptr.push_arg(lltype.cast_int_to_ptr(rffi.VOIDP, space.int_w(space.getattr(w_arg, w('buffer')))))
+                ptr.push_arg(w_arg.ll_buffer)
             else:
                 raise OperationError(space.w_TypeError, w(
                     "Expected structure, array or simple type"))
@@ -158,11 +155,20 @@
 
 ll_typemap_iter = unrolling_iterable(LL_TYPEMAP.items())
 
-def repack_struct(space, w_struct, value, size):
-    w_unpack = space.getattr(w_struct, space.wrap('unpack'))
-    # ARGH! too much copying!
-    x = "".join([value[i] for i in range(size)])
-    space.call(w_unpack, space.newtuple([space.wrap(x)]))
+def wrap_result(space, restype, func):
+    for c, ll_type in ll_typemap_iter:
+        if restype == c:
+            if c == 's' or c == 'p':
+                return space.wrap(rffi.charp2str(func(rffi.CCHARP)))
+            elif c == 'P':
+                res = func(rffi.VOIDP)
+                return space.wrap(lltype.cast_ptr_to_int(res))
+            elif c == 'q' or c == 'Q' or c == 'L':
+                return space.newlong(func(ll_type))
+            else:
+                return space.wrap(func(ll_type))
+    return space.w_None
+wrap_result._annspecialcase_ = 'specialize:arg(2)'
 
 class W_FuncPtr(Wrappable):
     def __init__(self, ptr, argtypes, restype):
@@ -177,29 +183,15 @@
             raise OperationError(space.w_TypeError, space.wrap(
                 "Provided keyword arguments for C function call"))
         to_free = []
-        to_reconsider = []
         i = 0
         for argtype, w_arg in zip(self.argtypes, args_w):
-            push_arg(space, self.ptr, i, argtype, w_arg, to_free, to_reconsider)
+            push_arg(space, self.ptr, i, argtype, w_arg, to_free)
             i += 1
         try:
-            for c, ll_type in ll_typemap_iter:
-                if self.restype == c:
-                    if c == 's' or c == 'p':
-                        return space.wrap(rffi.charp2str(self.ptr.call(rffi.CCHARP)))
-                    elif c == 'P':
-                        res = self.ptr.call(rffi.VOIDP)
-                        return space.wrap(lltype.cast_ptr_to_int(res))
-                    elif c == 'q' or c == 'Q' or c == 'L':
-                        return space.newlong(self.ptr.call(ll_type))
-                    else:
-                        return space.wrap(self.ptr.call(ll_type))
+            return wrap_result(space, self.restype, self.ptr.call)
         finally:
             for elem in to_free:
                 lltype.free(elem, flavor='raw')
-            for num, value, size in to_reconsider:
-                repack_struct(space, args_w[num], value, size)
-                lltype.free(value, flavor='raw')
     call.unwrap_spec = ['self', ObjSpace, Arguments]
 
 W_FuncPtr.typedef = TypeDef(

Added: pypy/dist/pypy/module/_ffi/structure.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/_ffi/structure.py	Mon Oct 15 19:12:44 2007
@@ -0,0 +1,83 @@
+
+""" Interpreter-level implementation of structure, exposing ll-structure
+to app-level with apropriate interface
+"""
+
+from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable,\
+     Arguments
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.typedef import TypeDef, GetSetProperty
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.interpreter.error import OperationError, wrap_oserror
+# XXX we've got the very same info in two places - one is native_fmttable
+# the other one is in rlib/libffi, we should refactor it to reuse the same
+# logic, I'll not touch it by now, and refactor it later
+from pypy.module.struct.nativefmttable import native_fmttable
+from pypy.module._ffi.interp_ffi import wrap_result
+
+def unpack_fields(space, w_fields):
+    fields_w = space.unpackiterable(w_fields)
+    fields = []
+    for w_tup in fields_w:
+        l_w = space.unpackiterable(w_tup)
+        if not len(l_w) == 2:
+            raise OperationError(space.w_ValueError, space.wrap(
+                "Expected list of 2-size tuples"))
+        fields.append((space.str_w(l_w[0]), space.str_w(l_w[1])))
+    return fields
+
+def size_and_pos(fields):
+    size = native_fmttable[fields[0][1]]['size']
+    pos = [0]
+    for i in range(1, len(fields)):
+        field_desc = native_fmttable[fields[i][1]]
+        missing = size % field_desc.get('alignment', 1)
+        if missing:
+            size += field_desc['alignment'] - missing
+        pos.append(size)
+        size += field_desc['size']
+    return size, pos
+
+class W_StructureInstance(Wrappable):
+    def __init__(self, space, w_shape, w_fieldinits):
+        if space.is_true(w_fieldinits):
+            raise OperationError(space.w_ValueError, space.wrap(
+                "Fields should be not initialized with values by now"))
+        w_fields = space.getattr(w_shape, space.wrap('fields'))
+        fields = unpack_fields(space, w_fields)
+        size, pos = size_and_pos(fields)
+        self.fields = fields
+        self.ll_buffer = lltype.malloc(rffi.VOIDP.TO, size, flavor='raw',
+                                       zero=True)
+        self.ll_positions = pos
+        self.next_pos = 0
+
+    def cast_pos(self, ll_t):
+        i = self.next_pos
+        pos = rffi.ptradd(self.ll_buffer, self.ll_positions[i])
+        TP = rffi.CArrayPtr(ll_t)
+        return rffi.cast(TP, pos)[0]
+    cast_pos._annspecialcase_ = 'specialize:arg(1)'
+
+    def getattr(self, space, attr):
+        for i in range(len(self.fields)):
+            name, c = self.fields[i]
+            if name == attr:
+                # XXX RPython-trick for passing lambda around
+                self.next_pos = i
+                return wrap_result(space, c, self.cast_pos)
+        raise OperationError(space.w_AttributeError, space.wrap(
+            "C Structure has no attribute %s" % name))
+    getattr.unwrap_spec = ['self', ObjSpace, str]
+
+    def __del__(self):
+        lltype.free(self.ll_buffer, flavor='raw')
+
+def descr_new_structure_instance(space, w_type, w_shape, w_fieldinits):
+    return W_StructureInstance(space, w_shape, w_fieldinits)
+
+W_StructureInstance.typedef = TypeDef(
+    'StructureInstance',
+    __new__     = interp2app(descr_new_structure_instance),
+    __getattr__ = interp2app(W_StructureInstance.getattr),
+)

Modified: pypy/dist/pypy/module/_ffi/test/test__ffi.py
==============================================================================
--- pypy/dist/pypy/module/_ffi/test/test__ffi.py	(original)
+++ pypy/dist/pypy/module/_ffi/test/test__ffi.py	Mon Oct 15 19:12:44 2007
@@ -73,4 +73,7 @@
         struct2 = struct_type()
         assert gettimeofday(struct2, None) == 0
         assert structure.tv_usec != struct2.tv_usec
-        assert structure.tv_sec == struct2.tv_sec or structure.tv_sec == struct2.tv_sec - 1
+        assert (structure.tv_sec == struct2.tv_sec) or (structure.tv_sec == struct2.tv_sec - 1)
+        raises(AttributeError, "structure.xxx")
+
+    

Added: pypy/dist/pypy/module/_ffi/test/test_struct.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/_ffi/test/test_struct.py	Mon Oct 15 19:12:44 2007
@@ -0,0 +1,15 @@
+
+from pypy.module._ffi.structure import sizeof
+
+def unpack(desc):
+    return [('x', i) for i in desc]
+
+def test_sizeof():
+    s_c = sizeof(unpack('c'))
+    s_l = sizeof(unpack('l'))
+    s_q = sizeof(unpack('q'))
+    assert sizeof(unpack('cl')) == 2*s_l
+    assert sizeof(unpack('cq')) == s_q + s_l
+    assert sizeof(unpack('ccq')) == s_q + s_l
+    assert sizeof(unpack('ccccq')) == 4 * s_c + s_q
+



More information about the Pypy-commit mailing list