Author: Armin Rigo <ar...@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): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit