[pypy-commit] pypy default: special case the type "pointer to char", and allow automatic conversion of strings to it
antocuni
noreply at buildbot.pypy.org
Wed Jul 27 18:42:58 CEST 2011
Author: Antonio Cuni <anto.cuni at gmail.com>
Branch:
Changeset: r46021:d342648fe99a
Date: 2011-07-27 18:33 +0200
http://bitbucket.org/pypy/pypy/changeset/d342648fe99a/
Log: special case the type "pointer to char", and allow automatic
conversion of strings to it
diff --git a/pypy/module/_ffi/interp_ffi.py b/pypy/module/_ffi/interp_ffi.py
--- a/pypy/module/_ffi/interp_ffi.py
+++ b/pypy/module/_ffi/interp_ffi.py
@@ -74,6 +74,9 @@
def is_struct(self):
return libffi.types.is_struct(self.ffitype)
+ def is_char_p(self):
+ return self is app_types.char_p
+
W_FFIType.typedef = TypeDef(
'FFIType',
__repr__ = interp2app(W_FFIType.repr),
@@ -115,7 +118,10 @@
## 'Z' : ffi_type_pointer,
]
- return dict([(t.name, t) for t in types])
+ d = dict([(t.name, t) for t in types])
+ w_char = d['char']
+ d['char_p'] = W_FFIType('char_p', libffi.types.pointer, w_pointer_to = w_char)
+ return d
class app_types:
pass
@@ -125,9 +131,12 @@
try:
return descr_new_pointer.cache[w_pointer_to]
except KeyError:
- w_pointer_to = space.interp_w(W_FFIType, w_pointer_to)
- name = '(pointer to %s)' % w_pointer_to.name
- w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to)
+ if w_pointer_to is app_types.char:
+ w_result = app_types.char_p
+ else:
+ w_pointer_to = space.interp_w(W_FFIType, w_pointer_to)
+ name = '(pointer to %s)' % w_pointer_to.name
+ w_result = W_FFIType(name, libffi.types.pointer, w_pointer_to = w_pointer_to)
descr_new_pointer.cache[w_pointer_to] = w_result
return w_result
descr_new_pointer.cache = {}
@@ -178,6 +187,8 @@
self.func.name, expected, arg, given)
#
argchain = libffi.ArgChain()
+ to_free = [] # list of automatically malloc()ed buffers that needs to
+ # be freed after the call
for i in range(expected):
w_argtype = self.argtypes_w[i]
w_arg = args_w[i]
@@ -188,6 +199,9 @@
self.arg_longlong(space, argchain, w_arg)
elif w_argtype.is_signed():
argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg))
+ elif self.add_char_p_maybe(space, argchain, to_free, w_arg, w_argtype):
+ # the argument is added to the argchain direcly by the method above
+ pass
elif w_argtype.is_pointer():
w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype)
argchain.arg(intmask(space.uint_w(w_arg)))
@@ -210,7 +224,22 @@
argchain.arg_raw(ptrval)
else:
assert False, "Argument shape '%s' not supported" % w_argtype
- return argchain
+ return argchain, to_free
+
+ def add_char_p_maybe(self, space, argchain, to_free, w_arg, w_argtype):
+ """
+ Automatic conversion from string to char_p. The allocated buffer will
+ be automatically freed after the call.
+ """
+ w_type = jit.promote(space.type(w_arg))
+ if w_argtype.is_char_p() and w_type is space.w_str:
+ strval = space.str_w(w_arg)
+ buf = rffi.str2charp(strval)
+ to_free.append(buf)
+ addr = rffi.cast(rffi.ULONG, buf)
+ argchain.arg(addr)
+ return True
+ return False
def convert_pointer_arg_maybe(self, space, w_arg, w_argtype):
"""
@@ -234,7 +263,14 @@
def call(self, space, args_w):
self = jit.promote(self)
- argchain = self.build_argchain(space, args_w)
+ argchain, to_free = self.build_argchain(space, args_w)
+ try:
+ return self._do_call(space, argchain)
+ finally:
+ for buf in to_free:
+ lltype.free(buf, flavor='raw')
+
+ def _do_call(self, space, argchain):
w_restype = self.w_restype
if w_restype.is_longlong():
# note that we must check for longlong first, because either
diff --git a/pypy/module/_ffi/test/test__ffi.py b/pypy/module/_ffi/test/test__ffi.py
--- a/pypy/module/_ffi/test/test__ffi.py
+++ b/pypy/module/_ffi/test/test__ffi.py
@@ -188,6 +188,29 @@
assert get_dummy() == 123
set_val_to_ptr(ptr2, 0)
+ def test_convert_strings_to_char_str_p(self):
+ """
+ long mystrlen(char* s)
+ {
+ long len = 0;
+ while(*s++)
+ len++;
+ return len;
+ }
+ """
+ from _ffi import CDLL, types
+ import _rawffi
+ libfoo = CDLL(self.libfoo_name)
+ mystrlen = libfoo.getfunc('mystrlen', [types.char_p], types.slong)
+ #
+ # first, try automatic conversion from a string
+ assert mystrlen('foobar') == 6
+ # then, try to pass an explicit pointer
+ CharArray = _rawffi.Array('c')
+ mystr = CharArray(7, 'foobar')
+ assert mystrlen(mystr.buffer) == 6
+ mystr.free()
+
def test_typed_pointer(self):
from _ffi import types
intptr = types.Pointer(types.sint) # create a typed pointer to sint
@@ -204,6 +227,11 @@
assert x is y
assert x is not z
+ def test_char_p_cached(self):
+ from _ffi import types
+ x = types.Pointer(types.char)
+ assert x is types.char_p
+
def test_typed_pointer_args(self):
"""
extern int dummy; // defined in test_void_result
More information about the pypy-commit
mailing list