[pypy-commit] pypy ffi-backend: Bitfields.
arigo
noreply at buildbot.pypy.org
Fri Jul 6 15:25:44 CEST 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r55936:a1c66a24e626
Date: 2012-07-06 15:25 +0200
http://bitbucket.org/pypy/pypy/changeset/a1c66a24e626/
Log: Bitfields.
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
@@ -7,9 +7,10 @@
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.typedef import TypeDef, interp_attrproperty
from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.rarithmetic import r_ulonglong, r_longlong, intmask
from pypy.module._cffi_backend.ctypeobj import W_CType
-from pypy.module._cffi_backend import cdataobj
+from pypy.module._cffi_backend import cdataobj, ctypeprim, misc
class W_CTypeStructOrUnion(W_CType):
@@ -153,17 +154,70 @@
def read(self, cdata):
cdata = rffi.ptradd(cdata, self.offset)
if self.is_bitfield():
- xxx
+ return self.convert_bitfield_to_object(cdata)
else:
return self.ctype.convert_to_object(cdata)
def write(self, cdata, w_ob):
cdata = rffi.ptradd(cdata, self.offset)
if self.is_bitfield():
- xxx
+ self.convert_bitfield_from_object(cdata, w_ob)
else:
self.ctype.convert_from_object(cdata, w_ob)
+ def convert_bitfield_to_object(self, cdata):
+ ctype = self.ctype
+ space = ctype.space
+ #
+ if isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned):
+ value = r_ulonglong(misc.read_raw_signed_data(cdata, ctype.size))
+ valuemask = (r_ulonglong(1) << self.bitsize) - 1
+ shiftforsign = r_ulonglong(1) << (self.bitsize - 1)
+ value = ((value >> self.bitshift) + shiftforsign) & valuemask
+ result = r_longlong(value) - r_longlong(shiftforsign)
+ if ctype.value_fits_long:
+ return space.wrap(intmask(result))
+ else:
+ return space.wrap(result)
+ #
+ if isinstance(ctype, ctypeprim.W_CTypePrimitiveUnsigned):
+ value_fits_long = ctype.value_fits_long
+ elif isinstance(ctype, ctypeprim.W_CTypePrimitiveChar):
+ value_fits_long = True
+ else:
+ raise NotImplementedError
+ #
+ value = misc.read_raw_unsigned_data(cdata, ctype.size)
+ valuemask = (r_ulonglong(1) << self.bitsize) - 1
+ value = (value >> self.bitshift) & valuemask
+ if value_fits_long:
+ return space.wrap(intmask(value))
+ else:
+ return space.wrap(value)
+
+ def convert_bitfield_from_object(self, cdata, w_ob):
+ ctype = self.ctype
+ space = ctype.space
+ #
+ value = misc.as_long_long(space, w_ob)
+ if isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned):
+ fmin = -(r_longlong(1) << (self.bitsize-1))
+ fmax = (r_longlong(1) << (self.bitsize-1)) - 1
+ if fmax == 0:
+ fmax = 1 # special case to let "int x:1" receive "1"
+ else:
+ fmin = r_longlong(0)
+ fmax = r_longlong((r_ulonglong(1) << self.bitsize) - 1)
+ if value < fmin or value > fmax:
+ raise operationerrfmt(space.w_OverflowError,
+ "value %d outside the range allowed by the "
+ "bit field width: %d <= x <= %d",
+ value, fmin, fmax)
+ rawmask = ((r_ulonglong(1) << self.bitsize) - 1) << self.bitshift
+ rawvalue = r_ulonglong(value) << self.bitshift
+ rawfielddata = misc.read_raw_unsigned_data(cdata, ctype.size)
+ rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask)
+ misc.write_raw_integer_data(cdata, rawfielddata, ctype.size)
W_CField.typedef = TypeDef(
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
@@ -109,7 +109,6 @@
fields_list = []
fields_dict = {}
prev_bit_position = 0
- prev_field = None
custom_field_pos = False
for w_field in fields_w:
@@ -146,13 +145,34 @@
custom_field_pos |= (offset != foffset)
offset = foffset
#
- if fbitsize < 0 or (fbitsize == 8 * ftype.size and
- not isinstance(ftype, W_CTypePrimitiveChar)):
+ if fbitsize < 0 or (fbitsize == 8 * ftype.size and not
+ isinstance(ftype, ctypeprim.W_CTypePrimitiveChar)):
fbitsize = -1
bitshift = -1
prev_bit_position = 0
else:
- xxx
+ if (not (isinstance(ftype, ctypeprim.W_CTypePrimitiveSigned) or
+ isinstance(ftype, ctypeprim.W_CTypePrimitiveUnsigned) or
+ isinstance(ftype, ctypeprim.W_CTypePrimitiveChar)) or
+ fbitsize == 0 or
+ fbitsize > 8 * ftype.size):
+ raise operationerrfmt(space.w_TypeError,
+ "invalid bit field '%s'", fname)
+ if prev_bit_position > 0:
+ prev_field = fields_list[-1]
+ assert prev_field.bitshift >= 0
+ if prev_field.ctype.size != ftype.size:
+ raise OperationError(space.w_NotImplementedError,
+ space.wrap("consecutive bit fields should be "
+ "declared with a same-sized type"))
+ if prev_bit_position + fbitsize > 8 * ftype.size:
+ prev_bit_position = 0
+ else:
+ # we can share the same field as 'prev_field'
+ offset = prev_field.offset
+ bitshift = prev_bit_position
+ if not is_union:
+ prev_bit_position += fbitsize
#
fld = ctypestruct.W_CField(ftype, offset, bitshift, fbitsize)
fields_list.append(fld)
More information about the pypy-commit
mailing list