[pypy-svn] r49901 - in pypy/branch/applevel-ctypes/pypy/module/_ffi: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Tue Dec 18 21:22:48 CET 2007


Author: cfbolz
Date: Tue Dec 18 21:22:47 2007
New Revision: 49901

Modified:
   pypy/branch/applevel-ctypes/pypy/module/_ffi/__init__.py
   pypy/branch/applevel-ctypes/pypy/module/_ffi/app_ffi.py
   pypy/branch/applevel-ctypes/pypy/module/_ffi/interp_ffi.py
   pypy/branch/applevel-ctypes/pypy/module/_ffi/structure.py
   pypy/branch/applevel-ctypes/pypy/module/_ffi/test/test__ffi.py
Log:
refactor _ffi structure handling: don't recompute the offsets every time a
structure instances is created (!), only do it every time a new structure type
is created.


Modified: pypy/branch/applevel-ctypes/pypy/module/_ffi/__init__.py
==============================================================================
--- pypy/branch/applevel-ctypes/pypy/module/_ffi/__init__.py	(original)
+++ pypy/branch/applevel-ctypes/pypy/module/_ffi/__init__.py	Tue Dec 18 21:22:47 2007
@@ -12,6 +12,7 @@
     interpleveldefs = {
         'CDLL'               : 'interp_ffi.W_CDLL',
         'FuncPtr'            : 'interp_ffi.W_FuncPtr',
+        'Structure'          : 'structure.W_Structure',
         'StructureInstance'  : 'structure.W_StructureInstance',
         'ArrayInstance'      : 'array.W_ArrayInstance',
         '_get_type'          : 'interp_ffi._w_get_type',
@@ -19,7 +20,5 @@
     }
 
     appleveldefs = {
-        'Structure'         : 'app_ffi.Structure',
         'Array'             : 'app_ffi.Array',
-        #'StructureInstance' : 'app_ffi.StructureInstance',
     }

Modified: pypy/branch/applevel-ctypes/pypy/module/_ffi/app_ffi.py
==============================================================================
--- pypy/branch/applevel-ctypes/pypy/module/_ffi/app_ffi.py	(original)
+++ pypy/branch/applevel-ctypes/pypy/module/_ffi/app_ffi.py	Tue Dec 18 21:22:47 2007
@@ -1,24 +1,5 @@
 # NOT_RPYTHON
 
-class Structure(object):
-    def check_fields(self, fields):
-        import _ffi
-        for name, letter in fields:
-            _ffi._get_type(letter)
-    
-    def __init__(self, fields):
-        self.check_fields(fields)
-        self.fields = fields
-
-    def __call__(self, *args, **kwds):
-        from _ffi import StructureInstance
-        if args:
-            if len(args) > 1:
-                raise TypeError("Can give at most one non-keyword argument")
-            if kwds:
-                raise TypeError("Keyword arguments not allowed when passing address argument")
-            return StructureInstance(self, args[0], None)
-        return StructureInstance(self, None, kwds)
 
 class Array(object):
     def __init__(self, of):

Modified: pypy/branch/applevel-ctypes/pypy/module/_ffi/interp_ffi.py
==============================================================================
--- pypy/branch/applevel-ctypes/pypy/module/_ffi/interp_ffi.py	(original)
+++ pypy/branch/applevel-ctypes/pypy/module/_ffi/interp_ffi.py	Tue Dec 18 21:22:47 2007
@@ -124,14 +124,14 @@
     __new__     = interp2app(descr_new_cdll),
     ptr         = interp2app(W_CDLL.ptr),
     __doc__     = """ C Dynamically loaded library
-use CDLL(libname) to create handle to C library (argument is processed the
-same way as dlopen processes it). On such library call:
+use CDLL(libname) to create a handle to a C library (the argument is processed
+the same way as dlopen processes it). On such a library you can call:
 lib.ptr(func_name, argtype_list, restype)
 
 where argtype_list is a list of single characters and restype is a single
-character. Character meanings are more or less the same as in struct module,
-except that s has trailing \x00 added, while p is considered a raw buffer.
-"""
+character. The character meanings are more or less the same as in the struct
+module, except that s has trailing \x00 added, while p is considered a raw
+buffer."""
 )
 
 def pack_pointer(space, add_arg, argdesc, w_arg, push_func):

Modified: pypy/branch/applevel-ctypes/pypy/module/_ffi/structure.py
==============================================================================
--- pypy/branch/applevel-ctypes/pypy/module/_ffi/structure.py	(original)
+++ pypy/branch/applevel-ctypes/pypy/module/_ffi/structure.py	Tue Dec 18 21:22:47 2007
@@ -3,9 +3,9 @@
 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.baseobjspace import W_Root, Wrappable
+from pypy.interpreter.gateway import interp2app, ObjSpace
+from pypy.interpreter.argument import Arguments
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.interpreter.error import OperationError, wrap_oserror
@@ -13,7 +13,7 @@
 # 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 as struct_native_fmttable
-from pypy.module._ffi.interp_ffi import wrap_value, unwrap_value, _get_type
+from pypy.module._ffi.interp_ffi import wrap_value, unwrap_value, _get_type, TYPEMAP
 
 native_fmttable = {}
 for key, value in struct_native_fmttable.items():
@@ -45,55 +45,95 @@
         size += field_desc['size']
     return size, pos
 
+
+class W_Structure(Wrappable):
+    def __init__(self, space, w_fields):
+        fields = unpack_fields(space, w_fields)
+        name_to_offset = {}
+        for i in range(len(fields)):
+            name, letter = fields[i]
+            if letter not in TYPEMAP:
+                raise OperationError(space.w_ValueError, space.wrap(
+                    "Unkown type letter %s" % (letter,)))
+            if name in name_to_offset:
+                raise OperationError(space.w_ValueError, space.wrap(
+                    "duplicate field name %s" % (name, )))
+            name_to_offset[name] = i
+        size, pos = size_and_pos(fields)
+        self.size = size
+        self.ll_positions = pos
+        self.fields = fields
+        self.name_to_offset = name_to_offset
+
+    def descr_call(self, space, __args__):
+        args_w, kwargs_w = __args__.unpack()
+        if args_w:
+            if len(args_w) > 1:
+                raise OperationError(
+                        space.w_TypeError,
+                        space.wrap("Can give at most one non-keyword argument"))
+            if kwargs_w:
+                raise OperationError(
+                        space.w_TypeError,
+                        space.wrap("Keyword arguments not allowed when passing address argument"))
+            return W_StructureInstance(space, self, args_w[0], None)
+        return W_StructureInstance(space, self, None, kwargs_w)
+
+def descr_new_structure(space, w_type, w_fields):
+    return W_Structure(space, w_fields)
+
+W_Structure.typedef = TypeDef(
+    'Structure',
+    __new__     = interp2app(descr_new_structure),
+    __call__ = interp2app(W_Structure.descr_call,
+                          unwrap_spec=['self', ObjSpace, Arguments]),
+)
+W_Structure.typedef.acceptable_as_base_class = False
+
 def push_field(self, num, value):
-    ptr = rffi.ptradd(self.ll_buffer, self.ll_positions[num])
+    ptr = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[num])
     TP = lltype.typeOf(value)
     T = lltype.Ptr(rffi.CArray(TP))
     rffi.cast(T, ptr)[0] = value
 push_field._annspecialcase_ = 'specialize:argtype(2)'
     
 def cast_pos(self, i, ll_t):
-    pos = rffi.ptradd(self.ll_buffer, self.ll_positions[i])
+    pos = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[i])
     TP = lltype.Ptr(rffi.CArray(ll_t))
     return rffi.cast(TP, pos)[0]
 cast_pos._annspecialcase_ = 'specialize:arg(2)'
 
 class W_StructureInstance(Wrappable):
-    def __init__(self, space, w_shape, w_address, w_fieldinits):
+    def __init__(self, space, shape, w_address, fieldinits_w):
         self.free_afterwards = False
-        w_fields = space.getattr(w_shape, space.wrap('fields'))
-        fields = unpack_fields(space, w_fields)
-        size, pos = size_and_pos(fields)
-        self.fields = fields
-        if space.is_true(w_address):
+        self.shape = shape
+        if w_address is not None:
             self.ll_buffer = rffi.cast(rffi.VOIDP, space.int_w(w_address))
         else:
             self.free_afterwards = True
-            self.ll_buffer = lltype.malloc(rffi.VOIDP.TO, size, flavor='raw',
+            self.ll_buffer = lltype.malloc(rffi.VOIDP.TO, shape.size, flavor='raw',
                                            zero=True)
-        self.ll_positions = pos
-        if space.is_true(w_fieldinits):
-            for w_field in space.unpackiterable(w_fieldinits):
-                w_value = space.getitem(w_fieldinits, w_field)
-                self.setattr(space, space.str_w(w_field), w_value)
+        if fieldinits_w:
+            for field, w_value in fieldinits_w.iteritems():
+                self.setattr(space, field, w_value)
+
+    def getindex(self, space, attr):
+        try:
+            return self.shape.name_to_offset[attr]
+        except KeyError:
+            raise OperationError(space.w_AttributeError, space.wrap(
+                "C Structure has no attribute %s" % attr))
 
     def getattr(self, space, attr):
-        if attr.startswith('tm'):
-            pass
-        for i in range(len(self.fields)):
-            name, c = self.fields[i]
-            if name == attr:
-                return wrap_value(space, cast_pos, self, i, c)
-        raise OperationError(space.w_AttributeError, space.wrap(
-            "C Structure has no attribute %s" % attr))
+        i = self.getindex(space, attr)
+        _, c = self.shape.fields[i]
+        return wrap_value(space, cast_pos, self, i, c)
     getattr.unwrap_spec = ['self', ObjSpace, str]
 
     def setattr(self, space, attr, w_value):
-        for i in range(len(self.fields)):
-            name, c = self.fields[i]
-            if name == attr:
-                unwrap_value(space, push_field, self, i, c, w_value, None)
-                return
+        i = self.getindex(space, attr)
+        _, c = self.shape.fields[i]
+        unwrap_value(space, push_field, self, i, c, w_value, None)
     setattr.unwrap_spec = ['self', ObjSpace, str, W_Root]
 
     def __del__(self):
@@ -113,3 +153,5 @@
     __setattr__ = interp2app(W_StructureInstance.setattr),
     buffer      = GetSetProperty(W_StructureInstance.getbuffer),
 )
+W_StructureInstance.typedef.acceptable_as_base_class = False
+

Modified: pypy/branch/applevel-ctypes/pypy/module/_ffi/test/test__ffi.py
==============================================================================
--- pypy/branch/applevel-ctypes/pypy/module/_ffi/test/test__ffi.py	(original)
+++ pypy/branch/applevel-ctypes/pypy/module/_ffi/test/test__ffi.py	Tue Dec 18 21:22:47 2007
@@ -258,9 +258,7 @@
         raises(ValueError, "lib.ptr('get_char', ['x'], None)")
         raises(ValueError, "lib.ptr('get_char', [], 'x')")
         raises(ValueError, "_ffi.Structure(['x1', 'xx'])")
-        S = _ffi.Structure([('x1', 'i')])
-        S.fields[0] = ('x1', 'xx')
-        raises(ValueError, "S()")
+        raises(ValueError, _ffi.Structure, [('x1', 'xx')])
         raises(ValueError, "_ffi.Array('xx')")
         A = _ffi.Array('i')
         A.of = 'xx'
@@ -305,3 +303,14 @@
               _ffi.CallbackPtr(compare, ['i', 'i'], 'i'))
         res = [ll_to_sort[i] for i in range(len(to_sort))]
         assert res == sorted(to_sort)
+
+    def test_setattr_struct(self):
+        import _ffi
+        X = _ffi.Structure([('value1', 'i'), ('value2', 'i')])
+        x = X(value1=1, value2=2)
+        assert x.value1 == 1
+        assert x.value2 == 2
+        x.value1 = 3
+        assert x.value1 == 3
+        raises(AttributeError, "x.foo")
+        raises(AttributeError, "x.foo = 1")



More information about the Pypy-commit mailing list