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