FMT 0.9.8
Forest management tools for forest planning
Loading...
Searching...
No Matches
FMTpythoncore.hpp
Go to the documentation of this file.
1/*
2Copyright (c) 2019 Gouvernement du Québec
3
4SPDX-License-Identifier: LiLiQ-R-1.1
5License-Filename: LICENSES/EN/LiLiQ-R11unicode.txt
6*/
7
8#ifndef FMTPYTHONCORE_H_INCLUDED
9#define FMTPYTHONCORE_H_INCLUDED
10
11#if defined FMTWITHPYTHON
12#ifndef BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS
13 #define BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS
14#endif
15
16#include <boost/python.hpp>
17#include <boost/algorithm/string.hpp>
18#include <boost/python/stl_iterator.hpp>
19#include <boost/regex.hpp>
20#include <iterator>
21#include <iostream>
22#include <fstream>
23#include <string>
24#include <vector>
25#include <limits>
26#include <map>
27#include <tuple>
28#include <boost/dynamic_bitset.hpp>
29#include <boost/unordered_map.hpp>
30#include "FMTexception.hpp"
31#include "FMTerror.hpp"
32#include "FMTwarning.hpp"
33
34
35
36namespace boost{
37
38template<class T>
39static size_t pyhash(const T& value)
40 {
41 return boost::hash<T>()(value);
42 }
43}
44
45namespace Python
46{
47 template <class K, class V>
48 struct MapToDict
49 {
50 static PyObject* convert(const std::map<K, V>& lmap)
51 {
52 boost::python::dict* dictionary = new boost::python::dict();
53 for (typename std::map<K, V>::const_iterator it = lmap.begin(); it != lmap.end(); ++it)
54 {
55 dictionary->operator[](it->first) = it->second;
56 }
57 return dictionary->ptr();
58 }
59
60 };
61
62 template <class K, class V>
63 struct UMapToDict
64 {
65 static PyObject* convert(const boost::unordered_map<K, V>& lmap)
66 {
67 boost::python::dict* dictionary = new boost::python::dict();
68 for (typename boost::unordered_map<K, V>::const_iterator it = lmap.begin(); it != lmap.end(); ++it)
69 {
70 dictionary->operator[](it->first) = it->second;
71 }
72 return dictionary->ptr();
73 }
74
75 };
76
77
78
79 template<class T>
80 struct VecToList
81 {
82 static PyObject* convert(const std::vector<T>& vec)
83 {
84 boost::python::list* l = new boost::python::list();
85 for (size_t i = 0; i < vec.size(); i++) {
86 l->append(vec[i]);
87 }
88
89 return l->ptr();
90 }
91 };
92
93 template<typename T>
94 struct VecFrList
95 {
96
97 VecFrList()
98 {
99 boost::python::converter::registry::push_back(&VecFrList<T>::convertible,
100 &VecFrList<T>::construct,
101 boost::python::type_id<std::vector<T> >());
102 }
103
104 // Determine if obj_ptr can be converted in a std::vector<T>
105 static void* convertible(PyObject* obj_ptr)
106 {
107 if (!PyList_Check(obj_ptr)) {
108 PyObject* nullobj = nullptr;
109 return nullobj;
110 }
111 return obj_ptr;
112 }
113
114 // Convert obj_ptr into a std::vector<T>
115 static void construct(
116 PyObject* obj_ptr,
117 boost::python::converter::rvalue_from_python_stage1_data* data)
118 {
119 // Extract the character data from the python string
120 // const char* value = PyString_AsString(obj_ptr);
121 boost::python::list l(boost::python::handle<>(boost::python::borrowed(obj_ptr)));
122
123 // // Verify that obj_ptr is a string (should be ensured by convertible())
124 // assert(value);
125
126 // Grab pointer to memory into which to construct the new std::vector<T>
127 void* storage = (
128 (boost::python::converter::rvalue_from_python_storage<std::vector<T> >*)
129 data)->storage.bytes;
130
131 // in-place construct the new std::vector<T> using the character data
132 // extraced from the python object
133 std::vector<T>& v = *(new (storage) std::vector<T>());
134
135 // populate the vector from list contains !!!
136 int le = static_cast<int>(boost::python::len(l));
137 v.resize(le);
138 for (int i = 0; i != le; ++i) {
139 v[i] = boost::python::extract<T>(l[i]);
140 }
141
142 // Stash the memory chunk pointer for later use by boost.python
143 data->convertible = storage;
144 }
145 };
146
147
148
149 struct iterable_converter
150 {
153 template <typename Container>
154 iterable_converter&
155 from_python()
156 {
157 boost::python::converter::registry::push_back(
158 &iterable_converter::convertible,
159 &iterable_converter::construct<Container>,
160 boost::python::type_id<Container>());
161
162 // Support chaining.
163 return *this;
164 }
165
166 static void* convertible(PyObject* object)
167 {
168 return PyObject_GetIter(object) ? object : NULL;
169 }
170
171 template <typename Container>
172 static void construct(
173 PyObject* object,
174 boost::python::converter::rvalue_from_python_stage1_data* data)
175 {
176
177 // Object is a borrowed reference, so create a handle indicting it is
178 // borrowed for proper reference counting.
179 boost::python::handle<> handle(boost::python::borrowed(object));
180
181 // Obtain a handle to the memory block that the converter has allocated
182 // for the C++ type.
183 typedef boost::python::converter::rvalue_from_python_storage<Container>
184 storage_type;
185 void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;
186
187 typedef boost::python::stl_input_iterator<typename Container::value_type>
188 iterator;
189
190 // Allocate the C++ type into the converter's memory block, and assign
191 // its handle to the converter's convertible variable. The C++
192 // container is populated by passing the begin and end iterators of
193 // the python object to the container's constructor.
194 new (storage) Container(
195 iterator(boost::python::object(handle)), // begin
196 iterator()); // end
197 data->convertible = storage;
198 }
199 };
200
201 template<class k, class e>
202 struct MapFrDict
203 {
206 MapFrDict()
207 {
208
209 boost::python::converter::registry::push_back(&MapFrDict<k, e>::convertible,
210 &MapFrDict<k, e>::construct,
211 boost::python::type_id<std::map<k, e> >());
212
213
214 }
215
216 static void* convertible(PyObject* obj_ptr)
217 {
218 if (PyMapping_Check(obj_ptr)) {
219 return obj_ptr;
220 }
221 else {
222 PyObject* nullobj = nullptr;
223 return nullobj;
224 }
225 }
226
227
228 static void construct(
229 PyObject* obj_ptr,
230 boost::python::converter::rvalue_from_python_stage1_data* data)
231 {
232 boost::python::dict mapping(boost::python::handle<>(boost::python::borrowed(obj_ptr)));
233
234 // // Verify that obj_ptr is a string (should be ensured by convertible())
235 // assert(value);
236
237 // Grab pointer to memory into which to construct the new std::vector<T>
238 void* storage = (
239 (boost::python::converter::rvalue_from_python_storage<std::map<k, e>>*)
240 data)->storage.bytes;
241
242 // in-place construct the new std::vector<T> using the character data
243 // extraced from the python object
244 std::map<k, e>& v = *(new (storage) std::map<k, e>());
245
246 // populate the vector from list contains !!!
247 boost::python::list keys = mapping.keys();
248 for (int i = 0; i < boost::python::len(keys); ++i)
249 {
250 boost::python::extract<k> extracted_key(keys[i]);
251 k newkey = extracted_key;
252 boost::python::extract<e> extracted_val(mapping[newkey]);
253 e value = extracted_val;
254 v[newkey] = value;
255 }
256
257 // Stash the memory chunk pointer for later use by boost.python
258 data->convertible = storage;
259 }
260 };
261
262
263 void FMTtranslate_warning(Exception::FMTwarning const& e)
264 {
265 PyErr_SetString(PyExc_UserWarning, e.what());
266 }
267
268 PyObject* FMTexceptiontype = NULL;
269
270 void FMTtranslate_error(Exception::FMTerror const& error) //should be implemented more like https://stackoverflow.com/questions/9620268/boost-python-custom-exception-class
271 {
272 if (error.hold())
273 {
274 assert(FMTexceptiontype != NULL);
275 boost::python::object pythonExceptionInstance(error);
276 PyErr_SetObject(FMTexceptiontype, pythonExceptionInstance.ptr());
277 }
278 else {
279 PyErr_SetString(PyExc_RuntimeError, error.what());
280 }
281 }
282
283 template<typename T1, typename T2>
284 struct PairToPythonConverter {
285 static PyObject* convert(const std::pair<T1, T2>& pair)
286 {
287 return boost::python::incref(boost::python::make_tuple(pair.first, pair.second).ptr());
288 }
289 };
290
291 template<typename T1, typename T2>
292 struct PythonToPairConverter {
293 PythonToPairConverter()
294 {
295 boost::python::converter::registry::push_back(&convertible, &construct, boost::python::type_id<std::pair<T1, T2> >());
296 }
297 static void* convertible(PyObject* obj)
298 {
299 if (!PyTuple_CheckExact(obj)) return 0;
300 if (PyTuple_Size(obj) != 2) return 0;
301 return obj;
302 }
303 static void construct(PyObject* obj, boost::python::converter::rvalue_from_python_stage1_data* data)
304 {
305 boost::python::tuple tuple(boost::python::borrowed(obj));
306 void* storage = ((boost::python::converter::rvalue_from_python_storage<std::pair<T1, T2> >*) data)->storage.bytes;
307 new (storage) std::pair<T1, T2>(boost::python::extract<T1>(tuple[0]), boost::python::extract<T2>(tuple[1]));
308 data->convertible = storage;
309 }
310 };
311
312 template<typename T1, typename T2>
313 struct py_pair {
314 boost::python::to_python_converter<std::pair<T1, T2>, PairToPythonConverter<T1, T2> > toPy;
315 PythonToPairConverter<T1, T2> fromPy;
316 };
317
318}
319
320#endif
321
322#endif
Definition: FMTerror.hpp:32
const char * what() const override
Definition: FMTwarning.hpp:32
Definition: PYdefinitions.hpp:14
Definition: FMTaction.hpp:364