1 #ifndef PYKEP_UTILS_H
2 #define PYKEP_UTILS_H
3 
4 #include <Python.h>
5 #include <boost/archive/text_iarchive.hpp>
6 #include <boost/archive/text_oarchive.hpp>
7 #include <boost/python/class.hpp>
8 #include <boost/python/dict.hpp>
9 #include <boost/python/docstring_options.hpp>
10 #include <boost/python/extract.hpp>
11 #include <boost/python/tuple.hpp>
12 #include <boost/serialization/serialization.hpp>
13 #include <sstream>
14 #include <string>
15 
16 template <class T>
Py_copy_from_ctor(const T & x)17 inline T Py_copy_from_ctor(const T &x)
18 {
19     return T(x);
20 }
21 
22 template <class T>
Py_deepcopy_from_ctor(const T & x,boost::python::dict)23 inline T Py_deepcopy_from_ctor(const T &x, boost::python::dict)
24 {
25     return T(x);
26 }
27 
28 // Generic pickle suite for C++ classes with default constructor extensible from Python.
29 // We need to take care of handling the derived class' dict.
30 // And we need to define the serialize member for the boost::python::wrapper class
31 
32 // Serialization for python wrapper.
33 namespace boost
34 {
35 namespace serialization
36 {
37 template <class Archive, class T>
serialize(Archive &,boost::python::wrapper<T> &,const unsigned int)38 void serialize(Archive &, boost::python::wrapper<T> &, const unsigned int)
39 {
40 }
41 }
42 }
43 
44 template <class T>
45 struct python_class_pickle_suite : boost::python::pickle_suite {
getinitargspython_class_pickle_suite46     static boost::python::tuple getinitargs(const T &)
47     {
48         return boost::python::make_tuple();
49     }
getstatepython_class_pickle_suite50     static boost::python::tuple getstate(boost::python::object obj)
51     {
52         T const &x = boost::python::extract<T const &>(obj)();
53         std::stringstream ss;
54         boost::archive::text_oarchive oa(ss);
55         oa << x;
56         return boost::python::make_tuple(obj.attr("__dict__"), ss.str());
57     }
setstatepython_class_pickle_suite58     static void setstate(boost::python::object obj, boost::python::tuple state)
59     {
60         using namespace boost::python;
61         T &x = extract<T &>(obj)();
62         if (len(state) != 2) {
63             PyErr_SetObject(PyExc_ValueError, ("expected 2-item tuple in call to __setstate__; got %s" % state).ptr());
64             throw_error_already_set();
65         }
66         // Restore the object's __dict__.
67         dict d = extract<dict>(obj.attr("__dict__"))();
68         d.update(state[0]);
69         // Restore the internal state of the C++ object.
70         const std::string str = extract<std::string>(state[1]);
71         std::stringstream ss(str);
72         boost::archive::text_iarchive ia(ss);
73         ia >> x;
74     }
getstate_manages_dictpython_class_pickle_suite75     static bool getstate_manages_dict()
76     {
77         return true;
78     }
79 };
80 
81 template <class T>
py_cpp_loads(T & x,const std::string & s)82 inline void py_cpp_loads(T &x, const std::string &s)
83 {
84     std::stringstream ss(s);
85     boost::archive::text_iarchive ia(ss);
86     ia >> x;
87 }
88 
89 template <class T>
py_cpp_dumps(const T & x)90 inline std::string py_cpp_dumps(const T &x)
91 {
92     std::stringstream ss;
93     boost::archive::text_oarchive oa(ss);
94     oa << x;
95     return ss.str();
96 }
97 
98 #endif // PYKEP_UTILS_H
99