Author: Wim Lavrijsen <wlavrij...@lbl.gov>
Branch: cppyy-packaging
Changeset: r94736:bf4f9f2a4234
Date: 2018-05-21 20:56 -0700
http://bitbucket.org/pypy/pypy/changeset/bf4f9f2a4234/

Log:    finish pythonization of smart pointers

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
@@ -699,8 +699,8 @@
                     "no overload found matching %s", self.signature)
 
 
-class SmartPtrCppObjectConverter(TypeConverter):
-    _immutable_fields = ['smartdecl', 'rawdecl', 'deref']
+class SmartPointerConverter(TypeConverter):
+    _immutable_fields = ['typecode', 'smartdecl', 'rawdecl', 'deref']
     typecode    = 'V'
 
     def __init__(self, space, smartdecl, raw, deref):
@@ -746,6 +746,19 @@
         return interp_cppyy.wrap_cppinstance(space, address,
             self.rawdecl, smartdecl=self.smartdecl, deref=self.deref, 
do_cast=False)
 
+class SmartPointerPtrConverter(SmartPointerConverter):
+    typecode    = 'o'
+
+    def from_memory(self, space, w_obj, w_pycppclass, offset):
+        self._is_abstract(space)
+
+    def to_memory(self, space, w_obj, w_value, offset):
+        self._is_abstract(space)
+
+
+class SmartPointerRefConverter(SmartPointerPtrConverter):
+    typecode    = 'V'
+
 
 class MacroConverter(TypeConverter):
     def from_memory(self, space, w_obj, w_pycppclass, offset):
@@ -800,7 +813,13 @@
         # check smart pointer type
         check_smart = capi.c_smartptr_info(space, clean_name)
         if check_smart[0]:
-            return SmartPtrCppObjectConverter(space, clsdecl, check_smart[1], 
check_smart[2])
+            if compound == '':
+                return SmartPointerConverter(space, clsdecl, check_smart[1], 
check_smart[2])
+            elif compound == '*':
+                return SmartPointerPtrConverter(space, clsdecl, 
check_smart[1], check_smart[2])
+            elif compound == '&':
+                return SmartPointerRefConverter(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 == "*":
diff --git a/pypy/module/_cppyy/executor.py b/pypy/module/_cppyy/executor.py
--- a/pypy/module/_cppyy/executor.py
+++ b/pypy/module/_cppyy/executor.py
@@ -125,7 +125,6 @@
 
 
 class CStringExecutor(FunctionExecutor):
-
     def execute(self, space, cppmethod, cppthis, num_args, args):
         lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
         ccpresult = rffi.cast(rffi.CCHARP, lresult)
@@ -136,7 +135,6 @@
 
 
 class ConstructorExecutor(FunctionExecutor):
-
     def execute(self, space, cppmethod, cpptype, num_args, args):
         from pypy.module._cppyy import interp_cppyy
         newthis = capi.c_constructor(space, cppmethod, cpptype, num_args, args)
@@ -144,80 +142,77 @@
         return space.newlong(rffi.cast(rffi.LONG, newthis))   # really want 
ptrdiff_t here
 
 
-class InstancePtrExecutor(FunctionExecutor):
-    _immutable_fields_ = ['cppclass']
+class InstanceExecutor(FunctionExecutor):
+    # For return of a C++ instance by pointer: MyClass* func()
+    _immutable_fields_ = ['clsdecl']
 
-    def __init__(self, space, cppclass):
-        FunctionExecutor.__init__(self, space, cppclass)
-        self.cppclass = cppclass
+    def __init__(self, space, clsdecl):
+        FunctionExecutor.__init__(self, space, clsdecl)
+        self.clsdecl = clsdecl
+
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppinstance(space,
+            obj, self.clsdecl, do_cast=False, python_owns=True, fresh=True)
+
+    def execute(self, space, cppmethod, cppthis, num_args, args):
+        oresult = capi.c_call_o(space, cppmethod, cppthis, num_args, args, 
self.clsdecl)
+        return self._wrap_result(space, rffi.cast(capi.C_OBJECT, oresult))
+
+
+class InstancePtrExecutor(InstanceExecutor):
+    # For return of a C++ instance by pointer: MyClass* func()
 
     def cffi_type(self, space):
         state = space.fromcache(ffitypes.State)
         return state.c_voidp
 
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppinstance(space, obj, self.clsdecl)
+
     def execute(self, space, cppmethod, cppthis, num_args, args):
-        from pypy.module._cppyy import interp_cppyy
-        long_result = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
-        ptr_result = rffi.cast(capi.C_OBJECT, long_result)
-        pyres = interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
-        return pyres
+        lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
+        return self._wrap_result(space, rffi.cast(capi.C_OBJECT, lresult))
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
-        result = rffi.ptradd(buffer, cif_descr.exchange_result)
-        from pypy.module._cppyy import interp_cppyy
-        ptr_result = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, 
result)[0])
-        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
+        presult = rffi.ptradd(buffer, cif_descr.exchange_result)
+        obj = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, presult)[0])
+        return self._wrap_result(space, obj)
 
 class InstancePtrPtrExecutor(InstancePtrExecutor):
+    # For return of a C++ instance by ptr-to-ptr or ptr-to-ref: MyClass*& 
func()
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
-        from pypy.module._cppyy import interp_cppyy
-        voidp_result = capi.c_call_r(space, cppmethod, cppthis, num_args, args)
-        ref_address = rffi.cast(rffi.VOIDPP, voidp_result)
-        ptr_result = rffi.cast(capi.C_OBJECT, ref_address[0])
-        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
+        presult = capi.c_call_r(space, cppmethod, cppthis, num_args, args)
+        ref = rffi.cast(rffi.VOIDPP, presult)
+        return self._wrap_result(space, rffi.cast(capi.C_OBJECT, ref[0]))
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
-class InstanceExecutor(InstancePtrExecutor):
-
-    def execute(self, space, cppmethod, cppthis, num_args, args):
-        from pypy.module._cppyy import interp_cppyy
-        long_result = capi.c_call_o(space, cppmethod, cppthis, num_args, args, 
self.cppclass)
-        ptr_result = rffi.cast(capi.C_OBJECT, long_result)
-        return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass,
-                                             do_cast=False, python_owns=True, 
fresh=True)
-
-    def execute_libffi(self, space, cif_descr, funcaddr, buffer):
-        from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
-        raise FastCallNotPossible
-
 
 class StdStringExecutor(InstancePtrExecutor):
-
     def execute(self, space, cppmethod, cppthis, num_args, args):
         cstr, cstr_len = capi.c_call_s(space, cppmethod, cppthis, num_args, 
args)
         pystr = rffi.charpsize2str(cstr, cstr_len)
         capi.c_free(space, rffi.cast(rffi.VOIDP, cstr))
-        return space.newbytes(pystr)
+        return space.newbytes(pystr) 
 
     def execute_libffi(self, space, cif_descr, funcaddr, buffer):
         from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
         raise FastCallNotPossible
 
 class StdStringRefExecutor(InstancePtrExecutor):
-
-    def __init__(self, space, cppclass):
+    def __init__(self, space, clsdecl):
         from pypy.module._cppyy import interp_cppyy
-        cppclass = interp_cppyy.scope_byname(space, capi.std_string_name)
-        InstancePtrExecutor.__init__(self, space, cppclass)
+        clsdecl = interp_cppyy.scope_byname(space, capi.std_string_name)
+        InstancePtrExecutor.__init__(self, space, clsdecl)
 
 
 class PyObjectExecutor(PtrTypeExecutor):
-
     def wrap_result(self, space, lresult):
         space.getbuiltinmodule("cpyext")
         from pypy.module.cpyext.pyobject import PyObject, from_ref, make_ref, 
decref
@@ -241,6 +236,41 @@
         return self.wrap_result(space, rffi.cast(rffi.LONGP, result)[0])
 
 
+class SmartPointerExecutor(InstanceExecutor):
+    _immutable_fields_ = ['smartdecl', 'deref']
+
+    def __init__(self, space, smartdecl, raw, deref):
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl, 
get_pythonized_cppclass
+        w_raw   = get_pythonized_cppclass(space, raw)
+        rawdecl = space.interp_w(W_CPPClassDecl, space.findattr(w_raw, 
space.newtext("__cppdecl__")))
+        InstanceExecutor.__init__(self, space, rawdecl)
+        self.smartdecl = smartdecl
+        self.deref     = deref
+
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        return interp_cppyy.wrap_cppinstance(space, obj, self.clsdecl,
+            self.smartdecl, self.deref, do_cast=False, python_owns=True, 
fresh=True)
+
+class SmartPointerPtrExecutor(InstancePtrExecutor):
+    _immutable_fields_ = ['smartdecl', 'deref']
+
+    def __init__(self, space, smartdecl, raw, deref):
+        # TODO: share this with SmartPointerExecutor through in mixin
+        from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl, 
get_pythonized_cppclass
+        w_raw   = get_pythonized_cppclass(space, raw)
+        rawdecl = space.interp_w(W_CPPClassDecl, space.findattr(w_raw, 
space.newtext("__cppdecl__")))
+        InstancePtrExecutor.__init__(self, space, rawdecl)
+        self.smartdecl = smartdecl
+        self.deref     = deref
+
+    def _wrap_result(self, space, obj):
+        from pypy.module._cppyy import interp_cppyy
+        # TODO: this is a pointer to a smart pointer, take ownership on the 
smart one?
+        return interp_cppyy.wrap_cppinstance(space, obj, self.clsdecl,
+            self.smartdecl, self.deref, do_cast=False)
+
+
 _executors = {}
 def get_executor(space, name):
     # Matching of 'name' to an executor factory goes through up to four levels:
@@ -253,7 +283,7 @@
 
     name = capi.c_resolve_name(space, name)
 
-    #   1) full, qualified match
+    # full, qualified match
     try:
         return _executors[name](space, None)
     except KeyError:
@@ -262,13 +292,13 @@
     compound = helper.compound(name)
     clean_name = capi.c_resolve_name(space, helper.clean_type(name))
 
-    #   1a) clean lookup
+    # clean lookup
     try:
         return _executors[clean_name+compound](space, None)
     except KeyError:
         pass
 
-    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
+    # drop '&': by-ref is pretty much the same as by-value, python-wise
     if compound and compound[len(compound)-1] == '&':
         # TODO: this does not actually work with Reflex (?)
         try:
@@ -276,19 +306,29 @@
         except KeyError:
             pass
 
-    #   3) types/classes, either by ref/ptr or by value
+    # types/classes, either by ref/ptr or by value
     from pypy.module._cppyy import interp_cppyy
     cppclass = interp_cppyy.scope_byname(space, clean_name)
     if cppclass:
         # type check for the benefit of the annotator
         from pypy.module._cppyy.interp_cppyy import W_CPPClassDecl
-        cppclass = space.interp_w(W_CPPClassDecl, cppclass, can_be_None=False)
+        clsdecl = space.interp_w(W_CPPClassDecl, cppclass, can_be_None=False)
+
+        # check smart pointer type
+        check_smart = capi.c_smartptr_info(space, clean_name)
+        if check_smart[0]:
+            if compound == '':
+                return SmartPointerExecutor(space, clsdecl, check_smart[1], 
check_smart[2])
+            elif compound == '*' or compound == '&':
+                return SmartPointerPtrExecutor(space, clsdecl, check_smart[1], 
check_smart[2])
+            # fall through: can still return smart pointer in non-smart way
+
         if compound == '':
-            return InstanceExecutor(space, cppclass)
+            return InstanceExecutor(space, clsdecl)
         elif compound == '*' or compound == '&':
-            return InstancePtrExecutor(space, cppclass)
+            return InstancePtrExecutor(space, clsdecl)
         elif compound == '**' or compound == '*&':
-            return InstancePtrPtrExecutor(space, cppclass)
+            return InstancePtrPtrExecutor(space, clsdecl)
     elif "(anonymous)" in name:
         # special case: enum w/o a type name
         return _executors["internal_enum_type_t"](space, None)
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
@@ -1284,9 +1284,15 @@
             return wrap_cppinstance(self.space, self._rawobject, 
self.smartdecl, do_cast=False)
 
     def destruct(self):
-        if self._rawobject and not (self.flags & INSTANCE_FLAGS_IS_REF):
+        if self._rawobject:
+            if self.smartdecl and self.deref:
+                klass = self.smartdecl
+            elif not (self.flags & INSTANCE_FLAGS_IS_REF):
+                klass = self.clsdecl
+            else:
+                return
             memory_regulator.unregister(self)
-            capi.c_destruct(self.space, self.clsdecl, self._rawobject)
+            capi.c_destruct(self.space, klass, self._rawobject)
             self._rawobject = capi.C_NULL_OBJECT
 
     def _finalize_(self):
diff --git a/pypy/module/_cppyy/test/test_pythonization.py 
b/pypy/module/_cppyy/test/test_pythonization.py
--- a/pypy/module/_cppyy/test/test_pythonization.py
+++ b/pypy/module/_cppyy/test/test_pythonization.py
@@ -133,15 +133,21 @@
 
         mine = pz.gime_mine_ptr()
         assert type(mine) == Countable
+        assert mine.m_check == 0xcdcdcdcd
         assert type(mine.__smartptr__()) == cppyy.gbl.std.shared_ptr(Countable)
+        assert mine.__smartptr__().get().m_check == 0xcdcdcdcd
         assert mine.say_hi() == "Hi!"
 
         mine = pz.gime_mine_ref()
         assert type(mine) == Countable
+        assert mine.m_check == 0xcdcdcdcd
         assert type(mine.__smartptr__()) == cppyy.gbl.std.shared_ptr(Countable)
+        assert mine.__smartptr__().get().m_check == 0xcdcdcdcd
         assert mine.say_hi() == "Hi!"
 
         mine = pz.gime_mine()
         assert type(mine) == Countable
+        assert mine.m_check == 0xcdcdcdcd
         assert type(mine.__smartptr__()) == cppyy.gbl.std.shared_ptr(Countable)
+        assert mine.__smartptr__().get().m_check == 0xcdcdcdcd
         assert mine.say_hi() == "Hi!"
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to