Author: Armin Rigo <armin.r...@gmail.com>
Branch: 
Changeset: r2792:0650dc86447a
Date: 2016-10-19 06:53 +0000
http://bitbucket.org/cffi/cffi/changeset/0650dc86447a/

Log:    Merged in coronafire/cffi/calculate_variable_array_length (pull
        request #71)

        Track and use length of variable length structs and their varsized
        array

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -185,14 +185,15 @@
     PyObject_HEAD
     CTypeDescrObject *cf_type;
     Py_ssize_t cf_offset;
-    short cf_bitshift;   /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_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;
 } CFieldObject;
-#define BS_REGULAR     (-1)      /* a regular field, not with bitshift */
-#define BS_EMPTY_ARRAY (-2)      /* a field which is an array 'type[0]' */
-#define BF_IGNORE_IN_CTOR  0x01  /* union field not in the first place */
+#define BS_REGULAR             (-1) /* a regular field, not with bitshift */
+#define BS_EMPTY_ARRAY         (-2) /* a field which is an array 'type[0]' */
+#define BS_VARSIZESTRUCT_ARRAY (-3) /* a variable sized struct variable field 
'type[]' */
+#define BF_IGNORE_IN_CTOR      0x01 /* union field not in the first place */
 
 static PyTypeObject CTypeDescr_Type;
 static PyTypeObject CField_Type;
@@ -238,6 +239,7 @@
 
 typedef struct {
     CDataObject head;
+    Py_ssize_t length;     /* same as CDataObject_own_length up to here */
     PyObject *structobj;
 } CDataObject_own_structptr;
 
@@ -908,6 +910,23 @@
     return (PyObject *)cd;
 }
 
+static PyObject *
+new_sized_cdata(char *data, CTypeDescrObject *ct, Py_ssize_t length)
+{
+    CDataObject_own_length *scd;
+    
+    scd = (CDataObject_own_length *)PyObject_Malloc(
+        offsetof(CDataObject_own_length, alignment));
+    if (PyObject_Init((PyObject *)scd, &CData_Type) == NULL)
+        return NULL;
+    Py_INCREF(ct);
+    scd->head.c_type = ct;
+    scd->head.c_data = data;
+    scd->head.c_weakreflist = NULL;
+    scd->length = length;
+    return (PyObject *)scd;
+}
+
 static CDataObject *_new_casted_primitive(CTypeDescrObject *ct);  /*forward*/
 
 static PyObject *
@@ -1834,7 +1853,9 @@
 static PyObject *cdataowning_repr(CDataObject *cd)
 {
     Py_ssize_t size;
-    if (cd->c_type->ct_flags & CT_POINTER)
+    if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED)
+        size = ((CDataObject_own_structptr *)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)
         size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
@@ -2405,7 +2426,14 @@
             if (cf != NULL) {
                 /* read the field 'cf' */
                 char *data = cd->c_data + cf->cf_offset;
-                if (cf->cf_bitshift == BS_REGULAR)
+
+                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;
+                    return new_sized_cdata(data, cf->cf_type, array_len);
+                }
+                else if (cf->cf_bitshift == BS_REGULAR)
                     return convert_to_object(data, cf->cf_type);
                 else if (cf->cf_bitshift == BS_EMPTY_ARRAY)
                     return new_simple_cdata(data,
@@ -3220,6 +3248,8 @@
         }
         /* 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;
         assert(explicitlength < 0);
 
         cd->c_data = cds->c_data;
@@ -4291,7 +4321,9 @@
             /* not a bitfield: common case */
             int bs_flag;
 
-            if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == 0)
+            if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == -1 && i == 
nb_fields - 1)
+                bs_flag = BS_VARSIZESTRUCT_ARRAY;
+            else if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == 0)
                 bs_flag = BS_EMPTY_ARRAY;
             else
                 bs_flag = BS_REGULAR;
@@ -5833,7 +5865,11 @@
                                      &CData_Type, &cd, &size))
         return NULL;
 
-    if (cd->c_type->ct_flags & CT_POINTER) {
+    if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) {
+        if (size < 0)
+            size = ((CDataObject_own_structptr *)cd)->length;
+    }
+    else if (cd->c_type->ct_flags & CT_POINTER) {
         if (size < 0)
             size = cd->c_type->ct_itemdescr->ct_size;
     }
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -3172,17 +3172,19 @@
     assert d[1][0] == 'y'
     assert d[1][1].type is BArray
     assert d[1][1].offset == size_of_int()
-    assert d[1][1].bitshift == -1
+    assert d[1][1].bitshift == -3
     assert d[1][1].bitsize == -1
     #
     p = newp(new_pointer_type(BStruct))
     p.x = 42
     assert p.x == 42
-    assert typeof(p.y) is BIntP
+    assert typeof(p.y) is BArray
+    assert len(p.y) == 0
     assert p.y == cast(BIntP, p) + 1
     #
     p = newp(new_pointer_type(BStruct), [100])
     assert p.x == 100
+    assert len(p.y) == 0
     #
     # Tests for
     #    ffi.new("struct_with_var_array *", [field.., [the_array_items..]])
@@ -3197,6 +3199,8 @@
             p.y[0] = 200
             assert p.y[2] == 0
             p.y[2] = 400
+        assert len(p.y) == 3
+        assert len(buffer(p)) == sizeof(BInt) * 4
         plist.append(p)
     for i in range(20):
         p = plist[i]
@@ -3204,13 +3208,14 @@
         assert p.y[0] == 200
         assert p.y[1] == i
         assert p.y[2] == 400
-        assert list(p.y[0:3]) == [200, i, 400]
+        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[0:3]) == [500, 600, 400]
+    assert list(p.y) == [500, 600, 400]
     #
     # error cases
+    py.test.raises(IndexError, "p.y[4]")
     py.test.raises(TypeError, "p.y = cast(BIntP, 0)")
     py.test.raises(TypeError, "p.y = 15")
     py.test.raises(TypeError, "p.y = None")
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to