diff options
Diffstat (limited to 'boost/python/converter')
27 files changed, 2440 insertions, 0 deletions
diff --git a/boost/python/converter/arg_from_python.hpp b/boost/python/converter/arg_from_python.hpp new file mode 100644 index 0000000000..e2edce7e1c --- /dev/null +++ b/boost/python/converter/arg_from_python.hpp @@ -0,0 +1,336 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef ARG_FROM_PYTHON_DWA2002127_HPP +# define ARG_FROM_PYTHON_DWA2002127_HPP + +# include <boost/python/detail/prefix.hpp> +# include <boost/python/converter/from_python.hpp> +# include <boost/python/detail/indirect_traits.hpp> +# include <boost/type_traits/transform_traits.hpp> +# include <boost/type_traits/cv_traits.hpp> +# include <boost/python/converter/rvalue_from_python_data.hpp> +# include <boost/mpl/eval_if.hpp> +# include <boost/mpl/if.hpp> +# include <boost/mpl/identity.hpp> +# include <boost/mpl/and.hpp> +# include <boost/mpl/or.hpp> +# include <boost/mpl/not.hpp> +# include <boost/python/converter/registry.hpp> +# include <boost/python/converter/registered.hpp> +# include <boost/python/converter/registered_pointee.hpp> +# include <boost/python/detail/void_ptr.hpp> +# include <boost/python/back_reference.hpp> +# include <boost/python/detail/referent_storage.hpp> +# include <boost/python/converter/obj_mgr_arg_from_python.hpp> + +namespace boost { namespace python +{ + template <class T> struct arg_from_python; +}} + +// This header defines Python->C++ function argument converters, +// parametrized on the argument type. + +namespace boost { namespace python { namespace converter { + +// +// lvalue converters +// +// These require that an lvalue of the type U is stored somewhere in +// the Python object being converted. + +// Used when T == U*const& +template <class T> +struct pointer_cref_arg_from_python +{ + typedef T result_type; + + pointer_cref_arg_from_python(PyObject*); + T operator()() const; + bool convertible() const; + + private: // storage for a U* + // needed because not all compilers will let us declare U* as the + // return type of operator() -- we return U*const& instead + typename python::detail::referent_storage<T>::type m_result; +}; + +// Base class for pointer and reference converters +struct arg_lvalue_from_python_base +{ + public: // member functions + arg_lvalue_from_python_base(void* result); + bool convertible() const; + + protected: // member functions + void*const& result() const; + + private: // data members + void* m_result; +}; + +// Used when T == U* +template <class T> +struct pointer_arg_from_python : arg_lvalue_from_python_base +{ + typedef T result_type; + + pointer_arg_from_python(PyObject*); + T operator()() const; +}; + +// Used when T == U& and (T != V const& or T == W volatile&) +template <class T> +struct reference_arg_from_python : arg_lvalue_from_python_base +{ + typedef T result_type; + + reference_arg_from_python(PyObject*); + T operator()() const; +}; + +// =================== + +// +// rvalue converters +// +// These require only that an object of type T can be created from +// the given Python object, but not that the T object exist +// somewhere in storage. +// + +// Used when T is a plain value (non-pointer, non-reference) type or +// a (non-volatile) const reference to a plain value type. +template <class T> +struct arg_rvalue_from_python +{ + typedef typename boost::add_reference< + T + // We can't add_const here, or it would be impossible to pass + // auto_ptr<U> args from Python to C++ + >::type result_type; + + arg_rvalue_from_python(PyObject*); + bool convertible() const; + +# if BOOST_MSVC < 1301 || _MSC_FULL_VER > 13102196 + typename arg_rvalue_from_python<T>:: +# endif + result_type operator()(); + + private: + rvalue_from_python_data<result_type> m_data; + PyObject* m_source; +}; + + +// ================== + +// Converts to a (PyObject*,T) bundle, for when you need a reference +// back to the Python object +template <class T> +struct back_reference_arg_from_python + : boost::python::arg_from_python<typename T::type> +{ + typedef T result_type; + + back_reference_arg_from_python(PyObject*); + T operator()(); + private: + typedef boost::python::arg_from_python<typename T::type> base; + PyObject* m_source; +}; + + +// ================== + +template <class C, class T, class F> +struct if_2 +{ + typedef typename mpl::eval_if<C, mpl::identity<T>, F>::type type; +}; + +// This metafunction selects the appropriate arg_from_python converter +// type for an argument of type T. +template <class T> +struct select_arg_from_python +{ + typedef typename if_2< + is_object_manager<T> + , object_manager_value_arg_from_python<T> + , if_2< + is_reference_to_object_manager<T> + , object_manager_ref_arg_from_python<T> + , if_2< + is_pointer<T> + , pointer_arg_from_python<T> + , if_2< + mpl::and_< + indirect_traits::is_reference_to_pointer<T> + , indirect_traits::is_reference_to_const<T> + , mpl::not_<indirect_traits::is_reference_to_volatile<T> > + > + , pointer_cref_arg_from_python<T> + , if_2< + mpl::or_< + indirect_traits::is_reference_to_non_const<T> + , indirect_traits::is_reference_to_volatile<T> + > + , reference_arg_from_python<T> + , mpl::if_< + boost::python::is_back_reference<T> + , back_reference_arg_from_python<T> + , arg_rvalue_from_python<T> + > + > + > + > + > + >::type type; +}; + +// ================== + +// +// implementations +// + +// arg_lvalue_from_python_base +// +inline arg_lvalue_from_python_base::arg_lvalue_from_python_base(void* result) + : m_result(result) +{ +} + +inline bool arg_lvalue_from_python_base::convertible() const +{ + return m_result != 0; +} + +inline void*const& arg_lvalue_from_python_base::result() const +{ + return m_result; +} + +// pointer_cref_arg_from_python +// +namespace detail +{ + // null_ptr_reference -- a function returning a reference to a null + // pointer of type U. Needed so that extractors for T*const& can + // convert Python's None. + template <class T> + struct null_ptr_owner + { + static T value; + }; + template <class T> T null_ptr_owner<T>::value = 0; + + template <class U> + inline U& null_ptr_reference(U&(*)()) + { + return null_ptr_owner<U>::value; + } +} + +template <class T> +inline pointer_cref_arg_from_python<T>::pointer_cref_arg_from_python(PyObject* p) +{ + // T == U*const&: store a U* in the m_result storage. Nonzero + // indicates success. If find returns nonzero, it's a pointer to + // a U object. + python::detail::write_void_ptr_reference( + m_result.bytes + , p == Py_None ? p : converter::get_lvalue_from_python(p, registered_pointee<T>::converters) + , (T(*)())0); +} + +template <class T> +inline bool pointer_cref_arg_from_python<T>::convertible() const +{ + return python::detail::void_ptr_to_reference(m_result.bytes, (T(*)())0) != 0; +} +template <class T> +inline T pointer_cref_arg_from_python<T>::operator()() const +{ + return (*(void**)m_result.bytes == Py_None) // None ==> 0 + ? detail::null_ptr_reference((T(*)())0) + // Otherwise, return a U*const& to the m_result storage. + : python::detail::void_ptr_to_reference(m_result.bytes, (T(*)())0); +} + +// pointer_arg_from_python +// +template <class T> +inline pointer_arg_from_python<T>::pointer_arg_from_python(PyObject* p) + : arg_lvalue_from_python_base( + p == Py_None ? p : converter::get_lvalue_from_python(p, registered_pointee<T>::converters)) +{ +} + +template <class T> +inline T pointer_arg_from_python<T>::operator()() const +{ + return (result() == Py_None) ? 0 : T(result()); +} + +// reference_arg_from_python +// +template <class T> +inline reference_arg_from_python<T>::reference_arg_from_python(PyObject* p) + : arg_lvalue_from_python_base(converter::get_lvalue_from_python(p,registered<T>::converters)) +{ +} + +template <class T> +inline T reference_arg_from_python<T>::operator()() const +{ + return python::detail::void_ptr_to_reference(result(), (T(*)())0); +} + + +// arg_rvalue_from_python +// +template <class T> +inline arg_rvalue_from_python<T>::arg_rvalue_from_python(PyObject* obj) + : m_data(converter::rvalue_from_python_stage1(obj, registered<T>::converters)) + , m_source(obj) +{ +} + +template <class T> +inline bool arg_rvalue_from_python<T>::convertible() const +{ + return m_data.stage1.convertible != 0; +} + +template <class T> +inline typename arg_rvalue_from_python<T>::result_type +arg_rvalue_from_python<T>::operator()() +{ + if (m_data.stage1.construct != 0) + m_data.stage1.construct(m_source, &m_data.stage1); + + return python::detail::void_ptr_to_reference(m_data.stage1.convertible, (result_type(*)())0); +} + +// back_reference_arg_from_python +// +template <class T> +back_reference_arg_from_python<T>::back_reference_arg_from_python(PyObject* x) + : base(x), m_source(x) +{ +} + +template <class T> +inline T +back_reference_arg_from_python<T>::operator()() +{ + return T(m_source, base::operator()()); +} + +}}} // namespace boost::python::converter + +#endif // ARG_FROM_PYTHON_DWA2002127_HPP diff --git a/boost/python/converter/arg_to_python.hpp b/boost/python/converter/arg_to_python.hpp new file mode 100644 index 0000000000..3a19ec4395 --- /dev/null +++ b/boost/python/converter/arg_to_python.hpp @@ -0,0 +1,261 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef ARG_TO_PYTHON_DWA200265_HPP +# define ARG_TO_PYTHON_DWA200265_HPP + +# include <boost/python/ptr.hpp> +# include <boost/python/tag.hpp> +# include <boost/python/to_python_indirect.hpp> + +# include <boost/python/converter/registered.hpp> +# include <boost/python/converter/registered_pointee.hpp> +# include <boost/python/converter/arg_to_python_base.hpp> +# include <boost/python/converter/shared_ptr_to_python.hpp> +// Bring in specializations +# include <boost/python/converter/builtin_converters.hpp> + +# include <boost/python/object/function_handle.hpp> + +# include <boost/python/base_type_traits.hpp> + +# include <boost/python/detail/indirect_traits.hpp> +# include <boost/python/detail/convertible.hpp> +# include <boost/python/detail/string_literal.hpp> +# include <boost/python/detail/value_is_shared_ptr.hpp> + +# include <boost/type_traits/cv_traits.hpp> +# include <boost/type_traits/composite_traits.hpp> +# include <boost/type_traits/function_traits.hpp> + + +# include <boost/mpl/or.hpp> + +namespace boost { namespace python { namespace converter { + +template <class T> struct is_object_manager; + +namespace detail +{ + template <class T> + struct function_arg_to_python : handle<> + { + function_arg_to_python(T const& x); + }; + + template <class T> + struct reference_arg_to_python : handle<> + { + reference_arg_to_python(T& x); + private: + static PyObject* get_object(T& x); + }; + + template <class T> + struct shared_ptr_arg_to_python : handle<> + { + shared_ptr_arg_to_python(T const& x); + private: + static PyObject* get_object(T& x); + }; + + template <class T> + struct value_arg_to_python : arg_to_python_base + { + // Throw an exception if the conversion can't succeed + value_arg_to_python(T const&); + }; + + template <class Ptr> + struct pointer_deep_arg_to_python : arg_to_python_base + { + // Throw an exception if the conversion can't succeed + pointer_deep_arg_to_python(Ptr); + }; + + template <class Ptr> + struct pointer_shallow_arg_to_python : handle<> + { + // Throw an exception if the conversion can't succeed + pointer_shallow_arg_to_python(Ptr); + private: + static PyObject* get_object(Ptr p); + }; + + // Convert types that manage a Python object to_python + template <class T> + struct object_manager_arg_to_python + { + object_manager_arg_to_python(T const& x) : m_src(x) {} + + PyObject* get() const + { + return python::upcast<PyObject>(get_managed_object(m_src, tag)); + } + + private: + T const& m_src; + }; + + template <class T> + struct select_arg_to_python + { + typedef typename unwrap_reference<T>::type unwrapped_referent; + typedef typename unwrap_pointer<T>::type unwrapped_ptr; + + typedef typename mpl::if_< + // Special handling for char const[N]; interpret them as char + // const* for the sake of conversion + python::detail::is_string_literal<T const> + , arg_to_python<char const*> + + , typename mpl::if_< + python::detail::value_is_shared_ptr<T> + , shared_ptr_arg_to_python<T> + + , typename mpl::if_< + mpl::or_< + is_function<T> + , indirect_traits::is_pointer_to_function<T> + , is_member_function_pointer<T> + > + , function_arg_to_python<T> + + , typename mpl::if_< + is_object_manager<T> + , object_manager_arg_to_python<T> + + , typename mpl::if_< + is_pointer<T> + , pointer_deep_arg_to_python<T> + + , typename mpl::if_< + is_pointer_wrapper<T> + , pointer_shallow_arg_to_python<unwrapped_ptr> + + , typename mpl::if_< + is_reference_wrapper<T> + , reference_arg_to_python<unwrapped_referent> + , value_arg_to_python<T> + >::type + >::type + >::type + >::type + >::type + >::type + >::type + + type; + }; +} + +template <class T> +struct arg_to_python + : detail::select_arg_to_python<T>::type +{ + typedef typename detail::select_arg_to_python<T>::type base; + public: // member functions + // Throw an exception if the conversion can't succeed + arg_to_python(T const& x); +}; + +// +// implementations +// +namespace detail +{ + // reject_raw_object_ptr -- cause a compile-time error if the user + // should pass a raw Python object pointer + using python::detail::yes_convertible; + using python::detail::no_convertible; + using python::detail::unspecialized; + + template <class T> struct cannot_convert_raw_PyObject; + + template <class T, class Convertibility> + struct reject_raw_object_helper + { + static void error(Convertibility) + { + cannot_convert_raw_PyObject<T*>::to_python_use_handle_instead(); + } + static void error(...) {} + }; + + template <class T> + inline void reject_raw_object_ptr(T*) + { + reject_raw_object_helper<T,yes_convertible>::error( + python::detail::convertible<PyObject const volatile*>::check((T*)0)); + + typedef typename remove_cv<T>::type value_type; + + reject_raw_object_helper<T,no_convertible>::error( + python::detail::convertible<unspecialized*>::check( + (base_type_traits<value_type>*)0 + )); + } + // --------- + + template <class T> + inline function_arg_to_python<T>::function_arg_to_python(T const& x) + : handle<>(python::objects::make_function_handle(x)) + { + } + + template <class T> + inline value_arg_to_python<T>::value_arg_to_python(T const& x) + : arg_to_python_base(&x, registered<T>::converters) + { + } + + template <class Ptr> + inline pointer_deep_arg_to_python<Ptr>::pointer_deep_arg_to_python(Ptr x) + : arg_to_python_base(x, registered_pointee<Ptr>::converters) + { + detail::reject_raw_object_ptr((Ptr)0); + } + + template <class T> + inline PyObject* reference_arg_to_python<T>::get_object(T& x) + { + to_python_indirect<T&,python::detail::make_reference_holder> convert; + return convert(x); + } + + template <class T> + inline reference_arg_to_python<T>::reference_arg_to_python(T& x) + : handle<>(reference_arg_to_python<T>::get_object(x)) + { + } + + template <class T> + inline shared_ptr_arg_to_python<T>::shared_ptr_arg_to_python(T const& x) + : handle<>(shared_ptr_to_python(x)) + { + } + + template <class Ptr> + inline pointer_shallow_arg_to_python<Ptr>::pointer_shallow_arg_to_python(Ptr x) + : handle<>(pointer_shallow_arg_to_python<Ptr>::get_object(x)) + { + detail::reject_raw_object_ptr((Ptr)0); + } + + template <class Ptr> + inline PyObject* pointer_shallow_arg_to_python<Ptr>::get_object(Ptr x) + { + to_python_indirect<Ptr,python::detail::make_reference_holder> convert; + return convert(x); + } +} + +template <class T> +inline arg_to_python<T>::arg_to_python(T const& x) + : base(x) +{} + +}}} // namespace boost::python::converter + +#endif // ARG_TO_PYTHON_DWA200265_HPP diff --git a/boost/python/converter/arg_to_python_base.hpp b/boost/python/converter/arg_to_python_base.hpp new file mode 100644 index 0000000000..d85b302e48 --- /dev/null +++ b/boost/python/converter/arg_to_python_base.hpp @@ -0,0 +1,32 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef ARG_TO_PYTHON_BASE_DWA200237_HPP +# define ARG_TO_PYTHON_BASE_DWA200237_HPP +# include <boost/python/handle.hpp> + +namespace boost { namespace python { namespace converter { + +struct registration; + +namespace detail +{ + struct BOOST_PYTHON_DECL arg_to_python_base +# if !defined(BOOST_MSVC) || BOOST_MSVC <= 1300 || _MSC_FULL_VER > 13102179 + : handle<> +# endif + { + arg_to_python_base(void const volatile* source, registration const&); +# if defined(BOOST_MSVC) && BOOST_MSVC > 1300 && _MSC_FULL_VER <= 13102179 + PyObject* get() const { return m_ptr.get(); } + PyObject* release() { return m_ptr.release(); } + private: + handle<> m_ptr; +# endif + }; +} + +}}} // namespace boost::python::converter + +#endif // ARG_TO_PYTHON_BASE_DWA200237_HPP diff --git a/boost/python/converter/as_to_python_function.hpp b/boost/python/converter/as_to_python_function.hpp new file mode 100644 index 0000000000..19a3efaafc --- /dev/null +++ b/boost/python/converter/as_to_python_function.hpp @@ -0,0 +1,49 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef AS_TO_PYTHON_FUNCTION_DWA2002121_HPP +# define AS_TO_PYTHON_FUNCTION_DWA2002121_HPP +# include <boost/python/converter/to_python_function_type.hpp> + +namespace boost { namespace python { namespace converter { + +// Given a typesafe to_python conversion function, produces a +// to_python_function_t which can be registered in the usual way. +template <class T, class ToPython> +struct as_to_python_function +{ + // Assertion functions used to prevent wrapping of converters + // which take non-const reference parameters. The T* argument in + // the first overload ensures it isn't used in case T is a + // reference. + template <class U> + static void convert_function_must_take_value_or_const_reference(U(*)(T), int, T* = 0) {} + template <class U> + static void convert_function_must_take_value_or_const_reference(U(*)(T const&), long ...) {} + + static PyObject* convert(void const* x) + { + convert_function_must_take_value_or_const_reference(&ToPython::convert, 1L); + + // Yes, the const_cast below opens a hole in const-correctness, + // but it's needed to convert auto_ptr<U> to python. + // + // How big a hole is it? It allows ToPython::convert() to be + // a function which modifies its argument. The upshot is that + // client converters applied to const objects may invoke + // undefined behavior. The damage, however, is limited by the + // use of the assertion function. Thus, the only way this can + // modify its argument is if T is an auto_ptr-like type. There + // is still a const-correctness hole w.r.t. auto_ptr<U> const, + // but c'est la vie. + return ToPython::convert(*const_cast<T*>(static_cast<T const*>(x))); + } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const * get_pytype() { return ToPython::get_pytype(); } +#endif +}; + +}}} // namespace boost::python::converter + +#endif // AS_TO_PYTHON_FUNCTION_DWA2002121_HPP diff --git a/boost/python/converter/builtin_converters.hpp b/boost/python/converter/builtin_converters.hpp new file mode 100644 index 0000000000..c2e01c03d3 --- /dev/null +++ b/boost/python/converter/builtin_converters.hpp @@ -0,0 +1,190 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef BUILTIN_CONVERTERS_DWA2002124_HPP +# define BUILTIN_CONVERTERS_DWA2002124_HPP +# include <boost/python/detail/prefix.hpp> +# include <boost/python/detail/none.hpp> +# include <boost/python/handle.hpp> +# include <boost/python/ssize_t.hpp> +# include <boost/implicit_cast.hpp> +# include <string> +# include <complex> +# include <boost/limits.hpp> + +// Since all we can use to decide how to convert an object to_python +// is its C++ type, there can be only one such converter for each +// type. Therefore, for built-in conversions we can bypass registry +// lookups using explicit specializations of arg_to_python and +// result_to_python. + +namespace boost { namespace python { + +namespace converter +{ + template <class T> struct arg_to_python; + BOOST_PYTHON_DECL PyObject* do_return_to_python(char); + BOOST_PYTHON_DECL PyObject* do_return_to_python(char const*); + BOOST_PYTHON_DECL PyObject* do_return_to_python(PyObject*); + BOOST_PYTHON_DECL PyObject* do_arg_to_python(PyObject*); +} + +// Provide specializations of to_python_value +template <class T> struct to_python_value; + +namespace detail +{ + // Since there's no registry lookup, always report the existence of + // a converter. + struct builtin_to_python + { + // This information helps make_getter() decide whether to try to + // return an internal reference or not. I don't like it much, + // but it will have to serve for now. + BOOST_STATIC_CONSTANT(bool, uses_registry = false); + }; +} + +// Use expr to create the PyObject corresponding to x +# define BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(T, expr, pytype)\ + template <> struct to_python_value<T&> \ + : detail::builtin_to_python \ + { \ + inline PyObject* operator()(T const& x) const \ + { \ + return (expr); \ + } \ + inline PyTypeObject const* get_pytype() const \ + { \ + return (pytype); \ + } \ + }; \ + template <> struct to_python_value<T const&> \ + : detail::builtin_to_python \ + { \ + inline PyObject* operator()(T const& x) const \ + { \ + return (expr); \ + } \ + inline PyTypeObject const* get_pytype() const \ + { \ + return (pytype); \ + } \ + }; + +# define BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE(T, expr) \ + namespace converter \ + { \ + template <> struct arg_to_python< T > \ + : handle<> \ + { \ + arg_to_python(T const& x) \ + : python::handle<>(expr) {} \ + }; \ + } + +// Specialize argument and return value converters for T using expr +# define BOOST_PYTHON_TO_PYTHON_BY_VALUE(T, expr, pytype) \ + BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(T,expr, pytype) \ + BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE(T,expr) + +// Specialize converters for signed and unsigned T to Python Int +#if PY_VERSION_HEX >= 0x03000000 + +# define BOOST_PYTHON_TO_INT(T) \ + BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, ::PyLong_FromLong(x), &PyLong_Type) \ + BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned T, ::PyLong_FromUnsignedLong(x), &PyLong_Type) + +#else + +# define BOOST_PYTHON_TO_INT(T) \ + BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, ::PyInt_FromLong(x), &PyInt_Type) \ + BOOST_PYTHON_TO_PYTHON_BY_VALUE( \ + unsigned T \ + , static_cast<unsigned long>(x) > static_cast<unsigned long>( \ + (std::numeric_limits<long>::max)()) \ + ? ::PyLong_FromUnsignedLong(x) \ + : ::PyInt_FromLong(x), &PyInt_Type) +#endif + +// Bool is not signed. +#if PY_VERSION_HEX >= 0x02030000 +BOOST_PYTHON_TO_PYTHON_BY_VALUE(bool, ::PyBool_FromLong(x), &PyBool_Type) +#else +BOOST_PYTHON_TO_PYTHON_BY_VALUE(bool, ::PyInt_FromLong(x), &PyInt_Type) +#endif + +// note: handles signed char and unsigned char, but not char (see below) +BOOST_PYTHON_TO_INT(char) + +BOOST_PYTHON_TO_INT(short) +BOOST_PYTHON_TO_INT(int) +BOOST_PYTHON_TO_INT(long) + +# if defined(_MSC_VER) && defined(_WIN64) && PY_VERSION_HEX < 0x03000000 +/* Under 64-bit Windows std::size_t is "unsigned long long". To avoid + getting a Python long for each std::size_t the value is checked before + the conversion. A std::size_t is converted to a simple Python int + if possible; a Python long appears only if the value is too small or + too large to fit into a simple int. */ +BOOST_PYTHON_TO_PYTHON_BY_VALUE( + signed BOOST_PYTHON_LONG_LONG, + ( x < static_cast<signed BOOST_PYTHON_LONG_LONG>( + (std::numeric_limits<long>::min)()) + || x > static_cast<signed BOOST_PYTHON_LONG_LONG>( + (std::numeric_limits<long>::max)())) + ? ::PyLong_FromLongLong(x) + : ::PyInt_FromLong(static_cast<long>(x)), &PyInt_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE( + unsigned BOOST_PYTHON_LONG_LONG, + x > static_cast<unsigned BOOST_PYTHON_LONG_LONG>( + (std::numeric_limits<long>::max)()) + ? ::PyLong_FromUnsignedLongLong(x) + : ::PyInt_FromLong(static_cast<long>(x)), &PyInt_Type) +// +# elif defined(HAVE_LONG_LONG) // using Python's macro instead of Boost's + // - we don't seem to get the config right + // all the time. +BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed BOOST_PYTHON_LONG_LONG, ::PyLong_FromLongLong(x), &PyLong_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned BOOST_PYTHON_LONG_LONG, ::PyLong_FromUnsignedLongLong(x), &PyLong_Type) +# endif + +# undef BOOST_TO_PYTHON_INT + +#if PY_VERSION_HEX >= 0x03000000 +BOOST_PYTHON_TO_PYTHON_BY_VALUE(char, converter::do_return_to_python(x), &PyUnicode_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(char const*, converter::do_return_to_python(x), &PyUnicode_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::string, ::PyUnicode_FromStringAndSize(x.data(),implicit_cast<ssize_t>(x.size())), &PyUnicode_Type) +#else +BOOST_PYTHON_TO_PYTHON_BY_VALUE(char, converter::do_return_to_python(x), &PyString_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(char const*, converter::do_return_to_python(x), &PyString_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::string, ::PyString_FromStringAndSize(x.data(),implicit_cast<ssize_t>(x.size())), &PyString_Type) +#endif + +#if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::wstring, ::PyUnicode_FromWideChar(x.data(),implicit_cast<ssize_t>(x.size())), &PyUnicode_Type) +# endif +BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, ::PyFloat_FromDouble(x), &PyFloat_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, ::PyFloat_FromDouble(x), &PyFloat_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(long double, ::PyFloat_FromDouble(x), &PyFloat_Type) +BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(PyObject*, converter::do_return_to_python(x), 0) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<float>, ::PyComplex_FromDoubles(x.real(), x.imag()), &PyComplex_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<double>, ::PyComplex_FromDoubles(x.real(), x.imag()), &PyComplex_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex<long double>, ::PyComplex_FromDoubles(x.real(), x.imag()), &PyComplex_Type) + +# undef BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE +# undef BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE +# undef BOOST_PYTHON_TO_PYTHON_BY_VALUE +# undef BOOST_PYTHON_TO_INT + +namespace converter +{ + + void initialize_builtin_converters(); + +} + +}} // namespace boost::python::converter + +#endif // BUILTIN_CONVERTERS_DWA2002124_HPP diff --git a/boost/python/converter/constructor_function.hpp b/boost/python/converter/constructor_function.hpp new file mode 100644 index 0000000000..814aa7d763 --- /dev/null +++ b/boost/python/converter/constructor_function.hpp @@ -0,0 +1,17 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef CONSTRUCTOR_FUNCTION_DWA200278_HPP +# define CONSTRUCTOR_FUNCTION_DWA200278_HPP + +namespace boost { namespace python { namespace converter { + +// Declares the type of functions used to construct C++ objects for +// rvalue from_python conversions. +struct rvalue_from_python_stage1_data; +typedef void (*constructor_function)(PyObject* source, rvalue_from_python_stage1_data*); + +}}} // namespace boost::python::converter + +#endif // CONSTRUCTOR_FUNCTION_DWA200278_HPP diff --git a/boost/python/converter/context_result_converter.hpp b/boost/python/converter/context_result_converter.hpp new file mode 100644 index 0000000000..beb7e9f098 --- /dev/null +++ b/boost/python/converter/context_result_converter.hpp @@ -0,0 +1,17 @@ +// Copyright David Abrahams 2003. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef CONTEXT_RESULT_CONVERTER_DWA2003917_HPP +# define CONTEXT_RESULT_CONVERTER_DWA2003917_HPP + +namespace boost { namespace python { namespace converter { + +// A ResultConverter base class used to indicate that this result +// converter should be constructed with the original Python argument +// list. +struct context_result_converter {}; + +}}} // namespace boost::python::converter + +#endif // CONTEXT_RESULT_CONVERTER_DWA2003917_HPP diff --git a/boost/python/converter/convertible_function.hpp b/boost/python/converter/convertible_function.hpp new file mode 100644 index 0000000000..4b29fbb00b --- /dev/null +++ b/boost/python/converter/convertible_function.hpp @@ -0,0 +1,14 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef CONVERTIBLE_FUNCTION_DWA200278_HPP +# define CONVERTIBLE_FUNCTION_DWA200278_HPP + +namespace boost { namespace python { namespace converter { + +typedef void* (*convertible_function)(PyObject*); + +}}} // namespace boost::python::converter + +#endif // CONVERTIBLE_FUNCTION_DWA200278_HPP diff --git a/boost/python/converter/from_python.hpp b/boost/python/converter/from_python.hpp new file mode 100644 index 0000000000..b2f24b3519 --- /dev/null +++ b/boost/python/converter/from_python.hpp @@ -0,0 +1,41 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef FIND_FROM_PYTHON_DWA2002223_HPP +# define FIND_FROM_PYTHON_DWA2002223_HPP + +# include <boost/python/detail/prefix.hpp> +# include <boost/python/converter/rvalue_from_python_data.hpp> + +namespace boost { namespace python { namespace converter { + +struct registration; + + +BOOST_PYTHON_DECL void* get_lvalue_from_python( + PyObject* source, registration const&); + +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( + PyObject* source, registration const&); + +BOOST_PYTHON_DECL void* rvalue_from_python_stage2( + PyObject* source, rvalue_from_python_stage1_data&, registration const&); + +BOOST_PYTHON_DECL void* rvalue_result_from_python( + PyObject*, rvalue_from_python_stage1_data&); + +BOOST_PYTHON_DECL void* reference_result_from_python(PyObject*, registration const&); +BOOST_PYTHON_DECL void* pointer_result_from_python(PyObject*, registration const&); + +BOOST_PYTHON_DECL void void_result_from_python(PyObject*); + +BOOST_PYTHON_DECL void throw_no_pointer_from_python(PyObject*, registration const&); +BOOST_PYTHON_DECL void throw_no_reference_from_python(PyObject*, registration const&); + +}}} // namespace boost::python::converter + +#endif // FIND_FROM_PYTHON_DWA2002223_HPP diff --git a/boost/python/converter/implicit.hpp b/boost/python/converter/implicit.hpp new file mode 100644 index 0000000000..8bbbfd5ac1 --- /dev/null +++ b/boost/python/converter/implicit.hpp @@ -0,0 +1,46 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef IMPLICIT_DWA2002326_HPP +# define IMPLICIT_DWA2002326_HPP + +# include <boost/python/converter/rvalue_from_python_data.hpp> +# include <boost/python/converter/registrations.hpp> +# include <boost/python/converter/registered.hpp> + +# include <boost/python/extract.hpp> + +namespace boost { namespace python { namespace converter { + +template <class Source, class Target> +struct implicit +{ + static void* convertible(PyObject* obj) + { + // 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<Source>::converters) + ? obj : 0; + } + + static void construct(PyObject* obj, rvalue_from_python_stage1_data* data) + { + void* storage = ((rvalue_from_python_storage<Target>*)data)->storage.bytes; + + arg_from_python<Source> get_source(obj); + bool convertible = get_source.convertible(); + BOOST_VERIFY(convertible); + + new (storage) Target(get_source()); + + // record successful construction + data->convertible = storage; + } +}; + +}}} // namespace boost::python::converter + +#endif // IMPLICIT_DWA2002326_HPP diff --git a/boost/python/converter/obj_mgr_arg_from_python.hpp b/boost/python/converter/obj_mgr_arg_from_python.hpp new file mode 100644 index 0000000000..cd4e1e0ea8 --- /dev/null +++ b/boost/python/converter/obj_mgr_arg_from_python.hpp @@ -0,0 +1,121 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef OBJ_MGR_ARG_FROM_PYTHON_DWA2002628_HPP +# define OBJ_MGR_ARG_FROM_PYTHON_DWA2002628_HPP + +# include <boost/python/detail/prefix.hpp> +# include <boost/python/detail/referent_storage.hpp> +# include <boost/python/detail/destroy.hpp> +# include <boost/python/detail/construct.hpp> +# include <boost/python/converter/object_manager.hpp> +# include <boost/python/detail/raw_pyobject.hpp> +# include <boost/python/tag.hpp> + +// +// arg_from_python converters for Python type wrappers, to be used as +// base classes for specializations. +// +namespace boost { namespace python { namespace converter { + +template <class T> +struct object_manager_value_arg_from_python +{ + typedef T result_type; + + object_manager_value_arg_from_python(PyObject*); + bool convertible() const; + T operator()() const; + private: + PyObject* m_source; +}; + +// Used for converting reference-to-object-manager arguments from +// python. The process used here is a little bit odd. Upon +// construction, we build the object manager object in the m_result +// object, *forcing* it to accept the source Python object by casting +// its pointer to detail::borrowed_reference. This is supposed to +// bypass any type checking of the source object. The convertible +// check then extracts the owned object and checks it. If the check +// fails, nothing else in the program ever gets to touch this strange +// "forced" object. +template <class Ref> +struct object_manager_ref_arg_from_python +{ + typedef Ref result_type; + + object_manager_ref_arg_from_python(PyObject*); + bool convertible() const; + Ref operator()() const; + ~object_manager_ref_arg_from_python(); + private: + typename python::detail::referent_storage<Ref>::type m_result; +}; + +// +// implementations +// + +template <class T> +inline object_manager_value_arg_from_python<T>::object_manager_value_arg_from_python(PyObject* x) + : m_source(x) +{ +} + +template <class T> +inline bool object_manager_value_arg_from_python<T>::convertible() const +{ + return object_manager_traits<T>::check(m_source); +} + +template <class T> +inline T object_manager_value_arg_from_python<T>::operator()() const +{ + return T(python::detail::borrowed_reference(m_source)); +} + +template <class Ref> +inline object_manager_ref_arg_from_python<Ref>::object_manager_ref_arg_from_python(PyObject* x) +{ +# if defined(__EDG_VERSION__) && __EDG_VERSION__ <= 243 + // needed for warning suppression + python::detail::borrowed_reference x_ = python::detail::borrowed_reference(x); + python::detail::construct_referent<Ref>(&m_result.bytes, x_); +# else + python::detail::construct_referent<Ref>(&m_result.bytes, (python::detail::borrowed_reference)x); +# endif +} + +template <class Ref> +inline object_manager_ref_arg_from_python<Ref>::~object_manager_ref_arg_from_python() +{ + python::detail::destroy_referent<Ref>(this->m_result.bytes); +} + +namespace detail +{ + template <class T> + inline bool object_manager_ref_check(T const& x) + { + return object_manager_traits<T>::check(get_managed_object(x, tag)); + } +} + +template <class Ref> +inline bool object_manager_ref_arg_from_python<Ref>::convertible() const +{ + return detail::object_manager_ref_check( + python::detail::void_ptr_to_reference(this->m_result.bytes, (Ref(*)())0)); +} + +template <class Ref> +inline Ref object_manager_ref_arg_from_python<Ref>::operator()() const +{ + return python::detail::void_ptr_to_reference( + this->m_result.bytes, (Ref(*)())0); +} + +}}} // namespace boost::python::converter + +#endif // OBJ_MGR_ARG_FROM_PYTHON_DWA2002628_HPP diff --git a/boost/python/converter/object_manager.hpp b/boost/python/converter/object_manager.hpp new file mode 100644 index 0000000000..84e44d475b --- /dev/null +++ b/boost/python/converter/object_manager.hpp @@ -0,0 +1,230 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef OBJECT_MANAGER_DWA2002614_HPP +# define OBJECT_MANAGER_DWA2002614_HPP + +# include <boost/python/handle.hpp> +# include <boost/python/cast.hpp> +# include <boost/python/converter/pyobject_traits.hpp> +# include <boost/type_traits/object_traits.hpp> +# include <boost/mpl/if.hpp> +# include <boost/python/detail/indirect_traits.hpp> +# include <boost/mpl/bool.hpp> + +// Facilities for dealing with types which always manage Python +// objects. Some examples are object, list, str, et. al. Different +// to_python/from_python conversion rules apply here because in +// contrast to other types which are typically embedded inside a +// Python object, these are wrapped around a Python object. For most +// object managers T, a C++ non-const T reference argument does not +// imply the existence of a T lvalue embedded in the corresponding +// Python argument, since mutating member functions on T actually only +// modify the held Python object. +// +// handle<T> is an object manager, though strictly speaking it should +// not be. In other words, even though mutating member functions of +// hanlde<T> actually modify the handle<T> and not the T object, +// handle<T>& arguments of wrapped functions will bind to "rvalues" +// wrapping the actual Python argument, just as with other object +// manager classes. Making an exception for handle<T> is simply not +// worth the trouble. +// +// borrowed<T> cv* is an object manager so that we can use the general +// to_python mechanisms to convert raw Python object pointers to +// python, without the usual semantic problems of using raw pointers. + + +// Object Manager Concept requirements: +// +// T is an Object Manager +// p is a PyObject* +// x is a T +// +// * object_manager_traits<T>::is_specialized == true +// +// * T(detail::borrowed_reference(p)) +// Manages p without checking its type +// +// * get_managed_object(x, boost::python::tag) +// Convertible to PyObject* +// +// Additional requirements if T can be converted from_python: +// +// * T(object_manager_traits<T>::adopt(p)) +// steals a reference to p, or throws a TypeError exception if +// p doesn't have an appropriate type. May assume p is non-null +// +// * X::check(p) +// convertible to bool. True iff T(X::construct(p)) will not +// throw. + +// Forward declarations +// +namespace boost { namespace python +{ + namespace api + { + class object; + } +}} + +namespace boost { namespace python { namespace converter { + + +// Specializations for handle<T> +template <class T> +struct handle_object_manager_traits + : pyobject_traits<typename T::element_type> +{ + private: + typedef pyobject_traits<typename T::element_type> base; + + public: + BOOST_STATIC_CONSTANT(bool, is_specialized = true); + + // Initialize with a null_ok pointer for efficiency, bypassing the + // null check since the source is always non-null. + static null_ok<typename T::element_type>* adopt(PyObject* p) + { + return python::allow_null(base::checked_downcast(p)); + } +}; + +template <class T> +struct default_object_manager_traits +{ + BOOST_STATIC_CONSTANT( + bool, is_specialized = python::detail::is_borrowed_ptr<T>::value + ); +}; + +template <class T> +struct object_manager_traits + : mpl::if_c< + is_handle<T>::value + , handle_object_manager_traits<T> + , default_object_manager_traits<T> + >::type +{ +}; + +// +// Traits for detecting whether a type is an object manager or a +// (cv-qualified) reference to an object manager. +// + +template <class T> +struct is_object_manager + : mpl::bool_<object_manager_traits<T>::is_specialized> +{ +}; + +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template <class T> +struct is_reference_to_object_manager + : mpl::false_ +{ +}; + +template <class T> +struct is_reference_to_object_manager<T&> + : is_object_manager<T> +{ +}; + +template <class T> +struct is_reference_to_object_manager<T const&> + : is_object_manager<T> +{ +}; + +template <class T> +struct is_reference_to_object_manager<T volatile&> + : is_object_manager<T> +{ +}; + +template <class T> +struct is_reference_to_object_manager<T const volatile&> + : is_object_manager<T> +{ +}; +# else + +namespace detail +{ + typedef char (&yes_reference_to_object_manager)[1]; + typedef char (&no_reference_to_object_manager)[2]; + + // A number of nastinesses go on here in order to work around MSVC6 + // bugs. + template <class T> + struct is_object_manager_help + { + typedef typename mpl::if_< + is_object_manager<T> + , yes_reference_to_object_manager + , no_reference_to_object_manager + >::type type; + + // If we just use the type instead of the result of calling this + // function, VC6 will ICE. + static type call(); + }; + + // A set of overloads for each cv-qualification. The same argument + // is passed twice: the first one is used to unwind the cv*, and the + // second one is used to avoid relying on partial ordering for + // overload resolution. + template <class U> + typename is_object_manager_help<U> + is_object_manager_helper(U*, void*); + + template <class U> + typename is_object_manager_help<U> + is_object_manager_helper(U const*, void const*); + + template <class U> + typename is_object_manager_help<U> + is_object_manager_helper(U volatile*, void volatile*); + + template <class U> + typename is_object_manager_help<U> + is_object_manager_helper(U const volatile*, void const volatile*); + + template <class T> + struct is_reference_to_object_manager_nonref + : mpl::false_ + { + }; + + template <class T> + struct is_reference_to_object_manager_ref + { + static T sample_object; + BOOST_STATIC_CONSTANT( + bool, value + = (sizeof(is_object_manager_helper(&sample_object, &sample_object).call()) + == sizeof(detail::yes_reference_to_object_manager) + ) + ); + typedef mpl::bool_<value> type; + }; +} + +template <class T> +struct is_reference_to_object_manager + : mpl::if_< + is_reference<T> + , detail::is_reference_to_object_manager_ref<T> + , detail::is_reference_to_object_manager_nonref<T> + >::type +{ +}; +# endif + +}}} // namespace boost::python::converter + +#endif // OBJECT_MANAGER_DWA2002614_HPP diff --git a/boost/python/converter/pointer_type_id.hpp b/boost/python/converter/pointer_type_id.hpp new file mode 100644 index 0000000000..963f58f717 --- /dev/null +++ b/boost/python/converter/pointer_type_id.hpp @@ -0,0 +1,68 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef POINTER_TYPE_ID_DWA2002222_HPP +# define POINTER_TYPE_ID_DWA2002222_HPP + +# include <boost/python/type_id.hpp> +# include <boost/type_traits/composite_traits.hpp> + +namespace boost { namespace python { namespace converter { + +namespace detail +{ + template <bool is_ref = false> + struct pointer_typeid_select + { + template <class T> + static inline type_info execute(T*(*)() = 0) + { + return type_id<T>(); + } + }; + + template <> + struct pointer_typeid_select<true> + { + template <class T> + static inline type_info execute(T* const volatile&(*)() = 0) + { + return type_id<T>(); + } + + template <class T> + static inline type_info execute(T*volatile&(*)() = 0) + { + return type_id<T>(); + } + + template <class T> + static inline type_info execute(T*const&(*)() = 0) + { + return type_id<T>(); + } + + template <class T> + static inline type_info execute(T*&(*)() = 0) + { + return type_id<T>(); + } + }; +} + +// Usage: pointer_type_id<T>() +// +// Returns a type_info associated with the type pointed +// to by T, which may be a pointer or a reference to a pointer. +template <class T> +type_info pointer_type_id(T(*)() = 0) +{ + return detail::pointer_typeid_select< + is_reference<T>::value + >::execute((T(*)())0); +} + +}}} // namespace boost::python::converter + +#endif // POINTER_TYPE_ID_DWA2002222_HPP diff --git a/boost/python/converter/pyobject_traits.hpp b/boost/python/converter/pyobject_traits.hpp new file mode 100644 index 0000000000..43e384af8d --- /dev/null +++ b/boost/python/converter/pyobject_traits.hpp @@ -0,0 +1,46 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef PYOBJECT_TRAITS_DWA2002720_HPP +# define PYOBJECT_TRAITS_DWA2002720_HPP + +# include <boost/python/detail/prefix.hpp> +# include <boost/python/converter/pyobject_type.hpp> + +namespace boost { namespace python { namespace converter { + +template <class> struct pyobject_traits; + +template <> +struct pyobject_traits<PyObject> +{ + // All objects are convertible to PyObject + static bool check(PyObject*) { return true; } + static PyObject* checked_downcast(PyObject* x) { return x; } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const* get_pytype() { return 0; } +#endif +}; + +// +// Specializations +// + +# define BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(T) \ + template <> struct pyobject_traits<Py##T##Object> \ + : pyobject_type<Py##T##Object, &Py##T##_Type> {} + +// This is not an exhaustive list; should be expanded. +BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Type); +BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(List); +#if PY_VERSION_HEX < 0x03000000 +BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Int); +#endif +BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Long); +BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Dict); +BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Tuple); + +}}} // namespace boost::python::converter + +#endif // PYOBJECT_TRAITS_DWA2002720_HPP diff --git a/boost/python/converter/pyobject_type.hpp b/boost/python/converter/pyobject_type.hpp new file mode 100644 index 0000000000..526f9f9dba --- /dev/null +++ b/boost/python/converter/pyobject_type.hpp @@ -0,0 +1,37 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef PYOBJECT_TYPE_DWA2002720_HPP +# define PYOBJECT_TYPE_DWA2002720_HPP + +# include <boost/python/cast.hpp> + +namespace boost { namespace python { namespace converter { + +BOOST_PYTHON_DECL PyObject* checked_downcast_impl(PyObject*, PyTypeObject*); + +// Used as a base class for specializations which need to provide +// Python type checking capability. +template <class Object, PyTypeObject* pytype> +struct pyobject_type +{ + static bool check(PyObject* x) + { + return ::PyObject_IsInstance(x, (PyObject*)pytype); + } + + static Object* checked_downcast(PyObject* x) + { + return python::downcast<Object>( + (checked_downcast_impl)(x, pytype) + ); + } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const* get_pytype() { return pytype; } +#endif +}; + +}}} // namespace boost::python::converter + +#endif // PYOBJECT_TYPE_DWA2002720_HPP diff --git a/boost/python/converter/pytype_function.hpp b/boost/python/converter/pytype_function.hpp new file mode 100644 index 0000000000..95d0f66d46 --- /dev/null +++ b/boost/python/converter/pytype_function.hpp @@ -0,0 +1,132 @@ +// Copyright David Abrahams 2002, Nikolay Mladenov 2007. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef WRAP_PYTYPE_NM20070606_HPP +# define WRAP_PYTYPE_NM20070606_HPP + +# include <boost/python/detail/prefix.hpp> +# include <boost/python/converter/registered.hpp> +# include <boost/python/detail/unwind_type.hpp> + + +namespace boost { namespace python { + +namespace converter +{ +template <PyTypeObject const* python_type> +struct wrap_pytype +{ + static PyTypeObject const* get_pytype() + { + return python_type; + } +}; + +typedef PyTypeObject const* (*pytype_function)(); + +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + + + +namespace detail +{ +struct unwind_type_id_helper{ + typedef python::type_info result_type; + template <class U> + static result_type execute(U* ){ + return python::type_id<U>(); + } +}; + +template <class T> +inline python::type_info unwind_type_id_(boost::type<T>* = 0, mpl::false_ * =0) +{ + return boost::python::detail::unwind_type<unwind_type_id_helper, T> (); +} + +inline python::type_info unwind_type_id_(boost::type<void>* = 0, mpl::true_* =0) +{ + return type_id<void>(); +} + +template <class T> +inline python::type_info unwind_type_id(boost::type<T>* p= 0) +{ + return unwind_type_id_(p, (mpl::bool_<boost::is_void<T>::value >*)0 ); +} +} + + +template <class T> +struct expected_pytype_for_arg +{ + static PyTypeObject const *get_pytype() + { + const converter::registration *r=converter::registry::query( + detail::unwind_type_id_((boost::type<T>*)0, (mpl::bool_<boost::is_void<T>::value >*)0 ) + ); + return r ? r->expected_from_python_type(): 0; + } +}; + + +template <class T> +struct registered_pytype +{ + static PyTypeObject const *get_pytype() + { + const converter::registration *r=converter::registry::query( + detail::unwind_type_id_((boost::type<T>*) 0, (mpl::bool_<boost::is_void<T>::value >*)0 ) + ); + return r ? r->m_class_object: 0; + } +}; + + +template <class T> +struct registered_pytype_direct +{ + static PyTypeObject const* get_pytype() + { + return registered<T>::converters.m_class_object; + } +}; + +template <class T> +struct expected_from_python_type : expected_pytype_for_arg<T>{}; + +template <class T> +struct expected_from_python_type_direct +{ + static PyTypeObject const* get_pytype() + { + return registered<T>::converters.expected_from_python_type(); + } +}; + +template <class T> +struct to_python_target_type +{ + static PyTypeObject const *get_pytype() + { + const converter::registration *r=converter::registry::query( + detail::unwind_type_id_((boost::type<T>*)0, (mpl::bool_<boost::is_void<T>::value >*)0 ) + ); + return r ? r->to_python_target_type(): 0; + } +}; + +template <class T> +struct to_python_target_type_direct +{ + static PyTypeObject const *get_pytype() + { + return registered<T>::converters.to_python_target_type(); + } +}; +#endif + +}}} // namespace boost::python + +#endif // WRAP_PYTYPE_NM20070606_HPP diff --git a/boost/python/converter/pytype_object_mgr_traits.hpp b/boost/python/converter/pytype_object_mgr_traits.hpp new file mode 100644 index 0000000000..8f5b2b7677 --- /dev/null +++ b/boost/python/converter/pytype_object_mgr_traits.hpp @@ -0,0 +1,42 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef PYTYPE_OBJECT_MANAGER_TRAITS_DWA2002716_HPP +# define PYTYPE_OBJECT_MANAGER_TRAITS_DWA2002716_HPP + +# include <boost/python/detail/prefix.hpp> +# include <boost/python/detail/raw_pyobject.hpp> +# include <boost/python/cast.hpp> +# include <boost/python/converter/pyobject_type.hpp> +# include <boost/python/errors.hpp> + +namespace boost { namespace python { namespace converter { + +// Provide a forward declaration as a convenience for clients, who all +// need it. +template <class T> struct object_manager_traits; + +// Derive specializations of object_manager_traits from this class +// when T is an object manager for a particular Python type hierarchy. +// +template <PyTypeObject* pytype, class T> +struct pytype_object_manager_traits + : pyobject_type<T, pytype> // provides check() +{ + BOOST_STATIC_CONSTANT(bool, is_specialized = true); + static inline python::detail::new_reference adopt(PyObject*); +}; + +// +// implementations +// +template <PyTypeObject* pytype, class T> +inline python::detail::new_reference pytype_object_manager_traits<pytype,T>::adopt(PyObject* x) +{ + return python::detail::new_reference(python::pytype_check(pytype, x)); +} + +}}} // namespace boost::python::converter + +#endif // PYTYPE_OBJECT_MANAGER_TRAITS_DWA2002716_HPP diff --git a/boost/python/converter/registered.hpp b/boost/python/converter/registered.hpp new file mode 100644 index 0000000000..2404cb0ff2 --- /dev/null +++ b/boost/python/converter/registered.hpp @@ -0,0 +1,111 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef REGISTERED_DWA2002710_HPP +# define REGISTERED_DWA2002710_HPP +# include <boost/python/type_id.hpp> +# include <boost/python/converter/registry.hpp> +# include <boost/python/converter/registrations.hpp> +# include <boost/type_traits/transform_traits.hpp> +# include <boost/type_traits/cv_traits.hpp> +# include <boost/type_traits/is_void.hpp> +# include <boost/detail/workaround.hpp> +# include <boost/python/type_id.hpp> +# include <boost/type.hpp> + +namespace boost { + +// You'll see shared_ptr mentioned in this header because we need to +// note which types are shared_ptrs in their registrations, to +// implement special shared_ptr handling for rvalue conversions. +template <class T> class shared_ptr; + +namespace python { namespace converter { + +struct registration; + +namespace detail +{ + template <class T> + struct registered_base + { + static registration const& converters; + }; +} + +template <class T> +struct registered + : detail::registered_base< + typename add_reference< + typename add_cv<T>::type + >::type + > +{ +}; + +# if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + && !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1310)) +// collapses a few more types to the same static instance. MSVC7.1 +// fails to strip cv-qualification from array types in typeid. For +// some reason we can't use this collapse there or array converters +// will not be found. +template <class T> +struct registered<T&> + : registered<T> {}; +# endif + +// +// implementations +// +namespace detail +{ + inline void + register_shared_ptr0(...) + { + } + + template <class T> + inline void + register_shared_ptr0(shared_ptr<T>*) + { + registry::lookup_shared_ptr(type_id<shared_ptr<T> >()); + } + + template <class T> + inline void + register_shared_ptr1(T const volatile*) + { + detail::register_shared_ptr0((T*)0); + } + + template <class T> + inline registration const& + registry_lookup2(T&(*)()) + { + detail::register_shared_ptr1((T*)0); + return registry::lookup(type_id<T&>()); + } + + template <class T> + inline registration const& + registry_lookup1(type<T>) + { + return registry_lookup2((T(*)())0); + } + + inline registration const& + registry_lookup1(type<const volatile void>) + { + detail::register_shared_ptr1((void*)0); + return registry::lookup(type_id<void>()); + } + + template <class T> + registration const& registered_base<T>::converters = detail::registry_lookup1(type<T>()); + +} + +}}} // namespace boost::python::converter + +#endif // REGISTERED_DWA2002710_HPP diff --git a/boost/python/converter/registered_pointee.hpp b/boost/python/converter/registered_pointee.hpp new file mode 100644 index 0000000000..d9e7ac75a8 --- /dev/null +++ b/boost/python/converter/registered_pointee.hpp @@ -0,0 +1,62 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef REGISTERED_POINTEE_DWA2002710_HPP +# define REGISTERED_POINTEE_DWA2002710_HPP +# include <boost/python/converter/registered.hpp> +# include <boost/python/converter/pointer_type_id.hpp> +# include <boost/python/converter/registry.hpp> +# include <boost/type_traits/transform_traits.hpp> +# include <boost/type_traits/cv_traits.hpp> + +namespace boost { namespace python { namespace converter { + +struct registration; + +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template <class T> +struct registered_pointee + : registered< + typename remove_pointer< + typename remove_cv< + typename remove_reference<T>::type + >::type + >::type + > +{ +}; +# else +namespace detail +{ + template <class T> + struct registered_pointee_base + { + static registration const& converters; + }; +} + +template <class T> +struct registered_pointee + : detail::registered_pointee_base< + typename add_reference< + typename add_cv<T>::type + >::type + > +{ +}; + +// +// implementations +// +namespace detail +{ + template <class T> + registration const& registered_pointee_base<T>::converters + = registry::lookup(pointer_type_id<T>()); +} + +# endif +}}} // namespace boost::python::converter + +#endif // REGISTERED_POINTEE_DWA2002710_HPP diff --git a/boost/python/converter/registrations.hpp b/boost/python/converter/registrations.hpp new file mode 100644 index 0000000000..7ef74e8f40 --- /dev/null +++ b/boost/python/converter/registrations.hpp @@ -0,0 +1,99 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef REGISTRATIONS_DWA2002223_HPP +# define REGISTRATIONS_DWA2002223_HPP + +# include <boost/python/detail/prefix.hpp> + +# include <boost/python/type_id.hpp> + +# include <boost/python/converter/convertible_function.hpp> +# include <boost/python/converter/constructor_function.hpp> +# include <boost/python/converter/to_python_function_type.hpp> + +# include <boost/detail/workaround.hpp> + +namespace boost { namespace python { namespace converter { + +struct lvalue_from_python_chain +{ + convertible_function convert; + lvalue_from_python_chain* next; +}; + +struct rvalue_from_python_chain +{ + convertible_function convertible; + constructor_function construct; + PyTypeObject const* (*expected_pytype)(); + rvalue_from_python_chain* next; +}; + +struct BOOST_PYTHON_DECL registration +{ + public: // member functions + explicit registration(type_info target, bool is_shared_ptr = false); + ~registration(); + + // Convert the appropriately-typed data to Python + PyObject* to_python(void const volatile*) const; + + // Return the class object, or raise an appropriate Python + // exception if no class has been registered. + PyTypeObject* get_class_object() const; + + // Return common denominator of the python class objects, + // convertable to target. Inspects the m_class_object and the value_chains. + PyTypeObject const* expected_from_python_type() const; + PyTypeObject const* to_python_target_type() const; + + public: // data members. So sue me. + const python::type_info target_type; + + // The chain of eligible from_python converters when an lvalue is required + lvalue_from_python_chain* lvalue_chain; + + // The chain of eligible from_python converters when an rvalue is acceptable + rvalue_from_python_chain* rvalue_chain; + + // The class object associated with this type + PyTypeObject* m_class_object; + + // The unique to_python converter for the associated C++ type. + to_python_function_t m_to_python; + PyTypeObject const* (*m_to_python_target_type)(); + + + // True iff this type is a shared_ptr. Needed for special rvalue + // from_python handling. + const bool is_shared_ptr; + +# if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) + private: + void operator=(registration); // This is not defined, and just keeps MWCW happy. +# endif +}; + +// +// implementations +// +inline registration::registration(type_info target_type, bool is_shared_ptr) + : target_type(target_type) + , lvalue_chain(0) + , rvalue_chain(0) + , m_class_object(0) + , m_to_python(0) + , m_to_python_target_type(0) + , is_shared_ptr(is_shared_ptr) +{} + +inline bool operator<(registration const& lhs, registration const& rhs) +{ + return lhs.target_type < rhs.target_type; +} + +}}} // namespace boost::python::converter + +#endif // REGISTRATIONS_DWA2002223_HPP diff --git a/boost/python/converter/registry.hpp b/boost/python/converter/registry.hpp new file mode 100644 index 0000000000..368adcc61d --- /dev/null +++ b/boost/python/converter/registry.hpp @@ -0,0 +1,55 @@ +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef REGISTRY_DWA20011127_HPP +# define REGISTRY_DWA20011127_HPP +# include <boost/python/type_id.hpp> +# include <boost/python/converter/to_python_function_type.hpp> +# include <boost/python/converter/rvalue_from_python_data.hpp> +# include <boost/python/converter/constructor_function.hpp> +# include <boost/python/converter/convertible_function.hpp> + +namespace boost { namespace python { namespace converter { + +struct registration; + +// This namespace acts as a sort of singleton +namespace registry +{ + // Get the registration corresponding to the type, creating it if necessary + BOOST_PYTHON_DECL registration const& lookup(type_info); + + // Get the registration corresponding to the type, creating it if + // necessary. Use this first when the type is a shared_ptr. + BOOST_PYTHON_DECL registration const& lookup_shared_ptr(type_info); + + // Return a pointer to the corresponding registration, if one exists + BOOST_PYTHON_DECL registration const* query(type_info); + + BOOST_PYTHON_DECL void insert(to_python_function_t, type_info, PyTypeObject const* (*to_python_target_type)() = 0); + + // Insert an lvalue from_python converter + BOOST_PYTHON_DECL void insert(convertible_function, type_info, PyTypeObject const* (*expected_pytype)() = 0); + + // Insert an rvalue from_python converter + BOOST_PYTHON_DECL void insert( + convertible_function + , constructor_function + , type_info + , PyTypeObject const* (*expected_pytype)() = 0 + ); + + // Insert an rvalue from_python converter at the tail of the + // chain. Used for implicit conversions + BOOST_PYTHON_DECL void push_back( + convertible_function + , constructor_function + , type_info + , PyTypeObject const* (*expected_pytype)() = 0 + ); +} + +}}} // namespace boost::python::converter + +#endif // REGISTRY_DWA20011127_HPP diff --git a/boost/python/converter/return_from_python.hpp b/boost/python/converter/return_from_python.hpp new file mode 100644 index 0000000000..5db9748545 --- /dev/null +++ b/boost/python/converter/return_from_python.hpp @@ -0,0 +1,162 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef RETURN_FROM_PYTHON_DWA200265_HPP +# define RETURN_FROM_PYTHON_DWA200265_HPP + +# include <boost/python/converter/from_python.hpp> +# include <boost/python/converter/rvalue_from_python_data.hpp> +# include <boost/python/converter/registered.hpp> +# include <boost/python/converter/registered_pointee.hpp> +# include <boost/python/converter/object_manager.hpp> +# include <boost/python/detail/void_ptr.hpp> +# include <boost/python/detail/void_return.hpp> +# include <boost/python/errors.hpp> +# include <boost/python/handle.hpp> +# include <boost/type_traits/has_trivial_copy.hpp> +# include <boost/mpl/and.hpp> +# include <boost/mpl/bool.hpp> + +namespace boost { namespace python { namespace converter { + +template <class T> struct is_object_manager; + +namespace detail +{ + template <class T> + struct return_pointer_from_python + { + typedef T result_type; + T operator()(PyObject*) const; + }; + + template <class T> + struct return_reference_from_python + { + typedef T result_type; + T operator()(PyObject*) const; + }; + + template <class T> + struct return_rvalue_from_python + { + typedef T result_type; + + return_rvalue_from_python(); + result_type operator()(PyObject*); + private: + rvalue_from_python_data<T> m_data; + }; + + template <class T> + struct return_object_manager_from_python + { + typedef T result_type; + result_type operator()(PyObject*) const; + }; + + template <class T> + struct select_return_from_python + { + BOOST_STATIC_CONSTANT( + bool, obj_mgr = is_object_manager<T>::value); + + BOOST_STATIC_CONSTANT( + bool, ptr = is_pointer<T>::value); + + BOOST_STATIC_CONSTANT( + bool, ref = is_reference<T>::value); + + typedef typename mpl::if_c< + obj_mgr + , return_object_manager_from_python<T> + , typename mpl::if_c< + ptr + , return_pointer_from_python<T> + , typename mpl::if_c< + ref + , return_reference_from_python<T> + , return_rvalue_from_python<T> + >::type + >::type + >::type type; + }; +} + +template <class T> +struct return_from_python + : detail::select_return_from_python<T>::type +{ +}; + +// Specialization as a convenience for call and call_method +template <> +struct return_from_python<void> +{ + typedef python::detail::returnable<void>::type result_type; + + result_type operator()(PyObject* x) const + { + (void_result_from_python)(x); +# ifdef BOOST_NO_VOID_RETURNS + return result_type(); +# endif + } +}; + +// +// Implementations +// +namespace detail +{ + template <class T> + inline return_rvalue_from_python<T>::return_rvalue_from_python() + : m_data( + const_cast<registration*>(®istered<T>::converters) + ) + { + } + + template <class T> + inline typename return_rvalue_from_python<T>::result_type + return_rvalue_from_python<T>::operator()(PyObject* obj) + { + // Take possession of the source object here. If the result is in + // fact going to be a copy of an lvalue embedded in the object, + // and we take possession inside rvalue_result_from_python, it + // will be destroyed too early. + handle<> holder(obj); + + return *(T*) + (rvalue_result_from_python)(obj, m_data.stage1); + } + + template <class T> + inline T return_reference_from_python<T>::operator()(PyObject* obj) const + { + return python::detail::void_ptr_to_reference( + (reference_result_from_python)(obj, registered<T>::converters) + , (T(*)())0); + } + + template <class T> + inline T return_pointer_from_python<T>::operator()(PyObject* obj) const + { + return T( + (pointer_result_from_python)(obj, registered_pointee<T>::converters) + ); + } + + template <class T> + inline T return_object_manager_from_python<T>::operator()(PyObject* obj) const + { + return T( + object_manager_traits<T>::adopt(expect_non_null(obj)) + ); + } +} + +}}} // namespace boost::python::converter + +#endif // RETURN_FROM_PYTHON_DWA200265_HPP diff --git a/boost/python/converter/rvalue_from_python_data.hpp b/boost/python/converter/rvalue_from_python_data.hpp new file mode 100644 index 0000000000..471a5255b6 --- /dev/null +++ b/boost/python/converter/rvalue_from_python_data.hpp @@ -0,0 +1,140 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef FROM_PYTHON_AUX_DATA_DWA2002128_HPP +# define FROM_PYTHON_AUX_DATA_DWA2002128_HPP + +# include <boost/python/converter/constructor_function.hpp> +# include <boost/python/detail/referent_storage.hpp> +# include <boost/python/detail/destroy.hpp> +# include <boost/static_assert.hpp> +# include <boost/type_traits/add_reference.hpp> +# include <boost/type_traits/add_cv.hpp> +# include <cstddef> + +// Data management for potential rvalue conversions from Python to C++ +// types. When a client requests a conversion to T* or T&, we +// generally require that an object of type T exists in the source +// Python object, and the code here does not apply**. This implements +// conversions which may create new temporaries of type T. The classic +// example is a conversion which converts a Python tuple to a +// std::vector. Since no std::vector lvalue exists in the Python +// object -- it must be created "on-the-fly" by the converter, and +// which must manage the lifetime of the created object. +// +// Note that the client is not precluded from using a registered +// lvalue conversion to T in this case. In other words, we will +// happily accept a Python object which /does/ contain a std::vector +// lvalue, provided an appropriate converter is registered. So, while +// this is an rvalue conversion from the client's point-of-view, the +// converter registry may serve up lvalue or rvalue conversions for +// the target type. +// +// ** C++ argument from_python conversions to T const& are an +// exception to the rule for references: since in C++, const +// references can bind to temporary rvalues, we allow rvalue +// converters to be chosen when the target type is T const& for some +// T. +namespace boost { namespace python { namespace converter { + +// Conversions begin by filling in and returning a copy of this +// structure. The process looks up a converter in the rvalue converter +// registry for the target type. It calls the convertible() function +// of each registered converter, passing the source PyObject* as an +// argument, until a non-null result is returned. This result goes in +// the convertible field, and the converter's construct() function is +// stored in the construct field. +// +// If no appropriate converter is found, conversion fails and the +// convertible field is null. When used in argument conversion for +// wrapped C++ functions, it causes overload resolution to reject the +// current function but not to fail completely. If an exception is +// thrown, overload resolution stops and the exception propagates back +// through the caller. +// +// If an lvalue converter is matched, its convertible() function is +// expected to return a pointer to the stored T object; its +// construct() function will be NULL. The convertible() function of +// rvalue converters may return any non-singular pointer; the actual +// target object will only be available once the converter's +// construct() function is called. +struct rvalue_from_python_stage1_data +{ + void* convertible; + constructor_function construct; +}; + +// Augments rvalue_from_python_stage1_data by adding storage for +// constructing an object of remove_reference<T>::type. The +// construct() function of rvalue converters (stored in m_construct +// above) will cast the rvalue_from_python_stage1_data to an +// appropriate instantiation of this template in order to access that +// storage. +template <class T> +struct rvalue_from_python_storage +{ + rvalue_from_python_stage1_data stage1; + + // Storage for the result, in case an rvalue must be constructed + typename python::detail::referent_storage< + typename add_reference<T>::type + >::type storage; +}; + +// Augments rvalue_from_python_storage<T> with a destructor. If +// stage1.convertible == storage.bytes, it indicates that an object of +// remove_reference<T>::type has been constructed in storage and +// should will be destroyed in ~rvalue_from_python_data(). It is +// crucial that successful rvalue conversions establish this equality +// and that unsuccessful ones do not. +template <class T> +struct rvalue_from_python_data : rvalue_from_python_storage<T> +{ +# if (!defined(__MWERKS__) || __MWERKS__ >= 0x3000) \ + && (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 245) \ + && (!defined(__DECCXX_VER) || __DECCXX_VER > 60590014) \ + && !defined(BOOST_PYTHON_SYNOPSIS) /* Synopsis' OpenCXX has trouble parsing this */ + // This must always be a POD struct with m_data its first member. + BOOST_STATIC_ASSERT(BOOST_PYTHON_OFFSETOF(rvalue_from_python_storage<T>,stage1) == 0); +# endif + + // The usual constructor + rvalue_from_python_data(rvalue_from_python_stage1_data const&); + + // This constructor just sets m_convertible -- used by + // implicitly_convertible<> to perform the final step of the + // conversion, where the construct() function is already known. + rvalue_from_python_data(void* convertible); + + // Destroys any object constructed in the storage. + ~rvalue_from_python_data(); + private: + typedef typename add_reference<typename add_cv<T>::type>::type ref_type; +}; + +// +// Implementataions +// +template <class T> +inline rvalue_from_python_data<T>::rvalue_from_python_data(rvalue_from_python_stage1_data const& _stage1) +{ + this->stage1 = _stage1; +} + +template <class T> +inline rvalue_from_python_data<T>::rvalue_from_python_data(void* convertible) +{ + this->stage1.convertible = convertible; +} + +template <class T> +inline rvalue_from_python_data<T>::~rvalue_from_python_data() +{ + if (this->stage1.convertible == this->storage.bytes) + python::detail::destroy_referent<ref_type>(this->storage.bytes); +} + +}}} // namespace boost::python::converter + +#endif // FROM_PYTHON_AUX_DATA_DWA2002128_HPP diff --git a/boost/python/converter/shared_ptr_deleter.hpp b/boost/python/converter/shared_ptr_deleter.hpp new file mode 100644 index 0000000000..926508d00e --- /dev/null +++ b/boost/python/converter/shared_ptr_deleter.hpp @@ -0,0 +1,22 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef SHARED_PTR_DELETER_DWA2002121_HPP +# define SHARED_PTR_DELETER_DWA2002121_HPP + +namespace boost { namespace python { namespace converter { + +struct BOOST_PYTHON_DECL shared_ptr_deleter +{ + shared_ptr_deleter(handle<> owner); + ~shared_ptr_deleter(); + + void operator()(void const*); + + handle<> owner; +}; + +}}} // namespace boost::python::converter + +#endif // SHARED_PTR_DELETER_DWA2002121_HPP diff --git a/boost/python/converter/shared_ptr_from_python.hpp b/boost/python/converter/shared_ptr_from_python.hpp new file mode 100644 index 0000000000..c09107765c --- /dev/null +++ b/boost/python/converter/shared_ptr_from_python.hpp @@ -0,0 +1,63 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef SHARED_PTR_FROM_PYTHON_DWA20021130_HPP +# define SHARED_PTR_FROM_PYTHON_DWA20021130_HPP + +# include <boost/python/handle.hpp> +# include <boost/python/converter/shared_ptr_deleter.hpp> +# include <boost/python/converter/from_python.hpp> +# include <boost/python/converter/rvalue_from_python_data.hpp> +# include <boost/python/converter/registered.hpp> +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +# include <boost/python/converter/pytype_function.hpp> +#endif +# include <boost/shared_ptr.hpp> + +namespace boost { namespace python { namespace converter { + +template <class T> +struct shared_ptr_from_python +{ + shared_ptr_from_python() + { + converter::registry::insert(&convertible, &construct, type_id<shared_ptr<T> >() +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + , &converter::expected_from_python_type_direct<T>::get_pytype +#endif + ); + } + + private: + static void* convertible(PyObject* p) + { + if (p == Py_None) + return p; + + return converter::get_lvalue_from_python(p, registered<T>::converters); + } + + static void construct(PyObject* source, rvalue_from_python_stage1_data* data) + { + void* const storage = ((converter::rvalue_from_python_storage<shared_ptr<T> >*)data)->storage.bytes; + // Deal with the "None" case. + if (data->convertible == source) + new (storage) shared_ptr<T>(); + else + { + boost::shared_ptr<void> hold_convertible_ref_count( + (void*)0, shared_ptr_deleter(handle<>(borrowed(source))) ); + // use aliasing constructor + new (storage) shared_ptr<T>( + hold_convertible_ref_count, + static_cast<T*>(data->convertible)); + } + + data->convertible = storage; + } +}; + +}}} // namespace boost::python::converter + +#endif // SHARED_PTR_FROM_PYTHON_DWA20021130_HPP diff --git a/boost/python/converter/shared_ptr_to_python.hpp b/boost/python/converter/shared_ptr_to_python.hpp new file mode 100644 index 0000000000..fe867ace13 --- /dev/null +++ b/boost/python/converter/shared_ptr_to_python.hpp @@ -0,0 +1,28 @@ +// Copyright David Abrahams 2003. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef SHARED_PTR_TO_PYTHON_DWA2003224_HPP +# define SHARED_PTR_TO_PYTHON_DWA2003224_HPP + +# include <boost/python/refcount.hpp> +# include <boost/python/converter/shared_ptr_deleter.hpp> +# include <boost/shared_ptr.hpp> +# include <boost/get_pointer.hpp> + +namespace boost { namespace python { namespace converter { + +template <class T> +PyObject* shared_ptr_to_python(shared_ptr<T> const& x) +{ + if (!x) + return python::detail::none(); + else if (shared_ptr_deleter* d = boost::get_deleter<shared_ptr_deleter>(x)) + return incref( get_pointer( d->owner ) ); + else + return converter::registered<shared_ptr<T> const&>::converters.to_python(&x); +} + +}}} // namespace boost::python::converter + +#endif // SHARED_PTR_TO_PYTHON_DWA2003224_HPP diff --git a/boost/python/converter/to_python_function_type.hpp b/boost/python/converter/to_python_function_type.hpp new file mode 100644 index 0000000000..cccd014d68 --- /dev/null +++ b/boost/python/converter/to_python_function_type.hpp @@ -0,0 +1,19 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef TO_PYTHON_FUNCTION_TYPE_DWA200236_HPP +# define TO_PYTHON_FUNCTION_TYPE_DWA200236_HPP +# include <boost/python/detail/prefix.hpp> +# include <boost/static_assert.hpp> + +namespace boost { namespace python { namespace converter { + +// The type of stored function pointers which actually do conversion +// by-value. The void* points to the object to be converted, and +// type-safety is preserved through runtime registration. +typedef PyObject* (*to_python_function_t)(void const*); + +}}} // namespace boost::python::converter + +#endif // TO_PYTHON_FUNCTION_TYPE_DWA200236_HPP |