7#ifndef __eigenpy_utils_std_vector_hpp__ 8#define __eigenpy_utils_std_vector_hpp__ 10#include <boost/mpl/if.hpp> 11#include <boost/python.hpp> 12#include <boost/python/stl_iterator.hpp> 13#include <boost/python/suite/indexing/vector_indexing_suite.hpp> 18#include "eigenpy/eigenpy.hpp" 19#include "eigenpy/config.hpp" 20#include "eigenpy/copyable.hpp" 21#include "eigenpy/eigen-to-python.hpp" 22#include "eigenpy/pickle-vector.hpp" 23#include "eigenpy/registration.hpp" 24#include "eigenpy/utils/empty-visitor.hpp" 28template <
typename vector_type,
bool NoProxy = false>
35bool from_python_list(PyObject *obj_ptr, T *) {
37 if (!PyList_Check(obj_ptr))
return false;
40 bp::object bp_obj(bp::handle<>(bp::borrowed(obj_ptr)));
41 bp::list bp_list(bp_obj);
42 bp::ssize_t list_size = bp::len(bp_list);
45 for (bp::ssize_t k = 0; k < list_size; ++k) {
46 bp::extract<T> elt(bp_list[k]);
47 if (!elt.check())
return false;
53template <
typename vector_type,
bool NoProxy>
55 static ::boost::python::list run(vector_type &vec,
const bool deep_copy) {
56 if (deep_copy)
return build_list<vector_type, true>::run(vec,
true);
59 for (
size_t k = 0; k < vec.size(); ++k) {
60 bp_list.append(boost::ref(vec[k]));
66template <
typename vector_type>
68 static ::boost::python::list run(vector_type &vec,
const bool) {
69 typedef bp::iterator<vector_type> iterator;
70 return bp::list(iterator()(vec));
77template <
typename Container>
79 :
public boost::python::def_visitor<
80 overload_base_get_item_for_std_vector<Container>> {
81 typedef typename Container::value_type value_type;
82 typedef typename Container::value_type data_type;
83 typedef size_t index_type;
85 template <
class Class>
86 void visit(Class &cl)
const {
87 cl.def(
"__getitem__", &base_get_item);
91 static boost::python::object base_get_item(
92 boost::python::back_reference<Container &> container, PyObject *i_) {
93 index_type idx = convert_index(container.get(), i_);
94 typename Container::iterator i = container.get().begin();
96 if (i == container.get().end()) {
97 PyErr_SetString(PyExc_KeyError,
"Invalid index");
98 bp::throw_error_already_set();
101 typename bp::to_python_indirect<data_type &,
102 bp::detail::make_reference_holder>
104 return bp::object(bp::handle<>(convert(*i)));
107 static index_type convert_index(Container &container, PyObject *i_) {
108 bp::extract<long> i(i_);
111 if (index < 0) index += (long)container.size();
112 if (index >=
long(container.size()) || index < 0) {
113 PyErr_SetString(PyExc_IndexError,
"Index out of range");
114 bp::throw_error_already_set();
116 return (index_type)index;
119 PyErr_SetString(PyExc_TypeError,
"Invalid index type");
120 bp::throw_error_already_set();
130template <
typename MatrixType>
131struct extract_to_eigen_ref
132 : converter::extract_rvalue<Eigen::Ref<MatrixType>> {
133 typedef Eigen::Ref<MatrixType> RefType;
136 typedef converter::extract_rvalue<RefType> base;
139 typedef RefType result_type;
141 operator result_type()
const {
return (*
this)(); }
143 extract_to_eigen_ref(PyObject *o) : base(o) {}
144 extract_to_eigen_ref(api::object
const &o) : base(o.ptr()) {}
149template <
typename Scalar,
int Rows,
int Cols,
int Options,
int MaxRows,
151struct extract<Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> &>
152 : extract_to_eigen_ref<
153 Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>> {
154 typedef Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>
156 typedef extract_to_eigen_ref<MatrixType> base;
157 extract(PyObject *o) : base(o) {}
158 extract(api::object
const &o) : base(o.ptr()) {}
161template <
typename Derived>
162struct extract<Eigen::MatrixBase<Derived> &>
163 : extract_to_eigen_ref<Eigen::MatrixBase<Derived>> {
164 typedef Eigen::MatrixBase<Derived> MatrixType;
165 typedef extract_to_eigen_ref<MatrixType> base;
166 extract(PyObject *o) : base(o) {}
167 extract(api::object
const &o) : base(o.ptr()) {}
170template <
typename Derived>
171struct extract<Eigen::RefBase<Derived> &>
172 : extract_to_eigen_ref<Eigen::RefBase<Derived>> {
173 typedef Eigen::RefBase<Derived> MatrixType;
174 typedef extract_to_eigen_ref<MatrixType> base;
175 extract(PyObject *o) : base(o) {}
176 extract(api::object
const &o) : base(o.ptr()) {}
181template <
typename Type,
class Allocator>
182struct reference_arg_from_python<std::vector<Type, Allocator> &>
183 : arg_lvalue_from_python_base {
184 typedef std::vector<Type, Allocator> vector_type;
185 typedef vector_type &ref_vector_type;
186 typedef ref_vector_type result_type;
187 typedef extract<Type &> extract_type;
189 reference_arg_from_python(PyObject *py_obj)
190 : arg_lvalue_from_python_base(converter::get_lvalue_from_python(
191 py_obj, registered<vector_type>::converters)),
200 bool is_convertible =
201 ::eigenpy::details::from_python_list(py_obj, (Type *)(0));
202 if (!is_convertible)
return;
204 typedef ::eigenpy::StdContainerFromPythonList<vector_type> Constructor;
205 Constructor::construct(py_obj, &m_data.stage1);
207 void *&m_result =
const_cast<void *&
>(result());
208 m_result = m_data.stage1.convertible;
209 vec_ptr =
reinterpret_cast<vector_type *
>(m_data.storage.bytes);
212 result_type operator()()
const {
213 return ::boost::python::detail::void_ptr_to_reference(result(),
214 (result_type (*)())0);
217 ~reference_arg_from_python() {
218 if (m_data.stage1.convertible == m_data.storage.bytes) {
220 const vector_type &vec = *vec_ptr;
221 list bp_list(handle<>(borrowed(m_source)));
222 for (
size_t i = 0; i < vec.size(); ++i) {
223 typename extract_type::result_type elt = extract_type(bp_list[i]);
230 rvalue_from_python_data<ref_vector_type> m_data;
232 vector_type *vec_ptr;
243template <
class Container>
246 typedef typename Container::allocator_type Allocator;
249template <
typename _Tp, std::
size_t Size>
260template <
typename vector_type,
bool NoProxy>
262 typedef typename vector_type::value_type T;
263 typedef typename details::container_traits<vector_type>::Allocator Allocator;
267 namespace bp = boost::python;
270 if (!PyList_Check(obj_ptr))
return 0;
273 bp::object bp_obj(bp::handle<>(bp::borrowed(obj_ptr)));
274 bp::list bp_list(bp_obj);
275 bp::ssize_t list_size = bp::len(bp_list);
278 for (bp::ssize_t k = 0; k < list_size; ++k) {
279 bp::extract<T> elt(bp_list[k]);
280 if (!elt.check())
return 0;
290 boost::python::converter::rvalue_from_python_stage1_data *memory) {
292 bp::object bp_obj(bp::handle<>(bp::borrowed(obj_ptr)));
293 bp::list bp_list(bp_obj);
297 bp::converter::rvalue_from_python_storage<vector_type> *
>(
298 reinterpret_cast<void *
>(memory))
301 typedef bp::stl_input_iterator<T> iterator;
304 new (storage) vector_type(iterator(bp_list), iterator());
307 memory->convertible = storage;
310 static void register_converter() {
311 ::boost::python::converter::registry::push_back(
315 static ::boost::python::list tolist(vector_type &self,
316 const bool deep_copy =
false) {
317 return details::build_list<vector_type, NoProxy>::run(self, deep_copy);
324 bool has_operator_equal_value =
325 std::is_base_of<std::true_type, has_operator_equal<T>>::value>
329struct contains_algo<T, true> {
330 template <
class Container,
typename key_type>
331 static bool run(
const Container &container, key_type
const &key) {
332 return std::find(container.begin(), container.end(), key) !=
338struct contains_algo<T, false> {
339 template <
class Container,
typename key_type>
340 static bool run(
const Container &container, key_type
const &key) {
341 for (
size_t k = 0; k < container.size(); ++k) {
342 if (&container[k] == &key)
return true;
348template <
class Container,
bool NoProxy>
349struct contains_vector_derived_policies
350 :
public ::boost::python::vector_indexing_suite<
352 contains_vector_derived_policies<Container, NoProxy>> {
353 typedef typename Container::value_type key_type;
355 static bool contains(Container &container, key_type
const &key) {
356 return contains_algo<key_type>::run(container, key);
365template <
typename Container,
bool NoProxy,
typename CoVisitor>
366struct ExposeStdMethodToStdVector
367 :
public boost::python::def_visitor<
368 ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor>> {
369 typedef StdContainerFromPythonList<Container, NoProxy>
370 FromPythonListConverter;
372 ExposeStdMethodToStdVector(
const CoVisitor &co_visitor)
373 : m_co_visitor(co_visitor) {}
375 template <
class Class>
376 void visit(Class &cl)
const {
378 .def(
"tolist", &FromPythonListConverter::tolist,
379 (bp::arg(
"self"), bp::arg(
"deep_copy") =
false),
380 "Returns the std::vector as a Python list.")
381 .def(
"reserve", &Container::reserve,
382 (bp::arg(
"self"), bp::arg(
"new_cap")),
383 "Increase the capacity of the vector to a value that's greater " 384 "or equal to new_cap.")
385 .def(CopyableVisitor<Container>());
388 const CoVisitor &m_co_visitor;
392template <
typename Container,
bool NoProxy,
typename CoVisitor>
393static ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor>
394createExposeStdMethodToStdVector(
const CoVisitor &co_visitor) {
395 return ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor>(co_visitor);
401template <
typename vector_type,
bool T_picklable = false>
402struct def_pickle_std_vector {
403 static void run(bp::class_<vector_type> &) {}
406template <
typename vector_type>
407struct def_pickle_std_vector<vector_type, true> {
408 static void run(bp::class_<vector_type> &cl) {
409 cl.def_pickle(PickleVector<vector_type>());
422template <
class vector_type,
bool NoProxy =
false,
423 bool EnableFromPythonListConverter =
true,
bool pickable =
true>
425 typedef typename vector_type::value_type value_type;
427 FromPythonListConverter;
429 static void expose(
const std::string &class_name,
430 const std::string &doc_string =
"") {
434 template <
typename DerivedVisitor>
435 static void expose(
const std::string &class_name,
436 const bp::def_visitor<DerivedVisitor> &visitor) {
437 expose(class_name,
"", visitor);
440 template <
typename DerivedVisitor>
441 static void expose(
const std::string &class_name,
442 const std::string &doc_string,
443 const bp::def_visitor<DerivedVisitor> &visitor) {
446 auto add_std_visitor =
447 internal::createExposeStdMethodToStdVector<vector_type, NoProxy>(
451 bp::class_<vector_type> cl(class_name.c_str(), doc_string.c_str());
455 boost::python::vector_indexing_suite<
456 vector_type, NoProxy,
457 internal::contains_vector_derived_policies<vector_type, NoProxy>>
460 cl.def(bp::init<size_t, const value_type &>(
461 bp::args(
"self",
"size",
"value"),
462 "Constructor from a given size and a given value."))
463 .def(bp::init<const vector_type &>(bp::args(
"self",
"other"),
466 .def(vector_indexing)
467 .def(add_std_visitor);
469 internal::def_pickle_std_vector<vector_type, pickable>::run(cl);
471 if (EnableFromPythonListConverter) {
473 FromPythonListConverter::register_converter();
483template <
typename MatType,
typename Alloc = Eigen::aligned_allocator<MatType>>
484void exposeStdVectorEigenSpecificType(
const char *name) {
485 typedef std::vector<MatType, Alloc> VecMatType;
486 std::string full_name =
"StdVec_";
488 StdVectorPythonVisitor<VecMatType>::expose(
void expose()
Call the expose function of a given type T.
void EIGENPY_DLLAPI exposeStdVector()
bool register_symbolic_link_to_registered_type()
Symlink to the current scope the already registered class T.
Add the Python method id to retrieving a unique id for a given object exposed with Boost....
Register the conversion from a Python list to a std::vector.
static void construct(PyObject *obj_ptr, boost::python::converter::rvalue_from_python_stage1_data *memory)
Allocate the std::vector and fill it with the element contained in the list.
static void * convertible(PyObject *obj_ptr)
Check if obj_ptr can be converted.
Expose an std::vector from a type given as template argument.
Change the behavior of indexing (method getitem in Python). This is suitable for container of Eigen m...