FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Added python C++11 wrapper. · binarypearl/Programs-Scripts@dfdab7c · GitHub

Repository navigation

Commit dfdab7c

Browse files
committed
Added python C++11 wrapper.
1 parent e09db39 commit dfdab7c

2 files changed

Lines changed: 322 additions & 0 deletions

File tree

‎pywrapper/pywrapper.cpp‎

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* This program is free software; you can redistribute it and/or modify
2+
* it under the terms of the GNU General Public License as published by
3+
* the Free Software Foundation; either version 3 of the License, or
4+
* (at your option) any later version.
5+
*
6+
* This program is distributed in the hope that it will be useful,
7+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9+
* GNU General Public License for more details.
10+
*
11+
* You should have received a copy of the GNU General Public License
12+
* along with this program; if not, write to the Free Software
13+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
14+
* MA 02110-1301, USA.
15+
*
16+
* Author:
17+
* Matias Fontanini
18+
*
19+
*/
20+
21+
#include <array>
22+
#include "pywrapper.h"
23+
24+
using std::runtime_error;
25+
using std::string;
26+
27+
Python::Script::Script(const string &script_path)
28+
throw(runtime_error) {
29+
Py_Initialize();
30+
char arr[] = "path";
31+
//pyunique_ptr path(PySys_GetObject("path"));
32+
PyObject *path(PySys_GetObject(arr));
33+
pyunique_ptr pwd(PyString_FromString("."));
34+
PyList_Insert(path, 0, pwd.get());
35+
/* We don't need that string value anymore, so deref it */
36+
module.reset(PyImport_ImportModule(script_path.c_str()));
37+
if(!module.get())
38+
throw runtime_error("Failed to load script");
39+
}
40+
41+
PyObject *Python::Script::load_function(const std::string &name)
42+
throw(runtime_error) {
43+
auto it(functions.find(name));
44+
// Is it cached?
45+
if(it == functions.end()) {
46+
PyObject *obj(PyObject_GetAttrString(module.get(), name.c_str()));
47+
if(!obj)
48+
throw std::runtime_error("Failed to load function");
49+
functions[name] = obj;
50+
return obj;
51+
}
52+
else
53+
return it->second;
54+
}
55+
56+
PyObject *Python::alloc_pyobject(const std::string &str) {
57+
return PyString_FromString(str.c_str());
58+
}
59+
60+
PyObject *Python::alloc_pyobject(int num) {
61+
return PyInt_FromLong(num);
62+
}
63+
64+
PyObject *Python::alloc_pyobject(double num) {
65+
return PyFloat_FromDouble(num);
66+
}
67+
68+
bool is_py_int(PyObject *obj) {
69+
return PyInt_Check(obj);
70+
}
71+
72+
bool is_py_float(PyObject *obj) {
73+
return PyFloat_Check(obj);
74+
}
75+
76+
bool Python::convert(PyObject *obj, std::string &val) {
77+
if(!PyString_Check(obj))
78+
return false;
79+
val = PyString_AsString(obj);
80+
return true;
81+
}
82+
83+
bool Python::convert(PyObject *obj, Py_ssize_t &val) {
84+
return generic_convert<Py_ssize_t>(obj, is_py_int, PyInt_AsSsize_t, val);
85+
}
86+
87+
bool Python::convert(PyObject *obj, double &val) {
88+
return generic_convert<double>(obj, is_py_float, PyFloat_AsDouble, val);
89+
}
90+
91+
bool Python::convert(PyObject *obj, long &val) {
92+
return generic_convert<long>(obj, is_py_int, PyInt_AsLong, val);
93+
}

‎pywrapper/pywrapper.h‎

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
/* This program is free software; you can redistribute it and/or modify
2+
* it under the terms of the GNU General Public License as published by
3+
* the Free Software Foundation; either version 3 of the License, or
4+
* (at your option) any later version.
5+
*
6+
* This program is distributed in the hope that it will be useful,
7+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9+
* GNU General Public License for more details.
10+
*
11+
* You should have received a copy of the GNU General Public License
12+
* along with this program; if not, write to the Free Software
13+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
14+
* MA 02110-1301, USA.
15+
*
16+
* Author:
17+
* Matias Fontanini
18+
*
19+
*/
20+
21+
#ifndef __PYWRAPPER_H
22+
#define __PYWRAPPER_H
23+
24+
#include <string>
25+
#include <stdexcept>
26+
#include <utility>
27+
#include <memory>
28+
#include <map>
29+
#include <vector>
30+
#include <list>
31+
#include <tuple>
32+
#include <python2.7/Python.h>
33+
34+
35+
namespace Python {
36+
// Deleter that calls Py_XDECREF on the PyObject parameter.
37+
struct PyObjectDeleter {
38+
void operator()(PyObject *obj) {
39+
Py_XDECREF(obj);
40+
}
41+
};
42+
// unique_ptr that uses Py_XDECREF as the destructor function.
43+
typedef std::unique_ptr<PyObject, PyObjectDeleter> pyunique_ptr;
44+
45+
// ------------ Conversion functions ------------
46+
47+
// Convert a PyObject to a std::string.
48+
bool convert(PyObject *obj, std::string &val);
49+
// Convert a PyObject to a ssize_t.
50+
bool convert(PyObject *obj, Py_ssize_t &val);
51+
// Convert a PyObject to a long.
52+
bool convert(PyObject *obj, long &val);
53+
// Convert a PyObject to an float.
54+
bool convert(PyObject *obj, double &val);
55+
56+
// Helper class to use when constructing tuples from PyObjects
57+
template<class Tuple, std::size_t N>
58+
struct TupleCreater {
59+
static bool initialize(PyObject *obj, Tuple &tup) {
60+
TupleCreater<Tuple, N-1>::initialize(obj, tup);
61+
return convert(PyTuple_GetItem(obj, N-1), std::get<N-1>(tup));
62+
}
63+
};
64+
template<class Tuple>
65+
struct TupleCreater<Tuple, 1> {
66+
static bool initialize(PyObject *obj, Tuple &tup) {
67+
return convert(PyTuple_GetItem(obj, 0), std::get<0>(tup));
68+
}
69+
};
70+
// Convert a PyObject to a std::tuple.
71+
template<class... Args>
72+
bool convert(PyObject *obj, std::tuple<Args...> &tup) {
73+
if(!PyTuple_Check(obj) ||
74+
PyTuple_Size(obj) != sizeof...(Args))
75+
return false;
76+
return TupleCreater<decltype(tup), sizeof...(Args)>::initialize(obj, tup);
77+
}
78+
// Convert a PyObject to a std::map
79+
template<class K, class V>
80+
bool convert(PyObject *obj, std::map<K, V> &mp) {
81+
if(!PyDict_Check(obj))
82+
return false;
83+
PyObject *py_key, *py_val;
84+
Py_ssize_t pos(0);
85+
while (PyDict_Next(obj, &pos, &py_key, &py_val)) {
86+
K key;
87+
if(!convert(py_key, key))
88+
return false;
89+
V val;
90+
if(!convert(py_val, val))
91+
return false;
92+
mp.insert(std::make_pair(key, val));
93+
}
94+
return true;
95+
}
96+
// Convert a PyObject to a generic container.
97+
template<class T, class C>
98+
bool convert_list(PyObject *obj, C &container) {
99+
if(!PyList_Check(obj))
100+
return false;
101+
for(Py_ssize_t i(0); i < PyList_Size(obj); ++i) {
102+
T val;
103+
if(!convert(PyList_GetItem(obj, i), val))
104+
return false;
105+
container.push_back(std::move(val));
106+
}
107+
return true;
108+
}
109+
// Convert a PyObject to a std::list.
110+
template<class T> bool convert(PyObject *obj, std::list<T> &lst) {
111+
return convert_list<T, std::list<T>>(obj, lst);
112+
}
113+
// Convert a PyObject to a std::vector.
114+
template<class T> bool convert(PyObject *obj, std::vector<T> &vec) {
115+
return convert_list<T, std::vector<T>>(obj, vec);
116+
}
117+
118+
template<class T> bool generic_convert(PyObject *obj,
119+
const std::function<bool(PyObject*)> &is_obj,
120+
const std::function<T(PyObject*)> &converter,
121+
T &val) {
122+
if(!is_obj(obj))
123+
return false;
124+
val = converter(obj);
125+
return true;
126+
}
127+
128+
// -------------- PyObject allocators ----------------
129+
130+
// Generic python list allocation
131+
template<class T> static PyObject *alloc_list(const T &container) {
132+
PyObject *lst(PyList_New(container.size()));
133+
134+
Py_ssize_t i(0);
135+
for(auto it(container.begin()); it != container.end(); ++it)
136+
PyList_SetItem(lst, i++, alloc_pyobject(*it));
137+
138+
return lst;
139+
}
140+
// Creates a PyObject from a std::string
141+
PyObject *alloc_pyobject(const std::string &str);
142+
// Creates a PyObject from an int
143+
PyObject *alloc_pyobject(int num);
144+
// Creates a PyObject from a double
145+
PyObject *alloc_pyobject(double num);
146+
// Creates a PyObject from a std::vector
147+
template<class T> PyObject *alloc_pyobject(const std::vector<T> &container) {
148+
return alloc_list(container);
149+
}
150+
// Creates a PyObject from a std::list
151+
template<class T> PyObject *alloc_pyobject(const std::list<T> &container) {
152+
return alloc_list(container);
153+
}
154+
// Creates a PyObject from a std::map
155+
template<class T, class K> PyObject *alloc_pyobject(
156+
const std::map<T, K> &container) {
157+
PyObject *dict(PyDict_New());
158+
159+
for(auto it(container.begin()); it != container.end(); ++it)
160+
PyDict_SetItem(dict,
161+
alloc_pyobject(it->first),
162+
alloc_pyobject(it->second)
163+
);
164+
165+
return dict;
166+
}
167+
168+
// This class is an abstraction of a python script.
169+
class Script {
170+
public:
171+
// Script constructor that takes the script path as the name.
172+
Script(const std::string &script_path) throw(std::runtime_error);
173+
174+
// Calls the function named "name" using the arguments "args".
175+
template<typename... Args>
176+
pyunique_ptr call_function(const std::string &name, Args... args)
177+
throw(std::runtime_error) {
178+
PyObject *func(load_function(name));
179+
// Create the tuple argument
180+
pyunique_ptr tup(PyTuple_New(sizeof...(args)));
181+
add_tuple_vars(tup, args...);
182+
// Call our object
183+
PyObject *ret(PyObject_CallObject(func, tup.get()));
184+
if(!ret)
185+
throw std::runtime_error("Failed to call function");
186+
return pyunique_ptr(ret);
187+
}
188+
189+
pyunique_ptr call_function(const std::string &name)
190+
throw(std::runtime_error) {
191+
PyObject *func(load_function(name));
192+
PyObject *ret(PyObject_CallObject(func, 0));
193+
if(!ret)
194+
throw std::runtime_error("Failed to call function");
195+
return pyunique_ptr(ret);
196+
}
197+
private:
198+
PyObject *load_function(const std::string &name)
199+
throw(std::runtime_error);
200+
201+
// Variadic template method to add items to a tuple
202+
template<typename First, typename... Rest>
203+
void add_tuple_vars(pyunique_ptr &tup, First head, Rest... tail) {
204+
add_tuple_var(
205+
tup,
206+
PyTuple_Size(tup.get()) - sizeof...(tail) - 1,
207+
alloc_pyobject(head)
208+
);
209+
add_tuple_vars(tup, tail...);
210+
}
211+
212+
// Base case for add_tuple_vars
213+
template<typename Arg>
214+
void add_tuple_vars(pyunique_ptr &tup, Arg arg) {
215+
add_tuple_var(tup, PyTuple_Size(tup.get()) - 1, alloc_pyobject(arg));
216+
}
217+
218+
// Adds a PyObject* to the tuple object
219+
void add_tuple_var(pyunique_ptr &tup, Py_ssize_t i, PyObject *pobj) {
220+
PyTuple_SetItem(tup.get(), i, pobj);
221+
}
222+
223+
pyunique_ptr module;
224+
std::map<std::string, PyObject*> functions;
225+
};
226+
227+
};
228+
229+
#endif // __PYWRAPPER_H

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL