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