summaryrefslogtreecommitdiff
path: root/numpy/core/src/multiarray/ctors.c
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core/src/multiarray/ctors.c')
-rw-r--r--numpy/core/src/multiarray/ctors.c615
1 files changed, 260 insertions, 355 deletions
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index 05575cad7..3c5b047c3 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -20,6 +20,8 @@
#include "common.h"
#include "ctors.h"
#include "convert_datatype.h"
+#include "descriptor.h"
+#include "dtypemeta.h"
#include "shape.h"
#include "npy_buffer.h"
#include "lowlevel_strided_loops.h"
@@ -626,8 +628,7 @@ NPY_NO_EXPORT PyObject *
PyArray_NewFromDescr_int(
PyTypeObject *subtype, PyArray_Descr *descr, int nd,
npy_intp const *dims, npy_intp const *strides, void *data,
- int flags, PyObject *obj, PyObject *base, int zeroed,
- int allow_emptystring)
+ int flags, PyObject *obj, PyObject *base, _NPY_CREATION_FLAGS cflags)
{
PyArrayObject_fields *fa;
npy_intp nbytes;
@@ -642,44 +643,54 @@ PyArray_NewFromDescr_int(
return NULL;
}
- if (descr->subarray) {
- PyObject *ret;
- npy_intp newdims[2*NPY_MAXDIMS];
- npy_intp *newstrides = NULL;
- memcpy(newdims, dims, nd*sizeof(npy_intp));
- if (strides) {
- newstrides = newdims + NPY_MAXDIMS;
- memcpy(newstrides, strides, nd*sizeof(npy_intp));
- }
- nd =_update_descr_and_dimensions(&descr, newdims,
- newstrides, nd);
- ret = PyArray_NewFromDescr_int(
- subtype, descr,
- nd, newdims, newstrides, data,
- flags, obj, base,
- zeroed, allow_emptystring);
- return ret;
- }
-
- /* Check datatype element size */
nbytes = descr->elsize;
- if (PyDataType_ISUNSIZED(descr)) {
- if (!PyDataType_ISFLEXIBLE(descr)) {
- PyErr_SetString(PyExc_TypeError, "Empty data-type");
- Py_DECREF(descr);
- return NULL;
- }
- else if (PyDataType_ISSTRING(descr) && !allow_emptystring &&
- data == NULL) {
- PyArray_DESCR_REPLACE(descr);
- if (descr == NULL) {
+ /*
+ * Unless explicitly asked not to, we do replace dtypes in some cases.
+ * This mainly means that we never create arrays with a subarray dtype
+ * (unless for internal use when requested). And neither do we create
+ * S0/U0 arrays in most cases (unless data == NULL so this is probably
+ * a view where growing the dtype would be presumable wrong).
+ */
+ if (!(cflags & _NPY_ARRAY_ENSURE_DTYPE_IDENTITY)) {
+ if (descr->subarray) {
+ PyObject *ret;
+ npy_intp newdims[2*NPY_MAXDIMS];
+ npy_intp *newstrides = NULL;
+ memcpy(newdims, dims, nd*sizeof(npy_intp));
+ if (strides) {
+ newstrides = newdims + NPY_MAXDIMS;
+ memcpy(newstrides, strides, nd*sizeof(npy_intp));
+ }
+ nd =_update_descr_and_dimensions(&descr, newdims,
+ newstrides, nd);
+ ret = PyArray_NewFromDescr_int(
+ subtype, descr,
+ nd, newdims, newstrides, data,
+ flags, obj, base, cflags);
+ return ret;
+ }
+
+ /* Check datatype element size */
+ if (PyDataType_ISUNSIZED(descr)) {
+ if (!PyDataType_ISFLEXIBLE(descr) &&
+ NPY_DT_is_legacy(NPY_DTYPE(descr))) {
+ PyErr_SetString(PyExc_TypeError, "Empty data-type");
+ Py_DECREF(descr);
return NULL;
}
- if (descr->type_num == NPY_STRING) {
- nbytes = descr->elsize = 1;
- }
- else {
- nbytes = descr->elsize = sizeof(npy_ucs4);
+ else if (PyDataType_ISSTRING(descr)
+ && !(cflags & _NPY_ARRAY_ALLOW_EMPTY_STRING)
+ && data == NULL) {
+ PyArray_DESCR_REPLACE(descr);
+ if (descr == NULL) {
+ return NULL;
+ }
+ if (descr->type_num == NPY_STRING) {
+ nbytes = descr->elsize = 1;
+ }
+ else {
+ nbytes = descr->elsize = sizeof(npy_ucs4);
+ }
}
}
}
@@ -712,6 +723,11 @@ PyArray_NewFromDescr_int(
fa->base = (PyObject *)NULL;
fa->weakreflist = (PyObject *)NULL;
+ /* needed for zero-filling logic below, defined and initialized up here
+ so cleanup logic can go in the fail block */
+ NPY_traverse_info fill_zero_info;
+ NPY_traverse_info_init(&fill_zero_info);
+
if (nd > 0) {
fa->dimensions = npy_alloc_cache_dim(2 * nd);
if (fa->dimensions == NULL) {
@@ -781,6 +797,32 @@ PyArray_NewFromDescr_int(
if (data == NULL) {
+ /* float errors do not matter and we do not release GIL */
+ NPY_ARRAYMETHOD_FLAGS zero_flags;
+ get_traverse_loop_function *get_fill_zero_loop =
+ NPY_DT_SLOTS(NPY_DTYPE(descr))->get_fill_zero_loop;
+ if (get_fill_zero_loop != NULL) {
+ if (get_fill_zero_loop(
+ NULL, descr, 1, descr->elsize, &(fill_zero_info.func),
+ &(fill_zero_info.auxdata), &zero_flags) < 0) {
+ goto fail;
+ }
+ }
+
+ /*
+ * We always want a zero-filled array allocated with calloc if
+ * NPY_NEEDS_INIT is set on the dtype, for safety. We also want a
+ * zero-filled array if zeroed is set and the zero-filling loop isn't
+ * defined, for better performance.
+ *
+ * If the zero-filling loop is defined and zeroed is set, allocate
+ * with malloc and let the zero-filling loop fill the array buffer
+ * with valid zero values for the dtype.
+ */
+ int use_calloc = (
+ PyDataType_FLAGCHK(descr, NPY_NEEDS_INIT) ||
+ ((cflags & _NPY_ARRAY_ZEROED) && (fill_zero_info.func == NULL)));
+
/* Store the handler in case the default is modified */
fa->mem_handler = PyDataMem_GetHandler();
if (fa->mem_handler == NULL) {
@@ -798,11 +840,8 @@ PyArray_NewFromDescr_int(
fa->strides[i] = 0;
}
}
- /*
- * It is bad to have uninitialized OBJECT pointers
- * which could also be sub-fields of a VOID array
- */
- if (zeroed || PyDataType_FLAGCHK(descr, NPY_NEEDS_INIT)) {
+
+ if (use_calloc) {
data = PyDataMem_UserNEW_ZEROED(nbytes, 1, fa->mem_handler);
}
else {
@@ -813,6 +852,19 @@ PyArray_NewFromDescr_int(
goto fail;
}
+ /*
+ * If the array needs special dtype-specific zero-filling logic, do that
+ */
+ if (NPY_UNLIKELY((cflags & _NPY_ARRAY_ZEROED)
+ && (fill_zero_info.func != NULL))) {
+ npy_intp size = PyArray_MultiplyList(fa->dimensions, fa->nd);
+ if (fill_zero_info.func(
+ NULL, descr, data, size, descr->elsize,
+ fill_zero_info.auxdata) < 0) {
+ goto fail;
+ }
+ }
+
fa->flags |= NPY_ARRAY_OWNDATA;
}
else {
@@ -907,9 +959,11 @@ PyArray_NewFromDescr_int(
}
}
}
+ NPY_traverse_info_xfree(&fill_zero_info);
return (PyObject *)fa;
fail:
+ NPY_traverse_info_xfree(&fill_zero_info);
Py_XDECREF(fa->mem_handler);
Py_DECREF(fa);
return NULL;
@@ -957,7 +1011,7 @@ PyArray_NewFromDescrAndBase(
{
return PyArray_NewFromDescr_int(subtype, descr, nd,
dims, strides, data,
- flags, obj, base, 0, 0);
+ flags, obj, base, 0);
}
/*
@@ -1440,167 +1494,44 @@ PyArray_GetArrayParamsFromObject(PyObject *NPY_UNUSED(op),
}
-/*
- * This function is a legacy implementation to retain subarray dtype
- * behaviour in array coercion. The behaviour here makes sense if tuples
- * of matching dimensionality are being coerced. Due to the difficulty
- * that the result is ill-defined for lists of array-likes, this is deprecated.
- *
- * WARNING: Do not use this function, it exists purely to support a deprecated
- * code path.
+/*NUMPY_API
+ * Does not check for NPY_ARRAY_ENSURECOPY and NPY_ARRAY_NOTSWAPPED in flags
+ * Steals a reference to newtype --- which can be NULL
*/
-static int
-setArrayFromSequence(PyArrayObject *a, PyObject *s,
- int dim, PyArrayObject * dst)
+NPY_NO_EXPORT PyObject *
+PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
+ int max_depth, int flags, PyObject *context)
{
- Py_ssize_t i, slen;
- int res = -1;
-
- /* first recursion, view equal destination */
- if (dst == NULL)
- dst = a;
-
- /*
- * This code is to ensure that the sequence access below will
- * return a lower-dimensional sequence.
- */
-
- /* INCREF on entry DECREF on exit */
- Py_INCREF(s);
-
- PyObject *seq = NULL;
+ npy_dtype_info dt_info = {NULL, NULL};
- if (PyArray_Check(s)) {
- if (!(PyArray_CheckExact(s))) {
- /*
- * make sure a base-class array is used so that the dimensionality
- * reduction assumption is correct.
- */
- /* This will DECREF(s) if replaced */
- s = PyArray_EnsureArray(s);
- if (s == NULL) {
- goto fail;
- }
- }
-
- /* dst points to correct array subsection */
- if (PyArray_CopyInto(dst, (PyArrayObject *)s) < 0) {
- goto fail;
- }
-
- Py_DECREF(s);
- return 0;
- }
-
- if (dim > PyArray_NDIM(a)) {
- PyErr_Format(PyExc_ValueError,
- "setArrayFromSequence: sequence/array dimensions mismatch.");
- goto fail;
- }
+ int res = PyArray_ExtractDTypeAndDescriptor(
+ newtype, &dt_info.descr, &dt_info.dtype);
- /* Try __array__ before using s as a sequence */
- PyObject *tmp = _array_from_array_like(s, NULL, 0, NULL, 0);
- if (tmp == NULL) {
- goto fail;
- }
- else if (tmp == Py_NotImplemented) {
- Py_DECREF(tmp);
- }
- else {
- int r = PyArray_CopyInto(dst, (PyArrayObject *)tmp);
- Py_DECREF(tmp);
- if (r < 0) {
- goto fail;
- }
- Py_DECREF(s);
- return 0;
- }
-
- seq = PySequence_Fast(s, "Could not convert object to sequence");
- if (seq == NULL) {
- goto fail;
- }
- slen = PySequence_Fast_GET_SIZE(seq);
-
- /*
- * Either the dimensions match, or the sequence has length 1 and can
- * be broadcast to the destination.
- */
- if (slen != PyArray_DIMS(a)[dim] && slen != 1) {
- PyErr_Format(PyExc_ValueError,
- "cannot copy sequence with size %zd to array axis "
- "with dimension %" NPY_INTP_FMT, slen, PyArray_DIMS(a)[dim]);
- goto fail;
- }
-
- /* Broadcast the one element from the sequence to all the outputs */
- if (slen == 1) {
- PyObject *o = PySequence_Fast_GET_ITEM(seq, 0);
- npy_intp alen = PyArray_DIM(a, dim);
-
- for (i = 0; i < alen; i++) {
- if ((PyArray_NDIM(a) - dim) > 1) {
- PyArrayObject * tmp =
- (PyArrayObject *)array_item_asarray(dst, i);
- if (tmp == NULL) {
- goto fail;
- }
-
- res = setArrayFromSequence(a, o, dim+1, tmp);
- Py_DECREF(tmp);
- }
- else {
- char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]);
- res = PyArray_SETITEM(dst, b, o);
- }
- if (res < 0) {
- goto fail;
- }
- }
- }
- /* Copy element by element */
- else {
- for (i = 0; i < slen; i++) {
- PyObject * o = PySequence_Fast_GET_ITEM(seq, i);
- if ((PyArray_NDIM(a) - dim) > 1) {
- PyArrayObject * tmp =
- (PyArrayObject *)array_item_asarray(dst, i);
- if (tmp == NULL) {
- goto fail;
- }
+ Py_XDECREF(newtype);
- res = setArrayFromSequence(a, o, dim+1, tmp);
- Py_DECREF(tmp);
- }
- else {
- char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]);
- res = PyArray_SETITEM(dst, b, o);
- }
- if (res < 0) {
- goto fail;
- }
- }
+ if (res < 0) {
+ Py_XDECREF(dt_info.descr);
+ Py_XDECREF(dt_info.dtype);
+ return NULL;
}
- Py_DECREF(seq);
- Py_DECREF(s);
- return 0;
+ PyObject* ret = PyArray_FromAny_int(op, dt_info.descr, dt_info.dtype,
+ min_depth, max_depth, flags, context);
- fail:
- Py_XDECREF(seq);
- Py_DECREF(s);
- return res;
+ Py_XDECREF(dt_info.descr);
+ Py_XDECREF(dt_info.dtype);
+ return ret;
}
-
-
-/*NUMPY_API
- * Does not check for NPY_ARRAY_ENSURECOPY and NPY_ARRAY_NOTSWAPPED in flags
- * Steals a reference to newtype --- which can be NULL
+/*
+ * Internal version of PyArray_FromAny that accepts a dtypemeta. Borrows
+ * references to the descriptor and dtype.
*/
+
NPY_NO_EXPORT PyObject *
-PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
- int max_depth, int flags, PyObject *context)
+PyArray_FromAny_int(PyObject *op, PyArray_Descr *in_descr,
+ PyArray_DTypeMeta *in_DType, int min_depth, int max_depth,
+ int flags, PyObject *context)
{
/*
* This is the main code to make a NumPy array from a Python
@@ -1617,89 +1548,14 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
return NULL;
}
- PyArray_Descr *fixed_descriptor;
- PyArray_DTypeMeta *fixed_DType;
- if (PyArray_ExtractDTypeAndDescriptor((PyObject *)newtype,
- &fixed_descriptor, &fixed_DType) < 0) {
- Py_XDECREF(newtype);
- return NULL;
- }
- Py_XDECREF(newtype);
-
ndim = PyArray_DiscoverDTypeAndShape(op,
- NPY_MAXDIMS, dims, &cache, fixed_DType, fixed_descriptor, &dtype,
+ NPY_MAXDIMS, dims, &cache, in_DType, in_descr, &dtype,
flags & NPY_ARRAY_ENSURENOCOPY);
- Py_XDECREF(fixed_descriptor);
- Py_XDECREF(fixed_DType);
if (ndim < 0) {
return NULL;
}
- if (NPY_UNLIKELY(fixed_descriptor != NULL && PyDataType_HASSUBARRAY(dtype))) {
- /*
- * When a subarray dtype was passed in, its dimensions are appended
- * to the array dimension (causing a dimension mismatch).
- * There is a problem with that, because if we coerce from non-arrays
- * we do this correctly by element (as defined by tuples), but for
- * arrays we first append the dimensions and then assign to the base
- * dtype and then assign which causes the problem.
- *
- * Thus, we check if there is an array included, in that case we
- * give a FutureWarning.
- * When the warning is removed, PyArray_Pack will have to ensure
- * that it does not append the dimensions when creating the subarrays
- * to assign `arr[0] = obj[0]`.
- */
- int includes_array = 0;
- if (cache != NULL) {
- /* This is not ideal, but it is a pretty special case */
- coercion_cache_obj *next = cache;
- while (next != NULL) {
- if (!next->sequence) {
- includes_array = 1;
- break;
- }
- next = next->next;
- }
- }
- if (includes_array) {
- npy_free_coercion_cache(cache);
-
- ret = (PyArrayObject *) PyArray_NewFromDescr(
- &PyArray_Type, dtype, ndim, dims, NULL, NULL,
- flags & NPY_ARRAY_F_CONTIGUOUS, NULL);
- if (ret == NULL) {
- return NULL;
- }
- assert(PyArray_NDIM(ret) != ndim);
-
- /* NumPy 1.20, 2020-10-01 */
- if (DEPRECATE_FUTUREWARNING(
- "creating an array with a subarray dtype will behave "
- "differently when the `np.array()` (or `asarray`, etc.) "
- "call includes an array or array object.\n"
- "If you are converting a single array or a list of arrays,"
- "you can opt-in to the future behaviour using:\n"
- " np.array(arr, dtype=np.dtype(['f', dtype]))['f']\n"
- " np.array([arr1, arr2], dtype=np.dtype(['f', dtype]))['f']\n"
- "\n"
- "By including a new field and indexing it after the "
- "conversion.\n"
- "This may lead to a different result or to current failures "
- "succeeding. (FutureWarning since NumPy 1.20)") < 0) {
- Py_DECREF(ret);
- return NULL;
- }
-
- if (setArrayFromSequence(ret, op, 0, NULL) < 0) {
- Py_DECREF(ret);
- return NULL;
- }
- return (PyObject *)ret;
- }
- }
-
if (dtype == NULL) {
dtype = PyArray_DescrFromType(NPY_DEFAULT_TYPE);
}
@@ -1734,7 +1590,7 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
}
else if (cache == NULL && PyArray_IsScalar(op, Void) &&
!(((PyVoidScalarObject *)op)->flags & NPY_ARRAY_OWNDATA) &&
- newtype == NULL) {
+ ((in_descr == NULL) && (in_DType == NULL))) {
/*
* Special case, we return a *view* into void scalars, mainly to
* allow things similar to the "reversed" assignment:
@@ -1765,8 +1621,9 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
return NULL;
}
- if (cache == NULL && newtype != NULL &&
- PyDataType_ISSIGNED(newtype) && PyArray_IsScalar(op, Generic)) {
+ if (cache == NULL && in_descr != NULL &&
+ PyDataType_ISSIGNED(dtype) &&
+ PyArray_IsScalar(op, Generic)) {
assert(ndim == 0);
/*
* This is an (possible) inconsistency where:
@@ -1895,7 +1752,6 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth,
* NPY_ARRAY_FORCECAST will cause a cast to occur regardless of whether or not
* it is safe.
*
- * context is passed through to PyArray_GetArrayParamsFromObject
*/
/*NUMPY_API
@@ -1905,24 +1761,57 @@ NPY_NO_EXPORT PyObject *
PyArray_CheckFromAny(PyObject *op, PyArray_Descr *descr, int min_depth,
int max_depth, int requires, PyObject *context)
{
+ npy_dtype_info dt_info = {NULL, NULL};
+
+ int res = PyArray_ExtractDTypeAndDescriptor(
+ descr, &dt_info.descr, &dt_info.dtype);
+
+ Py_XDECREF(descr);
+
+ if (res < 0) {
+ Py_XDECREF(dt_info.descr);
+ Py_XDECREF(dt_info.dtype);
+ return NULL;
+ }
+
+ PyObject* ret = PyArray_CheckFromAny_int(
+ op, dt_info.descr, dt_info.dtype, min_depth, max_depth, requires,
+ context);
+
+ Py_XDECREF(dt_info.descr);
+ Py_XDECREF(dt_info.dtype);
+ return ret;
+}
+
+/*
+ * Internal version of PyArray_CheckFromAny that accepts a dtypemeta. Borrows
+ * references to the descriptor and dtype.
+ */
+
+NPY_NO_EXPORT PyObject *
+PyArray_CheckFromAny_int(PyObject *op, PyArray_Descr *in_descr,
+ PyArray_DTypeMeta *in_DType, int min_depth,
+ int max_depth, int requires, PyObject *context)
+{
PyObject *obj;
if (requires & NPY_ARRAY_NOTSWAPPED) {
- if (!descr && PyArray_Check(op) &&
+ if (!in_descr && PyArray_Check(op) &&
PyArray_ISBYTESWAPPED((PyArrayObject* )op)) {
- descr = PyArray_DescrNew(PyArray_DESCR((PyArrayObject *)op));
- if (descr == NULL) {
+ in_descr = PyArray_DescrNew(PyArray_DESCR((PyArrayObject *)op));
+ if (in_descr == NULL) {
return NULL;
}
}
- else if (descr && !PyArray_ISNBO(descr->byteorder)) {
- PyArray_DESCR_REPLACE(descr);
+ else if (in_descr && !PyArray_ISNBO(in_descr->byteorder)) {
+ PyArray_DESCR_REPLACE(in_descr);
}
- if (descr && descr->byteorder != NPY_IGNORE) {
- descr->byteorder = NPY_NATIVE;
+ if (in_descr && in_descr->byteorder != NPY_IGNORE) {
+ in_descr->byteorder = NPY_NATIVE;
}
}
- obj = PyArray_FromAny(op, descr, min_depth, max_depth, requires, context);
+ obj = PyArray_FromAny_int(op, in_descr, in_DType, min_depth,
+ max_depth, requires, context);
if (obj == NULL) {
return NULL;
}
@@ -2030,13 +1919,26 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags)
if ((flags & NPY_ARRAY_ENSUREARRAY)) {
subok = 0;
}
+ Py_INCREF(newtype);
ret = (PyArrayObject *)PyArray_NewLikeArray(arr, order,
newtype, subok);
if (ret == NULL) {
+ Py_DECREF(newtype);
return NULL;
}
- if (PyArray_CopyInto(ret, arr) < 0) {
+ int actual_ndim = PyArray_NDIM(ret);
+ PyArray_Descr *actual_dtype = PyArray_DESCR(ret);
+ ((PyArrayObject_fields *)ret)->nd = PyArray_NDIM(arr);
+ ((PyArrayObject_fields *)ret)->descr = newtype;
+
+ int success = PyArray_CopyInto(ret, arr);
+
+ Py_DECREF(newtype);
+ ((PyArrayObject_fields *)ret)->nd = actual_ndim;
+ ((PyArrayObject_fields *)ret)->descr = actual_dtype;
+
+ if (success < 0) {
Py_DECREF(ret);
return NULL;
}
@@ -2831,7 +2733,7 @@ PyArray_CopyAsFlat(PyArrayObject *dst, PyArrayObject *src, NPY_ORDER order)
}
if (res == 0 && !(flags & NPY_METH_NO_FLOATINGPOINT_ERRORS)) {
- int fpes = npy_get_floatstatus_barrier((char *)src_iter);
+ int fpes = npy_get_floatstatus_barrier((char *)&src_iter);
if (fpes && PyUFunc_GiveFloatingpointErrors("cast", fpes) < 0) {
return -1;
}
@@ -2955,23 +2857,13 @@ PyArray_Zeros(int nd, npy_intp const *dims, PyArray_Descr *type, int is_f_order)
&PyArray_Type, type,
nd, dims, NULL, NULL,
is_f_order, NULL, NULL,
- 1, 0);
+ _NPY_ARRAY_ZEROED);
if (ret == NULL) {
return NULL;
}
- /* handle objects */
- if (PyDataType_REFCHK(PyArray_DESCR(ret))) {
- if (_zerofill(ret) < 0) {
- Py_DECREF(ret);
- return NULL;
- }
- }
-
-
return (PyObject *)ret;
-
}
/*NUMPY_API
@@ -3242,11 +3134,11 @@ _calc_length(PyObject *start, PyObject *stop, PyObject *step, PyObject **next, i
NPY_NO_EXPORT PyObject *
PyArray_ArangeObj(PyObject *start, PyObject *stop, PyObject *step, PyArray_Descr *dtype)
{
- PyArrayObject *range;
+ PyArrayObject *range = NULL;
PyArray_ArrFuncs *funcs;
- PyObject *next, *err;
- npy_intp length;
+ PyObject *next = NULL;
PyArray_Descr *native = NULL;
+ npy_intp length;
int swap;
NPY_BEGIN_THREADS_DEF;
@@ -3259,94 +3151,100 @@ PyArray_ArangeObj(PyObject *start, PyObject *stop, PyObject *step, PyArray_Descr
return (PyObject *)datetime_arange(start, stop, step, dtype);
}
- if (!dtype) {
- PyArray_Descr *deftype;
- PyArray_Descr *newtype;
+ /* We need to replace many of these, so hold on for easier cleanup */
+ Py_XINCREF(start);
+ Py_XINCREF(stop);
+ Py_XINCREF(step);
+ Py_XINCREF(dtype);
+ if (!dtype) {
/* intentionally made to be at least NPY_LONG */
- deftype = PyArray_DescrFromType(NPY_LONG);
- newtype = PyArray_DescrFromObject(start, deftype);
- Py_DECREF(deftype);
- if (newtype == NULL) {
- return NULL;
+ dtype = PyArray_DescrFromType(NPY_LONG);
+ Py_SETREF(dtype, PyArray_DescrFromObject(start, dtype));
+ if (dtype == NULL) {
+ goto fail;
}
- deftype = newtype;
if (stop && stop != Py_None) {
- newtype = PyArray_DescrFromObject(stop, deftype);
- Py_DECREF(deftype);
- if (newtype == NULL) {
- return NULL;
+ Py_SETREF(dtype, PyArray_DescrFromObject(stop, dtype));
+ if (dtype == NULL) {
+ goto fail;
}
- deftype = newtype;
}
if (step && step != Py_None) {
- newtype = PyArray_DescrFromObject(step, deftype);
- Py_DECREF(deftype);
- if (newtype == NULL) {
- return NULL;
+ Py_SETREF(dtype, PyArray_DescrFromObject(step, dtype));
+ if (dtype == NULL) {
+ goto fail;
}
- deftype = newtype;
}
- dtype = deftype;
+ }
+
+ /*
+ * If dtype is not in native byte-order then get native-byte
+ * order version. And then swap on the way out.
+ */
+ if (!PyArray_ISNBO(dtype->byteorder)) {
+ native = PyArray_DescrNewByteorder(dtype, NPY_NATBYTE);
+ if (native == NULL) {
+ goto fail;
+ }
+ swap = 1;
}
else {
Py_INCREF(dtype);
+ native = dtype;
+ swap = 0;
}
- if (!step || step == Py_None) {
- step = PyLong_FromLong(1);
+
+ funcs = native->f;
+ if (!funcs->fill) {
+ /* This effectively forbids subarray types as well... */
+ PyErr_Format(PyExc_TypeError,
+ "arange() not supported for inputs with DType %S.",
+ Py_TYPE(dtype));
+ goto fail;
}
- else {
- Py_XINCREF(step);
+
+ if (!step || step == Py_None) {
+ Py_XSETREF(step, PyLong_FromLong(1));
+ if (step == NULL) {
+ goto fail;
+ }
}
if (!stop || stop == Py_None) {
- stop = start;
+ Py_XSETREF(stop, start);
start = PyLong_FromLong(0);
+ if (start == NULL) {
+ goto fail;
+ }
}
- else {
- Py_INCREF(start);
- }
+
/* calculate the length and next = start + step*/
length = _calc_length(start, stop, step, &next,
PyTypeNum_ISCOMPLEX(dtype->type_num));
- err = PyErr_Occurred();
+ PyObject *err = PyErr_Occurred();
if (err) {
- Py_DECREF(dtype);
- if (err && PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) {
+ if (PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) {
PyErr_SetString(PyExc_ValueError, "Maximum allowed size exceeded");
}
goto fail;
}
if (length <= 0) {
length = 0;
- range = (PyArrayObject *)PyArray_SimpleNewFromDescr(1, &length, dtype);
- Py_DECREF(step);
- Py_DECREF(start);
- return (PyObject *)range;
- }
-
- /*
- * If dtype is not in native byte-order then get native-byte
- * order version. And then swap on the way out.
- */
- if (!PyArray_ISNBO(dtype->byteorder)) {
- native = PyArray_DescrNewByteorder(dtype, NPY_NATBYTE);
- swap = 1;
- }
- else {
- native = dtype;
- swap = 0;
}
+ Py_INCREF(native);
range = (PyArrayObject *)PyArray_SimpleNewFromDescr(1, &length, native);
if (range == NULL) {
goto fail;
}
+ if (length == 0) {
+ goto finish;
+ }
/*
* place start in the buffer and the next value in the second position
* if length > 2, then call the inner loop, otherwise stop
*/
- funcs = PyArray_DESCR(range)->f;
if (funcs->setitem(start, PyArray_DATA(range), range) < 0) {
goto fail;
}
@@ -3360,11 +3258,7 @@ PyArray_ArangeObj(PyObject *start, PyObject *stop, PyObject *step, PyArray_Descr
if (length == 2) {
goto finish;
}
- if (!funcs->fill) {
- PyErr_SetString(PyExc_ValueError, "no fill-function for data-type.");
- Py_DECREF(range);
- goto fail;
- }
+
NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(range));
funcs->fill(PyArray_DATA(range), length, range);
NPY_END_THREADS;
@@ -3376,20 +3270,31 @@ PyArray_ArangeObj(PyObject *start, PyObject *stop, PyObject *step, PyArray_Descr
if (swap) {
PyObject *new;
new = PyArray_Byteswap(range, 1);
+ if (new == NULL) {
+ goto fail;
+ }
Py_DECREF(new);
+ /* Replace dtype after swapping in-place above: */
Py_DECREF(PyArray_DESCR(range));
- /* steals the reference */
+ Py_INCREF(dtype);
((PyArrayObject_fields *)range)->descr = dtype;
}
+ Py_DECREF(dtype);
+ Py_DECREF(native);
Py_DECREF(start);
+ Py_DECREF(stop);
Py_DECREF(step);
- Py_DECREF(next);
+ Py_XDECREF(next);
return (PyObject *)range;
fail:
- Py_DECREF(start);
- Py_DECREF(step);
+ Py_XDECREF(dtype);
+ Py_XDECREF(native);
+ Py_XDECREF(start);
+ Py_XDECREF(stop);
+ Py_XDECREF(step);
Py_XDECREF(next);
+ Py_XDECREF(range);
return NULL;
}
@@ -3606,7 +3511,7 @@ PyArray_FromFile(FILE *fp, PyArray_Descr *dtype, npy_intp num, char *sep)
&PyArray_Type, dtype,
1, &num, NULL, NULL,
0, NULL, NULL,
- 0, 1);
+ _NPY_ARRAY_ALLOW_EMPTY_STRING);
}
if ((sep == NULL) || (strlen(sep) == 0)) {
ret = array_fromfile_binary(fp, dtype, num, &nread);