[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