1 |
|
|
#ifndef __pinocchio_python_pybind11_hpp__ |
2 |
|
|
#define __pinocchio_python_pybind11_hpp__ |
3 |
|
|
|
4 |
|
|
/// \mainpage Pinocchio PyBind11 helpers |
5 |
|
|
/// |
6 |
|
|
/// This package provides utilities to ease the use of Pinocchio objects when |
7 |
|
|
/// using PyBind11. |
8 |
|
|
/// There are two methods: |
9 |
|
|
/// 1. The developer-friendly but likely less user-friendly method: \ref |
10 |
|
|
/// PINOCCHIO_PYBIND11_TYPE_CASTER |
11 |
|
|
/// 2. The user-friendly but less developer-friendly method: \ref |
12 |
|
|
/// pinocchio::python::make_pybind11_function |
13 |
|
|
/// |
14 |
|
|
/// Both methods can be mixed. For both cases, you may |
15 |
|
|
/// \code |
16 |
|
|
/// // with necessary #define. See below |
17 |
|
|
/// #include <pinocchio/bindings/python/pybind11-all.hpp> |
18 |
|
|
/// \endcode |
19 |
|
|
/// to get some \subpage default_type_caster. |
20 |
|
|
/// |
21 |
|
|
/// \section example Example |
22 |
|
|
/// \code |
23 |
|
|
/// #define SCALAR double |
24 |
|
|
/// #define OPTIONS 0 |
25 |
|
|
/// #define JOINT_MODEL_COLLECTION ::pinocchio::JointCollectionDefaultTpl |
26 |
|
|
/// #include <pinocchio/bindings/python/pybind11-all.hpp> |
27 |
|
|
/// |
28 |
|
|
/// ... |
29 |
|
|
/// // method 1 |
30 |
|
|
/// m.def("function", my_function); |
31 |
|
|
/// // method 2 |
32 |
|
|
/// m.def("function", pinocchio::python::make_pybind11_function(my_function)); |
33 |
|
|
/// \endcode |
34 |
|
|
/// |
35 |
|
|
|
36 |
|
|
#include <iostream> |
37 |
|
|
#include <pinocchio/fwd.hpp> |
38 |
|
|
|
39 |
|
|
// This lines forces clang-format to keep the include split here |
40 |
|
|
#include <pybind11/pybind11.h> |
41 |
|
|
|
42 |
|
|
#include <boost/python.hpp> |
43 |
|
|
|
44 |
|
|
namespace pinocchio { |
45 |
|
|
namespace python { |
46 |
|
|
namespace bp = boost::python; |
47 |
|
|
namespace py = pybind11; |
48 |
|
|
|
49 |
|
|
template <typename T> |
50 |
|
10 |
inline py::object to(T& t) { |
51 |
|
|
// Create PyObject using boost Python |
52 |
✓✗ |
10 |
bp::object obj = bp::api::object(t); |
53 |
|
10 |
PyObject* pyobj = obj.ptr(); |
54 |
|
20 |
return pybind11::reinterpret_borrow<py::object>(pyobj); |
55 |
|
|
} |
56 |
|
|
template <typename T> |
57 |
|
2 |
inline py::object to(T* t) { |
58 |
|
|
// Create PyObject using boost Python |
59 |
|
|
typename bp::manage_new_object::apply<T*>::type converter; |
60 |
✓✗ |
2 |
PyObject* pyobj = converter(t); |
61 |
|
|
// Create the Pybind11 object |
62 |
|
2 |
return py::reinterpret_borrow<py::object>(pyobj); |
63 |
|
|
} |
64 |
|
|
|
65 |
|
|
template <typename ReturnType> |
66 |
|
32 |
inline ReturnType& from(py::handle model) { |
67 |
✓✗ |
32 |
return bp::extract<ReturnType&>(model.ptr()); |
68 |
|
|
} |
69 |
|
|
|
70 |
|
|
template <typename T> |
71 |
|
|
struct convert_type { |
72 |
|
|
typedef T type; |
73 |
|
7 |
static inline T _to(T t) { return t; } |
74 |
|
2 |
static inline type _from(type t) { return t; } |
75 |
|
|
}; |
76 |
|
|
template <> |
77 |
|
|
struct convert_type<void> { |
78 |
|
|
// typedef void type; |
79 |
|
|
// static inline void _to() {} |
80 |
|
|
}; |
81 |
|
|
|
82 |
|
|
template <typename T> |
83 |
|
|
struct convert_boost_python_object { |
84 |
|
|
typedef py::object type; |
85 |
|
12 |
static inline type _to(T t) { |
86 |
|
|
return to<typename std::remove_pointer<typename std::remove_reference< |
87 |
|
12 |
typename std::remove_cv<T>::type>::type>::type>(t); |
88 |
|
|
} |
89 |
|
16 |
static inline T _from(type t) { |
90 |
|
|
return from< |
91 |
|
32 |
typename std::remove_cv<typename std::remove_reference<T>::type>::type>( |
92 |
|
32 |
t); |
93 |
|
|
} |
94 |
|
|
}; |
95 |
|
|
|
96 |
|
|
/// \brief Defines a conversion used by \ref make_pybind11_function |
97 |
|
|
#define PINOCCHIO_PYBIND11_ADD_CONVERT_TYPE(CLASS) \ |
98 |
|
|
namespace pinocchio { \ |
99 |
|
|
namespace python { \ |
100 |
|
|
template <> \ |
101 |
|
|
struct convert_type<CLASS> : convert_boost_python_object<CLASS> {}; \ |
102 |
|
|
} \ |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
/// \brief Defines a set of conversion used by \ref make_pybind11_function |
106 |
|
|
#define _SINGLE_ARG(...) __VA_ARGS__ |
107 |
|
|
#define PINOCCHIO_PYBIND11_ADD_ALL_CONVERT_TYPE(CLASS) \ |
108 |
|
|
PINOCCHIO_PYBIND11_ADD_CONVERT_TYPE(_SINGLE_ARG(CLASS)) \ |
109 |
|
|
PINOCCHIO_PYBIND11_ADD_CONVERT_TYPE(_SINGLE_ARG(CLASS const)) \ |
110 |
|
|
PINOCCHIO_PYBIND11_ADD_CONVERT_TYPE(_SINGLE_ARG(CLASS&)) \ |
111 |
|
|
PINOCCHIO_PYBIND11_ADD_CONVERT_TYPE(_SINGLE_ARG(CLASS const&)) \ |
112 |
|
|
PINOCCHIO_PYBIND11_ADD_CONVERT_TYPE(_SINGLE_ARG(CLASS*)) \ |
113 |
|
|
PINOCCHIO_PYBIND11_ADD_CONVERT_TYPE(_SINGLE_ARG(CLASS const*)) |
114 |
|
|
|
115 |
|
|
namespace internal { |
116 |
|
|
|
117 |
|
|
template <typename R, typename... Args> |
118 |
|
26 |
auto call(R (*f)(Args...), typename convert_type<Args>::type... args) { |
119 |
✓✓✗✓ ✓✗✓✓ ✗✓✗ |
26 |
return convert_type<R>::_to(f(convert_type<Args>::_from(args)...)); |
120 |
|
|
} |
121 |
|
|
template <typename... Args> |
122 |
|
2 |
void call(void (*f)(Args...), typename convert_type<Args>::type... args) { |
123 |
✓✗✓✗
|
2 |
f(convert_type<Args>::_from(args)...); |
124 |
|
|
} |
125 |
|
|
|
126 |
|
|
template <typename T> |
127 |
|
|
struct function_wrapper; |
128 |
|
|
|
129 |
|
|
template <typename R, typename... Args> |
130 |
|
|
struct function_wrapper<R (*)(Args...)> { |
131 |
|
|
static const size_t nargs = sizeof...(Args); |
132 |
|
|
|
133 |
|
|
typedef R result_type; |
134 |
|
|
|
135 |
|
|
template <size_t i> |
136 |
|
|
struct arg { |
137 |
|
|
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type; |
138 |
|
|
}; |
139 |
|
|
|
140 |
|
|
typedef R (*func_type)(Args...); |
141 |
|
|
|
142 |
|
|
func_type f; |
143 |
|
|
|
144 |
|
|
// typename convert_type<result_type>::type |
145 |
|
28 |
auto operator()(typename convert_type<Args>::type... args) { |
146 |
✓✓✗ |
28 |
return call(f, args...); |
147 |
|
|
} |
148 |
|
|
}; |
149 |
|
|
} // namespace internal |
150 |
|
|
|
151 |
|
|
/// \brief Creates a function wrapper. |
152 |
|
|
/// |
153 |
|
|
/// Using function wrapper has the advantage of being copy-less when possible |
154 |
|
|
/// but the disadvantage of requiring to wrap the exposed function. |
155 |
|
|
/// |
156 |
|
|
/// The wrapper does: |
157 |
|
|
/// - converts the argument if a conversion has been previously declared, |
158 |
|
|
/// - call the wrapped function |
159 |
|
|
/// - converts the result if a conversion has been previously declared. |
160 |
|
|
template <typename R, typename... Args> |
161 |
|
22 |
internal::function_wrapper<R (*)(Args...)> make_pybind11_function( |
162 |
|
|
R (*func)(Args...)) { |
163 |
|
|
internal::function_wrapper<R (*)(Args...)> wrapper; |
164 |
|
22 |
wrapper.f = func; |
165 |
|
22 |
return wrapper; |
166 |
|
|
} |
167 |
|
|
|
168 |
|
|
template <typename T> |
169 |
|
1 |
py::object default_arg(T t) { |
170 |
|
1 |
py::object obj = to<T>(t); |
171 |
|
|
//obj.inc_ref(); |
172 |
|
1 |
return obj; |
173 |
|
|
} |
174 |
|
|
|
175 |
|
|
/// \brief Add a PyBind11 type caster. |
176 |
|
|
/// |
177 |
|
|
/// Using type caster has the advantage of not requiring to wrap the exposed |
178 |
|
|
/// functions but the disadvantage of systematically requiring a copy. |
179 |
|
|
/// |
180 |
|
|
/// See \ref https://pybind11.readthedocs.io/en/stable/advanced/cast/custom.html |
181 |
|
|
/// "PyBind11 documentation" |
182 |
|
|
#define PINOCCHIO_PYBIND11_TYPE_CASTER(native_type, boost_python_name) \ |
183 |
|
|
namespace pybind11 { \ |
184 |
|
|
namespace detail { \ |
185 |
|
|
template <> \ |
186 |
|
|
struct type_caster<native_type> { \ |
187 |
|
|
PYBIND11_TYPE_CASTER(_SINGLE_ARG(native_type), boost_python_name); \ |
188 |
|
|
\ |
189 |
|
|
/* Python -> C++ */ \ |
190 |
|
|
bool load(pybind11::handle src, bool) { \ |
191 |
|
|
PyObject* source = src.ptr(); \ |
192 |
|
|
value = boost::python::extract<native_type>(source); \ |
193 |
|
|
return !PyErr_Occurred(); \ |
194 |
|
|
} \ |
195 |
|
|
/* C++ -> Python */ \ |
196 |
|
|
static pybind11::handle cast(native_type src, \ |
197 |
|
|
pybind11::return_value_policy /*policy*/, \ |
198 |
|
|
pybind11::handle /*parent*/) { \ |
199 |
|
|
return boost::python::api::object(src).ptr(); \ |
200 |
|
|
} \ |
201 |
|
|
}; \ |
202 |
|
|
} /* namespace detail */ \ |
203 |
|
|
} /* namespace pybind11 */ |
204 |
|
|
|
205 |
|
|
} // namespace python |
206 |
|
|
} // namespace pinocchio |
207 |
|
|
|
208 |
|
|
#undef _SINGLE_ARG |
209 |
|
|
|
210 |
|
|
#endif // #ifndef __pinocchio_python_pybind11_hpp__ |