1
1
// /
2
2
// / Copyright (c) 2016-2024 CNRS INRIA
3
+ // / Copyright (c) 2025-2025 Heriot-Watt University
3
4
// / This file was taken from Pinocchio (header
4
5
// / <pinocchio/bindings/python/utils/std-vector.hpp>)
5
6
// /
@@ -84,11 +85,14 @@ struct overload_base_get_item_for_std_vector
84
85
85
86
template <class Class >
86
87
void visit (Class &cl) const {
87
- cl.def (" __getitem__" , &base_get_item);
88
+ cl.def (" __getitem__" , &base_get_item_int)
89
+ .def (" __getitem__" , &base_get_item_slice)
90
+ .def (" __getitem__" , &base_get_item_list)
91
+ .def (" __getitem__" , &base_get_item_tuple);
88
92
}
89
93
90
94
private:
91
- static boost::python::object base_get_item (
95
+ static boost::python::object base_get_item_int (
92
96
boost::python::back_reference<Container &> container, PyObject *i_) {
93
97
index_type idx = convert_index (container.get (), i_);
94
98
typename Container::iterator i = container.get ().begin ();
@@ -104,6 +108,83 @@ struct overload_base_get_item_for_std_vector
104
108
return bp::object (bp::handle<>(convert (*i)));
105
109
}
106
110
111
+ static boost::python::object base_get_item_slice (
112
+ boost::python::back_reference<Container &> container,
113
+ boost::python::slice slice) {
114
+ bp::list out;
115
+ try {
116
+ auto rng =
117
+ slice.get_indices (container.get ().begin (), container.get ().end ());
118
+ // rng.start, rng.stop are iterators; rng.step is int; [start, stop] is
119
+ // closed
120
+ typename bp::to_python_indirect<value_type &,
121
+ bp::detail::make_reference_holder>
122
+ convert;
123
+ // forward or backward
124
+ for (typename Container::iterator it = rng.start ;;
125
+ std::advance (it, rng.step )) {
126
+ out.append (bp::object (bp::handle<>(convert (*it))));
127
+ if (it == rng.stop ) break ; // closed interval, include stop
128
+ }
129
+ } catch (const std::invalid_argument &) {
130
+ // Boost.Python specifies empty ranges throw invalid_argument.
131
+ // Return [] (matches Python's behavior for empty slices).
132
+ return bp::list ();
133
+ }
134
+ return out;
135
+ }
136
+
137
+ static bp::object base_get_item_list (bp::back_reference<Container &> c,
138
+ bp::list idxs) {
139
+ const Py_ssize_t m = bp::len (idxs);
140
+ bp::list out;
141
+ for (Py_ssize_t k = 0 ; k < m; ++k) {
142
+ bp::object obj = idxs[k];
143
+ bp::extract<long > ei (obj);
144
+ if (!ei.check ()) {
145
+ PyErr_SetString (PyExc_TypeError, " indices must be integers" );
146
+ bp::throw_error_already_set ();
147
+ }
148
+ auto idx = normalize_index (c.get ().size (), ei ());
149
+ out.append (elem_ref (c.get (), idx));
150
+ }
151
+ return out;
152
+ }
153
+
154
+ static bp::object base_get_item_tuple (bp::back_reference<Container &> c,
155
+ bp::tuple idxs) {
156
+ const Py_ssize_t m = bp::len (idxs);
157
+ bp::list out;
158
+ for (Py_ssize_t k = 0 ; k < m; ++k) {
159
+ bp::object obj = idxs[k];
160
+ bp::extract<long > ei (obj);
161
+ if (!ei.check ()) {
162
+ PyErr_SetString (PyExc_TypeError, " indices must be integers" );
163
+ bp::throw_error_already_set ();
164
+ }
165
+ auto idx = normalize_index (c.get ().size (), ei ());
166
+ out.append (elem_ref (c.get (), idx));
167
+ }
168
+ return out;
169
+ }
170
+
171
+ static index_type normalize_index (std::size_t n, long i) {
172
+ long idx = i;
173
+ if (idx < 0 ) idx += static_cast <long >(n);
174
+ if (idx < 0 || idx >= static_cast <long >(n)) {
175
+ PyErr_SetString (PyExc_IndexError, " index out of range" );
176
+ bp::throw_error_already_set ();
177
+ }
178
+ return static_cast <index_type>(idx);
179
+ }
180
+
181
+ static bp::object elem_ref (Container &c, index_type i) {
182
+ typename bp::to_python_indirect<value_type &,
183
+ bp::detail::make_reference_holder>
184
+ conv;
185
+ return bp::object (bp::handle<>(conv (c[i])));
186
+ }
187
+
107
188
static index_type convert_index (Container &container, PyObject *i_) {
108
189
bp::extract<long > i (i_);
109
190
if (i.check ()) {
0 commit comments