Author: Armin Rigo <ar...@tunes.org> Branch: ffi-backend Changeset: r56508:04fd96420368 Date: 2012-07-30 16:30 +0200 http://bitbucket.org/pypy/pypy/changeset/04fd96420368/
Log: Fix the new test. diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py --- a/pypy/module/_cffi_backend/ctypearray.py +++ b/pypy/module/_cffi_backend/ctypearray.py @@ -10,7 +10,6 @@ from pypy.rlib.objectmodel import keepalive_until_here from pypy.rlib.rarithmetic import ovfcheck -from pypy.module._cffi_backend.ctypeobj import W_CType from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveChar from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUniChar from pypy.module._cffi_backend.ctypeptr import W_CTypePtrOrArray @@ -18,8 +17,8 @@ class W_CTypeArray(W_CTypePtrOrArray): - _attrs_ = ['length', 'ctptr'] - _immutable_fields_ = ['length', 'ctptr'] + _attrs_ = ['ctptr'] + _immutable_fields_ = ['ctptr'] def __init__(self, space, ctptr, length, arraysize, extra): W_CTypePtrOrArray.__init__(self, space, arraysize, extra, 0, @@ -92,55 +91,7 @@ return self def convert_from_object(self, cdata, w_ob): - space = self.space - if (space.isinstance_w(w_ob, space.w_list) or - space.isinstance_w(w_ob, space.w_tuple)): - lst_w = space.listview(w_ob) - if self.length >= 0 and len(lst_w) > self.length: - raise operationerrfmt(space.w_IndexError, - "too many initializers for '%s' (got %d)", - self.name, len(lst_w)) - ctitem = self.ctitem - for i in range(len(lst_w)): - ctitem.convert_from_object(cdata, lst_w[i]) - cdata = rffi.ptradd(cdata, ctitem.size) - elif isinstance(self.ctitem, W_CTypePrimitiveChar): - try: - s = space.str_w(w_ob) - except OperationError, e: - if not e.match(space, space.w_TypeError): - raise - raise self._convert_error("str or list or tuple", w_ob) - n = len(s) - if self.length >= 0 and n > self.length: - raise operationerrfmt(space.w_IndexError, - "initializer string is too long for '%s'" - " (got %d characters)", - self.name, n) - for i in range(n): - cdata[i] = s[i] - if n != self.length: - cdata[n] = '\x00' - elif isinstance(self.ctitem, W_CTypePrimitiveUniChar): - try: - s = space.unicode_w(w_ob) - except OperationError, e: - if not e.match(space, space.w_TypeError): - raise - raise self._convert_error("unicode or list or tuple", w_ob) - n = len(s) - if self.length >= 0 and n > self.length: - raise operationerrfmt(space.w_IndexError, - "initializer unicode string is too long for '%s'" - " (got %d characters)", - self.name, n) - unichardata = rffi.cast(rffi.CWCHARP, cdata) - for i in range(n): - unichardata[i] = s[i] - if n != self.length: - unichardata[n] = u'\x00' - else: - raise self._convert_error("list or tuple", w_ob) + self.convert_array_from_object(cdata, w_ob) def convert_to_object(self, cdata): return cdataobj.W_CData(self.space, cdata, self) diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py --- a/pypy/module/_cffi_backend/ctypefunc.py +++ b/pypy/module/_cffi_backend/ctypefunc.py @@ -10,7 +10,7 @@ from pypy.rlib.objectmodel import keepalive_until_here from pypy.module._cffi_backend.ctypeobj import W_CType -from pypy.module._cffi_backend.ctypeptr import W_CTypePtrBase +from pypy.module._cffi_backend.ctypeptr import W_CTypePtrBase, W_CTypePointer from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid from pypy.module._cffi_backend.ctypestruct import W_CTypeStruct from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion @@ -127,38 +127,9 @@ buffer_array[i] = data w_obj = args_w[i] argtype = self.fargs[i] - # - # special-case for strings. xxx should avoid copying - if argtype.is_char_ptr_or_array(): - try: - s = space.str_w(w_obj) - except OperationError, e: - if not e.match(space, space.w_TypeError): - raise - else: - raw_string = rffi.str2charp(s) - rffi.cast(rffi.CCHARPP, data)[0] = raw_string - # set the "must free" flag to 1 - set_mustfree_flag(data, 1) - mustfree_max_plus_1 = i + 1 - continue # skip the convert_from_object() - - # set the "must free" flag to 0 - set_mustfree_flag(data, 0) - # - if argtype.is_unichar_ptr_or_array(): - try: - space.unicode_w(w_obj) - except OperationError, e: - if not e.match(space, space.w_TypeError): - raise - else: - # passing a unicode raises NotImplementedError for now - raise OperationError(space.w_NotImplementedError, - space.wrap("automatic unicode-to-" - "'wchar_t *' conversion")) - # - argtype.convert_from_object(data, w_obj) + if argtype.convert_argument_from_object(data, w_obj): + # argtype is a pointer type, and w_obj a list/tuple/str + mustfree_max_plus_1 = i + 1 resultdata = rffi.ptradd(buffer, cif_descr.exchange_result) ec = cerrno.get_errno_container(space) @@ -189,7 +160,7 @@ finally: for i in range(mustfree_max_plus_1): argtype = self.fargs[i] - if argtype.is_char_ptr_or_array(): + if isinstance(argtype, W_CTypePointer): data = rffi.ptradd(buffer, cif_descr.exchange_args[i]) if get_mustfree_flag(data): raw_string = rffi.cast(rffi.CCHARPP, data)[0] @@ -413,7 +384,7 @@ # loop over args for i, farg in enumerate(self.fargs): - if farg.is_char_ptr_or_array(): + if isinstance(farg, W_CTypePointer): exchange_offset += 1 # for the "must free" flag exchange_offset = self.align_arg(exchange_offset) cif_descr.exchange_args[i] = exchange_offset diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py --- a/pypy/module/_cffi_backend/ctypeobj.py +++ b/pypy/module/_cffi_backend/ctypeobj.py @@ -73,6 +73,10 @@ raise operationerrfmt(space.w_TypeError, "cannot initialize cdata '%s'", self.name) + def convert_argument_from_object(self, cdata, w_ob): + self.convert_from_object(cdata, w_ob) + return False + def _convert_error(self, expected, w_got): space = self.space ob = space.interpclass_w(w_got) diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py --- a/pypy/module/_cffi_backend/ctypeptr.py +++ b/pypy/module/_cffi_backend/ctypeptr.py @@ -2,17 +2,21 @@ Pointers. """ -from pypy.interpreter.error import operationerrfmt -from pypy.rpython.lltypesystem import rffi +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.objectmodel import keepalive_until_here +from pypy.rlib.rarithmetic import ovfcheck from pypy.module._cffi_backend.ctypeobj import W_CType -from pypy.module._cffi_backend import cdataobj, misc +from pypy.module._cffi_backend import cdataobj, misc, ctypeprim class W_CTypePtrOrArray(W_CType): - _attrs_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr'] - _immutable_fields_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr'] + _attrs_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr', + 'length'] + _immutable_fields_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr', + 'length'] + length = -1 def __init__(self, space, size, extra, extra_position, ctitem, could_cast_anything=True): @@ -28,15 +32,12 @@ self.is_struct_ptr = isinstance(ctitem, W_CTypeStructOrUnion) def is_char_ptr_or_array(self): - from pypy.module._cffi_backend import ctypeprim return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar) def is_unichar_ptr_or_array(self): - from pypy.module._cffi_backend import ctypeprim return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar) def is_char_or_unichar_ptr_or_array(self): - from pypy.module._cffi_backend import ctypeprim return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveCharOrUniChar) def cast(self, w_ob): @@ -56,6 +57,57 @@ value = rffi.cast(rffi.CCHARP, value) return cdataobj.W_CData(space, value, self) + def convert_array_from_object(self, cdata, w_ob): + space = self.space + if (space.isinstance_w(w_ob, space.w_list) or + space.isinstance_w(w_ob, space.w_tuple)): + lst_w = space.listview(w_ob) + if self.length >= 0 and len(lst_w) > self.length: + raise operationerrfmt(space.w_IndexError, + "too many initializers for '%s' (got %d)", + self.name, len(lst_w)) + ctitem = self.ctitem + for i in range(len(lst_w)): + ctitem.convert_from_object(cdata, lst_w[i]) + cdata = rffi.ptradd(cdata, ctitem.size) + elif isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar): + try: + s = space.str_w(w_ob) + except OperationError, e: + if not e.match(space, space.w_TypeError): + raise + raise self._convert_error("str or list or tuple", w_ob) + n = len(s) + if self.length >= 0 and n > self.length: + raise operationerrfmt(space.w_IndexError, + "initializer string is too long for '%s'" + " (got %d characters)", + self.name, n) + for i in range(n): + cdata[i] = s[i] + if n != self.length: + cdata[n] = '\x00' + elif isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar): + try: + s = space.unicode_w(w_ob) + except OperationError, e: + if not e.match(space, space.w_TypeError): + raise + raise self._convert_error("unicode or list or tuple", w_ob) + n = len(s) + if self.length >= 0 and n > self.length: + raise operationerrfmt(space.w_IndexError, + "initializer unicode string is too long for '%s'" + " (got %d characters)", + self.name, n) + unichardata = rffi.cast(rffi.CWCHARP, cdata) + for i in range(n): + unichardata[i] = s[i] + if n != self.length: + unichardata[n] = u'\x00' + else: + raise self._convert_error("list or tuple", w_ob) + class W_CTypePtrBase(W_CTypePtrOrArray): # base class for both pointers and pointers-to-functions @@ -125,7 +177,6 @@ return W_CTypePtrOrArray.unicode(self, cdataobj) def newp(self, w_init): - from pypy.module._cffi_backend import ctypeprim space = self.space ctitem = self.ctitem datasize = ctitem.size @@ -168,3 +219,47 @@ self.name) p = rffi.ptradd(cdata, i * self.ctitem.size) return cdataobj.W_CData(space, p, self) + + def _prepare_pointer_call_argument(self, w_init): + space = self.space + if (space.isinstance_w(w_init, space.w_list) or + space.isinstance_w(w_init, space.w_tuple)): + length = space.int_w(space.len(w_init)) + elif space.isinstance_w(w_init, space.w_basestring): + # from a string, we add the null terminator + length = space.int_w(space.len(w_init)) + 1 + else: + return lltype.nullptr(rffi.CCHARP.TO) + if self.ctitem.size <= 0: + return lltype.nullptr(rffi.CCHARP.TO) + try: + datasize = ovfcheck(length * self.ctitem.size) + except OverflowError: + raise OperationError(space.w_OverflowError, + space.wrap("array size would overflow a ssize_t")) + result = lltype.malloc(rffi.CCHARP.TO, datasize, + flavor='raw', zero=True) + try: + self.convert_array_from_object(result, w_init) + except Exception: + lltype.free(result, flavor='raw') + raise + return result + + def convert_argument_from_object(self, cdata, w_ob): + from pypy.module._cffi_backend.ctypefunc import set_mustfree_flag + space = self.space + ob = space.interpclass_w(w_ob) + if isinstance(ob, cdataobj.W_CData): + buffer = lltype.nullptr(rffi.CCHARP.TO) + else: + buffer = self._prepare_pointer_call_argument(w_ob) + # + if buffer: + rffi.cast(rffi.CCHARPP, cdata)[0] = buffer + set_mustfree_flag(cdata, True) + return True + else: + set_mustfree_flag(cdata, False) + self.convert_from_object(cdata, w_ob) + return False _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit