Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r67889:73de8b43bff0
Date: 2013-11-09 10:33 +0100
http://bitbucket.org/pypy/pypy/changeset/73de8b43bff0/

Log:    Port cffi's c99-array branch.

diff --git a/pypy/module/_cffi_backend/ctypearray.py 
b/pypy/module/_cffi_backend/ctypearray.py
--- a/pypy/module/_cffi_backend/ctypearray.py
+++ b/pypy/module/_cffi_backend/ctypearray.py
@@ -34,19 +34,8 @@
         datasize = self.size
         #
         if datasize < 0:
-            if (space.isinstance_w(w_init, space.w_list) or
-                space.isinstance_w(w_init, space.w_tuple)):
-                length = space.int_w(space.len(w_init))
-            elif space.isinstance_w(w_init, space.w_basestring):
-                # from a string, we add the null terminator
-                length = space.int_w(space.len(w_init)) + 1
-            else:
-                length = space.getindex_w(w_init, space.w_OverflowError)
-                if length < 0:
-                    raise OperationError(space.w_ValueError,
-                                         space.wrap("negative array length"))
-                w_init = space.w_None
-            #
+            from pypy.module._cffi_backend import misc
+            w_init, length = misc.get_new_array_length(space, w_init)
             try:
                 datasize = ovfcheck(length * self.ctitem.size)
             except OverflowError:
diff --git a/pypy/module/_cffi_backend/ctypeptr.py 
b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -15,15 +15,12 @@
 
 
 class W_CTypePtrOrArray(W_CType):
-    _attrs_            = ['ctitem', 'can_cast_anything', 'is_struct_ptr',
-                          'length']
-    _immutable_fields_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr',
-                          'length']
+    _attrs_            = ['ctitem', 'can_cast_anything', 'length']
+    _immutable_fields_ = ['ctitem', 'can_cast_anything', 'length']
     length = -1
 
     def __init__(self, space, size, extra, extra_position, ctitem,
                  could_cast_anything=True):
-        from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
         name, name_position = ctitem.insert_name(extra, extra_position)
         W_CType.__init__(self, space, size, name, name_position)
         # this is the "underlying type":
@@ -32,7 +29,6 @@
         #  - for functions, it is the return type
         self.ctitem = ctitem
         self.can_cast_anything = could_cast_anything and ctitem.cast_anything
-        self.is_struct_ptr = isinstance(ctitem, W_CTypeStructOrUnion)
 
     def is_char_ptr_or_array(self):
         return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar)
@@ -195,6 +191,7 @@
         W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem)
 
     def newp(self, w_init):
+        from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
         space = self.space
         ctitem = self.ctitem
         datasize = ctitem.size
@@ -202,10 +199,15 @@
             raise operationerrfmt(space.w_TypeError,
                 "cannot instantiate ctype '%s' of unknown size",
                                   self.name)
-        if self.is_struct_ptr:
+        if isinstance(ctitem, W_CTypeStructOrUnion):
             # 'newp' on a struct-or-union pointer: in this case, we return
             # a W_CDataPtrToStruct object which has a strong reference
             # to a W_CDataNewOwning that really contains the structure.
+            #
+            if ctitem.with_var_array and not space.is_w(w_init, space.w_None):
+                datasize = ctitem.convert_struct_from_object(
+                    lltype.nullptr(rffi.CCHARP.TO), w_init, datasize)
+            #
             cdatastruct = cdataobj.W_CDataNewOwning(space, datasize, ctitem)
             cdata = cdataobj.W_CDataPtrToStructOrUnion(space,
                                                        cdatastruct._cdata,
@@ -321,7 +323,8 @@
         space = self.space
         ctype2 = cdata.ctype
         if (isinstance(ctype2, W_CTypeStructOrUnion) or
-            (isinstance(ctype2, W_CTypePtrOrArray) and ctype2.is_struct_ptr)):
+               (isinstance(ctype2, W_CTypePtrOrArray) and
+                isinstance(ctype2.ctitem, W_CTypeStructOrUnion))):
             ptrdata = rffi.ptradd(cdata._cdata, offset)
             return cdataobj.W_CData(space, ptrdata, self)
         else:
diff --git a/pypy/module/_cffi_backend/ctypestruct.py 
b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -9,7 +9,8 @@
 from rpython.rlib import jit
 from rpython.rlib.objectmodel import keepalive_until_here
 from rpython.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, intmask
-from rpython.rtyper.lltypesystem import rffi
+from rpython.rlib.rarithmetic import ovfcheck
+from rpython.rtyper.lltypesystem import lltype, rffi
 
 from pypy.module._cffi_backend import cdataobj, ctypeprim, misc
 from pypy.module._cffi_backend.ctypeobj import W_CType
@@ -17,12 +18,13 @@
 
 class W_CTypeStructOrUnion(W_CType):
     _immutable_fields_ = ['alignment?', 'fields_list?', 'fields_dict?',
-                          'custom_field_pos?']
+                          'custom_field_pos?', 'with_var_array?']
     # fields added by complete_struct_or_union():
     alignment = -1
     fields_list = None
     fields_dict = None
     custom_field_pos = False
+    with_var_array = False
 
     def __init__(self, space, name):
         W_CType.__init__(self, space, -1, name, len(name))
@@ -90,12 +92,13 @@
         pass
 
     def convert_from_object(self, cdata, w_ob):
-        space = self.space
-        if self._copy_from_same(cdata, w_ob):
-            return
+        if not self._copy_from_same(cdata, w_ob):
+            self.convert_struct_from_object(cdata, w_ob)
 
+    def convert_struct_from_object(self, cdata, w_ob, optvarsize=-1):
         self._check_only_one_argument_for_union(w_ob)
 
+        space = self.space
         if (space.isinstance_w(w_ob, space.w_list) or
             space.isinstance_w(w_ob, space.w_tuple)):
             lst_w = space.listview(w_ob)
@@ -104,7 +107,9 @@
                         "too many initializers for '%s' (got %d)",
                                       self.name, len(lst_w))
             for i in range(len(lst_w)):
-                self.fields_list[i].write(cdata, lst_w[i])
+                optvarsize = self.fields_list[i].write_v(cdata, lst_w[i],
+                                                         optvarsize)
+            return optvarsize
 
         elif space.isinstance_w(w_ob, space.w_dict):
             lst_w = space.fixedview(w_ob)
@@ -116,11 +121,16 @@
                 except KeyError:
                     space.raise_key_error(w_key)
                     assert 0
-                cf.write(cdata, space.getitem(w_ob, w_key))
+                optvarsize = cf.write_v(cdata, space.getitem(w_ob, w_key),
+                                        optvarsize)
+            return optvarsize
 
         else:
-            raise self._convert_error("list or tuple or dict or struct-cdata",
-                                      w_ob)
+            if optvarsize == -1:
+                msg = "list or tuple or dict or struct-cdata"
+            else:
+                msg = "list or tuple or dict"
+            raise self._convert_error(msg, w_ob)
 
     @jit.elidable
     def _getcfield_const(self, attr):
@@ -192,6 +202,37 @@
         else:
             self.ctype.convert_from_object(cdata, w_ob)
 
+    def write_v(self, cdata, w_ob, optvarsize):
+        # a special case for var-sized C99 arrays
+        from pypy.module._cffi_backend import ctypearray
+        ct = self.ctype
+        if isinstance(ct, ctypearray.W_CTypeArray) and ct.length < 0:
+            space = ct.space
+            w_ob, varsizelength = misc.get_new_array_length(space, w_ob)
+            if optvarsize != -1:
+                # in this mode, the only purpose of this function is to compute
+                # the real size of the structure from a var-sized C99 array
+                assert cdata == lltype.nullptr(rffi.CCHARP.TO)
+                itemsize = ct.ctitem.size
+                try:
+                    varsize = ovfcheck(itemsize * varsizelength)
+                    size = ovfcheck(self.offset + varsize)
+                except OverflowError:
+                    raise OperationError(space.w_OverflowError,
+                        space.wrap("array size would overflow a ssize_t"))
+                assert size >= 0
+                return max(size, optvarsize)
+            # if 'value' was only an integer, get_new_array_length() returns
+            # w_ob = space.w_None.  Detect if this was the case,
+            # and if so, stop here, leaving the content uninitialized
+            # (it should be zero-initialized from somewhere else).
+            if space.is_w(w_ob, space.w_None):
+                return optvarsize
+        #
+        if optvarsize == -1:
+            self.write(cdata, w_ob)
+        return optvarsize
+
     def convert_bitfield_to_object(self, cdata):
         ctype = self.ctype
         space = ctype.space
diff --git a/pypy/module/_cffi_backend/misc.py 
b/pypy/module/_cffi_backend/misc.py
--- a/pypy/module/_cffi_backend/misc.py
+++ b/pypy/module/_cffi_backend/misc.py
@@ -278,6 +278,22 @@
 
 # ____________________________________________________________
 
+def get_new_array_length(space, w_value):
+    if (space.isinstance_w(w_value, space.w_list) or
+        space.isinstance_w(w_value, space.w_tuple)):
+        return (w_value, space.int_w(space.len(w_value)))
+    elif space.isinstance_w(w_value, space.w_basestring):
+        # from a string, we add the null terminator
+        return (w_value, space.int_w(space.len(w_value)) + 1)
+    else:
+        explicitlength = space.getindex_w(w_value, space.w_OverflowError)
+        if explicitlength < 0:
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("negative array length"))
+        return (space.w_None, explicitlength)
+
+# ____________________________________________________________
+
 @specialize.arg(0)
 def _raw_memcopy_tp(TPP, source, dest):
     # in its own function: LONGLONG may make the whole function jit-opaque
diff --git a/pypy/module/_cffi_backend/newtype.py 
b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -158,8 +158,10 @@
     fields_list = []
     fields_dict = {}
     custom_field_pos = False
+    with_var_array = False
 
-    for w_field in fields_w:
+    for i in range(len(fields_w)):
+        w_field = fields_w[i]
         field_w = space.fixedview(w_field)
         if not (2 <= len(field_w) <= 4):
             raise OperationError(space.w_TypeError,
@@ -176,7 +178,11 @@
                                   "duplicate field name '%s'", fname)
         #
         if ftype.size < 0:
-            raise operationerrfmt(space.w_TypeError,
+            if (isinstance(ftype, ctypearray.W_CTypeArray) and fbitsize < 0
+                    and (i == len(fields_w) - 1 or foffset != -1)):
+                with_var_array = True
+            else:
+                raise operationerrfmt(space.w_TypeError,
                     "field '%s.%s' has ctype '%s' of unknown size",
                                   w_ctype.name, fname, ftype.name)
         #
@@ -235,7 +241,8 @@
                 fields_list.append(fld)
                 fields_dict[fname] = fld
 
-            boffset += ftype.size * 8
+            if ftype.size >= 0:
+                boffset += ftype.size * 8
             prev_bitfield_size = 0
 
         else:
@@ -359,6 +366,7 @@
     w_ctype.fields_list = fields_list
     w_ctype.fields_dict = fields_dict
     w_ctype.custom_field_pos = custom_field_pos
+    w_ctype.with_var_array = with_var_array
 
 # ____________________________________________________________
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to