Author: Wim Lavrijsen <[email protected]>
Branch: cppyy-packaging
Changeset: r94854:80195e50eca4
Date: 2018-07-12 12:39 -0700
http://bitbucket.org/pypy/pypy/changeset/80195e50eca4/
Log: improve object identity handling (now also includes data members)
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
@@ -566,10 +566,6 @@
from pypy.module._cppyy import interp_cppyy
return interp_cppyy.wrap_cppinstance(space, address, self.clsdecl,
do_cast=False)
- def to_memory(self, space, w_obj, w_value, offset):
- address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj,
offset))
- address[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_value))
-
class InstancePtrPtrConverter(InstancePtrConverter):
typecode = 'o'
@@ -597,6 +593,25 @@
return interp_cppyy.wrap_cppinstance(
space, address, self.clsdecl, do_cast=False, is_ref=True)
+ def to_memory(self, space, w_obj, w_value, offset):
+ # the actual data member is of object* type, but we receive a pointer
to that
+ # data member in order to modify its value, so by convention, the
internal type
+ # used is object**
+ address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj,
offset))
+ from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+ cppinstance = space.interp_w(W_CPPInstance, w_value, can_be_None=True)
+ if cppinstance:
+ rawobject = cppinstance.get_rawobject()
+ offset = capi.c_base_offset(space, cppinstance.clsdecl,
self.clsdecl, rawobject, 1)
+ obj_address = capi.direct_ptradd(rawobject, offset)
+ address[0] = rffi.cast(rffi.VOIDP, obj_address);
+ # register the value for potential recycling
+ from pypy.module._cppyy.interp_cppyy import memory_regulator
+ memory_regulator.register(cppinstance)
+ else:
+ raise oefmt(space.w_TypeError,
+ "cannot pass %T instance as %s", w_value, self.clsdecl.name)
+
def finalize_call(self, space, w_obj):
if self.ref_buffer:
set_rawobject(space, w_obj, self.ref_buffer[0])
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
@@ -167,6 +167,7 @@
#
# W_CPPOverload: instance methods (base class)
# W_CPPConstructorOverload: constructors
+# W_CPPAbstractCtorOverload: to provent instantiation of abstract classes
# W_CPPStaticOverload: free and static functions
# W_CPPTemplateOverload: templated methods
# W_CPPTemplateStaticOverload: templated free and static functions
@@ -674,7 +675,7 @@
__doc__ = GetSetProperty(W_CPPConstructorOverload.fget_doc)
)
-class W_CPPAbstractConstructorOverload(W_CPPOverload):
+class W_CPPAbstractCtorOverload(W_CPPOverload):
_attrs_ = []
@unwrap_spec(args_w='args_w')
@@ -683,12 +684,12 @@
"cannot instantiate abstract class '%s'", self.scope.name)
def __repr__(self):
- return "W_CPPAbstractConstructorOverload"
+ return "W_CPPAbstractCtorOverload"
-W_CPPAbstractConstructorOverload.typedef = TypeDef(
- 'CPPAbstractConstructorOverload',
- __get__ = interp2app(W_CPPAbstractConstructorOverload.descr_get),
- __call__ = interp2app(W_CPPAbstractConstructorOverload.call_args),
+W_CPPAbstractCtorOverload.typedef = TypeDef(
+ 'CPPAbstractCtorOverload',
+ __get__ = interp2app(W_CPPAbstractCtorOverload.descr_get),
+ __call__ = interp2app(W_CPPAbstractCtorOverload.call_args),
)
@@ -1086,7 +1087,7 @@
sig = '(%s)' % signature
for f in overload.functions:
if f.signature(False) == sig:
- return W_CPPOverload(self.space, self, [f])
+ return type(overload)(self.space, self, [f])
raise oefmt(self.space.w_LookupError, "no overload matches signature")
def __eq__(self, other):
@@ -1181,9 +1182,13 @@
class W_CPPClassDecl(W_CPPScopeDecl):
- _attrs_ = ['space', 'handle', 'name', 'overloads', 'datamembers']
+ _attrs_ = ['space', 'handle', 'name', 'overloads', 'datamembers',
'cppobjects']
_immutable_fields_ = ['handle', 'name', 'overloads[*]', 'datamembers[*]']
+ def __init__(self, space, opaque_handle, final_scoped_name):
+ W_CPPScopeDecl.__init__(self, space, opaque_handle, final_scoped_name)
+ self.cppobjects = rweakref.RWeakValueDictionary(int, W_CPPInstance)
+
def _build_overloads(self):
assert len(self.overloads) == 0
methods_tmp = {}; ftype_tmp = {}
@@ -1223,7 +1228,7 @@
CPPMethodSort(methods).sort()
if ftype & FUNCTION_IS_CONSTRUCTOR:
if capi.c_is_abstract(self.space, self.handle):
- overload = W_CPPAbstractConstructorOverload(self.space,
self, methods[:])
+ overload = W_CPPAbstractCtorOverload(self.space, self,
methods[:])
else:
overload = W_CPPConstructorOverload(self.space, self,
methods[:])
elif ftype & FUNCTION_IS_STATIC:
@@ -1543,31 +1548,33 @@
class MemoryRegulator:
- # TODO: (?) An object address is not unique if e.g. the class has a
- # public data member of class type at the start of its definition and
- # has no virtual functions. A _key class that hashes on address and
- # type would be better, but my attempt failed in the rtyper, claiming
- # a call on None ("None()") and needed a default ctor. (??)
- # Note that for now, the associated test carries an m_padding to make
- # a difference in the addresses.
- def __init__(self):
- self.objects = rweakref.RWeakValueDictionary(int, W_CPPInstance)
+ _immutable_ = True
- def register(self, obj):
+ @staticmethod
+ def register(obj):
if not obj._rawobject:
return
- int_address = int(rffi.cast(rffi.LONG, obj._rawobject))
- self.objects.set(int_address, obj)
+ addr_as_int = int(rffi.cast(rffi.LONG, obj.get_rawobject()))
+ clsdecl = obj.clsdecl
+ assert isinstance(clsdecl, W_CPPClassDecl)
+ clsdecl.cppobjects.set(addr_as_int, obj)
- def unregister(self, obj):
+ @staticmethod
+ def unregister(obj):
if not obj._rawobject:
return
- int_address = int(rffi.cast(rffi.LONG, obj._rawobject))
- self.objects.set(int_address, None)
+ addr_as_int = int(rffi.cast(rffi.LONG, obj.get_rawobject()))
+ clsdecl = obj.clsdecl
+ assert isinstance(clsdecl, W_CPPClassDecl)
+ clsdecl.cppobjects.set(addr_as_int, None) # actually deletes (pops)
- def retrieve(self, address):
- int_address = int(rffi.cast(rffi.LONG, address))
- return self.objects.get(int_address)
+ @staticmethod
+ def retrieve(clsdecl, address):
+ if not address:
+ return None
+ addr_as_int = int(rffi.cast(rffi.LONG, address))
+ assert isinstance(clsdecl, W_CPPClassDecl)
+ return clsdecl.cppobjects.get(addr_as_int)
memory_regulator = MemoryRegulator()
@@ -1613,8 +1620,11 @@
# try to recycle existing object if this one is not newly created
if not fresh and rawobject:
- obj = memory_regulator.retrieve(rawobject)
- if obj is not None and obj.clsdecl is clsdecl:
+ address = rawobject
+ if is_ref:
+ address = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP,
address)[0])
+ obj = memory_regulator.retrieve(clsdecl, address)
+ if obj is not None:
return obj
# fresh creation
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
@@ -489,6 +489,23 @@
d2.__destruct__()
d1.__destruct__()
+ RTS = cppyy.gbl.refers_to_self
+
+ r1 = RTS()
+ r2 = RTS()
+ r1.m_other = r2
+
+ r3 = r1.m_other
+ r4 = r1.m_other
+ assert r3 is r4
+
+ assert r3 == r2
+ assert r3 is r2
+
+ r3.extra = 42
+ assert r2.extra == 42
+ assert r4.extra == 42
+
def test11_multi_methods(self):
"""Test calling of methods from multiple inheritance"""
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit