[pypy-commit] cffi cffi-1.0: ffi.addressof()

arigo noreply at buildbot.pypy.org
Sat Apr 25 14:42:54 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1825:d073836b9835
Date: 2015-04-25 14:43 +0200
http://bitbucket.org/cffi/cffi/changeset/d073836b9835/

Log:	ffi.addressof()

diff --git a/_cffi1/ffi_obj.c b/_cffi1/ffi_obj.c
--- a/_cffi1/ffi_obj.c
+++ b/_cffi1/ffi_obj.c
@@ -336,85 +336,65 @@
     return PyInt_FromSsize_t(offset);
 }
 
-#if 0
-static PyObject *ffi_addressof(ZefFFIObject *self, PyObject *args)
+PyDoc_STRVAR(ffi_addressof_doc,
+"With a single arg, return the address of a <cdata 'struct-or-union'>.\n"
+"If 'fields_or_indexes' are given, returns the address of that field or\n"
+"array item in the structure or array, recursively in case of nested\n"
+"structures.");
+
+static PyObject *ffi_addressof(FFIObject *self, PyObject *args)
 {
-    PyObject *obj;
-    char *fieldname = NULL;
+    PyObject *arg, *z, *result;
+    CTypeDescrObject *ct;
+    Py_ssize_t i, offset = 0;
+    int accepted_flags;
 
-    if (!PyArg_ParseTuple(args, "O|z:addressof", &obj, &fieldname))
+    if (PyTuple_Size(args) < 1) {
+        PyErr_SetString(PyExc_TypeError,
+                        "addressof() expects at least 1 argument");
+        return NULL;
+    }
+
+    arg = PyTuple_GET_ITEM(args, 0);
+    ct = _ffi_type(self, arg, ACCEPT_CDATA);
+    if (ct == NULL)
         return NULL;
 
-    if (CData_Check(obj)) {
-        CDataObject *cd = (CDataObject *)obj;
-        CTypeDescrObject *ct;
-        Py_ssize_t offset;
-
-        ct = cd->c_type;
-        if (fieldname != NULL && ct->ct_flags & CT_POINTER)
-            ct = ct->ct_itemdescr;
-
-        if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) {
-            PyErr_Format(PyExc_TypeError,
-                         "expected a struct or union cdata, got '%s'",
-                         ct->ct_name);
+    if (PyTuple_GET_SIZE(args) == 1) {
+        accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY;
+        if ((ct->ct_flags & accepted_flags) == 0) {
+            PyErr_SetString(PyExc_TypeError,
+                            "expected a cdata struct/union/array object");
             return NULL;
         }
-
-        if (fieldname == NULL) {
-            offset = 0;
-        }
-        else {
-            CFieldObject *cf = _ffi_field(ct, fieldname);
-            if (cf == NULL)
-                return NULL;
-            offset = cf->cf_offset;
-            ct = cf->cf_type;
-        }
-        ct = fetch_pointer_type(self->types_dict, ct);
-        if (ct == NULL)
-            return NULL;
-        return new_simple_cdata(cd->c_data + offset, ct);
     }
-    else if (ZefLib_Check(obj)) {
-        PyObject *attr, *name;
-        char *reason;
-
-        if (fieldname == NULL) {
-            PyErr_SetString(PyExc_TypeError, "addressof(Lib, fieldname) "
-                            "cannot be used with only one argument");
+    else {
+        accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY | CT_POINTER;
+        if ((ct->ct_flags & accepted_flags) == 0) {
+            PyErr_SetString(PyExc_TypeError,
+                        "expected a cdata struct/union/array/pointer object");
             return NULL;
         }
-        name = PyString_FromString(fieldname);
-        if (name == NULL)
-            return NULL;
-        attr = lib_findattr((ZefLibObject *)obj, name, ZefError);
-        Py_DECREF(name);
-        if (attr == NULL)
-            return NULL;
+        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;
+        }
+    }
 
-        if (ZefGlobSupport_Check(attr)) {
-            return addressof_global_var((ZefGlobSupportObject *)attr);
-        }
+    z = new_pointer_type(ct);
+    z = get_unique_type(self->types_builder, z);
+    if (z == NULL)
+        return NULL;
 
-        if (PyCFunction_Check(attr))
-            reason = "declare that function as a function pointer instead";
-        else
-            reason = "numeric constants don't have addresses";
-
-        PyErr_Format(PyExc_TypeError,
-                     "cannot take the address of '%s' (%s)",
-                     fieldname, reason);
-        return NULL;
-    }
-    else {
-        PyErr_SetString(PyExc_TypeError, "addressof() first argument must be "
-                        "a cdata struct or union, a pointer to one, or a Lib "
-                        "object");
-        return NULL;
-    }
+    result = new_simple_cdata(((CDataObject *)arg)->c_data + offset,
+                              (CTypeDescrObject *)z);
+    Py_DECREF(z);
+    return result;
 }
-#endif
 
 static PyObject *_combine_type_name_l(CTypeDescrObject *ct,
                                       size_t extra_text_len)
@@ -695,28 +675,26 @@
 }
 
 static PyMethodDef ffi_methods[] = {
-    {"__set_types",(PyCFunction)ffi__set_types, METH_VARARGS},
+ {"__set_types",(PyCFunction)ffi__set_types, METH_VARARGS},
+ {"addressof",  (PyCFunction)ffi_addressof,  METH_VARARGS, ffi_addressof_doc},
+ {"alignof",    (PyCFunction)ffi_alignof,    METH_O,       ffi_alignof_doc},
+ {"callback",   (PyCFunction)ffi_callback,   METH_VARARGS |
+                                             METH_KEYWORDS,ffi_callback_doc},
+ {"cast",       (PyCFunction)ffi_cast,       METH_VARARGS, ffi_cast_doc},
 #if 0
-    {"addressof",  (PyCFunction)ffi_addressof,  METH_VARARGS},
+ {"from_handle",(PyCFunction)ffi_from_handle,METH_O},
+ {"gc",         (PyCFunction)ffi_gc,         METH_VARARGS},
 #endif
-    {"alignof",    (PyCFunction)ffi_alignof,    METH_O,       ffi_alignof_doc},
-    {"callback",   (PyCFunction)ffi_callback,   METH_VARARGS |
-                                                METH_KEYWORDS,ffi_callback_doc},
-    {"cast",       (PyCFunction)ffi_cast,       METH_VARARGS, ffi_cast_doc},
+ {"getctype",   (PyCFunction)ffi_getctype,   METH_VARARGS, ffi_getctype_doc},
+ {"offsetof",   (PyCFunction)ffi_offsetof,   METH_VARARGS, ffi_offsetof_doc},
+ {"new",        (PyCFunction)ffi_new,        METH_VARARGS, ffi_new_doc},
 #if 0
-    {"from_handle",(PyCFunction)ffi_from_handle,METH_O},
-    {"gc",         (PyCFunction)ffi_gc,         METH_VARARGS},
+ {"new_handle", (PyCFunction)ffi_new_handle, METH_O},
 #endif
-    {"getctype",   (PyCFunction)ffi_getctype,   METH_VARARGS, ffi_getctype_doc},
-    {"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},
-#endif
-    {"sizeof",     (PyCFunction)ffi_sizeof,     METH_O,       ffi_sizeof_doc},
-    {"string",     (PyCFunction)ffi_string,     METH_VARARGS, ffi_string_doc},
-    {"typeof",     (PyCFunction)ffi_typeof,     METH_O,       ffi_typeof_doc},
-    {NULL}
+ {"sizeof",     (PyCFunction)ffi_sizeof,     METH_O,       ffi_sizeof_doc},
+ {"string",     (PyCFunction)ffi_string,     METH_VARARGS, ffi_string_doc},
+ {"typeof",     (PyCFunction)ffi_typeof,     METH_O,       ffi_typeof_doc},
+ {NULL}
 };
 
 static PyGetSetDef ffi_getsets[] = {
diff --git a/_cffi1/test_ffi_obj.py b/_cffi1/test_ffi_obj.py
--- a/_cffi1/test_ffi_obj.py
+++ b/_cffi1/test_ffi_obj.py
@@ -114,3 +114,10 @@
     assert ffi.getctype("int[5]", '*') == "int(*)[5]"
     assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]"
     assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]"
+
+def test_addressof():
+    ffi = _cffi1_backend.FFI()
+    a = ffi.new("int[10]")
+    b = ffi.addressof(a, 5)
+    b[2] = -123
+    assert a[7] == -123
diff --git a/_cffi1/test_recompiler.py b/_cffi1/test_recompiler.py
--- a/_cffi1/test_recompiler.py
+++ b/_cffi1/test_recompiler.py
@@ -235,6 +235,12 @@
     #
     assert ffi.offsetof("struct foo_s", "a") == 0
     assert ffi.offsetof("struct foo_s", "b") == 4
+    #
+    py.test.raises(TypeError, ffi.addressof, p)
+    assert ffi.addressof(p[0]) == p
+    assert ffi.typeof(ffi.addressof(p[0])) is ffi.typeof("struct foo_s *")
+    assert ffi.typeof(ffi.addressof(p, "b")) is ffi.typeof("int *")
+    assert ffi.addressof(p, "b")[0] == p.b
 
 def test_verify_exact_field_offset():
     ffi = FFI()


More information about the pypy-commit mailing list