summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorMark Wiebe <mwiebe@enthought.com>2011-07-19 17:06:08 -0500
committerCharles Harris <charlesr.harris@gmail.com>2011-08-27 07:26:45 -0600
commit263df0ccb21e7ccb53ea3b6654387eb85feec932 (patch)
treead6983581476cf2f71de1b6c2fc729dcde778cad /numpy
parentaa55ba7437fbe6b8772a360a641b5aa7d3e669e0 (diff)
downloadnumpy-263df0ccb21e7ccb53ea3b6654387eb85feec932.tar.gz
ENH: missingdata: Add the NA mask members to PyArrayObject
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/SConscript1
-rw-r--r--numpy/core/code_generators/genapi.py1
-rw-r--r--numpy/core/code_generators/numpy_api.py4
-rw-r--r--numpy/core/include/numpy/ndarraytypes.h226
-rw-r--r--numpy/core/include/numpy/npy_deprecated_api.h6
-rw-r--r--numpy/core/setup.py1
-rw-r--r--numpy/core/src/multiarray/dtype_transfer.c8
-rw-r--r--numpy/core/src/multiarray/getset.c2
-rw-r--r--numpy/core/src/multiarray/na_mask.c49
-rw-r--r--numpy/core/src/umath/ufunc_type_resolution.c4
10 files changed, 212 insertions, 90 deletions
diff --git a/numpy/core/SConscript b/numpy/core/SConscript
index 5bf62ea11..80a7d08de 100644
--- a/numpy/core/SConscript
+++ b/numpy/core/SConscript
@@ -452,6 +452,7 @@ if ENABLE_SEPARATE_COMPILATION:
pjoin('src', 'multiarray', 'descriptor.c'),
pjoin('src', 'multiarray', 'iterators.c'),
pjoin('src', 'multiarray', 'mapping.c'),
+ pjoin('src', 'multiarray', 'na_mask.c'),
pjoin('src', 'multiarray', 'number.c'),
pjoin('src', 'multiarray', 'getset.c'),
pjoin('src', 'multiarray', 'sequence.c'),
diff --git a/numpy/core/code_generators/genapi.py b/numpy/core/code_generators/genapi.py
index 29cbb271f..b083f6e77 100644
--- a/numpy/core/code_generators/genapi.py
+++ b/numpy/core/code_generators/genapi.py
@@ -52,6 +52,7 @@ API_FILES = [join('multiarray', 'methods.c'),
join('multiarray', 'nditer_pywrap.c'),
join('multiarray', 'nditer_templ.c.src'),
join('multiarray', 'einsum.c.src'),
+ join('multiarray', 'na_mask.c'),
join('umath', 'ufunc_object.c'),
join('umath', 'ufunc_type_resolution.c'),
join('umath', 'loops.c.src'),
diff --git a/numpy/core/code_generators/numpy_api.py b/numpy/core/code_generators/numpy_api.py
index a256d849a..682c8eb3d 100644
--- a/numpy/core/code_generators/numpy_api.py
+++ b/numpy/core/code_generators/numpy_api.py
@@ -318,7 +318,9 @@ multiarray_funcs_api = {
# End 1.6 API
'PyArray_MaskedCopyInto': 281,
'PyArray_MaskedMoveInto': 282,
- 'PyArray_SetBaseObject': 283,
+ 'PyArray_SetBaseObject': 283,
+ 'PyArray_HasNASupport': 284,
+ 'PyArray_ContainsNA': 285,
}
ufunc_types_api = {
diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h
index 94c45df88..85cc8a379 100644
--- a/numpy/core/include/numpy/ndarraytypes.h
+++ b/numpy/core/include/numpy/ndarraytypes.h
@@ -287,6 +287,40 @@ typedef enum {
NPY_BUSDAY_RAISE
} NPY_BUSDAY_ROLL;
+/*********************************************************************
+ * NumPy functions for dealing with masks, such as in masked iteration
+ *********************************************************************/
+
+typedef npy_uint8 npy_mask;
+#define NPY_MASK NPY_UINT8
+
+/*
+ * Bit 0 of the mask indicates whether a value is exposed
+ * or hidden. This is compatible with a 'where=' boolean
+ * mask, because NumPy booleans are 1 byte, and contain
+ * either the value 0 or 1.
+ */
+static NPY_INLINE npy_bool
+NpyMaskValue_IsExposed(npy_mask mask)
+{
+ return (mask & 0x01) != 0;
+}
+
+/*
+ * Bits 1 through 7 of the mask contain the payload.
+ */
+static NPY_INLINE npy_uint8
+NpyMaskValue_GetPayload(npy_mask mask)
+{
+ return ((npy_uint8)mask) >> 1;
+}
+
+static NPY_INLINE npy_mask
+NpyMaskValue_Create(npy_bool exposed, npy_uint8 payload)
+{
+ return (npy_mask)(exposed != 0) | (npy_mask)(payload << 1);
+}
+
#define NPY_ERR(str) fprintf(stderr, #str); fflush(stderr);
#define NPY_ERR2(str) fprintf(stderr, str); fflush(stderr);
@@ -583,32 +617,64 @@ typedef struct _arr_descr {
*/
/* This struct will be moved to a private header in a future release */
typedef struct tagPyArrayObject_fieldaccess {
- PyObject_HEAD
- char *data; /* pointer to raw data buffer */
- int nd; /* number of dimensions, also called ndim */
- npy_intp *dimensions; /* size in each dimension */
- npy_intp *strides; /*
- * bytes to jump to get to the
- * next element in each dimension
- */
- PyObject *base; /*
- * This object should be decref'd upon
- * deletion of array
- *
- * For views it points to the original
- * array
- *
- * For creation from buffer object it
- * points to an object that shold be
- * decref'd on deletion
- *
- * For UPDATEIFCOPY flag this is an
- * array to-be-updated upon deletion
- * of this one
- */
- PyArray_Descr *descr; /* Pointer to type structure */
- int flags; /* Flags describing array -- see below */
- PyObject *weakreflist; /* For weakreferences */
+ PyObject_HEAD
+ /* Pointer to the raw data buffer */
+ char *data;
+ /* The number of dimensions, also called 'ndim' */
+ int nd;
+ /* The size in each dimension, also called 'shape' */
+ npy_intp *dimensions;
+ /*
+ * Number of bytes to jump to get to the
+ * next element in each dimension
+ */
+ npy_intp *strides;
+ /*
+ * This object is decref'd upon
+ * deletion of array. Except in the
+ * case of UPDATEIFCOPY which has
+ * special handling.
+ *
+ * For views it points to the original
+ * array, collapsed so no chains of
+ * views occur.
+ *
+ * For creation from buffer object it
+ * points to an object that shold be
+ * decref'd on deletion
+ *
+ * For UPDATEIFCOPY flag this is an
+ * array to-be-updated upon deletion
+ * of this one
+ */
+ PyObject *base;
+ /* Pointer to type structure */
+ PyArray_Descr *descr;
+ /* Flags describing array -- see below */
+ int flags;
+ /* For weak references */
+ PyObject *weakreflist;
+
+ /* New fields added as of NumPy 1.7 */
+
+ /*
+ * Descriptor for the mask dtype.
+ * If no mask: NULL
+ * If mask : bool/uint8/structured dtype of mask dtypes
+ */
+ PyArray_Descr *maskna_descr;
+ /*
+ * Raw data buffer for mask. If the array has the flag
+ * NPY_ARRAY_OWNMASKNA enabled, it owns this memory and
+ * must call PyArray_free on it when destroyed.
+ */
+ npy_mask *maskna_data;
+ /*
+ * Just like dimensions and strides point into the same memory
+ * buffer, we now just make that buffer 3x the nd instead of 2x
+ * and use the same buffer.
+ */
+ npy_intp *maskna_strides;
} PyArrayObject_fieldaccess;
/*
@@ -688,7 +754,7 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
* the fastest in memory (strides array is reverse of C-contiguous
* array)
*/
-#define NPY_ARRAY_F_CONTIGUOUS 0x0002
+#define NPY_ARRAY_F_CONTIGUOUS 0x0002
/*
* Note: all 0-d arrays are C_CONTIGUOUS and F_CONTIGUOUS. If a
@@ -699,7 +765,7 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
* If set, the array owns the data: it will be free'd when the array
* is deleted.
*/
-#define NPY_ARRAY_OWNDATA 0x0004
+#define NPY_ARRAY_OWNDATA 0x0004
/*
* An array never has the next four set; they're only used as parameter
@@ -707,22 +773,22 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
*/
/* Cause a cast to occur regardless of whether or not it is safe. */
-#define NPY_ARRAY_FORCECAST 0x0010
+#define NPY_ARRAY_FORCECAST 0x0010
/*
* Always copy the array. Returned arrays are always CONTIGUOUS,
* ALIGNED, and WRITEABLE.
*/
-#define NPY_ARRAY_ENSURECOPY 0x0020
+#define NPY_ARRAY_ENSURECOPY 0x0020
/* Make sure the returned array is a base-class ndarray */
-#define NPY_ARRAY_ENSUREARRAY 0x0040
+#define NPY_ARRAY_ENSUREARRAY 0x0040
/*
* Make sure that the strides are in units of the element size Needed
* for some operations with record-arrays.
*/
-#define NPY_ARRAY_ELEMENTSTRIDES 0x0080
+#define NPY_ARRAY_ELEMENTSTRIDES 0x0080
/*
* Array data is aligned on the appropiate memory address for the type
@@ -730,20 +796,27 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
* array of integers (4 bytes each) starts on a memory address that's
* a multiple of 4)
*/
-#define NPY_ARRAY_ALIGNED 0x0100
+#define NPY_ARRAY_ALIGNED 0x0100
/* Array data has the native endianness */
-#define NPY_ARRAY_NOTSWAPPED 0x0200
+#define NPY_ARRAY_NOTSWAPPED 0x0200
/* Array data is writeable */
-#define NPY_ARRAY_WRITEABLE 0x0400
+#define NPY_ARRAY_WRITEABLE 0x0400
/*
* If this flag is set, then base contains a pointer to an array of
* the same size that should be updated with the current contents of
* this array when this array is deallocated
*/
-#define NPY_ARRAY_UPDATEIFCOPY 0x1000
+#define NPY_ARRAY_UPDATEIFCOPY 0x1000
+
+/*
+ * If this flag is set, then the array owns the memory for the
+ * missing values NA mask.
+ */
+#define NPY_ARRAY_OWNMASKNA 0x2000
+
#define NPY_ARRAY_BEHAVED (NPY_ARRAY_ALIGNED | \
NPY_ARRAY_WRITEABLE)
@@ -772,7 +845,7 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
NPY_ARRAY_F_CONTIGUOUS | \
NPY_ARRAY_ALIGNED)
-/* This flag is for the array interface */
+/* This flag is for the array interface, not PyArrayObject */
#define NPY_ARR_HAS_DESCR 0x0800
@@ -845,9 +918,9 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
#define NPY_DISABLE_C_API
#endif
-/*****************************
- * New iterator object
- *****************************/
+/**********************************
+ * The nditer object, added in 1.6
+ **********************************/
/* The actual structure of the iterator is an internal detail */
typedef struct NpyIter_InternalOnly NpyIter;
@@ -1278,8 +1351,6 @@ PyArrayNeighborhoodIter_Next2D(PyArrayNeighborhoodIterObject* iter);
#define PyArray_FORTRAN_IF(m) ((PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS) ? \
NPY_ARRAY_F_CONTIGUOUS : 0))
-#define FORTRAN_IF PyArray_FORTRAN_IF
-
#ifdef NPY_NO_DEPRECATED_API
/*
* Changing access macros into functions, to allow for future hiding
@@ -1364,17 +1435,14 @@ static NPY_INLINE PyObject *
PyArray_GETITEM(PyArrayObject *arr, char *itemptr)
{
return ((PyArrayObject_fieldaccess *)arr)->descr->f->getitem(
- itemptr,
- arr);
+ itemptr, arr);
}
static NPY_INLINE int
PyArray_SETITEM(PyArrayObject *arr, char *itemptr, PyObject *v)
{
return ((PyArrayObject_fieldaccess *)arr)->descr->f->setitem(
- v,
- itemptr,
- arr);
+ v, itemptr, arr);
}
/* Same as PyArray_DATA */
@@ -1382,7 +1450,7 @@ PyArray_SETITEM(PyArrayObject *arr, char *itemptr, PyObject *v)
#else
-/* Macros are deprecated as of NumPy 1.7. */
+/* These macros are deprecated as of NumPy 1.7. */
#define PyArray_NDIM(obj) (((PyArrayObject_fieldaccess *)(obj))->nd)
#define PyArray_BYTES(obj) ((char *)(((PyArrayObject_fieldaccess *)(obj))->data))
#define PyArray_DATA(obj) ((void *)(((PyArrayObject_fieldaccess *)(obj))->data))
@@ -1429,6 +1497,34 @@ PyArray_CLEARFLAGS(PyArrayObject *arr, int flags)
((PyArrayObject_fieldaccess *)arr)->flags &= ~flags;
}
+/* Access to the missing values NA mask, added in 1.7 */
+
+static NPY_INLINE PyArray_Descr *
+PyArray_MASKNA_DESCR(PyArrayObject *arr)
+{
+ return ((PyArrayObject_fieldaccess *)arr)->maskna_descr;
+}
+
+static NPY_INLINE npy_mask *
+PyArray_MASKNA_DATA(PyArrayObject *arr)
+{
+ return ((PyArrayObject_fieldaccess *)arr)->maskna_data;
+}
+
+/* For the corresponding DIMS, use PyArray_DIMS(arr) */
+static NPY_INLINE npy_intp *
+PyArray_MASKNA_STRIDES(PyArrayObject *arr)
+{
+ return ((PyArrayObject_fieldaccess *)arr)->maskna_strides;
+}
+
+static NPY_INLINE npy_bool
+PyArray_HASMASKNA(PyArrayObject *arr)
+{
+ return ((PyArrayObject_fieldaccess *)arr)->maskna_data != NULL;
+}
+
+
#define PyTypeNum_ISBOOL(type) ((type) == NPY_BOOL)
#define PyTypeNum_ISUNSIGNED(type) (((type) == NPY_UBYTE) || \
@@ -1592,40 +1688,6 @@ struct NpyAuxData_tag {
#define NPY_AUXDATA_CLONE(auxdata) \
((auxdata)->clone(auxdata))
-/*********************************************************************
- * NumPy functions for dealing with masks, such as in masked iteration
- *********************************************************************/
-
-typedef npy_uint8 npy_mask;
-#define NPY_MASK NPY_UINT8
-
-/*
- * Bit 0 of the mask indicates whether a value is exposed
- * or hidden. This is compatible with a 'where=' boolean
- * mask, because NumPy booleans are 1 byte, and contain
- * either the value 0 or 1.
- */
-static NPY_INLINE npy_bool
-NpyMask_IsExposed(npy_mask mask)
-{
- return (mask & 0x01) != 0;
-}
-
-/*
- * Bits 1 through 7 of the mask contain the payload.
- */
-static NPY_INLINE npy_uint8
-NpyMask_GetPayload(npy_mask mask)
-{
- return ((npy_uint8)mask) >> 1;
-}
-
-static NPY_INLINE npy_mask
-NpyMask_Create(npy_bool exposed, npy_uint8 payload)
-{
- return (npy_mask)(exposed != 0) | (npy_mask)(payload << 1);
-}
-
/*
* This is the form of the struct that's returned pointed by the
* PyCObject attribute of an array __array_struct__. See
diff --git a/numpy/core/include/numpy/npy_deprecated_api.h b/numpy/core/include/numpy/npy_deprecated_api.h
index 413d24d4e..a268f504a 100644
--- a/numpy/core/include/numpy/npy_deprecated_api.h
+++ b/numpy/core/include/numpy/npy_deprecated_api.h
@@ -89,4 +89,10 @@
*/
#define fortran fortran_
+/*
+ * Deprecated as of NumPy 1.7, as it is a namespace-polluting
+ * macro.
+ */
+#define FORTRAN_IF PyArray_FORTRAN_IF
+
#endif
diff --git a/numpy/core/setup.py b/numpy/core/setup.py
index 6b5b0df3b..e2cdf35e1 100644
--- a/numpy/core/setup.py
+++ b/numpy/core/setup.py
@@ -773,6 +773,7 @@ def configuration(parent_package='',top_path=None):
join('src', 'multiarray', 'mapping.c'),
join('src', 'multiarray', 'methods.c'),
join('src', 'multiarray', 'multiarraymodule.c'),
+ join('src', 'multiarray', 'na_mask.c'),
join('src', 'multiarray', 'nditer_templ.c.src'),
join('src', 'multiarray', 'nditer_api.c'),
join('src', 'multiarray', 'nditer_constr.c'),
diff --git a/numpy/core/src/multiarray/dtype_transfer.c b/numpy/core/src/multiarray/dtype_transfer.c
index ce688efd5..045e6c4b5 100644
--- a/numpy/core/src/multiarray/dtype_transfer.c
+++ b/numpy/core/src/multiarray/dtype_transfer.c
@@ -3077,7 +3077,7 @@ void _strided_masked_wrapper_decsrcref_transfer_function(
while (N > 0) {
/* Skip masked values, still calling decsrcref for move_references */
subloopsize = 0;
- while (subloopsize < N && !NpyMask_IsExposed(*mask)) {
+ while (subloopsize < N && !NpyMaskValue_IsExposed(*mask)) {
++subloopsize;
mask += mask_stride;
}
@@ -3088,7 +3088,7 @@ void _strided_masked_wrapper_decsrcref_transfer_function(
N -= subloopsize;
/* Process unmasked values */
subloopsize = 0;
- while (subloopsize < N && NpyMask_IsExposed(*mask)) {
+ while (subloopsize < N && NpyMaskValue_IsExposed(*mask)) {
++subloopsize;
mask += mask_stride;
}
@@ -3120,7 +3120,7 @@ void _strided_masked_wrapper_transfer_function(
while (N > 0) {
/* Skip masked values */
subloopsize = 0;
- while (subloopsize < N && !NpyMask_IsExposed(*mask)) {
+ while (subloopsize < N && !NpyMaskValue_IsExposed(*mask)) {
++subloopsize;
mask += mask_stride;
}
@@ -3129,7 +3129,7 @@ void _strided_masked_wrapper_transfer_function(
N -= subloopsize;
/* Process unmasked values */
subloopsize = 0;
- while (subloopsize < N && NpyMask_IsExposed(*mask)) {
+ while (subloopsize < N && NpyMaskValue_IsExposed(*mask)) {
++subloopsize;
mask += mask_stride;
}
diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c
index e9e052683..6503d8f12 100644
--- a/numpy/core/src/multiarray/getset.c
+++ b/numpy/core/src/multiarray/getset.c
@@ -775,7 +775,7 @@ array_flat_set(PyArrayObject *self, PyObject *val)
typecode = PyArray_DESCR(self);
Py_INCREF(typecode);
arr = (PyArrayObject *)PyArray_FromAny(val, typecode,
- 0, 0, NPY_ARRAY_FORCECAST | FORTRAN_IF(self), NULL);
+ 0, 0, NPY_ARRAY_FORCECAST | PyArray_FORTRAN_IF(self), NULL);
if (arr == NULL) {
return -1;
}
diff --git a/numpy/core/src/multiarray/na_mask.c b/numpy/core/src/multiarray/na_mask.c
new file mode 100644
index 000000000..ce8dd1e4b
--- /dev/null
+++ b/numpy/core/src/multiarray/na_mask.c
@@ -0,0 +1,49 @@
+/*
+ * This file implements missing value NA mask support for the NumPy array.
+ *
+ * Written by Mark Wiebe (mwwiebe@gmail.com)
+ * Copyright (c) 2011 by Enthought, Inc.
+ *
+ * See LICENSE.txt for the license.
+ */
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+
+#define NPY_NO_DEPRECATED_API
+#define _MULTIARRAYMODULE
+#include <numpy/arrayobject.h>
+
+#include "npy_config.h"
+#include "numpy/npy_3kcompat.h"
+
+/*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
+ *
+ * Returns false if the array has no NA support. Returns
+ * true if the array has NA support AND there is an
+ * NA anywhere in the array.
+ */
+NPY_NO_EXPORT npy_bool
+PyArray_ContainsNA(PyArrayObject *arr)
+{
+ /* Need NA support to contain NA */
+ if (!PyArray_HasNASupport(arr)) {
+ return 0;
+ }
+
+ /* TODO: Loop through NA mask */
+
+ return 0;
+}
diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c
index fb7352070..df3bb19bd 100644
--- a/numpy/core/src/umath/ufunc_type_resolution.c
+++ b/numpy/core/src/umath/ufunc_type_resolution.c
@@ -1408,7 +1408,7 @@ unmasked_ufunc_loop_as_masked(
/* Skip masked values */
subloopsize = 0;
while (subloopsize < loopsize &&
- !NpyMask_IsExposed(*(npy_mask *)mask)) {
+ !NpyMaskValue_IsExposed(*(npy_mask *)mask)) {
++subloopsize;
mask += mask_stride;
}
@@ -1422,7 +1422,7 @@ unmasked_ufunc_loop_as_masked(
*/
subloopsize = 0;
while (subloopsize < loopsize &&
- NpyMask_IsExposed(*(npy_mask *)mask)) {
+ NpyMaskValue_IsExposed(*(npy_mask *)mask)) {
++subloopsize;
mask += mask_stride;
}