[pypy-commit] cffi cpy-extension: Completing structs.
arigo
noreply at buildbot.pypy.org
Tue Jun 12 23:24:28 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: cpy-extension
Changeset: r303:b69a8e2d13a1
Date: 2012-06-12 23:24 +0200
http://bitbucket.org/cffi/cffi/changeset/b69a8e2d13a1/
Log: Completing structs.
diff --git a/c/_ffi_backend.c b/c/_ffi_backend.c
--- a/c/_ffi_backend.c
+++ b/c/_ffi_backend.c
@@ -2271,12 +2271,14 @@
PyObject *fields, *interned_fields, *ignored;
int is_union, alignment;
Py_ssize_t offset, i, nb_fields, maxsize, prev_bit_position;
+ Py_ssize_t totalsize = -1;
+ int totalalignment = -1;
CFieldObject **previous, *prev_field;
- if (!PyArg_ParseTuple(args, "O!O!|O:complete_struct_or_union",
+ if (!PyArg_ParseTuple(args, "O!O!|Oni:complete_struct_or_union",
&CTypeDescr_Type, &ct,
&PyList_Type, &fields,
- &ignored))
+ &ignored, &totalsize, &totalalignment))
return NULL;
if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) ==
@@ -2308,13 +2310,13 @@
for (i=0; i<nb_fields; i++) {
PyObject *fname;
CTypeDescrObject *ftype;
- int fbitsize, falign, err, bitshift;
+ int fbitsize, falign, err, bitshift, foffset = -1;
CFieldObject *cf;
- if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!i:list item",
+ if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!i|i:list item",
&PyString_Type, &fname,
&CTypeDescr_Type, &ftype,
- &fbitsize))
+ &fbitsize, &foffset))
goto error;
if (ftype->ct_size < 0) {
@@ -2331,8 +2333,12 @@
if (alignment < falign)
alignment = falign;
- /* align this field to its own 'falign' by inserting padding */
- offset = (offset + falign - 1) & ~(falign-1);
+ if (foffset < 0) {
+ /* align this field to its own 'falign' by inserting padding */
+ offset = (offset + falign - 1) & ~(falign-1);
+ }
+ else
+ offset = foffset;
if (fbitsize < 0 || (fbitsize == 8 * ftype->ct_size &&
!(ftype->ct_flags & CT_PRIMITIVE_CHAR))) {
@@ -2407,15 +2413,23 @@
if (is_union) {
assert(offset == 0);
- ct->ct_size = maxsize;
+ offset = maxsize;
}
else {
if (offset == 0)
offset = 1;
offset = (offset + alignment - 1) & ~(alignment-1);
- ct->ct_size = offset;
}
- ct->ct_length = alignment;
+ if (totalsize < 0)
+ totalsize = offset;
+ else if (totalsize < offset) {
+ PyErr_Format(PyExc_TypeError,
+ "%s cannot be of size %zd: there are fields at least "
+ "up to %zd", ct->ct_name, totalsize, offset);
+ goto error;
+ }
+ ct->ct_size = totalsize;
+ ct->ct_length = totalalignment < 0 ? alignment : totalalignment;
ct->ct_stuff = interned_fields;
ct->ct_flags &= ~CT_IS_OPAQUE;
@@ -3328,6 +3342,28 @@
return result;
}
+static PyObject *_cffi_get_struct_layout(Py_ssize_t nums[])
+{
+ PyObject *result;
+ int count = 0;
+ while (nums[count] >= 0)
+ count++;
+
+ result = PyList_New(count);
+ if (result == NULL)
+ return NULL;
+
+ while (--count >= 0) {
+ PyObject *o = PyInt_FromSsize_t(nums[count]);
+ if (o == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ PyList_SET_ITEM(result, count, o);
+ }
+ return result;
+}
+
static void *cffi_exports[] = {
_cffi_to_c_char_p,
_cffi_to_c_signed_char,
@@ -3346,6 +3382,7 @@
_cffi_to_c_char,
_cffi_from_c_pointer,
_cffi_to_c_pointer,
+ _cffi_get_struct_layout,
};
/************************************************************/
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -129,7 +129,8 @@
class StructOrUnion(BaseType):
_attrs_ = ('name',)
-
+ fixedlayout = None
+
def __init__(self, name, fldnames, fldtypes, fldbitsize):
self.name = name
self.fldnames = fldnames
@@ -148,8 +149,14 @@
return args
def finish_backend_type(self, ffi, BType, *fldtypes):
- lst = zip(self.fldnames, fldtypes, self.fldbitsize)
- ffi._backend.complete_struct_or_union(BType, lst, self)
+ if self.fixedlayout is None:
+ lst = zip(self.fldnames, fldtypes, self.fldbitsize)
+ ffi._backend.complete_struct_or_union(BType, lst, self)
+ else:
+ fieldofs, totalsize, totalalignment = self.fixedlayout
+ lst = zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs)
+ ffi._backend.complete_struct_or_union(BType, lst, self,
+ totalsize, totalalignment)
return BType
@@ -158,7 +165,7 @@
partial = False
def check_not_partial(self):
- if self.partial:
+ if self.partial and self.fixedlayout is None:
from . import ffiplatform
raise ffiplatform.VerificationMissing(self.get_c_name())
@@ -166,59 +173,6 @@
self.check_not_partial()
return ffi._backend.new_struct_type(self.name)
- def verifier_declare_struct(self, verifier, name):
- assert name == self.name
- if self.partial:
- self.verifier_decl_partial(verifier)
- else:
- self.verifier_decl_notpartial(verifier)
-
- def verifier_decl_notpartial(self, verifier):
- if self.fldnames is None: # not partial, but fully opaque:
- return # cannot really test even for existence
- struct = verifier.ffi._get_cached_btype(self)
- verifier.write('{')
- verifier.write('struct __aligncheck__ { char x; struct %s y; };' %
- self.name)
- verifier.write(
- '__sameconstant__(sizeof(struct %s), %d)' % (
- self.name, verifier.ffi.sizeof(struct)))
- verifier.write(
- '__sameconstant__(offsetof(struct __aligncheck__, y), %d)' % (
- verifier.ffi.alignof(struct),))
- for fname, ftype, fbitsize in zip(self.fldnames, self.fldtypes,
- self.fldbitsize):
- if fbitsize >= 0:
- assert 0, "XXX: bitfield"
- verifier.write('__sameconstant__(offsetof(struct %s, %s), %d)' % (
- self.name, fname, verifier.ffi.offsetof(struct, fname)))
- # XXX gcc only!
- verifier.write('__sametype__(%s, typeof(((struct %s *)0)->%s))' % (
- ftype.get_c_name('** result'), self.name, fname))
- verifier.write('}')
-
- def verifier_decl_partial(self, verifier):
- assert self.fldnames is not None
- verifier.write('{')
- verifier.write('struct __aligncheck__ { char x; struct %s y; };' %
- self.name)
- verifier.write('struct %s __test__;' % self.name)
- verifier.write_printf('BEGIN struct %s' % self.name)
- verifier.write_printf('SIZE %ld %ld',
- '(long)sizeof(struct %s)' % self.name,
- '(long)offsetof(struct __aligncheck__, y)')
- for fname, ftype, fbitsize in zip(self.fldnames, self.fldtypes,
- self.fldbitsize):
- if fbitsize < 0:
- verifier.write_printf('FIELD ' + fname + ' %ld %ld',
- '(long)offsetof(struct %s, %s)' %
- (self.name, fname),
- '(long)sizeof(__test__.%s)' % fname)
- else:
- assert 0, "XXX: bitfield"
- verifier.write_printf('END')
- verifier.write('}')
-
class UnionType(StructOrUnion):
kind = 'union'
diff --git a/cffi/verifier.py b/cffi/verifier.py
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -68,6 +68,12 @@
lst = [revmapping[i] for i in range(len(revmapping))]
module._cffi_setup(lst)
del module._cffi_setup
+ #
+ for name, tp in self.ffi._parser._declarations.iteritems():
+ kind, realname = name.split(' ', 1)
+ method = getattr(self, 'loading_cpy_%s' % (kind,))
+ method(tp, realname, module)
+ #
return module
def generate(self, step_name):
@@ -79,6 +85,9 @@
def generate_nothing(self, tp, name):
pass
+ def loaded_noop(self, tp, name, module):
+ pass
+
# ----------
def convert_to_c(self, tp, fromvar, tovar, errcode, is_funcarg=False):
@@ -115,13 +124,15 @@
raise NotImplementedError(tp)
# ----------
+ # typedefs: generates no code so far
- # XXX
generate_cpy_typedef_decl = generate_nothing
generate_cpy_typedef_method = generate_nothing
generate_cpy_typedef_init = generate_nothing
+ loading_cpy_typedef = loaded_noop
# ----------
+ # function declarations
def generate_cpy_function_decl(self, tp, name):
assert isinstance(tp, model.FunctionType)
@@ -133,8 +144,8 @@
argname = 'arg0'
else:
argname = 'args'
- prnt('static PyObject *_cffi_f_%s(PyObject *self, PyObject *%s)' %
- (name, argname))
+ prnt('static PyObject *')
+ prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
prnt('{')
assert not tp.ellipsis # XXX later
#
@@ -186,10 +197,50 @@
self.prnt(' {"%s", _cffi_f_%s, %s},' % (name, name, meth))
generate_cpy_function_init = generate_nothing
+ loading_cpy_function = loaded_noop
+
+ # ----------
+ # struct declarations
+
+ def generate_cpy_struct_decl(self, tp, name):
+ assert name == tp.name
+ prnt = self.prnt
+ prnt('static PyObject *')
+ prnt('_cffi_struct_%s(PyObject *self, PyObject *noarg)' % name)
+ prnt('{')
+ prnt(' struct _cffi_aligncheck { char x; struct %s y; };' % name)
+ prnt(' static Py_ssize_t nums[] = {')
+ prnt(' sizeof(struct %s),' % name)
+ prnt(' offsetof(struct _cffi_aligncheck, y),')
+ for i in range(len(tp.fldnames)):
+ prnt(' offsetof(struct %s, %s),' % (name, tp.fldnames[i]))
+ prnt(' -1')
+ prnt(' };')
+ prnt(' return _cffi_get_struct_layout(nums);')
+ prnt('}')
+
+ def generate_cpy_struct_method(self, tp, name):
+ self.prnt(' {"_cffi_struct_%s", _cffi_struct_%s, METH_NOARGS},' % (
+ name, name))
+
+ generate_cpy_struct_init = generate_nothing
+
+ def loading_cpy_struct(self, tp, name, module):
+ assert name == tp.name
+ function = getattr(module, '_cffi_struct_%s' % name)
+ layout = function()
+ totalsize = layout[0]
+ totalalignment = layout[1]
+ fieldofs = layout[2:]
+ assert len(fieldofs) == len(tp.fldnames)
+ tp.fixedlayout = fieldofs, totalsize, totalalignment
+
+ # ----------
cffimod_header = r'''
#include <Python.h>
+#include <stddef.h>
#define _cffi_from_c_double PyFloat_FromDouble
#define _cffi_from_c_float PyFloat_FromDouble
@@ -253,6 +304,8 @@
((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10])
#define _cffi_to_c_pointer \
((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11])
+#define _cffi_get_struct_layout \
+ ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12])
#if SIZEOF_LONG < SIZEOF_LONG_LONG
# define _cffi_to_c_long_long PyLong_AsLongLong
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -113,7 +113,7 @@
def test_verify_typedefs():
- py.test.skip("XXX?")
+ py.test.skip("ignored so far")
types = ['signed char', 'unsigned char', 'int', 'long']
for cdefed in types:
for real in types:
@@ -127,7 +127,7 @@
def test_ffi_full_struct():
- py.test.skip("XXX?")
+ py.test.skip("XXX")
ffi = FFI()
ffi.cdef("struct foo_s { char x; int y; long *z; };")
ffi.verify("struct foo_s { char x; int y; long *z; };")
@@ -147,7 +147,6 @@
def test_ffi_nonfull_struct():
- py.test.skip("XXX")
ffi = FFI()
ffi.cdef("""
struct foo_s {
@@ -163,5 +162,5 @@
int a, b, x, c, d, e;
};
""")
- assert ffi.sizeof('struct foo_s') == 6 * ffi.sizeof(int)
- assert ffi.offsetof('struct foo_s', 'x') == 2 * ffi.sizeof(int)
+ assert ffi.sizeof('struct foo_s') == 6 * ffi.sizeof('int')
+ assert ffi.offsetof('struct foo_s', 'x') == 2 * ffi.sizeof('int')
More information about the pypy-commit
mailing list