Author: Wim Lavrijsen <wlavrij...@lbl.gov> Branch: reflex-support Changeset: r45201:e58b8f224098 Date: 2011-06-30 13:20 -0700 http://bitbucket.org/pypy/pypy/changeset/e58b8f224098/
Log: offsets for calling base classes diff --git a/pypy/module/cppyy/capi.py b/pypy/module/cppyy/capi.py --- a/pypy/module/cppyy/capi.py +++ b/pypy/module/cppyy/capi.py @@ -78,6 +78,10 @@ "cppyy_is_subtype", [C_TYPEHANDLE, C_TYPEHANDLE], rffi.INT, compilation_info=eci) +c_base_offset = rffi.llexternal( + "cppyy_base_offset", + [C_TYPEHANDLE, C_TYPEHANDLE], rffi.SIZE_T, + compilation_info=eci) c_call_v = rffi.llexternal( @@ -168,7 +172,7 @@ compilation_info=eci) c_data_member_offset = rffi.llexternal( "cppyy_data_member_offset", - [C_TYPEHANDLE, rffi.INT], rffi.INT, + [C_TYPEHANDLE, rffi.INT], rffi.SIZE_T, compilation_info=eci) c_is_staticdata = 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 @@ -357,7 +357,10 @@ obj = space.interpclass_w(w_obj) if isinstance(obj, W_CPPInstance): if capi.c_is_subtype(obj.cppclass.handle, self.cpptype.handle): - return obj.rawobject + offset = capi.c_base_offset(obj.cppclass.handle, self.cpptype.handle) + obj_address = lltype.direct_ptradd(obj.rawobject, offset) + objptr = rffi.cast(rffi.CCHARP, obj_address) + return objptr raise OperationError(space.w_TypeError, space.wrap("cannot pass %s as %s" % ( space.type(w_obj).getname(space, "?"), diff --git a/pypy/module/cppyy/include/reflexcwrapper.h b/pypy/module/cppyy/include/reflexcwrapper.h --- a/pypy/module/cppyy/include/reflexcwrapper.h +++ b/pypy/module/cppyy/include/reflexcwrapper.h @@ -36,7 +36,8 @@ char* cppyy_final_name(cppyy_typehandle_t handle); int cppyy_num_bases(cppyy_typehandle_t handle); char* cppyy_base_name(cppyy_typehandle_t handle, int base_index); - int cppyy_is_subtype(cppyy_typehandle_t h1, cppyy_typehandle_t h2); + int cppyy_is_subtype(cppyy_typehandle_t dh, cppyy_typehandle_t bh); + size_t cppyy_base_offset(cppyy_typehandle_t dh, cppyy_typehandle_t bh); /* method/function reflection information */ int cppyy_num_methods(cppyy_typehandle_t handle); 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 @@ -21,6 +21,36 @@ return Reflex::Scope((Reflex::ScopeName*)handle); } +static inline size_t base_offset(const Reflex::Type& td, const Reflex::Type& tb) { + // when dealing with virtual inheritance the only (reasonably) well-defined info is + // in a Reflex internal base table, that contains all offsets within the hierarchy + Reflex::Member getbases = td.FunctionMemberByName( + "__getBasesTable", Reflex::Type(), 0, Reflex::INHERITEDMEMBERS_NO, Reflex::DELAYEDLOAD_OFF); + if (getbases) { + typedef std::vector<std::pair<Reflex::Base, int> > Bases_t; + Bases_t* bases; + Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), &bases); + getbases.Invoke(&bases_holder); + + for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); ++ibase) { + if (ibase->first.ToType() == tb) { + if (ibase->first.IsVirtual()) { + Reflex::Object o = td.Construct(); + size_t offset = ibase->first.Offset(o.Address()); + o.Destruct(); + return offset; + } else + return ibase->first.Offset(0); + } + } + + // contrary to typical invoke()s, the result of the internal getbases function + // is a pointer to a function static, so no delete + } + + return 0; +} + /* name to handle --------------------------------------------------------- */ cppyy_typehandle_t cppyy_get_typehandle(const char* class_name) { @@ -171,12 +201,20 @@ return cppstring_to_cstring(name); } -int cppyy_is_subtype(cppyy_typehandle_t h1, cppyy_typehandle_t h2) { - if (h1 == h2) +int cppyy_is_subtype(cppyy_typehandle_t dh, cppyy_typehandle_t bh) { + if (dh == bh) return 1; - Reflex::Type t1 = type_from_handle(h1); - Reflex::Type t2 = type_from_handle(h2); - return (int)t2.HasBase(t1); + Reflex::Type td = type_from_handle(dh); + Reflex::Type tb = type_from_handle(bh); + return (int)td.HasBase(tb); +} + +size_t cppyy_base_offset(cppyy_typehandle_t dh, cppyy_typehandle_t bh) { + if (dh == bh) + return 0; + Reflex::Type td = type_from_handle(dh); + Reflex::Type tb = type_from_handle(bh); + return base_offset(td, tb); } @@ -265,34 +303,8 @@ if (s != m.DeclaringScope()) { // in case this data member is part of a base class, the offset is complicated - // when dealing with virtual inheritance and only (reasonably) well-defined with a - // Reflex internal base table, that contains all offsets within the full hierarchy - Reflex::Member getbases = s.FunctionMemberByName( - "__getBasesTable", Reflex::Type(), 0, Reflex::INHERITEDMEMBERS_NO, Reflex::DELAYEDLOAD_OFF); - if (getbases) { - typedef std::vector<std::pair<Reflex::Base, int> > Bases_t; - Bases_t* bases; - Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), &bases); - getbases.Invoke(&bases_holder); - - Reflex::Type d = m.DeclaringType(); - - for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); ++ibase) { - if (ibase->first.ToType() == d) { - if (d.IsVirtual()) { - Reflex::Type t = type_from_handle(handle); - Reflex::Object o = t.Construct(); - size_t offset = ibase->first.Offset(o.Address()) + m.Offset(); - o.Destruct(); - return offset; - } else - return ibase->first.Offset(0); - } - } - - // contrary to typical invoke()s, the result of the internal getbases function - // is a pointer to a function static, so no delete - } + // when dealing with virtual inheritance and needs to be calculated + return base_offset(s, m.DeclaringType()) + m.Offset(); } return m.Offset(); 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,8 @@ <class name="c_class_2" /> <class name="d_class" /> + <function pattern="get_*" /> + <class pattern="T1<*>" /> <class pattern="T2<*>" /> <class pattern="T3<*>" /> 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 @@ -23,7 +23,7 @@ import cppyy return cppyy.load_lib(%r)""" % (shared_lib, )) - def test01_default_argeumetns(self): + def test01_default_arguments(self): """Test usage of default arguments""" import cppyy @@ -277,3 +277,36 @@ # assert d.get_value() == 44 d.destruct() + + def test07_pass_by_reference(self): + """Test reference passing when using virtual inheritance""" + + import cppyy + gbl = cppyy.gbl + b_class = gbl.b_class + c_class = gbl.c_class_2 + d_class = gbl.d_class + + #----- + b = b_class() + b.m_a, b.m_b = 11, 22 + assert gbl.get_a(b) == 11 + assert gbl.get_b(b) == 22 + b.destruct() + + #----- + c = c_class() + c.m_a, c.m_b, c.m_c = 11, 22, 33 + assert gbl.get_a(c) == 11 + assert gbl.get_b(c) == 22 + assert gbl.get_c(c) == 33 + c.destruct() + + #----- + d = d_class() + d.m_a, d.m_b, d.m_c, d.m_d = 11, 22, 33, 44 + assert gbl.get_a(d) == 11 + assert gbl.get_b(d) == 22 + assert gbl.get_c(d) == 33 + assert gbl.get_d(d) == 44 + d.destruct() _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit