Commit f326fc11 authored by Joseph Mirabel's avatar Joseph Mirabel
Browse files

[python] Add pybind11 header.

parent 1ca9c789
#include <pybind11/pybind11.h>
#include <pinocchio/multibody/model.hpp>
namespace pinocchio {
namespace cpp2pybind11 {
namespace bp = boost::python;
template<typename T> pybind11::object to(T& t)
{
// Create PyObject using boost Python
typename bp::reference_existing_object::apply<T*>::type converter;
PyObject* pyobj = converter(t);
// Create the Pybind11 object
return pybind11::reinterpret_borrow<pybind11::object>(pyobj);
}
template <typename T>
auto to(T* t) {
// Create PyObject using boost Python
typename bp::manage_new_object::apply<T*>::type converter;
PyObject* pyobj = converter(t);
// Create the Pybind11 object
return pybind11::reinterpret_steal<pybind11::object>(pyobj);
}
template <typename ReturnType>
ReturnType& from(pybind11::object model) {
return boost::python::extract<ReturnType&>(model.ptr());
}
template <typename T>
struct convert_type {
typedef T type;
static inline auto _to(T t) { return t; }
static inline auto _from(type t) { return t; }
};
template <>
struct convert_type<void> {
static inline void _to() {}
};
template <typename T>
struct convert_boost_python_object {
typedef pybind11::object type;
static inline auto _to(T t) {
return to<typename std::remove_pointer<typename std::remove_reference<
typename std::remove_cv<T>::type>::type>::type>(t);
}
static inline T _from(type t) {
return from<
typename std::remove_cv<typename std::remove_reference<T>::type>::type>(
t);
}
};
#define ADD_CONVERT_TYPE(CLASS) \
template <> \
struct convert_type<pinocchio::CLASS> \
: convert_boost_python_object<pinocchio::CLASS> {}
ADD_CONVERT_TYPE(Model*);
ADD_CONVERT_TYPE(Model&);
ADD_CONVERT_TYPE(Model const&);
namespace internal {
template <typename R, typename... Args>
auto call(R (*f)(Args...), typename convert_type<Args>::type... args) {
return convert_type<R>::_to(f(convert_type<Args>::_from(args)...));
}
template <typename... Args>
void call(void (*f)(Args...), typename convert_type<Args>::type... args) {
return f(convert_type<Args>::_from(args)...);
}
template <typename T>
struct function_wrapper;
template <typename R, typename... Args>
struct function_wrapper<R (*)(Args...)> {
static const size_t nargs = sizeof...(Args);
typedef R result_type;
template <size_t i>
struct arg {
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
typedef R (*func_type)(Args...);
func_type f;
auto operator()(typename convert_type<Args>::type... args) {
// return convert_type<R>::_to(f(convert_type<Args>::_from(args)...));
return call(f, args...);
}
};
} // namespace internal
template <typename R, typename... Args>
internal::function_wrapper<R (*)(Args...)> make_function(R (*func)(Args...)) {
internal::function_wrapper<R (*)(Args...)> wrapper;
wrapper.f = func;
return wrapper;
}
} // namespace cpp2pybind11
} // namespace pinocchio
cmake_minimum_required(VERSION 3.4)
project(test_boost_pybind11 LANGUAGES CXX)
find_package(pybind11 REQUIRED)
find_package(pinocchio REQUIRED)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import sys; sys.stdout.write(sys.version[:3])"
OUTPUT_VARIABLE PYTHON_MAJOR_MINOR_VERSION)
set(BOOST_PYTHON python${PYTHON_MAJOR_MINOR_VERSION})
find_package(Boost 1.70 REQUIRED COMPONENTS ${BOOST_PYTHON})
pybind11_add_module(cpp2pybind11 cpp2pybind11.cpp)
target_link_libraries(cpp2pybind11 PRIVATE pinocchio::pinocchio Boost::${BOOST_PYTHON})
#include <pinocchio/multibody/model.hpp>
#include <pybind11/pybind11.h>
#include <boost/python.hpp>
#include <pinocchio/bindings/python/pybind11.hpp>
pinocchio::Model* make_model()
{
pinocchio::Model* model = new pinocchio::Model;
std::cout << "make_model: " << reinterpret_cast<intptr_t>(model) << std::endl;
return model;
}
pinocchio::Model& return_same_model(pinocchio::Model& m)
{
return m;
}
intptr_t get_ptr(pinocchio::Model& model)
{
return reinterpret_cast<intptr_t>(&model);
}
void test1(int i)
{
std::cout << "no conversion: " << ' ' << i << std::endl;
}
void testModel1(pinocchio::Model& model)
{
std::cout << "testModel1: " << &model << std::endl;
model.name = "testModel1: I modified the model name";
}
intptr_t testModel2(pinocchio::Model& model, int i)
{
std::cout << "testModel2: " << &model << ' ' << i << std::endl;
model.name = "testModel2: I modified the model name";
return reinterpret_cast<intptr_t>(&model);
}
intptr_t testModel3(pinocchio::Model const& model, int i)
{
std::cout << "testModel3: " << &model << ' ' << i << std::endl;
return reinterpret_cast<intptr_t>(&model);
}
void testModel_manual(pybind11::object model) {
testModel1(pinocchio::cpp2pybind11::from<pinocchio::Model&>(model));
}
PYBIND11_MODULE(cpp2pybind11, m) {
pybind11::module::import("pinocchio");
m.def("testModel_manual", testModel_manual);
m.def("test1", pinocchio::cpp2pybind11::make_function(&test1));
m.def("make_model", pinocchio::cpp2pybind11::make_function(&make_model));
m.def("return_same_model", pinocchio::cpp2pybind11::make_function(&return_same_model),
pybind11::return_value_policy::reference);
m.def("get_ptr", pinocchio::cpp2pybind11::make_function(&get_ptr));
m.def("testModel1", pinocchio::cpp2pybind11::make_function(&testModel1));
m.def("testModel2", pinocchio::cpp2pybind11::make_function(&testModel2));
m.def("testModel3", pinocchio::cpp2pybind11::make_function(&testModel3));
}
import cpp2pybind11, sys, gc
def print_ref_count(v,what=""):
# - 2 because one for variable v and one for variable inside getrefcount
idv = id(v)
gc.collect()
#n = len(gc.get_referrers(v))
n = sys.getrefcount(v)
print("ref count of", what, idv, n)
m = cpp2pybind11.make_model()
print_ref_count(m, "m")
print(cpp2pybind11.get_ptr(m))
print_ref_count(m, "m")
m.name = ""
cpp2pybind11.testModel1(m)
print_ref_count(m, "m")
assert m.name.startswith("testModel1")
addr2 = cpp2pybind11.testModel2(m, 1)
print_ref_count(m, "m")
assert m.name.startswith("testModel2")
addr3 = cpp2pybind11.testModel3(m, 2)
print_ref_count(m, "m")
assert addr2 == addr3
mm = cpp2pybind11.return_same_model(m)
# Not sure why but the ref count of m and mm sticks to one
print_ref_count(m, "m")
mmm = m
print_ref_count(m, "m")
print_ref_count(mm, "mm")
assert cpp2pybind11.get_ptr(m) == cpp2pybind11.get_ptr(mm)
if True:
print("deleting m")
del m
print("deleted m")
print("mm is", mm)
else:
print("deleting mm")
del mm
print("deleted mm")
print("m is", m)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment