static PyObject * array_slice(PyArrayObject *self, Py_ssize_t ilow, Py_ssize_t ihigh) { PyArrayObject *ret; PyArray_Descr *dtype; Py_ssize_t dim0; char *data; npy_intp shape[NPY_MAXDIMS]; if (PyArray_NDIM(self) == 0) { PyErr_SetString(PyExc_ValueError, "cannot slice a 0-d array"); return NULL; } dim0 = PyArray_DIM(self, 0); if (ilow < 0) { ilow = 0; } else if (ilow > dim0) { ilow = dim0; } if (ihigh < ilow) { ihigh = ilow; } else if (ihigh > dim0) { ihigh = dim0; } data = PyArray_DATA(self); if (ilow < ihigh) { data += ilow * PyArray_STRIDE(self, 0); } /* Same shape except dimension 0 */ shape[0] = ihigh - ilow; memcpy(shape+1, PyArray_DIMS(self) + 1, (PyArray_NDIM(self)-1)*sizeof(npy_intp)); dtype = PyArray_DESCR(self); Py_INCREF(dtype); ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self), dtype, PyArray_NDIM(self), shape, PyArray_STRIDES(self), data, PyArray_FLAGS(self) & ~(NPY_ARRAY_MASKNA | NPY_ARRAY_OWNMASKNA), (PyObject *)self); if (ret == NULL) { return NULL; } Py_INCREF(self); if (PyArray_SetBaseObject(ret, (PyObject *)self) < 0) { Py_DECREF(ret); return NULL; } PyArray_UpdateFlags(ret, NPY_ARRAY_UPDATE_ALL); /* Also take a view of the NA mask if it exists */ if (PyArray_HASMASKNA(self)) { PyArrayObject_fields *fret = (PyArrayObject_fields *)ret; fret->maskna_dtype = PyArray_MASKNA_DTYPE(self); Py_INCREF(fret->maskna_dtype); data = PyArray_MASKNA_DATA(self); if (ilow < ihigh) { data += ilow * PyArray_MASKNA_STRIDES(self)[0]; } fret->maskna_data = data; memcpy(fret->maskna_strides, PyArray_MASKNA_STRIDES(self), PyArray_NDIM(self) * sizeof(npy_intp)); /* This view doesn't own the mask */ fret->flags |= NPY_ARRAY_MASKNA; fret->flags &= ~NPY_ARRAY_OWNMASKNA; } return (PyObject *)ret; }
/*NUMPY_API * * Returns true if the array has an NA mask. When * NA dtypes are implemented, will also return true * if the array's dtype has NA support. */ NPY_NO_EXPORT npy_bool PyArray_HasNASupport(PyArrayObject *arr) { return PyArray_HASMASKNA(arr); }
/*NUMPY_API * Clip * * TODO: For adding NA support, a Clip UFunc should be created, then * this should call that ufunc. 'min' and 'max' can default to * the -inf/+inf or the smallest/largest representable values * of the dtype respectively. */ NPY_NO_EXPORT PyObject * PyArray_Clip(PyArrayObject *self, PyObject *min, PyObject *max, PyArrayObject *out) { PyArray_FastClipFunc *func; int outgood = 0, ingood = 0; PyArrayObject *maxa = NULL; PyArrayObject *mina = NULL; PyArrayObject *newout = NULL, *newin = NULL; PyArray_Descr *indescr, *newdescr; char *max_data, *min_data; PyObject *zero; /* Treat None the same as NULL */ if (min == Py_None) { min = NULL; } if (max == Py_None) { max = NULL; } if ((max == NULL) && (min == NULL)) { PyErr_SetString(PyExc_ValueError, "array_clip: must set either max or min"); return NULL; } func = PyArray_DESCR(self)->f->fastclip; /* Trigger the slow array clip for NA support as well */ if (func == NULL || PyArray_HASMASKNA(self) || (min != NULL && (!PyArray_CheckAnyScalar(min) || (PyArray_Check(min) && PyArray_HASMASKNA((PyArrayObject *)min)))) || (max != NULL && (!PyArray_CheckAnyScalar(max) || (PyArray_Check(max) && PyArray_HASMASKNA((PyArrayObject *)max))))) { return _slow_array_clip(self, min, max, out); } /* Use the fast scalar clip function */ /* First we need to figure out the correct type */ indescr = NULL; if (min != NULL) { indescr = PyArray_DescrFromObject(min, NULL); if (indescr == NULL) { return NULL; } } if (max != NULL) { newdescr = PyArray_DescrFromObject(max, indescr); Py_XDECREF(indescr); if (newdescr == NULL) { return NULL; } } else { /* Steal the reference */ newdescr = indescr; } /* * Use the scalar descriptor only if it is of a bigger * KIND than the input array (and then find the * type that matches both). */ if (PyArray_ScalarKind(newdescr->type_num, NULL) > PyArray_ScalarKind(PyArray_DESCR(self)->type_num, NULL)) { indescr = PyArray_PromoteTypes(newdescr, PyArray_DESCR(self)); func = indescr->f->fastclip; if (func == NULL) { return _slow_array_clip(self, min, max, out); } } else { indescr = PyArray_DESCR(self); Py_INCREF(indescr); } Py_DECREF(newdescr); if (!PyDataType_ISNOTSWAPPED(indescr)) { PyArray_Descr *descr2; descr2 = PyArray_DescrNewByteorder(indescr, '='); Py_DECREF(indescr); if (descr2 == NULL) { goto fail; } indescr = descr2; } /* Convert max to an array */ if (max != NULL) { maxa = (PyArrayObject *)PyArray_FromAny(max, indescr, 0, 0, NPY_ARRAY_DEFAULT, NULL); if (maxa == NULL) { return NULL; } } else { /* Side-effect of PyArray_FromAny */ Py_DECREF(indescr); } /* * If we are unsigned, then make sure min is not < 0 * This is to match the behavior of _slow_array_clip * * We allow min and max to go beyond the limits * for other data-types in which case they * are interpreted as their modular counterparts. */ if (min != NULL) { if (PyArray_ISUNSIGNED(self)) { int cmp; zero = PyInt_FromLong(0); cmp = PyObject_RichCompareBool(min, zero, Py_LT); if (cmp == -1) { Py_DECREF(zero); goto fail; } if (cmp == 1) { min = zero; } else { Py_DECREF(zero); Py_INCREF(min); } } else { Py_INCREF(min); } /* Convert min to an array */ Py_INCREF(indescr); mina = (PyArrayObject *)PyArray_FromAny(min, indescr, 0, 0, NPY_ARRAY_DEFAULT, NULL); Py_DECREF(min); if (mina == NULL) { goto fail; } } /* * Check to see if input is single-segment, aligned, * and in native byteorder */ if (PyArray_ISONESEGMENT(self) && PyArray_CHKFLAGS(self, NPY_ARRAY_ALIGNED) && PyArray_ISNOTSWAPPED(self) && (PyArray_DESCR(self) == indescr)) { ingood = 1; } if (!ingood) { int flags; if (PyArray_ISFORTRAN(self)) { flags = NPY_ARRAY_FARRAY; } else { flags = NPY_ARRAY_CARRAY; } Py_INCREF(indescr); newin = (PyArrayObject *)PyArray_FromArray(self, indescr, flags); if (newin == NULL) { goto fail; } } else { newin = self; Py_INCREF(newin); } /* * At this point, newin is a single-segment, aligned, and correct * byte-order array of the correct type * * if ingood == 0, then it is a copy, otherwise, * it is the original input. */ /* * If we have already made a copy of the data, then use * that as the output array */ if (out == NULL && !ingood) { out = newin; } /* * Now, we know newin is a usable array for fastclip, * we need to make sure the output array is available * and usable */ if (out == NULL) { Py_INCREF(indescr); out = (PyArrayObject*)PyArray_NewFromDescr(Py_TYPE(self), indescr, PyArray_NDIM(self), PyArray_DIMS(self), NULL, NULL, PyArray_ISFORTRAN(self), (PyObject *)self); if (out == NULL) { goto fail; } if ((maxa != NULL && PyArray_HASMASKNA(maxa)) || (mina != NULL && PyArray_HASMASKNA(mina))) { if (PyArray_AllocateMaskNA(out, 1, 0, 1) < 0) { goto fail; } } outgood = 1; } else Py_INCREF(out); /* Input is good at this point */ if (out == newin) { outgood = 1; } if (!outgood && PyArray_ISONESEGMENT(out) && PyArray_CHKFLAGS(out, NPY_ARRAY_ALIGNED) && PyArray_ISNOTSWAPPED(out) && PyArray_EquivTypes(PyArray_DESCR(out), indescr)) { outgood = 1; } /* * Do we still not have a suitable output array? * Create one, now */ if (!outgood) { int oflags; if (PyArray_ISFORTRAN(out)) oflags = NPY_ARRAY_FARRAY; else oflags = NPY_ARRAY_CARRAY; oflags |= NPY_ARRAY_UPDATEIFCOPY | NPY_ARRAY_FORCECAST; Py_INCREF(indescr); newout = (PyArrayObject*)PyArray_FromArray(out, indescr, oflags); if (newout == NULL) { goto fail; } } else { newout = out; Py_INCREF(newout); } /* make sure the shape of the output array is the same */ if (!PyArray_SAMESHAPE(newin, newout)) { PyErr_SetString(PyExc_ValueError, "clip: Output array must have the" "same shape as the input."); goto fail; } if (PyArray_DATA(newout) != PyArray_DATA(newin)) { if (PyArray_AssignArray(newout, newin, NULL, NPY_DEFAULT_ASSIGN_CASTING, 0, NULL) < 0) { goto fail; } } /* Now we can call the fast-clip function */ min_data = max_data = NULL; if (mina != NULL) { min_data = PyArray_DATA(mina); } if (maxa != NULL) { max_data = PyArray_DATA(maxa); } func(PyArray_DATA(newin), PyArray_SIZE(newin), min_data, max_data, PyArray_DATA(newout)); /* Clean up temporary variables */ Py_XDECREF(mina); Py_XDECREF(maxa); Py_DECREF(newin); /* Copy back into out if out was not already a nice array. */ Py_DECREF(newout); return (PyObject *)out; fail: Py_XDECREF(maxa); Py_XDECREF(mina); Py_XDECREF(newin); PyArray_XDECREF_ERR(newout); return NULL; }