Author: Armin Rigo <[email protected]>
Branch: cffi-1.0
Changeset: r1779:3f61ed84336c
Date: 2015-04-22 16:40 +0200
http://bitbucket.org/cffi/cffi/changeset/3f61ed84336c/
Log: ffi.offsetof()
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -4952,27 +4952,26 @@
return res;
}
-static PyObject *b_typeoffsetof(PyObject *self, PyObject *args)
-{
- PyObject *res, *fieldname;
- CTypeDescrObject *ct;
+static CTypeDescrObject *direct_typeoffsetof(CTypeDescrObject *ct,
+ PyObject *fieldname,
+ int following, Py_ssize_t *offset)
+{
+ /* Does not return a new reference! */
+ CTypeDescrObject *res;
CFieldObject *cf;
- Py_ssize_t offset;
- int following = 0;
-
- if (!PyArg_ParseTuple(args, "O!O|i:typeoffsetof",
- &CTypeDescr_Type, &ct, &fieldname, &following))
- return NULL;
if (PyTextAny_Check(fieldname)) {
if (!following && (ct->ct_flags & CT_POINTER))
ct = ct->ct_itemdescr;
- if (!(ct->ct_flags & (CT_STRUCT|CT_UNION)) ||
- force_lazy_struct(ct) <= 0) {
+ if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) {
+ PyErr_SetString(PyExc_TypeError,
+ "with a field name argument, expected a "
+ "struct or union ctype");
+ return NULL;
+ }
+ if (force_lazy_struct(ct) <= 0) {
if (!PyErr_Occurred())
- PyErr_SetString(PyExc_TypeError,
- "with a field name argument, expected an "
- "initialized struct or union ctype");
+ PyErr_SetString(PyExc_TypeError, "struct/union is opaque");
return NULL;
}
cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, fieldname);
@@ -4984,8 +4983,8 @@
PyErr_SetString(PyExc_TypeError, "not supported for bitfields");
return NULL;
}
- res = (PyObject *)cf->cf_type;
- offset = cf->cf_offset;
+ res = cf->cf_type;
+ *offset = cf->cf_offset;
}
else {
ssize_t index = PyInt_AsSsize_t(fieldname);
@@ -5002,14 +5001,32 @@
"pointer to non-opaque");
return NULL;
}
- res = (PyObject *)ct->ct_itemdescr;
- offset = index * ct->ct_itemdescr->ct_size;
- if ((offset / ct->ct_itemdescr->ct_size) != index) {
+ res = ct->ct_itemdescr;
+ *offset = index * ct->ct_itemdescr->ct_size;
+ if ((*offset / ct->ct_itemdescr->ct_size) != index) {
PyErr_SetString(PyExc_OverflowError,
"array offset would overflow a Py_ssize_t");
return NULL;
}
}
+ return res;
+}
+
+static PyObject *b_typeoffsetof(PyObject *self, PyObject *args)
+{
+ PyObject *res, *fieldname;
+ CTypeDescrObject *ct;
+ Py_ssize_t offset;
+ int following = 0;
+
+ if (!PyArg_ParseTuple(args, "O!O|i:typeoffsetof",
+ &CTypeDescr_Type, &ct, &fieldname, &following))
+ return NULL;
+
+ res = (PyObject *)direct_typeoffsetof(ct, fieldname, following, &offset);
+ if (res == NULL)
+ return NULL;
+
return Py_BuildValue("(On)", res, offset);
}
diff --git a/new/ffi_obj.c b/new/ffi_obj.c
--- a/new/ffi_obj.c
+++ b/new/ffi_obj.c
@@ -290,58 +290,46 @@
"string or unicode string.\n"
"\n"
"If 'cdata' is an enum, returns the value of the enumerator as a\n"
-"string, or 'NUMBER' if the value is out of range.\n");
+"string, or 'NUMBER' if the value is out of range.");
#define ffi_string b_string /* ffi_string() => b_string()
from _cffi_backend.c */
-#if 0
-static CFieldObject *_ffi_field(CTypeDescrObject *ct, const char *fieldname)
+PyDoc_STRVAR(ffi_offsetof_doc,
+"Return the offset of the named field inside the given structure or\n"
+"array, which must be given as a C type name. You can give several\n"
+"field names in case of nested structures. You can also give numeric\n"
+"values which correspond to array items, in case of an array type.");
+
+static PyObject *ffi_offsetof(FFIObject *self, PyObject *args)
{
- CFieldObject *cf;
- if (force_lazy_struct(ct) == NULL) {
- PyErr_Format(PyExc_TypeError, "'%s' is incomplete", ct->ct_name);
+ PyObject *arg;
+ CTypeDescrObject *ct;
+ Py_ssize_t i, offset;
+
+ if (PyTuple_Size(args) < 2) {
+ PyErr_SetString(PyExc_TypeError,
+ "offsetof() expects at least 2 arguments");
return NULL;
}
- cf = (CFieldObject *)PyDict_GetItemString(ct->ct_stuff, fieldname);
- if (cf == NULL) {
- PyErr_Format(PyExc_KeyError, "'%s' has got no field '%s'",
- ct->ct_name, fieldname);
- return NULL;
- }
- if (cf->cf_bitshift >= 0) {
- PyErr_SetString(PyExc_TypeError, "not supported for bitfields");
- return NULL;
- }
- return cf;
-}
-static PyObject *ffi_offsetof(ZefFFIObject *self, PyObject *args)
-{
- PyObject *arg;
- char *fieldname;
- CTypeDescrObject *ct;
- CFieldObject *cf;
-
- if (!PyArg_ParseTuple(args, "Os:offsetof", &arg, &fieldname))
- return NULL;
-
+ arg = PyTuple_GET_ITEM(args, 0);
ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE);
if (ct == NULL)
return NULL;
- if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) {
- PyErr_Format(PyExc_TypeError,
- "expected a struct or union ctype, got '%s'",
- ct->ct_name);
- return NULL;
+ offset = 0;
+ for (i = 1; i < PyTuple_GET_SIZE(args); i++) {
+ Py_ssize_t ofs1;
+ ct = direct_typeoffsetof(ct, PyTuple_GET_ITEM(args, i), i > 1, &ofs1);
+ if (ct == NULL)
+ return NULL;
+ offset += ofs1;
}
- cf = _ffi_field(ct, fieldname);
- if (cf == NULL)
- return NULL;
- return PyInt_FromSsize_t(cf->cf_offset);
+ return PyInt_FromSsize_t(offset);
}
+#if 0
static PyObject *ffi_addressof(ZefFFIObject *self, PyObject *args)
{
PyObject *obj;
@@ -612,8 +600,8 @@
{"gc", (PyCFunction)ffi_gc, METH_VARARGS},
{"getctype", (PyCFunction)ffi_getctype, METH_VARARGS},
{"load_library",
(PyCFunction)ffi_load_library,METH_VARARGS|METH_KEYWORDS},
- {"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS},
#endif
+ {"offsetof", (PyCFunction)ffi_offsetof,
METH_VARARGS,ffi_offsetof_doc},
{"new", (PyCFunction)ffi_new, METH_VARARGS, ffi_new_doc},
#if 0
{"new_handle", (PyCFunction)ffi_new_handle,METH_O},
diff --git a/new/test_recompiler.py b/new/test_recompiler.py
--- a/new/test_recompiler.py
+++ b/new/test_recompiler.py
@@ -216,6 +216,9 @@
py.test.raises(OverflowError, "p.b -= 1")
q = ffi.new("struct bar_s *", {'f': p})
assert q.f == p
+ #
+ assert ffi.offsetof("struct foo_s", "a") == 0
+ assert ffi.offsetof("struct foo_s", "b") == 4
def test_verify_exact_field_offset():
ffi = FFI()
diff --git a/new/test_verify1.py b/new/test_verify1.py
--- a/new/test_verify1.py
+++ b/new/test_verify1.py
@@ -451,8 +451,8 @@
};
""")
py.test.raises(ffi.error, ffi.sizeof, 'struct foo_s')
- py.test.raises(ffi.error, ffi.offsetof, 'struct foo_s', 'x')
- py.test.raises(ffi.error, ffi.new, 'struct foo_s *')
+ py.test.raises(TypeError, ffi.offsetof, 'struct foo_s', 'x')
+ py.test.raises(TypeError, ffi.new, 'struct foo_s *')
ffi.verify("""
struct foo_s {
int a, b, x, c, d, e;
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit