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