summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/core/code_generators/multiarray_api_order.txt2
-rw-r--r--numpy/core/include/numpy/arrayobject.h57
-rw-r--r--numpy/core/src/arrayobject.c127
-rw-r--r--numpy/core/src/arraytypes.inc.src6
-rw-r--r--numpy/core/src/multiarraymodule.c69
-rw-r--r--numpy/core/src/ufuncobject.c22
6 files changed, 224 insertions, 59 deletions
diff --git a/numpy/core/code_generators/multiarray_api_order.txt b/numpy/core/code_generators/multiarray_api_order.txt
index 2daf423c6..902bc97dd 100644
--- a/numpy/core/code_generators/multiarray_api_order.txt
+++ b/numpy/core/code_generators/multiarray_api_order.txt
@@ -69,3 +69,5 @@ PyArray_Round
PyArray_EquivTypenums
PyArray_RegisterDataType
PyArray_RegisterCastFunc
+PyArray_RegisterCanCast
+PyArray_InitArrFuncs
diff --git a/numpy/core/include/numpy/arrayobject.h b/numpy/core/include/numpy/arrayobject.h
index 7ef892ad6..0050bb6d4 100644
--- a/numpy/core/include/numpy/arrayobject.h
+++ b/numpy/core/include/numpy/arrayobject.h
@@ -79,7 +79,7 @@ extern "C" CONFUSE_EMACS
#define PY_SUCCEED 1
/* Helpful to distinguish what is installed */
-#define NDARRAY_VERSION 0x00090902
+#define NDARRAY_VERSION 0x00090904
/* Some platforms don't define bool, long long, or long double.
Handle that here.
@@ -229,14 +229,15 @@ typedef enum {
typedef enum {
- PyArray_NOSCALAR=0,
- PyArray_BOOL_SCALAR=1,
- PyArray_INTPOS_SCALAR=2,
- PyArray_INTNEG_SCALAR=3,
- PyArray_FLOAT_SCALAR=4,
- PyArray_COMPLEX_SCALAR=5,
- PyArray_OBJECT_SCALAR=6
+ PyArray_NOSCALAR=-1,
+ PyArray_BOOL_SCALAR,
+ PyArray_INTPOS_SCALAR,
+ PyArray_INTNEG_SCALAR,
+ PyArray_FLOAT_SCALAR,
+ PyArray_COMPLEX_SCALAR,
+ PyArray_OBJECT_SCALAR,
} PyArray_SCALARKIND;
+#define PyArray_NSCALARKINDS PyArray_OBJECT_SCALAR+1
typedef enum {
PyArray_ANYORDER=-1,
@@ -828,6 +829,8 @@ typedef int (PyArray_ArgSortFunc)(void *, intp *, intp, void *);
typedef int (PyArray_FillWithScalarFunc)(void *, intp, void *, void *);
+typedef int (PyArray_ScalarKindFunc)(void *);
+
typedef struct {
intp *ptr;
int len;
@@ -835,8 +838,11 @@ typedef struct {
typedef struct {
/* Functions to cast to all other standard types*/
+ /* Can have some NULL entries */
PyArray_VectorUnaryFunc *cast[PyArray_NTYPES];
+ /* The next four functions *cannot* be NULL */
+
/* Functions to get and set items with standard
Python types -- not array scalars */
PyArray_GetItemFunc *getitem;
@@ -848,41 +854,58 @@ typedef struct {
PyArray_CopySwapFunc *copyswap;
/* Function to compare items */
+ /* Can be NULL
+ */
PyArray_CompareFunc *compare;
- /* Function to select largest */
+ /* Function to select largest
+ Can be NULL
+ */
PyArray_ArgFunc *argmax;
/* Function to compute dot product */
+ /* Can be NULL */
PyArray_DotFunc *dotfunc;
/* Function to scan an ASCII file and
- place a single value plus possible separator */
+ place a single value plus possible separator
+ Can be NULL
+ */
PyArray_ScanFunc *scanfunc;
/* Function to read a single value from a string */
- /* and adjust the pointer */
+ /* and adjust the pointer; Can be NULL */
PyArray_FromStrFunc *fromstr;
/* Function to determine if data is zero or not */
+ /* If NULL a default version is */
+ /* used at Registration time. */
PyArray_NonzeroFunc *nonzero;
- /* Used for arange */
+ /* Used for arange. Can be NULL.*/
PyArray_FillFunc *fill;
- /* Function to fill arrays with scalar values */
+ /* Function to fill arrays with scalar values
+ Can be NULL*/
PyArray_FillWithScalarFunc *fillwithscalar;
- /* Sorting functions */
+ /* Sorting functions; Can be NULL*/
PyArray_SortFunc *sort[PyArray_NSORTS];
PyArray_ArgSortFunc *argsort[PyArray_NSORTS];
/* Dictionary of additional casting functions
PyArray_VectorUnaryFuncs
which can be populated to support casting
- to other registered types */
+ to other registered types. Can be NULL*/
PyObject *castdict;
+ /* Functions useful for generalizing
+ the casting rules. Can be NULL;
+ */
+ PyArray_ScalarKindFunc *scalarkind;
+ int **cancastscalarkindto;
+ int *cancastto;
+
} PyArray_ArrFuncs;
@@ -894,8 +917,8 @@ typedef struct {
char type; /* unique-character representing this type */
char byteorder; /* '>' (big), '<' (little), '|'
(not-applicable), or '=' (native). */
- char hasobject; /* non-zero if it has object arrays in fields */
- int type_num; /* number representing this type */
+ char hasobject; /* non-zero if it has object arrays in fields */
+ int type_num; /* number representing this type */
int elsize; /* element size for this type */
int alignment; /* alignment needed for this type */
struct _arr_descr \
diff --git a/numpy/core/src/arrayobject.c b/numpy/core/src/arrayobject.c
index 2f76637ea..51f50a08b 100644
--- a/numpy/core/src/arrayobject.c
+++ b/numpy/core/src/arrayobject.c
@@ -1166,6 +1166,51 @@ PyArray_Return(PyArrayObject *mp)
}
}
+
+/*MULTIARRAY_API
+ Initialize arrfuncs to NULL
+*/
+static void
+PyArray_InitArrFuncs(PyArray_ArrFuncs *f)
+{
+ int i;
+ for (i=0; i<PyArray_NTYPES; i++) {
+ f->cast[i] = NULL;
+ }
+ f->getitem = NULL;
+ f->setitem = NULL;
+ f->copyswapn = NULL;
+ f->copyswap = NULL;
+ f->compare = NULL;
+ f->argmax = NULL;
+ f->dotfunc = NULL;
+ f->scanfunc = NULL;
+ f->fromstr = NULL;
+ f->nonzero = NULL;
+ f->fill = NULL;
+ f->fillwithscalar = NULL;
+ for (i=0; i<PyArray_NSORTS; i++) {
+ f->sort[i] = NULL;
+ f->argsort[i] = NULL;
+ }
+ f->castdict = NULL;
+ f->scalarkind = NULL;
+ f->cancastscalarkindto = NULL;
+ f->cancastto = NULL;
+}
+
+static Bool
+_default_nonzero(void *ip, void *arr)
+{
+ int elsize = PyArray_ITEMSIZE(arr);
+ char *ptr = ip;
+ while (elsize--) {
+ if (*ptr++ != 0) return TRUE;
+ }
+ return FALSE;
+}
+
+
/*
returns typenum to associate with this type >=PyArray_USERDEF.
Also creates a copy of the VOID_DESCR table inserting it's typeobject in
@@ -1200,9 +1245,11 @@ PyArray_RegisterDataType(PyArray_Descr *descr)
return -1;
}
f = descr->f;
- if (f->nonzero == NULL || f->copyswap == NULL ||
- f->copyswapn == NULL || f->setitem == NULL ||
- f->getitem == NULL || f->cast == NULL) {
+ if (f->nonzero == NULL) {
+ f->nonzero = _default_nonzero;
+ }
+ if (f->copyswap == NULL || f->getitem == NULL ||
+ f->copyswapn == NULL || f->setitem == NULL) {
PyErr_SetString(PyExc_ValueError, "a required array function" \
" is missing.");
return -1;
@@ -1253,6 +1300,62 @@ PyArray_RegisterCastFunc(PyArray_Descr *descr, int totype,
return ret;
}
+static int *
+_append_new(int *types, int insert)
+{
+ int n=0;
+ int *newtypes;
+
+ while (types[n] != PyArray_NOTYPE) n++;
+ newtypes = (int *)realloc(types, (n+2)*sizeof(int));
+ newtypes[n] = insert;
+ newtypes[n+1] = PyArray_NOTYPE;
+ return newtypes;
+}
+
+/*MULTIARRAY_API
+ Register a type number indicating that a descriptor can be cast
+ to it safely
+*/
+static int
+PyArray_RegisterCanCast(PyArray_Descr *descr, int totype,
+ PyArray_SCALARKIND scalar)
+{
+ if (scalar == PyArray_NOSCALAR) {
+ /* register with cancastto */
+ /* These lists won't be freed once created
+ -- they become part of the data-type */
+ if (descr->f->cancastto == NULL) {
+ descr->f->cancastto = (int *)malloc(1*sizeof(int));
+ descr->f->cancastto[0] = PyArray_NOTYPE;
+ }
+ descr->f->cancastto = _append_new(descr->f->cancastto,
+ totype);
+ }
+ else {
+ /* register with cancastscalarkindto */
+ if (descr->f->cancastscalarkindto == NULL) {
+ int i;
+ descr->f->cancastscalarkindto = \
+ (int **)malloc(PyArray_NSCALARKINDS* \
+ sizeof(int*));
+ for (i=0; i<PyArray_NSCALARKINDS; i++) {
+ descr->f->cancastscalarkindto[i] = NULL;
+ }
+ }
+ if (descr->f->cancastscalarkindto[scalar] == NULL) {
+ descr->f->cancastscalarkindto[scalar] = \
+ (int *)malloc(1*sizeof(int));
+ descr->f->cancastscalarkindto[scalar][0] = \
+ PyArray_NOTYPE;
+ }
+ descr->f->cancastscalarkindto[scalar] = \
+ _append_new(descr->f->cancastscalarkindto[scalar],
+ totype);
+ }
+ return 0;
+}
+
/*OBJECT_API
To File
*/
@@ -7122,6 +7225,18 @@ PyArray_CanCastSafely(int fromtype, int totype)
if (fromtype == PyArray_OBJECT || fromtype == PyArray_VOID) return 0;
from = PyArray_DescrFromType(fromtype);
+ /* cancastto is a PyArray_NOTYPE terminated C-int-array of types that
+ the data-type can be cast to safely.
+ */
+ if (from->f->cancastto) {
+ int *curtype;
+ curtype = from->f->cancastto;
+ while (*curtype != PyArray_NOTYPE) {
+ if (*curtype++ == totype) return 1;
+ }
+ }
+ if (PyTypeNum_ISUSERDEF(totype)) return 0;
+
to = PyArray_DescrFromType(totype);
telsize = to->elsize;
felsize = from->elsize;
@@ -7230,12 +7345,6 @@ PyArray_CanCastTo(PyArray_Descr *from, PyArray_Descr *to)
stringified value of the object.
*/
}
- if (!ret && (PyTypeNum_ISUSERDEF(fromtype) || \
- PyTypeNum_ISUSERDEF(totype))) {
- /* don't restrict casting to and from
- additional data-types */
- return TRUE;
- }
return ret;
}
diff --git a/numpy/core/src/arraytypes.inc.src b/numpy/core/src/arraytypes.inc.src
index e65a1ff85..bfcf104be 100644
--- a/numpy/core/src/arraytypes.inc.src
+++ b/numpy/core/src/arraytypes.inc.src
@@ -1855,6 +1855,9 @@ static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = {
{
NULL, NULL, NULL, NULL
},
+ NULL,
+ (PyArray_ScalarKindFunc*)NULL,
+ NULL,
NULL
};
@@ -1927,6 +1930,9 @@ static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = {
{
NULL, NULL, NULL, NULL
},
+ NULL,
+ (PyArray_ScalarKindFunc*)NULL,
+ NULL,
NULL
};
diff --git a/numpy/core/src/multiarraymodule.c b/numpy/core/src/multiarraymodule.c
index 1c10f0c33..147c1e880 100644
--- a/numpy/core/src/multiarraymodule.c
+++ b/numpy/core/src/multiarraymodule.c
@@ -1628,33 +1628,57 @@ PyArray_ScalarKind(int typenum, PyArrayObject **arr)
if (PyTypeNum_ISCOMPLEX(typenum)) return PyArray_COMPLEX_SCALAR;
if (PyTypeNum_ISBOOL(typenum)) return PyArray_BOOL_SCALAR;
+ if (PyTypeNum_ISUSERDEF(typenum)) {
+ PyArray_SCALARKIND retval;
+ PyArray_Descr* descr;
+ descr = PyArray_DescrFromType(typenum);
+ if (descr->f->scalarkind)
+ retval = descr->f->scalarkind((arr ? *arr : NULL));
+ else
+ retval = PyArray_NOSCALAR;
+ Py_DECREF(descr);
+ return retval;
+ }
return PyArray_OBJECT_SCALAR;
}
/*OBJECT_API*/
static int
-PyArray_CanCoerceScalar(char thistype, char neededtype,
+PyArray_CanCoerceScalar(int thistype, int neededtype,
PyArray_SCALARKIND scalar)
-{
+{
+ PyArray_Descr* from;
+ int *castlist;
+ if (scalar == PyArray_NOSCALAR) {
+ return PyArray_CanCastSafely(thistype, neededtype);
+ }
+ from = PyArray_DescrFromType(thistype);
+ if (from->f->cancastscalarkindto &&
+ (castlist = from->f->cancastscalarkindto[scalar])) {
+ while (*castlist != PyArray_NOTYPE)
+ if (*castlist++ == neededtype) return 1;
+ }
switch(scalar) {
- case PyArray_NOSCALAR:
case PyArray_BOOL_SCALAR:
case PyArray_OBJECT_SCALAR:
return PyArray_CanCastSafely(thistype, neededtype);
- case PyArray_INTPOS_SCALAR:
- return (neededtype >= PyArray_BYTE);
- case PyArray_INTNEG_SCALAR:
- return (neededtype >= PyArray_BYTE) && \
- !(PyTypeNum_ISUNSIGNED(neededtype));
- case PyArray_FLOAT_SCALAR:
- return (neededtype >= PyArray_FLOAT);
- case PyArray_COMPLEX_SCALAR:
- return (neededtype >= PyArray_CFLOAT);
- }
- fprintf(stderr, "\n**Error** coerce fall through: %d %d %d\n\n",
- thistype, neededtype, scalar);
- return 1; /* should never get here... */
+ default:
+ if (PyTypeNum_ISUSERDEF(neededtype)) return FALSE;
+ switch(scalar) {
+ case PyArray_INTPOS_SCALAR:
+ return (neededtype >= PyArray_BYTE);
+ case PyArray_INTNEG_SCALAR:
+ return (neededtype >= PyArray_BYTE) && \
+ !(PyTypeNum_ISUNSIGNED(neededtype));
+ case PyArray_FLOAT_SCALAR:
+ return (neededtype >= PyArray_FLOAT);
+ case PyArray_COMPLEX_SCALAR:
+ return (neededtype >= PyArray_CFLOAT);
+ default:
+ return 1; /* should never get here... */
+ }
+ }
}
@@ -1668,8 +1692,7 @@ PyArray_ConvertToCommonType(PyObject *op, int *retn)
PyObject *otmp;
PyArray_Descr *intype=NULL, *stype=NULL;
PyArray_Descr *newtype=NULL;
- char scalarkind;
-
+ PyArray_SCALARKIND scalarkind;
*retn = n = PySequence_Length(op);
if (PyErr_Occurred()) {*retn = 0; return NULL;}
@@ -1692,10 +1715,12 @@ PyArray_ConvertToCommonType(PyObject *op, int *retn)
newtype = PyArray_DescrFromObject(otmp, stype);
Py_XDECREF(stype);
stype = newtype;
- scalarkind = PyArray_ScalarKind(newtype->type_num, NULL);
- if (intype && !PyArray_CanCoerceScalar(newtype->type_num,
- intype->type_num,
- scalarkind)) {
+ scalarkind = PyArray_ScalarKind(newtype->type_num,
+ NULL);
+ if (intype && \
+ !PyArray_CanCoerceScalar(newtype->type_num,
+ intype->type_num,
+ scalarkind)) {
Py_XDECREF(intype);
intype = stype;
}
diff --git a/numpy/core/src/ufuncobject.c b/numpy/core/src/ufuncobject.c
index a2fb34233..2cdb435b6 100644
--- a/numpy/core/src/ufuncobject.c
+++ b/numpy/core/src/ufuncobject.c
@@ -629,24 +629,24 @@ select_types(PyUFuncObject *self, int *arg_types,
char start_type;
int userdef=-1;
- for (i=0; i<self->nin; i++) {
- if (PyTypeNum_ISUSERDEF(arg_types[i])) {
- userdef = arg_types[i];
- break;
+ if (self->userloops) {
+ for (i=0; i<self->nin; i++) {
+ if (PyTypeNum_ISUSERDEF(arg_types[i])) {
+ userdef = arg_types[i];
+ break;
+ }
}
}
-
+
if (userdef > 0) {
PyObject *key, *obj;
int *this_types=NULL;
obj = NULL;
- if (self->userloops) {
- key = PyInt_FromLong((long) userdef);
- if (key == NULL) return -1;
- obj = PyDict_GetItem(self->userloops, key);
- Py_DECREF(key);
- }
+ key = PyInt_FromLong((long) userdef);
+ if (key == NULL) return -1;
+ obj = PyDict_GetItem(self->userloops, key);
+ Py_DECREF(key);
if (obj == NULL) {
PyErr_SetString(PyExc_TypeError,
"user-defined type used in ufunc" \