Author: Armin Rigo <[email protected]>
Branch:
Changeset: r67889:73de8b43bff0
Date: 2013-11-09 10:33 +0100
http://bitbucket.org/pypy/pypy/changeset/73de8b43bff0/
Log: Port cffi's c99-array branch.
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
@@ -34,19 +34,8 @@
datasize = self.size
#
if datasize < 0:
- 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:
- length = space.getindex_w(w_init, space.w_OverflowError)
- if length < 0:
- raise OperationError(space.w_ValueError,
- space.wrap("negative array length"))
- w_init = space.w_None
- #
+ from pypy.module._cffi_backend import misc
+ w_init, length = misc.get_new_array_length(space, w_init)
try:
datasize = ovfcheck(length * self.ctitem.size)
except OverflowError:
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
@@ -15,15 +15,12 @@
class W_CTypePtrOrArray(W_CType):
- _attrs_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr',
- 'length']
- _immutable_fields_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr',
- 'length']
+ _attrs_ = ['ctitem', 'can_cast_anything', 'length']
+ _immutable_fields_ = ['ctitem', 'can_cast_anything', 'length']
length = -1
def __init__(self, space, size, extra, extra_position, ctitem,
could_cast_anything=True):
- from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
name, name_position = ctitem.insert_name(extra, extra_position)
W_CType.__init__(self, space, size, name, name_position)
# this is the "underlying type":
@@ -32,7 +29,6 @@
# - for functions, it is the return type
self.ctitem = ctitem
self.can_cast_anything = could_cast_anything and ctitem.cast_anything
- self.is_struct_ptr = isinstance(ctitem, W_CTypeStructOrUnion)
def is_char_ptr_or_array(self):
return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar)
@@ -195,6 +191,7 @@
W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem)
def newp(self, w_init):
+ from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
space = self.space
ctitem = self.ctitem
datasize = ctitem.size
@@ -202,10 +199,15 @@
raise operationerrfmt(space.w_TypeError,
"cannot instantiate ctype '%s' of unknown size",
self.name)
- if self.is_struct_ptr:
+ if isinstance(ctitem, W_CTypeStructOrUnion):
# 'newp' on a struct-or-union pointer: in this case, we return
# a W_CDataPtrToStruct object which has a strong reference
# to a W_CDataNewOwning that really contains the structure.
+ #
+ if ctitem.with_var_array and not space.is_w(w_init, space.w_None):
+ datasize = ctitem.convert_struct_from_object(
+ lltype.nullptr(rffi.CCHARP.TO), w_init, datasize)
+ #
cdatastruct = cdataobj.W_CDataNewOwning(space, datasize, ctitem)
cdata = cdataobj.W_CDataPtrToStructOrUnion(space,
cdatastruct._cdata,
@@ -321,7 +323,8 @@
space = self.space
ctype2 = cdata.ctype
if (isinstance(ctype2, W_CTypeStructOrUnion) or
- (isinstance(ctype2, W_CTypePtrOrArray) and ctype2.is_struct_ptr)):
+ (isinstance(ctype2, W_CTypePtrOrArray) and
+ isinstance(ctype2.ctitem, W_CTypeStructOrUnion))):
ptrdata = rffi.ptradd(cdata._cdata, offset)
return cdataobj.W_CData(space, ptrdata, self)
else:
diff --git a/pypy/module/_cffi_backend/ctypestruct.py
b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -9,7 +9,8 @@
from rpython.rlib import jit
from rpython.rlib.objectmodel import keepalive_until_here
from rpython.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, intmask
-from rpython.rtyper.lltypesystem import rffi
+from rpython.rlib.rarithmetic import ovfcheck
+from rpython.rtyper.lltypesystem import lltype, rffi
from pypy.module._cffi_backend import cdataobj, ctypeprim, misc
from pypy.module._cffi_backend.ctypeobj import W_CType
@@ -17,12 +18,13 @@
class W_CTypeStructOrUnion(W_CType):
_immutable_fields_ = ['alignment?', 'fields_list?', 'fields_dict?',
- 'custom_field_pos?']
+ 'custom_field_pos?', 'with_var_array?']
# fields added by complete_struct_or_union():
alignment = -1
fields_list = None
fields_dict = None
custom_field_pos = False
+ with_var_array = False
def __init__(self, space, name):
W_CType.__init__(self, space, -1, name, len(name))
@@ -90,12 +92,13 @@
pass
def convert_from_object(self, cdata, w_ob):
- space = self.space
- if self._copy_from_same(cdata, w_ob):
- return
+ if not self._copy_from_same(cdata, w_ob):
+ self.convert_struct_from_object(cdata, w_ob)
+ def convert_struct_from_object(self, cdata, w_ob, optvarsize=-1):
self._check_only_one_argument_for_union(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)
@@ -104,7 +107,9 @@
"too many initializers for '%s' (got %d)",
self.name, len(lst_w))
for i in range(len(lst_w)):
- self.fields_list[i].write(cdata, lst_w[i])
+ optvarsize = self.fields_list[i].write_v(cdata, lst_w[i],
+ optvarsize)
+ return optvarsize
elif space.isinstance_w(w_ob, space.w_dict):
lst_w = space.fixedview(w_ob)
@@ -116,11 +121,16 @@
except KeyError:
space.raise_key_error(w_key)
assert 0
- cf.write(cdata, space.getitem(w_ob, w_key))
+ optvarsize = cf.write_v(cdata, space.getitem(w_ob, w_key),
+ optvarsize)
+ return optvarsize
else:
- raise self._convert_error("list or tuple or dict or struct-cdata",
- w_ob)
+ if optvarsize == -1:
+ msg = "list or tuple or dict or struct-cdata"
+ else:
+ msg = "list or tuple or dict"
+ raise self._convert_error(msg, w_ob)
@jit.elidable
def _getcfield_const(self, attr):
@@ -192,6 +202,37 @@
else:
self.ctype.convert_from_object(cdata, w_ob)
+ def write_v(self, cdata, w_ob, optvarsize):
+ # a special case for var-sized C99 arrays
+ from pypy.module._cffi_backend import ctypearray
+ ct = self.ctype
+ if isinstance(ct, ctypearray.W_CTypeArray) and ct.length < 0:
+ space = ct.space
+ w_ob, varsizelength = misc.get_new_array_length(space, w_ob)
+ if optvarsize != -1:
+ # in this mode, the only purpose of this function is to compute
+ # the real size of the structure from a var-sized C99 array
+ assert cdata == lltype.nullptr(rffi.CCHARP.TO)
+ itemsize = ct.ctitem.size
+ try:
+ varsize = ovfcheck(itemsize * varsizelength)
+ size = ovfcheck(self.offset + varsize)
+ except OverflowError:
+ raise OperationError(space.w_OverflowError,
+ space.wrap("array size would overflow a ssize_t"))
+ assert size >= 0
+ return max(size, optvarsize)
+ # if 'value' was only an integer, get_new_array_length() returns
+ # w_ob = space.w_None. Detect if this was the case,
+ # and if so, stop here, leaving the content uninitialized
+ # (it should be zero-initialized from somewhere else).
+ if space.is_w(w_ob, space.w_None):
+ return optvarsize
+ #
+ if optvarsize == -1:
+ self.write(cdata, w_ob)
+ return optvarsize
+
def convert_bitfield_to_object(self, cdata):
ctype = self.ctype
space = ctype.space
diff --git a/pypy/module/_cffi_backend/misc.py
b/pypy/module/_cffi_backend/misc.py
--- a/pypy/module/_cffi_backend/misc.py
+++ b/pypy/module/_cffi_backend/misc.py
@@ -278,6 +278,22 @@
# ____________________________________________________________
+def get_new_array_length(space, w_value):
+ if (space.isinstance_w(w_value, space.w_list) or
+ space.isinstance_w(w_value, space.w_tuple)):
+ return (w_value, space.int_w(space.len(w_value)))
+ elif space.isinstance_w(w_value, space.w_basestring):
+ # from a string, we add the null terminator
+ return (w_value, space.int_w(space.len(w_value)) + 1)
+ else:
+ explicitlength = space.getindex_w(w_value, space.w_OverflowError)
+ if explicitlength < 0:
+ raise OperationError(space.w_ValueError,
+ space.wrap("negative array length"))
+ return (space.w_None, explicitlength)
+
+# ____________________________________________________________
+
@specialize.arg(0)
def _raw_memcopy_tp(TPP, source, dest):
# in its own function: LONGLONG may make the whole function jit-opaque
diff --git a/pypy/module/_cffi_backend/newtype.py
b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -158,8 +158,10 @@
fields_list = []
fields_dict = {}
custom_field_pos = False
+ with_var_array = False
- for w_field in fields_w:
+ for i in range(len(fields_w)):
+ w_field = fields_w[i]
field_w = space.fixedview(w_field)
if not (2 <= len(field_w) <= 4):
raise OperationError(space.w_TypeError,
@@ -176,7 +178,11 @@
"duplicate field name '%s'", fname)
#
if ftype.size < 0:
- raise operationerrfmt(space.w_TypeError,
+ if (isinstance(ftype, ctypearray.W_CTypeArray) and fbitsize < 0
+ and (i == len(fields_w) - 1 or foffset != -1)):
+ with_var_array = True
+ else:
+ raise operationerrfmt(space.w_TypeError,
"field '%s.%s' has ctype '%s' of unknown size",
w_ctype.name, fname, ftype.name)
#
@@ -235,7 +241,8 @@
fields_list.append(fld)
fields_dict[fname] = fld
- boffset += ftype.size * 8
+ if ftype.size >= 0:
+ boffset += ftype.size * 8
prev_bitfield_size = 0
else:
@@ -359,6 +366,7 @@
w_ctype.fields_list = fields_list
w_ctype.fields_dict = fields_dict
w_ctype.custom_field_pos = custom_field_pos
+ w_ctype.with_var_array = with_var_array
# ____________________________________________________________
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit