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

Reply via email to