[pypy-commit] pypy reflex-support: initial attempt at having dynamic return types
wlav
noreply at buildbot.pypy.org
Wed Mar 14 14:27:01 CET 2012
Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r53553:562d9b039b46
Date: 2012-03-14 02:24 -0700
http://bitbucket.org/pypy/pypy/changeset/562d9b039b46/
Log: initial attempt at having dynamic return types
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
@@ -45,6 +45,10 @@
"cppyy_get_template",
[rffi.CCHARP], C_TYPE,
compilation_info=backend.eci)
+c_get_object_type = rffi.llexternal(
+ "cppyy_get_object_type",
+ [C_TYPE, C_OBJECT], C_TYPE,
+ compilation_info=backend.eci)
# memory management ----------------------------------------------------------
c_allocate = rffi.llexternal(
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
@@ -17,6 +17,7 @@
char* cppyy_resolve_name(const char* cppitem_name);
cppyy_scope_t cppyy_get_scope(const char* scope_name);
cppyy_type_t cppyy_get_template(const char* template_name);
+ cppyy_type_t cppyy_get_object_type(cppyy_type_t klass, cppyy_object_t obj);
/* memory management ------------------------------------------------------ */
cppyy_object_t cppyy_allocate(cppyy_type_t type);
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
@@ -638,12 +638,20 @@
def new_instance(space, w_type, cpptype, rawobject, isref, python_owns):
- obj = memory_regulator.retrieve(rawobject)
- if obj and obj.cppclass == cpptype:
+ obj_actual = rawobject
+ actual = cpptype.handle
+ if rawobject:
+ actual = capi.c_get_object_type(cpptype.handle, rawobject)
+ if actual != cpptype.handle:
+ offset = capi.c_base_offset(actual, cpptype.handle, rawobject)
+ obj_actual = capi.direct_ptradd(rawobject, offset)
+ # TODO: fix-up w_type to be w_actual_type
+ obj = memory_regulator.retrieve(obj_actual)
+ if obj and obj.cppclass.handle == actual:# == cpptype:
return obj
w_cppinstance = space.allocate_instance(W_CPPInstance, w_type)
cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False)
- W_CPPInstance.__init__(cppinstance, space, cpptype, rawobject, isref, python_owns)
+ W_CPPInstance.__init__(cppinstance, space, cpptype, obj_actual, isref, python_owns)
memory_regulator.register(cppinstance)
return w_cppinstance
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
@@ -206,6 +206,15 @@
return (cppyy_type_t)sz;
}
+cppyy_type_t cppyy_get_object_type(cppyy_type_t klass, cppyy_object_t obj) {
+ TClassRef cr = type_from_handle(klass);
+ TClass* clActual = cr->GetActualClass( (void*)obj );
+ if (clActual && clActual != cr.GetClass()) {
+ // TODO: lookup through name should not be needed
+ return (cppyy_type_t)cppyy_get_scope(clActual->GetName());
+ }
+ return klass;
+}
/* memory management ------------------------------------------------------ */
cppyy_object_t cppyy_allocate(cppyy_type_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
@@ -70,6 +70,17 @@
return (cppyy_type_t)tt.Id();
}
+cppyy_type_t cppyy_get_object_type(cppyy_type_t klass, cppyy_object_t obj) {
+ Reflex::Type t = type_from_handle(klass);
+ Reflex::Type tActual = t.DynamicType(Reflex::Object(t, (void*)obj));
+ if (tActual && tActual != t) {
+ // TODO: lookup through name should not be needed (but tActual.Id()
+ // does not return a singular Id for the system :( )
+ return (cppyy_type_t)cppyy_get_scope(tActual.Name().c_str());
+ }
+ return klass;
+}
+
/* memory management ------------------------------------------------------ */
cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
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
@@ -19,6 +19,8 @@
virtual int get_value() { return m_b; }
double get_base_value() { return m_db; }
+ virtual base_class* cycle(base_class* b) { return b; }
+
public:
int m_b;
double m_db;
diff --git a/pypy/module/cppyy/test/example01.h b/pypy/module/cppyy/test/example01.h
--- a/pypy/module/cppyy/test/example01.h
+++ b/pypy/module/cppyy/test/example01.h
@@ -24,7 +24,7 @@
example01(int a);
example01(const example01& e);
example01& operator=(const example01& e);
- ~example01();
+ virtual ~example01();
public: // class-level methods
static int staticAddOneToInt(int a);
@@ -101,3 +101,9 @@
z_& gime_z_(z_& z);
int myint;
};
+
+// for pythonization checking
+class example01a : public example01 {
+public:
+ example01a(int a) : example01(a) {}
+};
diff --git a/pypy/module/cppyy/test/example01.xml b/pypy/module/cppyy/test/example01.xml
--- a/pypy/module/cppyy/test/example01.xml
+++ b/pypy/module/cppyy/test/example01.xml
@@ -3,6 +3,7 @@
<class name="payload" />
<class name="example01" />
<class name="example01_t" />
+ <class name="example01a" />
<class name="std::string" />
<class name="z_" />
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
@@ -406,3 +406,27 @@
assert m.get_multi1_int() == 1
assert m.get_multi2_int() == 2
assert m.get_my_own_int() == 3
+
+ def test12_actual_type(self):
+ """Test that a pointer to base return does an auto-downcast"""
+
+ import cppyy
+ base_class = cppyy.gbl.base_class
+ derived_class = cppyy.gbl.derived_class
+
+ b = base_class()
+ d = derived_class()
+
+ assert b == b.cycle(b)
+ assert id(b) == id(b.cycle(b))
+ assert b == d.cycle(b)
+ assert id(b) == id(d.cycle(b))
+ assert d == b.cycle(d)
+ assert id(d) == id(b.cycle(d))
+ assert d == d.cycle(d)
+ assert id(d) == id(d.cycle(d))
+
+ assert isinstance(b.cycle(b), base_class)
+ assert isinstance(d.cycle(b), base_class)
+ assert isinstance(b.cycle(d), derived_class)
+ assert isinstance(d.cycle(d), derived_class)
diff --git a/pypy/module/cppyy/test/test_pythonify.py b/pypy/module/cppyy/test/test_pythonify.py
--- a/pypy/module/cppyy/test/test_pythonify.py
+++ b/pypy/module/cppyy/test/test_pythonify.py
@@ -324,15 +324,15 @@
import cppyy
- def example01_pythonize(pyclass):
- assert pyclass.__name__ == 'example01'
+ def example01a_pythonize(pyclass):
+ assert pyclass.__name__ == 'example01a'
def getitem(self, idx):
return self.addDataToInt(idx)
pyclass.__getitem__ = getitem
- cppyy.add_pythonization('example01', example01_pythonize)
+ cppyy.add_pythonization('example01a', example01a_pythonize)
- e = cppyy.gbl.example01(1)
+ e = cppyy.gbl.example01a(1)
assert e[0] == 1
assert e[1] == 2
More information about the pypy-commit
mailing list