[pypy-commit] pypy cffi-1.0: ffi.addressof(lib, "var")
arigo
noreply at buildbot.pypy.org
Mon May 11 15:55:57 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r77293:abb305ea8684
Date: 2015-05-11 15:55 +0200
http://bitbucket.org/pypy/pypy/changeset/abb305ea8684/
Log: ffi.addressof(lib, "var")
diff --git a/pypy/module/_cffi_backend/cglob.py b/pypy/module/_cffi_backend/cglob.py
--- a/pypy/module/_cffi_backend/cglob.py
+++ b/pypy/module/_cffi_backend/cglob.py
@@ -1,6 +1,7 @@
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.typedef import TypeDef
from pypy.module._cffi_backend.cdataobj import W_CData
+from pypy.module._cffi_backend import newtype
class W_GlobSupport(W_Root):
@@ -15,5 +16,9 @@
def write_global_var(self, w_newvalue):
self.w_ctype.convert_from_object(self.ptr, w_newvalue)
+ def address(self):
+ w_ctypeptr = newtype.new_pointer_type(self.space, self.w_ctype)
+ return W_CData(self.space, self.ptr, w_ctypeptr)
+
W_GlobSupport.typedef = TypeDef("FFIGlobSupport")
W_GlobSupport.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -145,20 +145,34 @@
def descr_addressof(self, w_arg, args_w):
"""\
-With a single arg, return the address of a <cdata 'struct-or-union'>.
-If 'fields_or_indexes' are given, returns the address of that field or
-array item in the structure or array, recursively in case of nested
-structures."""
+Limited equivalent to the '&' operator in C:
+
+1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a
+pointer to this struct or union.
+
+2. ffi.addressof(<cdata>, field-or-index...) returns the address of a
+field or array item inside the given structure or array, recursively
+in case of nested structures or arrays.
+
+3. ffi.addressof(<library>, "name") returns the address of the named
+global variable."""
+ #
+ from pypy.module._cffi_backend.lib_obj import W_LibObject
+ space = self.space
+ if isinstance(w_arg, W_LibObject) and len(args_w) == 1:
+ # case 3 in the docstring
+ return w_arg.address_of_global_var(space.str_w(args_w[0]))
#
w_ctype = self.ffi_type(w_arg, ACCEPT_CDATA)
- space = self.space
if len(args_w) == 0:
+ # case 1 in the docstring
if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion) and
not isinstance(w_ctype, ctypearray.W_CTypeArray)):
raise oefmt(space.w_TypeError,
"expected a cdata struct/union/array object")
offset = 0
else:
+ # case 2 in the docstring
if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion) and
not isinstance(w_ctype, ctypearray.W_CTypeArray) and
not isinstance(w_ctype, ctypeptr.W_CTypePointer)):
diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py
--- a/pypy/module/_cffi_backend/lib_obj.py
+++ b/pypy/module/_cffi_backend/lib_obj.py
@@ -10,6 +10,7 @@
from pypy.module._cffi_backend import cffi_opcode, cglob
from pypy.module._cffi_backend.realize_c_type import getop, getarg
from pypy.module._cffi_backend.cdataobj import W_CData
+from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc
from pypy.module._cffi_backend.structwrapper import W_StructWrapper
@@ -173,6 +174,24 @@
for i in range(total)]
return space.newlist(names_w)
+ def address_of_global_var(self, varname):
+ # rebuild a string object from 'varname', to do typechecks and
+ # to force a unicode back to a plain string
+ space = self.space
+ w_value = self._get_attr(space.wrap(varname))
+ if isinstance(w_value, cglob.W_GlobSupport):
+ # regular case: a global variable
+ return w_value.address()
+ #
+ if ((isinstance(w_value, W_CData) and
+ isinstance(w_value.ctype, W_CTypeFunc))
+ or isinstance(w_value, W_StructWrapper)):
+ # '&func' is 'func' in C, for a constant function 'func'
+ return w_value
+ #
+ raise oefmt(space.w_AttributeError,
+ "cannot take the address of the constant '%s'", varname)
+
W_LibObject.typedef = TypeDef(
'CompiledLib',
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -695,3 +695,37 @@
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(self):
+ ffi, lib = self.prepare("""
+ long bottom, bottoms[2];
+ long FetchRectBottom(void);
+ long FetchRectBottoms1(void);
+ #define FOOBAR 42
+ """, "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
+ #
+ raises(AttributeError, ffi.addressof, lib, 'unknown_var')
+ raises(AttributeError, ffi.addressof, lib, "FOOBAR")
+ assert ffi.addressof(lib, 'FetchRectBottom') == lib.FetchRectBottom
More information about the pypy-commit
mailing list