From 0ce8ab7bcec74ee7f0ed19079e511445dfe18099 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 24 Mar 2002 14:52:30 +0000 Subject: [PATCH] Full virtual function and abstract base support; new class interface. [SVN r13253] --- include/boost/python/class.hpp | 190 +++++++++++------- include/boost/python/class_fwd.hpp | 7 +- .../boost/python/detail/arg_tuple_size.hpp | 2 +- include/boost/python/detail/msvc_typeinfo.hpp | 31 +-- include/boost/python/make_function.hpp | 6 +- .../boost/python/object/class_converters.hpp | 25 +-- include/boost/python/object/class_wrapper.hpp | 11 +- include/boost/python/object/find_instance.hpp | 3 + include/boost/python/object/make_holder.hpp | 36 ++-- .../boost/python/object/pointer_holder.hpp | 142 +++++-------- include/boost/python/object/select_holder.hpp | 70 +++++++ include/boost/python/object/value_holder.hpp | 23 +-- test/Jamfile | 15 ++ test/m1.cpp | 13 +- test/select_holder.cpp | 77 +++++++ test/virtual_functions.cpp | 14 +- test/virtual_functions.py | 70 +++---- 17 files changed, 430 insertions(+), 305 deletions(-) create mode 100644 include/boost/python/object/select_holder.hpp create mode 100644 test/select_holder.cpp diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index 0a9c5d87..cff0adf9 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -7,55 +7,50 @@ # define CLASS_DWA200216_HPP # include +# include +# include # include # include -# include # include # include # include -# include # include +# include +# include # include # include -# include - -namespace // put some convenience classes into the unnamed namespace for the user -{ - // A type list for specifying bases - template < BOOST_MPL_LIST_DEFAULT_PARAMETERS(typename B, ::boost::mpl::null_argument) > - struct bases : ::boost::mpl::type_list< BOOST_MPL_LIST_PARAMETERS(B) >::type - {}; - - // A type list for specifying arguments - template < BOOST_MPL_LIST_DEFAULT_PARAMETERS(typename A, ::boost::mpl::null_argument) > - struct args : ::boost::mpl::type_list< BOOST_MPL_LIST_PARAMETERS(A) >::type - {}; -} +# include +# include +# include +# include namespace boost { namespace python { namespace detail { - // This is an mpl BinaryMetaFunction object with a runtime behavior, - // which is to write the id of the type which is passed as its 2nd - // compile-time argument into the iterator pointed to by its runtime - // argument - struct write_type_id - { - // The first argument is Ignored because mpl::for_each is still - // currently an accumulate (reduce) implementation. - template struct apply - { - // also an artifact of accumulate-based for_each - typedef void type; + struct write_type_id; + + template + struct select_held_type; + + template + struct has_noncopyable; - // Here's the runtime behavior - static void execute(converter::undecorated_type_id_t** p) - { - *(*p)++ = converter::undecorated_type_id(); - } - }; - }; + // Register a to_python converter for a class T, depending on the + // type of the first (tag) argument. The 2nd argument is a pointer + // to the type of holder that must be created. The 3rd argument is a + // reference to the Python type object to be created. + template + static inline void register_copy_constructor(mpl::bool_t const&, Holder*, ref const& obj, T* = 0) + { + objects::class_wrapper x(obj); + } + + // Tag dispatched to have no effect. + template + static inline void register_copy_constructor(mpl::bool_t const&, Holder*, ref const&, T* = 0) + { + } } // @@ -64,27 +59,24 @@ namespace detail // This is the primary mechanism through which users will expose // C++ classes to Python. The three template arguments are: // -// T - The class being exposed to Python -// -// Bases - An MPL sequence of base classes -// -// HolderGenerator - -// An optional type generator for the "holder" which -// maintains the C++ object inside the Python instance. The -// default just holds the object "by-value", but other -// holders can be substituted which will hold the C++ object -// by smart pointer, for example. -// template < class T // class being wrapped - , class Bases - , class HolderGenerator + , class X1 // = detail::not_specified + , class X2 // = detail::not_specified + , class X3 // = detail::not_specified > class class_ : private objects::class_base { - typedef class_ self; + typedef class_ self; + BOOST_STATIC_CONSTANT(bool, is_copyable = (!detail::has_noncopyable::value)); + + typedef typename detail::select_held_type< + X1, typename detail::select_held_type< + X2, typename detail::select_held_type< + X3 + >::type>::type>::type held_type; + public: - // Automatically derive the class name - only works on some // compilers because type_info::name is sometimes mangled (gcc) class_(); @@ -130,7 +122,12 @@ class class_ : private objects::class_base template self& def_init(Args const&) { - def("__init__", make_constructor()); + def("__init__", + make_constructor( + // Using runtime type selection works around a CWPro7 bug. + objects::select_holder((held_type*)0).get() + ) + ); return *this; } @@ -147,6 +144,12 @@ class class_ : private objects::class_base private: // types typedef objects::class_id class_id; + typedef typename detail::select_bases::type + >::type + >::type bases; + // A helper class which will contain an array of id objects to be // passed to the base class constructor struct id_vector @@ -159,50 +162,97 @@ class class_ : private objects::class_base // Write the rest of the elements into succeeding positions. class_id* p = ids + 1; - mpl::for_each::execute(&p); + mpl::for_each::execute(&p); } BOOST_STATIC_CONSTANT( - std::size_t, size = mpl::size::value + 1); + std::size_t, size = mpl::size::value + 1); class_id ids[size]; }; - - private: // helper functions - void initialize_converters(); }; // // implementations // -template -inline class_::class_() +template +inline class_::class_() : class_base(typeid(T).name(), id_vector::size, id_vector().ids) { - // Bring the class converters into existence. This static object - // will survive until the shared library this module lives in is - // unloaded (that doesn't happen until Python terminates). - static objects::class_converters converters(object()); + // register converters + objects::register_class_from_python(); + + detail::register_copy_constructor( + mpl::bool_t() + , objects::select_holder((held_type*)0).get() + , this->object()); } -template -inline class_::class_(char const* name) +template +inline class_::class_(char const* name) : class_base(name, id_vector::size, id_vector().ids) { - // Bring the class converters into existence. This static object - // will survive until the shared library this module lives in is - // unloaded (that doesn't happen until Python terminates). - static objects::class_converters converters(object()); + // register converters + objects::register_class_from_python(); + + detail::register_copy_constructor( + mpl::bool_t() + , objects::select_holder((held_type*)0).get() + , this->object()); } -template -inline ref class_::object() const +template +inline ref class_::object() const { typedef objects::class_base base; return this->base::object(); } +namespace detail +{ + // This is an mpl BinaryMetaFunction object with a runtime behavior, + // which is to write the id of the type which is passed as its 2nd + // compile-time argument into the iterator pointed to by its runtime + // argument + struct write_type_id + { + // The first argument is Ignored because mpl::for_each is still + // currently an accumulate (reduce) implementation. + template struct apply + { + // also an artifact of accumulate-based for_each + typedef void type; + + // Here's the runtime behavior + static void execute(converter::undecorated_type_id_t** p) + { + *(*p)++ = converter::undecorated_type_id(); + } + }; + }; + + + template + struct has_noncopyable + : type_traits::ice_or< + is_same::value + , is_same::value + , is_same::value> + {}; + + + template + struct select_held_type + : mpl::select_type< + !(specifies_bases::value | is_same::value) + , T + , Prev + > + { + }; +} + }} // namespace boost::python #endif // CLASS_DWA200216_HPP diff --git a/include/boost/python/class_fwd.hpp b/include/boost/python/class_fwd.hpp index bef2e250..1ef941aa 100644 --- a/include/boost/python/class_fwd.hpp +++ b/include/boost/python/class_fwd.hpp @@ -5,7 +5,7 @@ // to its suitability for any purpose. #ifndef CLASS_FWD_DWA200222_HPP # define CLASS_FWD_DWA200222_HPP -# include +# include namespace boost { namespace python { @@ -16,8 +16,9 @@ namespace detail template < class T // class being wrapped - , class Bases = detail::empty_list - , class HolderGenerator = objects::value_holder_generator<> + , class X1 = detail::not_specified + , class X2 = detail::not_specified + , class X3 = detail::not_specified > class class_; diff --git a/include/boost/python/detail/arg_tuple_size.hpp b/include/boost/python/detail/arg_tuple_size.hpp index 04bca0af..fa38a4a9 100644 --- a/include/boost/python/detail/arg_tuple_size.hpp +++ b/include/boost/python/detail/arg_tuple_size.hpp @@ -103,7 +103,7 @@ struct arg_tuple_size // Metrowerks thinks this creates ambiguities -# if !defined(__MWERKS__) || __MWERKS__ > 0x2406 +# if !defined(__MWERKS__) || __MWERKS__ > 0x2407 template struct arg_tuple_size diff --git a/include/boost/python/detail/msvc_typeinfo.hpp b/include/boost/python/detail/msvc_typeinfo.hpp index 2473023a..3da411f0 100644 --- a/include/boost/python/detail/msvc_typeinfo.hpp +++ b/include/boost/python/detail/msvc_typeinfo.hpp @@ -8,7 +8,8 @@ #include #include - +#include +#include // // Fix for MSVC's broken typeid() implementation which doesn't strip // decoration. This fix doesn't handle cv-qualified array types. It @@ -62,35 +63,35 @@ inline typeinfo typeid_nonref(boost::type* = 0) } template -inline typeinfo typeid_ref(boost::type*, ...) -{ - return typeid_nonref(); -} - -template -inline typeinfo typeid_ref(boost::type*, T& (*)()) +inline typeinfo typeid_ref(T&(*)()) { return typeid_nonref(); } template -inline typeinfo typeid_array(bool_t, boost::type* = 0) +inline typeinfo array_ref_typeid(bool_t, bool_t, boost::type* = 0) { - typedef T (*x)(); - return typeid_ref((boost::type*)0, x(0)); + return typeid_ref((T&(*)())0); } template -inline typeinfo typeid_array(bool_t, boost::type* = 0) +inline typeinfo array_ref_typeid(bool_t, bool_t, boost::type* = 0) { - return typeid_nonref(); + return typeid_ref((T(*)())0); +} + +template +inline typeinfo array_ref_typeid(bool_t, bool_t, boost::type* = 0) +{ + return typeid_ref((T&(*)())0); } template inline typeinfo msvc_typeid(boost::type* = 0) { - typedef bool_t::value> tag; - return typeid_array(tag(), (boost::type*)0); + typedef bool_t::value> array_tag; + typedef bool_t::value> ref_tag; + return array_ref_typeid(array_tag(), ref_tag(), (boost::type*)0); } }}} // namespace boost::python::detail diff --git a/include/boost/python/make_function.hpp b/include/boost/python/make_function.hpp index 2943d96c..6e7f1661 100644 --- a/include/boost/python/make_function.hpp +++ b/include/boost/python/make_function.hpp @@ -35,8 +35,8 @@ objects::function* make_function(F f, Policies const& policies) , detail::arg_tuple_size::value); } -template -objects::function* make_constructor(T* = 0, ArgList* = 0, Generator* = 0) +template +objects::function* make_constructor(Holder* = 0, ArgList* = 0) { enum { nargs = mpl::size::value }; @@ -44,7 +44,7 @@ objects::function* make_constructor(T* = 0, ArgList* = 0, Generator* = 0) objects::py_function( ::boost::bind(detail::caller(), objects::make_holder - ::template apply::execute + ::template apply::execute , _1, _2, default_call_policies())) , nargs + 1); } diff --git a/include/boost/python/object/class_converters.hpp b/include/boost/python/object/class_converters.hpp index 5c2a35ae..8f2786f3 100644 --- a/include/boost/python/object/class_converters.hpp +++ b/include/boost/python/object/class_converters.hpp @@ -11,27 +11,10 @@ # include # include # include +# include namespace boost { namespace python { namespace objects { -// Instantiating this class brings into existence all converters -// associated with a class Bases is expected to be an mpl sequence of -// base types. -template -struct class_converters -{ - public: // member functions - // Constructor takes the python class object associated with T - class_converters(ref const& python_class); - - private: // data members - class_wrapper m_wrapper; -}; - -// -// Implementation details -// - ////////////////////////////////////////////////////////////////////// // // register_base_of - @@ -86,9 +69,11 @@ struct register_base_of }; }; + +// Brings into existence all converters associated with a class Bases +// is expected to be an mpl sequence of base types. template -class_converters::class_converters(ref const& type_object) - : m_wrapper(type_object) +inline void register_class_from_python(Derived* = 0, Bases* = 0) { (void)instance_finder::registration; diff --git a/include/boost/python/object/class_wrapper.hpp b/include/boost/python/object/class_wrapper.hpp index f8702205..577d1012 100644 --- a/include/boost/python/object/class_wrapper.hpp +++ b/include/boost/python/object/class_wrapper.hpp @@ -6,15 +6,14 @@ #ifndef CLASS_WRAPPER_DWA20011221_HPP # define CLASS_WRAPPER_DWA20011221_HPP -# include # include # include namespace boost { namespace python { namespace objects { -template +template struct class_wrapper - : to_python_converter > + : to_python_converter > { class_wrapper(ref const& type_) : m_class_object_keeper(type_) @@ -39,7 +38,7 @@ struct class_wrapper // Build a value_holder to contain the object using the copy // constructor - value_holder* p = new value_holder(raw_result, cref(x)); + Holder* p = new Holder(raw_result, cref(x)); // Install it in the instance p->install(raw_result); @@ -53,8 +52,8 @@ struct class_wrapper static PyTypeObject* m_class_object; }; -template -PyTypeObject* class_wrapper::m_class_object; +template +PyTypeObject* class_wrapper::m_class_object; }}} // namespace boost::python::objects diff --git a/include/boost/python/object/find_instance.hpp b/include/boost/python/object/find_instance.hpp index c60a82f7..3db670fc 100644 --- a/include/boost/python/object/find_instance.hpp +++ b/include/boost/python/object/find_instance.hpp @@ -6,6 +6,9 @@ #ifndef FIND_INSTANCE_DWA2002312_HPP # define FIND_INSTANCE_DWA2002312_HPP +# include +# include + namespace boost { namespace python { namespace objects { // Given an undecorated type_id, find the instance data which diff --git a/include/boost/python/object/make_holder.hpp b/include/boost/python/object/make_holder.hpp index 871ed059..59043317 100644 --- a/include/boost/python/object/make_holder.hpp +++ b/include/boost/python/object/make_holder.hpp @@ -10,7 +10,6 @@ # include # include # include -# include namespace boost { namespace python { namespace objects { @@ -19,14 +18,13 @@ template struct make_holder; template <> struct make_holder<0> { - template + template struct apply { - typedef typename mpl::apply1::type holder; static void execute( PyObject* p) { - (new holder(p))->install(p); + (new Holder(p))->install(p); } }; }; @@ -35,10 +33,9 @@ struct make_holder<0> template <> struct make_holder<1> { - template + template struct apply { - typedef typename mpl::apply1::type holder; typedef typename mpl::at<0,ArgList>::type t0; typedef typename forward::type f0; @@ -46,7 +43,7 @@ struct make_holder<1> PyObject* p , t0 a0) { - (new holder(p, f0(a0)))->install(p); + (new Holder(p, f0(a0)))->install(p); } }; }; @@ -54,10 +51,9 @@ struct make_holder<1> template <> struct make_holder<2> { - template + template struct apply { - typedef typename mpl::apply1::type holder; typedef typename mpl::at<0,ArgList>::type t0; typedef typename forward::type f0; typedef typename mpl::at<1,ArgList>::type t1; @@ -66,7 +62,7 @@ struct make_holder<2> static void execute( PyObject* p, t0 a0, t1 a1) { - (new holder(p, f0(a0), f1(a1)))->install(p); + (new Holder(p, f0(a0), f1(a1)))->install(p); } }; }; @@ -74,10 +70,9 @@ struct make_holder<2> template <> struct make_holder<3> { - template + template struct apply { - typedef typename mpl::apply1::type holder; typedef typename mpl::at<0,ArgList>::type t0; typedef typename forward::type f0; typedef typename mpl::at<1,ArgList>::type t1; @@ -88,7 +83,7 @@ struct make_holder<3> static void execute( PyObject* p, t0 a0, t1 a1, t2 a2) { - (new holder(p, f0(a0), f1(a1), f2(a2)))->install(p); + (new Holder(p, f0(a0), f1(a1), f2(a2)))->install(p); } }; }; @@ -96,10 +91,9 @@ struct make_holder<3> template <> struct make_holder<4> { - template + template struct apply { - typedef typename mpl::apply1::type holder; typedef typename mpl::at<0,ArgList>::type t0; typedef typename forward::type f0; typedef typename mpl::at<1,ArgList>::type t1; @@ -112,7 +106,7 @@ struct make_holder<4> static void execute( PyObject* p, t0 a0, t1 a1, t2 a2, t3 a3) { - (new holder(p, f0(a0), f1(a1), f2(a2), f3(a3)))->install(p); + (new Holder(p, f0(a0), f1(a1), f2(a2), f3(a3)))->install(p); } }; }; @@ -120,10 +114,9 @@ struct make_holder<4> template <> struct make_holder<5> { - template + template struct apply { - typedef typename mpl::apply1::type holder; typedef typename mpl::at<0,ArgList>::type t0; typedef typename forward::type f0; typedef typename mpl::at<1,ArgList>::type t1; @@ -138,7 +131,7 @@ struct make_holder<5> static void execute( PyObject* p, t0 a0, t1 a1, t2 a2, t3 a3, t4 a4) { - (new holder(p, f0(a0), f1(a1), f2(a2), f3(a3), f4(a4)))->install(p); + (new Holder(p, f0(a0), f1(a1), f2(a2), f3(a3), f4(a4)))->install(p); } }; }; @@ -146,10 +139,9 @@ struct make_holder<5> template <> struct make_holder<6> { - template + template struct apply { - typedef typename mpl::apply1::type holder; typedef typename mpl::at<0,ArgList>::type t0; typedef typename forward::type f0; typedef typename mpl::at<1,ArgList>::type t1; @@ -166,7 +158,7 @@ struct make_holder<6> static void execute( PyObject* p, t0 a0, t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) { - (new holder(p, f0(a0), f1(a1), f2(a2), f3(a3), f4(a4), f5(a5)))->install(p); + (new Holder(p, f0(a0), f1(a1), f2(a2), f3(a3), f4(a4), f5(a5)))->install(p); } }; }; diff --git a/include/boost/python/object/pointer_holder.hpp b/include/boost/python/object/pointer_holder.hpp index 84700299..8bce39bd 100644 --- a/include/boost/python/object/pointer_holder.hpp +++ b/include/boost/python/object/pointer_holder.hpp @@ -14,6 +14,7 @@ # include # include # include +# include namespace boost { namespace python { namespace objects { @@ -147,81 +148,83 @@ struct pointer_holder : instance_holder Pointer m_p; }; -template +template struct pointer_holder_back_reference : instance_holder { + private: + typedef typename python::detail::pointee::type held_type; + public: + pointer_holder_back_reference(Pointer); // Forward construction to the held object pointer_holder_back_reference(PyObject* p) - : m_p(new BackReferenceType(p)) { - (void)instance_finder::registration; + : m_p(new held_type(p)) { + (void)instance_finder::registration; } - - template pointer_holder_back_reference(PyObject* p, A1 a1) - : m_p(new BackReferenceType(p + : m_p(new held_type(p , (typename unwrap_reference::type&)(a1) )) { - (void)instance_finder::registration; + (void)instance_finder::registration; } template pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2) - : m_p(new BackReferenceType(p + : m_p(new held_type(p , (typename unwrap_reference::type&)(a1) , (typename unwrap_reference::type&)(a2) )) { - (void)instance_finder::registration; + (void)instance_finder::registration; } template pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3) - : m_p(new BackReferenceType(p + : m_p(new held_type(p , (typename unwrap_reference::type&)(a1) , (typename unwrap_reference::type&)(a2) , (typename unwrap_reference::type&)(a3) )) { - (void)instance_finder::registration; + (void)instance_finder::registration; } template pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4) - : m_p(new BackReferenceType(p + : m_p(new held_type(p , (typename unwrap_reference::type&)(a1) , (typename unwrap_reference::type&)(a2) , (typename unwrap_reference::type&)(a3) , (typename unwrap_reference::type&)(a4) )) { - (void)instance_finder::registration; + (void)instance_finder::registration; } template pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) - : m_p(new BackReferenceType(p + : m_p(new held_type(p , (typename unwrap_reference::type&)(a1) , (typename unwrap_reference::type&)(a2) , (typename unwrap_reference::type&)(a3) , (typename unwrap_reference::type&)(a4) , (typename unwrap_reference::type&)(a5) )) { - (void)instance_finder::registration; + (void)instance_finder::registration; } template pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) - : m_p(new BackReferenceType(p + : m_p(new held_type(p , (typename unwrap_reference::type&)(a1) , (typename unwrap_reference::type&)(a2) , (typename unwrap_reference::type&)(a3) @@ -229,13 +232,13 @@ struct pointer_holder_back_reference : instance_holder , (typename unwrap_reference::type&)(a5) , (typename unwrap_reference::type&)(a6) )) { - (void)instance_finder::registration; + (void)instance_finder::registration; } template pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) - : m_p(new BackReferenceType(p + : m_p(new held_type(p , (typename unwrap_reference::type&)(a1) , (typename unwrap_reference::type&)(a2) , (typename unwrap_reference::type&)(a3) @@ -245,13 +248,13 @@ struct pointer_holder_back_reference : instance_holder , (typename unwrap_reference::type&)(a7) )) { - (void)instance_finder::registration; + (void)instance_finder::registration; } template pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) - : m_p(new BackReferenceType(p + : m_p(new held_type(p , (typename unwrap_reference::type&)(a1) , (typename unwrap_reference::type&)(a2) , (typename unwrap_reference::type&)(a3) @@ -262,13 +265,13 @@ struct pointer_holder_back_reference : instance_holder , (typename unwrap_reference::type&)(a8) )) { - (void)instance_finder::registration; + (void)instance_finder::registration; } template pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) - : m_p(new BackReferenceType(p + : m_p(new held_type(p , (typename unwrap_reference::type&)(a1) , (typename unwrap_reference::type&)(a2) , (typename unwrap_reference::type&)(a3) @@ -280,13 +283,13 @@ struct pointer_holder_back_reference : instance_holder , (typename unwrap_reference::type&)(a9) )) { - (void)instance_finder::registration; + (void)instance_finder::registration; } template pointer_holder_back_reference(PyObject* p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) - : m_p(new BackReferenceType(p + : m_p(new held_type(p , (typename unwrap_reference::type&)(a1) , (typename unwrap_reference::type&)(a2) , (typename unwrap_reference::type&)(a3) @@ -299,7 +302,7 @@ struct pointer_holder_back_reference : instance_holder , (typename unwrap_reference::type&)(a10) )) { - (void)instance_finder::registration; + (void)instance_finder::registration; } @@ -310,81 +313,18 @@ struct pointer_holder_back_reference : instance_holder Pointer m_p; }; -}}} // namespace boost::python::objects - -// back to namespace boost for this forward declaration -namespace boost -{ - template class shared_ptr; -} - -namespace boost { namespace python { namespace objects { - -struct shared_ptr_generator -{ - template - struct apply - { - typedef boost::shared_ptr type; - }; -}; - -struct no_back_reference; - -// Workaround lack of partial specialization -namespace detail -{ - template - struct pointer_holder_back_reference_generator - { - template - struct apply - { - typedef typename mpl::apply1< - PointerGenerator,BackReferenceType - >::type pointer; - - typedef pointer_holder_back_reference type; - }; - }; - - template - struct plain_pointer_holder_generator - { - template - struct apply - { - typedef typename mpl::apply1< - PointerGenerator,Held - >::type pointer; - - typedef pointer_holder type; - }; - }; -} - -// A generator metafunction which can be passed to make_holder -// PointerGenerator should be another generator metafunction which -// makes the appropriate (smart) pointer type to hold the argument to -// pointer_holder_generator. -template -struct pointer_holder_generator - : mpl::select_type< - is_same::value - , detail::plain_pointer_holder_generator< - PointerGenerator> - , detail::pointer_holder_back_reference_generator< - BackReferenceType,PointerGenerator> - >::type -{ -}; - template pointer_holder::pointer_holder(Pointer p) : m_p(p) { } +template +pointer_holder_back_reference::pointer_holder_back_reference(Pointer p) + : m_p(p) +{ +} + template void* pointer_holder::holds(converter::undecorated_type_id_t dst_t) { @@ -396,6 +336,20 @@ void* pointer_holder::holds(converter::undecorated_type_id_t dst : find_dynamic_type(&*this->m_p, src_t, dst_t); } +template +void* pointer_holder_back_reference::holds(converter::undecorated_type_id_t dst_t) +{ + if (dst_t == converter::undecorated_type_id()) + return &this->m_p; + + if (dst_t == converter::undecorated_type_id()) + return &*this->m_p; + + converter::type_id_t src_t = converter::undecorated_type_id(); + Value* p = &*this->m_p; + return src_t == dst_t ? p : find_dynamic_type(p, src_t, dst_t); +} + }}} // namespace boost::python::objects #endif // POINTER_HOLDER_DWA20011215_HPP diff --git a/include/boost/python/object/select_holder.hpp b/include/boost/python/object/select_holder.hpp new file mode 100644 index 00000000..39d50c0a --- /dev/null +++ b/include/boost/python/object/select_holder.hpp @@ -0,0 +1,70 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef SELECT_HOLDER_DWA2002322_HPP +# define SELECT_HOLDER_DWA2002322_HPP + +# include +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace objects { + +namespace detail +{ + template + struct select_value_holder + { + typedef typename mpl::select_type< + (!is_same::value) | has_back_reference::value + , value_holder_back_reference + , value_holder + >::type holder; + + static holder* get() { return 0; } + }; + + template + struct select_pointer_holder + { + typedef typename python::detail::pointee::type pointee; + + typedef typename mpl::select_type< + (!is_same::value) | has_back_reference::value + , pointer_holder_back_reference + , pointer_holder + >::type holder; + + static holder* get() { return 0; } + }; +} + +template +inline detail::select_value_holder select_holder(python::detail::not_specified*, T* = 0, NotSpecified* = 0) +{ + return detail::select_value_holder(); +} + +template +inline detail::select_value_holder select_holder(T*, Held* = 0) +{ + return detail::select_value_holder(); +} + + +template +detail::select_pointer_holder select_holder(void*, Ptr* = 0, T* = 0) +{ + return detail::select_pointer_holder(); +} + +}}} // namespace boost::python::objects + +#endif // SELECT_HOLDER_DWA2002322_HPP diff --git a/include/boost/python/object/value_holder.hpp b/include/boost/python/object/value_holder.hpp index c0a5c580..4154a7e8 100644 --- a/include/boost/python/object/value_holder.hpp +++ b/include/boost/python/object/value_holder.hpp @@ -142,7 +142,7 @@ struct value_holder : instance_holder Held m_held; }; -template +template struct value_holder_back_reference : instance_holder { // Forward construction to the held object @@ -301,27 +301,6 @@ struct value_holder_back_reference : instance_holder BackReferenceType m_held; }; -// A generator metafunction which can be passed to make_holder -template <> -struct value_holder_generator -{ - template - struct apply - { - typedef value_holder type; - }; -}; - -template -struct value_holder_generator -{ - template - struct apply - { - typedef value_holder_back_reference type; - }; -}; - template void* value_holder::holds(converter::undecorated_type_id_t dst_t) { diff --git a/test/Jamfile b/test/Jamfile index a01efdde..6db104fb 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -68,6 +68,20 @@ unit-test pointer_type_id_test unit-test member_function_cast : member_function_cast.cpp : $(BOOST_ROOT) ; +unit-test bases + : bases.cpp : $(BOOST_ROOT) ; + +unit-test if_else + : if_else.cpp : $(BOOST_ROOT) ; + +unit-test pointee + : pointee.cpp : $(BOOST_ROOT) ; + +unit-test select_holder + : select_holder.cpp + : $(BOOST_ROOT) BOOST_PYTHON_STATIC_LIB $(PYTHON_PROPERTIES) +; + unit-test select_from_python_test : select_from_python_test.cpp ../src/converter/type_id.cpp @@ -77,3 +91,4 @@ unit-test select_from_python_test $(PYTHON_V1_PROPERTIES) ; + diff --git a/test/m1.cpp b/test/m1.cpp index 439d58e2..cbaaf8db 100644 --- a/test/m1.cpp +++ b/test/m1.cpp @@ -201,6 +201,7 @@ BOOST_PYTHON_MODULE_INIT(m1) { using namespace boost::python; using boost::mpl::type_list; + using boost::shared_ptr; simple_to_python(); @@ -219,10 +220,6 @@ BOOST_PYTHON_MODULE_INIT(m1) module m1("m1"); - typedef boost::python::objects::pointer_holder_generator< - boost::python::objects::shared_ptr_generator - > use_shared_ptr; - m1 // Insert the metaclass for all extension classes .setattr("xclass", boost::python::objects::class_metatype()) @@ -251,7 +248,7 @@ BOOST_PYTHON_MODULE_INIT(m1) .def("take_d", take_d) .add( - class_, use_shared_ptr>("A") + class_ >("A") .def_init() .def("name", &A::name) ) @@ -262,13 +259,13 @@ BOOST_PYTHON_MODULE_INIT(m1) // or "C" below if we make them part of the same chain m1 .add( - class_, use_shared_ptr>("B") + class_, shared_ptr >("B") .def_init() .def("name", &B::name) ) .add( - class_, use_shared_ptr>("C") + class_, shared_ptr >("C") .def_init() .def("name", &C::name) ) @@ -276,7 +273,7 @@ BOOST_PYTHON_MODULE_INIT(m1) m1 .add( - class_, use_shared_ptr>("D") + class_, bases >("D") .def_init() .def("name", &D::name) ) diff --git a/test/select_holder.cpp b/test/select_holder.cpp new file mode 100644 index 00000000..cb8fd640 --- /dev/null +++ b/test/select_holder.cpp @@ -0,0 +1,77 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include +#include +#include +#include +#include +#include + +#define BOOST_INCLUDE_MAIN +#include + +struct BR {}; + +struct Base {}; +struct Derived : Base {}; + +namespace boost { namespace python +{ + // specialization + template <> + struct has_back_reference
+ { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +}} // namespace boost::python + +template +void assert_same(U* = 0, T* = 0) +{ + BOOST_TEST((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::is_same::value)); + +} + +template +void assert_holder(T* = 0, Held* = 0, Holder* = 0) +{ + assert_same(boost::python::objects::select_holder((Held*)0).get()); +} + +int test_main(int, char * []) +{ + using namespace boost::python::detail; + using namespace boost::python::objects; + + assert_holder >(); + + assert_holder >(); + assert_holder >(); + assert_holder >(); + + assert_holder >(); + + assert_holder + ,pointer_holder,Base> >(); + + assert_holder + ,pointer_holder_back_reference,Base> >(); + + assert_holder + ,pointer_holder_back_reference,BR> > (); + + return 0; +} + +#if defined(__GNUC__) && __GNUC__ <= 3 +// This definition is needed for MinGW 2.95.2 for some reason +namespace boost { namespace python +{ + bool handle_exception_impl(boost::function0) { return false; } +}} +#endif diff --git a/test/virtual_functions.cpp b/test/virtual_functions.cpp index ab05fe3c..586048d5 100644 --- a/test/virtual_functions.cpp +++ b/test/virtual_functions.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using namespace boost::python; @@ -66,6 +67,10 @@ struct concrete_callback : concrete : concrete(x), self(p) {} + concrete_callback(PyObject* p, concrete const& x) + : concrete(x), self(p) + {} + int f(Y const& y) { return returning::call_method(self, "f", boost::ref(y)); @@ -85,26 +90,21 @@ BOOST_PYTHON_MODULE_INIT(virtual_functions_ext) { module("virtual_functions_ext") .add( - class_, objects::value_holder_generator >("concrete") + class_("concrete") .def_init(args()) .def("value", &concrete::value) .def("set", &concrete::set) .def("call_f", &concrete::call_f) .def("f", &concrete_callback::f_impl)) -#if 0 .add( - class_ - , objects::pointer_holder_generator< - boost::python::objects::shared_ptr_generator - , abstract_callback> + class_ >("abstract") .def_init(args()) .def("value", &abstract::value) .def("call_f", &abstract::call_f) .def("set", &abstract::set)) -#endif .add( class_("Y") diff --git a/test/virtual_functions.py b/test/virtual_functions.py index 8ea992c5..9b074b1a 100644 --- a/test/virtual_functions.py +++ b/test/virtual_functions.py @@ -8,13 +8,13 @@ >>> class C2(concrete): ... pass -<<<>>> class A1(abstract): -<<<... def f(self, y): -<<<... return abstract.f(self, Y(-y.value())) -<<< -<<<>>> class A2(abstract): -<<<... pass -<<< +>>> class A1(abstract): +... def f(self, y): +... return y.value() * 2 + +>>> class A2(abstract): +... pass + >>> y1 = Y(16) >>> y2 = Y(17) @@ -24,33 +24,35 @@ # # Test abstract with f overridden # -<<<>>> a1 = A1(42) -<<<>>> a1.value() -<<<42 -<<< -<<<# Call f indirectly from C++ -<<<>>> a1.call_f(y1) -<<<-16 -<<< -<<<# Call f directly from Python -<<<>>> a1.f(y2) -<<<-17 -<<< -<<<# -<<<# Test abstract with f not overridden -<<<# -<<<>>> a2 = A2(42) -<<<>>> A2.value() -<<<42 -<<< -<<<# Call f indirectly from C++ -<<<>>> c1.call_f(y1) -<<<16 -<<< -<<<# Call f directly from Python -<<<>>> c1.f(y2) -<<<17 -<<< +>>> a1 = A1(42) +>>> a1.value() +42 + +# Call f indirectly from C++ +>>> a1.call_f(y1) +32 + +# Call f directly from Python +>>> a1.f(y2) +34 + +# +# Test abstract with f not overridden +# +>>> a2 = A2(42) +>>> a2.value() +42 + +# Call f indirectly from C++ +>>> try: a2.call_f(y1) +... except AttributeError: pass +... else: print 'no exception' + +# Call f directly from Python +>>> try: a2.call_f(y2) +... except AttributeError: pass +... else: print 'no exception' + ############# Concrete Tests ############ #