[pypy-commit] cffi default: Support the baseline case of functions returning structs.
arigo
noreply at buildbot.pypy.org
Thu Jun 28 21:39:11 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r556:0ed9b03dd40d
Date: 2012-06-28 21:38 +0200
http://bitbucket.org/cffi/cffi/changeset/0ed9b03dd40d/
Log: Support the baseline case of functions returning structs.
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -1749,10 +1749,26 @@
/************************************************************/
+static CDataObject *allocate_owning_object(Py_ssize_t dataoffset,
+ Py_ssize_t datasize,
+ CTypeDescrObject *ct)
+{
+ CDataObject_own_base *cdb;
+ cdb = (CDataObject_own_base *)PyObject_Malloc(dataoffset + datasize);
+ if (PyObject_Init((PyObject *)cdb, &CDataOwning_Type) == NULL)
+ return NULL;
+
+ Py_INCREF(ct);
+ cdb->head.c_type = ct;
+ cdb->head.c_data = ((char *)cdb) + dataoffset;
+ cdb->weakreflist = NULL;
+ return &cdb->head;
+}
+
static PyObject *b_newp(PyObject *self, PyObject *args)
{
CTypeDescrObject *ct, *ctitem;
- CDataObject_own_base *cdb;
+ CDataObject *cd;
PyObject *init = Py_None;
Py_ssize_t dataoffset, datasize, explicitlength;
if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init))
@@ -1809,26 +1825,21 @@
return NULL;
}
- cdb = (CDataObject_own_base *)PyObject_Malloc(dataoffset + datasize);
- if (PyObject_Init((PyObject *)cdb, &CDataOwning_Type) == NULL)
+ cd = allocate_owning_object(dataoffset, datasize, ct);
+ if (cd == NULL)
return NULL;
-
- Py_INCREF(ct);
- cdb->head.c_type = ct;
- cdb->head.c_data = ((char *)cdb) + dataoffset;
- cdb->weakreflist = NULL;
if (explicitlength >= 0)
- ((CDataObject_own_length*)cdb)->length = explicitlength;
-
- memset(cdb->head.c_data, 0, datasize);
+ ((CDataObject_own_length*)cd)->length = explicitlength;
+
+ memset(cd->c_data, 0, datasize);
if (init != Py_None) {
- if (convert_from_object(cdb->head.c_data,
+ if (convert_from_object(cd->c_data,
(ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) {
- Py_DECREF(cdb);
+ Py_DECREF(cd);
return NULL;
}
}
- return (PyObject *)cdb;
+ return (PyObject *)cd;
}
static CDataObject *_new_casted_primitive(CTypeDescrObject *ct)
@@ -3566,6 +3577,25 @@
return PyString_FromStringAndSize(&x, 1);
}
+static PyObject *_cffi_from_c_struct(char *data, CTypeDescrObject *ct)
+{
+ CDataObject *cd;
+ Py_ssize_t dataoffset = offsetof(CDataObject_own_nolength, alignment);
+ Py_ssize_t datasize = ct->ct_size;
+
+ if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) != CT_STRUCT) {
+ PyErr_SetString(PyExc_TypeError,
+ "return type is not a struct or is opaque");
+ return NULL;
+ }
+ cd = allocate_owning_object(dataoffset, datasize, ct);
+ if (cd == NULL)
+ return NULL;
+
+ memcpy(cd->c_data, data, datasize);
+ return (PyObject *)cd;
+}
+
static void *cffi_exports[] = {
_cffi_to_c_char_p,
_cffi_to_c_signed_char,
@@ -3590,6 +3620,7 @@
_cffi_from_c_char,
convert_to_object,
convert_from_object,
+ _cffi_from_c_struct,
};
/************************************************************/
diff --git a/cffi/verifier.py b/cffi/verifier.py
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -184,6 +184,9 @@
elif isinstance(tp, model.ArrayType):
return '_cffi_from_c_deref((char *)%s, _cffi_type(%d))' % (
var, self.gettypenum(tp))
+ elif isinstance(tp, model.StructType):
+ return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
+ var, self.gettypenum(tp))
else:
raise NotImplementedError(tp)
@@ -614,7 +617,9 @@
((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16])
#define _cffi_to_c \
((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17])
-#define _CFFI_NUM_EXPORTS 18
+#define _cffi_from_c_struct \
+ ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18])
+#define _CFFI_NUM_EXPORTS 19
#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
@@ -576,3 +576,27 @@
""")
msg = 'cannot pass as a argument a struct that was completed with verify()'
assert msg in str(e.value)
+
+def test_func_returns_struct():
+ # only supported via verify(), when GCC is the compiler; and only for
+ # regular functions.
+ ffi = FFI()
+ ffi.cdef("""
+ struct foo_s { int aa, bb; };
+ struct foo_s foo(int a, int b);
+ """)
+ lib = ffi.verify("""
+ struct foo_s { int aa, bb; };
+ struct foo_s foo(int a, int b) {
+ struct foo_s r;
+ r.aa = a*a;
+ r.bb = b*b;
+ return r;
+ }
+ """)
+ s = lib.foo(6, 7)
+ # It's the only way to have a 'struct foo_s' that owns its memory.
+ # With ffi.new() we always get a 'struct foo_s *' that owns the memory.
+ assert repr(s) == "<cdata 'struct foo_s' owning 8 bytes>"
+ assert s.aa == 36
+ assert s.bb == 49
More information about the pypy-commit
mailing list