Author: Wim Lavrijsen <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit