Author: Wim Lavrijsen <wlavrij...@lbl.gov>
Branch: reflex-support
Changeset: r54704:ad4fa188692f
Date: 2012-04-23 17:36 -0700
http://bitbucket.org/pypy/pypy/changeset/ad4fa188692f/

Log:    better auto-casting support (Reflex only)

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
@@ -243,15 +243,15 @@
 
 _c_base_offset = rffi.llexternal(
     "cppyy_base_offset",
-    [C_TYPE, C_TYPE, C_OBJECT], rffi.SIZE_T,
+    [C_TYPE, C_TYPE, C_OBJECT, rffi.INT], rffi.LONG,
     threadsafe=threadsafe,
     compilation_info=backend.eci,
     elidable_function=True)
 @jit.elidable_promote()
-def c_base_offset(derived, base, address):
+def c_base_offset(derived, base, address, direction):
     if derived == base:
         return 0
-    return _c_base_offset(derived.handle, base.handle, address)
+    return _c_base_offset(derived.handle, base.handle, address, direction)
 
 # method/function reflection information -------------------------------------
 _c_num_methods = rffi.llexternal(
diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py
--- a/pypy/module/cppyy/converter.py
+++ b/pypy/module/cppyy/converter.py
@@ -584,7 +584,7 @@
         if isinstance(obj, W_CPPInstance):
             if capi.c_is_subtype(obj.cppclass, self.cppclass):
                 rawobject = obj.get_rawobject()
-                offset = capi.c_base_offset(obj.cppclass, self.cppclass, 
rawobject)
+                offset = capi.c_base_offset(obj.cppclass, self.cppclass, 
rawobject, 1)
                 obj_address = capi.direct_ptradd(rawobject, offset)
                 return rffi.cast(capi.C_OBJECT, obj_address)
         raise OperationError(space.w_TypeError,
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
@@ -59,7 +59,9 @@
     int cppyy_num_bases(cppyy_type_t type);
     char* cppyy_base_name(cppyy_type_t type, int base_index);
     int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base);
-    size_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, 
cppyy_object_t address);
+
+    /* calculate offsets between declared and actual type, up-cast: direction 
> 0; down-cast: direction < 0 */
+    long cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, 
cppyy_object_t address, int direction);
 
     /* method/function reflection information 
--------------------------------- */
     int cppyy_num_methods(cppyy_scope_t scope);
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
@@ -354,7 +354,7 @@
         if cppinstance:
             assert lltype.typeOf(cppinstance.cppclass.handle) == 
lltype.typeOf(self.scope.handle)
             offset = self.offset + capi.c_base_offset(
-                cppinstance.cppclass, self.scope, cppinstance.get_rawobject())
+                cppinstance.cppclass, self.scope, cppinstance.get_rawobject(), 
1)
         else:
             offset = self.offset
         return offset
@@ -594,7 +594,7 @@
 
     def get_cppthis(self, cppinstance, calling_scope):
         assert self == cppinstance.cppclass
-        offset = capi.c_base_offset(self, calling_scope, 
cppinstance.get_rawobject())
+        offset = capi.c_base_offset(self, calling_scope, 
cppinstance.get_rawobject(), 1)
         return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
 
 W_ComplexCPPClass.typedef = TypeDef(
@@ -749,7 +749,7 @@
     if rawobject:
         actual = capi.c_actual_class(cppclass, rawobject)
         if actual != cppclass.handle:
-            offset = capi._c_base_offset(actual, cppclass.handle, rawobject)
+            offset = capi._c_base_offset(actual, cppclass.handle, rawobject, 
-1)
             rawobject = capi.direct_ptradd(rawobject, offset)
             w_pycppclass = get_pythonized_cppclass(space, actual)
             w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
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
@@ -467,11 +467,13 @@
     return derived_type->GetBaseClass(base_type) != 0;
 }
 
-size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t 
base_handle, cppyy_object_t address) {
+long cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
+                       cppyy_object_t address, int /* direction */) {
+    // WARNING: CINT can not handle actual dynamic casts!
     TClassRef derived_type = type_from_handle(derived_handle);
     TClassRef base_type = type_from_handle(base_handle);
 
-    size_t offset = 0;
+    long offset = 0;
 
     if (derived_type && base_type) {
         G__ClassInfo* base_ci    = (G__ClassInfo*)base_type->GetClassInfo();
@@ -483,18 +485,15 @@
             // with CINT's (or Reflex's) interfaces.
             long baseprop = derived_ci->IsBase(*base_ci);
             if (!baseprop || (baseprop & G__BIT_ISVIRTUALBASE))
-                offset = (size_t)derived_type->GetBaseClassOffset(base_type);
+                offset = derived_type->GetBaseClassOffset(base_type);
             else
 #endif
                 offset = G__isanybase(base_ci->Tagnum(), derived_ci->Tagnum(), 
(long)address);
          } else {
-             offset = (size_t)derived_type->GetBaseClassOffset(base_type);
+             offset = derived_type->GetBaseClassOffset(base_type);
          }
     }
 
-    if (offset < 0)      // error return of G__isanybase()
-        return 0;
-
     return offset;
 }
 
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
@@ -277,7 +277,8 @@
     return (int)derived_type.HasBase(base_type);
 }
 
-size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t 
base_handle, cppyy_object_t address) {
+long cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
+                       cppyy_object_t address, int direction) {
     Reflex::Type derived_type = type_from_handle(derived_handle);
     Reflex::Type base_type = type_from_handle(base_handle);
 
@@ -291,9 +292,20 @@
         Reflex::Object bases_holder(Reflex::Type::ByTypeInfo(typeid(Bases_t)), 
&bases);
         getbases.Invoke(&bases_holder);
 
+        // if direction is down-cast, perform the cast in C++ first in order 
to ensure
+        // we have a derived object for accessing internal offset pointers
+        if (direction < 0) {
+           Reflex::Object o(base_type, (void*)address);
+           address = (cppyy_object_t)o.CastObject(derived_type).Address();
+        }
+
         for (Bases_t::iterator ibase = bases->begin(); ibase != bases->end(); 
++ibase) {
-            if (ibase->first.ToType() == base_type)
-                return (size_t)ibase->first.Offset((void*)address);
+            if (ibase->first.ToType() == base_type) {
+                long offset = (long)ibase->first.Offset((void*)address);
+                if (direction < 0)
+                    return -offset;
+                return offset;
+            }
         }
 
         // contrary to typical invoke()s, the result of the internal getbases 
function
diff --git a/pypy/module/cppyy/test/advancedcpp.cxx 
b/pypy/module/cppyy/test/advancedcpp.cxx
--- a/pypy/module/cppyy/test/advancedcpp.cxx
+++ b/pypy/module/cppyy/test/advancedcpp.cxx
@@ -10,6 +10,9 @@
 
 
 // for esoteric inheritance testing
+a_class* create_c1() { return new c_class_1; }
+a_class* create_c2() { return new c_class_2; }
+
 int get_a( a_class& a ) { return a.m_a; }
 int get_b( b_class& b ) { return b.m_b; }
 int get_c( c_class& c ) { return c.m_c; }
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
@@ -91,6 +91,9 @@
    int m_d;
 };
 
+a_class* create_c1();
+a_class* create_c2();
+
 int get_a(a_class& a);
 int get_b(b_class& b);
 int get_c(c_class& c);
diff --git a/pypy/module/cppyy/test/advancedcpp.xml 
b/pypy/module/cppyy/test/advancedcpp.xml
--- a/pypy/module/cppyy/test/advancedcpp.xml
+++ b/pypy/module/cppyy/test/advancedcpp.xml
@@ -12,6 +12,7 @@
   <class name="c_class_2" />
   <class name="d_class" />
 
+  <function pattern="create_*" />
   <function pattern="get_*" />
 
   <class pattern="T1<*>" />
diff --git a/pypy/module/cppyy/test/advancedcpp_LinkDef.h 
b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
--- a/pypy/module/cppyy/test/advancedcpp_LinkDef.h
+++ b/pypy/module/cppyy/test/advancedcpp_LinkDef.h
@@ -16,6 +16,9 @@
 #pragma link C++ class c_class_2;
 #pragma link C++ class d_class;
 
+#pragma link C++ function create_c1();
+#pragma link C++ function create_c2();
+
 #pragma link C++ function get_a(a_class&);
 #pragma link C++ function get_b(b_class&);
 #pragma link C++ function get_c(c_class&);
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
@@ -1,6 +1,8 @@
 import py, os, sys
 from pypy.conftest import gettestobjspace
 
+from pypy.module.cppyy import capi
+
 
 currpath = py.path.local(__file__).dirpath()
 test_dct = str(currpath.join("advancedcppDict.so"))
@@ -20,6 +22,7 @@
         cls.space = space
         env = os.environ
         cls.w_test_dct = space.wrap(test_dct)
+        cls.w_capi_identity = space.wrap(capi.identify())
         cls.w_advanced = cls.space.appexec([], """():
             import cppyy
             return cppyy.load_reflection_info(%r)""" % (test_dct, ))
@@ -466,3 +469,22 @@
 
         assert isinstance(b.clone(), base_class)      # TODO: clone() leaks
         assert isinstance(d.clone(), derived_class)   # TODO: clone() leaks
+
+    def test13_actual_type_virtual_multi(self):
+        """Test auto-downcast in adverse inheritance situation"""
+
+        import cppyy
+
+        c1 = cppyy.gbl.create_c1()
+        assert type(c1) == cppyy.gbl.c_class_1
+        assert c1.m_c == 3
+        c1.destruct()
+
+        if self.capi_identity == 'CINT':     # CINT does not support dynamic 
casts
+            return
+
+        c2 = cppyy.gbl.create_c2()
+        assert type(c2) == cppyy.gbl.c_class_2
+        print c2.m_c
+        assert c2.m_c == 3
+        c2.destruct()
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to