[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