Author: Wim Lavrijsen <[email protected]>
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
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit