diff --git a/extclass.cpp b/extclass.cpp index a4f723ae..c8af3a4a 100644 --- a/extclass.cpp +++ b/extclass.cpp @@ -220,35 +220,35 @@ ExtensionClassBase::ExtensionClassBase(const char* name) void * ExtensionClassBase::try_class_conversions(InstanceHolderBase * object) const { - void * result = try_sub_class_conversions(object); + void * result = try_subclass_conversions(object); if(result) return result; - result = try_super_class_conversions(object); + result = try_superclass_conversions(object); return result; } -void * ExtensionClassBase::try_super_class_conversions(InstanceHolderBase * object) const +void * ExtensionClassBase::try_superclass_conversions(InstanceHolderBase * object) const { void * result = 0; for(int i=0; iconvert_from_holder(object); - if(result) return (*base_classes()[i].second)(result); - result = base_classes()[i].first->try_super_class_conversions(object); - if(result) return (*base_classes()[i].second)(result); + if(base_classes()[i].convert == 0) continue; + result = base_classes()[i].class_object->convert_from_holder(object); + if(result) return (*base_classes()[i].convert)(result); + result = base_classes()[i].class_object->try_superclass_conversions(object); + if(result) return (*base_classes()[i].convert)(result); } return 0; } -void * ExtensionClassBase::try_sub_class_conversions(InstanceHolderBase * object) const +void * ExtensionClassBase::try_subclass_conversions(InstanceHolderBase * object) const { void * result = 0; for(int i=0; iconvert_from_holder(object); - if(result) return (*sub_classes()[i].second)(result); - result = sub_classes()[i].first->try_sub_class_conversions(object); - if(result) return (*sub_classes()[i].second)(result); + result = sub_classes()[i].class_object->convert_from_holder(object); + if(result) return (*sub_classes()[i].convert)(result); + result = sub_classes()[i].class_object->try_subclass_conversions(object); + if(result) return (*sub_classes()[i].convert)(result); } return 0; } diff --git a/extclass.h b/extclass.h index fb96955d..48017f78 100644 --- a/extclass.h +++ b/extclass.h @@ -53,8 +53,17 @@ T* check_non_null(T* p) template class HeldInstance; typedef void * (*ConversionFct)(void *); -typedef std::pair BaseClassInfo; -typedef std::pair SubClassInfo; + +struct BaseClassInfo +{ + BaseClassInfo(TypeObjectBase * t, ConversionFct f) + :class_object(t), convert(f) + {} + + TypeObjectBase *class_object; + ConversionFct convert; +}; +typedef BaseClassInfo SubClassInfo; class ExtensionClassBase : public Class { @@ -71,8 +80,8 @@ class ExtensionClassBase : public Class void add_getter_method(Function*, const char* name); virtual void * try_class_conversions(InstanceHolderBase*) const; - virtual void * try_super_class_conversions(InstanceHolderBase*) const; - virtual void * try_sub_class_conversions(InstanceHolderBase*) const; + virtual void * try_superclass_conversions(InstanceHolderBase*) const; + virtual void * try_subclass_conversions(InstanceHolderBase*) const; virtual std::vector const & base_classes() const = 0; virtual std::vector const & sub_classes() const = 0; }; diff --git a/extclass_demo.cpp b/extclass_demo.cpp index 6ea54f5e..4ce70904 100644 --- a/extclass_demo.cpp +++ b/extclass_demo.cpp @@ -363,10 +363,9 @@ static int getX(OverloadTest * u) return u->x(); } - /************************************************************/ /* */ -/* classes to test base declarations snd conversions */ +/* classes to test base declarations and conversions */ /* */ /************************************************************/ @@ -425,6 +424,57 @@ static int testDowncast2(Derived2 * d) return d->x(); } +/************************************************************/ +/* */ +/* test classes for interaction of overloading, */ +/* base declarations, and callbacks */ +/* */ +/************************************************************/ + +struct CallbackTestBase +{ + virtual int testCallback(int i) { return callback(i); } + virtual int callback(int i) = 0; +}; + +struct CallbackTest : public CallbackTestBase +{ + virtual int callback(int i) { return i + 1; } + virtual std::string callbackString(std::string const & i) { return i + " 1"; } +}; + +struct CallbackTestCallback : public CallbackTest +{ + CallbackTestCallback(PyObject* self) + : m_self(self) + {} + + int callback(int x) + { + return py::Callback::call_method(m_self, "callback", x); + } + std::string callbackString(std::string const & x) + { + return py::Callback::call_method(m_self, "callback", x); + } + + static int default_callback(CallbackTest * self, int x) + { + return self->CallbackTest::callback(x); + } + static std::string default_callbackString(CallbackTest * self, std::string x) + { + return self->CallbackTest::callbackString(x); + } + + PyObject * m_self; +}; + +int testCallback(CallbackTestBase * b, int i) +{ + return b->testCallback(i); +} + /************************************************************/ /* */ /* init the module */ @@ -472,7 +522,7 @@ void init_module(py::Module& m) m.def(&test5, "overloaded"); py::ClassWrapper over(m, "OverloadTest"); - over.def(py::Constructor<>()); + over.def(py::Constructor()); over.def(py::Constructor()); over.def(py::Constructor()); over.def(py::Constructor()); @@ -507,6 +557,19 @@ void init_module(py::Module& m) m.def(&derived2Factory, "derived2Factory"); m.def(&testDowncast1, "testDowncast1"); m.def(&testDowncast2, "testDowncast2"); + + py::ClassWrapper callbackTestBase(m, "CallbackTestBase"); + callbackTestBase.def(&CallbackTestBase::testCallback, "testCallback"); + m.def(&testCallback, "testCallback"); + + py::ClassWrapper callbackTest(m, "CallbackTest"); + callbackTest.def(py::Constructor()); + callbackTest.def(&CallbackTest::callback, "callback", + &CallbackTestCallback::default_callback); + callbackTest.def(&CallbackTest::callbackString, "callback", + &CallbackTestCallback::default_callbackString); + + callbackTest.declare_base(callbackTestBase); } void init_module() diff --git a/newtypes.h b/newtypes.h index 51a27e9d..083ffbc7 100644 --- a/newtypes.h +++ b/newtypes.h @@ -62,8 +62,8 @@ class TypeObjectBase : public PythonType virtual int instance_setattr(PyObject* instance, const char* name, PyObject* value) const; virtual void * try_class_conversions(InstanceHolderBase*) const { return 0; } - virtual void * try_super_class_conversions(InstanceHolderBase*) const { return 0; } - virtual void * try_sub_class_conversions(InstanceHolderBase*) const { return 0; } + virtual void * try_superclass_conversions(InstanceHolderBase*) const { return 0; } + virtual void * try_subclass_conversions(InstanceHolderBase*) const { return 0; } virtual void * convert_from_holder(InstanceHolderBase*) const { return 0; } // Dealloc is a special case, since every type needs a nonzero tp_dealloc slot. diff --git a/test_extclass.py b/test_extclass.py index 8a0c06f0..1ef74a7c 100644 --- a/test_extclass.py +++ b/test_extclass.py @@ -512,6 +512,46 @@ Testing base class conversions >>> testDowncast2(der1) Traceback (innermost last): TypeError: extension class 'Base' is not convertible into 'Derived2'. + +Testing interaction between callbacks, base declarations, and overloading +- testCallback() calls callback() (within C++) +- callback() is overloaded (in the wrapped class CallbackTest) +- callback() is redefined in RedefineCallback (overloading is simulated by type casing) +- testCallback() should use the redefined callback() + + >>> c = CallbackTest() + >>> c.testCallback(1) + 2 + >>> c.testCallback('foo') + Traceback (innermost last): + File "", line 1, in ? + TypeError: illegal argument type for built-in operation + >>> c.callback(1) + 2 + >>> c.callback('foo') + 'foo 1' + + >>> import types + >>> class RedefineCallback(CallbackTest): + ... def callback(self, x): + ... if type(x) is types.IntType: + ... return x - 2 + ... else: + ... return CallbackTest.callback(self,x) + ... + >>> r = RedefineCallback() + >>> r.callback(1) + -1 + >>> r.callback('foo') + 'foo 1' + >>> r.testCallback('foo') + Traceback (innermost last): + File "", line 1, in ? + TypeError: illegal argument type for built-in operation + >>> r.testCallback(1) + -1 + >>> testCallback(r, 1) + -1 ''' from demo import *