[pypy-commit] cffi cffi-1.0: Reasonably messy to implement: ffi.addressof(lib, "var")
arigo
noreply at buildbot.pypy.org
Mon May 11 15:36:57 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1971:758808b32477
Date: 2015-05-11 15:36 +0200
http://bitbucket.org/cffi/cffi/changeset/758808b32477/
Log: Reasonably messy to implement: ffi.addressof(lib, "var")
diff --git a/_cffi1/cglob.c b/_cffi1/cglob.c
--- a/_cffi1/cglob.c
+++ b/_cffi1/cglob.c
@@ -60,9 +60,13 @@
return convert_from_object(gs->gs_data, gs->gs_type, obj);
}
-#if 0
-static PyObject *addressof_global_var(GlobSupportObject *gs)
+static PyObject *cg_addressof_global_var(GlobSupportObject *gs)
{
- return new_simple_cdata(gs->gs_data, gs->gs_type);
+ PyObject *x, *ptrtype = new_pointer_type(gs->gs_type);
+ if (ptrtype == NULL)
+ return NULL;
+
+ x = new_simple_cdata(gs->gs_data, (CTypeDescrObject *)ptrtype);
+ Py_DECREF(ptrtype);
+ return x;
}
-#endif
diff --git a/_cffi1/ffi_obj.c b/_cffi1/ffi_obj.c
--- a/_cffi1/ffi_obj.c
+++ b/_cffi1/ffi_obj.c
@@ -19,6 +19,7 @@
#define FFI_COMPLEXITY_OUTPUT 1200 /* xxx should grow as needed */
#define FFIObject_Check(op) PyObject_TypeCheck(op, &FFI_Type)
+#define LibObject_Check(ob) ((Py_TYPE(ob) == &Lib_Type))
struct FFIObject_s {
PyObject_HEAD
@@ -368,10 +369,19 @@
}
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.");
+"Limited equivalent to the '&' operator in C:\n"
+"\n"
+"1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a\n"
+"pointer to this struct or union.\n"
+"\n"
+"2. ffi.addressof(<cdata>, field-or-index...) returns the address of a\n"
+"field or array item inside the given structure or array, recursively\n"
+"in case of nested structures or arrays.\n"
+"\n"
+"3. ffi.addressof(<library>, \"name\") returns the address of the named\n"
+"global variable.");
+
+static PyObject *address_of_global_var(PyObject *args); /* forward */
static PyObject *ffi_addressof(FFIObject *self, PyObject *args)
{
@@ -387,11 +397,17 @@
}
arg = PyTuple_GET_ITEM(args, 0);
+ if (LibObject_Check(arg)) {
+ /* case 3 in the docstring */
+ return address_of_global_var(args);
+ }
+
ct = _ffi_type(self, arg, ACCEPT_CDATA);
if (ct == NULL)
return NULL;
if (PyTuple_GET_SIZE(args) == 1) {
+ /* case 1 in the docstring */
accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY;
if ((ct->ct_flags & accepted_flags) == 0) {
PyErr_SetString(PyExc_TypeError,
@@ -400,6 +416,7 @@
}
}
else {
+ /* case 2 in the docstring */
accepted_flags = CT_STRUCT | CT_UNION | CT_ARRAY | CT_POINTER;
if ((ct->ct_flags & accepted_flags) == 0) {
PyErr_SetString(PyExc_TypeError,
diff --git a/_cffi1/lib_obj.c b/_cffi1/lib_obj.c
--- a/_cffi1/lib_obj.c
+++ b/_cffi1/lib_obj.c
@@ -27,15 +27,9 @@
FFIObject *l_ffi; /* reference back to the ffi object */
};
-#define LibObject_Check(ob) ((Py_TYPE(ob) == &Lib_Type))
-
-static PyObject *_cpyextfunc_type_index(PyObject *x)
+static struct CPyExtFunc_s *_cpyextfunc_get(PyObject *x)
{
struct CPyExtFunc_s *exf;
- LibObject *lib;
- PyObject *tuple, *result;
-
- assert(PyErr_Occurred());
if (!PyCFunction_Check(x))
return NULL;
@@ -46,6 +40,20 @@
if (exf->md.ml_doc != cpyextfunc_doc)
return NULL;
+ return exf;
+}
+
+static PyObject *_cpyextfunc_type_index(PyObject *x)
+{
+ struct CPyExtFunc_s *exf;
+ LibObject *lib;
+ PyObject *tuple, *result;
+
+ assert(PyErr_Occurred());
+ exf = _cpyextfunc_get(x);
+ if (exf == NULL)
+ return NULL; /* still the same exception is set */
+
PyErr_Clear();
lib = (LibObject *)PyCFunction_GET_SELF(x);
@@ -269,14 +277,21 @@
return x;
}
+#define LIB_GET_OR_CACHE_ADDR(x, lib, name, error) \
+ do { \
+ x = PyDict_GetItem(lib->l_dict, name); \
+ if (x == NULL) { \
+ x = lib_build_and_cache_attr(lib, name, 0); \
+ if (x == NULL) { \
+ error; \
+ } \
+ } \
+ } while (0)
+
static PyObject *lib_getattr(LibObject *lib, PyObject *name)
{
- PyObject *x = PyDict_GetItem(lib->l_dict, name);
- if (x == NULL) {
- x = lib_build_and_cache_attr(lib, name, 0);
- if (x == NULL)
- return NULL;
- }
+ PyObject *x;
+ LIB_GET_OR_CACHE_ADDR(x, lib, name, return NULL);
if (GlobSupport_Check(x)) {
return read_global_var((GlobSupportObject *)x);
@@ -287,12 +302,8 @@
static int lib_setattr(LibObject *lib, PyObject *name, PyObject *val)
{
- PyObject *x = PyDict_GetItem(lib->l_dict, name);
- if (x == NULL) {
- x = lib_build_and_cache_attr(lib, name, 0);
- if (x == NULL)
- return -1;
- }
+ PyObject *x;
+ LIB_GET_OR_CACHE_ADDR(x, lib, name, return -1);
if (val == NULL) {
PyErr_SetString(PyExc_AttributeError, "C attribute cannot be deleted");
@@ -396,3 +407,44 @@
lib->l_ffi = ffi;
return lib;
}
+
+static PyObject *address_of_global_var(PyObject *args)
+{
+ LibObject *lib;
+ PyObject *x, *o_varname;
+ char *varname;
+
+ if (!PyArg_ParseTuple(args, "O!s", &Lib_Type, &lib, &varname))
+ return NULL;
+
+ /* rebuild a string from 'varname', to do typechecks and to force
+ a unicode back to a plain string */
+ o_varname = PyString_FromString(varname);
+ if (o_varname == NULL)
+ return NULL;
+
+ LIB_GET_OR_CACHE_ADDR(x, lib, o_varname, goto error);
+ Py_DECREF(o_varname);
+ if (GlobSupport_Check(x)) {
+ return cg_addressof_global_var((GlobSupportObject *)x);
+ }
+ else {
+ struct CPyExtFunc_s *exf = _cpyextfunc_get(x);
+ if (exf != NULL || /* an OP_CPYTHON_BLTN: '&func' is 'func' in C */
+ ((CData_Check(x) && /* or, a constant functionptr cdata: same */
+ (((CDataObject *)x)->c_type->ct_flags & CT_FUNCTIONPTR) != 0))) {
+ Py_INCREF(x);
+ return x;
+ }
+ else {
+ PyErr_Format(PyExc_AttributeError,
+ "cannot take the address of the constant '%.200s'",
+ varname);
+ return NULL;
+ }
+ }
+
+ error:
+ Py_DECREF(o_varname);
+ return NULL;
+}
diff --git a/_cffi1/test_recompiler.py b/_cffi1/test_recompiler.py
--- a/_cffi1/test_recompiler.py
+++ b/_cffi1/test_recompiler.py
@@ -707,3 +707,39 @@
assert repr(ffi.typeof("foo_t")) == "<ctype 'foo_t'>"
assert repr(ffi.typeof("bar_p")) == "<ctype 'struct $1 *'>"
assert repr(ffi.typeof("baz_pp")) == "<ctype 'struct $2 * *'>"
+
+def test_address_of_global_var():
+ ffi = FFI()
+ ffi.cdef("""
+ long bottom, bottoms[2];
+ long FetchRectBottom(void);
+ long FetchRectBottoms1(void);
+ #define FOOBAR 42
+ """)
+ lib = verify(ffi, "test_address_of_global_var", """
+ long bottom, bottoms[2];
+ long FetchRectBottom(void) { return bottom; }
+ long FetchRectBottoms1(void) { return bottoms[1]; }
+ #define FOOBAR 42
+ """)
+ lib.bottom = 300
+ assert lib.FetchRectBottom() == 300
+ lib.bottom += 1
+ assert lib.FetchRectBottom() == 301
+ lib.bottoms[1] = 500
+ assert lib.FetchRectBottoms1() == 500
+ lib.bottoms[1] += 2
+ assert lib.FetchRectBottoms1() == 502
+ #
+ p = ffi.addressof(lib, 'bottom')
+ assert ffi.typeof(p) == ffi.typeof("long *")
+ assert p[0] == 301
+ p[0] += 1
+ assert lib.FetchRectBottom() == 302
+ p = ffi.addressof(lib, 'bottoms')
+ assert ffi.typeof(p) == ffi.typeof("long(*)[2]")
+ assert p[0] == lib.bottoms
+ #
+ py.test.raises(AttributeError, ffi.addressof, lib, 'unknown_var')
+ py.test.raises(AttributeError, ffi.addressof, lib, "FOOBAR")
+ assert ffi.addressof(lib, 'FetchRectBottom') == lib.FetchRectBottom
More information about the pypy-commit
mailing list