* Implements boolean indexing. This produces a one-dimensional * array which picks out all of the elements of 'self' for which * the corresponding element of 'op' is True. * * This operation is somewhat unfortunate, because to produce * a one-dimensional output array, it has to choose a particular * iteration order, in the case of NumPy that is always C order even * though this function all
| 915 | * though this function allows different choices. |
| 916 | */ |
| 917 | NPY_NO_EXPORT PyArrayObject * |
| 918 | array_boolean_subscript(PyArrayObject *self, |
| 919 | PyArrayObject *bmask, NPY_ORDER order) |
| 920 | { |
| 921 | npy_intp size, itemsize; |
| 922 | char *ret_data; |
| 923 | PyArray_Descr *dtype; |
| 924 | PyArrayObject *ret; |
| 925 | |
| 926 | size = count_boolean_trues(PyArray_NDIM(bmask), PyArray_DATA(bmask), |
| 927 | PyArray_DIMS(bmask), PyArray_STRIDES(bmask)); |
| 928 | |
| 929 | /* Allocate the output of the boolean indexing */ |
| 930 | dtype = PyArray_DESCR(self); |
| 931 | Py_INCREF(dtype); |
| 932 | ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, 1, &size, |
| 933 | NULL, NULL, 0, NULL); |
| 934 | if (ret == NULL) { |
| 935 | return NULL; |
| 936 | } |
| 937 | |
| 938 | itemsize = dtype->elsize; |
| 939 | ret_data = PyArray_DATA(ret); |
| 940 | |
| 941 | /* Create an iterator for the data */ |
| 942 | if (size > 0) { |
| 943 | NpyIter *iter; |
| 944 | PyArrayObject *op[2] = {self, bmask}; |
| 945 | npy_uint32 flags, op_flags[2]; |
| 946 | npy_intp fixed_strides[3]; |
| 947 | |
| 948 | NpyIter_IterNextFunc *iternext; |
| 949 | npy_intp innersize, *innerstrides; |
| 950 | char **dataptrs; |
| 951 | |
| 952 | npy_intp self_stride, bmask_stride, subloopsize; |
| 953 | char *self_data; |
| 954 | char *bmask_data; |
| 955 | NPY_BEGIN_THREADS_DEF; |
| 956 | |
| 957 | /* Set up the iterator */ |
| 958 | flags = NPY_ITER_EXTERNAL_LOOP | NPY_ITER_REFS_OK; |
| 959 | op_flags[0] = NPY_ITER_READONLY | NPY_ITER_NO_BROADCAST; |
| 960 | op_flags[1] = NPY_ITER_READONLY; |
| 961 | |
| 962 | iter = NpyIter_MultiNew(2, op, flags, order, NPY_NO_CASTING, |
| 963 | op_flags, NULL); |
| 964 | if (iter == NULL) { |
| 965 | Py_DECREF(ret); |
| 966 | return NULL; |
| 967 | } |
| 968 | |
| 969 | /* Get a dtype transfer function */ |
| 970 | NpyIter_GetInnerFixedStrideArray(iter, fixed_strides); |
| 971 | NPY_cast_info cast_info; |
| 972 | /* |
| 973 | * TODO: Ignoring cast flags, since this is only ever a copy. In |
| 974 | * principle that may not be quite right in some future? |
no test coverage detected