Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:40:58

0001 // (C) Copyright 2006 Douglas Gregor <doug.gregor -at- gmail.com>
0002 
0003 // Use, modification and distribution is subject to the Boost Software
0004 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 //  Authors: Douglas Gregor
0008 #ifndef BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP
0009 #define BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP
0010 
0011 /** @file skeleton_and_content.hpp
0012  *
0013  *  This file reflects the skeleton/content facilities into Python.
0014  */
0015 #include <boost/python.hpp>
0016 #include <boost/mpi.hpp>
0017 #include <boost/function/function1.hpp>
0018 #define BOOST_MPI_PYTHON_FORWARD_ONLY
0019 #include <boost/mpi/python.hpp>
0020 #include <boost/mpi/python/serialize.hpp>
0021 
0022 
0023 namespace boost { namespace mpi { namespace python {
0024 
0025 /**
0026  * INTERNAL ONLY
0027  *
0028  * This @c content class is a wrapper around the C++ "content"
0029  * retrieved from get_content. This wrapper is only needed to store a
0030  * copy of the Python object on which get_content() was called.
0031  */
0032 class content : public boost::mpi::content
0033 {
0034   typedef boost::mpi::content inherited;
0035 
0036  public:
0037   content(const inherited& base, boost::python::object object) 
0038     : inherited(base), object(object) { }
0039 
0040   inherited&       base()       { return *this; }
0041   const inherited& base() const { return *this; }
0042 
0043   boost::python::object object;
0044 };
0045 
0046 /**
0047  * INTERNAL ONLY
0048  *
0049  * A class specific to the Python bindings that mimics the behavior of
0050  * the skeleton_proxy<T> template. In the case of Python skeletons, we
0051  * only need to know the object (and its type) to transmit the
0052  * skeleton. This is the only user-visible skeleton proxy type,
0053  * although instantiations of its derived classes (@c
0054  * skeleton_proxy<T>) will be returned from the Python skeleton()
0055  * function.
0056  */
0057 class skeleton_proxy_base 
0058 {
0059 public:
0060   skeleton_proxy_base(const boost::python::object& object) : object(object) { }
0061 
0062   boost::python::object object;
0063 };
0064 
0065 /**
0066  * INTERNAL ONLY
0067  *
0068  * The templated @c skeleton_proxy class represents a skeleton proxy
0069  * in Python. The only data is stored in the @c skeleton_proxy_base
0070  * class (which is the type actually exposed as @c skeleton_proxy in
0071  * Python). However, the type of @c skeleton_proxy<T> is important for
0072  * (de-)serialization of @c skeleton_proxy<T>'s for transmission.
0073  */
0074 template<typename T>
0075 class skeleton_proxy : public skeleton_proxy_base
0076 {
0077  public:
0078   skeleton_proxy(const boost::python::object& object) 
0079     : skeleton_proxy_base(object) { }
0080 };
0081 
0082 namespace detail {
0083   using boost::python::object;
0084   using boost::python::extract;
0085    
0086   extern BOOST_MPI_DECL boost::python::object skeleton_proxy_base_type;
0087 
0088   template<typename T>
0089   struct skeleton_saver
0090   {
0091     void 
0092     operator()(packed_oarchive& ar, const object& obj, const unsigned int)
0093     {
0094       packed_skeleton_oarchive pso(ar);
0095       pso << extract<T&>(obj.attr("object"))();
0096     }
0097   };
0098 
0099   template<typename T> 
0100   struct skeleton_loader
0101   {
0102     void 
0103     operator()(packed_iarchive& ar, object& obj, const unsigned int)
0104     {
0105       packed_skeleton_iarchive psi(ar);
0106       extract<skeleton_proxy<T>&> proxy(obj);
0107       if (!proxy.check())
0108         obj = object(skeleton_proxy<T>(object(T())));
0109 
0110       psi >> extract<T&>(obj.attr("object"))();
0111     }
0112   };
0113 
0114   /**
0115    * The @c skeleton_content_handler structure contains all of the
0116    * information required to extract a skeleton and content from a
0117    * Python object with a certain C++ type.
0118    */
0119   struct skeleton_content_handler {
0120     function1<object, const object&> get_skeleton_proxy;
0121     function1<content, const object&> get_content;
0122   };
0123 
0124   /**
0125    * A function object that extracts the skeleton from of a Python
0126    * object, which is actually a wrapped C++ object of type T.
0127    */
0128   template<typename T>
0129   struct do_get_skeleton_proxy
0130   {
0131     object operator()(object value) {
0132       return object(skeleton_proxy<T>(value));
0133     }
0134   };
0135 
0136   /**
0137    * A function object that extracts the content of a Python object,
0138    * which is actually a wrapped C++ object of type T.
0139    */
0140   template<typename T>
0141   struct do_get_content
0142   {
0143     content operator()(object value_obj) {
0144       T& value = extract<T&>(value_obj)();
0145       return content(boost::mpi::get_content(value), value_obj);
0146     }
0147   };
0148 
0149   /**
0150    * Determine if a skeleton and content handler for @p type has
0151    * already been registered.
0152    */
0153   BOOST_MPI_PYTHON_DECL bool
0154   skeleton_and_content_handler_registered(PyTypeObject* type);
0155  
0156   /**
0157    * Register a skeleton/content handler with a particular Python type
0158    * (which actually wraps a C++ type).
0159    */
0160   BOOST_MPI_PYTHON_DECL void 
0161   register_skeleton_and_content_handler(PyTypeObject*, 
0162                                         const skeleton_content_handler&);
0163 } // end namespace detail
0164 
0165 template<typename T>
0166 void register_skeleton_and_content(const T& value, PyTypeObject* type)
0167 {
0168   using boost::python::detail::direct_serialization_table;
0169   using boost::python::detail::get_direct_serialization_table;
0170   using namespace boost::python;
0171 
0172   // Determine the type
0173   if (!type)
0174     type = object(value).ptr()->ob_type;
0175 
0176   // Don't re-register the same type.
0177   if (detail::skeleton_and_content_handler_registered(type))
0178     return;
0179 
0180   // Register the skeleton proxy type
0181   {
0182     boost::python::scope proxy_scope(detail::skeleton_proxy_base_type);
0183     std::string name("skeleton_proxy<");
0184     name += typeid(T).name();
0185     name += ">";
0186     class_<skeleton_proxy<T>, bases<skeleton_proxy_base> >(name.c_str(), 
0187                                                            no_init);
0188   }
0189 
0190   // Register the saver and loader for the associated skeleton and
0191   // proxy, to allow (de-)serialization of skeletons via the proxy.
0192   direct_serialization_table<packed_iarchive, packed_oarchive>& table = 
0193     get_direct_serialization_table<packed_iarchive, packed_oarchive>();
0194   table.register_type(detail::skeleton_saver<T>(), 
0195                       detail::skeleton_loader<T>(), 
0196                       skeleton_proxy<T>(object(value)));
0197 
0198   // Register the rest of the skeleton/content mechanism, including
0199   // handlers that extract a skeleton proxy from a Python object and
0200   // extract the content from a Python object.
0201   detail::skeleton_content_handler handler;
0202   handler.get_skeleton_proxy = detail::do_get_skeleton_proxy<T>();
0203   handler.get_content = detail::do_get_content<T>();
0204   detail::register_skeleton_and_content_handler(type, handler);
0205 }
0206 
0207 } } } // end namespace boost::mpi::python
0208 
0209 #endif // BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP