* Turn an index argument into a c-array of `PyObject *`s, one for each index. * * When a tuple is passed, the tuple elements are unpacked into the buffer. * Anything else is handled by unpack_scalar(). * * @param index The index object, which may or may not be a tuple. This is * a borrowed reference. * @param result An empty buffer of PyObject* to write each index
| 221 | * dispose of them. |
| 222 | */ |
| 223 | NPY_NO_EXPORT npy_intp |
| 224 | unpack_indices(PyObject *index, PyObject **result, npy_intp result_n) |
| 225 | { |
| 226 | /* It is likely that the logic here can be simplified. See the discussion |
| 227 | * on https://github.com/numpy/numpy/pull/21029 |
| 228 | */ |
| 229 | |
| 230 | /* Fast route for passing a tuple */ |
| 231 | if (PyTuple_CheckExact(index)) { |
| 232 | return unpack_tuple((PyTupleObject *)index, result, result_n); |
| 233 | } |
| 234 | |
| 235 | /* |
| 236 | * Passing a tuple subclass - coerce to the base type. This incurs an |
| 237 | * allocation, but doesn't need to be a fast path anyway. Note that by |
| 238 | * calling `PySequence_Tuple`, we ensure that the subclass `__iter__` is |
| 239 | * called. |
| 240 | */ |
| 241 | if (PyTuple_Check(index)) { |
| 242 | PyTupleObject *tup = (PyTupleObject *) PySequence_Tuple(index); |
| 243 | if (tup == NULL) { |
| 244 | return -1; |
| 245 | } |
| 246 | npy_intp n = unpack_tuple(tup, result, result_n); |
| 247 | Py_DECREF(tup); |
| 248 | return n; |
| 249 | } |
| 250 | |
| 251 | return unpack_scalar(index, result, result_n); |
| 252 | } |
| 253 | |
| 254 | /** |
| 255 | * Prepare an npy_index_object from the python slicing object. |
no test coverage detected