Author: Wim Lavrijsen <wlavrij...@lbl.gov> 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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit