From bcaa1043ea9ae1f0ed052079d6220d066fd63c57 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Fri, 23 Aug 2002 18:07:27 +0000 Subject: [PATCH] More smart pointer handling [SVN r15069] --- include/boost/python/class.hpp | 10 +++-- include/boost/python/instance_holder.hpp | 4 ++ include/boost/python/object/class_wrapper.hpp | 40 ++++++++++--------- .../boost/python/object/pointer_holder.hpp | 40 +++++++++++++++++-- include/boost/python/object/value_holder.hpp | 13 +++++- test/m1.cpp | 10 ++++- test/newtest.py | 7 ++++ 7 files changed, 97 insertions(+), 27 deletions(-) diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index 870f644c..1e75a6f5 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -52,15 +52,17 @@ namespace detail // 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*, object const& obj, T* = 0) + static inline void register_copy_constructor(mpl::bool_t const&, Holder*, T* = 0) { - objects::class_wrapper x(obj); + force_instantiate(objects::class_wrapper()); + Holder::register_(); } // Tag dispatched to have no effect. template - static inline void register_copy_constructor(mpl::bool_t const&, Holder*, object const&, T* = 0) + static inline void register_copy_constructor(mpl::bool_t const&, Holder*, T* = 0) { + Holder::register_(); } template int assert_default_constructible(T const&); @@ -331,7 +333,7 @@ inline void class_::register_() const detail::register_copy_constructor( mpl::bool_t() , objects::select_holder((held_type*)0).get() - , *this); + ); } diff --git a/include/boost/python/instance_holder.hpp b/include/boost/python/instance_holder.hpp index eb148431..f4962479 100755 --- a/include/boost/python/instance_holder.hpp +++ b/include/boost/python/instance_holder.hpp @@ -24,6 +24,10 @@ struct BOOST_PYTHON_DECL instance_holder : private noncopyable virtual void* holds(type_info) = 0; void install(PyObject* inst) throw(); + + // Register any converters associated with this Holder + static inline void register_() {} + private: instance_holder* m_next; }; diff --git a/include/boost/python/object/class_wrapper.hpp b/include/boost/python/object/class_wrapper.hpp index 2e06f921..723126a4 100644 --- a/include/boost/python/object/class_wrapper.hpp +++ b/include/boost/python/object/class_wrapper.hpp @@ -8,26 +8,37 @@ # include # include +# include +# include namespace boost { namespace python { namespace objects { -template -struct class_wrapper - : to_python_converter > +template +struct copy_construct_instance { - class_wrapper(object const& type_) - : m_class_object_keeper(type_) + static Holder* execute(PyObject* instance, Src const& x) { - assert(type_.ptr()->ob_type == (PyTypeObject*)class_metatype().get()); - m_class_object = (PyTypeObject*)type_.ptr(); + return new Holder(instance, cref(x)); } - - static PyObject* convert(T const& x) +}; + +// Used to convert objects of type Src to wrapped C++ classes by +// building a new instance object and installing a Holder constructed +// from the Src object. +template > +struct class_wrapper + : to_python_converter > +{ + static PyObject* convert(Src const& x) { + // Get the class object associated with the wrapped type + typedef typename Holder::value_type value_type; + PyTypeObject* class_object = converter::registered::converters.class_object; + // Don't call the type directly to do the construction, since // that would require the registration of an appropriate // __init__ function. - PyObject* raw_result = m_class_object->tp_alloc(m_class_object, 0); + PyObject* raw_result = class_object->tp_alloc(class_object, 0); if (raw_result == 0) return 0; @@ -38,7 +49,7 @@ struct class_wrapper // Build a value_holder to contain the object using the copy // constructor - Holder* p = new Holder(raw_result, cref(x)); + Holder* p = MakeHolder::execute(raw_result, x); // Install it in the instance p->install(raw_result); @@ -46,15 +57,8 @@ struct class_wrapper // Return the new result return result.release(); } - - private: - object m_class_object_keeper; - static PyTypeObject* m_class_object; }; -template -PyTypeObject* class_wrapper::m_class_object; - }}} // namespace boost::python::objects #endif // CLASS_WRAPPER_DWA20011221_HPP diff --git a/include/boost/python/object/pointer_holder.hpp b/include/boost/python/object/pointer_holder.hpp index 8498a8df..3d9e9992 100644 --- a/include/boost/python/object/pointer_holder.hpp +++ b/include/boost/python/object/pointer_holder.hpp @@ -16,6 +16,7 @@ # include # include # include +# include # include # include # include @@ -34,13 +35,26 @@ namespace boost { namespace python { namespace objects { template struct pointer_holder : instance_holder { + typedef Value value_type; + pointer_holder(Pointer); + static void register_(); + // Forward construction to the held object # define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, , 1)) # include BOOST_PP_ITERATE() + private: // types + struct construct_from_pointer + { + static pointer_holder* execute(PyObject*, Pointer x) + { + return new pointer_holder(x); + } + }; + private: // required holder implementation void* holds(type_info); @@ -54,9 +68,14 @@ struct pointer_holder_back_reference : instance_holder private: typedef typename python::pointee::type held_type; public: + typedef Value value_type; + // Not sure about this one -- can it work? The source object + // undoubtedly does not carry the correct back reference pointer. pointer_holder_back_reference(Pointer); + static void register_(); + // Forward construction to the held object # define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, , 2)) # include BOOST_PP_ITERATE() @@ -76,12 +95,29 @@ inline pointer_holder::pointer_holder(Pointer p) { } +template +inline void pointer_holder::register_() +{ + python::detail::force_instantiate(class_wrapper()); + python::detail::force_instantiate(instance_finder::registration); +} + + template inline pointer_holder_back_reference::pointer_holder_back_reference(Pointer p) : m_p(p) { } +template +inline void pointer_holder_back_reference::register_() +{ + // not implemented at least until we solve the back reference issue mentioned above. + // python::detail::force_instantiate(class_wrapper()); + python::detail::force_instantiate(instance_finder::registration); + python::detail::force_instantiate(instance_finder::registration); +} + template void* pointer_holder::holds(type_info dst_t) { @@ -142,9 +178,7 @@ void* pointer_holder_back_reference::holds(type_info dst_t) : m_p(new held_type( p BOOST_PP_COMMA_IF(N) BOOST_PP_REPEAT(N, BOOST_PYTHON_UNFORWARD_LOCAL, nil) )) - { - python::detail::force_instantiate(instance_finder::registration); - } + {} # undef N diff --git a/include/boost/python/object/value_holder.hpp b/include/boost/python/object/value_holder.hpp index 6eb0c4ed..3d8d2ac2 100644 --- a/include/boost/python/object/value_holder.hpp +++ b/include/boost/python/object/value_holder.hpp @@ -29,6 +29,8 @@ namespace boost { namespace python { namespace objects { template struct value_holder : instance_holder { + typedef Held value_type; + // Forward construction to the held object # define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, , 1)) # include BOOST_PP_ITERATE() @@ -43,6 +45,10 @@ struct value_holder : instance_holder template struct value_holder_back_reference : instance_holder { + typedef Held value_type; + + static void register_(); + // Forward construction to the held object # define BOOST_PP_ITERATION_PARAMS_1 (4, (0, BOOST_PYTHON_MAX_ARITY, , 2)) # include BOOST_PP_ITERATE() @@ -79,6 +85,12 @@ void* value_holder_back_reference::holds( return find_static_type(x, src_t, dst_t); } +template +void value_holder_back_reference::register_() +{ + python::detail::force_instantiate(instance_finder::registration); +} + }}} // namespace boost::python::objects # endif // VALUE_HOLDER_DWA20011215_HPP @@ -119,7 +131,6 @@ void* value_holder_back_reference::holds( BOOST_PP_REPEAT(N, BOOST_PYTHON_UNFORWARD_LOCAL, nil) ) { - python::detail::force_instantiate(instance_finder::registration); } # undef N diff --git a/test/m1.cpp b/test/m1.cpp index de76f64a..34832dfa 100644 --- a/test/m1.cpp +++ b/test/m1.cpp @@ -190,7 +190,11 @@ A take_a(A const& a) { return a; } B take_b(B& b) { return b; } C take_c(C* c) { return *c; } D take_d(D* const& d) { return *d; } - + +D take_d_shared_ptr(boost::shared_ptr d) { return *d; } + +boost::shared_ptr d_factory() { return boost::shared_ptr(new D); } + BOOST_PYTHON_MODULE_INIT(m1) { using namespace boost::python; @@ -237,6 +241,10 @@ BOOST_PYTHON_MODULE_INIT(m1) .def("take_b", take_b) .def("take_c", take_c) .def("take_d", take_d) + + + .def("take_d_shared_ptr", take_d_shared_ptr) + .def("d_factory", d_factory) ; class_ >("A") diff --git a/test/newtest.py b/test/newtest.py index 0edd34b8..7b68a260 100644 --- a/test/newtest.py +++ b/test/newtest.py @@ -158,6 +158,13 @@ are a complicated constructor and member function, respectively. >>> take_d(d).name() 'D' +>>> take_d_shared_ptr(d).name() +'D' + +>>> d_as_a = d_factory() +>>> dd = take_d(d_as_a) +>>> dd.name() +'D' """