Program Listing for File std-vector.hpp
↰ Return to documentation for file (include/eigenpy/std-vector.hpp
)
#ifndef __eigenpy_utils_std_vector_hpp__
#define __eigenpy_utils_std_vector_hpp__
#include <boost/mpl/if.hpp>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <iterator>
#include <string>
#include <vector>
#include "eigenpy/eigenpy.hpp"
#include "eigenpy/config.hpp"
#include "eigenpy/copyable.hpp"
#include "eigenpy/eigen-to-python.hpp"
#include "eigenpy/pickle-vector.hpp"
#include "eigenpy/registration.hpp"
#include "eigenpy/utils/empty-visitor.hpp"
namespace eigenpy {
// Forward declaration
template <typename vector_type, bool NoProxy = false>
struct StdContainerFromPythonList;
namespace details {
template <typename T>
bool from_python_list(PyObject *obj_ptr, T *) {
// Check if it is a list
if (!PyList_Check(obj_ptr)) return false;
// Retrieve the underlying list
bp::object bp_obj(bp::handle<>(bp::borrowed(obj_ptr)));
bp::list bp_list(bp_obj);
bp::ssize_t list_size = bp::len(bp_list);
// Check if all the elements contained in the current vector is of type T
for (bp::ssize_t k = 0; k < list_size; ++k) {
bp::extract<T> elt(bp_list[k]);
if (!elt.check()) return false;
}
return true;
}
template <typename vector_type, bool NoProxy>
struct build_list {
static ::boost::python::list run(vector_type &vec, const bool deep_copy) {
if (deep_copy) return build_list<vector_type, true>::run(vec, true);
bp::list bp_list;
for (size_t k = 0; k < vec.size(); ++k) {
bp_list.append(boost::ref(vec[k]));
}
return bp_list;
}
};
template <typename vector_type>
struct build_list<vector_type, true> {
static ::boost::python::list run(vector_type &vec, const bool) {
typedef bp::iterator<vector_type> iterator;
return bp::list(iterator()(vec));
}
};
template <typename Container>
struct overload_base_get_item_for_std_vector
: public boost::python::def_visitor<
overload_base_get_item_for_std_vector<Container> > {
typedef typename Container::value_type value_type;
typedef typename Container::value_type data_type;
typedef size_t index_type;
template <class Class>
void visit(Class &cl) const {
cl.def("__getitem__", &base_get_item);
}
private:
static boost::python::object base_get_item(
boost::python::back_reference<Container &> container, PyObject *i_) {
index_type idx = convert_index(container.get(), i_);
typename Container::iterator i = container.get().begin();
std::advance(i, idx);
if (i == container.get().end()) {
PyErr_SetString(PyExc_KeyError, "Invalid index");
bp::throw_error_already_set();
}
typename bp::to_python_indirect<data_type &,
bp::detail::make_reference_holder>
convert;
return bp::object(bp::handle<>(convert(*i)));
}
static index_type convert_index(Container &container, PyObject *i_) {
bp::extract<long> i(i_);
if (i.check()) {
long index = i();
if (index < 0) index += (long)container.size();
if (index >= long(container.size()) || index < 0) {
PyErr_SetString(PyExc_IndexError, "Index out of range");
bp::throw_error_already_set();
}
return (index_type)index;
}
PyErr_SetString(PyExc_TypeError, "Invalid index type");
bp::throw_error_already_set();
return index_type();
}
};
} // namespace details
} // namespace eigenpy
namespace boost {
namespace python {
template <typename MatrixType>
struct extract_to_eigen_ref
: converter::extract_rvalue<Eigen::Ref<MatrixType> > {
typedef Eigen::Ref<MatrixType> RefType;
protected:
typedef converter::extract_rvalue<RefType> base;
public:
typedef RefType result_type;
operator result_type() const { return (*this)(); }
extract_to_eigen_ref(PyObject *o) : base(o) {}
extract_to_eigen_ref(api::object const &o) : base(o.ptr()) {}
};
template <typename Scalar, int Rows, int Cols, int Options, int MaxRows,
int MaxCols>
struct extract<Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> &>
: extract_to_eigen_ref<
Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols> > {
typedef Eigen::Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>
MatrixType;
typedef extract_to_eigen_ref<MatrixType> base;
extract(PyObject *o) : base(o) {}
extract(api::object const &o) : base(o.ptr()) {}
};
template <typename Derived>
struct extract<Eigen::MatrixBase<Derived> &>
: extract_to_eigen_ref<Eigen::MatrixBase<Derived> > {
typedef Eigen::MatrixBase<Derived> MatrixType;
typedef extract_to_eigen_ref<MatrixType> base;
extract(PyObject *o) : base(o) {}
extract(api::object const &o) : base(o.ptr()) {}
};
template <typename Derived>
struct extract<Eigen::RefBase<Derived> &>
: extract_to_eigen_ref<Eigen::RefBase<Derived> > {
typedef Eigen::RefBase<Derived> MatrixType;
typedef extract_to_eigen_ref<MatrixType> base;
extract(PyObject *o) : base(o) {}
extract(api::object const &o) : base(o.ptr()) {}
};
namespace converter {
template <typename Type, class Allocator>
struct reference_arg_from_python<std::vector<Type, Allocator> &>
: arg_lvalue_from_python_base {
typedef std::vector<Type, Allocator> vector_type;
typedef vector_type &ref_vector_type;
typedef ref_vector_type result_type;
typedef extract<Type &> extract_type;
reference_arg_from_python(PyObject *py_obj)
: arg_lvalue_from_python_base(converter::get_lvalue_from_python(
py_obj, registered<vector_type>::converters)),
m_data(NULL),
m_source(py_obj),
vec_ptr(NULL) {
if (result() != 0) // we have found a lvalue converter
return;
// Check if py_obj is a py_list, which can then be converted to an
// std::vector
bool is_convertible =
::eigenpy::details::from_python_list(py_obj, (Type *)(0));
if (!is_convertible) return;
typedef ::eigenpy::StdContainerFromPythonList<vector_type> Constructor;
Constructor::construct(py_obj, &m_data.stage1);
void *&m_result = const_cast<void *&>(result());
m_result = m_data.stage1.convertible;
vec_ptr = reinterpret_cast<vector_type *>(m_data.storage.bytes);
}
result_type operator()() const {
return ::boost::python::detail::void_ptr_to_reference(result(),
(result_type(*)())0);
}
~reference_arg_from_python() {
if (m_data.stage1.convertible == m_data.storage.bytes) {
// Copy back the reference
const vector_type &vec = *vec_ptr;
list bp_list(handle<>(borrowed(m_source)));
for (size_t i = 0; i < vec.size(); ++i) {
typename extract_type::result_type elt = extract_type(bp_list[i]);
elt = vec[i];
}
}
}
private:
rvalue_from_python_data<ref_vector_type> m_data;
PyObject *m_source;
vector_type *vec_ptr;
};
} // namespace converter
} // namespace python
} // namespace boost
namespace eigenpy {
namespace details {
template <class Container>
struct container_traits {
// default behavior expects allocators
typedef typename Container::allocator_type Allocator;
};
template <typename _Tp, std::size_t Size>
struct container_traits<std::array<_Tp, Size> > {
typedef void Allocator;
};
}; // namespace details
template <typename vector_type, bool NoProxy>
struct StdContainerFromPythonList {
typedef typename vector_type::value_type T;
typedef typename details::container_traits<vector_type>::Allocator Allocator;
static void *convertible(PyObject *obj_ptr) {
namespace bp = boost::python;
// Check if it is a list
if (!PyList_Check(obj_ptr)) return 0;
// Retrieve the underlying list
bp::object bp_obj(bp::handle<>(bp::borrowed(obj_ptr)));
bp::list bp_list(bp_obj);
bp::ssize_t list_size = bp::len(bp_list);
// Check if all the elements contained in the current vector is of type T
for (bp::ssize_t k = 0; k < list_size; ++k) {
bp::extract<T> elt(bp_list[k]);
if (!elt.check()) return 0;
}
return obj_ptr;
}
static void construct(
PyObject *obj_ptr,
boost::python::converter::rvalue_from_python_stage1_data *memory) {
// Extract the list
bp::object bp_obj(bp::handle<>(bp::borrowed(obj_ptr)));
bp::list bp_list(bp_obj);
void *storage =
reinterpret_cast<
bp::converter::rvalue_from_python_storage<vector_type> *>(
reinterpret_cast<void *>(memory))
->storage.bytes;
typedef bp::stl_input_iterator<T> iterator;
// Build the std::vector
new (storage) vector_type(iterator(bp_list), iterator());
// Validate the construction
memory->convertible = storage;
}
static void register_converter() {
::boost::python::converter::registry::push_back(
&convertible, &construct, ::boost::python::type_id<vector_type>());
}
static ::boost::python::list tolist(vector_type &self,
const bool deep_copy = false) {
return details::build_list<vector_type, NoProxy>::run(self, deep_copy);
}
};
namespace internal {
template <typename T,
bool has_operator_equal_value =
std::is_base_of<std::true_type, has_operator_equal<T> >::value>
struct contains_algo;
template <typename T>
struct contains_algo<T, true> {
template <class Container, typename key_type>
static bool run(const Container &container, key_type const &key) {
return std::find(container.begin(), container.end(), key) !=
container.end();
}
};
template <typename T>
struct contains_algo<T, false> {
template <class Container, typename key_type>
static bool run(const Container &container, key_type const &key) {
for (size_t k = 0; k < container.size(); ++k) {
if (&container[k] == &key) return true;
}
return false;
}
};
template <class Container, bool NoProxy>
struct contains_vector_derived_policies
: public ::boost::python::vector_indexing_suite<
Container, NoProxy,
contains_vector_derived_policies<Container, NoProxy> > {
typedef typename Container::value_type key_type;
static bool contains(Container &container, key_type const &key) {
return contains_algo<key_type>::run(container, key);
}
};
template <typename Container, bool NoProxy, typename CoVisitor>
struct ExposeStdMethodToStdVector
: public boost::python::def_visitor<
ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor> > {
typedef StdContainerFromPythonList<Container, NoProxy>
FromPythonListConverter;
ExposeStdMethodToStdVector(const CoVisitor &co_visitor)
: m_co_visitor(co_visitor) {}
template <class Class>
void visit(Class &cl) const {
cl.def(m_co_visitor)
.def("tolist", &FromPythonListConverter::tolist,
(bp::arg("self"), bp::arg("deep_copy") = false),
"Returns the std::vector as a Python list.")
.def("reserve", &Container::reserve,
(bp::arg("self"), bp::arg("new_cap")),
"Increase the capacity of the vector to a value that's greater "
"or equal to new_cap.")
.def(CopyableVisitor<Container>());
}
const CoVisitor &m_co_visitor;
};
template <typename Container, bool NoProxy, typename CoVisitor>
static ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor>
createExposeStdMethodToStdVector(const CoVisitor &co_visitor) {
return ExposeStdMethodToStdVector<Container, NoProxy, CoVisitor>(co_visitor);
}
} // namespace internal
namespace internal {
template <typename vector_type, bool T_picklable = false>
struct def_pickle_std_vector {
static void run(bp::class_<vector_type> &) {}
};
template <typename vector_type>
struct def_pickle_std_vector<vector_type, true> {
static void run(bp::class_<vector_type> &cl) {
cl.def_pickle(PickleVector<vector_type>());
}
};
} // namespace internal
template <class vector_type, bool NoProxy = false,
bool EnableFromPythonListConverter = true, bool pickable = true>
struct StdVectorPythonVisitor {
typedef typename vector_type::value_type value_type;
typedef StdContainerFromPythonList<vector_type, NoProxy>
FromPythonListConverter;
static void expose(const std::string &class_name,
const std::string &doc_string = "") {
expose(class_name, doc_string, EmptyPythonVisitor());
}
template <typename DerivedVisitor>
static void expose(const std::string &class_name,
const bp::def_visitor<DerivedVisitor> &visitor) {
expose(class_name, "", visitor);
}
template <typename DerivedVisitor>
static void expose(const std::string &class_name,
const std::string &doc_string,
const bp::def_visitor<DerivedVisitor> &visitor) {
// Apply visitor on already registered type or if type is not already
// registered, we define and apply the visitor on it
auto add_std_visitor =
internal::createExposeStdMethodToStdVector<vector_type, NoProxy>(
visitor);
if (!register_symbolic_link_to_registered_type<vector_type>(
add_std_visitor)) {
bp::class_<vector_type> cl(class_name.c_str(), doc_string.c_str());
cl.def(IdVisitor<vector_type>());
// Standard vector indexing definition
boost::python::vector_indexing_suite<
vector_type, NoProxy,
internal::contains_vector_derived_policies<vector_type, NoProxy> >
vector_indexing;
cl.def(bp::init<size_t, const value_type &>(
bp::args("self", "size", "value"),
"Constructor from a given size and a given value."))
.def(bp::init<const vector_type &>(bp::args("self", "other"),
"Copy constructor"))
.def(vector_indexing)
.def(add_std_visitor);
internal::def_pickle_std_vector<vector_type, pickable>::run(cl);
}
if (EnableFromPythonListConverter) {
// Register conversion
FromPythonListConverter::register_converter();
}
}
};
void EIGENPY_DLLAPI exposeStdVector();
template <typename MatType, typename Alloc = Eigen::aligned_allocator<MatType> >
void exposeStdVectorEigenSpecificType(const char *name) {
typedef std::vector<MatType, Alloc> VecMatType;
std::string full_name = "StdVec_";
full_name += name;
StdVectorPythonVisitor<VecMatType>::expose(
full_name.c_str(),
details::overload_base_get_item_for_std_vector<VecMatType>());
}
} // namespace eigenpy
#endif // ifndef __eigenpy_utils_std_vector_hpp__