Skip to content

Commit 5ae3793

Browse files
authored
Merge pull request #325 from ManifoldFR/wj/move-std-vector
Copy std-vector and std-map from Pinocchio
2 parents 15fb426 + be7c2ef commit 5ae3793

17 files changed

+877
-71
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ repos:
55
rev: v15.0.4
66
hooks:
77
- id: clang-format
8-
args: [--style=Google]
8+
args: ['--style={BasedOnStyle: Google, SortIncludes: false}']
99
- repo: https://github.com/pre-commit/pre-commit-hooks
1010
rev: v4.4.0
1111
hooks:

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ set(${PROJECT_NAME}_HEADERS
135135
include/eigenpy/exception.hpp
136136
include/eigenpy/scalar-conversion.hpp
137137
include/eigenpy/expose.hpp
138+
include/eigenpy/copyable.hpp
138139
include/eigenpy/details.hpp
139140
include/eigenpy/fwd.hpp
140141
include/eigenpy/eigen-allocator.hpp
@@ -154,6 +155,9 @@ set(${PROJECT_NAME}_HEADERS
154155
include/eigenpy/user-type.hpp
155156
include/eigenpy/ufunc.hpp
156157
include/eigenpy/register.hpp
158+
include/eigenpy/std-map.hpp
159+
include/eigenpy/std-vector.hpp
160+
include/eigenpy/pickle-vector.hpp
157161
include/eigenpy/stride.hpp
158162
include/eigenpy/swig.hpp
159163
include/eigenpy/version.hpp)
@@ -194,6 +198,7 @@ set(${PROJECT_NAME}_SOURCES
194198
src/angle-axis.cpp
195199
src/quaternion.cpp
196200
src/geometry-conversion.cpp
201+
src/std-vector.cpp
197202
src/version.cpp)
198203

199204
add_library(${PROJECT_NAME} SHARED ${${PROJECT_NAME}_SOURCES}

include/eigenpy/copyable.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// Copyright (c) 2016-2021 CNRS INRIA
3+
//
4+
5+
#ifndef __eigenpy_utils_copyable_hpp__
6+
#define __eigenpy_utils_copyable_hpp__
7+
8+
#include <boost/python.hpp>
9+
10+
namespace eigenpy {
11+
12+
namespace bp = boost::python;
13+
14+
///
15+
/// \brief Add the Python method copy to allow a copy of this by calling the
16+
/// copy constructor.
17+
///
18+
template <class C>
19+
struct CopyableVisitor : public bp::def_visitor<CopyableVisitor<C> > {
20+
template <class PyClass>
21+
void visit(PyClass& cl) const {
22+
cl.def("copy", &copy, bp::arg("self"), "Returns a copy of *this.");
23+
}
24+
25+
private:
26+
static C copy(const C& self) { return C(self); }
27+
};
28+
} // namespace eigenpy
29+
30+
#endif // ifndef __eigenpy_utils_copyable_hpp__

include/eigenpy/eigen-allocator.hpp

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,22 @@ struct EigenAllocator {
232232
};
233233

234234
#if EIGEN_VERSION_AT_LEAST(3, 2, 0)
235+
/// @brief Check if we need to allocate @tparam MatType to convert @param
236+
/// pyArray.
237+
/// @details do not allocate if:
238+
/// want row-major & data C-contiguous OR
239+
/// want col-major & data F-contiguous OR
240+
/// you want a compile-time vector
241+
/// in these cases, data layout fits desired view layout
242+
template <typename MatType>
243+
inline bool is_arr_layout_compatible_with_mat_type(PyArrayObject *pyArray) {
244+
bool is_array_C_cont = PyArray_IS_C_CONTIGUOUS(pyArray);
245+
bool is_array_F_cont = PyArray_IS_F_CONTIGUOUS(pyArray);
246+
return (MatType::IsRowMajor && is_array_C_cont) ||
247+
(!MatType::IsRowMajor && is_array_F_cont) ||
248+
MatType::IsVectorAtCompileTime;
249+
}
250+
235251
template <typename MatType, int Options, typename Stride>
236252
struct EigenAllocator<Eigen::Ref<MatType, Options, Stride> > {
237253
typedef Eigen::Ref<MatType, Options, Stride> RefType;
@@ -255,16 +271,9 @@ struct EigenAllocator<Eigen::Ref<MatType, Options, Stride> > {
255271
const int pyArray_type_code = EIGENPY_GET_PY_ARRAY_TYPE(pyArray);
256272
const int Scalar_type_code = Register::getTypeCode<Scalar>();
257273
if (pyArray_type_code != Scalar_type_code) need_to_allocate |= true;
258-
if ((MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) &&
259-
!PyArray_IS_F_CONTIGUOUS(pyArray))) ||
260-
(!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) &&
261-
!PyArray_IS_C_CONTIGUOUS(pyArray))) ||
262-
MatType::IsVectorAtCompileTime ||
263-
(PyArray_IS_F_CONTIGUOUS(pyArray) &&
264-
PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
265-
need_to_allocate |= false;
266-
else
267-
need_to_allocate |= true;
274+
bool incompatible_layout =
275+
!is_arr_layout_compatible_with_mat_type<MatType>(pyArray);
276+
need_to_allocate |= incompatible_layout;
268277
if (Options !=
269278
Eigen::Unaligned) // we need to check whether the memory is correctly
270279
// aligned and composed of a continuous segment
@@ -365,16 +374,9 @@ struct EigenAllocator<const Eigen::Ref<const MatType, Options, Stride> > {
365374
const int Scalar_type_code = Register::getTypeCode<Scalar>();
366375

367376
if (pyArray_type_code != Scalar_type_code) need_to_allocate |= true;
368-
if ((MatType::IsRowMajor && (PyArray_IS_C_CONTIGUOUS(pyArray) &&
369-
!PyArray_IS_F_CONTIGUOUS(pyArray))) ||
370-
(!MatType::IsRowMajor && (PyArray_IS_F_CONTIGUOUS(pyArray) &&
371-
!PyArray_IS_C_CONTIGUOUS(pyArray))) ||
372-
MatType::IsVectorAtCompileTime ||
373-
(PyArray_IS_F_CONTIGUOUS(pyArray) &&
374-
PyArray_IS_C_CONTIGUOUS(pyArray))) // no need to allocate
375-
need_to_allocate |= false;
376-
else
377-
need_to_allocate |= true;
377+
bool incompatible_layout =
378+
!is_arr_layout_compatible_with_mat_type<MatType>(pyArray);
379+
need_to_allocate |= incompatible_layout;
378380
if (Options !=
379381
Eigen::Unaligned) // we need to check whether the memory is correctly
380382
// aligned and composed of a continuous segment

include/eigenpy/pickle-vector.hpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// Copyright (c) 2019-2020 CNRS INRIA
3+
//
4+
5+
#ifndef __eigenpy_utils_pickle_vector_hpp__
6+
#define __eigenpy_utils_pickle_vector_hpp__
7+
8+
#include <boost/python.hpp>
9+
#include <boost/python/stl_iterator.hpp>
10+
#include <boost/python/tuple.hpp>
11+
12+
namespace eigenpy {
13+
///
14+
/// \brief Create a pickle interface for the std::vector
15+
///
16+
/// \tparam VecType Vector Type to pickle
17+
///
18+
template <typename VecType>
19+
struct PickleVector : boost::python::pickle_suite {
20+
static boost::python::tuple getinitargs(const VecType&) {
21+
return boost::python::make_tuple();
22+
}
23+
24+
static boost::python::tuple getstate(boost::python::object op) {
25+
return boost::python::make_tuple(
26+
boost::python::list(boost::python::extract<const VecType&>(op)()));
27+
}
28+
29+
static void setstate(boost::python::object op, boost::python::tuple tup) {
30+
if (boost::python::len(tup) > 0) {
31+
VecType& o = boost::python::extract<VecType&>(op)();
32+
boost::python::stl_input_iterator<typename VecType::value_type> begin(
33+
tup[0]),
34+
end;
35+
while (begin != end) {
36+
o.push_back(*begin);
37+
++begin;
38+
}
39+
}
40+
}
41+
42+
static bool getstate_manages_dict() { return true; }
43+
};
44+
} // namespace eigenpy
45+
46+
#endif // ifndef __eigenpy_utils_pickle_vector_hpp__

include/eigenpy/quaternion.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,8 @@ class QuaternionVisitor
294294
return q;
295295
}
296296

297-
static Quaternion* FromTwoVectors(const Eigen::Ref<Vector3> u,
298-
const Eigen::Ref<Vector3> v) {
297+
static Quaternion* FromTwoVectors(const Eigen::Ref<const Vector3> u,
298+
const Eigen::Ref<const Vector3> v) {
299299
Quaternion* q(new Quaternion);
300300
q->setFromTwoVectors(u, v);
301301
return q;
@@ -308,12 +308,12 @@ class QuaternionVisitor
308308

309309
static Quaternion* DefaultConstructor() { return new Quaternion; }
310310

311-
static Quaternion* FromOneVector(const Eigen::Ref<Vector4> v) {
311+
static Quaternion* FromOneVector(const Eigen::Ref<const Vector4> v) {
312312
Quaternion* q(new Quaternion(v[3], v[0], v[1], v[2]));
313313
return q;
314314
}
315315

316-
static Quaternion* FromRotationMatrix(const Eigen::Ref<Matrix3> R) {
316+
static Quaternion* FromRotationMatrix(const Eigen::Ref<const Matrix3> R) {
317317
Quaternion* q(new Quaternion(R));
318318
return q;
319319
}

include/eigenpy/std-map.hpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/// Copyright (c) 2016-2022 CNRS INRIA
2+
/// This file was taken from Pinocchio (header
3+
/// <pinocchio/bindings/python/utils/std-vector.hpp>)
4+
///
5+
6+
#ifndef __eigenpy_utils_map_hpp__
7+
#define __eigenpy_utils_map_hpp__
8+
9+
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
10+
11+
namespace eigenpy {
12+
namespace details {
13+
template <typename Container>
14+
struct overload_base_get_item_for_std_map
15+
: public boost::python::def_visitor<
16+
overload_base_get_item_for_std_map<Container> > {
17+
typedef typename Container::value_type value_type;
18+
typedef typename Container::value_type::second_type data_type;
19+
typedef typename Container::key_type key_type;
20+
typedef typename Container::key_type index_type;
21+
22+
template <class Class>
23+
void visit(Class& cl) const {
24+
cl.def("__getitem__", &base_get_item);
25+
}
26+
27+
private:
28+
static boost::python::object base_get_item(
29+
boost::python::back_reference<Container&> container, PyObject* i_) {
30+
namespace bp = ::boost::python;
31+
32+
index_type idx = convert_index(container.get(), i_);
33+
typename Container::iterator i = container.get().find(idx);
34+
if (i == container.get().end()) {
35+
PyErr_SetString(PyExc_KeyError, "Invalid key");
36+
bp::throw_error_already_set();
37+
}
38+
39+
typename bp::to_python_indirect<data_type&,
40+
bp::detail::make_reference_holder>
41+
convert;
42+
return bp::object(bp::handle<>(convert(i->second)));
43+
}
44+
45+
static index_type convert_index(Container& /*container*/, PyObject* i_) {
46+
namespace bp = ::boost::python;
47+
bp::extract<key_type const&> i(i_);
48+
if (i.check()) {
49+
return i();
50+
} else {
51+
bp::extract<key_type> i(i_);
52+
if (i.check()) return i();
53+
}
54+
55+
PyErr_SetString(PyExc_TypeError, "Invalid index type");
56+
bp::throw_error_already_set();
57+
return index_type();
58+
}
59+
};
60+
61+
} // namespace details
62+
} // namespace eigenpy
63+
64+
#endif // ifndef __eigenpy_utils_map_hpp__

0 commit comments

Comments
 (0)