[pypy-commit] cffi default: Tweaks, and add extra tests, which fail for now :-/

arigo pypy.commits at gmail.com
Wed Oct 19 03:43:46 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r2793:6d176858847d
Date: 2016-10-19 09:43 +0200
http://bitbucket.org/cffi/cffi/changeset/6d176858847d/

Log:	Tweaks, and add extra tests, which fail for now :-/

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -132,7 +132,7 @@
 #define CT_PRIMITIVE_FITS_LONG   2048
 #define CT_IS_OPAQUE             4096
 #define CT_IS_ENUM               8192
-#define CT_IS_PTR_TO_OWNED      16384
+#define CT_IS_PTR_TO_OWNED      16384   /* only if CDataOwning_Type! */
 #define CT_CUSTOM_FIELD_POS     32768
 #define CT_IS_LONGDOUBLE        65536
 #define CT_IS_BOOL             131072
@@ -185,7 +185,8 @@
     PyObject_HEAD
     CTypeDescrObject *cf_type;
     Py_ssize_t cf_offset;
-    short cf_bitshift;   /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY or BS_VARSIZESTRUCT_ARRAY */
+    short cf_bitshift;   /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY
+                                            or BS_VARSIZESTRUCT_ARRAY */
     short cf_bitsize;
     unsigned char cf_flags;   /* BF_... */
     struct cfieldobject_s *cf_next;
@@ -239,7 +240,6 @@
 
 typedef struct {
     CDataObject head;
-    Py_ssize_t length;     /* same as CDataObject_own_length up to here */
     PyObject *structobj;
 } CDataObject_own_structptr;
 
@@ -1854,7 +1854,7 @@
 {
     Py_ssize_t size;
     if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED)
-        size = ((CDataObject_own_structptr *)cd)->length;
+        size = ((CDataObject_own_length *)cd)->length;
     else if (cd->c_type->ct_flags & CT_POINTER)
         size = cd->c_type->ct_itemdescr->ct_size;
     else if (cd->c_type->ct_flags & CT_ARRAY)
@@ -2427,10 +2427,17 @@
                 /* read the field 'cf' */
                 char *data = cd->c_data + cf->cf_offset;
 
-                if ((cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) &&  // Is owned struct (or union)
-                    (cf->cf_bitshift == BS_VARSIZESTRUCT_ARRAY)) { // variable length array
-                    /* if reading variable length array from variable length struct, calculate array type from allocated length*/
-                    Py_ssize_t array_len = (((CDataObject_own_structptr *)cd)->length - ct->ct_size) / cf->cf_type->ct_itemdescr->ct_size;
+                if (cf->cf_bitshift == BS_VARSIZESTRUCT_ARRAY) {
+                    /* variable-length array */
+                    if (!CDataOwn_Check(cd)) {
+                        return new_simple_cdata(data,
+                            (CTypeDescrObject *)cf->cf_type->ct_stuff);
+                    }
+                    /* if reading variable length array from variable length
+                       struct, calculate array type from allocated length*/
+                    Py_ssize_t array_len =
+                       (((CDataObject_own_structptr *)cd)->length - ct->ct_size)
+                       / cf->cf_type->ct_itemdescr->ct_size;
                     return new_sized_cdata(data, cf->cf_type, array_len);
                 }
                 else if (cf->cf_bitshift == BS_REGULAR)
@@ -3192,12 +3199,15 @@
         if (ctitem->ct_flags & CT_PRIMITIVE_CHAR)
             datasize *= 2;   /* forcefully add another character: a null */
 
+        if (force_lazy_struct(ctitem) < 0)   /* for CT_WITH_VAR_ARRAY */
+            return NULL;
+        if (ctitem->ct_flags & CT_WITH_VAR_ARRAY)
+            dataoffset = offsetof(CDataObject_own_length, alignment);
+
         if ((ctitem->ct_flags & (CT_STRUCT | CT_UNION)) && init != Py_None) {
-            if (force_lazy_struct(ctitem) < 0)   /* for CT_WITH_VAR_ARRAY */
-                return NULL;
             if (ctitem->ct_flags & CT_WITH_VAR_ARRAY) {
                 Py_ssize_t optvarsize = datasize;
-                if (convert_struct_from_object(NULL,ctitem, init,
+                if (convert_struct_from_object(NULL, ctitem, init,
                                                &optvarsize) < 0)
                     return NULL;
                 datasize = optvarsize;
@@ -3249,7 +3259,7 @@
         /* store the only reference to cds into cd */
         ((CDataObject_own_structptr *)cd)->structobj = (PyObject *)cds;
         /* store information about the allocated size of the struct */
-        ((CDataObject_own_structptr *)cd)->length = datasize;
+        ((CDataObject_own_length *)cds)->length = datasize;
         assert(explicitlength < 0);
 
         cd->c_data = cds->c_data;
@@ -4321,7 +4331,7 @@
             /* not a bitfield: common case */
             int bs_flag;
 
-            if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == -1 && i == nb_fields - 1)
+            if ((i == nb_fields - 1) && (ct->ct_flags & CT_WITH_VAR_ARRAY))
                 bs_flag = BS_VARSIZESTRUCT_ARRAY;
             else if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == 0)
                 bs_flag = BS_EMPTY_ARRAY;
@@ -5865,7 +5875,8 @@
                                      &CData_Type, &cd, &size))
         return NULL;
 
-    if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) {
+    if ((cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) && CDataOwn_Check(cd)) {
+        abort();
         if (size < 0)
             size = ((CDataObject_own_structptr *)cd)->length;
     }
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -3200,7 +3200,9 @@
             assert p.y[2] == 0
             p.y[2] = 400
         assert len(p.y) == 3
+        assert len(p[0].y) == 3
         assert len(buffer(p)) == sizeof(BInt) * 4
+        assert len(buffer(p[0])) == sizeof(BInt) * 4
         plist.append(p)
     for i in range(20):
         p = plist[i]
@@ -3211,8 +3213,23 @@
         assert list(p.y) == [200, i, 400]
     #
     # the following assignment works, as it normally would, for any array field
-    p.y = [500, 600]
-    assert list(p.y) == [500, 600, 400]
+    p.y = [501, 601]
+    assert list(p.y) == [501, 601, 400]
+    p[0].y = [500, 600]
+    assert list(p[0].y) == [500, 600, 400]
+    assert repr(p) == "<cdata 'foo *' owning %d bytes>" % (
+        sizeof(BStruct) + 3 * sizeof(BInt),)
+    assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % (
+        sizeof(BStruct) + 3 * sizeof(BInt),)
+    #
+    # from a non-owning pointer, we can't get the length
+    q = cast(new_pointer_type(BStruct), p)
+    assert q.y[0] == 500
+    assert q[0].y[0] == 500
+    py.test.raises(TypeError, len, q.y)
+    py.test.raises(TypeError, len, q[0].y)
+    assert typeof(q.y) is BIntP
+    assert typeof(q[0].y) is BIntP
     #
     # error cases
     py.test.raises(IndexError, "p.y[4]")
diff --git a/testing/cffi0/test_ffi_backend.py b/testing/cffi0/test_ffi_backend.py
--- a/testing/cffi0/test_ffi_backend.py
+++ b/testing/cffi0/test_ffi_backend.py
@@ -282,10 +282,20 @@
         ffi.cdef("struct foo_s { int x; int a[]; };")
         p = ffi.new("struct foo_s *", [100, [200, 300, 400]])
         assert p.x == 100
-        assert ffi.typeof(p.a) is ffi.typeof("int *")   # no length available
+        assert ffi.typeof(p.a) is ffi.typeof("int[]")
+        assert len(p.a) == 3                            # length recorded
         assert p.a[0] == 200
         assert p.a[1] == 300
         assert p.a[2] == 400
+        assert list(p.a) == [200, 300, 400]
+        q = ffi.cast("struct foo_s *", p)
+        assert q.x == 100
+        assert ffi.typeof(q.a) is ffi.typeof("int *")   # no length recorded
+        py.test.raises(TypeError, len, q.a)
+        assert q.a[0] == 200
+        assert q.a[1] == 300
+        assert q.a[2] == 400
+        py.test.raises(TypeError, list, q.a)
 
     @pytest.mark.skipif("sys.platform != 'win32'")
     def test_getwinerror(self):


More information about the pypy-commit mailing list