summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/compiled_base.c224
-rw-r--r--numpy/lib/function_base.py3
-rw-r--r--numpy/lib/tests/test_function_base.py5
3 files changed, 78 insertions, 154 deletions
diff --git a/numpy/core/src/multiarray/compiled_base.c b/numpy/core/src/multiarray/compiled_base.c
index 932b94f15..711a0ab91 100644
--- a/numpy/core/src/multiarray/compiled_base.c
+++ b/numpy/core/src/multiarray/compiled_base.c
@@ -302,193 +302,111 @@ arr_digitize(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
}
/*
- * Insert values from an input array into an output array, at positions
- * indicated by a mask. If the arrays are of dtype object (indicated by
- * the objarray flag), take care of reference counting.
- *
- * This function implements the copying logic of arr_insert() defined
- * below.
- */
-static void
-arr_insert_loop(char *mptr, char *vptr, char *input_data, char *zero,
- char *avals_data, int melsize, int delsize, int objarray,
- int totmask, int numvals, int nd, npy_intp *instrides,
- npy_intp *inshape)
-{
- int mindx, rem_indx, indx, i, copied;
-
- /*
- * Walk through mask array, when non-zero is encountered
- * copy next value in the vals array to the input array.
- * If we get through the value array, repeat it as necessary.
- */
- copied = 0;
- for (mindx = 0; mindx < totmask; mindx++) {
- if (memcmp(mptr,zero,melsize) != 0) {
- /* compute indx into input array */
- rem_indx = mindx;
- indx = 0;
- for (i = nd - 1; i > 0; --i) {
- indx += (rem_indx % inshape[i]) * instrides[i];
- rem_indx /= inshape[i];
- }
- indx += rem_indx * instrides[0];
- /* fprintf(stderr, "mindx = %d, indx=%d\n", mindx, indx); */
- /* Copy value element over to input array */
- memcpy(input_data+indx,vptr,delsize);
- if (objarray) {
- Py_INCREF(*((PyObject **)vptr));
- }
- vptr += delsize;
- copied += 1;
- /* If we move past value data. Reset */
- if (copied >= numvals) {
- vptr = avals_data;
- copied = 0;
- }
- }
- mptr += melsize;
- }
-}
-
-/*
* Returns input array with values inserted sequentially into places
* indicated by the mask
*/
NPY_NO_EXPORT PyObject *
arr_insert(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict)
{
- PyObject *mask = NULL, *vals = NULL;
- PyArrayObject *ainput = NULL, *amask = NULL, *avals = NULL, *tmp = NULL;
- int numvals, totmask, sameshape;
- char *input_data, *mptr, *vptr, *zero = NULL;
- int melsize, delsize, nd, objarray, k;
- npy_intp *instrides, *inshape;
+ char *src, *dest;
+ npy_bool *mask_data;
+ PyArray_Descr *dtype;
+ PyArray_CopySwapFunc *copyswap;
+ PyObject *array0, *mask0, *values0;
+ PyArrayObject *array, *mask, *values;
+ npy_intp i, j, chunk, nm, ni, nv;
static char *kwlist[] = {"input", "mask", "vals", NULL};
+ NPY_BEGIN_THREADS_DEF;
+ values = mask = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O&OO", kwlist,
- PyArray_Converter, &ainput,
- &mask, &vals)) {
- goto fail;
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O!OO:place", kwlist,
+ &PyArray_Type, &array0, &mask0, &values0)) {
+ return NULL;
}
- amask = (PyArrayObject *)PyArray_FROM_OF(mask, NPY_ARRAY_CARRAY);
- if (amask == NULL) {
+ array = (PyArrayObject *)PyArray_FromArray((PyArrayObject *)array0, NULL,
+ NPY_ARRAY_CARRAY | NPY_ARRAY_UPDATEIFCOPY);
+ if (array == NULL) {
goto fail;
}
- /* Cast an object array */
- if (PyArray_DESCR(amask)->type_num == NPY_OBJECT) {
- tmp = (PyArrayObject *)PyArray_Cast(amask, NPY_INTP);
- if (tmp == NULL) {
- goto fail;
- }
- Py_DECREF(amask);
- amask = tmp;
- }
- sameshape = 1;
- if (PyArray_NDIM(amask) == PyArray_NDIM(ainput)) {
- for (k = 0; k < PyArray_NDIM(amask); k++) {
- if (PyArray_DIMS(amask)[k] != PyArray_DIMS(ainput)[k]) {
- sameshape = 0;
- }
- }
- }
- else {
- /* Test to see if amask is 1d */
- if (PyArray_NDIM(amask) != 1) {
- sameshape = 0;
- }
- else if ((PyArray_SIZE(ainput)) != PyArray_SIZE(amask)) {
- sameshape = 0;
- }
- }
- if (!sameshape) {
- PyErr_SetString(PyExc_TypeError,
- "mask array must be 1-d or same shape as input array");
+ ni = PyArray_SIZE(array);
+ dest = PyArray_DATA(array);
+ chunk = PyArray_DESCR(array)->elsize;
+ mask = (PyArrayObject *)PyArray_FROM_OTF(mask0, NPY_BOOL,
+ NPY_ARRAY_CARRAY | NPY_ARRAY_FORCECAST);
+ if (mask == NULL) {
goto fail;
}
- avals = (PyArrayObject *)PyArray_FromObject(vals,
- PyArray_DESCR(ainput)->type_num, 0, 1);
- if (avals == NULL) {
+ nm = PyArray_SIZE(mask);
+ if (nm != ni) {
+ PyErr_SetString(PyExc_ValueError,
+ "place: mask and data must be "
+ "the same size");
goto fail;
}
- numvals = PyArray_SIZE(avals);
- nd = PyArray_NDIM(ainput);
- input_data = PyArray_DATA(ainput);
- mptr = PyArray_DATA(amask);
- melsize = PyArray_DESCR(amask)->elsize;
- vptr = PyArray_DATA(avals);
- delsize = PyArray_DESCR(avals)->elsize;
- zero = PyArray_Zero(amask);
- if (zero == NULL) {
+
+ mask_data = PyArray_DATA(mask);
+ dtype = PyArray_DESCR(array);
+ Py_INCREF(dtype);
+
+ values = (PyArrayObject *)PyArray_FromAny(values0, dtype,
+ 0, 0, NPY_ARRAY_CARRAY, NULL);
+ if (values == NULL) {
goto fail;
}
- objarray = (PyArray_DESCR(ainput)->type_num == NPY_OBJECT);
- if (!numvals) {
- /* nothing to insert! fail unless none of mask is true */
- const char *iter = mptr;
- const char *const last = iter + PyArray_NBYTES(amask);
- while (iter != last && !memcmp(iter, zero, melsize)) {
- iter += melsize;
+ nv = PyArray_SIZE(values); /* zero if null array */
+ if (nv <= 0) {
+ npy_bool allFalse = 1;
+ i = 0;
+
+ while (allFalse && i < ni) {
+ if (mask_data[i]) {
+ allFalse = 0;
+ } else {
+ i++;
+ }
}
- if (iter != last) {
+ if (!allFalse) {
PyErr_SetString(PyExc_ValueError,
- "Cannot insert from an empty array!");
+ "Cannot insert from an empty array!");
goto fail;
+ } else {
+ Py_XDECREF(values);
+ Py_XDECREF(mask);
+ Py_RETURN_NONE;
}
- goto finish;
}
- /* Handle zero-dimensional case separately */
- if (nd == 0) {
- if (memcmp(mptr,zero,melsize) != 0) {
- /* Copy value element over to input array */
- memcpy(input_data,vptr,delsize);
- if (objarray) {
- Py_INCREF(*((PyObject **)vptr));
+ src = PyArray_DATA(values);
+ j = 0;
+
+ copyswap = PyArray_DESCR(array)->f->copyswap;
+ NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(array));
+ for (i = 0; i < ni; i++) {
+ if (mask_data[i]) {
+ if (j >= nv) {
+ j = 0;
}
- }
- Py_DECREF(amask);
- Py_DECREF(avals);
- PyDataMem_FREE(zero);
- Py_DECREF(ainput);
- Py_RETURN_NONE;
- }
- totmask = (int) PyArray_SIZE(amask);
- instrides = PyArray_STRIDES(ainput);
- inshape = PyArray_DIMS(ainput);
- if (objarray) {
- /* object array, need to refcount, can't release the GIL */
- arr_insert_loop(mptr, vptr, input_data, zero, PyArray_DATA(avals),
- melsize, delsize, objarray, totmask, numvals, nd,
- instrides, inshape);
- }
- else {
- /* No increfs take place in arr_insert_loop, so release the GIL */
- NPY_BEGIN_ALLOW_THREADS;
- arr_insert_loop(mptr, vptr, input_data, zero, PyArray_DATA(avals),
- melsize, delsize, objarray, totmask, numvals, nd,
- instrides, inshape);
- NPY_END_ALLOW_THREADS;
+ copyswap(dest + i*chunk, src + j*chunk, 0, array);
+ j++;
+ }
}
+ NPY_END_THREADS;
-finish:
- Py_DECREF(amask);
- Py_DECREF(avals);
- PyDataMem_FREE(zero);
- Py_DECREF(ainput);
+ Py_XDECREF(values);
+ Py_XDECREF(mask);
+ Py_DECREF(array);
Py_RETURN_NONE;
-fail:
- PyDataMem_FREE(zero);
- Py_XDECREF(ainput);
- Py_XDECREF(amask);
- Py_XDECREF(avals);
+ fail:
+ Py_XDECREF(mask);
+ Py_XDECREF(array);
+ Py_XDECREF(values);
return NULL;
}
diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py
index c155babef..648eb5019 100644
--- a/numpy/lib/function_base.py
+++ b/numpy/lib/function_base.py
@@ -2026,7 +2026,8 @@ def place(arr, mask, vals):
vals : 1-D sequence
Values to put into `a`. Only the first N elements are used, where
N is the number of True values in `mask`. If `vals` is smaller
- than N it will be repeated.
+ than N, it will be repeated, and if elements of `a` are to be masked,
+ this sequence must be non-empty.
See Also
--------
diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py
index e04a497c1..945992fc0 100644
--- a/numpy/lib/tests/test_function_base.py
+++ b/numpy/lib/tests/test_function_base.py
@@ -805,6 +805,11 @@ class TestExtins(TestCase):
assert_raises_regex(ValueError, "Cannot insert from an empty array",
lambda: place(a, [0, 0, 0, 0, 0, 1, 0], []))
+ # See Issue #6974
+ a = np.array(['12', '34'])
+ place(a, [0, 1], '9')
+ assert_array_equal(a, ['12', '9'])
+
def test_both(self):
a = rand(10)
mask = a > 0.5