[pypy-commit] pypy ffi-backend: Pom pom pom

arigo noreply at buildbot.pypy.org
Sat Jun 23 15:46:58 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r55780:e73d843759a7
Date: 2012-06-23 15:46 +0200
http://bitbucket.org/pypy/pypy/changeset/e73d843759a7/

Log:	Pom pom pom

diff --git a/pypy/module/_ffi_backend/__init__.py b/pypy/module/_ffi_backend/__init__.py
--- a/pypy/module/_ffi_backend/__init__.py
+++ b/pypy/module/_ffi_backend/__init__.py
@@ -12,9 +12,12 @@
         'new_primitive_type': 'newtype.new_primitive_type',
         'new_pointer_type': 'newtype.new_pointer_type',
         'new_array_type': 'newtype.new_array_type',
+        'new_struct_type': 'newtype.new_struct_type',
+        'complete_struct_or_union': 'newtype.complete_struct_or_union',
 
         'newp': 'func.newp',
         'cast': 'func.cast',
         'sizeof': 'func.sizeof',
         'alignof': 'func.alignof',
+        '_getfields': 'func._getfields',
         }
diff --git a/pypy/module/_ffi_backend/ctypeobj.py b/pypy/module/_ffi_backend/ctypeobj.py
--- a/pypy/module/_ffi_backend/ctypeobj.py
+++ b/pypy/module/_ffi_backend/ctypeobj.py
@@ -1,16 +1,16 @@
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rlib.rarithmetic import intmask, ovfcheck
-from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.objectmodel import keepalive_until_here, we_are_translated
 
 from pypy.module._ffi_backend import cdataobj, misc
 
 
 class W_CType(Wrappable):
-    _immutable_ = True
+    #_immutable_ = True    XXX newtype.complete_struct_or_union()?
 
     def __init__(self, space, size, name, name_position):
         self.space = space
@@ -72,8 +72,20 @@
         return name, name_position
 
     def alignof(self):
+        align = self._alignof()
+        if not we_are_translated():
+            # obscure hack when untranslated, maybe, approximate, don't use
+            from pypy.rpython.lltypesystem import llmemory
+            if isinstance(align, llmemory.FieldOffset):
+                align = rffi.sizeof(align.TYPE.y)
+        return align
+
+    def _alignof(self):
         xxx
 
+    def _getfields(self):
+        return None
+
 
 class W_CTypePtrOrArray(W_CType):
 
@@ -135,7 +147,7 @@
         p = rffi.ptradd(cdata, i * self.ctitem.size)
         return cdataobj.W_CData(self.space, p, self)
 
-    def alignof(self):
+    def _alignof(self):
         from pypy.module._ffi_backend import newtype
         return newtype.alignment_of_pointer
 
@@ -148,7 +160,7 @@
         self.length = length
         self.ctptr = ctptr
 
-    def alignof(self):
+    def _alignof(self):
         return self.ctitem.alignof()
 
     def newp(self, w_init):
@@ -223,7 +235,7 @@
         W_CType.__init__(self, space, size, name, name_position)
         self.align = align
 
-    def alignof(self):
+    def _alignof(self):
         return self.align
 
     def cast_single_char(self, w_ob):
@@ -370,8 +382,61 @@
         misc.write_raw_float_data(cdata, value, self.size)
 
 
+class W_CTypeStructOrUnion(W_CType):
+    # fields added by complete_struct_or_union():
+    alignment = -1
+    fields_list = None
+    fields_dict = None
+
+    def __init__(self, space, name):
+        name = '%s %s' % (self.kind, name)
+        W_CType.__init__(self, space, -1, name, len(name))
+
+    def _alignof(self):
+        space = self.space
+        if self.size < 0:
+            raise operationerrfmt(space.w_TypeError,
+                                  "'%s' is not completed yet", self.name)
+        return self.alignment
+
+    def _getfields(self):
+        if self.size < 0:
+            return None
+        space = self.space
+        result = [None] * len(self.fields_list)
+        for fname, field in self.fields_dict.iteritems():
+            i = self.fields_list.index(field)
+            result[i] = space.newtuple([space.wrap(fname),
+                                        space.wrap(field)])
+        return space.newlist(result)
+
+
+class W_CTypeStruct(W_CTypeStructOrUnion):
+    kind = "struct"
+
+class W_CTypeUnion(W_CTypeStructOrUnion):
+    kind = "union"
+
+class W_CField(Wrappable):
+    _immutable_ = True
+    def __init__(self, ctype, offset, bitshift, bitsize):
+        self.ctype = ctype
+        self.offset = offset
+        self.bitshift = bitshift
+        self.bitsize = bitsize
+
+
 W_CType.typedef = TypeDef(
     '_ffi_backend.CTypeDescr',
     __repr__ = interp2app(W_CType.repr),
     )
 W_CType.typedef.acceptable_as_base_class = False
+
+W_CField.typedef = TypeDef(
+    '_ffi_backend.CField',
+    type = interp_attrproperty('ctype', W_CField),
+    offset = interp_attrproperty('offset', W_CField),
+    bitshift = interp_attrproperty('bitshift', W_CField),
+    bitsize = interp_attrproperty('bitsize', W_CField),
+    )
+W_CField.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_ffi_backend/func.py b/pypy/module/_ffi_backend/func.py
--- a/pypy/module/_ffi_backend/func.py
+++ b/pypy/module/_ffi_backend/func.py
@@ -1,8 +1,7 @@
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-from pypy.rlib.objectmodel import we_are_translated
+from pypy.rpython.lltypesystem import lltype, rffi
 
 from pypy.module._ffi_backend import ctypeobj, cdataobj
 
@@ -40,8 +39,8 @@
 @unwrap_spec(ctype=ctypeobj.W_CType)
 def alignof(space, ctype):
     align = ctype.alignof()
-    if not we_are_translated():
-        # obscure hack when untranslated, maybe, approximate, don't use
-        assert isinstance(align, llmemory.FieldOffset)
-        align = rffi.sizeof(align.TYPE.y)
     return space.wrap(align)
+
+ at unwrap_spec(ctype=ctypeobj.W_CType)
+def _getfields(space, ctype):
+    return ctype._getfields()
diff --git a/pypy/module/_ffi_backend/newtype.py b/pypy/module/_ffi_backend/newtype.py
--- a/pypy/module/_ffi_backend/newtype.py
+++ b/pypy/module/_ffi_backend/newtype.py
@@ -80,3 +80,98 @@
     #
     ctypeptr = ctypeobj.W_CTypeArray(space, ctptr, length, arraysize, extra)
     return ctypeptr
+
+# ____________________________________________________________
+
+ at unwrap_spec(name=str)
+def new_struct_type(space, name):
+    return ctypeobj.W_CTypeStruct(space, name)
+
+ at unwrap_spec(ctype=ctypeobj.W_CType, totalsize=int, totalalignment=int)
+def complete_struct_or_union(space, ctype, w_fields, w_ignored=None,
+                             totalsize=-1, totalalignment=-1):
+    if (not isinstance(ctype, ctypeobj.W_CTypeStructOrUnion)
+            or ctype.size >= 0):
+        raise OperationError(space.w_TypeError,
+                             space.wrap("first arg must be a non-initialized"
+                                        " struct or union ctype"))
+
+    is_union = isinstance(ctype, ctypeobj.W_CTypeUnion)
+    maxsize = 1
+    alignment = 1
+    offset = 0
+    fields_w = space.listview(w_fields)
+    fields_list = []
+    fields_dict = {}
+    prev_bit_position = 0
+    prev_field = None
+
+    for w_field in fields_w:
+        field_w = space.fixedview(w_field)
+        if not (2 <= len(field_w) <= 4):
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("bad field descr"))
+        fname = space.str_w(field_w[0])
+        ftype = space.interp_w(ctypeobj.W_CType, field_w[1])
+        fbitsize = -1
+        foffset = -1
+        if len(field_w) > 2: fbitsize = space.int_w(field_w[2])
+        if len(field_w) > 3: foffset = space.int_w(field_w[3])
+        #
+        if fname in fields_dict:
+            raise operationerrfmt(space.w_KeyError,
+                                  "duplicate field name '%s'", fname)
+        #
+        if ftype.size < 0:
+            raise operationerrfmt(space.w_TypeError,
+                    "field '%s.%s' has ctype '%s' of unknown size",
+                                  ctype.name, fname, ftype.name)
+        #
+        falign = ftype.alignof()
+        if alignment < falign:
+            alignment = falign
+        #
+        if foffset < 0:
+            # align this field to its own 'falign' by inserting padding
+            offset = (offset + falign - 1) & ~(falign-1)
+        else:
+            offset = foffset
+        #
+        if fbitsize < 0 or (fbitsize == 8 * ftype.size and
+                            not isinstance(ftype, W_CTypePrimitiveChar)):
+            fbitsize = -1
+            bitshift = -1
+            prev_bit_position = 0
+        else:
+            xxx
+        #
+        fld = ctypeobj.W_CField(ftype, offset, bitshift, fbitsize)
+        fields_list.append(fld)
+        fields_dict[fname] = fld
+        #
+        if maxsize < ftype.size:
+            maxsize = ftype.size
+        if not is_union:
+            offset += ftype.size
+
+    if is_union:
+        assert offset == 0
+        offset = maxsize
+    else:
+        if offset == 0:
+            offset = 1
+        offset = (offset + alignment - 1) & ~(alignment-1)
+
+    if totalsize < 0:
+        totalsize = offset
+    elif totalsize < offset:
+        raise operationerrfmt(space.w_TypeError,
+                     "%s cannot be of size %d: there are fields at least "
+                     "up to %d", ctype.name, totalsize, offset)
+    if totalalignment < 0:
+        totalalignment = alignment
+
+    ctype.size = totalsize
+    ctype.alignment = totalalignment
+    ctype.fields_list = fields_list
+    ctype.fields_dict = fields_dict
diff --git a/pypy/module/_ffi_backend/test/_backend_test_c.py b/pypy/module/_ffi_backend/test/_backend_test_c.py
--- a/pypy/module/_ffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_ffi_backend/test/_backend_test_c.py
@@ -440,6 +440,7 @@
     assert repr(BStruct) == "<ctype 'struct foo'>"
     BPtr = new_pointer_type(BStruct)
     assert repr(BPtr) == "<ctype 'struct foo *'>"
+    py.test.raises(TypeError, alignof, BStruct)
 
 def test_new_union_type():
     BUnion = new_union_type("foo")


More information about the pypy-commit mailing list