PageRenderTime 44ms CodeModel.GetById 14ms app.highlight 22ms RepoModel.GetById 4ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/mpi/python/skeleton_and_content.hpp

http://hadesmem.googlecode.com/
C++ Header | 209 lines | 114 code | 30 blank | 65 comment | 3 complexity | 793c8b21d9af80c6bb4e437600138bdf MD5 | raw file
  1// (C) Copyright 2006 Douglas Gregor <doug.gregor -at- gmail.com>
  2
  3// Use, modification and distribution is subject to the Boost Software
  4// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5// http://www.boost.org/LICENSE_1_0.txt)
  6
  7//  Authors: Douglas Gregor
  8#ifndef BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP
  9#define BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP
 10
 11/** @file skeleton_and_content.hpp
 12 *
 13 *  This file reflects the skeleton/content facilities into Python.
 14 */
 15#include <boost/python.hpp>
 16#include <boost/mpi.hpp>
 17#include <boost/function/function1.hpp>
 18#define BOOST_MPI_PYTHON_FORWARD_ONLY
 19#include <boost/mpi/python.hpp>
 20#include <boost/mpi/python/serialize.hpp>
 21
 22
 23namespace boost { namespace mpi { namespace python {
 24
 25/**
 26 * INTERNAL ONLY
 27 *
 28 * This @c content class is a wrapper around the C++ "content"
 29 * retrieved from get_content. This wrapper is only needed to store a
 30 * copy of the Python object on which get_content() was called.
 31 */
 32class content : public boost::mpi::content
 33{
 34  typedef boost::mpi::content inherited;
 35
 36 public:
 37  content(const inherited& base, boost::python::object object) 
 38    : inherited(base), object(object) { }
 39
 40  inherited&       base()       { return *this; }
 41  const inherited& base() const { return *this; }
 42
 43  boost::python::object object;
 44};
 45
 46/**
 47 * INTERNAL ONLY
 48 *
 49 * A class specific to the Python bindings that mimics the behavior of
 50 * the skeleton_proxy<T> template. In the case of Python skeletons, we
 51 * only need to know the object (and its type) to transmit the
 52 * skeleton. This is the only user-visible skeleton proxy type,
 53 * although instantiations of its derived classes (@c
 54 * skeleton_proxy<T>) will be returned from the Python skeleton()
 55 * function.
 56 */
 57class skeleton_proxy_base 
 58{
 59public:
 60  skeleton_proxy_base(const boost::python::object& object) : object(object) { }
 61
 62  boost::python::object object;
 63};
 64
 65/**
 66 * INTERNAL ONLY
 67 *
 68 * The templated @c skeleton_proxy class represents a skeleton proxy
 69 * in Python. The only data is stored in the @c skeleton_proxy_base
 70 * class (which is the type actually exposed as @c skeleton_proxy in
 71 * Python). However, the type of @c skeleton_proxy<T> is important for
 72 * (de-)serialization of @c skeleton_proxy<T>'s for transmission.
 73 */
 74template<typename T>
 75class skeleton_proxy : public skeleton_proxy_base
 76{
 77 public:
 78  skeleton_proxy(const boost::python::object& object) 
 79    : skeleton_proxy_base(object) { }
 80};
 81
 82namespace detail {
 83  using boost::python::object;
 84  using boost::python::extract;
 85   
 86  extern BOOST_MPI_DECL boost::python::object skeleton_proxy_base_type;
 87
 88  template<typename T>
 89  struct skeleton_saver
 90  {
 91    void 
 92    operator()(packed_oarchive& ar, const object& obj, const unsigned int)
 93    {
 94      packed_skeleton_oarchive pso(ar);
 95      pso << extract<T&>(obj.attr("object"))();
 96    }
 97  };
 98
 99  template<typename T> 
100  struct skeleton_loader
101  {
102    void 
103    operator()(packed_iarchive& ar, object& obj, const unsigned int)
104    {
105      packed_skeleton_iarchive psi(ar);
106      extract<skeleton_proxy<T>&> proxy(obj);
107      if (!proxy.check())
108        obj = object(skeleton_proxy<T>(object(T())));
109
110      psi >> extract<T&>(obj.attr("object"))();
111    }
112  };
113
114  /**
115   * The @c skeleton_content_handler structure contains all of the
116   * information required to extract a skeleton and content from a
117   * Python object with a certain C++ type.
118   */
119  struct skeleton_content_handler {
120    function1<object, const object&> get_skeleton_proxy;
121    function1<content, const object&> get_content;
122  };
123
124  /**
125   * A function object that extracts the skeleton from of a Python
126   * object, which is actually a wrapped C++ object of type T.
127   */
128  template<typename T>
129  struct do_get_skeleton_proxy
130  {
131    object operator()(object value) {
132      return object(skeleton_proxy<T>(value));
133    }
134  };
135
136  /**
137   * A function object that extracts the content of a Python object,
138   * which is actually a wrapped C++ object of type T.
139   */
140  template<typename T>
141  struct do_get_content
142  {
143    content operator()(object value_obj) {
144      T& value = extract<T&>(value_obj)();
145      return content(boost::mpi::get_content(value), value_obj);
146    }
147  };
148
149  /**
150   * Determine if a skeleton and content handler for @p type has
151   * already been registered.
152   */
153  BOOST_MPI_PYTHON_DECL bool
154  skeleton_and_content_handler_registered(PyTypeObject* type);
155 
156  /**
157   * Register a skeleton/content handler with a particular Python type
158   * (which actually wraps a C++ type).
159   */
160  BOOST_MPI_PYTHON_DECL void 
161  register_skeleton_and_content_handler(PyTypeObject*, 
162                                        const skeleton_content_handler&);
163} // end namespace detail
164
165template<typename T>
166void register_skeleton_and_content(const T& value, PyTypeObject* type)
167{
168  using boost::python::detail::direct_serialization_table;
169  using boost::python::detail::get_direct_serialization_table;
170  using namespace boost::python;
171
172  // Determine the type
173  if (!type)
174    type = object(value).ptr()->ob_type;
175
176  // Don't re-register the same type.
177  if (detail::skeleton_and_content_handler_registered(type))
178    return;
179
180  // Register the skeleton proxy type
181  {
182    boost::python::scope proxy_scope(detail::skeleton_proxy_base_type);
183    std::string name("skeleton_proxy<");
184    name += typeid(T).name();
185    name += ">";
186    class_<skeleton_proxy<T>, bases<skeleton_proxy_base> >(name.c_str(), 
187                                                           no_init);
188  }
189
190  // Register the saver and loader for the associated skeleton and
191  // proxy, to allow (de-)serialization of skeletons via the proxy.
192  direct_serialization_table<packed_iarchive, packed_oarchive>& table = 
193    get_direct_serialization_table<packed_iarchive, packed_oarchive>();
194  table.register_type(detail::skeleton_saver<T>(), 
195                      detail::skeleton_loader<T>(), 
196                      skeleton_proxy<T>(object(value)));
197
198  // Register the rest of the skeleton/content mechanism, including
199  // handlers that extract a skeleton proxy from a Python object and
200  // extract the content from a Python object.
201  detail::skeleton_content_handler handler;
202  handler.get_skeleton_proxy = detail::do_get_skeleton_proxy<T>();
203  handler.get_content = detail::do_get_content<T>();
204  detail::register_skeleton_and_content_handler(type, handler);
205}
206
207} } } // end namespace boost::mpi::python
208
209#endif // BOOST_MPI_PYTHON_SKELETON_AND_CONTENT_HPP