Author: Wim Lavrijsen <wlavrij...@lbl.gov> Branch: reflex-support Changeset: r45153:af6a2914198f Date: 2011-06-27 16:15 -0700 http://bitbucket.org/pypy/pypy/changeset/af6a2914198f/
Log: support for virtually inherited data members diff --git a/pypy/module/cppyy/pythonify.py b/pypy/module/cppyy/pythonify.py --- a/pypy/module/cppyy/pythonify.py +++ b/pypy/module/cppyy/pythonify.py @@ -108,20 +108,30 @@ _existing_cppitems[namespace_name] = pycppns return pycppns + +def _drop_cycles(bases): + # TODO: figure this out, as it seems to be a PyPy bug?! + for b1 in bases: + for b2 in bases: + if not (b1 is b2) and issubclass(b2, b1): + bases.remove(b1) # removes lateral class + break + return tuple(bases) + def make_cppclass(class_name, cpptype): # get a list of base classes for class creation - bases = tuple([get_cppclass(base) for base in cpptype.get_base_names()]) + bases = [get_cppclass(base) for base in cpptype.get_base_names()] if not bases: - bases = (CppyyObject,) + bases = [CppyyObject,] # create a meta class to allow properties (for static data write access) - metabases = tuple([type(base) for base in bases]) - metacpp = type(CppyyClass)(class_name+'_meta', metabases, {}) + metabases = [type(base) for base in bases] + metacpp = type(CppyyClass)(class_name+'_meta', _drop_cycles(metabases), {}) # create the python-side C++ class representation d = {"_cppyyclass" : cpptype} - pycpptype = metacpp(class_name, bases, d) + pycpptype = metacpp(class_name, _drop_cycles(bases), d) # cache result early so that the class methods can find the class itself _existing_cppitems[class_name] = pycpptype 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 @@ -2,6 +2,7 @@ #include "reflexcwrapper.h" #include <iostream> #include <string> +#include <utility> #include <vector> @@ -120,8 +121,7 @@ return 0; } -cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_typehandle_t handle, int method_index) -{ +cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_typehandle_t handle, int method_index) { Reflex::Scope s = scope_from_handle(handle); Reflex::Member m = s.FunctionMemberAt(method_index); return get_methptr_getter(m); @@ -219,33 +219,69 @@ /* data member reflection information ------------------------------------- */ int cppyy_num_data_members(cppyy_typehandle_t handle) { Reflex::Scope s = scope_from_handle(handle); - return s.DataMemberSize(); + return s.DataMemberSize(Reflex::INHERITEDMEMBERS_ALSO); } char* cppyy_data_member_name(cppyy_typehandle_t handle, int data_member_index) { Reflex::Scope s = scope_from_handle(handle); - Reflex::Member m = s.DataMemberAt(data_member_index); + Reflex::Member m = s.DataMemberAt(data_member_index, Reflex::INHERITEDMEMBERS_ALSO); std::string name = m.Name(); return cppstring_to_cstring(name); } char* cppyy_data_member_type(cppyy_typehandle_t handle, int data_member_index) { Reflex::Scope s = scope_from_handle(handle); - Reflex::Member m = s.DataMemberAt(data_member_index); + Reflex::Member m = s.DataMemberAt(data_member_index, Reflex::INHERITEDMEMBERS_ALSO); std::string name = m.TypeOf().Name(Reflex::FINAL|Reflex::SCOPED|Reflex::QUALIFIED); return cppstring_to_cstring(name); } +static void* fgFakeObject = 0; +static void* fgFakeAddress = &fgFakeObject; + size_t cppyy_data_member_offset(cppyy_typehandle_t handle, int data_member_index) { Reflex::Scope s = scope_from_handle(handle); - Reflex::Member m = s.DataMemberAt(data_member_index); + Reflex::Member m = s.DataMemberAt(data_member_index, Reflex::INHERITEDMEMBERS_ALSO); + + 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 + } + } + return m.Offset(); } int cppyy_is_staticdata(cppyy_typehandle_t handle, int data_member_index) { Reflex::Scope s = scope_from_handle(handle); - Reflex::Member m = s.DataMemberAt(data_member_index); + Reflex::Member m = s.DataMemberAt(data_member_index, Reflex::INHERITEDMEMBERS_ALSO); return m.IsStatic(); } 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_simple_inheritence(self): + def test01_simple_inheritance(self): """Test binding of a basic inheritance structure""" import cppyy @@ -37,16 +37,43 @@ assert isinstance(b, base_class) assert not isinstance(b, derived_class) + assert b.m_b == 1 assert b.get_value() == 1 + assert b.m_db == 1.1 assert b.get_base_value() == 1.1 + b.m_b, b.m_db = 11, 11.11 + assert b.m_b == 11 + assert b.get_value() == 11 + assert b.m_db == 11.11 + assert b.get_base_value() == 11.11 + + b.destruct() + d = derived_class() assert isinstance(d, derived_class) assert isinstance(d, base_class) + assert d.m_d == 2 assert d.get_value() == 2 + assert d.m_dd == 2.2 + assert d.get_derived_value() == 2.2 + + assert d.m_b == 1 + assert d.m_db == 1.1 assert d.get_base_value() == 1.1 - assert d.get_derived_value() == 2.2 + + d.m_b, d.m_db = 11, 11.11 + d.m_d, d.m_dd = 22, 22.22 + + assert d.m_d == 22 + assert d.get_value() == 22 + assert d.m_dd == 22.22 + assert d.get_derived_value() == 22.22 + + assert d.m_b == 11 + assert d.m_db == 11.11 + assert d.get_base_value() == 11.11 d.destruct() @@ -112,11 +139,111 @@ assert t1.value() == 111 t1.destruct() - def test04_instantiation(self): + def test04_abstract_classes(self): """Test non-instatiatability of abstract classes""" import cppyy - - raises(TypeError, cppyy.gbl.a_class) - raises(TypeError, cppyy.gbl.some_abstract_class) + gbl = cppyy.gbl + raises(TypeError, gbl.a_class) + raises(TypeError, gbl.some_abstract_class) + + assert issubclass(gbl.some_concrete_class, gbl.some_abstract_class) + + c = gbl.some_concrete_class() + assert isinstance(c, gbl.some_concrete_class) + assert isinstance(c, gbl.some_abstract_class) + + def test05_data_members(self): + """Test data member access when using virtual inheritence""" + + import cppyy + a_class = cppyy.gbl.a_class + b_class = cppyy.gbl.b_class + c_class_1 = cppyy.gbl.c_class_1 + c_class_2 = cppyy.gbl.c_class_2 + d_class = cppyy.gbl.d_class + + assert issubclass(b_class, a_class) + assert issubclass(c_class_1, a_class) + assert issubclass(c_class_1, b_class) + assert issubclass(c_class_2, a_class) + assert issubclass(c_class_2, b_class) + assert issubclass(d_class, a_class) + assert issubclass(d_class, b_class) + assert issubclass(d_class, c_class_2) + + #----- + b = b_class() + assert b.m_a == 1 + assert b.m_da == 1.1 + assert b.m_b == 2 + assert b.m_db == 2.2 + + b.m_a = 11 + assert b.m_a == 11 + assert b.m_b == 2 + + b.m_da = 11.11 + assert b.m_da == 11.11 + assert b.m_db == 2.2 + + b.m_b = 22 + assert b.m_a == 11 + assert b.m_da == 11.11 + assert b.m_b == 22 + # assert b.get_value() == 22 + + b.m_db = 22.22 + assert b.m_db == 22.22 + + b.destruct() + + #----- + c1 = c_class_1() + assert c1.m_a == 1 + assert c1.m_b == 2 + assert c1.m_c == 3 + + c1.m_a = 11 + assert c1.m_a == 11 + + c1.m_b = 22 + assert c1.m_a == 11 + assert c1.m_b == 22 + + c1.m_c = 33 + assert c1.m_a == 11 + assert c1.m_b == 22 + assert c1.m_c == 33 + # assert c1.get_value() == 33 + + c1.destruct() + + #----- + d = d_class() + assert d.m_a == 1 + assert d.m_b == 2 + assert d.m_c == 3 + assert d.m_d == 4 + + d.m_a = 11 + assert d.m_a == 11 + + d.m_b = 22 + assert d.m_a == 11 + assert d.m_b == 22 + + d.m_c = 33 + assert d.m_a == 11 + assert d.m_b == 22 + assert d.m_c == 33 + + d.m_d = 44 + assert d.m_a == 11 + assert d.m_b == 22 + assert d.m_c == 33 + assert d.m_d == 44 + # assert d.get_value() == 44 + + d.destruct() _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit