[pypy-svn] r50622 - in pypy/branch/applevel-ctypes2/pypy/module/_rawffi: . test

arigo at codespeak.net arigo at codespeak.net
Tue Jan 15 12:41:50 CET 2008


Author: arigo
Date: Tue Jan 15 12:41:48 2008
New Revision: 50622

Modified:
   pypy/branch/applevel-ctypes2/pypy/module/_rawffi/__init__.py
   pypy/branch/applevel-ctypes2/pypy/module/_rawffi/array.py
   pypy/branch/applevel-ctypes2/pypy/module/_rawffi/interp_rawffi.py
   pypy/branch/applevel-ctypes2/pypy/module/_rawffi/structure.py
   pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test_nested.py
   pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test_struct.py
Log:
(cfbolz, fijal, arigo)
Support nested structures inside other structures.


Modified: pypy/branch/applevel-ctypes2/pypy/module/_rawffi/__init__.py
==============================================================================
--- pypy/branch/applevel-ctypes2/pypy/module/_rawffi/__init__.py	(original)
+++ pypy/branch/applevel-ctypes2/pypy/module/_rawffi/__init__.py	Tue Jan 15 12:41:48 2008
@@ -16,7 +16,6 @@
         'StructureInstance'  : 'structure.W_StructureInstance',
         'Array'              : 'array.W_Array',
         'ArrayInstance'      : 'array.W_ArrayInstance',
-        '_get_type'          : 'interp_rawffi._w_get_type',
         'sizeof'             : 'interp_rawffi.sizeof',
         'alignment'          : 'interp_rawffi.alignment',
         'charp2string'       : 'interp_rawffi.charp2string',

Modified: pypy/branch/applevel-ctypes2/pypy/module/_rawffi/array.py
==============================================================================
--- pypy/branch/applevel-ctypes2/pypy/module/_rawffi/array.py	(original)
+++ pypy/branch/applevel-ctypes2/pypy/module/_rawffi/array.py	Tue Jan 15 12:41:48 2008
@@ -11,8 +11,8 @@
 from pypy.interpreter.error import OperationError, wrap_oserror
 from pypy.module._rawffi.interp_rawffi import segfault_exception
 from pypy.module._rawffi.interp_rawffi import W_DataInstance
-from pypy.module._rawffi.interp_rawffi import unwrap_value, wrap_value, _get_type,\
-     TYPEMAP
+from pypy.module._rawffi.interp_rawffi import unwrap_value, wrap_value
+from pypy.module._rawffi.interp_rawffi import unpack_typecode, letter2tp
 from pypy.rlib.rarithmetic import intmask
 
 def push_elem(ll_array, pos, value):
@@ -27,10 +27,10 @@
 get_elem._annspecialcase_ = 'specialize:arg(2)'
 
 class W_Array(Wrappable):
-    def __init__(self, space, of):
+    def __init__(self, space, itemtp):
+        assert isinstance(itemtp, tuple)
         self.space = space
-        self.of = of
-        self.itemsize = intmask(TYPEMAP[of].c_size)
+        self.itemtp = itemtp
 
     def allocate(self, space, length):
         return W_ArrayInstance(space, self, length)
@@ -46,8 +46,8 @@
                                                 " array length"))
             for num in range(iterlength):
                 w_item = items_w[num]
-                unwrap_value(space, push_elem, result.ll_buffer, num, self.of,
-                             w_item)
+                unwrap_value(space, push_elem, result.ll_buffer, num,
+                             self.itemtp, w_item)
         return space.wrap(result)
 
     def fromaddress(self, space, address, length):
@@ -58,27 +58,28 @@
     def __init__(self, space):
         self.space = space
         self.cache = {}
-        self.array_of_ptr = self.get_array_type('P')
+        self.array_of_ptr = self.get_array_type(letter2tp(space, 'P'))
 
-    def get_array_type(self, of):
+    def get_array_type(self, itemtp):
         try:
-            return self.cache[of]
+            return self.cache[itemtp]
         except KeyError:
-            _get_type(self.space, of)
-            result = W_Array(self.space, of)
-            self.cache[of] = result
+            result = W_Array(self.space, itemtp)
+            self.cache[itemtp] = result
             return result
 
 def get_array_cache(space):
     return space.fromcache(ArrayCache)
 
-def descr_new_array(space, w_type, of):
-    array_type = get_array_cache(space).get_array_type(of)
+def descr_new_array(space, w_type, w_itemtp):
+    itemtp = unpack_typecode(space, w_itemtp)
+    array_type = get_array_cache(space).get_array_type(itemtp)
     return space.wrap(array_type)
 
 W_Array.typedef = TypeDef(
     'Array',
-    __new__  = interp2app(descr_new_array, unwrap_spec=[ObjSpace, W_Root, str]),
+    __new__  = interp2app(descr_new_array,
+                          unwrap_spec=[ObjSpace, W_Root, W_Root]),
     __call__ = interp2app(W_Array.descr_call,
                           unwrap_spec=['self', ObjSpace, int, W_Root]),
     fromaddress = interp2app(W_Array.fromaddress),
@@ -89,7 +90,8 @@
 
 class W_ArrayInstance(W_DataInstance):
     def __init__(self, space, shape, length, address=0):
-        W_DataInstance.__init__(self, space, shape.itemsize * length, address)
+        _, itemsize, _ = shape.itemtp
+        W_DataInstance.__init__(self, space, itemsize * length, address)
         self.length = length
         self.shape = shape
 
@@ -98,14 +100,15 @@
     def setitem(self, space, num, w_value):
         if num >= self.length or num < 0:
             raise OperationError(space.w_IndexError, space.w_None)
-        unwrap_value(space, push_elem, self.ll_buffer, num, self.shape.of,
+        unwrap_value(space, push_elem, self.ll_buffer, num, self.shape.itemtp,
                      w_value)
     setitem.unwrap_spec = ['self', ObjSpace, int, W_Root]
 
     def getitem(self, space, num):
         if num >= self.length or num < 0:
             raise OperationError(space.w_IndexError, space.w_None)
-        return wrap_value(space, get_elem, self.ll_buffer, num, self.shape.of)
+        return wrap_value(space, get_elem, self.ll_buffer, num,
+                          self.shape.itemtp)
     getitem.unwrap_spec = ['self', ObjSpace, int]
 
 W_ArrayInstance.typedef = TypeDef(

Modified: pypy/branch/applevel-ctypes2/pypy/module/_rawffi/interp_rawffi.py
==============================================================================
--- pypy/branch/applevel-ctypes2/pypy/module/_rawffi/interp_rawffi.py	(original)
+++ pypy/branch/applevel-ctypes2/pypy/module/_rawffi/interp_rawffi.py	Tue Jan 15 12:41:48 2008
@@ -12,6 +12,7 @@
 from pypy.module.struct.standardfmttable import min_max_acc_method
 from pypy.module.struct.nativefmttable import native_fmttable
 from pypy.tool.sourcetools import func_with_new_name
+from pypy.rlib.rarithmetic import intmask
 
 class FfiValueError(Exception):
     def __init__(self, msg):
@@ -54,6 +55,11 @@
 }
 TYPEMAP_PTR_LETTERS = "POsz"
 
+UNPACKED_TYPECODES = dict([(code, (code,
+                                   intmask(field_desc.c_size),
+                                   intmask(field_desc.c_alignment)))
+                           for code, field_desc in TYPEMAP.items()])
+
 LL_TYPEMAP = {
     'c' : rffi.CHAR,
     'b' : rffi.SIGNEDCHAR,
@@ -75,18 +81,19 @@
     'v' : lltype.Void,
 }
 
-def _get_type(space, key):
+def letter2tp(space, key):
     try:
-        return TYPEMAP[key]
+        return UNPACKED_TYPECODES[key]
     except KeyError:
         raise OperationError(space.w_ValueError, space.wrap(
             "Unknown type letter %s" % (key,)))
-    return lltype.nullptr(FFI_TYPE_P.TO)
 
-def _w_get_type(space, key):
-    _get_type(space, key)
-    return space.w_None
-_w_get_type.unwrap_spec = [ObjSpace, str]
+def _get_type_(space, key):
+    try:
+        return TYPEMAP[key]
+    except KeyError:
+        raise OperationError(space.w_ValueError, space.wrap(
+            "Unknown type letter %s" % (key,)))
 
 class W_CDLL(Wrappable):
     def __init__(self, space, name):
@@ -97,7 +104,7 @@
 
     def get_type(self, key):
         space = self.space
-        return _get_type(space, key)
+        return _get_type_(space, key)
 
     def ptr(self, space, name, w_argtypes, w_restype):
         """ Get a pointer for function name with provided argtypes
@@ -188,6 +195,14 @@
     w_exception = space.getattr(w_mod, space.wrap("SegfaultException"))
     return OperationError(w_exception, space.wrap(reason))
 
+def unpack_typecode(space, w_typecode):
+    if space.is_true(space.isinstance(w_typecode, space.w_str)):
+        letter = space.str_w(w_typecode)
+        return letter2tp(space, letter)
+    else:
+        w_size, w_align = space.unpacktuple(w_typecode, expected_length=2)
+        return ('?', space.int_w(w_size), space.int_w(w_align))
+
 
 class W_DataInstance(Wrappable):
     def __init__(self, space, size, address=0):
@@ -217,20 +232,21 @@
 
 
 def unwrap_value(space, push_func, add_arg, argdesc, tp, w_arg):
+    letter, _, _ = tp
     w = space.wrap
-    if tp == "d":
+    if letter == "d":
         push_func(add_arg, argdesc, space.float_w(w_arg))
-    elif tp == "f":
+    elif letter == "f":
         push_func(add_arg, argdesc, rffi.cast(rffi.FLOAT,
                                               space.float_w(w_arg)))
-    elif tp in TYPEMAP_PTR_LETTERS:
+    elif letter in TYPEMAP_PTR_LETTERS:
         # check for NULL ptr
         if space.is_true(space.isinstance(w_arg, space.w_int)):
             push_func(add_arg, argdesc, rffi.cast(rffi.VOIDP, space.int_w(w_arg)))
         else:
             datainstance = space.interp_w(W_DataInstance, w_arg)
             push_func(add_arg, argdesc, datainstance.ll_buffer)
-    elif tp == "c":
+    elif letter == "c":
         s = space.str_w(w_arg)
         if len(s) != 1:
             raise OperationError(space.w_TypeError, w(
@@ -239,7 +255,7 @@
         push_func(add_arg, argdesc, val)
     else:
         for c, checker in unroll_size_checkers:
-            if tp == c:
+            if letter == c:
                 if c == "q":
                     val = space.r_longlong_w(w_arg)
                 elif c == "Q":
@@ -254,14 +270,18 @@
                     raise OperationError(space.w_ValueError, w(e.msg))
                 TP = LL_TYPEMAP[c]
                 push_func(add_arg, argdesc, rffi.cast(TP, val))
-    
+                return
+        else:
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("cannot directly write value"))
 unwrap_value._annspecialcase_ = 'specialize:arg(1)'
 
 ll_typemap_iter = unrolling_iterable(LL_TYPEMAP.items())
 
 def wrap_value(space, func, add_arg, argdesc, tp):
+    letter, _, _ = tp
     for c, ll_type in ll_typemap_iter:
-        if tp == c:
+        if letter == c:
             if c in TYPEMAP_PTR_LETTERS:
                 res = func(add_arg, argdesc, rffi.VOIDP)
                 return space.wrap(rffi.cast(lltype.Signed, res))
@@ -277,7 +297,8 @@
                                                            ll_type)))
             else:
                 return space.wrap(intmask(func(add_arg, argdesc, ll_type)))
-    return space.w_None
+    raise OperationError(space.w_TypeError,
+                         space.wrap("cannot directly read value"))
 wrap_value._annspecialcase_ = 'specialize:arg(1)'
 
 class W_FuncPtr(Wrappable):
@@ -286,7 +307,7 @@
         self.ptr = ptr
         if restype != 'v':
             cache = get_array_cache(space)
-            self.resarray = cache.get_array_type(restype)
+            self.resarray = cache.get_array_type(letter2tp(space, restype))
         else:
             self.resarray = None
         self.argtypes = argtypes
@@ -307,9 +328,9 @@
                 msg = ("Argument %d should be an array of length 1, "
                        "got length %d" % (i+1, arg.length))
                 raise OperationError(space.w_TypeError, space.wrap(msg))
-            if arg.shape.of != argtype:
+            if arg.shape.itemtp[0] != argtype:
                 msg = "Argument %d should be typecode %s, got %s" % (
-                    i+1, argtype, arg.shape.of)
+                    i+1, argtype, arg.shape.itemtp[0])
                 raise OperationError(space.w_TypeError, space.wrap(msg))
             args_ll.append(arg.ll_buffer)
             # XXX we could avoid the intermediate list args_ll

Modified: pypy/branch/applevel-ctypes2/pypy/module/_rawffi/structure.py
==============================================================================
--- pypy/branch/applevel-ctypes2/pypy/module/_rawffi/structure.py	(original)
+++ pypy/branch/applevel-ctypes2/pypy/module/_rawffi/structure.py	Tue Jan 15 12:41:48 2008
@@ -12,8 +12,8 @@
 from pypy.interpreter.error import OperationError, wrap_oserror
 from pypy.module._rawffi.interp_rawffi import segfault_exception
 from pypy.module._rawffi.interp_rawffi import W_DataInstance
-from pypy.module._rawffi.interp_rawffi import wrap_value, unwrap_value, _get_type,\
-     TYPEMAP
+from pypy.module._rawffi.interp_rawffi import wrap_value, unwrap_value
+from pypy.module._rawffi.interp_rawffi import unpack_typecode
 from pypy.rlib.rarithmetic import intmask
 
 def unpack_fields(space, w_fields):
@@ -24,9 +24,9 @@
         if not len(l_w) == 2:
             raise OperationError(space.w_ValueError, space.wrap(
                 "Expected list of 2-size tuples"))
-        name, code = space.str_w(l_w[0]), space.str_w(l_w[1])
-        _get_type(space, code) # be paranoid about types
-        fields.append((name, code))
+        name = space.str_w(l_w[0])
+        tp = unpack_typecode(space, l_w[1])
+        fields.append((name, tp))
     return fields
 
 def round_up(size, alignment):
@@ -36,12 +36,11 @@
     size = 0
     alignment = 1
     pos = []
-    for i in range(len(fields)):
-        field_desc = TYPEMAP[fields[i][1]]
-        size = round_up(size, intmask(field_desc.c_alignment))
-        alignment = max(alignment, intmask(field_desc.c_alignment))
+    for fieldname, (letter, fieldsize, fieldalignment) in fields:
+        size = round_up(size, fieldalignment)
+        alignment = max(alignment, fieldalignment)
         pos.append(size)
-        size += intmask(field_desc.c_size)
+        size += intmask(fieldsize)
     size = round_up(size, alignment)
     return size, alignment, pos
 
@@ -51,10 +50,7 @@
         fields = unpack_fields(space, w_fields)
         name_to_index = {}
         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,)))
+            name, tp = fields[i]
             if name in name_to_index:
                 raise OperationError(space.w_ValueError, space.wrap(
                     "duplicate field name %s" % (name, )))
@@ -91,6 +87,11 @@
         return space.wrap(self.ll_positions[index])
     descr_getfieldoffset.unwrap_spec = ['self', ObjSpace, str]
 
+    def descr_gettypecode(self, space):
+        return space.newtuple([space.wrap(self.size),
+                               space.wrap(self.alignment)])
+    descr_gettypecode.unwrap_spec = ['self', ObjSpace]
+
 def descr_new_structure(space, w_type, w_fields):
     return space.wrap(W_Structure(space, w_fields))
 
@@ -102,6 +103,7 @@
     size        = interp_attrproperty('size', W_Structure),
     alignment   = interp_attrproperty('alignment', W_Structure),
     getfieldoffset = interp2app(W_Structure.descr_getfieldoffset),
+    gettypecode = interp2app(W_Structure.descr_gettypecode),
 )
 W_Structure.typedef.acceptable_as_base_class = False
 
@@ -130,18 +132,24 @@
         if not self.ll_buffer:
             raise segfault_exception(space, "accessing NULL pointer")
         i = self.shape.getindex(space, attr)
-        _, c = self.shape.fields[i]
-        return wrap_value(space, cast_pos, self, i, c)
+        _, tp = self.shape.fields[i]
+        return wrap_value(space, cast_pos, self, i, tp)
     getattr.unwrap_spec = ['self', ObjSpace, str]
 
     def setattr(self, space, attr, w_value):
         if not self.ll_buffer:
             raise segfault_exception(space, "accessing NULL pointer")
         i = self.shape.getindex(space, attr)
-        _, c = self.shape.fields[i]
-        unwrap_value(space, push_field, self, i, c, w_value)
+        _, tp = self.shape.fields[i]
+        unwrap_value(space, push_field, self, i, tp, w_value)
     setattr.unwrap_spec = ['self', ObjSpace, str, W_Root]
 
+    def descr_fieldaddress(self, space, attr):
+        i = self.shape.getindex(space, attr)
+        ptr = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[i])
+        return space.wrap(rffi.cast(lltype.Signed, ptr))
+    descr_fieldaddress.unwrap_spec = ['self', ObjSpace, str]
+
 
 W_StructureInstance.typedef = TypeDef(
     'StructureInstance',
@@ -151,6 +159,7 @@
     free        = interp2app(W_StructureInstance.free),
     shape       = interp_attrproperty('shape', W_StructureInstance),
     byptr       = interp2app(W_StructureInstance.byptr),
+    fieldaddress= interp2app(W_StructureInstance.descr_fieldaddress),
 )
 W_StructureInstance.typedef.acceptable_as_base_class = False
 

Modified: pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test_nested.py
==============================================================================
--- pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test_nested.py	(original)
+++ pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test_nested.py	Tue Jan 15 12:41:48 2008
@@ -23,3 +23,23 @@
         assert S.getfieldoffset('a') == 0
         assert S.getfieldoffset('b') == align
         assert S.getfieldoffset('c') == round_up(struct.calcsize("iP"))
+        assert S.gettypecode() == (S.size, S.alignment)
+
+    def test_nested_structures(self):
+        import _rawffi
+        S1 = _rawffi.Structure([('a', 'i'), ('b', 'P'), ('c', 'c')])
+        S = _rawffi.Structure([('x', 'c'), ('s1', S1.gettypecode())])
+        assert S.size == S1.alignment + S1.size
+        assert S.alignment == S1.alignment
+        assert S.getfieldoffset('x') == 0
+        assert S.getfieldoffset('s1') == S1.alignment
+        s = S()
+        s.x = 'G'
+        raises(TypeError, 's.s1')
+        assert s.fieldaddress('s1') == s.buffer + S.getfieldoffset('s1')
+        s1 = S1.fromaddress(s.fieldaddress('s1'))
+        s1.c = 'H'
+        rawbuf = _rawffi.Array('c').fromaddress(s.buffer, S.size)
+        assert rawbuf[0] == 'G'
+        assert rawbuf[S1.alignment + S1.getfieldoffset('c')] == 'H'
+        s.free()

Modified: pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test_struct.py
==============================================================================
--- pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test_struct.py	(original)
+++ pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test_struct.py	Tue Jan 15 12:41:48 2008
@@ -1,10 +1,11 @@
 
-from pypy.module._rawffi.structure import size_alignment_pos, TYPEMAP
+from pypy.module._rawffi.structure import size_alignment_pos
+from pypy.module._rawffi.interp_rawffi import TYPEMAP, letter2tp
 
 sizeof = lambda x : size_alignment_pos(x)[0]
 
 def unpack(desc):
-    return [('x', i) for i in desc]
+    return [('x', letter2tp('space', i)) for i in desc]
 
 def test_sizeof():
     s_c = sizeof(unpack('c'))



More information about the Pypy-commit mailing list