Chris@16: // (C) Copyright 2006 Douglas Gregor Chris@16: Chris@16: // Use, modification and distribution is subject to the Boost Software Chris@16: // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // Authors: Douglas Gregor Chris@16: #ifndef BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP Chris@16: #define BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP Chris@16: Chris@16: /** @file skeleton_and_content.hpp Chris@16: * Chris@16: * This file reflects the skeleton/content facilities into Python. Chris@16: */ Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #define BOOST_MPI_PYTHON_FORWARD_ONLY Chris@16: #include Chris@16: #include Chris@16: Chris@16: Chris@16: namespace boost { namespace mpi { namespace python { Chris@16: Chris@16: /** Chris@16: * INTERNAL ONLY Chris@16: * Chris@16: * This @c content class is a wrapper around the C++ "content" Chris@16: * retrieved from get_content. This wrapper is only needed to store a Chris@16: * copy of the Python object on which get_content() was called. Chris@16: */ Chris@16: class content : public boost::mpi::content Chris@16: { Chris@16: typedef boost::mpi::content inherited; Chris@16: Chris@16: public: Chris@16: content(const inherited& base, boost::python::object object) Chris@16: : inherited(base), object(object) { } Chris@16: Chris@16: inherited& base() { return *this; } Chris@16: const inherited& base() const { return *this; } Chris@16: Chris@16: boost::python::object object; Chris@16: }; Chris@16: Chris@16: /** Chris@16: * INTERNAL ONLY Chris@16: * Chris@16: * A class specific to the Python bindings that mimics the behavior of Chris@16: * the skeleton_proxy template. In the case of Python skeletons, we Chris@16: * only need to know the object (and its type) to transmit the Chris@16: * skeleton. This is the only user-visible skeleton proxy type, Chris@16: * although instantiations of its derived classes (@c Chris@16: * skeleton_proxy) will be returned from the Python skeleton() Chris@16: * function. Chris@16: */ Chris@16: class skeleton_proxy_base Chris@16: { Chris@16: public: Chris@16: skeleton_proxy_base(const boost::python::object& object) : object(object) { } Chris@16: Chris@16: boost::python::object object; Chris@16: }; Chris@16: Chris@16: /** Chris@16: * INTERNAL ONLY Chris@16: * Chris@16: * The templated @c skeleton_proxy class represents a skeleton proxy Chris@16: * in Python. The only data is stored in the @c skeleton_proxy_base Chris@16: * class (which is the type actually exposed as @c skeleton_proxy in Chris@16: * Python). However, the type of @c skeleton_proxy is important for Chris@16: * (de-)serialization of @c skeleton_proxy's for transmission. Chris@16: */ Chris@16: template Chris@16: class skeleton_proxy : public skeleton_proxy_base Chris@16: { Chris@16: public: Chris@16: skeleton_proxy(const boost::python::object& object) Chris@16: : skeleton_proxy_base(object) { } Chris@16: }; Chris@16: Chris@16: namespace detail { Chris@16: using boost::python::object; Chris@16: using boost::python::extract; Chris@16: Chris@16: extern BOOST_MPI_DECL boost::python::object skeleton_proxy_base_type; Chris@16: Chris@16: template Chris@16: struct skeleton_saver Chris@16: { Chris@16: void Chris@16: operator()(packed_oarchive& ar, const object& obj, const unsigned int) Chris@16: { Chris@16: packed_skeleton_oarchive pso(ar); Chris@16: pso << extract(obj.attr("object"))(); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct skeleton_loader Chris@16: { Chris@16: void Chris@16: operator()(packed_iarchive& ar, object& obj, const unsigned int) Chris@16: { Chris@16: packed_skeleton_iarchive psi(ar); Chris@16: extract&> proxy(obj); Chris@16: if (!proxy.check()) Chris@16: obj = object(skeleton_proxy(object(T()))); Chris@16: Chris@16: psi >> extract(obj.attr("object"))(); Chris@16: } Chris@16: }; Chris@16: Chris@16: /** Chris@16: * The @c skeleton_content_handler structure contains all of the Chris@16: * information required to extract a skeleton and content from a Chris@16: * Python object with a certain C++ type. Chris@16: */ Chris@16: struct skeleton_content_handler { Chris@16: function1 get_skeleton_proxy; Chris@16: function1 get_content; Chris@16: }; Chris@16: Chris@16: /** Chris@16: * A function object that extracts the skeleton from of a Python Chris@16: * object, which is actually a wrapped C++ object of type T. Chris@16: */ Chris@16: template Chris@16: struct do_get_skeleton_proxy Chris@16: { Chris@16: object operator()(object value) { Chris@16: return object(skeleton_proxy(value)); Chris@16: } Chris@16: }; Chris@16: Chris@16: /** Chris@16: * A function object that extracts the content of a Python object, Chris@16: * which is actually a wrapped C++ object of type T. Chris@16: */ Chris@16: template Chris@16: struct do_get_content Chris@16: { Chris@16: content operator()(object value_obj) { Chris@16: T& value = extract(value_obj)(); Chris@16: return content(boost::mpi::get_content(value), value_obj); Chris@16: } Chris@16: }; Chris@16: Chris@16: /** Chris@16: * Determine if a skeleton and content handler for @p type has Chris@16: * already been registered. Chris@16: */ Chris@16: BOOST_MPI_PYTHON_DECL bool Chris@16: skeleton_and_content_handler_registered(PyTypeObject* type); Chris@16: Chris@16: /** Chris@16: * Register a skeleton/content handler with a particular Python type Chris@16: * (which actually wraps a C++ type). Chris@16: */ Chris@16: BOOST_MPI_PYTHON_DECL void Chris@16: register_skeleton_and_content_handler(PyTypeObject*, Chris@16: const skeleton_content_handler&); Chris@16: } // end namespace detail Chris@16: Chris@16: template Chris@16: void register_skeleton_and_content(const T& value, PyTypeObject* type) Chris@16: { Chris@16: using boost::python::detail::direct_serialization_table; Chris@16: using boost::python::detail::get_direct_serialization_table; Chris@16: using namespace boost::python; Chris@16: Chris@16: // Determine the type Chris@16: if (!type) Chris@16: type = object(value).ptr()->ob_type; Chris@16: Chris@16: // Don't re-register the same type. Chris@16: if (detail::skeleton_and_content_handler_registered(type)) Chris@16: return; Chris@16: Chris@16: // Register the skeleton proxy type Chris@16: { Chris@16: boost::python::scope proxy_scope(detail::skeleton_proxy_base_type); Chris@16: std::string name("skeleton_proxy<"); Chris@16: name += typeid(T).name(); Chris@16: name += ">"; Chris@16: class_, bases >(name.c_str(), Chris@16: no_init); Chris@16: } Chris@16: Chris@16: // Register the saver and loader for the associated skeleton and Chris@16: // proxy, to allow (de-)serialization of skeletons via the proxy. Chris@16: direct_serialization_table& table = Chris@16: get_direct_serialization_table(); Chris@16: table.register_type(detail::skeleton_saver(), Chris@16: detail::skeleton_loader(), Chris@16: skeleton_proxy(object(value))); Chris@16: Chris@16: // Register the rest of the skeleton/content mechanism, including Chris@16: // handlers that extract a skeleton proxy from a Python object and Chris@16: // extract the content from a Python object. Chris@16: detail::skeleton_content_handler handler; Chris@16: handler.get_skeleton_proxy = detail::do_get_skeleton_proxy(); Chris@16: handler.get_content = detail::do_get_content(); Chris@16: detail::register_skeleton_and_content_handler(type, handler); Chris@16: } Chris@16: Chris@16: } } } // end namespace boost::mpi::python Chris@16: Chris@16: #endif // BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP