-
Notifications
You must be signed in to change notification settings - Fork 47
Expose std::array types #412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
jorisv
merged 27 commits into
stack-of-tasks:devel
from
ManifoldFR:topic/wjallet/expose-std-array
Dec 4, 2023
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
bf02d84
[std-vector] StdContainerFromPythonList : remove Allocator typedef
ManifoldFR 4f07565
Add header eigenpy/std-array.hpp
ManifoldFR dd8071d
[std-array] array_indexing_suite: fix up set_sice from iterators
ManifoldFR d0f7674
[unittest] add unit tests for std::array
ManifoldFR 6211cf5
[std-array] array_indexing_suite: get_slice returns std::vector<T>
ManifoldFR 153ba3e
[unittest] std::array test: test for size of _ints_slice
ManifoldFR f9e84ec
[std-array] add SliceAllocator template parameter
ManifoldFR a9903ad
[std-array] add SliceAllocator template parameter to StdArrayPythonVi…
ManifoldFR 2cbf10e
[std-array] fix size of returned slice
ManifoldFR 5e60184
[unittest] expose std::vector<VectorXd> for use in slices
ManifoldFR ced9002
[unittest/python] update test_std_array.py
ManifoldFR 82ec784
[std-array] use visitor in StdArrayPythonVisitor::expose()
ManifoldFR 5d487e8
[unittest/python] update test_std_array.py
ManifoldFR ba6751b
[unittest] std_array : add test_struct
ManifoldFR a03deb8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 70bae63
[std-array] add docstring for StdArrayPythonVisitor
ManifoldFR 384c193
[unittest/python] test set_slice on std::array<int, ...>
ManifoldFR 36d2ba3
[cmake] I forgot to add the std-array.hpp header...
ManifoldFR 58571e5
update changelog
ManifoldFR dc9789e
[std-vector] add container_traits struct
ManifoldFR f4d61cc
[std-array] defining array_indexing_suite::extend and ::append not re…
ManifoldFR 2c18089
[std-array] array_indexing_suite::delete_item and ::delete_slice will…
ManifoldFR 70e518d
[std-array] various fixes
ManifoldFR 6ad6448
Update CHANGELOG
ManifoldFR cc30e46
[std-array] Test array edge cases
jorisv 44f8bdc
[std-array] implement tolist() for std::array
ManifoldFR ff7517a
[unittest/python] test .tolist()
ManifoldFR File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| /// Copyright (c) 2023 CNRS INRIA | ||
|
|
||
| #ifndef __eigenpy_utils_std_array_hpp__ | ||
| #define __eigenpy_utils_std_array_hpp__ | ||
|
|
||
| #include <boost/python/suite/indexing/indexing_suite.hpp> | ||
| #include "eigenpy/std-vector.hpp" | ||
|
|
||
| #include <array> | ||
|
|
||
| namespace eigenpy { | ||
|
|
||
| template <typename Container, bool NoProxy, class SliceAllocator, | ||
| class DerivedPolicies> | ||
| class array_indexing_suite; | ||
| namespace details { | ||
|
|
||
| template <typename Container, bool NoProxy, class SliceAllocator> | ||
| class final_array_derived_policies | ||
| : public array_indexing_suite< | ||
| Container, NoProxy, SliceAllocator, | ||
| final_array_derived_policies<Container, NoProxy, SliceAllocator> > {}; | ||
| } // namespace details | ||
|
|
||
| template <typename Container, bool NoProxy = false, | ||
| class SliceAllocator = std::allocator<typename Container::value_type>, | ||
| class DerivedPolicies = details::final_array_derived_policies< | ||
| Container, NoProxy, SliceAllocator> > | ||
| class array_indexing_suite | ||
| : public bp::vector_indexing_suite<Container, NoProxy, DerivedPolicies> { | ||
| public: | ||
| typedef typename Container::value_type data_type; | ||
| typedef typename Container::value_type key_type; | ||
| typedef typename Container::size_type index_type; | ||
| typedef typename Container::size_type size_type; | ||
| typedef typename Container::difference_type difference_type; | ||
| typedef std::vector<data_type, SliceAllocator> slice_vector_type; | ||
| static constexpr std::size_t Size = std::tuple_size<Container>{}; | ||
|
|
||
| template <class Class> | ||
| static void extension_def(Class &) {} | ||
|
|
||
| // throws exception | ||
| static void delete_item(Container &, index_type) { | ||
| PyErr_SetString(PyExc_NotImplementedError, | ||
| "Cannot delete item from std::array type."); | ||
| bp::throw_error_already_set(); | ||
| } | ||
|
|
||
| // throws exception | ||
| static void delete_slice(Container &, index_type, index_type) { | ||
| PyErr_SetString(PyExc_NotImplementedError, | ||
| "Cannot delete slice from std::array type."); | ||
| bp::throw_error_already_set(); | ||
| } | ||
|
|
||
| static void set_slice(Container &container, index_type from, index_type to, | ||
| data_type const &v) { | ||
| if (from >= to) { | ||
| PyErr_SetString(PyExc_NotImplementedError, | ||
| "Setting this slice would insert into an std::array, " | ||
| "which is not supported."); | ||
| bp::throw_error_already_set(); | ||
| } else { | ||
| std::fill(container.begin() + from, container.begin() + to, v); | ||
| } | ||
| } | ||
|
|
||
| template <class Iter> | ||
| static void set_slice(Container &container, index_type from, index_type to, | ||
| Iter first, Iter last) { | ||
| if (from >= to) { | ||
| PyErr_SetString(PyExc_NotImplementedError, | ||
| "Setting this slice would insert into an std::array, " | ||
| "which is not supported."); | ||
| bp::throw_error_already_set(); | ||
| } else { | ||
| if (long(to - from) == std::distance(first, last)) { | ||
| std::copy(first, last, container.begin() + from); | ||
| } else { | ||
| PyErr_SetString(PyExc_NotImplementedError, | ||
| "Size of std::array slice and size of right-hand side " | ||
| "iterator are incompatible."); | ||
| bp::throw_error_already_set(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| static bp::object get_slice(Container &container, index_type from, | ||
| index_type to) { | ||
| if (from > to) return bp::object(slice_vector_type()); | ||
| slice_vector_type out; | ||
| for (size_t i = from; i < to; i++) { | ||
| out.push_back(container[i]); | ||
| } | ||
| return bp::object(std::move(out)); | ||
| } | ||
| }; | ||
|
|
||
| /// \brief Expose an std::array (a C++11 fixed-size array) from a given type | ||
| /// \tparam array_type std::array type to expose | ||
| /// \tparam NoProxy When set to false, the elements will be copied when | ||
| /// returned to Python. | ||
| /// \tparam SliceAllocator Allocator type to use for slices of std::array type | ||
| /// accessed using e.g. __getitem__[0:4] in Python. These slices are returned as | ||
| /// std::vector (dynamic size). | ||
| template <typename array_type, bool NoProxy = false, | ||
| class SliceAllocator = | ||
| std::allocator<typename array_type::value_type> > | ||
| struct StdArrayPythonVisitor { | ||
| typedef typename array_type::value_type value_type; | ||
|
|
||
| static ::boost::python::list tolist(array_type &self) { | ||
| return details::build_list<array_type, NoProxy>::run(self); | ||
| } | ||
|
|
||
| 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) { | ||
| if (!register_symbolic_link_to_registered_type<array_type>()) { | ||
| bp::class_<array_type> cl(class_name.c_str(), doc_string.c_str()); | ||
| cl.def(bp::init<const array_type &>(bp::args("self", "other"), | ||
| "Copy constructor")); | ||
|
|
||
| array_indexing_suite<array_type, NoProxy, SliceAllocator> indexing_suite; | ||
| cl.def(indexing_suite) | ||
| .def(visitor) | ||
| .def("tolist", tolist, bp::arg("self"), | ||
| "Returns the std::array as a Python list."); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| /// Exposes std::array<MatrixType, Size> | ||
| template <typename MatrixType, std::size_t Size> | ||
| void exposeStdArrayEigenSpecificType(const char *name) { | ||
| std::ostringstream oss; | ||
| oss << "StdArr"; | ||
| oss << Size << "_" << name; | ||
| typedef std::array<MatrixType, Size> array_type; | ||
| StdArrayPythonVisitor<array_type, false, | ||
| Eigen::aligned_allocator<MatrixType> >:: | ||
| expose(oss.str(), | ||
| details::overload_base_get_item_for_std_vector<array_type>()); | ||
| } | ||
|
|
||
| } // namespace eigenpy | ||
|
|
||
| #endif // ifndef __eigenpy_utils_std_array_hpp__ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,143 @@ | ||
| import std_array | ||
|
|
||
|
|
||
| ints = std_array.get_arr_3_ints() | ||
| print(ints[0]) | ||
| print(ints[1]) | ||
| print(ints[2]) | ||
| print(ints.tolist()) | ||
| assert ints.tolist() == [1, 2, 3] | ||
|
|
||
| _ints_slice = ints[1:3] | ||
| print("Printing slice...") | ||
| for el in _ints_slice: | ||
| print(el) | ||
|
|
||
| ref = [1, 2, 3] | ||
| assert len(ref[1:2]) == 1 # sanity check | ||
|
|
||
| assert len(_ints_slice) == 2, "Slice size should be 1, got %d" % len(_ints_slice) | ||
| assert _ints_slice[0] == 2 | ||
| assert _ints_slice[1] == 3 | ||
|
|
||
| # Test that insert/delete is impossible with the slice operator | ||
|
|
||
| # prepend | ||
| try: | ||
| ints[0:0] = [0, 1] | ||
| except NotImplementedError: | ||
| pass | ||
| else: | ||
| assert False, "Insert value with slice operator should be impossible" | ||
|
|
||
| # append | ||
| try: | ||
| ints[10:12] = [0] | ||
| except NotImplementedError: | ||
| pass | ||
| else: | ||
| assert False, "Insert value with slice operator should be impossible" | ||
|
|
||
| # append | ||
| try: | ||
| ints[3:3] = [0] | ||
| except NotImplementedError: | ||
| pass | ||
| else: | ||
| assert False, "Insert value with slice operator should be impossible" | ||
|
|
||
| # Erase two elements and replace by one | ||
| try: | ||
| ints[1:3] = [0] | ||
| except NotImplementedError: | ||
| pass | ||
| else: | ||
| assert False, "Insert value with slice operator should be impossible" | ||
|
|
||
| # Erase two elements and replace by three | ||
| try: | ||
| ints[1:3] = [0, 1, 2] | ||
| except NotImplementedError: | ||
| pass | ||
| else: | ||
| assert False, "Insert value with slice operator should be impossible" | ||
|
|
||
| # Test that delete operator is not implemented | ||
| # Index delete | ||
| try: | ||
| del ints[0] | ||
| except NotImplementedError: | ||
| pass | ||
| else: | ||
| assert False, "del is not implemented" | ||
|
|
||
| # Slice delete | ||
| try: | ||
| del ints[1:3] | ||
| except NotImplementedError: | ||
| pass | ||
| else: | ||
| assert False, "del is not implemented" | ||
|
|
||
| # Slice delete | ||
| try: | ||
| del ints[1:3] | ||
| except NotImplementedError: | ||
| pass | ||
| else: | ||
| assert False, "del is not implemented" | ||
|
|
||
| # Test that append/extend are not implemented | ||
| # append | ||
| try: | ||
| ints.append(4) | ||
| except AttributeError: | ||
| pass | ||
| else: | ||
| assert False, "append is not implemented" | ||
|
|
||
| # extend | ||
| try: | ||
| ints.extend([4, 5]) | ||
| except AttributeError: | ||
| pass | ||
| else: | ||
| assert False, "extend is not implemented" | ||
|
|
||
| # Test set_slice nominal case | ||
| ints[1:3] = [10, 20] | ||
| assert ints[1] == 10 | ||
| assert ints[2] == 20 | ||
|
|
||
| # print(ints.tolist()) | ||
|
|
||
| vecs = std_array.get_arr_3_vecs() | ||
| assert len(vecs) == 3 | ||
| print(vecs[0]) | ||
| print(vecs[1]) | ||
| print(vecs[2]) | ||
|
|
||
| # slices do not work for Eigen objects... | ||
|
|
||
| # v2 = vecs[:] | ||
| # assert isinstance(v2, std_array.StdVec_VectorXd) | ||
| # assert len(v2) == 3 | ||
| # print(v2.tolist()) | ||
| # print(v2[0]) | ||
|
|
||
| ts = std_array.test_struct() | ||
| assert len(ts.integs) == 3 | ||
| assert len(ts.vecs) == 2 | ||
| print(ts.integs[:].tolist()) | ||
| print(ts.vecs[0]) | ||
| print(ts.vecs[1]) | ||
|
|
||
| ts.integs[:] = 111 | ||
| print("Test of set_slice for std::array<int>:", ts.integs[:].tolist()) | ||
| for el in ts.integs: | ||
| assert el == 111 | ||
|
|
||
| ts.vecs[0][0] = 0.0 | ||
| ts.vecs[1][0] = -243 | ||
| print(ts.vecs[0]) | ||
| print(ts.vecs[1]) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.