From b4143056187e079c97df6956e86d900a299b4831 Mon Sep 17 00:00:00 2001 From: Mark Wiebe Date: Thu, 7 Jul 2011 15:16:37 -0500 Subject: ENH: nditer: Add the per-operand masked iteration flags --- doc/neps/missing-data.rst | 4 ++++ numpy/core/include/numpy/ndarraytypes.h | 6 +++++ numpy/core/src/multiarray/nditer_api.c | 2 ++ numpy/core/src/multiarray/nditer_constr.c | 11 +++++++++ numpy/core/src/multiarray/nditer_impl.h | 2 ++ numpy/core/src/multiarray/nditer_pywrap.c | 39 +++++++++++++++++++++++++------ 6 files changed, 57 insertions(+), 7 deletions(-) diff --git a/doc/neps/missing-data.rst b/doc/neps/missing-data.rst index 478d019a5..de00cbb74 100644 --- a/doc/neps/missing-data.rst +++ b/doc/neps/missing-data.rst @@ -738,6 +738,10 @@ NPY_ITER_WRITEMASKED to know the mask ahead of time, and copying everything into the buffer will never destroy data. + The code using the iterator should only write to values which + are not masked by the mask specified, otherwise the result will + be different depending on whether buffering is enabled or not. + NPY_ITER_ARRAYMASK Indicates that this array is a boolean mask to use when copying any WRITEMASKED argument from a buffer back to the array. There diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h index 5e32c9d7c..11ea47c8f 100644 --- a/numpy/core/include/numpy/ndarraytypes.h +++ b/numpy/core/include/numpy/ndarraytypes.h @@ -893,6 +893,12 @@ typedef void (NpyIter_GetMultiIndexFunc)(NpyIter *iter, #define NPY_ITER_NO_SUBTYPE 0x02000000 /* Require that the dimension match the iterator dimensions exactly */ #define NPY_ITER_NO_BROADCAST 0x08000000 +/* A mask is being used on this array, affects buffer -> array copy */ +#define NPY_ITER_WRITEMASKED 0x04000000 +/* This array is the mask for all WRITEMASKED operands */ +#define NPY_ITER_ARRAYMASK 0x10000000 +/* This is a virtual array slot of the mask for all WRITEMASKED operands */ +#define NPY_ITER_VIRTUALMASK 0x20000000 #define NPY_ITER_GLOBAL_FLAGS 0x0000ffff #define NPY_ITER_PER_OP_FLAGS 0xffff0000 diff --git a/numpy/core/src/multiarray/nditer_api.c b/numpy/core/src/multiarray/nditer_api.c index 10f4afd8b..30990fff1 100644 --- a/numpy/core/src/multiarray/nditer_api.c +++ b/numpy/core/src/multiarray/nditer_api.c @@ -1418,6 +1418,8 @@ NpyIter_DebugPrint(NpyIter *iter) printf("ALIGNED "); if ((NIT_OPITFLAGS(iter)[iop])&NPY_OP_ITFLAG_REDUCE) printf("REDUCE "); + if ((NIT_OPITFLAGS(iter)[iop])&NPY_OP_ITFLAG_WRITEMASKED) + printf("WRITEMASKED "); printf("\n"); } printf("|\n"); diff --git a/numpy/core/src/multiarray/nditer_constr.c b/numpy/core/src/multiarray/nditer_constr.c index 774ed65e4..53b46c019 100644 --- a/numpy/core/src/multiarray/nditer_constr.c +++ b/numpy/core/src/multiarray/nditer_constr.c @@ -899,6 +899,17 @@ npyiter_check_per_op_flags(npy_uint32 op_flags, char *op_itflags) return 0; } + /* Check the flag for a write masked operands */ + if (op_flags&NPY_ITER_WRITEMASKED) { + if (!(*op_itflags)&NPY_OP_ITFLAG_WRITE) { + PyErr_SetString(PyExc_ValueError, + "The iterator flag WRITEMASKED may only " + "be used with READWRITE or WRITEONLY"); + return 0; + } + *op_itflags |= NPY_OP_ITFLAG_WRITEMASKED; + } + return 1; } diff --git a/numpy/core/src/multiarray/nditer_impl.h b/numpy/core/src/multiarray/nditer_impl.h index f79ac3415..3494d3937 100644 --- a/numpy/core/src/multiarray/nditer_impl.h +++ b/numpy/core/src/multiarray/nditer_impl.h @@ -116,6 +116,8 @@ #define NPY_OP_ITFLAG_ALIGNED 0x10 /* The operand is being reduced */ #define NPY_OP_ITFLAG_REDUCE 0x20 +/* The operand requires masking when copying buffer -> array */ +#define NPY_OP_ITFLAG_WRITEMASKED 0x40 /* * The data layout of the iterator is fully specified by diff --git a/numpy/core/src/multiarray/nditer_pywrap.c b/numpy/core/src/multiarray/nditer_pywrap.c index 8b2f3a0c0..7f902d6fa 100644 --- a/numpy/core/src/multiarray/nditer_pywrap.c +++ b/numpy/core/src/multiarray/nditer_pywrap.c @@ -370,11 +370,22 @@ NpyIter_OpFlagsConverter(PyObject *op_flags_in, flag = 0; switch (str[0]) { case 'a': - if (strcmp(str, "allocate") == 0) { - flag = NPY_ITER_ALLOCATE; - } - if (strcmp(str, "aligned") == 0) { - flag = NPY_ITER_ALIGNED; + if (length > 2) switch(str[2]) { + case 'i': + if (strcmp(str, "aligned") == 0) { + flag = NPY_ITER_ALIGNED; + } + break; + case 'l': + if (strcmp(str, "allocate") == 0) { + flag = NPY_ITER_ALLOCATE; + } + break; + case 'r': + if (strcmp(str, "arraymask") == 0) { + flag = NPY_ITER_ARRAYMASK; + } + break; } break; case 'c': @@ -421,9 +432,23 @@ NpyIter_OpFlagsConverter(PyObject *op_flags_in, flag = NPY_ITER_UPDATEIFCOPY; } break; + case 'v': + if (strcmp(str, "virtualmask") == 0) { + flag = NPY_ITER_VIRTUALMASK; + } + break; case 'w': - if (strcmp(str, "writeonly") == 0) { - flag = NPY_ITER_WRITEONLY; + if (length > 5) switch (str[5]) { + case 'o': + if (strcmp(str, "writeonly") == 0) { + flag = NPY_ITER_WRITEONLY; + } + break; + case 'm': + if (strcmp(str, "writemasked") == 0) { + flag = NPY_ITER_WRITEMASKED; + } + break; } break; } -- cgit v1.2.1