Chris@16
|
1 // Copyright (C) 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
|
Chris@16
|
9 /** @file serialize.hpp
|
Chris@16
|
10 *
|
Chris@16
|
11 * This file provides Boost.Serialization support for Python objects
|
Chris@16
|
12 * within Boost.MPI. Python objects can be serialized in one of two
|
Chris@16
|
13 * ways. The default serialization method involves using the Python
|
Chris@16
|
14 * "pickle" module to pickle the Python objects, transmits the
|
Chris@16
|
15 * pickled representation, and unpickles the result when
|
Chris@16
|
16 * received. For C++ types that have been exposed to Python and
|
Chris@16
|
17 * registered with register_serialized(), objects are directly
|
Chris@16
|
18 * serialized for transmissing, skipping the pickling step.
|
Chris@16
|
19 */
|
Chris@16
|
20 #ifndef BOOST_MPI_PYTHON_SERIALIZE_HPP
|
Chris@16
|
21 #define BOOST_MPI_PYTHON_SERIALIZE_HPP
|
Chris@16
|
22
|
Chris@16
|
23 #include <boost/mpi/python/config.hpp>
|
Chris@16
|
24
|
Chris@16
|
25 #include <boost/python/object.hpp>
|
Chris@16
|
26 #include <boost/python/str.hpp>
|
Chris@16
|
27 #include <boost/python/extract.hpp>
|
Chris@16
|
28
|
Chris@16
|
29 #include <memory>
|
Chris@16
|
30 #include <map>
|
Chris@16
|
31
|
Chris@16
|
32 #include <boost/function/function3.hpp>
|
Chris@16
|
33
|
Chris@16
|
34 #include <boost/mpl/bool.hpp>
|
Chris@16
|
35 #include <boost/mpl/if.hpp>
|
Chris@16
|
36
|
Chris@16
|
37 #include <boost/serialization/split_free.hpp>
|
Chris@16
|
38 #include <boost/serialization/array.hpp>
|
Chris@16
|
39
|
Chris@16
|
40 #include <boost/assert.hpp>
|
Chris@16
|
41
|
Chris@16
|
42 #include <boost/type_traits/is_fundamental.hpp>
|
Chris@16
|
43
|
Chris@16
|
44 #define BOOST_MPI_PYTHON_FORWARD_ONLY
|
Chris@16
|
45 #include <boost/mpi/python.hpp>
|
Chris@16
|
46
|
Chris@16
|
47 /************************************************************************
|
Chris@16
|
48 * Boost.Python Serialization Section *
|
Chris@16
|
49 ************************************************************************/
|
Chris@16
|
50 #if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE)
|
Chris@16
|
51 /**
|
Chris@16
|
52 * @brief Declare IArchive and OArchive as a Boost.Serialization
|
Chris@16
|
53 * archives that can be used for Python objects.
|
Chris@16
|
54 *
|
Chris@16
|
55 * This macro can only be expanded from the global namespace. It only
|
Chris@16
|
56 * requires that Archiver be forward-declared. IArchiver and OArchiver
|
Chris@16
|
57 * will only support Serialization of Python objects by pickling
|
Chris@16
|
58 * them. If the Archiver type should also support "direct"
|
Chris@16
|
59 * serialization (for C++ types), use
|
Chris@16
|
60 * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE instead.
|
Chris@16
|
61 */
|
Chris@16
|
62 # define BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \
|
Chris@16
|
63 namespace boost { namespace python { namespace api { \
|
Chris@16
|
64 template<typename R, typename T> \
|
Chris@16
|
65 struct enable_binary< IArchiver , R, T> {}; \
|
Chris@16
|
66 \
|
Chris@16
|
67 template<typename R, typename T> \
|
Chris@16
|
68 struct enable_binary< OArchiver , R, T> {}; \
|
Chris@16
|
69 } } }
|
Chris@16
|
70 # else
|
Chris@16
|
71 # define BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver)
|
Chris@16
|
72 #endif
|
Chris@16
|
73
|
Chris@16
|
74 /**
|
Chris@16
|
75 * @brief Declare IArchiver and OArchiver as a Boost.Serialization
|
Chris@16
|
76 * archives that can be used for Python objects and C++ objects
|
Chris@16
|
77 * wrapped in Python.
|
Chris@16
|
78 *
|
Chris@16
|
79 * This macro can only be expanded from the global namespace. It only
|
Chris@16
|
80 * requires that IArchiver and OArchiver be forward-declared. However,
|
Chris@16
|
81 * note that you will also need to write
|
Chris@16
|
82 * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL(IArchiver,
|
Chris@16
|
83 * OArchiver) in one of your translation units.
|
Chris@16
|
84
|
Chris@16
|
85 DPG PICK UP HERE
|
Chris@16
|
86 */
|
Chris@16
|
87 #define BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \
|
Chris@16
|
88 BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \
|
Chris@16
|
89 namespace boost { namespace python { namespace detail { \
|
Chris@16
|
90 template<> \
|
Chris@16
|
91 BOOST_MPI_PYTHON_DECL direct_serialization_table< IArchiver , OArchiver >& \
|
Chris@16
|
92 get_direct_serialization_table< IArchiver , OArchiver >(); \
|
Chris@16
|
93 } \
|
Chris@16
|
94 \
|
Chris@16
|
95 template<> \
|
Chris@16
|
96 struct has_direct_serialization< IArchiver , OArchiver> : mpl::true_ { }; \
|
Chris@16
|
97 \
|
Chris@16
|
98 template<> \
|
Chris@16
|
99 struct output_archiver< IArchiver > { typedef OArchiver type; }; \
|
Chris@16
|
100 \
|
Chris@16
|
101 template<> \
|
Chris@16
|
102 struct input_archiver< OArchiver > { typedef IArchiver type; }; \
|
Chris@16
|
103 } }
|
Chris@16
|
104
|
Chris@16
|
105 /**
|
Chris@16
|
106 * @brief Define the implementation for Boost.Serialization archivers
|
Chris@16
|
107 * that can be used for Python objects and C++ objects wrapped in
|
Chris@16
|
108 * Python.
|
Chris@16
|
109 *
|
Chris@16
|
110 * This macro can only be expanded from the global namespace. It only
|
Chris@16
|
111 * requires that IArchiver and OArchiver be forward-declared. Before
|
Chris@16
|
112 * using this macro, you will need to declare IArchiver and OArchiver
|
Chris@16
|
113 * as direct serialization archives with
|
Chris@16
|
114 * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE(IArchiver, OArchiver).
|
Chris@16
|
115 */
|
Chris@16
|
116 #define BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL(IArchiver, OArchiver) \
|
Chris@16
|
117 namespace boost { namespace python { namespace detail { \
|
Chris@16
|
118 template \
|
Chris@16
|
119 class BOOST_MPI_PYTHON_DECL direct_serialization_table< IArchiver , OArchiver >; \
|
Chris@16
|
120 \
|
Chris@16
|
121 template<> \
|
Chris@16
|
122 BOOST_MPI_PYTHON_DECL \
|
Chris@16
|
123 direct_serialization_table< IArchiver , OArchiver >& \
|
Chris@16
|
124 get_direct_serialization_table< IArchiver , OArchiver >( ) \
|
Chris@16
|
125 { \
|
Chris@16
|
126 static direct_serialization_table< IArchiver, OArchiver > table; \
|
Chris@16
|
127 return table; \
|
Chris@16
|
128 } \
|
Chris@16
|
129 } } }
|
Chris@16
|
130
|
Chris@16
|
131 namespace boost { namespace python {
|
Chris@16
|
132
|
Chris@16
|
133 /**
|
Chris@16
|
134 * INTERNAL ONLY
|
Chris@16
|
135 *
|
Chris@16
|
136 * Provides access to the Python "pickle" module from within C++.
|
Chris@16
|
137 */
|
Chris@16
|
138 class BOOST_MPI_PYTHON_DECL pickle {
|
Chris@16
|
139 struct data_t;
|
Chris@16
|
140
|
Chris@16
|
141 public:
|
Chris@16
|
142 static str dumps(object obj, int protocol = -1);
|
Chris@16
|
143 static object loads(str s);
|
Chris@16
|
144
|
Chris@16
|
145 private:
|
Chris@16
|
146 static void initialize_data();
|
Chris@16
|
147
|
Chris@16
|
148 static data_t* data;
|
Chris@16
|
149 };
|
Chris@16
|
150
|
Chris@16
|
151 /**
|
Chris@16
|
152 * @brief Whether the input/output archiver pair has "direct"
|
Chris@16
|
153 * serialization for C++ objects exposed in Python.
|
Chris@16
|
154 *
|
Chris@16
|
155 * Users do not typically need to specialize this trait, as it will be
|
Chris@16
|
156 * specialized as part of the macro
|
Chris@16
|
157 * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE.
|
Chris@16
|
158 */
|
Chris@16
|
159 template<typename IArchiver, typename OArchiver>
|
Chris@16
|
160 struct has_direct_serialization : mpl::false_ { };
|
Chris@16
|
161
|
Chris@16
|
162 /**
|
Chris@16
|
163 * @brief A metafunction that determines the output archiver for the
|
Chris@16
|
164 * given input archiver.
|
Chris@16
|
165 *
|
Chris@16
|
166 * Users do not typically need to specialize this trait, as it will be
|
Chris@16
|
167 * specialized as part of the macro
|
Chris@16
|
168 * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE.
|
Chris@16
|
169 */
|
Chris@16
|
170 template<typename IArchiver> struct output_archiver { };
|
Chris@16
|
171
|
Chris@16
|
172 /**
|
Chris@16
|
173 * @brief A metafunction that determines the input archiver for the
|
Chris@16
|
174 * given output archiver.
|
Chris@16
|
175 *
|
Chris@16
|
176 * Users do not typically need to specialize this trait, as it will be
|
Chris@16
|
177 * specialized as part of the macro
|
Chris@16
|
178 * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE.
|
Chris@16
|
179 *
|
Chris@16
|
180 */
|
Chris@16
|
181 template<typename OArchiver> struct input_archiver { };
|
Chris@16
|
182
|
Chris@16
|
183 namespace detail {
|
Chris@16
|
184
|
Chris@16
|
185 /**
|
Chris@16
|
186 * INTERNAL ONLY
|
Chris@16
|
187 *
|
Chris@16
|
188 * This class contains the direct-serialization code for the given
|
Chris@16
|
189 * IArchiver/OArchiver pair. It is intended to be used as a
|
Chris@16
|
190 * singleton class, and will be accessed when (de-)serializing a
|
Chris@16
|
191 * Boost.Python object with an archiver that supports direct
|
Chris@16
|
192 * serializations. Do not create instances of this class directly:
|
Chris@16
|
193 * instead, use get_direct_serialization_table.
|
Chris@16
|
194 */
|
Chris@16
|
195 template<typename IArchiver, typename OArchiver>
|
Chris@16
|
196 class BOOST_MPI_PYTHON_DECL direct_serialization_table
|
Chris@16
|
197 {
|
Chris@16
|
198 public:
|
Chris@16
|
199 typedef boost::function3<void, OArchiver&, const object&, const unsigned int>
|
Chris@16
|
200 saver_t;
|
Chris@16
|
201 typedef boost::function3<void, IArchiver&, object&, const unsigned int>
|
Chris@16
|
202 loader_t;
|
Chris@16
|
203
|
Chris@16
|
204 typedef std::map<PyTypeObject*, std::pair<int, saver_t> > savers_t;
|
Chris@16
|
205 typedef std::map<int, loader_t> loaders_t;
|
Chris@16
|
206
|
Chris@16
|
207 /**
|
Chris@16
|
208 * Retrieve the saver (serializer) associated with the Python
|
Chris@16
|
209 * object @p obj.
|
Chris@16
|
210 *
|
Chris@16
|
211 * @param obj The object we want to save. Only its (Python) type
|
Chris@16
|
212 * is important.
|
Chris@16
|
213 *
|
Chris@16
|
214 * @param descriptor The value of the descriptor associated to
|
Chris@16
|
215 * the returned saver. Will be set to zero if no saver was found
|
Chris@16
|
216 * for @p obj.
|
Chris@16
|
217 *
|
Chris@16
|
218 * @returns a function object that can be used to serialize this
|
Chris@16
|
219 * object (and other objects of the same type), if possible. If
|
Chris@16
|
220 * no saver can be found, returns an empty function object..
|
Chris@16
|
221 */
|
Chris@16
|
222 saver_t saver(const object& obj, int& descriptor)
|
Chris@16
|
223 {
|
Chris@16
|
224 typename savers_t::iterator pos = savers.find(obj.ptr()->ob_type);
|
Chris@16
|
225 if (pos != savers.end()) {
|
Chris@16
|
226 descriptor = pos->second.first;
|
Chris@16
|
227 return pos->second.second;
|
Chris@16
|
228 }
|
Chris@16
|
229 else {
|
Chris@16
|
230 descriptor = 0;
|
Chris@16
|
231 return saver_t();
|
Chris@16
|
232 }
|
Chris@16
|
233 }
|
Chris@16
|
234
|
Chris@16
|
235 /**
|
Chris@16
|
236 * Retrieve the loader (deserializer) associated with the given
|
Chris@16
|
237 * descriptor.
|
Chris@16
|
238 *
|
Chris@16
|
239 * @param descriptor The descriptor number provided by saver()
|
Chris@16
|
240 * when determining the saver for this type.
|
Chris@16
|
241 *
|
Chris@16
|
242 * @returns a function object that can be used to deserialize an
|
Chris@16
|
243 * object whose type is the same as that corresponding to the
|
Chris@16
|
244 * descriptor. If the descriptor is unknown, the return value
|
Chris@16
|
245 * will be an empty function object.
|
Chris@16
|
246 */
|
Chris@16
|
247 loader_t loader(int descriptor)
|
Chris@16
|
248 {
|
Chris@16
|
249 typename loaders_t::iterator pos = loaders.find(descriptor);
|
Chris@16
|
250 if (pos != loaders.end())
|
Chris@16
|
251 return pos->second;
|
Chris@16
|
252 else
|
Chris@16
|
253 return loader_t();
|
Chris@16
|
254 }
|
Chris@16
|
255
|
Chris@16
|
256 /**
|
Chris@16
|
257 * Register the type T for direct serialization.
|
Chris@16
|
258 *
|
Chris@16
|
259 * @param value A sample value of the type @c T. This may be used
|
Chris@16
|
260 * to compute the Python type associated with the C++ type @c T.
|
Chris@16
|
261 *
|
Chris@16
|
262 * @param type The Python type associated with the C++ type @c
|
Chris@16
|
263 * T. If not provided, it will be computed from the same value @p
|
Chris@16
|
264 * value.
|
Chris@16
|
265 */
|
Chris@16
|
266 template<typename T>
|
Chris@16
|
267 void register_type(const T& value = T(), PyTypeObject* type = 0)
|
Chris@16
|
268 {
|
Chris@16
|
269 // If the user did not provide us with a Python type, figure it
|
Chris@16
|
270 // out for ourselves.
|
Chris@16
|
271 if (!type) {
|
Chris@16
|
272 object obj(value);
|
Chris@16
|
273 type = obj.ptr()->ob_type;
|
Chris@16
|
274 }
|
Chris@16
|
275
|
Chris@16
|
276 register_type(default_saver<T>(), default_loader<T>(type), value, type);
|
Chris@16
|
277 }
|
Chris@16
|
278
|
Chris@16
|
279 /**
|
Chris@16
|
280 * Register the type T for direct serialization.
|
Chris@16
|
281 *
|
Chris@16
|
282 * @param saver A function object that will serialize a
|
Chris@16
|
283 * Boost.Python object (that represents a C++ object of type @c
|
Chris@16
|
284 * T) to an @c OArchive.
|
Chris@16
|
285 *
|
Chris@16
|
286 * @param loader A function object that will deserialize from an
|
Chris@16
|
287 * @c IArchive into a Boost.Python object that represents a C++
|
Chris@16
|
288 * object of type @c T.
|
Chris@16
|
289 *
|
Chris@16
|
290 * @param value A sample value of the type @c T. This may be used
|
Chris@16
|
291 * to compute the Python type associated with the C++ type @c T.
|
Chris@16
|
292 *
|
Chris@16
|
293 * @param type The Python type associated with the C++ type @c
|
Chris@16
|
294 * T. If not provided, it will be computed from the same value @p
|
Chris@16
|
295 * value.
|
Chris@16
|
296 */
|
Chris@16
|
297 template<typename T>
|
Chris@16
|
298 void register_type(const saver_t& saver, const loader_t& loader,
|
Chris@16
|
299 const T& value = T(), PyTypeObject* type = 0)
|
Chris@16
|
300 {
|
Chris@16
|
301 // If the user did not provide us with a Python type, figure it
|
Chris@16
|
302 // out for ourselves.
|
Chris@16
|
303 if (!type) {
|
Chris@16
|
304 object obj(value);
|
Chris@16
|
305 type = obj.ptr()->ob_type;
|
Chris@16
|
306 }
|
Chris@16
|
307
|
Chris@16
|
308 int descriptor = savers.size() + 1;
|
Chris@16
|
309 if (savers.find(type) != savers.end())
|
Chris@16
|
310 return;
|
Chris@16
|
311
|
Chris@16
|
312 savers[type] = std::make_pair(descriptor, saver);
|
Chris@16
|
313 loaders[descriptor] = loader;
|
Chris@16
|
314 }
|
Chris@16
|
315
|
Chris@16
|
316 protected:
|
Chris@16
|
317 template<typename T>
|
Chris@16
|
318 struct default_saver {
|
Chris@16
|
319 void operator()(OArchiver& ar, const object& obj, const unsigned int) {
|
Chris@16
|
320 T value = extract<T>(obj)();
|
Chris@16
|
321 ar << value;
|
Chris@16
|
322 }
|
Chris@16
|
323 };
|
Chris@16
|
324
|
Chris@16
|
325 template<typename T>
|
Chris@16
|
326 struct default_loader {
|
Chris@16
|
327 default_loader(PyTypeObject* type) : type(type) { }
|
Chris@16
|
328
|
Chris@16
|
329 void operator()(IArchiver& ar, object& obj, const unsigned int) {
|
Chris@16
|
330 // If we can, extract the object in place.
|
Chris@16
|
331 if (!is_fundamental<T>::value && obj && obj.ptr()->ob_type == type) {
|
Chris@16
|
332 ar >> extract<T&>(obj)();
|
Chris@16
|
333 } else {
|
Chris@16
|
334 T value;
|
Chris@16
|
335 ar >> value;
|
Chris@16
|
336 obj = object(value);
|
Chris@16
|
337 }
|
Chris@16
|
338 }
|
Chris@16
|
339
|
Chris@16
|
340 private:
|
Chris@16
|
341 PyTypeObject* type;
|
Chris@16
|
342 };
|
Chris@16
|
343
|
Chris@16
|
344 savers_t savers;
|
Chris@16
|
345 loaders_t loaders;
|
Chris@16
|
346 };
|
Chris@16
|
347
|
Chris@16
|
348 /**
|
Chris@16
|
349 * @brief Retrieve the direct-serialization table for an
|
Chris@16
|
350 * IArchiver/OArchiver pair.
|
Chris@16
|
351 *
|
Chris@16
|
352 * This function is responsible for returning a reference to the
|
Chris@16
|
353 * singleton direct-serialization table. Its primary template is
|
Chris@16
|
354 * left undefined, to force the use of an explicit specialization
|
Chris@16
|
355 * with a definition in a single translation unit. Use the macro
|
Chris@16
|
356 * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL to define this
|
Chris@16
|
357 * explicit specialization.
|
Chris@16
|
358 */
|
Chris@16
|
359 template<typename IArchiver, typename OArchiver>
|
Chris@16
|
360 direct_serialization_table<IArchiver, OArchiver>&
|
Chris@16
|
361 get_direct_serialization_table();
|
Chris@16
|
362 } // end namespace detail
|
Chris@16
|
363
|
Chris@16
|
364 /**
|
Chris@16
|
365 * @brief Register the type T for direct serialization.
|
Chris@16
|
366 *
|
Chris@16
|
367 * The @c register_serialized function registers a C++ type for direct
|
Chris@16
|
368 * serialization with the given @c IArchiver/@c OArchiver pair. Direct
|
Chris@16
|
369 * serialization elides the use of the Python @c pickle package when
|
Chris@16
|
370 * serializing Python objects that represent C++ values. Direct
|
Chris@16
|
371 * serialization can be beneficial both to improve serialization
|
Chris@16
|
372 * performance (Python pickling can be very inefficient) and to permit
|
Chris@16
|
373 * serialization for Python-wrapped C++ objects that do not support
|
Chris@16
|
374 * pickling.
|
Chris@16
|
375 *
|
Chris@16
|
376 * @param value A sample value of the type @c T. This may be used
|
Chris@16
|
377 * to compute the Python type associated with the C++ type @c T.
|
Chris@16
|
378 *
|
Chris@16
|
379 * @param type The Python type associated with the C++ type @c
|
Chris@16
|
380 * T. If not provided, it will be computed from the same value @p
|
Chris@16
|
381 * value.
|
Chris@16
|
382 */
|
Chris@16
|
383 template<typename IArchiver, typename OArchiver, typename T>
|
Chris@16
|
384 void
|
Chris@16
|
385 register_serialized(const T& value = T(), PyTypeObject* type = 0)
|
Chris@16
|
386 {
|
Chris@16
|
387 detail::direct_serialization_table<IArchiver, OArchiver>& table =
|
Chris@16
|
388 detail::get_direct_serialization_table<IArchiver, OArchiver>();
|
Chris@16
|
389 table.register_type(value, type);
|
Chris@16
|
390 }
|
Chris@16
|
391
|
Chris@16
|
392 namespace detail {
|
Chris@16
|
393
|
Chris@16
|
394 /// Save a Python object by pickling it.
|
Chris@16
|
395 template<typename Archiver>
|
Chris@16
|
396 void
|
Chris@16
|
397 save_impl(Archiver& ar, const boost::python::object& obj,
|
Chris@16
|
398 const unsigned int /*version*/,
|
Chris@16
|
399 mpl::false_ /*has_direct_serialization*/)
|
Chris@16
|
400 {
|
Chris@16
|
401 boost::python::str py_string = boost::python::pickle::dumps(obj);
|
Chris@16
|
402 int len = boost::python::extract<int>(py_string.attr("__len__")());
|
Chris@16
|
403 const char* string = boost::python::extract<const char*>(py_string);
|
Chris@16
|
404 ar << len << boost::serialization::make_array(string, len);
|
Chris@16
|
405 }
|
Chris@16
|
406
|
Chris@16
|
407 /// Try to save a Python object by directly serializing it; fall back
|
Chris@16
|
408 /// on pickling if required.
|
Chris@16
|
409 template<typename Archiver>
|
Chris@16
|
410 void
|
Chris@16
|
411 save_impl(Archiver& ar, const boost::python::object& obj,
|
Chris@16
|
412 const unsigned int version,
|
Chris@16
|
413 mpl::true_ /*has_direct_serialization*/)
|
Chris@16
|
414 {
|
Chris@16
|
415 typedef Archiver OArchiver;
|
Chris@16
|
416 typedef typename input_archiver<OArchiver>::type IArchiver;
|
Chris@16
|
417 typedef typename direct_serialization_table<IArchiver, OArchiver>::saver_t
|
Chris@16
|
418 saver_t;
|
Chris@16
|
419
|
Chris@16
|
420 direct_serialization_table<IArchiver, OArchiver>& table =
|
Chris@16
|
421 get_direct_serialization_table<IArchiver, OArchiver>();
|
Chris@16
|
422
|
Chris@16
|
423 int descriptor = 0;
|
Chris@16
|
424 if (saver_t saver = table.saver(obj, descriptor)) {
|
Chris@16
|
425 ar << descriptor;
|
Chris@16
|
426 saver(ar, obj, version);
|
Chris@16
|
427 } else {
|
Chris@16
|
428 // Pickle it
|
Chris@16
|
429 ar << descriptor;
|
Chris@16
|
430 detail::save_impl(ar, obj, version, mpl::false_());
|
Chris@16
|
431 }
|
Chris@16
|
432 }
|
Chris@16
|
433
|
Chris@16
|
434 /// Load a Python object by unpickling it
|
Chris@16
|
435 template<typename Archiver>
|
Chris@16
|
436 void
|
Chris@16
|
437 load_impl(Archiver& ar, boost::python::object& obj,
|
Chris@16
|
438 const unsigned int /*version*/,
|
Chris@16
|
439 mpl::false_ /*has_direct_serialization*/)
|
Chris@16
|
440 {
|
Chris@16
|
441 int len;
|
Chris@16
|
442 ar >> len;
|
Chris@16
|
443
|
Chris@16
|
444 std::auto_ptr<char> string(new char[len]);
|
Chris@16
|
445 ar >> boost::serialization::make_array(string.get(), len);
|
Chris@16
|
446 boost::python::str py_string(string.get(), len);
|
Chris@16
|
447 obj = boost::python::pickle::loads(py_string);
|
Chris@16
|
448 }
|
Chris@16
|
449
|
Chris@16
|
450 /// Try to load a Python object by directly deserializing it; fall back
|
Chris@16
|
451 /// on unpickling if required.
|
Chris@16
|
452 template<typename Archiver>
|
Chris@16
|
453 void
|
Chris@16
|
454 load_impl(Archiver& ar, boost::python::object& obj,
|
Chris@16
|
455 const unsigned int version,
|
Chris@16
|
456 mpl::true_ /*has_direct_serialization*/)
|
Chris@16
|
457 {
|
Chris@16
|
458 typedef Archiver IArchiver;
|
Chris@16
|
459 typedef typename output_archiver<IArchiver>::type OArchiver;
|
Chris@16
|
460 typedef typename direct_serialization_table<IArchiver, OArchiver>::loader_t
|
Chris@16
|
461 loader_t;
|
Chris@16
|
462
|
Chris@16
|
463 direct_serialization_table<IArchiver, OArchiver>& table =
|
Chris@16
|
464 get_direct_serialization_table<IArchiver, OArchiver>();
|
Chris@16
|
465
|
Chris@16
|
466 int descriptor;
|
Chris@16
|
467 ar >> descriptor;
|
Chris@16
|
468
|
Chris@16
|
469 if (descriptor) {
|
Chris@16
|
470 loader_t loader = table.loader(descriptor);
|
Chris@16
|
471 BOOST_ASSERT(loader);
|
Chris@16
|
472
|
Chris@16
|
473 loader(ar, obj, version);
|
Chris@16
|
474 } else {
|
Chris@16
|
475 // Unpickle it
|
Chris@16
|
476 detail::load_impl(ar, obj, version, mpl::false_());
|
Chris@16
|
477 }
|
Chris@16
|
478 }
|
Chris@16
|
479
|
Chris@16
|
480 } // end namespace detail
|
Chris@16
|
481
|
Chris@16
|
482 template<typename Archiver>
|
Chris@16
|
483 void
|
Chris@16
|
484 save(Archiver& ar, const boost::python::object& obj,
|
Chris@16
|
485 const unsigned int version)
|
Chris@16
|
486 {
|
Chris@16
|
487 typedef Archiver OArchiver;
|
Chris@16
|
488 typedef typename input_archiver<OArchiver>::type IArchiver;
|
Chris@16
|
489
|
Chris@16
|
490 detail::save_impl(ar, obj, version,
|
Chris@16
|
491 has_direct_serialization<IArchiver, OArchiver>());
|
Chris@16
|
492 }
|
Chris@16
|
493
|
Chris@16
|
494 template<typename Archiver>
|
Chris@16
|
495 void
|
Chris@16
|
496 load(Archiver& ar, boost::python::object& obj,
|
Chris@16
|
497 const unsigned int version)
|
Chris@16
|
498 {
|
Chris@16
|
499 typedef Archiver IArchiver;
|
Chris@16
|
500 typedef typename output_archiver<IArchiver>::type OArchiver;
|
Chris@16
|
501
|
Chris@16
|
502 detail::load_impl(ar, obj, version,
|
Chris@16
|
503 has_direct_serialization<IArchiver, OArchiver>());
|
Chris@16
|
504 }
|
Chris@16
|
505
|
Chris@16
|
506 template<typename Archive>
|
Chris@16
|
507 inline void
|
Chris@16
|
508 serialize(Archive& ar, boost::python::object& obj, const unsigned int version)
|
Chris@16
|
509 {
|
Chris@16
|
510 boost::serialization::split_free(ar, obj, version);
|
Chris@16
|
511 }
|
Chris@16
|
512
|
Chris@16
|
513 } } // end namespace boost::python
|
Chris@16
|
514
|
Chris@16
|
515 /************************************************************************
|
Chris@16
|
516 * Boost.MPI-Specific Section *
|
Chris@16
|
517 ************************************************************************/
|
Chris@16
|
518 namespace boost { namespace mpi {
|
Chris@16
|
519 class packed_iarchive;
|
Chris@16
|
520 class packed_oarchive;
|
Chris@16
|
521 } } // end namespace boost::mpi
|
Chris@16
|
522
|
Chris@16
|
523 BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE(
|
Chris@16
|
524 ::boost::mpi::packed_iarchive,
|
Chris@16
|
525 ::boost::mpi::packed_oarchive)
|
Chris@16
|
526
|
Chris@16
|
527 namespace boost { namespace mpi { namespace python {
|
Chris@16
|
528
|
Chris@16
|
529 template<typename T>
|
Chris@16
|
530 void
|
Chris@16
|
531 register_serialized(const T& value, PyTypeObject* type)
|
Chris@16
|
532 {
|
Chris@16
|
533 using boost::python::register_serialized;
|
Chris@16
|
534 register_serialized<packed_iarchive, packed_oarchive>(value, type);
|
Chris@16
|
535 }
|
Chris@16
|
536
|
Chris@16
|
537 } } } // end namespace boost::mpi::python
|
Chris@16
|
538
|
Chris@16
|
539 #endif // BOOST_MPI_PYTHON_SERIALIZE_HPP
|