Michele De Stefano's C++ Utilities
conversion.hpp
Go to the documentation of this file.
1 // mds_utils/python/conversion.hpp
2 //
3 // Copyright (c) 2014 - Michele De Stefano (micdestefano@users.sourceforge.net)
4 //
5 // Distributed under the MIT License (See accompanying file LICENSE)
6 
7 #ifndef MDS_UTILS_PYTHON_CONVERSION_HPP_INCLUDED
8 #define MDS_UTILS_PYTHON_CONVERSION_HPP_INCLUDED
9 
10 #include <Python.h>
11 #include <stdexcept>
12 #include <string>
13 #include <complex>
14 #include <boost/preprocessor/seq/for_each.hpp>
15 #include <boost/preprocessor/tuple/elem.hpp>
16 #include <boost/preprocessor/stringize.hpp>
17 #include <boost/numeric/conversion/cast.hpp>
18 //#include <mds_utils/python/obj.hpp>
19 
39 namespace mds_utils {
40  namespace python {
41 
54 template<class T>
55 T get(PyObject *po);
56 
57 
70 PyObject* to_python(void);
71 
72 
74 
75 template<>
76 inline PyObject* get<PyObject*>(PyObject *po) {
77  return po;
78 }
79 
80 inline PyObject* to_python(PyObject *po) {
81  Py_XINCREF(po);
82  return po;
83 }
84 
85 
86 #define SEQ_TYPE_PY_TYPE_FUN_AS \
87  ((long,PyInt_AsLong,PyInt_FromLong)) \
88  ((double,PyFloat_AsDouble,PyFloat_FromDouble))
89 
90 #define SEQ_TYPE_PY_TYPE_FUN_AS_CAST \
91  ((short,PyInt_AsLong,PyInt_FromLong,long)) \
92  ((unsigned short,PyInt_AsLong,PyInt_FromLong,long)) \
93  ((int,PyInt_AsLong,PyInt_FromLong,long)) \
94  ((unsigned int,PyInt_AsLong,PyInt_FromLong,long)) \
95  ((unsigned long,PyInt_AsLong,PyInt_FromLong,long)) \
96  ((long long,PyInt_AsLong,PyInt_FromLong,long)) \
97  ((unsigned long long,PyInt_AsLong,PyInt_FromLong,long)) \
98  ((float,PyFloat_AsDouble,PyFloat_FromDouble,double))
99 
100 #define GET_SPEC_GEN(r,data,elem) \
101  template<> \
102  inline BOOST_PP_TUPLE_ELEM(3,0,elem) get< BOOST_PP_TUPLE_ELEM(3,0,elem) >(PyObject *po) { \
103  BOOST_PP_TUPLE_ELEM(3,0,elem) retval(BOOST_PP_TUPLE_ELEM(3,1,elem)(po)); \
104  \
105  if (PyErr_Occurred() != NULL) { \
106  throw std::invalid_argument("Cannot get a " BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(3,0,elem)) " value"); \
107  } \
108  \
109  return retval; \
110  } \
111  \
112  inline PyObject* to_python(BOOST_PP_TUPLE_ELEM(3,0,elem) val) { \
113  PyObject* retval(BOOST_PP_TUPLE_ELEM(3,2,elem)(val)); \
114  \
115  if (retval == NULL) throw std::invalid_argument("Cannot convert " BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(3,0,elem)) " to Python"); \
116  \
117  return retval; \
118  }
119 
120 
121 #define GET_SPEC_GEN_CAST(r,data,elem) \
122  template<> \
123  inline BOOST_PP_TUPLE_ELEM(4,0,elem) get< BOOST_PP_TUPLE_ELEM(4,0,elem) >(PyObject *po) { \
124  BOOST_PP_TUPLE_ELEM(4,0,elem) retval(boost::numeric_cast< BOOST_PP_TUPLE_ELEM(4,0,elem) >(BOOST_PP_TUPLE_ELEM(4,1,elem)(po))); \
125  \
126  if (PyErr_Occurred() != NULL) { \
127  throw std::invalid_argument("Cannot get a " BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,0,elem)) " value"); \
128  } \
129  \
130  return retval; \
131  } \
132  \
133  inline PyObject* to_python(const BOOST_PP_TUPLE_ELEM(4,0,elem) val) { \
134  PyObject* retval(BOOST_PP_TUPLE_ELEM(4,2,elem)(boost::numeric_cast< BOOST_PP_TUPLE_ELEM(4,3,elem) >(val))); \
135  \
136  if (retval == NULL) throw std::invalid_argument("Cannot convert " BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,0,elem)) " to Python"); \
137  \
138  return retval; \
139  }
140 
141 BOOST_PP_SEQ_FOR_EACH(GET_SPEC_GEN,~,SEQ_TYPE_PY_TYPE_FUN_AS)
142 BOOST_PP_SEQ_FOR_EACH(GET_SPEC_GEN_CAST,~,SEQ_TYPE_PY_TYPE_FUN_AS_CAST)
143 
144 
145 template<>
146 inline const char* get<const char*>(PyObject *po) {
147 
148  const char *retval(const_cast<const char*>(PyString_AsString(po)));
149 
150  if (PyErr_Occurred() != NULL) {
151  throw std::invalid_argument("Cannot get a const char* value"); \
152  }
153 
154  return retval;
155 }
156 
157 
158 template<>
159 inline std::string get<std::string>(PyObject *po) {
160  std::string retval(get<char*>(po));
161 
162  if (PyErr_Occurred() != NULL) {
163  throw std::invalid_argument("Cannot get a std::string value");
164  }
165 
166  return retval;
167 }
168 
169 
170 
171 inline PyObject* to_python(const char* str) {
172  PyObject *retval(PyString_FromString(str));
173 
174  if (retval == NULL) throw std::invalid_argument("Cannot convert a const char* to Python");
175 
176  return retval;
177 }
178 
179 
180 inline PyObject* to_python(const std::string& str) {
181 
182  PyObject* retval(PyString_FromString(str.c_str()));
183 
184  if (retval == NULL) throw std::invalid_argument("Cannot convert a std::string to Python");
185 
186  return retval;
187 }
188 
189 
190 template<>
191 inline std::complex<double> get< std::complex<double> >(PyObject *po) {
192 
193  std::complex<double> retval(
194  PyComplex_RealAsDouble(po),
195  PyComplex_ImagAsDouble(po)
196  );
197 
198  if (PyErr_Occurred() != NULL) {
199  throw std::invalid_argument("Cannot get a std::complex<double> value"); \
200  }
201 
202  return retval;
203 }
204 
205 
206 inline PyObject* to_python(const std::complex<double>& val) {
207 
208  PyObject* retval(PyComplex_FromDoubles(val.real(),val.imag()));
209 
210  if (retval == NULL) {
211  throw std::invalid_argument("Cannot convert a std::complex<double> to Python");
212  }
213 
214  return retval;
215 }
216 
217 // WARNING: I REMOVE THE CONVERSIONS BELOW, BECAUSE IN STANDARD PYTHON complex<float> numbers do not exist
218 // NumPy provides them.
219 //template<>
220 //inline std::complex<float> get< std::complex<float> >(PyObject *po) {
221 //
222 // std::complex<float> retval(
223 // boost::numeric_cast<float>(PyComplex_RealAsDouble(po)),
224 // boost::numeric_cast<float>(PyComplex_ImagAsDouble(po))
225 // );
226 //
227 // if (PyErr_Occurred() != NULL) {
228 // throw std::invalid_argument("Cannot get a std::complex<float> value");
229 // }
230 //
231 // return retval;
232 //}
233 //
234 //
235 //inline PyObject* to_python(const std::complex<float>& val) {
236 //
237 // PyObject* retval(PyComplex_FromDoubles(
238 // static_cast<double>(val.real()),
239 // static_cast<double>(val.imag())
240 // )
241 // );
242 //
243 // if (retval == NULL) {
244 // throw std::invalid_argument("Cannot convert a std::complex<float> to Python");
245 // }
246 //
247 // return retval;
248 //}
249 
250 
252 
253  } // namespace python
254 } // namespace mds_utils
255 
256 #endif
T get(PyObject *po)
Primary template for extracting a value from a Python object.
Definition: matrix.hpp:56
PyObject * to_python(void)
Converts a value into a Python object.
Main namespace of all Michele De Stefano&#39;s C++ utilities.
Definition: endian.hpp:30