[pypy-commit] pypy cppyy-packaging: converter for builtin arrays of instances

wlav pypy.commits at gmail.com
Thu Jul 19 00:42:43 EDT 2018


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: cppyy-packaging
Changeset: r94878:046b87bc288f
Date: 2018-07-18 21:21 -0700
http://bitbucket.org/pypy/pypy/changeset/046b87bc288f/

Log:	converter for builtin arrays of instances

diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
--- a/pypy/module/_cppyy/converter.py
+++ b/pypy/module/_cppyy/converter.py
@@ -622,6 +622,24 @@
             lltype.free(self.ref_buffer, flavor='raw')
             self.ref_buffer = lltype.nullptr(rffi.VOIDPP.TO)
 
+class InstanceArrayConverter(InstancePtrConverter):
+    _immutable_fields_ = ['size']
+
+    def __init__(self, space, clsdecl, array_size):
+        InstancePtrConverter.__init__(self, space, clsdecl)
+        if array_size <= 0:
+            self.size = sys.maxint
+        else:
+            self.size = array_size
+
+    def from_memory(self, space, w_obj, offset):
+        address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
+        return lowlevelviews.W_ArrayOfInstances(space, self.clsdecl, address, self.size)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        self._is_abstract(space)
+
+
 class StdStringConverter(InstanceConverter):
     def __init__(self, space, extra):
         from pypy.module._cppyy import interp_cppyy
@@ -846,20 +864,19 @@
         pass
 
     # match of decorated, unqualified type
-    compound = helper.compound(name)
+    cpd = helper.compound(name)
     clean_name = capi.c_resolve_name(space, helper.clean_type(name))
     try:
-        return _converters[clean_name+compound](space, default)
+        return _converters[clean_name+cpd](space, default)
     except KeyError:
         pass
 
-    # arrays
+    # arrays (array_size may be negative, meaning: no size or no size found)
+    array_size = helper.array_size(_name)     # uses original arg
     try:
-        # array_index may be negative to indicate no size or no size found
-        array_size = helper.array_size(_name)     # uses original arg
         # TODO: using clean_name here drops const (e.g. const char[] will
         # never be seen this way)
-        return _a_converters[clean_name+compound](space, array_size)
+        return _a_converters[clean_name+cpd](space, array_size)
     except KeyError:
         pass
 
@@ -873,24 +890,27 @@
         # check smart pointer type
         check_smart = capi.c_smartptr_info(space, clean_name)
         if check_smart[0]:
-            if compound == '':
+            if cpd == '':
                 return SmartPtrConverter(space, clsdecl, check_smart[1], check_smart[2])
-            elif compound == '*':
+            elif cpd == '*':
                 return SmartPtrPtrConverter(space, clsdecl, check_smart[1], check_smart[2])
-            elif compound == '&':
+            elif cpd == '&':
                 return SmartPtrRefConverter(space, clsdecl, check_smart[1], check_smart[2])
             # fall through: can still return smart pointer in non-smart way
 
         # type check for the benefit of the annotator
-        if compound == "*":
+        if cpd == "*":
             return InstancePtrConverter(space, clsdecl)
-        elif compound == "&":
+        elif cpd == "&":
             return InstanceRefConverter(space, clsdecl)
-        elif compound == "&&":
+        elif cpd == "&&":
             return InstanceMoveConverter(space, clsdecl)
-        elif compound == "**":
+        elif cpd in ["**", "*[]", "&*"]:
             return InstancePtrPtrConverter(space, clsdecl)
-        elif compound == "":
+        elif cpd == "[]" and array_size > 0:
+            # TODO: retrieve dimensions
+            return InstanceArrayConverter(space, clsdecl, array_size)
+        elif cpd == "":
             return InstanceConverter(space, clsdecl)
     elif "(anonymous)" in name:
         # special case: enum w/o a type name
@@ -902,7 +922,7 @@
             return FunctionPointerConverter(space, name[pos+2:])
 
     # void* or void converter (which fails on use)
-    if 0 <= compound.find('*'):
+    if 0 <= cpd.find('*'):
         return VoidPtrConverter(space, default)  # "user knows best"
 
     # return a void converter here, so that the class can be build even
diff --git a/pypy/module/_cppyy/interp_cppyy.py b/pypy/module/_cppyy/interp_cppyy.py
--- a/pypy/module/_cppyy/interp_cppyy.py
+++ b/pypy/module/_cppyy/interp_cppyy.py
@@ -1040,7 +1040,7 @@
         self.space = space
         self.scope = decl_scope
         self.converter = converter.get_converter(self.space, type_name, '')
-        self.offset = offset
+        self.offset = rffi.cast(rffi.LONG, offset)
 
     def _get_offset(self, cppinstance):
         if cppinstance:
diff --git a/pypy/module/_cppyy/lowlevelviews.py b/pypy/module/_cppyy/lowlevelviews.py
--- a/pypy/module/_cppyy/lowlevelviews.py
+++ b/pypy/module/_cppyy/lowlevelviews.py
@@ -3,10 +3,16 @@
 # a few more methods allowing such information to be set. Afterwards, it is
 # simple to pass these views on to e.g. numpy (w/o the need to copy).
 
-from pypy.interpreter.error import oefmt
+from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty_w
+from pypy.interpreter.baseobjspace import W_Root
+
+from rpython.rtyper.lltypesystem import rffi
+
 from pypy.module._rawffi.array import W_ArrayInstance
+from pypy.module._rawffi.interp_rawffi import segfault_exception
+from pypy.module._cppyy import capi
 
 
 class W_LowLevelView(W_ArrayInstance):
@@ -52,3 +58,33 @@
 )
 W_ArrayInstance.typedef.acceptable_as_base_class = False
 
+
+class W_ArrayOfInstances(W_Root):
+    _attrs_ = ['converter', 'baseaddress', 'clssize', 'length']
+    _immutable_fields_ = ['converter', 'baseaddress', 'clssize']
+
+    def __init__(self, space, clsdecl, address, length):
+        from pypy.module._cppyy import converter
+        self.converter   = converter.get_converter(space, clsdecl.name, '')
+        self.baseaddress = address
+        self.clssize     = capi.c_size_of_klass(space, clsdecl)
+        self.length      = length
+
+    @unwrap_spec(idx=int)
+    def getitem(self, space, idx):
+        if not self.baseaddress:
+            raise segfault_exception(space, "accessing elements of freed array")
+        if idx >= self.length or idx < 0:
+            raise OperationError(space.w_IndexError, space.w_None)
+        itemaddress = rffi.cast(rffi.LONG, self.baseaddress+idx*self.clssize)
+        return self.converter.from_memory(space, space.w_None, itemaddress)
+
+    def getlength(self, space):
+        return space.newint(self.length)
+
+W_ArrayOfInstances.typedef = TypeDef(
+    'ArrayOfInstances',
+    __getitem__ = interp2app(W_ArrayOfInstances.getitem),
+    __len__     = interp2app(W_ArrayOfInstances.getlength),
+)
+W_ArrayOfInstances.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cppyy/test/test_advancedcpp.py b/pypy/module/_cppyy/test/test_advancedcpp.py
--- a/pypy/module/_cppyy/test/test_advancedcpp.py
+++ b/pypy/module/_cppyy/test/test_advancedcpp.py
@@ -690,7 +690,6 @@
         # TODO: currently fails b/c double** not understood as &double*
         #assert cppyy.gbl.my_global_ptr[0] == 1234.
 
-        return
         v = cppyy.gbl.my_global_int_holders
         assert len(v) == 5
         expected_vals = [13, 42, 88, -1, 17]


More information about the pypy-commit mailing list