GCC Code Coverage Report


Directory: ./
File: bindings/python/crocoddyl/utils/set_indexing_suite.hpp
Date: 2025-02-24 23:41:29
Exec Total Coverage
Lines: 6 57 10.5%
Branches: 0 48 0.0%

Line Branch Exec Source
1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (C) 2022, University of Edinburgh
5 // Copyright note valid unless otherwise stated in individual files.
6 // All rights reserved.
7 ///////////////////////////////////////////////////////////////////////////////
8
9 #ifndef BINDINGS_PYTHON_CROCODDYL_UTILS_SET_INDEXING_SUITE_HPP_
10 #define BINDINGS_PYTHON_CROCODDYL_UTILS_SET_INDEXING_SUITE_HPP_
11
12 #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
13
14 namespace crocoddyl {
15 namespace python {
16
17 template <typename Container, bool NoProxy, typename DerivedPolicies>
18 class set_indexing_suite;
19
20 namespace detail {
21 template <typename Container, bool NoProxy>
22 class final_set_derived_policies
23 : public crocoddyl::python::set_indexing_suite<
24 Container, NoProxy, final_set_derived_policies<Container, NoProxy> > {
25 };
26 } // namespace detail
27
28 // The set_indexing_suite class is a predefined indexing_suite derived
29 // class for wrapping std::set (and std::set like) classes. It provides
30 // all the policies required by the indexing_suite (see indexing_suite).
31 // Example usage:
32 //
33 // class X {...};
34 //
35 // ...
36 //
37 // class_<std::set<X> >("XSet")
38 // .def(set_indexing_suite<std::set<X> >())
39 // ;
40 //
41 // By default indexed elements are returned by proxy. This can be
42 // disabled by supplying *true* in the NoProxy template parameter.
43 //
44 template <typename Container, bool NoProxy = false,
45 typename DerivedPolicies =
46 detail::final_set_derived_policies<Container, NoProxy> >
47 class set_indexing_suite
48 : public boost::python::vector_indexing_suite<Container, NoProxy,
49 DerivedPolicies> {
50 typedef boost::python::vector_indexing_suite<Container, NoProxy,
51 DerivedPolicies>
52 base;
53
54 public:
55 typedef typename base::data_type data_type;
56 typedef typename base::index_type index_type;
57 typedef typename base::key_type key_type;
58
59 template <class Class>
60 10 static void extension_def(Class& class_) {
61 10 class_.def("add", &function<DerivedPolicies::add>)
62 10 .def("remove", &function<DerivedPolicies::remove>)
63 10 .def("discard", &function<DerivedPolicies::discard>)
64 10 .def("clear", &DerivedPolicies::clear);
65 10 }
66
67 static bool contains(Container& container, key_type const& key) {
68 return container.find(key) != container.end();
69 }
70
71 static void add(Container& container, data_type const& v) {
72 container.insert(v);
73 }
74
75 static void discard(Container& container, data_type const& v) {
76 container.erase(v);
77 }
78
79 static void remove(Container& container, data_type const& v) {
80 if (!container.erase(v)) {
81 PyErr_SetString(PyExc_KeyError, "Element doesn't exist");
82 boost::python::throw_error_already_set();
83 }
84 }
85
86 static void clear(Container& container) { container.clear(); }
87
88 static data_type get_item(Container& container, index_type i) {
89 return *std::next(container.begin(), i);
90 }
91
92 static void set_item(Container&, index_type, data_type const&) {
93 not_supported();
94 }
95
96 static void delete_item(Container& container, index_type i) {
97 container.erase(advance(container.begin(), i));
98 }
99
100 static boost::python::object get_slice(Container& container, index_type from,
101 index_type to) {
102 if (from > to) return boost::python::object(Container());
103
104 auto s = slice(container, from, to);
105 return boost::python::object(Container(s.first, s.second));
106 }
107
108 static void set_slice(Container&, index_type, index_type, data_type const&) {
109 not_supported();
110 }
111
112 template <typename Iter>
113 static void set_slice(Container&, index_type, index_type, Iter, Iter) {
114 not_supported();
115 }
116
117 static void delete_slice(Container& container, index_type from,
118 index_type to) {
119 if (to >= from) {
120 auto s = slice(container, from, to);
121 container.erase(s.first, s.second);
122 }
123 }
124
125 private:
126 static typename Container::iterator advance(
127 typename Container::iterator it, typename Container::difference_type i) {
128 return std::advance(it, i), it;
129 }
130
131 static std::pair<typename Container::iterator, typename Container::iterator>
132 slice(Container& container, index_type from, index_type to) {
133 BOOST_ASSERT(to >= from);
134 std::pair<typename Container::iterator, typename Container::iterator> s;
135 s.first = container.begin();
136 std::advance(s.first, from);
137 s.second = s.first;
138 std::advance(s.second, to - from);
139 return s;
140 }
141
142 template <void (*fn)(Container&, data_type const&)>
143 static void function(Container& container, const boost::python::object v) {
144 using namespace boost::python;
145 extract<data_type&> elemRef(v);
146
147 if (elemRef.check()) {
148 fn(container, elemRef());
149 } else {
150 extract<data_type> elem(v);
151 if (elem.check()) {
152 fn(container, elem());
153 } else {
154 PyErr_SetString(PyExc_TypeError, "Invalid type");
155 throw_error_already_set();
156 }
157 }
158 }
159
160 static void not_supported() {
161 PyErr_SetString(PyExc_TypeError,
162 "__setitem__ not supported for set object");
163 boost::python::throw_error_already_set();
164 }
165 };
166
167 } // namespace python
168 } // namespace crocoddyl
169
170 #endif // BINDINGS_PYTHON_CROCODDYL_UTILS_SET_INDEXING_SUITE_HPP_
171