Author: Wim Lavrijsen <wlavrij...@lbl.gov> Branch: reflex-support Changeset: r54704:ad4fa188692f Date: 2012-04-23 17:36 -0700 http://bitbucket.org/pypy/pypy/changeset/ad4fa188692f/
Log: better auto-casting support (Reflex only) diff --git a/pypy/module/cppyy/capi/__init__.py b/pypy/module/cppyy/capi/__init__.py --- a/pypy/module/cppyy/capi/__init__.py +++ b/pypy/module/cppyy/capi/__init__.py @@ -243,15 +243,15 @@ _c_base_offset = rffi.llexternal( "cppyy_base_offset", - [C_TYPE, C_TYPE, C_OBJECT], rffi.SIZE_T, + [C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.LONG, threadsafe=threadsafe, compilation_info=backend.eci, elidable_function=True) @jit.elidable_promote() -def c_base_offset(derived, base, address): +def c_base_offset(derived, base, address, direction): if derived == base: return 0 - return _c_base_offset(derived.handle, base.handle, address) + return _c_base_offset(derived.handle, base.handle, address, direction) # method/function reflection information ------------------------------------- _c_num_methods = rffi.llexternal( 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 @@ -584,7 +584,7 @@ if isinstance(obj, W_CPPInstance): if capi.c_is_subtype(obj.cppclass, self.cppclass): rawobject = obj.get_rawobject() - offset = capi.c_base_offset(obj.cppclass, self.cppclass, rawobject) + offset = capi.c_base_offset(obj.cppclass, self.cppclass, rawobject, 1) obj_address = capi.direct_ptradd(rawobject, offset) return rffi.cast(capi.C_OBJECT, obj_address) raise OperationError(space.w_TypeError, diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h --- a/pypy/module/cppyy/include/capi.h +++ b/pypy/module/cppyy/include/capi.h @@ -59,7 +59,9 @@ int cppyy_num_bases(cppyy_type_t type); char* cppyy_base_name(cppyy_type_t type, int base_index); int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base); - size_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address); + + /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */ + long cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction); /* method/function reflection information --------------------------------- */ int cppyy_num_methods(cppyy_scope_t scope); 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 @@ -354,7 +354,7 @@ if cppinstance: assert lltype.typeOf(cppinstance.cppclass.handle) == lltype.typeOf(self.scope.handle) offset = self.offset + capi.c_base_offset( - cppinstance.cppclass, self.scope, cppinstance.get_rawobject()) + cppinstance.cppclass, self.scope, cppinstance.get_rawobject(), 1) else: offset = self.offset return offset @@ -594,7 +594,7 @@ def get_cppthis(self, cppinstance, calling_scope): assert self == cppinstance.cppclass - offset = capi.c_base_offset(self, calling_scope, cppinstance.get_rawobject()) + offset = capi.c_base_offset(self, calling_scope, cppinstance.get_rawobject(), 1) return capi.direct_ptradd(cppinstance.get_rawobject(), offset) W_ComplexCPPClass.typedef = TypeDef( @@ -749,7 +749,7 @@ if rawobject: actual = capi.c_actual_class(cppclass, rawobject) if actual != cppclass.handle: - offset = capi._c_base_offset(actual, cppclass.handle, rawobject) + offset = capi._c_base_offset(actual, cppclass.handle, rawobject, -1) rawobject = capi.direct_ptradd(rawobject, offset) w_pycppclass = get_pythonized_cppclass(space, actual) w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy")) diff --git a/pypy/module/cppyy/src/cintcwrapper.cxx b/pypy/module/cppyy/src/cintcwrapper.cxx --- a/pypy/module/cppyy/src/cintcwrapper.cxx +++ b/pypy/module/cppyy/src/cintcwrapper.cxx @@ -467,11 +467,13 @@ return derived_type->GetBaseClass(base_type) != 0; } -size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle, cppyy_object_t address) { +long cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle, + cppyy_object_t address, int /* direction */) { + // WARNING: CINT can not handle actual dynamic casts! TClassRef derived_type = type_from_handle(derived_handle); TClassRef base_type = type_from_handle(base_handle); - size_t offset = 0; + long offset = 0; if (derived_type && base_type) { G__ClassInfo* base_ci = (G__ClassInfo*)base_type->GetClassInfo(); @@ -483,18 +485,15 @@ // with CINT's (or Reflex's) interfaces. long baseprop = derived_ci->IsBase(*base_ci); if (!baseprop || (baseprop & G__BIT_ISVIRTUALBASE)) - offset = (size_t)derived_type->GetBaseClassOffset(base_type); + offset = derived_type->GetBaseClassOffset(base_type); else #endif offset = G__isanybase(base_ci->Tagnum(), derived_ci->Tagnum(), (long)address); } else { - offset = (size_t)derived_type->GetBaseClassOffset(base_type); + offset = derived_type->GetBaseClassOffset(base_type); } } - if (offset < 0) // error return of G__isanybase() - return 0; - return offset; } diff --git a/pypy/module/cppyy/src/reflexcwrapper.cxx b/pypy/module/cppyy/src/reflexcwrapper.cxx --- a/pypy/module/cppyy/src/reflexcwrapper.cxx +++ b/pypy/module/cppyy/src/reflexcwrapper.cxx @@ -277,7 +277,8 @@ return (int)derived_type.HasBase(base_type); } -size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle, cppyy_object_t address) { +long cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle, + cppyy_object_t address, int direction) { Reflex::Type derived_type = type_from_handle(derived_handle); Reflex::Type base_type = type_from_handle(base_handle); @@ -291,9 +292,20 @@ Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), &bases); getbases.Invoke(&bases_holder); + // if direction is down-cast, perform the cast in C++ first in order to ensure + // we have a derived object for accessing internal offset pointers + if (direction < 0) { + Reflex::Object o(base_type, (void*)address); + address = (cppyy_object_t)o.CastObject(derived_type).Address(); + } + for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); ++ibase) { - if (ibase->first.ToType() == base_type) - return (size_t)ibase->first.Offset((void*)address); + if (ibase->first.ToType() == base_type) { + long offset = (long)ibase->first.Offset((void*)address); + if (direction < 0) + return -offset; + return offset; + } } // contrary to typical invoke()s, the result of the internal getbases function diff --git a/pypy/module/cppyy/test/advancedcpp.cxx b/pypy/module/cppyy/test/advancedcpp.cxx --- a/pypy/module/cppyy/test/advancedcpp.cxx +++ b/pypy/module/cppyy/test/advancedcpp.cxx @@ -10,6 +10,9 @@ // for esoteric inheritance testing +a_class* create_c1() { return new c_class_1; } +a_class* create_c2() { return new c_class_2; } + int get_a( a_class& a ) { return a.m_a; } int get_b( b_class& b ) { return b.m_b; } int get_c( c_class& c ) { return c.m_c; } diff --git a/pypy/module/cppyy/test/advancedcpp.h b/pypy/module/cppyy/test/advancedcpp.h --- a/pypy/module/cppyy/test/advancedcpp.h +++ b/pypy/module/cppyy/test/advancedcpp.h @@ -91,6 +91,9 @@ int m_d; }; +a_class* create_c1(); +a_class* create_c2(); + int get_a(a_class& a); int get_b(b_class& b); int get_c(c_class& c); diff --git a/pypy/module/cppyy/test/advancedcpp.xml b/pypy/module/cppyy/test/advancedcpp.xml --- a/pypy/module/cppyy/test/advancedcpp.xml +++ b/pypy/module/cppyy/test/advancedcpp.xml @@ -12,6 +12,7 @@ <class name="c_class_2" /> <class name="d_class" /> + <function pattern="create_*" /> <function pattern="get_*" /> <class pattern="T1<*>" /> diff --git a/pypy/module/cppyy/test/advancedcpp_LinkDef.h b/pypy/module/cppyy/test/advancedcpp_LinkDef.h --- a/pypy/module/cppyy/test/advancedcpp_LinkDef.h +++ b/pypy/module/cppyy/test/advancedcpp_LinkDef.h @@ -16,6 +16,9 @@ #pragma link C++ class c_class_2; #pragma link C++ class d_class; +#pragma link C++ function create_c1(); +#pragma link C++ function create_c2(); + #pragma link C++ function get_a(a_class&); #pragma link C++ function get_b(b_class&); #pragma link C++ function get_c(c_class&); 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 @@ -1,6 +1,8 @@ import py, os, sys from pypy.conftest import gettestobjspace +from pypy.module.cppyy import capi + currpath = py.path.local(__file__).dirpath() test_dct = str(currpath.join("advancedcppDict.so")) @@ -20,6 +22,7 @@ cls.space = space env = os.environ cls.w_test_dct = space.wrap(test_dct) + cls.w_capi_identity = space.wrap(capi.identify()) cls.w_advanced = cls.space.appexec([], """(): import cppyy return cppyy.load_reflection_info(%r)""" % (test_dct, )) @@ -466,3 +469,22 @@ assert isinstance(b.clone(), base_class) # TODO: clone() leaks assert isinstance(d.clone(), derived_class) # TODO: clone() leaks + + def test13_actual_type_virtual_multi(self): + """Test auto-downcast in adverse inheritance situation""" + + import cppyy + + c1 = cppyy.gbl.create_c1() + assert type(c1) == cppyy.gbl.c_class_1 + assert c1.m_c == 3 + c1.destruct() + + if self.capi_identity == 'CINT': # CINT does not support dynamic casts + return + + c2 = cppyy.gbl.create_c2() + assert type(c2) == cppyy.gbl.c_class_2 + print c2.m_c + assert c2.m_c == 3 + c2.destruct() _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit