diff options
-rw-r--r-- | numpy/core/code_generators/multiarray_api_order.txt | 2 | ||||
-rw-r--r-- | numpy/core/include/numpy/arrayobject.h | 57 | ||||
-rw-r--r-- | numpy/core/src/arrayobject.c | 127 | ||||
-rw-r--r-- | numpy/core/src/arraytypes.inc.src | 6 | ||||
-rw-r--r-- | numpy/core/src/multiarraymodule.c | 69 | ||||
-rw-r--r-- | numpy/core/src/ufuncobject.c | 22 |
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" \ |