summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorMark Wiebe <mwwiebe@gmail.com>2011-01-07 11:48:33 -0800
committerMark Wiebe <mwwiebe@gmail.com>2011-01-09 01:55:03 -0800
commite8101f5d55541fcd25c5fe0d3dd5f37a5c66a3fc (patch)
treed65e5117e686dba2d1dcb6d17e56daf5bfe57007 /numpy
parent3550d410594cc86ae1a3d730bf689b484e0627de (diff)
downloadnumpy-e8101f5d55541fcd25c5fe0d3dd5f37a5c66a3fc.tar.gz
ENH: iter: Add NPY_ITER_DELAY_BUFALLOC flag, fix Python iterator wrapper issues
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/new_iterator.c.src265
-rw-r--r--numpy/core/src/multiarray/new_iterator.h9
-rw-r--r--numpy/core/src/multiarray/new_iterator_pywrap.c280
-rw-r--r--numpy/core/tests/test_new_iterator.py38
4 files changed, 398 insertions, 194 deletions
diff --git a/numpy/core/src/multiarray/new_iterator.c.src b/numpy/core/src/multiarray/new_iterator.c.src
index 78d45d2c1..8b9cafb26 100644
--- a/numpy/core/src/multiarray/new_iterator.c.src
+++ b/numpy/core/src/multiarray/new_iterator.c.src
@@ -37,6 +37,8 @@
#define NPY_ITFLAG_GROWINNER 0x100
/* There is just one iteration, can specialize iternext for that */
#define NPY_ITFLAG_ONEITERATION 0x200
+/* Delay buffer allocation until first Reset* call */
+#define NPY_ITFLAG_DELAYBUF 0x400
/* Internal iterator per-operand iterator flags */
@@ -46,10 +48,8 @@
#define NPY_OP_ITFLAG_READ 0x02
/* The operand may have a temporary copy made */
#define NPY_OP_ITFLAG_COPY 0x04
-/* The operand needs casting */
+/* The operand needs type conversion/byte swapping/alignment */
#define NPY_OP_ITFLAG_CAST 0x08
-/* The operand needs a byte swap and/or alignment operation */
-#define NPY_OP_ITFLAG_COPYSWAP 0x10
/* The operand never needs buffering */
#define NPY_OP_ITFLAG_BUFNEVER 0x20
/* The operand is aligned */
@@ -193,7 +193,7 @@ struct NpyIter_AD {
((niter) + ((itflags&NPY_ITFLAG_HASINDEX) ? 1 : 0))
/* Size of one AXISDATA struct within the iterator */
-#define NIT_SIZEOF_AXISDATA(itflags, ndim, niter) (( \
+#define NIT_AXISDATA_SIZEOF(itflags, ndim, niter) (( \
/* intp shape */ \
1 + \
/* intp coord */ \
@@ -205,7 +205,7 @@ struct NpyIter_AD {
/*
* Macro to advance an AXISDATA pointer by a specified count.
* Requires that sizeof_axisdata be previously initialized
- * to NIT_SIZEOF_AXISDATA(itflags, ndim, niter).
+ * to NIT_AXISDATA_SIZEOF(itflags, ndim, niter).
*/
#define NIT_ADVANCE_AXISDATA(axisdata, count) \
(*((char **)(&axisdata))) += (count)*sizeof_axisdata
@@ -216,7 +216,7 @@ struct NpyIter_AD {
#define NIT_SIZEOF_ITERATOR(itflags, ndim, niter) ( \
sizeof(struct NpyIter_InternalOnly) + \
NIT_AXISDATA_OFFSET(itflags, ndim, niter) + \
- NIT_SIZEOF_AXISDATA(itflags, ndim, niter)*(ndim))
+ NIT_AXISDATA_SIZEOF(itflags, ndim, niter)*(ndim))
/* Internal helper functions */
static int
@@ -389,6 +389,7 @@ NpyIter_MultiNew(npy_intp niter, PyArrayObject **op_in, npy_uint32 flags,
*/
if (itflags&NPY_ITFLAG_BUFFER) {
bufferdata = NIT_BUFFERDATA(iter);
+ NBF_SIZE(bufferdata) = 0;
memset(NBF_BUFFERS(bufferdata), 0, niter*NPY_SIZEOF_INTP);
memset(NBF_READTRANSFERDATA(bufferdata), 0, niter*NPY_SIZEOF_INTP);
memset(NBF_WRITETRANSFERDATA(bufferdata), 0, niter*NPY_SIZEOF_INTP);
@@ -563,15 +564,22 @@ NpyIter_MultiNew(npy_intp niter, PyArrayObject **op_in, npy_uint32 flags,
}
}
+ /* If buffering is set without delayed allocation */
if (itflags&NPY_ITFLAG_BUFFER) {
- /* Allocate the buffers */
- if (!npyiter_allocate_buffers(iter)) {
- NpyIter_Deallocate(iter);
- return NULL;
+ if (itflags&NPY_ITFLAG_DELAYBUF) {
+ /* Make the data pointers NULL */
+ memset(NBF_PTRS(bufferdata), 0, niter*NPY_SIZEOF_INTP);
}
+ else {
+ /* Allocate the buffers */
+ if (!npyiter_allocate_buffers(iter)) {
+ NpyIter_Deallocate(iter);
+ return NULL;
+ }
- /* Prepare the next buffers and set iterend/size */
- npyiter_copy_to_buffers(iter);
+ /* Prepare the next buffers and set iterend/size */
+ npyiter_copy_to_buffers(iter);
+ }
}
return iter;
@@ -756,7 +764,9 @@ int NpyIter_RemoveCoords(NpyIter *iter)
npy_uint32 itflags;
/* Make sure the iterator is reset */
- NpyIter_Reset(iter);
+ if (NpyIter_Reset(iter) != NPY_SUCCEED) {
+ return NPY_FAIL;
+ }
itflags = NIT_ITFLAGS(iter);
if (itflags&NPY_ITFLAG_HASCOORDS) {
@@ -781,6 +791,13 @@ int NpyIter_RemoveInnerLoop(NpyIter *iter)
"if coords or an index is being tracked");
return NPY_FAIL;
}
+ if ((itflags&(NPY_ITFLAG_BUFFER|NPY_ITFLAG_RANGE|NPY_ITFLAG_NOINNER))
+ == (NPY_ITFLAG_RANGE|NPY_ITFLAG_NOINNER)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Iterator flag NO_INNER_ITERATION cannot be used "
+ "with ranged iteration unless buffering is also enabled");
+ return NPY_FAIL;
+ }
/* Set the flag */
if (!(itflags&NPY_ITFLAG_NOINNER)) {
itflags |= NPY_ITFLAG_NOINNER;
@@ -799,13 +816,11 @@ int NpyIter_RemoveInnerLoop(NpyIter *iter)
}
/* Reset the iterator */
- NpyIter_Reset(iter);
-
- return NPY_SUCCEED;
+ return NpyIter_Reset(iter);
}
/* Resets the iterator to its initial state */
-void NpyIter_Reset(NpyIter *iter)
+int NpyIter_Reset(NpyIter *iter)
{
npy_uint32 itflags = NIT_ITFLAGS(iter);
npy_intp ndim = NIT_NDIM(iter);
@@ -814,18 +829,28 @@ void NpyIter_Reset(NpyIter *iter)
if (itflags&NPY_ITFLAG_BUFFER) {
NpyIter_BufferData *bufferdata;
- /*
- * If the iterindex is already right, no need to
- * do anything
- */
- bufferdata = NIT_BUFFERDATA(iter);
- if (NIT_ITERINDEX(iter) == NIT_ITERSTART(iter) &&
- NBF_BUFITEREND(bufferdata) <= NIT_ITEREND(iter) &&
- NBF_SIZE(bufferdata) > 0) {
- return;
+ /* If buffer allocation was delayed, do it now */
+ if (itflags&NPY_ITFLAG_DELAYBUF) {
+ if (!npyiter_allocate_buffers(iter)) {
+ return NPY_FAIL;
+ }
+ NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_DELAYBUF;
+ }
+ else {
+ /*
+ * If the iterindex is already right, no need to
+ * do anything
+ */
+ bufferdata = NIT_BUFFERDATA(iter);
+ if (NIT_ITERINDEX(iter) == NIT_ITERSTART(iter) &&
+ NBF_BUFITEREND(bufferdata) <= NIT_ITEREND(iter) &&
+ NBF_SIZE(bufferdata) > 0) {
+ return NPY_SUCCEED;
+ }
+
+ /* Copy any data from the buffers back to the arrays */
+ npyiter_copy_from_buffers(iter);
}
- /* Copy any data from the buffers back to the arrays */
- npyiter_copy_from_buffers(iter);
}
npyiter_goto_iterindex(iter, NIT_ITERSTART(iter));
@@ -834,10 +859,12 @@ void NpyIter_Reset(NpyIter *iter)
/* Prepare the next buffers and set iterend/size */
npyiter_copy_to_buffers(iter);
}
+
+ return NPY_SUCCEED;
}
/* Resets the iterator to its initial state, with new base data pointers */
-void NpyIter_ResetBasePointers(NpyIter *iter, char **baseptrs)
+int NpyIter_ResetBasePointers(NpyIter *iter, char **baseptrs)
{
npy_uint32 itflags = NIT_ITFLAGS(iter);
npy_intp ndim = NIT_NDIM(iter);
@@ -847,8 +874,17 @@ void NpyIter_ResetBasePointers(NpyIter *iter, char **baseptrs)
npy_intp *baseoffsets = NIT_BASEOFFSETS(iter);
if (itflags&NPY_ITFLAG_BUFFER) {
- /* Copy any data from the buffers back to the arrays */
- npyiter_copy_from_buffers(iter);
+ /* If buffer allocation was delayed, do it now */
+ if (itflags&NPY_ITFLAG_DELAYBUF) {
+ if (!npyiter_allocate_buffers(iter)) {
+ return NPY_FAIL;
+ }
+ NIT_ITFLAGS(iter) &= ~NPY_ITFLAG_DELAYBUF;
+ }
+ else {
+ /* Copy any data from the buffers back to the arrays */
+ npyiter_copy_from_buffers(iter);
+ }
}
/* The new data pointers for resetting */
@@ -862,6 +898,8 @@ void NpyIter_ResetBasePointers(NpyIter *iter, char **baseptrs)
/* Prepare the next buffers and set iterend/size */
npyiter_copy_to_buffers(iter);
}
+
+ return NPY_SUCCEED;
}
/* Resets the iterator to a new iterator index range */
@@ -896,9 +934,7 @@ NpyIter_ResetToIterIndexRange(NpyIter *iter,
NIT_ITERSTART(iter) = istart;
NIT_ITEREND(iter) = iend;
- NpyIter_Reset(iter);
-
- return NPY_SUCCEED;
+ return NpyIter_Reset(iter);
}
/*
@@ -943,7 +979,7 @@ int NpyIter_GotoCoords(NpyIter *iter, npy_intp *coords)
perm = NIT_PERM(iter);
axisdata = NIT_AXISDATA(iter);
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
/* Compute the iterindex corresponding to the coordinates */
iterindex = 0;
@@ -1032,7 +1068,7 @@ int NpyIter_GotoIndex(NpyIter *iter, npy_intp index)
}
axisdata = NIT_AXISDATA(iter);
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
/* Compute the iterindex corresponding to the index */
iterindex = 0;
@@ -1155,7 +1191,7 @@ npy_intp NpyIter_GetIterIndex(NpyIter *iter)
npy_intp sizeof_axisdata;
iterindex = 0;
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
axisdata = NIT_INDEX_AXISDATA(NIT_AXISDATA(iter), ndim-1);
for (idim = ndim-2; idim >= 0; --idim) {
@@ -1224,7 +1260,7 @@ npyiter_iternext_itflags@tag_itflags@_dims@tag_ndim@_iters@tag_niter@(
#endif
nstrides = NAD_NSTRIDES();
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
axisdata0 = NIT_AXISDATA(iter);
# if !(@const_itflags@&NPY_ITFLAG_NOINNER)
@@ -1520,7 +1556,7 @@ npyiter_getcoord_itflags@tag_itflags@(NpyIter *iter, npy_intp *outcoord)
#endif
axisdata = NIT_AXISDATA(iter);
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
#if ((@const_itflags@)&NPY_ITFLAG_IDENTPERM)
outcoord += ndim-1;
for(idim = 0; idim < ndim; ++idim, --outcoord,
@@ -1554,11 +1590,21 @@ NpyIter_GetCoords_Fn NpyIter_GetGetCoords(NpyIter *iter)
npy_intp ndim = NIT_NDIM(iter);
npy_intp niter = NIT_NITER(iter);
- if (!(itflags&NPY_ITFLAG_HASCOORDS)) {
- PyErr_SetString(PyExc_ValueError,
- "Cannot retrieve a GetCoords function for an iterator "
- "that doesn't track coordinates.");
- return NULL;
+ /* These flags must be correct */
+ if ((itflags&(NPY_ITFLAG_HASCOORDS|NPY_ITFLAG_DELAYBUF)) !=
+ NPY_ITFLAG_HASCOORDS) {
+ if (!(itflags&NPY_ITFLAG_HASCOORDS)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Cannot retrieve a GetCoords function for an iterator "
+ "that doesn't track coordinates.");
+ return NULL;
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "Cannot retrieve a GetCoords function for an iterator "
+ "that used DELAY_BUFALLOC before a Reset call");
+ return NULL;
+ }
}
/*
@@ -1601,6 +1647,11 @@ NpyIter_GetCoords_Fn NpyIter_GetGetCoords(NpyIter *iter)
}
+int NpyIter_HasDelayedBufAlloc(NpyIter *iter)
+{
+ return (NIT_ITFLAGS(iter)&NPY_ITFLAG_DELAYBUF) != 0;
+}
+
int NpyIter_HasInnerLoop(NpyIter *iter)
{
return (NIT_ITFLAGS(iter)&NPY_ITFLAG_NOINNER) == 0;
@@ -1658,7 +1709,7 @@ int NpyIter_GetShape(NpyIter *iter, npy_intp *outshape)
perm = NIT_PERM(iter);
axisdata = NIT_AXISDATA(iter);
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
for(idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) {
npy_intp p = perm[idim];
if (p < 0) {
@@ -1738,7 +1789,7 @@ PyArrayObject *NpyIter_GetIterView(NpyIter *iter, npy_intp i)
writeable = NIT_OPITFLAGS(iter)[i]&NPY_OP_ITFLAG_WRITE;
dataptr = NIT_RESETDATAPTR(iter)[i];
axisdata = NIT_AXISDATA(iter);
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
/* Retrieve the shape and strides from the axisdata */
for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) {
@@ -1901,6 +1952,9 @@ npyiter_check_global_flags(npy_uint32 flags, npy_uint32* itflags)
if (flags&NPY_ITER_GROWINNER) {
(*itflags) |= NPY_ITFLAG_GROWINNER;
}
+ if (flags&NPY_ITER_DELAY_BUFALLOC) {
+ (*itflags) |= NPY_ITFLAG_DELAYBUF;
+ }
}
return 1;
@@ -2161,11 +2215,11 @@ npyiter_prepare_one_operand(PyArrayObject **op,
*op_dtype = nbo_dtype;
/* Indicate that byte order or alignment needs fixing */
- *op_itflags |= NPY_OP_ITFLAG_COPYSWAP;
+ *op_itflags |= NPY_OP_ITFLAG_CAST;
}
/* Check alignment */
else if (!PyArray_ISALIGNED(*op)) {
- *op_itflags |= NPY_OP_ITFLAG_COPYSWAP;
+ *op_itflags |= NPY_OP_ITFLAG_CAST;
}
}
}
@@ -2412,7 +2466,7 @@ npyiter_fill_axisdata(NpyIter *iter, char **op_dataptr,
PyArrayObject **op = NIT_OBJECTS(iter);
axisdata0 = NIT_AXISDATA(iter);
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
/* Process the first operand */
if (op_axes == NULL || op_axes[0] == NULL) {
@@ -2683,7 +2737,7 @@ npyiter_replace_axisdata(NpyIter *iter, npy_intp iiter,
perm = NIT_PERM(iter);
axisdata0 = NIT_AXISDATA(iter);
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
/*
* Replace just the strides which were non-zero, and compute
@@ -2770,7 +2824,7 @@ npyiter_compute_index_strides(NpyIter *iter, npy_uint32 flags)
}
if (flags&NPY_ITER_C_INDEX) {
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
axisdata = NIT_AXISDATA(iter);
indexstride = 1;
for(idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) {
@@ -2787,7 +2841,7 @@ npyiter_compute_index_strides(NpyIter *iter, npy_uint32 flags)
}
}
else if (flags&NPY_ITER_F_INDEX) {
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
axisdata = NIT_INDEX_AXISDATA(NIT_AXISDATA(iter), ndim-1);
indexstride = 1;
for(idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, -1)) {
@@ -2871,7 +2925,7 @@ npyiter_flip_negative_strides(NpyIter *iter)
npy_intp istrides, nstrides = NAD_NSTRIDES();
NpyIter_AxisData *axisdata, *axisdata0;
npy_intp *baseoffsets;
- npy_intp sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
int any_flipped = 0;
axisdata0 = axisdata = NIT_AXISDATA(iter);
@@ -2956,7 +3010,7 @@ npyiter_reverse_axis_ordering(NpyIter *iter)
return;
}
- size = NIT_SIZEOF_AXISDATA(itflags, ndim, niter)/NPY_SIZEOF_INTP;
+ size = NIT_AXISDATA_SIZEOF(itflags, ndim, niter)/NPY_SIZEOF_INTP;
first = (npy_intp*)NIT_AXISDATA(iter);
last = first + (ndim-1)*size;
@@ -2995,7 +3049,7 @@ npyiter_find_best_axis_ordering(NpyIter *iter)
npy_intp i0, i1, ipos, j0, j1;
npy_intp *perm;
NpyIter_AxisData *axisdata = NIT_AXISDATA(iter);
- npy_intp sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
int permuted = 0;
perm = NIT_PERM(iter);
@@ -3132,7 +3186,7 @@ npyiter_coalesce_axes(NpyIter *iter)
npy_intp istrides, nstrides = NAD_NSTRIDES();
NpyIter_AxisData *axisdata = NIT_AXISDATA(iter);
- npy_intp sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
NpyIter_AxisData *ad_compress;
npy_intp new_ndim = 1;
@@ -3243,7 +3297,7 @@ npyiter_new_temp_array(NpyIter *iter, PyTypeObject *subtype,
stride = op_dtype->elsize;
char reversestride[NPY_MAXDIMS], anyreverse = 0;
NpyIter_AxisData *axisdata = NIT_AXISDATA(iter);
- npy_intp sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ npy_intp sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
PyArrayObject *ret;
@@ -3434,10 +3488,9 @@ npyiter_allocate_arrays(NpyIter *iter,
/* New arrays are aligned and need no swapping or casting */
op_itflags[iiter] |= NPY_OP_ITFLAG_ALIGNED;
- op_itflags[iiter] &= ~(NPY_OP_ITFLAG_COPYSWAP|NPY_OP_ITFLAG_CAST);
+ op_itflags[iiter] &= ~NPY_OP_ITFLAG_CAST;
}
- else if ((op_itflags[iiter]&
- (NPY_OP_ITFLAG_CAST|NPY_OP_ITFLAG_COPYSWAP)) &&
+ else if ((op_itflags[iiter]&NPY_OP_ITFLAG_CAST) &&
(op_itflags[iiter]&NPY_OP_ITFLAG_COPY)) {
PyArrayObject *temp;
npy_intp ondim = PyArray_NDIM(op[iiter]);
@@ -3479,16 +3532,15 @@ npyiter_allocate_arrays(NpyIter *iter,
/* The temporary copy is aligned and needs no swap or cast */
op_itflags[iiter] |= NPY_OP_ITFLAG_ALIGNED;
- op_itflags[iiter] &= ~(NPY_OP_ITFLAG_COPYSWAP|NPY_OP_ITFLAG_CAST);
+ op_itflags[iiter] &= ~NPY_OP_ITFLAG_CAST;
}
else {
/*
* Buffering must be enabled for casting/conversion if copy
* wasn't specified.
*/
- if (op_itflags[iiter]&
- (NPY_OP_ITFLAG_CAST|NPY_OP_ITFLAG_COPYSWAP) &&
- !(itflags&NPY_ITFLAG_BUFFER)) {
+ if ((op_itflags[iiter]&NPY_OP_ITFLAG_CAST) &&
+ !(itflags&NPY_ITFLAG_BUFFER)) {
PyErr_SetString(PyExc_TypeError,
"Iterator operand required copying or buffering, "
"but neither copying nor buffering was enabled");
@@ -3515,14 +3567,13 @@ npyiter_allocate_arrays(NpyIter *iter,
* dimension.
*/
if ((itflags&NPY_ITFLAG_BUFFER) &&
- (!(op_itflags[iiter]&(NPY_OP_ITFLAG_CAST|
- NPY_OP_ITFLAG_COPYSWAP)) ||
+ (!(op_itflags[iiter]&NPY_OP_ITFLAG_CAST) ||
(op_itflags[iiter]&NPY_OP_ITFLAG_WRITE))) {
int is_one_to_one = 1;
npy_intp stride, shape, innerstride = 0, innershape;
NpyIter_AxisData *axisdata = NIT_AXISDATA(iter);
npy_intp sizeof_axisdata =
- NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
/* Find stride of the first non-empty shape */
for (idim = 0; idim < ndim; ++idim) {
innershape = NAD_SHAPE(axisdata);
@@ -3563,9 +3614,7 @@ npyiter_allocate_arrays(NpyIter *iter,
* Set that stride, because it may not belong to the first
* dimension.
*/
- if (idim == ndim &&
- !(op_itflags[iiter]&(NPY_OP_ITFLAG_CAST|
- NPY_OP_ITFLAG_COPYSWAP))) {
+ if (idim == ndim && !(op_itflags[iiter]&NPY_OP_ITFLAG_CAST)) {
op_itflags[iiter] |= NPY_OP_ITFLAG_BUFNEVER;
NBF_STRIDES(bufferdata)[iiter] = innerstride;
}
@@ -3789,8 +3838,9 @@ npyiter_allocate_buffers(NpyIter *iter)
{
npy_uint32 itflags = NIT_ITFLAGS(iter);
npy_intp ndim = NIT_NDIM(iter);
- npy_intp iiter, niter = NIT_NITER(iter);
+ npy_intp iiter = 0, niter = NIT_NITER(iter);
+ npy_intp i;
char *op_itflags = NIT_OPITFLAGS(iter);
NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter);
NpyIter_AxisData *axisdata = NIT_AXISDATA(iter);
@@ -3798,7 +3848,11 @@ npyiter_allocate_buffers(NpyIter *iter)
PyArray_Descr **op_dtype = NIT_DTYPES(iter);
npy_intp *strides = NAD_STRIDES(axisdata), op_stride;
npy_intp buffersize = NBF_BUFFERSIZE(bufferdata);
- char *buffer;
+ char *buffer, **buffers = NBF_BUFFERS(bufferdata);
+ PyArray_StridedTransferFn *readtransferfn = NBF_READTRANSFERFN(bufferdata),
+ *writetransferfn = NBF_WRITETRANSFERFN(bufferdata);
+ void **readtransferdata = NBF_READTRANSFERDATA(bufferdata),
+ **writetransferdata = NBF_WRITETRANSFERDATA(bufferdata);
PyArray_StridedTransferFn stransfer = NULL;
void *transferdata = NULL;
@@ -3815,10 +3869,9 @@ npyiter_allocate_buffers(NpyIter *iter)
npy_intp itemsize = op_dtype[iiter]->elsize;
buffer = PyArray_malloc(itemsize*buffersize);
if (buffer == NULL) {
- PyErr_NoMemory();
- return 0;
+ goto fail;
}
- NBF_BUFFERS(bufferdata)[iiter] = buffer;
+ buffers[iiter] = buffer;
/* Also need to get an appropriate transfer functions */
if (flags&NPY_OP_ITFLAG_READ) {
@@ -3830,13 +3883,13 @@ npyiter_allocate_buffers(NpyIter *iter)
op_dtype[iiter],
&stransfer,
&transferdata) != NPY_SUCCEED) {
- return 0;
+ goto fail;
}
- NBF_READTRANSFERFN(bufferdata)[iiter] = stransfer;
- NBF_READTRANSFERDATA(bufferdata)[iiter] = transferdata;
+ readtransferfn[iiter] = stransfer;
+ readtransferdata[iiter] = transferdata;
}
else {
- NBF_READTRANSFERFN(bufferdata)[iiter] = NULL;
+ readtransferfn[iiter] = NULL;
}
if (flags&NPY_OP_ITFLAG_WRITE) {
if (PyArray_GetDTypeTransferFunction(
@@ -3847,22 +3900,40 @@ npyiter_allocate_buffers(NpyIter *iter)
PyArray_DESCR(op[iiter]),
&stransfer,
&transferdata) != NPY_SUCCEED) {
- return 0;
+ goto fail;
}
- NBF_WRITETRANSFERFN(bufferdata)[iiter] = stransfer;
- NBF_WRITETRANSFERDATA(bufferdata)[iiter] = transferdata;
+ writetransferfn[iiter] = stransfer;
+ writetransferdata[iiter] = transferdata;
}
else {
- NBF_WRITETRANSFERFN(bufferdata)[iiter] = NULL;
+ writetransferfn[iiter] = NULL;
}
}
else {
- NBF_READTRANSFERFN(bufferdata)[iiter] = NULL;
- NBF_WRITETRANSFERFN(bufferdata)[iiter] = NULL;
+ readtransferfn[iiter] = NULL;
+ writetransferfn[iiter] = NULL;
}
}
return 1;
+
+fail:
+ for (i = 0; i < iiter; ++i) {
+ if (buffers[i] != NULL) {
+ PyArray_free(buffers[i]);
+ buffers[i] = NULL;
+ }
+ if (readtransferdata[iiter] != NULL) {
+ PyArray_FreeStridedTransferData(readtransferdata[iiter]);
+ readtransferdata[iiter] = NULL;
+ }
+ if (writetransferdata[iiter] != NULL) {
+ PyArray_FreeStridedTransferData(writetransferdata[iiter]);
+ writetransferdata[iiter] = NULL;
+ }
+ }
+ PyErr_NoMemory();
+ return 0;
}
/*
@@ -3882,7 +3953,7 @@ static void npyiter_goto_iterindex(NpyIter *iter, npy_intp iterindex)
npy_intp istrides, nstrides, i, shape;
axisdata = NIT_AXISDATA(iter);
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
nstrides = NAD_NSTRIDES();
NIT_ITERINDEX(iter) = iterindex;
@@ -3973,7 +4044,7 @@ npyiter_copy_from_buffers(NpyIter *iter)
PyArray_StridedTransferFn stransfer = NULL;
void *transferdata = NULL;
- npy_intp axisdata_incr = NIT_SIZEOF_AXISDATA(itflags, ndim, niter) /
+ npy_intp axisdata_incr = NIT_AXISDATA_SIZEOF(itflags, ndim, niter) /
NPY_SIZEOF_INTP;
/* If we're past the end, nothing to copy */
@@ -4028,7 +4099,7 @@ npyiter_copy_to_buffers(NpyIter *iter)
PyArray_StridedTransferFn stransfer = NULL;
void *transferdata = NULL;
- npy_intp axisdata_incr = NIT_SIZEOF_AXISDATA(itflags, ndim, niter) /
+ npy_intp axisdata_incr = NIT_AXISDATA_SIZEOF(itflags, ndim, niter) /
NPY_SIZEOF_INTP;
/* Calculate the size if using any buffers */
@@ -4058,9 +4129,7 @@ npyiter_copy_to_buffers(NpyIter *iter)
stransfer = NBF_READTRANSFERFN(bufferdata)[iiter];
transferdata = NBF_READTRANSFERDATA(bufferdata)[iiter];
switch (op_itflags[iiter]&
- (NPY_OP_ITFLAG_BUFNEVER|
- NPY_OP_ITFLAG_COPYSWAP|
- NPY_OP_ITFLAG_CAST)) {
+ (NPY_OP_ITFLAG_BUFNEVER|NPY_OP_ITFLAG_CAST)) {
/* never need to buffer this operand */
case NPY_OP_ITFLAG_BUFNEVER:
ptrs[iiter] = ad_ptrs[iiter];
@@ -4150,10 +4219,16 @@ NpyIter_DebugPrint(NpyIter *iter)
printf("FORCEDORDER ");
if (itflags&NPY_ITFLAG_NOINNER)
printf("NOINNER ");
+ if (itflags&NPY_ITFLAG_RANGE)
+ printf("RANGE ");
if (itflags&NPY_ITFLAG_BUFFER)
printf("BUFFER ");
if (itflags&NPY_ITFLAG_GROWINNER)
printf("GROWINNER ");
+ if (itflags&NPY_ITFLAG_ONEITERATION)
+ printf("ONEITERATION ");
+ if (itflags&NPY_ITFLAG_DELAYBUF)
+ printf("DELAYBUF ");
printf("\n");
printf("NDim: %d\n", (int)ndim);
printf("NIter: %d\n", (int)niter);
@@ -4163,8 +4238,10 @@ NpyIter_DebugPrint(NpyIter *iter)
printf("IterIndex: %d\n", (int)NIT_ITERINDEX(iter));
printf("Iterator SizeOf: %d\n",
(int)NIT_SIZEOF_ITERATOR(itflags, ndim, niter));
+ printf("BufferData SizeOf: %d\n",
+ (int)NIT_BUFFERDATA_SIZEOF(itflags, ndim, niter));
printf("AxisData SizeOf: %d\n",
- (int)NIT_SIZEOF_AXISDATA(itflags, ndim, niter));
+ (int)NIT_AXISDATA_SIZEOF(itflags, ndim, niter));
printf("\n");
printf("Perm: ");
@@ -4216,8 +4293,6 @@ NpyIter_DebugPrint(NpyIter *iter)
printf("COPY ");
if ((NIT_OPITFLAGS(iter)[iiter])&NPY_OP_ITFLAG_CAST)
printf("CAST ");
- if ((NIT_OPITFLAGS(iter)[iiter])&NPY_OP_ITFLAG_COPYSWAP)
- printf("COPYSWAP ");
if ((NIT_OPITFLAGS(iter)[iiter])&NPY_OP_ITFLAG_BUFNEVER)
printf("BUFNEVER ");
if ((NIT_OPITFLAGS(iter)[iiter])&NPY_OP_ITFLAG_ALIGNED)
@@ -4264,7 +4339,7 @@ NpyIter_DebugPrint(NpyIter *iter)
}
axisdata = NIT_AXISDATA(iter);
- sizeof_axisdata = NIT_SIZEOF_AXISDATA(itflags, ndim, niter);
+ sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, niter);
for (idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) {
printf("AxisData[%d]:\n", (int)idim);
printf(" Shape: %d\n", (int)NAD_SHAPE(axisdata));
diff --git a/numpy/core/src/multiarray/new_iterator.h b/numpy/core/src/multiarray/new_iterator.h
index 72e7d87ea..2d54a31af 100644
--- a/numpy/core/src/multiarray/new_iterator.h
+++ b/numpy/core/src/multiarray/new_iterator.h
@@ -48,6 +48,9 @@ NpyIter_Copy(NpyIter *iter);
/* Deallocate an iterator */
int NpyIter_Deallocate(NpyIter* iter);
+/* Whether the buffer allocation is being delayed */
+int NpyIter_HasDelayedBufAlloc(NpyIter *iter);
+
/* Whether the iterator handles the inner loop */
int NpyIter_HasInnerLoop(NpyIter *iter);
/* Removes the inner loop handling (so HasInnerLoop returns false) */
@@ -58,9 +61,9 @@ npy_intp *NpyIter_GetInnerStrideArray(NpyIter *iter);
npy_intp* NpyIter_GetInnerLoopSizePtr(NpyIter *iter);
/* Resets the iterator to its initial state */
-void NpyIter_Reset(NpyIter *iter);
+int NpyIter_Reset(NpyIter *iter);
/* Resets the iterator to its initial state, with new base data pointers */
-void NpyIter_ResetBasePointers(NpyIter *iter, char **baseptrs);
+int NpyIter_ResetBasePointers(NpyIter *iter, char **baseptrs);
/* Resets the iterator to a new iterator index range */
int NpyIter_ResetToIterIndexRange(NpyIter *iter,
npy_intp istart, npy_intp iend);
@@ -137,6 +140,8 @@ NPY_NO_EXPORT void NpyIter_DebugPrint(NpyIter *iter);
#define NPY_ITER_BUFFERED 0x00000040
/* When buffering is enabled, grows the inner loop if possible */
#define NPY_ITER_GROWINNER 0x00000080
+/* Delay allocation of buffers until first Reset* call */
+#define NPY_ITER_DELAY_BUFALLOC 0x00000100
/*** Per-operand flags that may be passed to the iterator constructors ***/
diff --git a/numpy/core/src/multiarray/new_iterator_pywrap.c b/numpy/core/src/multiarray/new_iterator_pywrap.c
index 9a0b6cbfd..871ab33b7 100644
--- a/numpy/core/src/multiarray/new_iterator_pywrap.c
+++ b/numpy/core/src/multiarray/new_iterator_pywrap.c
@@ -38,7 +38,7 @@ void npyiter_cache_values(NewNpyArrayIterObject *self)
/* iternext and getcoords functions */
self->iternext = NpyIter_GetIterNext(iter);
- if (NpyIter_HasCoords(iter)) {
+ if (NpyIter_HasCoords(iter) && !NpyIter_HasDelayedBufAlloc(iter)) {
self->getcoords = NpyIter_GetGetCoords(iter);
}
else {
@@ -87,17 +87,17 @@ NpyIter_GlobalFlagsConverter(PyObject *flags_in, npy_uint32 *flags)
PyObject *f;
char *str = NULL;
Py_ssize_t length = 0;
- npy_uint32 flag = 0;
+ npy_uint32 flag;
if (flags_in == NULL || flags_in == Py_None) {
*flags = 0;
- return NPY_SUCCEED;
+ return 1;
}
if (!PyTuple_Check(flags_in) && !PyList_Check(flags_in)) {
PyErr_SetString(PyExc_ValueError,
"Iterator global flags must be a list or tuple of strings");
- return NPY_FAIL;
+ return 0;
}
nflags = PySequence_Size(flags_in);
@@ -105,13 +105,14 @@ NpyIter_GlobalFlagsConverter(PyObject *flags_in, npy_uint32 *flags)
for (iflags = 0; iflags < nflags; ++iflags) {
f = PySequence_GetItem(flags_in, iflags);
if (f == NULL) {
- return NPY_FAIL;
+ return 0;
}
if (PyString_AsStringAndSize(f, &str, &length) == -1) {
Py_DECREF(f);
- return NPY_FAIL;
+ return 0;
}
/* Use switch statements to quickly isolate the right flag */
+ flag = 0;
switch (str[0]) {
case 'b':
if (strcmp(str, "buffered") == 0) {
@@ -137,6 +138,11 @@ NpyIter_GlobalFlagsConverter(PyObject *flags_in, npy_uint32 *flags)
break;
}
break;
+ case 'd':
+ if (strcmp(str, "delay_bufalloc") == 0) {
+ flag = NPY_ITER_DELAY_BUFALLOC;
+ }
+ break;
case 'f':
if (strcmp(str, "f_index") == 0) {
flag = NPY_ITER_F_INDEX;
@@ -162,7 +168,7 @@ NpyIter_GlobalFlagsConverter(PyObject *flags_in, npy_uint32 *flags)
PyErr_Format(PyExc_ValueError,
"Unexpected iterator global flag \"%s\"", str);
Py_DECREF(f);
- return NPY_FAIL;
+ return 0;
}
else {
tmpflags |= flag;
@@ -171,7 +177,7 @@ NpyIter_GlobalFlagsConverter(PyObject *flags_in, npy_uint32 *flags)
}
*flags |= tmpflags;
- return NPY_SUCCEED;
+ return 1;
}
/* TODO: Use PyArray_OrderConverter once 'K' is added there */
@@ -182,27 +188,27 @@ npyiter_order_converter(PyObject *order_in, NPY_ORDER *order)
Py_ssize_t length = 0;
if (PyString_AsStringAndSize(order_in, &str, &length) == -1) {
- return NPY_FAIL;
+ return 0;
}
if (length == 1) switch (str[0]) {
case 'C':
*order = NPY_CORDER;
- return NPY_SUCCEED;
+ return 1;
case 'F':
*order = NPY_FORTRANORDER;
- return NPY_SUCCEED;
+ return 1;
case 'A':
*order = NPY_ANYORDER;
- return NPY_SUCCEED;
+ return 1;
case 'K':
*order = NPY_KEEPORDER;
- return NPY_SUCCEED;
+ return 1;
}
PyErr_SetString(PyExc_ValueError,
"order must be one of 'C', 'F', 'A', or 'K'");
- return NPY_FAIL;
+ return 0;
}
/*
@@ -216,37 +222,37 @@ PyArray_CastingConverter(PyObject *obj, NPY_CASTING *casting)
Py_ssize_t length = 0;
if (PyString_AsStringAndSize(obj, &str, &length) == -1) {
- return NPY_FAIL;
+ return 0;
}
if (length >= 2) switch (str[2]) {
case 0:
if (strcmp(str, "no") == 0) {
*casting = NPY_NO_CASTING;
- return NPY_SUCCEED;
+ return 1;
}
break;
case 'u':
if (strcmp(str, "equiv") == 0) {
*casting = NPY_EQUIV_CASTING;
- return NPY_SUCCEED;
+ return 1;
}
break;
case 'f':
if (strcmp(str, "safe") == 0) {
*casting = NPY_SAFE_CASTING;
- return NPY_SUCCEED;
+ return 1;
}
break;
case 'm':
if (strcmp(str, "same_kind") == 0) {
*casting = NPY_SAME_KIND_CASTING;
- return NPY_SUCCEED;
+ return 1;
}
break;
case 's':
if (strcmp(str, "unsafe") == 0) {
*casting = NPY_UNSAFE_CASTING;
- return NPY_SUCCEED;
+ return 1;
}
break;
}
@@ -254,7 +260,7 @@ PyArray_CastingConverter(PyObject *obj, NPY_CASTING *casting)
PyErr_SetString(PyExc_ValueError,
"casting must be one of 'no', 'equiv', 'safe', "
"'same_kind', or 'unsafe'");
- return NPY_FAIL;
+ return 0;
}
@@ -263,11 +269,12 @@ NpyIter_OpFlagsConverter(PyObject *op_flags_in,
npy_uint32 *op_flags)
{
int iflags, nflags;
+ npy_uint32 flag;
if (!PyTuple_Check(op_flags_in) && !PyList_Check(op_flags_in)) {
PyErr_SetString(PyExc_ValueError,
"op_flags must be a tuple or array of per-op flag-tuples");
- return NPY_FAIL;
+ return 0;
}
nflags = PySequence_Size(op_flags_in);
@@ -277,21 +284,21 @@ NpyIter_OpFlagsConverter(PyObject *op_flags_in,
PyObject *f;
char *str = NULL;
Py_ssize_t length = 0;
- npy_uint32 flag = 0;
f = PySequence_GetItem(op_flags_in, iflags);
if (f == NULL) {
- return NPY_FAIL;
+ return 0;
}
if (PyString_AsStringAndSize(f, &str, &length) == -1) {
Py_DECREF(f);
PyErr_SetString(PyExc_ValueError,
"op_flags must be a tuple or array of per-op flag-tuples");
- return NPY_FAIL;
+ return 0;
}
/* Use switch statements to quickly isolate the right flag */
+ flag = 0;
switch (str[0]) {
case 'a':
if (strcmp(str, "allocate") == 0) {
@@ -359,7 +366,7 @@ NpyIter_OpFlagsConverter(PyObject *op_flags_in,
PyErr_Format(PyExc_ValueError,
"Unexpected per-op iterator flag \"%s\"", str);
Py_DECREF(f);
- return NPY_FAIL;
+ return 0;
}
else {
*op_flags |= flag;
@@ -367,7 +374,7 @@ NpyIter_OpFlagsConverter(PyObject *op_flags_in,
Py_DECREF(f);
}
- return NPY_SUCCEED;
+ return 1;
}
static int
@@ -379,7 +386,7 @@ npyiter_convert_op_flags_array(PyObject *op_flags_in,
if (!PyTuple_Check(op_flags_in) && !PyList_Check(op_flags_in)) {
PyErr_SetString(PyExc_ValueError,
"op_flags must be a tuple or array of per-op flag-tuples");
- return NPY_FAIL;
+ return 0;
}
if (PySequence_Size(op_flags_in) != niter) {
@@ -389,35 +396,35 @@ npyiter_convert_op_flags_array(PyObject *op_flags_in,
for (iiter = 0; iiter < niter; ++iiter) {
PyObject *f = PySequence_GetItem(op_flags_in, iiter);
if (f == NULL) {
- return NPY_FAIL;
+ return 0;
}
if (NpyIter_OpFlagsConverter(f,
- &op_flags_array[iiter]) != NPY_SUCCEED) {
+ &op_flags_array[iiter]) != 1) {
Py_DECREF(f);
/* If the first one doesn't work, try the whole thing as flags */
if (iiter == 0) {
PyErr_Clear();
goto try_single_flags;
}
- return NPY_FAIL;
+ return 0;
}
Py_DECREF(f);
}
- return NPY_SUCCEED;
+ return 1;
try_single_flags:
if (NpyIter_OpFlagsConverter(op_flags_in,
- &op_flags_array[0]) != NPY_SUCCEED) {
- return NPY_FAIL;
+ &op_flags_array[0]) != 1) {
+ return 0;
}
for (iiter = 1; iiter < niter; ++iiter) {
op_flags_array[iiter] = op_flags_array[0];
}
- return NPY_SUCCEED;
+ return 1;
}
static int
@@ -443,11 +450,11 @@ npyiter_convert_dtypes(PyObject *op_dtypes_in,
for (i = 0; i < iiter; ++i ) {
Py_XDECREF(op_dtypes[i]);
}
- return NPY_FAIL;
+ return 0;
}
/* Try converting the object to a descr */
- if (PyArray_DescrConverter2(dtype, &op_dtypes[iiter]) != NPY_SUCCEED) {
+ if (PyArray_DescrConverter2(dtype, &op_dtypes[iiter]) != 1) {
npy_intp i;
for (i = 0; i < iiter; ++i ) {
Py_XDECREF(op_dtypes[i]);
@@ -460,18 +467,18 @@ npyiter_convert_dtypes(PyObject *op_dtypes_in,
Py_DECREF(dtype);
}
- return NPY_SUCCEED;
+ return 1;
try_single_dtype:
- if (PyArray_DescrConverter2(op_dtypes_in, &op_dtypes[0]) == NPY_SUCCEED) {
+ if (PyArray_DescrConverter2(op_dtypes_in, &op_dtypes[0]) == 1) {
for (iiter = 1; iiter < niter; ++iiter) {
op_dtypes[iiter] = op_dtypes[0];
Py_XINCREF(op_dtypes[iiter]);
}
- return NPY_SUCCEED;
+ return 1;
}
- return NPY_FAIL;
+ return 0;
}
static int
@@ -485,7 +492,7 @@ npyiter_convert_op_axes(PyObject *op_axes_in, npy_intp niter,
PySequence_Size(op_axes_in) != niter) {
PyErr_SetString(PyExc_ValueError,
"op_axes must be a tuple/list matching the number of ops");
- return NPY_FAIL;
+ return 0;
}
*oa_ndim = 0;
@@ -495,7 +502,7 @@ npyiter_convert_op_axes(PyObject *op_axes_in, npy_intp niter,
npy_intp idim;
a = PySequence_GetItem(op_axes_in, iiter);
if (a == NULL) {
- return NPY_FAIL;
+ return 0;
}
if (a == Py_None) {
op_axes[iiter] = NULL;
@@ -505,32 +512,32 @@ npyiter_convert_op_axes(PyObject *op_axes_in, npy_intp niter,
"Each entry of op_axes must be None "
"or a tuple/list");
Py_DECREF(a);
- return NPY_FAIL;
+ return 0;
}
if (*oa_ndim == 0) {
*oa_ndim = PySequence_Size(a);
if (*oa_ndim == 0) {
PyErr_SetString(PyExc_ValueError,
"op_axes must have at least one dimension");
- return NPY_FAIL;
+ return 0;
}
if (*oa_ndim > NPY_MAXDIMS) {
PyErr_SetString(PyExc_ValueError,
"Too many dimensions in op_axes");
- return NPY_FAIL;
+ return 0;
}
}
if (PySequence_Size(a) != *oa_ndim) {
PyErr_SetString(PyExc_ValueError,
"Each entry of op_axes must have the same size");
Py_DECREF(a);
- return NPY_FAIL;
+ return 0;
}
for (idim = 0; idim < *oa_ndim; ++idim) {
PyObject *v = PySequence_GetItem(a, idim);
if (v == NULL) {
Py_DECREF(a);
- return NPY_FAIL;
+ return 0;
}
/* numpy.newaxis is None */
if (v == Py_None) {
@@ -542,7 +549,7 @@ npyiter_convert_op_axes(PyObject *op_axes_in, npy_intp niter,
PyErr_Occurred()) {
Py_DECREF(a);
Py_DECREF(v);
- return NPY_FAIL;
+ return 0;
}
}
Py_DECREF(v);
@@ -555,10 +562,10 @@ npyiter_convert_op_axes(PyObject *op_axes_in, npy_intp niter,
PyErr_SetString(PyExc_ValueError,
"If op_axes is provided, at least one list of axes "
"must be contained within it");
- return NPY_FAIL;
+ return 0;
}
- return NPY_SUCCEED;
+ return 1;
}
/*
@@ -579,11 +586,11 @@ npyiter_convert_ops(PyObject *op_in, PyObject *op_flags_in,
if (niter == 0) {
PyErr_SetString(PyExc_ValueError,
"Must provide at least one operand");
- return NPY_FAIL;
+ return 0;
}
if (niter > NPY_MAXARGS) {
PyErr_SetString(PyExc_ValueError, "Too many operands");
- return NPY_FAIL;
+ return 0;
}
for (iiter = 0; iiter < niter; ++iiter) {
@@ -593,7 +600,7 @@ npyiter_convert_ops(PyObject *op_in, PyObject *op_flags_in,
for (i = 0; i < iiter; ++i) {
Py_XDECREF(op[i]);
}
- return NPY_FAIL;
+ return 0;
}
else if (item == Py_None) {
Py_DECREF(item);
@@ -633,11 +640,11 @@ npyiter_convert_ops(PyObject *op_in, PyObject *op_flags_in,
}
}
else if (npyiter_convert_op_flags_array(op_flags_in,
- op_flags, niter) != NPY_SUCCEED) {
+ op_flags, niter) != 1) {
for (iiter = 0; iiter < niter; ++iiter) {
Py_XDECREF(op[iiter]);
}
- return NPY_FAIL;
+ return 0;
}
/* Now that we have the flags - convert all the ops to arrays */
@@ -662,14 +669,14 @@ npyiter_convert_ops(PyObject *op_in, PyObject *op_flags_in,
for (iiter = 0; iiter < niter; ++iiter) {
Py_DECREF(op[iiter]);
}
- return NPY_FAIL;
+ return 0;
}
Py_DECREF(op[iiter]);
op[iiter] = ao;
}
}
- return NPY_SUCCEED;
+ return 1;
}
static int
@@ -679,7 +686,7 @@ npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds)
"order", "casting", "op_axes", "buffersize",
NULL};
- PyObject *op_in = NULL, *flags_in = NULL, *op_flags_in = NULL,
+ PyObject *op_in = NULL, *op_flags_in = NULL,
*op_dtypes_in = NULL, *op_axes_in = NULL;
npy_intp iiter, niter = 0;
@@ -700,9 +707,9 @@ npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds)
return -1;
}
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOOO&O&Oi", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&OOO&O&Oi", kwlist,
&op_in,
- &flags_in,
+ NpyIter_GlobalFlagsConverter, &flags,
&op_flags_in,
&op_dtypes_in,
npyiter_order_converter, &order,
@@ -712,14 +719,9 @@ npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds)
return -1;
}
- /* flags */
- if (NpyIter_GlobalFlagsConverter(flags_in, &flags) != NPY_SUCCEED) {
- return -1;
- }
-
/* op and op_flags */
if (npyiter_convert_ops(op_in, op_flags_in, op, op_flags, &niter)
- != NPY_SUCCEED) {
+ != 1) {
return -1;
}
@@ -729,7 +731,7 @@ npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds)
/* op_request_dtypes */
if (op_dtypes_in != NULL && op_dtypes_in != Py_None &&
npyiter_convert_dtypes(op_dtypes_in,
- op_request_dtypes, niter) != NPY_SUCCEED) {
+ op_request_dtypes, niter) != 1) {
goto fail;
}
@@ -741,7 +743,7 @@ npyiter_init(NewNpyArrayIterObject *self, PyObject *args, PyObject *kwds)
}
if (npyiter_convert_op_axes(op_axes_in, niter,
- op_axes, &oa_ndim) != NPY_SUCCEED) {
+ op_axes, &oa_ndim) != 1) {
goto fail;
}
}
@@ -786,7 +788,7 @@ NpyIter_NestedIters(PyObject *NPY_UNUSED(self),
"casting", "buffersize",
NULL};
- PyObject *op_in = NULL, *axes_in = NULL, *flags_in = NULL,
+ PyObject *op_in = NULL, *axes_in = NULL,
*op_flags_in = NULL, *op_dtypes_in = NULL;
npy_intp iiter, niter = 0, inest, nnest = 0;
@@ -806,10 +808,10 @@ NpyIter_NestedIters(PyObject *NPY_UNUSED(self),
PyObject *ret = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOOO&O&i", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O&OOO&O&i", kwlist,
&op_in,
&axes_in,
- &flags_in,
+ NpyIter_GlobalFlagsConverter, &flags,
&op_flags_in,
&op_dtypes_in,
npyiter_order_converter, &order,
@@ -884,14 +886,9 @@ NpyIter_NestedIters(PyObject *NPY_UNUSED(self),
Py_DECREF(item);
}
- /* flags */
- if (NpyIter_GlobalFlagsConverter(flags_in, &flags) != NPY_SUCCEED) {
- return NULL;
- }
-
/* op and op_flags */
if (npyiter_convert_ops(op_in, op_flags_in, op, op_flags, &niter)
- != NPY_SUCCEED) {
+ != 1) {
return NULL;
}
@@ -903,7 +900,7 @@ NpyIter_NestedIters(PyObject *NPY_UNUSED(self),
/* op_request_dtypes */
if (op_dtypes_in != NULL && op_dtypes_in != Py_None &&
npyiter_convert_dtypes(op_dtypes_in,
- op_request_dtypes, niter) != NPY_SUCCEED) {
+ op_request_dtypes, niter) != 1) {
goto fail;
}
@@ -1069,7 +1066,11 @@ NpyIter_NestedIters(PyObject *NPY_UNUSED(self),
* Need to do a nested reset so all the iterators point
* at the right data
*/
- NpyIter_ResetBasePointers(iter->nested_child->iter, iter->dataptrs);
+ if (NpyIter_ResetBasePointers(iter->nested_child->iter,
+ iter->dataptrs) != NPY_SUCCEED) {
+ Py_DECREF(ret);
+ return NULL;
+ }
}
return ret;
@@ -1095,16 +1096,20 @@ npyiter_dealloc(NewNpyArrayIterObject *self)
self->ob_type->tp_free((PyObject*)self);
}
-static void
+static int
npyiter_resetbasepointers(NewNpyArrayIterObject *self)
{
while (self->nested_child) {
- NpyIter_ResetBasePointers(self->nested_child->iter,
- self->dataptrs);
+ if (NpyIter_ResetBasePointers(self->nested_child->iter,
+ self->dataptrs) != NPY_SUCCEED) {
+ return NPY_FAIL;
+ }
self = self->nested_child;
self->started = 0;
self->finished = 0;
}
+
+ return NPY_SUCCEED;
}
static PyObject *
@@ -1116,12 +1121,20 @@ npyiter_reset(NewNpyArrayIterObject *self)
return NULL;
}
- NpyIter_Reset(self->iter);
+ if (NpyIter_Reset(self->iter) != NPY_SUCCEED) {
+ return NULL;
+ }
self->started = 0;
self->finished = 0;
+ if (self->getcoords == NULL && NpyIter_HasCoords(self->iter)) {
+ self->getcoords = NpyIter_GetGetCoords(self->iter);
+ }
+
/* If there is nesting, the nested iterators should be reset */
- npyiter_resetbasepointers(self);
+ if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
+ return NULL;
+ }
Py_RETURN_NONE;
}
@@ -1168,7 +1181,9 @@ npyiter_iternext(NewNpyArrayIterObject *self)
{
if (self->iter != NULL && !self->finished && self->iternext(self->iter)) {
/* If there is nesting, the nested iterators should be reset */
- npyiter_resetbasepointers(self);
+ if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
+ return NULL;
+ }
Py_RETURN_TRUE;
}
@@ -1346,7 +1361,9 @@ npyiter_next(NewNpyArrayIterObject *self)
}
/* If there is nesting, the nested iterators should be reset */
- npyiter_resetbasepointers(self);
+ if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
+ return NULL;
+ }
}
self->started = 1;
@@ -1390,7 +1407,7 @@ static PyObject *npyiter_coords_get(NewNpyArrayIterObject *self)
return NULL;
}
- if (NpyIter_HasCoords(self->iter)) {
+ if (self->getcoords != NULL) {
ndim = NpyIter_GetNDim(self->iter);
self->getcoords(self->iter, coords);
ret = PyTuple_New(ndim);
@@ -1401,9 +1418,22 @@ static PyObject *npyiter_coords_get(NewNpyArrayIterObject *self)
return ret;
}
else {
- PyErr_SetString(PyExc_ValueError,
- "Iterator does not have coordinates");
- return NULL;
+ if (!NpyIter_HasCoords(self->iter)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Iterator does not have coordinates");
+ return NULL;
+ }
+ else if (NpyIter_HasDelayedBufAlloc(self->iter)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Iterator construction used delayed buffer allocation, "
+ "and no reset has been done yet");
+ return NULL;
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "Iterator is in an invalid state");
+ return NULL;
+ }
}
}
@@ -1449,7 +1479,9 @@ static int npyiter_coords_set(NewNpyArrayIterObject *self, PyObject *value)
self->finished = 0;
/* If there is nesting, the nested iterators should be reset */
- npyiter_resetbasepointers(self);
+ if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
+ return -1;
+ }
return 0;
}
@@ -1506,7 +1538,9 @@ static int npyiter_index_set(NewNpyArrayIterObject *self, PyObject *value)
self->finished = 0;
/* If there is nesting, the nested iterators should be reset */
- npyiter_resetbasepointers(self);
+ if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
+ return -1;
+ }
return 0;
}
@@ -1555,7 +1589,9 @@ static int npyiter_iterindex_set(NewNpyArrayIterObject *self, PyObject *value)
self->finished = 0;
/* If there is nesting, the nested iterators should be reset */
- npyiter_resetbasepointers(self);
+ if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
+ return -1;
+ }
return 0;
}
@@ -1615,12 +1651,34 @@ static int npyiter_iterrange_set(NewNpyArrayIterObject *self, PyObject *value)
self->started = self->finished = 1;
}
+ if (self->getcoords == NULL && NpyIter_HasCoords(self->iter)) {
+ self->getcoords = NpyIter_GetGetCoords(self->iter);
+ }
+
/* If there is nesting, the nested iterators should be reset */
- npyiter_resetbasepointers(self);
+ if (npyiter_resetbasepointers(self) != NPY_SUCCEED) {
+ return -1;
+ }
return 0;
}
+static PyObject *npyiter_hasdelayedbufalloc_get(NewNpyArrayIterObject *self)
+{
+ if (self->iter == NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "Iterator is invalid");
+ return NULL;
+ }
+
+ if (NpyIter_HasDelayedBufAlloc(self->iter)) {
+ Py_RETURN_TRUE;
+ }
+ else {
+ Py_RETURN_FALSE;
+ }
+}
+
static PyObject *npyiter_hascoords_get(NewNpyArrayIterObject *self)
{
if (self->iter == NULL) {
@@ -1752,6 +1810,14 @@ npyiter_seq_item(NewNpyArrayIterObject *self, Py_ssize_t i)
"Iterator is past the end");
return NULL;
}
+
+ if (NpyIter_HasDelayedBufAlloc(self->iter)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Iterator construction used delayed buffer allocation, "
+ "and no reset has been done yet");
+ return NULL;
+ }
+
niter = NpyIter_GetNIter(self->iter);
if (i < 0 || i >= niter) {
PyErr_Format(PyExc_IndexError,
@@ -1815,6 +1881,14 @@ npyiter_seq_slice(NewNpyArrayIterObject *self,
"Iterator is past the end");
return NULL;
}
+
+ if (NpyIter_HasDelayedBufAlloc(self->iter)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Iterator construction used delayed buffer allocation, "
+ "and no reset has been done yet");
+ return NULL;
+ }
+
niter = NpyIter_GetNIter(self->iter);
if (ilow < 0) {
ilow = 0;
@@ -1825,8 +1899,8 @@ npyiter_seq_slice(NewNpyArrayIterObject *self,
if (ihigh < ilow) {
ihigh = ilow;
}
- else if (ihigh >= niter) {
- ihigh = niter-1;
+ else if (ihigh > niter) {
+ ihigh = niter;
}
ret = PyTuple_New(ihigh-ilow);
@@ -1859,11 +1933,20 @@ npyiter_seq_ass_item(NewNpyArrayIterObject *self, Py_ssize_t i, PyObject *v)
"can't delete iterator operands");
return -1;
}
+
if (self->iter == NULL || self->finished) {
PyErr_SetString(PyExc_ValueError,
"Iterator is past the end");
return -1;
}
+
+ if (NpyIter_HasDelayedBufAlloc(self->iter)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Iterator construction used delayed buffer allocation, "
+ "and no reset has been done yet");
+ return -1;
+ }
+
niter = NpyIter_GetNIter(self->iter);
if (i < 0 || i >= niter) {
PyErr_Format(PyExc_IndexError,
@@ -1948,6 +2031,9 @@ static PyGetSetDef npyiter_getsets[] = {
{"itviews",
(getter)npyiter_itviews_get,
NULL, NULL, NULL},
+ {"hasdelayedbufalloc",
+ (getter)npyiter_hasdelayedbufalloc_get,
+ NULL, NULL, NULL},
{"hascoords",
(getter)npyiter_hascoords_get,
NULL, NULL, NULL},
diff --git a/numpy/core/tests/test_new_iterator.py b/numpy/core/tests/test_new_iterator.py
index b2b9bcb59..25e96a73d 100644
--- a/numpy/core/tests/test_new_iterator.py
+++ b/numpy/core/tests/test_new_iterator.py
@@ -603,6 +603,14 @@ def test_iter_flags_errors():
assert_raises(ValueError, newiter, [], [], [])
# Too many operands
assert_raises(ValueError, newiter, [a]*100, [], [['readonly']]*100)
+ # Bad global flag
+ assert_raises(ValueError, newiter, [a], ['bad flag'], [['readonly']])
+ # Bad op flag
+ assert_raises(ValueError, newiter, [a], [], [['readonly','bad flag']])
+ # Bad order parameter
+ assert_raises(ValueError, newiter, [a], [], [['readonly']], order='G')
+ # Bad casting parameter
+ assert_raises(ValueError, newiter, [a], [], [['readonly']], casting='noon')
# op_flags must match ops
assert_raises(ValueError, newiter, [a]*3, [], [['readonly']]*2)
# Cannot track both a C and an F index
@@ -1035,6 +1043,12 @@ def test_iter_copy():
i = None
assert_equal([x[()] for x in j], a.ravel(order='F'))
+ a = arange(24, dtype='<i4').reshape(2,3,4)
+ i = newiter(a, ['buffered'], order='F', casting='unsafe',
+ op_dtypes='>f8', buffersize=5)
+ j = i.copy()
+ i = None
+ assert_equal([x[()] for x in j], a.ravel(order='F'))
def test_iter_allocate_output_simple():
# Check that the iterator will properly allocate outputs
@@ -1327,6 +1341,30 @@ def test_iter_write_buffering():
i.iternext()
assert_equal(a.ravel(order='C'), np.arange(24))
+def test_iter_buffering_delayed_alloc():
+ # Test that delaying buffer allocation works
+
+ a = np.arange(6)
+ b = np.arange(1, dtype='f4')
+ i = np.newiter([a,b], ['buffered','delay_bufalloc','coords'],
+ casting='unsafe',
+ op_dtypes='f4')
+ assert_(i.hasdelayedbufalloc)
+ assert_raises(ValueError, lambda i:i.coords, i)
+ assert_raises(ValueError, lambda i:i[0], i)
+ assert_raises(ValueError, lambda i:i[0:2], i)
+ def assign_iter(i):
+ i[0] = 0
+ assert_raises(ValueError, assign_iter, i)
+
+ i.reset()
+ assert_(not i.hasdelayedbufalloc)
+ assert_equal(i.coords, (0,))
+ assert_equal(i[0], 0)
+ i[1] = 1
+ assert_equal(i[0:2], [0,1])
+ assert_equal([[x[0][()],x[1][()]] for x in i], zip(range(6), [1]*6))
+
def test_iter_buffered_cast_simple():
# Test that buffering can handle a simple cast