diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index 5177e339..c67faae3 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -77,21 +77,21 @@ namespace detail template struct operator_; - // 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 + // Register to_python converters for a class T. The first argument + // will be mpl::true_c unless noncopyable was specified as a + // class_<...> template parameter. 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_c const&, SelectHolder const& , T* = 0) + inline void register_class_to_python(mpl::true_c copyable, SelectHolder selector, T* = 0) { typedef typename SelectHolder::type holder; force_instantiate(objects::class_cref_wrapper >()); SelectHolder::register_(); } - // Tag dispatched to have no effect. template - static inline void register_copy_constructor(mpl::bool_c const&, SelectHolder const&, T* = 0) + inline void register_class_to_python(mpl::false_c copyable, SelectHolder selector, T* = 0) { SelectHolder::register_(); } @@ -125,20 +125,14 @@ namespace detail template struct virtual_function_default -# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 - : assertion >::failed - , assertion >::failed -# endif { template static void must_be_derived_class_member(Default const&) { typedef typename assertion > >::failed test0; -# if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 typedef typename assertion >::failed test1; typedef typename assertion >::failed test2; -# endif not_a_derived_class_member(Fn()); } }; @@ -473,7 +467,7 @@ inline void class_::register_() const { objects::register_class_from_python(); - detail::register_copy_constructor( + detail::register_class_to_python( mpl::bool_c() , holder_selector::execute((held_type*)0) ); diff --git a/include/boost/python/converter/from_python.hpp b/include/boost/python/converter/from_python.hpp index dabafcaa..0822e563 100644 --- a/include/boost/python/converter/from_python.hpp +++ b/include/boost/python/converter/from_python.hpp @@ -18,7 +18,7 @@ struct rvalue_from_python_chain; BOOST_PYTHON_DECL void* get_lvalue_from_python( PyObject* source, registration const&); -BOOST_PYTHON_DECL rvalue_from_python_chain const* implicit_conversion_chain( +BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python( PyObject* source, registration const&); BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1( diff --git a/include/boost/python/converter/implicit.hpp b/include/boost/python/converter/implicit.hpp index 79a398aa..fd588f6b 100644 --- a/include/boost/python/converter/implicit.hpp +++ b/include/boost/python/converter/implicit.hpp @@ -5,10 +5,13 @@ // to its suitability for any purpose. #ifndef IMPLICIT_DWA2002326_HPP # define IMPLICIT_DWA2002326_HPP + # include # include # include +# include + namespace boost { namespace python { namespace converter { template @@ -16,39 +19,22 @@ struct implicit { static void* convertible(PyObject* obj) { - // Find a converter chain which can produce a Source instance - // from obj. The user has told us that Source can be converted - // to Target, and instantiating construct() below, ensures - // that at compile-time. - return const_cast( - converter::implicit_conversion_chain(obj, registered::converters)); + // Find a converter which can produce a Source instance from + // obj. The user has told us that Source can be converted to + // Target, and instantiating construct() below, ensures that + // at compile-time. + return implicit_rvalue_convertible_from_python(obj, registered::converters) + ? obj : 0; } static void construct(PyObject* obj, rvalue_from_python_stage1_data* data) { - // This is the chain we got from the convertible step - rvalue_from_python_chain const* chain - = static_cast(data->convertible); - - // Call the convertible function again - rvalue_from_python_data intermediate_data(chain->convertible(obj)); - - // Use the result to construct the source type if the first - // converter was an rvalue converter. - if (chain->construct != 0) - chain->construct(obj, &intermediate_data.stage1); - void* storage = ((rvalue_from_python_storage*)data)->storage.bytes; -# if !defined(BOOST_MSVC) || _MSC_FULL_VER != 13012108 // vc7.01 alpha workaround - new (storage) Target(*static_cast(intermediate_data.stage1.convertible)); -# else - Target x(*static_cast(intermediate_data.stage1.convertible)); - new (storage) Target(x); -# endif - + + new (storage) Target(extract(obj)()); + // record successful construction data->convertible = storage; - } }; diff --git a/include/boost/python/converter/registrations.hpp b/include/boost/python/converter/registrations.hpp index 8ed9d04a..973e052f 100644 --- a/include/boost/python/converter/registrations.hpp +++ b/include/boost/python/converter/registrations.hpp @@ -6,11 +6,15 @@ #ifndef REGISTRATIONS_DWA2002223_HPP # define REGISTRATIONS_DWA2002223_HPP -# include +# include + # include # include # include -# include + +# include + +# include namespace boost { namespace python { namespace converter { @@ -54,7 +58,7 @@ struct BOOST_PYTHON_DECL registration // The unique to_python converter for the associated C++ type. to_python_function_t m_to_python; -# if defined(__MWERKS__) && __MWERKS__ <= 0x3003 +# if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) private: void operator=(registration); // This is not defined, and just keeps MWCW happy. # endif diff --git a/include/boost/python/object/class_converters.hpp b/include/boost/python/object/class_converters.hpp index bd7ead82..e902a40f 100644 --- a/include/boost/python/object/class_converters.hpp +++ b/include/boost/python/object/class_converters.hpp @@ -9,7 +9,6 @@ # include # include -# include # include # include @@ -72,8 +71,6 @@ struct register_base_of template inline void register_class_from_python(Derived* = 0, Bases* = 0) { - // cause the static registration to be instantiated. - python::detail::force_instantiate(instance_finder::registration); python::detail::force_instantiate(converter::shared_ptr_from_python::registration); // register all up/downcasts here diff --git a/include/boost/python/object/find_instance.hpp b/include/boost/python/object/find_instance.hpp index 44c79550..113b622d 100644 --- a/include/boost/python/object/find_instance.hpp +++ b/include/boost/python/object/find_instance.hpp @@ -7,7 +7,6 @@ # define FIND_INSTANCE_DWA2002312_HPP # include -# include namespace boost { namespace python { namespace objects { @@ -15,26 +14,6 @@ namespace boost { namespace python { namespace objects { // return 0 in case no such type is held. BOOST_PYTHON_DECL void* find_instance_impl(PyObject*, type_info); -// This produces a function with the right signature for use in from_python conversions -template -struct instance_finder -{ - instance_finder() - { - converter::registry::insert(&execute, python::type_id()); - } - - static instance_finder const registration; - private: - static inline void* execute(PyObject* p) - { - return find_instance_impl(p, python::type_id()); - } -}; - -template -instance_finder const instance_finder::registration; - }}} // namespace boost::python::objects #endif // FIND_INSTANCE_DWA2002312_HPP diff --git a/include/boost/python/object/make_instance.hpp b/include/boost/python/object/make_instance.hpp index ecac7493..b9e0c981 100644 --- a/include/boost/python/object/make_instance.hpp +++ b/include/boost/python/object/make_instance.hpp @@ -11,6 +11,15 @@ namespace boost { namespace python { namespace objects { +struct decref_guard +{ + decref_guard(PyObject* o) : obj(o) {} + ~decref_guard() { Py_XDECREF(obj); } + void cancel() { obj = 0; } + private: + PyObject* obj; +}; + template struct make_instance { @@ -28,22 +37,20 @@ struct make_instance if (raw_result != 0) { - instance_t* result = (instance_t*)raw_result; - try - { - // construct the new C++ object and install the pointer - // in the Python object. - construct(result, x)->install(raw_result); - } - catch(...) - { - Py_DECREF(raw_result); // reclaim the Python object - throw; - } + decref_guard protect(raw_result); + + instance_t* instance = (instance_t*)raw_result; + + // construct the new C++ object and install the pointer + // in the Python object. + construct(instance, x)->install(raw_result); // Note the position of the internally-stored Holder, // for the sake of destruction - result->ob_size = offsetof(instance_t, storage); + instance->ob_size = offsetof(instance_t, storage); + + // Release ownership of the python object + protect.cancel(); } return raw_result; } diff --git a/include/boost/python/object/pointer_holder.hpp b/include/boost/python/object/pointer_holder.hpp index c35e012e..4400abe6 100644 --- a/include/boost/python/object/pointer_holder.hpp +++ b/include/boost/python/object/pointer_holder.hpp @@ -14,7 +14,6 @@ # include # include # include -# include # include # include # include diff --git a/include/boost/python/object/select_holder.hpp b/include/boost/python/object/select_holder.hpp index 67adacb8..46f3e212 100644 --- a/include/boost/python/object/select_holder.hpp +++ b/include/boost/python/object/select_holder.hpp @@ -12,7 +12,6 @@ # include # include # include -# include # include # include # include @@ -27,11 +26,22 @@ namespace boost { namespace python { namespace objects { namespace detail { + + // check_default_constructible -- + // + // Used to give a clean error message when the user doesn't specify + // any __init__ functions, but when the class being wrapped doesn't + // have an appropriate default constructor (or if + // has_back_reference is true, a constructor taking PyObject*). + // A helpful compile-time assertion which gives a reasonable error // message if T can't be default-constructed. template static int specify_init_arguments_or_no_init_for_class_(T const&); - + + // U is expected to take an initial hidden PyObject* in its + // constructor. Normally this means U is a virtual function + // dispatcher subclass for T. template void check_default_constructible(T*, U*, mpl::bool_c) { @@ -39,7 +49,9 @@ namespace detail sizeof(specify_init_arguments_or_no_init_for_class_(U((::PyObject*)0))) ); } - + + // Handles the "normal" case where T is held directly and + // has_back_reference is not specialized. template void check_default_constructible(T*, T*, mpl::bool_c) { @@ -47,76 +59,76 @@ namespace detail sizeof(specify_init_arguments_or_no_init_for_class_(T())) ); } + + // + // select_value_holder/select_pointer_holder -- + // + // An instantiation of one of these data-free class templates is + // returned by select_holder::execute(), below. Each provides the + // following public interface: + // + // static void assert_default_constructible() -- called when no + // init<...> arguments are specified in class_'s + // constructor; causes a compile-time error when T has no + // corresponding default constructor. + // + // typedef ... type -- the class derived from instance_holder + // which will manage a Held object in Python class instances + // + // static type* get() { return 0; } -- just a way to access the + // computed type at runtime. + // + // static void register_() -- forces registration of any + // to_python converters corresponding to Held. template struct select_value_holder { - BOOST_STATIC_CONSTANT(bool, selector = (!is_same::value) | has_back_reference::value); + BOOST_STATIC_CONSTANT(bool, back_ref = (!is_same::value) | has_back_reference::value); static void assert_default_constructible() { - detail::check_default_constructible((T*)0,(Held*)0,mpl::bool_c()); + detail::check_default_constructible((T*)0,(Held*)0,mpl::bool_c()); } typedef typename mpl::if_c< - selector + back_ref , value_holder_back_reference , value_holder >::type type; - static inline void register_() - { - select_value_holder::register_(mpl::bool_c()); - } + static inline void register_() {} static type* get() { return 0; } - - private: - static inline void register_(mpl::bool_c) - { - python::detail::force_instantiate(instance_finder::registration); - } - - static inline void register_(mpl::bool_c) - { - } }; template struct select_pointer_holder { typedef typename python::pointee::type pointee; - BOOST_STATIC_CONSTANT(bool, selector = (!is_same::value) | has_back_reference::value); + BOOST_STATIC_CONSTANT(bool, back_ref = (!is_same::value) | has_back_reference::value); static void assert_default_constructible() { - detail::check_default_constructible((T*)0,(pointee*)0,mpl::bool_c()); + detail::check_default_constructible((T*)0,(pointee*)0,mpl::bool_c()); } typedef typename mpl::if_c< - selector + back_ref , pointer_holder_back_reference , pointer_holder >::type type; static inline void register_() { - select_pointer_holder::register_(mpl::bool_c()); + select_pointer_holder::register_(mpl::bool_c()); } static type* get() { return 0; } private: - static inline void register_(mpl::bool_c) + static inline void register_(mpl::true_c) { - // not implemented at least until we solve the back - // reference issue mentioned in pointer_holder.hpp. - // - // python::detail::force_instantiate( - // class_wrapper >()); - - python::detail::force_instantiate(instance_finder::registration); - python::detail::force_instantiate(instance_finder::registration); } struct construct_from_pointer @@ -127,37 +139,56 @@ namespace detail } }; - static inline void register_(mpl::bool_c) + static inline void register_(mpl::false_c) { python::detail::force_instantiate( objects::class_value_wrapper >()); - - python::detail::force_instantiate( - instance_finder::registration); } }; } +// select_holder::execute((Held*)0) +// +// implements a compile-time returns an instantiation of +// detail::select_value_holder or detail::select_pointer_holder, as +// appropriate for class_ template struct select_holder { + // Return the additional size to allocate in Python class + // instances to hold the C++ instance data. static inline std::size_t additional_size() { return additional_size_helper(execute((Held*)0)); } - + + // These overloads are an elaborate workaround for deficient + // compilers: + // + // They are meant to be called with a null pointer to the class_'s + // Held template argument. The selected overload will create an + // appropriate instantiation of select_value_holder or + // select_pointer_holder, which is itself an empty class that is + // ultimately used to create the class_'s instance_holder subclass + // object. + + // No Held was specified; T is held directly by-value static inline detail::select_value_holder execute(python::detail::not_specified*) { return detail::select_value_holder(); } + // A type derived from T was specified; it is assumed to be a + // virtual function dispatcher class, and T is held as Held. static inline detail::select_value_holder execute(T*) { return detail::select_value_holder(); } + // Some other type was specified; Held is assumed to be a (smart) + // pointer to T or a class derived from T. static inline detail::select_pointer_holder execute(void*) { diff --git a/include/boost/python/object/value_holder.hpp b/include/boost/python/object/value_holder.hpp index 95b58746..6ae3ae75 100644 --- a/include/boost/python/object/value_holder.hpp +++ b/include/boost/python/object/value_holder.hpp @@ -10,11 +10,13 @@ # define VALUE_HOLDER_DWA20011215_HPP # include + # include # include + # include -# include # include + # include # include diff --git a/include/boost/python/to_python_indirect.hpp b/include/boost/python/to_python_indirect.hpp index 78e95098..c1ad8ce5 100644 --- a/include/boost/python/to_python_indirect.hpp +++ b/include/boost/python/to_python_indirect.hpp @@ -37,7 +37,9 @@ namespace detail template static result_type execute(T* p) { - // can't use auto_ptr with Intel 5 for some reason + // can't use auto_ptr with Intel 5 and VC6 Dinkum library + // for some reason. We get link errors against the auto_ptr + // copy constructor. # if defined(__ICL) && __ICL < 600 typedef boost::shared_ptr smart_pointer; # else diff --git a/src/converter/from_python.cpp b/src/converter/from_python.cpp index 49b362e0..904f66ff 100644 --- a/src/converter/from_python.cpp +++ b/src/converter/from_python.cpp @@ -7,11 +7,15 @@ #include #include #include + +#include + #include #include #include #include + #include #include @@ -38,18 +42,28 @@ BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1( PyObject* source , registration const& converters) { - rvalue_from_python_chain const* chain = converters.rvalue_chain; - rvalue_from_python_stage1_data data; - data.convertible = 0; - for (;chain != 0; chain = chain->next) + + // First check to see if it's embedded in an extension class + // instance, as a special case. + data.convertible = objects::find_instance_impl(source, converters.target_type); + if (data.convertible) { - void* r = chain->convertible(source); - if (r != 0) + data.construct = 0; + } + else + { + for (rvalue_from_python_chain const* chain = converters.rvalue_chain; + chain != 0; + chain = chain->next) { - data.convertible = r; - data.construct = chain->construct; - break; + void* r = chain->convertible(source); + if (r != 0) + { + data.convertible = r; + data.construct = chain->construct; + break; + } } } return data; @@ -111,8 +125,12 @@ BOOST_PYTHON_DECL void* get_lvalue_from_python( PyObject* source , registration const& converters) { + // Check to see if it's embedded in a class instance + void* x = objects::find_instance_impl(source, converters.target_type); + if (x) + return x; + lvalue_from_python_chain const* chain = converters.lvalue_chain; - for (;chain != 0; chain = chain->next) { void* r = chain->convert(source); @@ -138,38 +156,45 @@ namespace return true; } - void unvisit(rvalue_from_python_chain const* chain) + // RAII class for managing global visited marks. + struct unvisit { - visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); - assert(p != visited.end()); - visited.erase(p); - } + unvisit(rvalue_from_python_chain const* chain) + : chain(chain) {} + + ~unvisit() + { + visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain); + assert(p != visited.end()); + visited.erase(p); + } + private: + rvalue_from_python_chain const* chain; + }; } -BOOST_PYTHON_DECL rvalue_from_python_chain const* implicit_conversion_chain( + +BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python( PyObject* source , registration const& converters) { + if (objects::find_instance_impl(source, converters.target_type)) + return true; + rvalue_from_python_chain const* chain = converters.rvalue_chain; if (!visit(chain)) - return 0; + return false; + + unvisit protect(chain); - try + for (;chain != 0; chain = chain->next) { - for (;chain != 0; chain = chain->next) - { - if (chain->convertible(source)) - break; - } + if (chain->convertible(source)) + return true; } - catch(...) - { - unvisit(chain); - throw; - } - unvisit(chain); - return chain; + + return false; } namespace