Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit