/* W W AAA RRRR N N III N N GGG !!! ** W W A A R R NN N I NN N G G !!! ** W W W AAAAA RRRR N N N I N N N G ! ** W W W A A R R N NN I N NN G GG ** W W A A R R N N III N N GGG !!! ** ** WARNING: This file is program generated by genapi.py. ** ** DO NOT EDIT THIS FILE! Any changes made to this file will be lost! */ #include #define _libnumarray_MODULE #include "Python.h" #include "pystate.h" #include "libnumarray.h" #include "tc.h" #include #include static PyObject *pNDArrayModule; static PyObject *pNDArrayMDict; static PyObject *pNDArrayClass; static PyObject *pNumArrayModule; static PyObject *pNumArrayMDict; static PyObject *pNumArrayClass; static PyObject *pNumArrayNewFunc; static PyObject *pNumArrayArrayFunc; static PyObject *pNumericTypesModule; static PyObject *pNumericTypesMDict; static PyObject *pNumericTypeClass; static PyObject *pNumericTypesTDict; static PyObject *pUfuncModule; static PyObject *pUfuncMDict; static PyObject *pUfuncClass; static PyObject *pCfuncClass; static PyObject *pConverterModule; static PyObject *pConverterMDict; static PyObject *pConverterClass; static PyObject *pOperatorModule; static PyObject *pOperatorMDict; static PyObject *pOperatorClass; static PyObject *pNewMemoryFunc; static PyObject *pHandleErrorFunc; static PyObject *pNumType[nNumarrayType]; static PyTypeObject CfuncType; static PyObject *pEmptyDict; static PyObject *pEmptyTuple; static PyObject *dealloc_list; /* list of global references to DECREF at unload time, i.e. when the module dict is destructed. */ enum { BOOL_SCALAR, INT_SCALAR, LONG_SCALAR, FLOAT_SCALAR, COMPLEX_SCALAR }; static int initialized = 0; /* custom init function generally unuseable due to circular references */ static int libnumarray_init(void) { PyObject *m, *d; initialized = 0; if (!(dealloc_list = PyList_New(0))) return -1; if (!(m = PyImport_ImportModule("numarray.libnumarray"))) return -1; d = PyModule_GetDict(m); if (PyDict_SetItemString(d, "_dealloc_list", dealloc_list) < 0) return -1; Py_DECREF(dealloc_list); Py_DECREF(m); return 0; } static PyObject * init_module(char *modulename, PyObject **pMDict) { PyObject *pModule = PyImport_ImportModule(modulename); if (!pModule) return NULL; PyList_Append(dealloc_list, pModule); Py_DECREF(pModule); *pMDict = PyModule_GetDict(pModule); PyList_Append(dealloc_list, *pMDict); return pModule; } static PyObject * init_object(char *objectname, PyObject *pMDict) { PyObject *object = PyDict_GetItemString(pMDict, objectname); if (!object) return NULL; PyList_Append(dealloc_list, object); return object; } static int init_module_class(char *modulename, PyObject **pModule, PyObject **pMDict, char *classname, PyObject **pClass) { if ((*pModule = init_module(modulename, pMDict))) *pClass = init_object(classname, *pMDict); else return -1; return 0; } extern void *libnumarray_API[]; static int deferred_libnumarray_init(void) { int i; if (initialized) return 0; import_libtc(); if (init_module_class("numarray.generic", &pNDArrayModule, &pNDArrayMDict, "NDArray", &pNDArrayClass) < 0) goto _fail; if (init_module_class("numarray", &pNumArrayModule, &pNumArrayMDict, "NumArray", &pNumArrayClass) < 0) goto _fail; if (init_module_class("numarray.numerictypes", &pNumericTypesModule, &pNumericTypesMDict, "NumericType", &pNumericTypeClass) < 0) goto _fail; if (init_module_class("numarray._ufunc", &pUfuncModule, &pUfuncMDict, "_ufunc", &pUfuncClass) < 0) goto _fail; pCfuncClass = (PyObject *) &CfuncType; Py_INCREF(pCfuncClass); if (init_module_class("numarray._operator", &pOperatorModule, &pOperatorMDict, "_operator", &pOperatorClass) < 0) goto _fail; if (init_module_class("numarray._converter", &pConverterModule, &pConverterMDict, "_converter", &pConverterClass) < 0) goto _fail; if (!(pNumArrayNewFunc = PyObject_GetAttrString( pNumArrayClass, "__new__"))) goto _fail; if (!(pNumArrayArrayFunc = init_object( "array", pNumArrayMDict))) goto _fail; if (!(pNumericTypesTDict = init_object( "typeDict", pNumericTypesMDict))) goto _fail; pNewMemoryFunc = NA_initModuleGlobal("numarray.memory","new_memory"); if (!pNewMemoryFunc) goto _fail; pHandleErrorFunc = NA_initModuleGlobal("numarray.ufunc", "handleError"); if (!pHandleErrorFunc) goto _fail; /* Set up table of type objects */ for(i=0; i_get = NA_getPythonScalar; ptr->_set = NA_setFromPythonScalar; break; } } libnumarray_API[ 0 ] = (void *) pNumArrayClass; pEmptyDict = PyDict_New(); if (!pEmptyDict) goto _fail; pEmptyTuple = PyTuple_New(0); if (!pEmptyTuple) goto _fail; /* _exit: */ initialized = 1; return 0; _fail: initialized = 0; return -1; } /* Finalize this module. */ void fini_module_class(PyObject *module, PyObject *mdict, PyObject *class) { Py_DECREF(module); Py_DECREF(mdict); Py_DECREF(class); } static void NA_Done(void) { int i; fini_module_class(pNDArrayModule, pNDArrayMDict, pNDArrayClass); fini_module_class(pNumArrayModule, pNumArrayMDict, pNumArrayClass); Py_DECREF(pNumArrayArrayFunc); fini_module_class(pOperatorModule, pOperatorMDict, pOperatorClass); fini_module_class(pConverterModule, pConverterMDict, pConverterClass); fini_module_class(pUfuncModule, pUfuncMDict, pUfuncClass); Py_DECREF(pCfuncClass); fini_module_class(pNumericTypesModule, pNumericTypesMDict, pNumericTypeClass); Py_DECREF(pNumericTypesTDict); for(i=0; i= tAny) && (type <= tComplex64)) { return &descriptors[ type ]; } else { int i; for(i=0; i= 32) && (type <= 126)) PyErr_Format(_Error, "Type object lookup returned" " NULL for type \'%c\'", type); else PyErr_Format(_Error, "Type object lookup returned" " NULL for type %d", type); return NULL; } static PyObject * getTypeObject(NumarrayType type) { char strcharcode[2]; PyObject *typeobj; if (deferred_libnumarray_init() < 0) return NULL; if ((type >= tAny) && (type <= tObject)) { return pNumType[type]; } else { /* Test if it is a Numeric charcode */ strcharcode[0] = type; strcharcode[1] = 0; typeobj = PyDict_GetItemString( pNumericTypesTDict, strcharcode); return typeobj ? typeobj : setTypeException(type); } } static PyObject * NA_getType( PyObject *type) { PyObject *typeobj = NULL; if (deferred_libnumarray_init() < 0) goto _exit; if (!type) goto _exit; if (PyObject_IsInstance(type, pNumericTypeClass)) { Py_INCREF(type); typeobj = type; goto _exit; } if ((typeobj = PyDict_GetItem(pNumericTypesTDict, type))) { Py_INCREF(typeobj); } else { PyErr_Format(PyExc_ValueError, "NA_getType: unknown type."); } _exit: return typeobj; } /* Look up the NumarrayType which corresponds to typename */ static int NA_nameToTypeNo(char *typename) { int i; for(i=0; isuffix[0]) && (itemsize == ts->itemsize)) return i; } PyErr_Format(PyExc_TypeError, "Unknown __array_struct__ typekind"); return -1; } static int NA_scipy_typestr(NumarrayType t, int byteorder, char *typestr) { int i; if (byteorder) strcpy(typestr, ">"); else strcpy(typestr, "<"); for(i=0; itype_num == t) { strncat(typestr, ts->suffix, 4); return 0; } } return -1; } static long NA_isIntegerSequence(PyObject *sequence) { PyObject *o; long i, size, isInt = 1; if (!sequence) { isInt = -1; goto _exit; } if (!PySequence_Check(sequence)) { isInt = 0; goto _exit; } if ((size = PySequence_Length(sequence)) < 0) { isInt = -1; goto _exit; } for(i=0; i len) { PyErr_Format(PyExc_ValueError, "NA_maybeLongsFromIntTuple: sequence is too long"); size = -1; goto _exit; } for(i=0; i_data != Py_None) { if (getReadBufferDataPtr (me->_data, (void **) &me->data) < 0) { return (PyArrayObject *) PyErr_Format( _Error, "NA_updateDataPtr: error getting read buffer data ptr"); } if (isBufferWriteable( me->_data )) me->flags |= WRITABLE; else me->flags &= ~WRITABLE; } else { me->data = NULL; } me->data += me->byteoffset; return me; } /* Count the number of elements in a 1D static array. */ #define ELEM(x) (sizeof(x)/sizeof(x[0])) static int NA_ByteOrder(void) { unsigned long byteorder_test; byteorder_test = 1; if (*((char *) &byteorder_test)) return NUM_LITTLE_ENDIAN; else return NUM_BIG_ENDIAN; } /* Create a new numarray specifying all attribute values and using an object which meets the buffer API to store the array data. */ static void _stridesFromShape(PyArrayObject *self) { int i; if (self->nd > 0) { for(i=0; ind; i++) self->strides[i] = self->bytestride; for(i=self->nd-2; i>=0; i--) self->strides[i] = self->strides[i+1]*self->dimensions[i+1]; self->nstrides = self->nd; } else self->nstrides = 0; } static PyArrayObject * NA_NewAllFromBuffer(int ndim, maybelong *shape, NumarrayType type, PyObject *bufferObject, maybelong byteoffset, maybelong bytestride, int byteorder, int aligned, int writeable) { PyObject *typeObject; PyArrayObject *self = NULL; long i; if (deferred_libnumarray_init() < 0) goto _fail; if (type == tAny) type = tDefault; if (ndim > MAXDIM) goto _fail; { PyTypeObject *typ = (PyTypeObject *) pNumArrayClass; self = (PyArrayObject *) typ->tp_new( typ, pEmptyTuple, pEmptyDict); if (!self) goto _fail; } typeObject = getTypeObject(type); if (!typeObject) { setTypeException(type); goto _fail; } if (!(self->descr = NA_DescrFromType(type))) { goto _fail; } self->nd = self->nstrides = ndim; for(i=0; idimensions[i] = shape[i]; } if (bytestride == 0) self->bytestride = self->descr->elsize; else self->bytestride = bytestride; _stridesFromShape(self); self->byteoffset = byteoffset; self->byteorder = byteorder; self->itemsize = self->descr->elsize; Py_XDECREF(self->_data); if ((bufferObject == Py_None) || (bufferObject == NULL)) { long size = self->descr->elsize; for(i=0; ind; i++) { size *= self->dimensions[i]; } self->_data = PyObject_CallFunction( pNewMemoryFunc, "(l)", size); if (!self->_data) goto _fail; } else { self->_data = bufferObject; Py_INCREF(self->_data); } if (!NA_updateDataPtr(self)) goto _fail; NA_updateStatus(self); return self; _fail: Py_XDECREF(self); return NULL; } /* Create a new numarray specifying all attribute values but with a C-array as buffer which will be copied to a Python buffer. */ static PyArrayObject * NA_NewAll(int ndim, maybelong *shape, NumarrayType type, void *buffer, maybelong byteoffset, maybelong bytestride, int byteorder, int aligned, int writeable) { PyArrayObject *result = NA_NewAllFromBuffer( ndim, shape, type, Py_None, byteoffset, bytestride, byteorder, aligned, writeable); if (result) { if (!NA_NumArrayCheck((PyObject *) result)) { PyErr_Format( PyExc_TypeError, "NA_NewAll: non-NumArray result"); result = NULL; } else { if (buffer) { memcpy(result->data, buffer, NA_NBYTES(result)); } else { memset(result->data, 0, NA_NBYTES(result)); } } } return result; } static PyArrayObject * NA_NewAllStrides(int ndim, maybelong *shape, maybelong *strides, NumarrayType type, void *buffer, maybelong byteoffset, int byteorder, int aligned, int writeable) { int i; PyArrayObject *result = NA_NewAll(ndim, shape, type, buffer, byteoffset, 0, byteorder, aligned, writeable); for(i=0; istrides[i] = strides[i]; result->nstrides = ndim; return result; } #ifdef _MSC_VER static _int64 llabs(_int64 v) { return v < 0 ? -v : v; } #endif static PyArrayObject * NA_FromDimsStridesDescrAndData(int nd, maybelong *d, maybelong *s, PyArray_Descr *descr, char *data) { maybelong i, nelements, breadth, bsize, boffset, dimensions[MAXDIM], strides[MAXDIM]; PyArrayObject *a; PyObject *buf; if (!descr) return NULL; if (nd < 0) { PyErr_SetString(PyExc_ValueError, "number of dimensions must be >= 0"); return NULL; } if (nd > MAXDIM) { return (PyArrayObject *) PyErr_Format(PyExc_ValueError, "too many dimensions: %d", nd); } if (!s) { /* no strides specified so assume minimal contiguous array and compute */ if (nd) { for(i=0; ielsize; for(i=nd-2; i>=0; i--) strides[i] = strides[i+1]*d[i+1]; } } else { for(i=0; ielsize; /* find buffer size implied by array dimensions and strides */ boffset = 0; for(i=0; itype_num, buf, boffset, descr->elsize, NA_ByteOrder(), 1, 1); Py_XDECREF(buf); if (!a) return NULL; for(i=0; istrides[i] = strides[i]; if (!data && !s) { memset(a->data, 0, bsize); } NA_updateStatus(a); return a; } static PyArrayObject * NA_FromDimsTypeAndData(int nd, maybelong *d, int type, char *data) { PyArray_Descr *descr = NA_DescrFromType(type); return NA_FromDimsStridesDescrAndData(nd, d, NULL, descr, data); } static PyArrayObject * NA_FromDimsStridesTypeAndData(int nd, maybelong *shape, maybelong *strides, int type, char *data) { PyArray_Descr *descr = NA_DescrFromType(type); return NA_FromDimsStridesDescrAndData(nd, shape, strides, descr, data); } /* Create a new numarray which is initially a C_array, or which references a C_array: aligned, !byteswapped, contiguous, ... Call with buffer==NULL to allocate storage. */ static PyArrayObject * NA_vNewArray(void *buffer, NumarrayType type, int ndim, maybelong *shape) { return (PyArrayObject *) NA_NewAll(ndim, shape, type, buffer, 0, 0, NA_ByteOrder(), 1, 1); } static PyArrayObject * NA_NewArray(void *buffer, NumarrayType type, int ndim, ...) { int i; maybelong shape[MAXDIM]; va_list ap; va_start(ap, ndim); for(i=0; idescr->type_num; name = NA_typeNoToName(t); if (!name) return (PyArrayObject *) setTypeException(t); return (PyArrayObject *) PyObject_CallMethod((PyObject *) a, method, "s", name); } static int getShape(PyObject *a, maybelong *shape, int dims) { long slen; if (PyString_Check(a)) { PyErr_Format(PyExc_TypeError, "getShape: numerical sequences can't contain strings."); return -1; } if (!PySequence_Check(a) || (NA_NDArrayCheck(a) && (PyArray(a)->nd == 0))) return dims; slen = PySequence_Length(a); if (slen < 0) { PyErr_Format(_Error, "getShape: couldn't get sequence length."); return -1; } if (!slen) { *shape = 0; return dims+1; } else if (dims < MAXDIM) { PyObject *item0 = PySequence_GetItem(a, 0); if (item0) { *shape = PySequence_Length(a); dims = getShape(item0, ++shape, dims+1); Py_DECREF(item0); } else { PyErr_Format(_Error, "getShape: couldn't get sequence item."); return -1; } } else { PyErr_Format(_Error, "getShape: sequence object nested more than MAXDIM deep."); return -1; } return dims; } typedef enum { NOTHING, NUMBER, SEQUENCE } SequenceConstraint; static int setArrayFromSequence(PyArrayObject *a, PyObject *s, int dim, long offset) { SequenceConstraint mustbe = NOTHING; int i, seqlen=-1, slen = PySequence_Length(s); if (dim > a->nd) { PyErr_Format(PyExc_ValueError, "setArrayFromSequence: sequence/array dimensions mismatch."); return -1; } if (slen != a->dimensions[dim]) { PyErr_Format(PyExc_ValueError, "setArrayFromSequence: sequence/array shape mismatch."); return -1; } for(i=0; ind == 0)) && ((mustbe == NOTHING) || (mustbe == NUMBER))) { if (NA_setFromPythonScalar(a, offset, o) < 0) return -2; mustbe = NUMBER; } else if (PyString_Check(o)) { PyErr_SetString( PyExc_ValueError, "setArrayFromSequence: strings can't define numeric numarray."); return -3; } else if (PySequence_Check(o)) { if ((mustbe == NOTHING) || (mustbe == SEQUENCE)) { if (mustbe == NOTHING) { mustbe = SEQUENCE; seqlen = PySequence_Length(o); } else if (PySequence_Length(o) != seqlen) { PyErr_SetString( PyExc_ValueError, "Nested sequences with different lengths."); return -5; } setArrayFromSequence(a, o, dim+1, offset); } else { PyErr_SetString(PyExc_ValueError, "Nested sequences with different lengths."); return -4; } } else { PyErr_SetString(PyExc_ValueError, "Invalid sequence."); return -6; } Py_DECREF(o); offset += a->strides[dim]; } return 0; } static PyObject * NA_setArrayFromSequence(PyArrayObject *a, PyObject *s) { maybelong shape[MAXDIM]; if (!PySequence_Check(s)) return PyErr_Format( PyExc_TypeError, "NA_setArrayFromSequence: (array, seq) expected."); if (getShape(s, shape, 0) < 0) return NULL; if (!NA_updateDataPtr(a)) return NULL; if (setArrayFromSequence(a, s, 0, 0) < 0) return NULL; Py_INCREF(Py_None); return Py_None; } static int _NA_maxType(PyObject *seq, int limit) { if (limit > MAXDIM) { PyErr_Format( PyExc_ValueError, "NA_maxType: sequence nested too deep." ); return -1; } if (NA_NumArrayCheck(seq)) { switch(PyArray(seq)->descr->type_num) { case tBool: return BOOL_SCALAR; case tInt8: case tUInt8: case tInt16: case tUInt16: case tInt32: case tUInt32: return INT_SCALAR; case tInt64: case tUInt64: return LONG_SCALAR; case tFloat32: case tFloat64: return FLOAT_SCALAR; case tComplex32: case tComplex64: return COMPLEX_SCALAR; default: PyErr_Format(PyExc_TypeError, "Expecting a python numeric type, got something else."); return -1; } } else if (PySequence_Check(seq) && !PyString_Check(seq)) { long i, maxtype=BOOL_SCALAR, slen; slen = PySequence_Length(seq); if (slen < 0) return -1; if (slen == 0) return INT_SCALAR; for(i=0; i maxtype) { maxtype = newmax; } Py_DECREF(o); } return maxtype; } else { #if PY_VERSION_HEX >= 0x02030000 if (PyBool_Check(seq)) return BOOL_SCALAR; else #endif if (PyInt_Check(seq)) return INT_SCALAR; else if (PyLong_Check(seq)) return LONG_SCALAR; else if (PyFloat_Check(seq)) return FLOAT_SCALAR; else if (PyComplex_Check(seq)) return COMPLEX_SCALAR; else { PyErr_Format(PyExc_TypeError, "Expecting a python numeric type, got something else."); return -1; } } } static int NA_maxType(PyObject *seq) { int rval; rval = _NA_maxType(seq, 0); return rval; } NumarrayType NA_NumarrayType(PyObject *seq) { int maxtype = NA_maxType(seq); int rval; switch(maxtype) { case BOOL_SCALAR: rval = tBool; goto _exit; case INT_SCALAR: case LONG_SCALAR: rval = tLong; /* tLong corresponds to C long int, not Python long int */ goto _exit; case FLOAT_SCALAR: rval = tFloat64; goto _exit; case COMPLEX_SCALAR: rval = tComplex64; goto _exit; default: PyErr_Format(PyExc_TypeError, "expecting Python numeric scalar value; got something else."); rval = -1; } _exit: return rval; } /* sequenceAsArray converts a python sequence (list or tuple) into an array of the specified type and returns it. */ static PyArrayObject* sequenceAsArray(PyObject *s, NumarrayType *t) { maybelong shape[MAXDIM]; int dims = getShape(s, shape, 0); PyArrayObject *array; if (dims < 0) return NULL; if (*t == tAny) { *t = NA_NumarrayType(s); } if (!(array = NA_vNewArray(NULL, *t, dims, shape))) return NULL; if (setArrayFromSequence(array, s, 0, 0) < 0) { return (PyArrayObject *) PyErr_Format( _Error, "sequenceAsArray: can't convert sequence to array"); } return array; } /* satisfies ensures that 'a' meets a set of requirements and matches the specified type. */ static int satisfies(PyArrayObject *a, int requirements, NumarrayType t) { int type_ok = (a->descr->type_num == t) || (t == tAny); if (PyArray_ISCARRAY(a)) return type_ok; if (PyArray_ISBYTESWAPPED(a) && (requirements & NUM_NOTSWAPPED)) return 0; if (!PyArray_ISALIGNED(a) && (requirements & NUM_ALIGNED)) return 0; if (!PyArray_ISCONTIGUOUS(a) && (requirements & NUM_CONTIGUOUS)) return 0; if (!PyArray_ISWRITABLE(a) && (requirements & NUM_WRITABLE)) return 0; if (requirements & NUM_COPY) return 0; return type_ok; } /* NA_InputArray is the main input conversion routine. NA_InputArray converts input array 'a' as necessary to NumarrayType 't' also guaranteeing that either 'a' or the converted result is contigous, aligned, and not byteswapped. NA_InputArray returns a pointer to a Numarray for which C_array is 1, and fills in 'ainfo' with the array information of the return value. The return value provides a means to later deallocate any temporary array created by NA_InputArray, while 'ainfo' provides direct access to the array's "metadata" from C. Since the reference count of the input array 'a' is incremented when it is directly useable by C, the return value (either 'a' or a temporary) should always be passed to Py_XDECREF by the calller. Note that at failed sequence conversion, getNumInfo, or getArray results in the value NULL being returned. 1. 'a' is already c-usesable. 2. 'a' is an array, but needs conversion to be c-useable. 3. 'a' is a numeric sequence, not an array. 4. 'a' is a numeric scalar, not an array. The contents of the resulting array are either 'a' or 'a.astype(t)'. The return value should always be DECREF'ed by the caller. requires is a bitmask specifying a set of requirements on the converted array. */ static PyArrayObject * NA_FromArrayStruct(PyObject *obj) { PyArrayInterface *arrayif; maybelong i, shape[MAXDIM], strides[MAXDIM]; NumarrayType t; PyObject *cobj; PyArrayObject *a; cobj = PyObject_GetAttrString(obj, "__array_struct__"); /* does Py_INCREF */ if (!cobj) goto _fail; if (!PyCObject_Check(cobj)) { PyErr_Format( PyExc_TypeError, "__array_struct__ returned non-CObject."); goto _fail; } arrayif = PyCObject_AsVoidPtr(cobj); if (arrayif->nd > MAXDIM) { PyErr_Format( PyExc_ValueError, "__array_struct__ too many dimensions: %d", arrayif->nd); goto _fail; } for(i=0; ind; i++) { shape[i] = arrayif->shape[i]; strides[i] = arrayif->strides[i]; } t = _scipy_typekind_to_typeNo( arrayif->typekind, arrayif->itemsize ); if (t < 0) goto _fail; a = NA_FromDimsStridesTypeAndData(arrayif->nd, shape, strides, t, arrayif->data); if (!a) goto _fail; Py_INCREF(obj); Py_XDECREF(a->base); a->base = obj; Py_DECREF(cobj); return a; _fail: Py_XDECREF(cobj); return NULL; } static PyArrayObject* NA_InputArray(PyObject *a, NumarrayType t, int requires) { PyArrayObject *wa = NULL; if (NA_isPythonScalar(a)) { if (t == tAny) t = NA_NumarrayType(a); if (t < 0) goto _exit; wa = NA_vNewArray( NULL, t, 0, NULL); if (!wa) goto _exit; if (NA_setFromPythonScalar(wa, 0, a) < 0) { Py_DECREF(wa); wa = NULL; } goto _exit; } else if (NA_NumArrayCheck(a)) { wa = (PyArrayObject *) a; Py_INCREF(a); } else if (PyObject_HasAttrString(a, "__array_struct__")) { wa = NA_FromArrayStruct(a); } else if (PyObject_HasAttrString(a, "__array_typestr__")) { wa = (PyArrayObject *) PyObject_CallFunction( pNumArrayArrayFunc, "(O)", a ); } else { wa = sequenceAsArray(a, &t); } if (!wa) goto _exit; if (!satisfies(wa, requires, t)) { PyArrayObject *wa2 = getArray(wa, t, "astype"); Py_DECREF(wa); wa = wa2; } NA_updateDataPtr(wa); _exit: return wa; } /* NA_OutputArray creates a C-usable temporary array similar to 'a' but of type 't' as necessary. If 'a' is already C-useable and of type 't', then 'a' is returned. In either case, 'ainfo' is filled in with the array information for the return value. The contents of the resulting array are undefined, assumed to be filled in by the caller. */ static PyArrayObject * NA_OutputArray(PyObject *a0, NumarrayType t, int requires) { PyArrayObject *a = (PyArrayObject *) a0; if (!NA_NumArrayCheck(a0) || !PyArray_ISWRITABLE(a)) { PyErr_Format(PyExc_TypeError, "NA_OutputArray: only writable NumArrays work for output."); a = NULL; goto _exit; } if (satisfies(a, requires, t)) { Py_INCREF(a0); NA_updateDataPtr(a); goto _exit; } else { PyArrayObject *shadow = getArray(a, t, "new"); if (shadow) { Py_INCREF(a0); shadow->_shadows = a0; } a = shadow; } _exit: return a; } /* NA_OptionalOutputArray works like NA_ShadowOutput, but handles the case where the output array 'optional' is omitted entirely at the python level, resulting in 'optional'==Py_None. When 'optional' is Py_None, the return value is cloned (but with NumarrayType 't') from 'master', typically an input array with the same shape as the output array. */ static PyArrayObject * NA_OptionalOutputArray(PyObject *optional, NumarrayType t, int requires, PyArrayObject *master) { if ((optional == Py_None) || (optional == NULL)) { PyArrayObject *rval; rval = getArray(master, t, "new"); return rval; } else { return NA_OutputArray(optional, t, requires); } } /* NA_IoArray is a combination of NA_InputArray and NA_OutputArray. Unlike NA_OutputArray, if a temporary is required it is initialized to a copy of the input array. Unlike NA_InputArray, deallocating any resulting temporary array results in a copy from the temporary back to the original. */ static PyArrayObject * NA_IoArray(PyObject *a, NumarrayType t, int requires) { PyArrayObject *shadow = NA_InputArray(a, t, requires); if (!shadow) return NULL; /* Guard against non-writable, but otherwise satisfying requires. In this case, shadow == a. */ if (!PyArray_ISWRITABLE(shadow)) { PyErr_Format(PyExc_TypeError, "NA_IoArray: I/O numarray must be writable NumArrays."); Py_DECREF(shadow); shadow = NULL; goto _exit; } if ((shadow != (PyArrayObject *) a) && NA_NumArrayCheck(a)) { Py_INCREF(a); shadow->_shadows = a; } _exit: return shadow; } /* NA_ReturnOutput handles returning a possibly unspecified output array. If the array 'out' was specified on the original call to the Python wrapper function, then the contents of any 'shadow' array are copied into 'out' as required. The function then returns Py_None. If no output was specified in the original call, then the 'shadow' array *becomes* the output and is returned. This results in extension functions which return Py_None when you specify an output array, and return an array value otherwise. These functions also correctly handle data typing, alignment, byteswapping, and contiguity issues. */ static PyObject* NA_ReturnOutput(PyObject *out, PyArrayObject *shadow) { if ((out == Py_None) || (out == NULL)) { /* default behavior: return shadow array as the result */ return (PyObject *) shadow; } else { PyObject *rval; /* specified output behavior: return None */ /* del(shadow) --> out.copyFrom(shadow) */ Py_DECREF(shadow); Py_INCREF(Py_None); rval = Py_None; return rval; } } /* NA_ShapeEqual returns 1 if 'a' and 'b' have the same shape, 0 otherwise. */ static int NA_ShapeEqual(PyArrayObject *a, PyArrayObject *b) { int i; if (!NA_NDArrayCheck((PyObject *) a) || !NA_NDArrayCheck((PyObject*) b)) { PyErr_Format( PyExc_TypeError, "NA_ShapeEqual: non-array as parameter."); return -1; } if (a->nd != b->nd) return 0; for(i=0; ind; i++) if (a->dimensions[i] != b->dimensions[i]) return 0; return 1; } /* NA_ShapeLessThan returns 1 if a.shape[i] < b.shape[i] for all i, else 0. If they have a different number of dimensions, it compares the innermost overlapping dimensions of each. */ static int NA_ShapeLessThan(PyArrayObject *a, PyArrayObject *b) { int i; int mindim, aoff, boff; if (!NA_NDArrayCheck((PyObject *) a) || !NA_NDArrayCheck((PyObject *) b)) { PyErr_Format(PyExc_TypeError, "NA_ShapeLessThan: non-array as parameter."); return -1; } mindim = MIN(a->nd, b->nd); aoff = a->nd - mindim; boff = b->nd - mindim; for(i=0; idimensions[i+aoff] >= b->dimensions[i+boff]) return 0; return 1; } #define MakeChecker(name, classpointer) \ static int \ name##Exact(PyObject *op) { \ return ((PyObject *) op->ob_type) == classpointer; \ } \ static int \ name(PyObject *op) { \ int rval = -1; \ if (deferred_libnumarray_init() < 0) goto _exit; \ rval = PyObject_IsInstance(op, classpointer); \ _exit: \ return rval; \ } MakeChecker(NA_NDArrayCheck, pNDArrayClass) MakeChecker(NA_NumArrayCheck, pNumArrayClass) MakeChecker(NA_OperatorCheck, pOperatorClass) MakeChecker(NA_ConverterCheck, pConverterClass) MakeChecker(NA_UfuncCheck, pUfuncClass) MakeChecker(NA_CfuncCheck, pCfuncClass) static int NA_ComplexArrayCheck(PyObject *a) { int rval = NA_NumArrayCheck(a); if (rval > 0) { PyArrayObject *arr = (PyArrayObject *) a; switch(arr->descr->type_num) { case tComplex64: case tComplex32: return 1; default: return 0; } } return rval; } static PyObject * NA_Cast(PyArrayObject *a, int type) { PyObject *rval = NULL; if (deferred_libnumarray_init() < 0) goto _exit; rval = (PyObject *) getArray(a, type, "astype"); _exit: return rval; } static int NA_copyArray(PyArrayObject *to, const PyArrayObject *from) { int rval = -1; PyObject *result; result = PyObject_CallMethod((PyObject *) to, "_copyFrom","(O)", from); if (!result) goto _exit; Py_DECREF(result); rval = 0; _exit: return rval; } static PyArrayObject * NA_copy(PyArrayObject *from) { PyArrayObject * rval; rval = (PyArrayObject *) PyObject_CallMethod((PyObject *) from, "copy", NULL); return rval; } static void NA_stridesFromShape(int nshape, maybelong *shape, maybelong bytestride, maybelong *strides) { int i; if (nshape > 0) { for(i=0; i=0; i--) strides[i] = strides[i+1]*shape[i+1]; } } static int NA_getByteOffset(PyArrayObject *array, int nindices, maybelong *indices, long *offset) { int i; /* rank0 or _UBuffer */ if ((array->nd == 0) || (array->nstrides < 0)) { *offset = array->byteoffset; return 0; } /* Check for indices/shape mismatch when not rank-0. */ if ((nindices > array->nd) && !((nindices == 1) && (array->nd == 0))) { PyErr_Format(PyExc_IndexError, "too many indices."); return -1; } *offset = array->byteoffset; for(i=0; ind ? array->dimensions[i] : 0; if (ix < 0) ix += limit; if (ix < 0 || ix >= limit) { PyErr_Format(PyExc_IndexError, "Index out of range"); return -1; } *offset += ix*array->strides[i]; } return 0; } static int NA_swapAxes(PyArrayObject *array, int x, int y) { long temp; if (((PyObject *) array) == Py_None) return 0; if (array->nd < 2) return 0; if (x < 0) x += array->nd; if (y < 0) y += array->nd; if ((x < 0) || (x >= array->nd) || (y < 0) || (y >= array->nd)) { PyErr_Format(PyExc_ValueError, "Specified dimension does not exist"); return -1; } temp = array->dimensions[x]; array->dimensions[x] = array->dimensions[y]; array->dimensions[y] = temp; temp = array->strides[x]; array->strides[x] = array->strides[y]; array->strides[y] = temp; NA_updateStatus(array); return 0; } static PyObject * NA_initModuleGlobal(char *modulename, char *globalname) { PyObject *module, *dict, *global = NULL; module = PyImport_ImportModule(modulename); if (!module) { PyErr_Format(PyExc_RuntimeError, "Can't import '%s' module", modulename); goto _exit; } dict = PyModule_GetDict(module); global = PyDict_GetItemString(dict, globalname); if (!global) { PyErr_Format(PyExc_RuntimeError, "Can't find '%s' global in '%s' module.", globalname, modulename); goto _exit; } Py_DECREF(module); Py_INCREF(global); _exit: return global; } static long _isaligned(PyArrayObject *self) { long i, ptr, alignment, aligned = 1; alignment = MAX(MIN(self->itemsize, MAX_ALIGN), 1); ptr = (long) self->data; aligned = (ptr % alignment) == 0; for (i=0; i nd; i++) aligned &= ((self->strides[i] % alignment) == 0); return aligned != 0; } static void NA_updateAlignment(PyArrayObject *self) { if (_isaligned(self)) self->flags |= ALIGNED; else self->flags &= ~ALIGNED; } static long _is_contiguous(PyArrayObject *self, maybelong elements) { long i, ndim, nstrides; ndim = self->nd; nstrides = self->nstrides; /* rank-0 numarray are always contiguous */ if (ndim == 0) return 1; /* zero-length arrays are also contiguous */ if (elements == 0) return 1; /* Strides must be in decreasing order. ndim >= 1 */ for(i=0; istrides[i] != self->strides[i+1]*self->dimensions[i+1]) return 0; /* Broadcast numarray have 0 in some stride and are discontiguous */ for(i=0; istrides[i]) return 0; if ((self->strides[nstrides-1] == self->itemsize) && (self->bytestride == self->itemsize)) return 1; if ((self->strides[nstrides-1] == 0) && (nstrides > 1)) return 1; return 0; } static long _is_fortran_contiguous(PyArrayObject *self, maybelong elements) { long i, sd; /* rank-0 numarray are always fortran_contiguous */ if (self->nd == 0) return 1; /* zero-length arrays are also fortran_contiguous */ if (elements == 0) return 1; sd = self->descr->elsize; for (i=0;ind;++i) { /* fortran == increasing order */ if (self->dimensions[i] == 0) return 0; /* broadcast array */ if (self->strides[i] != sd) return 0; sd *= self->dimensions[i]; } return 1; } static void NA_updateContiguous(PyArrayObject *self) { maybelong elements = NA_elements(self); if (_is_contiguous(self, elements)) self->flags |= CONTIGUOUS; else self->flags &= ~CONTIGUOUS; if (_is_fortran_contiguous(self, elements)) self->flags |= FORTRAN_CONTIGUOUS; else self->flags &= ~FORTRAN_CONTIGUOUS; } static int _isbyteswapped(PyArrayObject *self) { int syslittle = (NA_ByteOrder() == NUM_LITTLE_ENDIAN); int selflittle = (self->byteorder == NUM_LITTLE_ENDIAN); int byteswapped = (syslittle != selflittle); return byteswapped; } static void NA_updateByteswap(PyArrayObject *self) { if (!_isbyteswapped(self)) self->flags |= NOTSWAPPED; else self->flags &= ~NOTSWAPPED; } static void NA_updateStatus(PyArrayObject *self) { NA_updateAlignment(self); NA_updateContiguous(self); NA_updateByteswap(self); } static char * NA_getArrayData(PyArrayObject *obj) { if (!NA_NDArrayCheck((PyObject *) obj)) { PyErr_Format(PyExc_TypeError, "expected an NDArray"); } if (!NA_updateDataPtr(obj)) return NULL; return obj->data; } /* The following function has much platform dependent code since ** there is no platform-independent way of checking Floating Point ** status bits */ /* OSF/Alpha (Tru64) ---------------------------------------------*/ #if defined(__osf__) && defined(__alpha) static int NA_checkFPErrors(void) { unsigned long fpstatus; int retstatus; #include /* Should migrate to global scope */ fpstatus = ieee_get_fp_control(); /* clear status bits as well as disable exception mode if on */ ieee_set_fp_control( 0 ); retstatus = pyFPE_DIVIDE_BY_ZERO* (int)((IEEE_STATUS_DZE & fpstatus) != 0) + pyFPE_OVERFLOW * (int)((IEEE_STATUS_OVF & fpstatus) != 0) + pyFPE_UNDERFLOW * (int)((IEEE_STATUS_UNF & fpstatus) != 0) + pyFPE_INVALID * (int)((IEEE_STATUS_INV & fpstatus) != 0); return retstatus; } /* MS Windows -----------------------------------------------------*/ #elif defined(_MSC_VER) #include static int NA_checkFPErrors(void) { int fpstatus = (int) _clear87(); int retstatus = pyFPE_DIVIDE_BY_ZERO * ((SW_ZERODIVIDE & fpstatus) != 0) + pyFPE_OVERFLOW * ((SW_OVERFLOW & fpstatus) != 0) + pyFPE_UNDERFLOW * ((SW_UNDERFLOW & fpstatus) != 0) + pyFPE_INVALID * ((SW_INVALID & fpstatus) != 0); return retstatus; } /* Solaris --------------------------------------------------------*/ /* --------ignoring SunOS ieee_flags approach, someone else can ** deal with that! */ #elif defined(sun) #include static int NA_checkFPErrors(void) { int fpstatus; int retstatus; fpstatus = (int) fpgetsticky(); retstatus = pyFPE_DIVIDE_BY_ZERO * ((FP_X_DZ & fpstatus) != 0) + pyFPE_OVERFLOW * ((FP_X_OFL & fpstatus) != 0) + pyFPE_UNDERFLOW * ((FP_X_UFL & fpstatus) != 0) + pyFPE_INVALID * ((FP_X_INV & fpstatus) != 0); (void) fpsetsticky(0); return retstatus; } #elif defined(linux) || defined(darwin) || defined(__CYGWIN__) #if defined(__GLIBC__) || defined(darwin) || defined(__MINGW32__) #include #elif defined(__CYGWIN__) #include #endif static int NA_checkFPErrors(void) { int fpstatus = (int) fetestexcept( FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INVALID); int retstatus = pyFPE_DIVIDE_BY_ZERO * ((FE_DIVBYZERO & fpstatus) != 0) + pyFPE_OVERFLOW * ((FE_OVERFLOW & fpstatus) != 0) + pyFPE_UNDERFLOW * ((FE_UNDERFLOW & fpstatus) != 0) + pyFPE_INVALID * ((FE_INVALID & fpstatus) != 0); (void) feclearexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INVALID); return retstatus; } #else static int NA_checkFPErrors(void) { return 0; } #endif static void NA_clearFPErrors() { NA_checkFPErrors(); } static int NA_checkAndReportFPErrors(char *name) { int error = NA_checkFPErrors(); if (error) { PyObject *ans; char msg[128]; if (deferred_libnumarray_init() < 0) return -1; strcpy(msg, " in "); strncat(msg, name, 100); ans = PyObject_CallFunction(pHandleErrorFunc, "(is)", error, msg); if (!ans) return -1; Py_DECREF(ans); /* Py_None */ } return 0; } /**********************************************************************/ /* Buffer Utility Functions */ /**********************************************************************/ static PyObject * getBuffer( PyObject *obj) { if (!obj) return PyErr_Format(PyExc_RuntimeError, "NULL object passed to getBuffer()"); if (obj->ob_type->tp_as_buffer == NULL) { return PyObject_CallMethod(obj, "__buffer__", NULL); } else { Py_INCREF(obj); /* Since CallMethod returns a new object when it succeeds, We'll need to DECREF later to free it. INCREF ordinary buffers here so we don't have to remember where the buffer came from at DECREF time. */ return obj; } } /* Either it defines the buffer API, or it is an instance which returns a buffer when obj.__buffer__() is called */ static int isBuffer (PyObject *obj) { PyObject *buf = getBuffer(obj); int ans = 0; if (buf) { ans = buf->ob_type->tp_as_buffer != NULL; Py_DECREF(buf); } else { PyErr_Clear(); } return ans; } /**********************************************************************/ static int getWriteBufferDataPtr(PyObject *buffobj, void **buff) { int rval = -1; PyObject *buff2; if ((buff2 = getBuffer(buffobj))) { if (buff2->ob_type->tp_as_buffer->bf_getwritebuffer) rval = buff2->ob_type->tp_as_buffer->bf_getwritebuffer(buff2, 0, buff); Py_DECREF(buff2); } return rval; } /**********************************************************************/ static int isBufferWriteable (PyObject *buffobj) { void *ptr; int rval = -1; rval = getWriteBufferDataPtr(buffobj, &ptr); if (rval == -1) PyErr_Clear(); /* Since we're just "testing", it's not really an error */ return rval != -1; } /**********************************************************************/ static int getReadBufferDataPtr(PyObject *buffobj, void **buff) { int rval = -1; PyObject *buff2; if ((buff2 = getBuffer(buffobj))) { if (buff2->ob_type->tp_as_buffer->bf_getreadbuffer) rval = buff2->ob_type->tp_as_buffer->bf_getreadbuffer(buff2, 0, buff); Py_DECREF(buff2); } return rval; } /**********************************************************************/ static int getBufferSize(PyObject *buffobj) { int segcount, size=0; PyObject *buff2; if ((buff2 = getBuffer(buffobj))) { segcount = buff2->ob_type->tp_as_buffer->bf_getsegcount(buff2, &size); Py_DECREF(buff2); } else size = -1; return size; } static long NA_getBufferPtrAndSize(PyObject *buffobj, int readonly, void **ptr) { long rval; if (readonly) rval = getReadBufferDataPtr(buffobj, ptr); else rval = getWriteBufferDataPtr(buffobj, ptr); return rval; } static int NA_checkOneCBuffer(char *name, long niter, void *buffer, long bsize, size_t typesize) { Int64 lniter = niter, ltypesize = typesize; if (lniter*ltypesize > bsize) { PyErr_Format(_Error, "%s: access out of buffer. niter=%d typesize=%d bsize=%d", name, (int) niter, (int) typesize, (int) bsize); return -1; } if ((typesize <= sizeof(Float64)) && (((long) buffer) % typesize)) { PyErr_Format(_Error, "%s: buffer not aligned on %d byte boundary.", name, (int) typesize); return -1; } return 0; } static int NA_checkIo(char *name, int wantIn, int wantOut, int gotIn, int gotOut) { if (wantIn != gotIn) { PyErr_Format(_Error, "%s: wrong # of input buffers. Expected %d. Got %d.", name, wantIn, gotIn); return -1; } if (wantOut != gotOut) { PyErr_Format(_Error, "%s: wrong # of output buffers. Expected %d. Got %d.", name, wantOut, gotOut); return -1; } return 0; } static int NA_checkNCBuffers(char *name, int N, long niter, void **buffers, long *bsizes, Int8 *typesizes, Int8 *iters) { int i; for (i=0; i= 0) { /* Skip dimension == 0. */ omax = MAX(omax, tmax); omin = MIN(omin, tmin); if (align && (ABS(stride[i]) % alignsize)) { PyErr_Format(_Error, "%s: stride %d not aligned on %d byte boundary.", name, (int) stride[i], (int) alignsize); return -1; } if (omax + itemsize > buffersize) { #if 0 _dump_hex("shape:", dim, shape); _dump_hex("strides:", dim, stride); #endif PyErr_Format(_Error, "%s: access beyond buffer. offset=%d buffersize=%d", name, (int) (omax+itemsize-1), (int) buffersize); return -1; } if (omin < 0) { PyErr_Format(_Error, "%s: access before buffer. offset=%d buffersize=%d", name, (int) omin, (int) buffersize); return -1; } } } return 0; } Float64 NA_get_Float64(PyArrayObject *a, long offset) { switch(a->descr->type_num) { case tBool: return NA_GETP(a, Bool, (NA_PTR(a)+offset)) != 0; case tInt8: return NA_GETP(a, Int8, (NA_PTR(a)+offset)); case tUInt8: return NA_GETP(a, UInt8, (NA_PTR(a)+offset)); case tInt16: return NA_GETP(a, Int16, (NA_PTR(a)+offset)); case tUInt16: return NA_GETP(a, UInt16, (NA_PTR(a)+offset)); case tInt32: return NA_GETP(a, Int32, (NA_PTR(a)+offset)); case tUInt32: return NA_GETP(a, UInt32, (NA_PTR(a)+offset)); case tInt64: return NA_GETP(a, Int64, (NA_PTR(a)+offset)); #if HAS_UINT64 case tUInt64: return NA_GETP(a, UInt64, (NA_PTR(a)+offset)); #endif case tFloat32: return NA_GETP(a, Float32, (NA_PTR(a)+offset)); case tFloat64: return NA_GETP(a, Float64, (NA_PTR(a)+offset)); case tComplex32: /* Since real value is first */ return NA_GETP(a, Float32, (NA_PTR(a)+offset)); case tComplex64: /* Since real value is first */ return NA_GETP(a, Float64, (NA_PTR(a)+offset)); default: PyErr_Format( PyExc_TypeError, "Unknown type %d in NA_get_Float64", a->descr->type_num); } return 0; /* suppress warning */ } void NA_set_Float64(PyArrayObject *a, long offset, Float64 v) { Bool b; switch(a->descr->type_num) { case tBool: b = (v != 0); NA_SETP(a, Bool, (NA_PTR(a)+offset), b); break; case tInt8: NA_SETP(a, Int8, (NA_PTR(a)+offset), v); break; case tUInt8: NA_SETP(a, UInt8, (NA_PTR(a)+offset), v); break; case tInt16: NA_SETP(a, Int16, (NA_PTR(a)+offset), v); break; case tUInt16: NA_SETP(a, UInt16, (NA_PTR(a)+offset), v); break; case tInt32: NA_SETP(a, Int32, (NA_PTR(a)+offset), v); break; case tUInt32: NA_SETP(a, UInt32, (NA_PTR(a)+offset), v); break; case tInt64: NA_SETP(a, Int64, (NA_PTR(a)+offset), v); break; #if HAS_UINT64 case tUInt64: NA_SETP(a, UInt64, (NA_PTR(a)+offset), v); break; #endif case tFloat32: NA_SETP(a, Float32, (NA_PTR(a)+offset), v); break; case tFloat64: NA_SETP(a, Float64, (NA_PTR(a)+offset), v); break; case tComplex32: { NA_SETP(a, Float32, (NA_PTR(a)+offset), v); NA_SETP(a, Float32, (NA_PTR(a)+offset+sizeof(Float32)), 0); break; } case tComplex64: { NA_SETP(a, Float64, (NA_PTR(a)+offset), v); NA_SETP(a, Float64, (NA_PTR(a)+offset+sizeof(Float64)), 0); break; } default: PyErr_Format( PyExc_TypeError, "Unknown type %d in NA_set_Float64", a->descr->type_num ); PyErr_Print(); } } static int NA_overflow(PyArrayObject *a, Float64 v) { if ((a->flags & CHECKOVERFLOW) == 0) return 0; switch(a->descr->type_num) { case tBool: return 0; case tInt8: if ((v < -128) || (v > 127)) goto _fail; return 0; case tUInt8: if ((v < 0) || (v > 255)) goto _fail; return 0; case tInt16: if ((v < -32768) || (v > 32767)) goto _fail; return 0; case tUInt16: if ((v < 0) || (v > 65535)) goto _fail; return 0; case tInt32: if ((v < -2147483648.) || (v > 2147483647.)) goto _fail; return 0; case tUInt32: if ((v < 0) || (v > 4294967295.)) goto _fail; return 0; case tInt64: if ((v < -9223372036854775808.) || (v > 9223372036854775807.)) goto _fail; return 0; #if HAS_UINT64 case tUInt64: if ((v < 0) || (v > 18446744073709551615.)) goto _fail; return 0; #endif case tFloat32: if ((v < -FLT_MAX) || (v > FLT_MAX)) goto _fail; return 0; case tFloat64: return 0; case tComplex32: if ((v < -FLT_MAX) || (v > FLT_MAX)) goto _fail; return 0; case tComplex64: return 0; default: PyErr_Format( PyExc_TypeError, "Unknown type %d in NA_overflow", a->descr->type_num ); PyErr_Print(); return -1; } _fail: PyErr_Format(PyExc_OverflowError, "value out of range for array"); return -1; } Complex64 NA_get_Complex64(PyArrayObject *a, long offset) { Complex32 v0; Complex64 v; switch(a->descr->type_num) { case tComplex32: v0 = NA_GETP(a, Complex32, (NA_PTR(a)+offset)); v.r = v0.r; v.i = v0.i; break; case tComplex64: v = NA_GETP(a, Complex64, (NA_PTR(a)+offset)); break; default: v.r = NA_get_Float64(a, offset); v.i = 0; break; } return v; } void NA_set_Complex64(PyArrayObject *a, long offset, Complex64 v) { Complex32 v0; switch(a->descr->type_num) { case tComplex32: v0.r = v.r; v0.i = v.i; NA_SETP(a, Complex32, (NA_PTR(a)+offset), v0); break; case tComplex64: NA_SETP(a, Complex64, (NA_PTR(a)+offset), v); break; default: NA_set_Float64(a, offset, v.r); break; } } Int64 NA_get_Int64(PyArrayObject *a, long offset) { switch(a->descr->type_num) { case tBool: return NA_GETP(a, Bool, (NA_PTR(a)+offset)) != 0; case tInt8: return NA_GETP(a, Int8, (NA_PTR(a)+offset)); case tUInt8: return NA_GETP(a, UInt8, (NA_PTR(a)+offset)); case tInt16: return NA_GETP(a, Int16, (NA_PTR(a)+offset)); case tUInt16: return NA_GETP(a, UInt16, (NA_PTR(a)+offset)); case tInt32: return NA_GETP(a, Int32, (NA_PTR(a)+offset)); case tUInt32: return NA_GETP(a, UInt32, (NA_PTR(a)+offset)); case tInt64: return NA_GETP(a, Int64, (NA_PTR(a)+offset)); case tUInt64: return NA_GETP(a, UInt64, (NA_PTR(a)+offset)); case tFloat32: return NA_GETP(a, Float32, (NA_PTR(a)+offset)); case tFloat64: return NA_GETP(a, Float64, (NA_PTR(a)+offset)); case tComplex32: return NA_GETP(a, Float32, (NA_PTR(a)+offset)); case tComplex64: return NA_GETP(a, Float64, (NA_PTR(a)+offset)); default: PyErr_Format( PyExc_TypeError, "Unknown type %d in NA_get_Int64", a->descr->type_num); PyErr_Print(); } return 0; /* suppress warning */ } void NA_set_Int64(PyArrayObject *a, long offset, Int64 v) { Bool b; switch(a->descr->type_num) { case tBool: b = (v != 0); NA_SETP(a, Bool, (NA_PTR(a)+offset), b); break; case tInt8: NA_SETP(a, Int8, (NA_PTR(a)+offset), v); break; case tUInt8: NA_SETP(a, UInt8, (NA_PTR(a)+offset), v); break; case tInt16: NA_SETP(a, Int16, (NA_PTR(a)+offset), v); break; case tUInt16: NA_SETP(a, UInt16, (NA_PTR(a)+offset), v); break; case tInt32: NA_SETP(a, Int32, (NA_PTR(a)+offset), v); break; case tUInt32: NA_SETP(a, UInt32, (NA_PTR(a)+offset), v); break; case tInt64: NA_SETP(a, Int64, (NA_PTR(a)+offset), v); break; case tUInt64: NA_SETP(a, UInt64, (NA_PTR(a)+offset), v); break; case tFloat32: NA_SETP(a, Float32, (NA_PTR(a)+offset), v); break; case tFloat64: NA_SETP(a, Float64, (NA_PTR(a)+offset), v); break; case tComplex32: NA_SETP(a, Float32, (NA_PTR(a)+offset), v); NA_SETP(a, Float32, (NA_PTR(a)+offset+sizeof(Float32)), 0); break; case tComplex64: NA_SETP(a, Float64, (NA_PTR(a)+offset), v); NA_SETP(a, Float64, (NA_PTR(a)+offset+sizeof(Float64)), 0); break; default: PyErr_Format( PyExc_TypeError, "Unknown type %d in NA_set_Int64", a->descr->type_num); PyErr_Print(); } } /* NA_get_offset computes the offset specified by the set of indices. If N > 0, the indices are taken from the outer dimensions of the array. If N < 0, the indices are taken from the inner dimensions of the array. If N == 0, the offset is 0. */ long NA_get_offset(PyArrayObject *a, int N, ...) { int i; long offset = 0; va_list ap; va_start(ap, N); if (N > 0) { /* compute offset of "outer" indices. */ for(i=0; istrides[i]; } else { /* compute offset of "inner" indices. */ N = -N; for(i=0; istrides[a->nd-N+i]; } va_end(ap); return offset; } Float64 NA_get1_Float64(PyArrayObject *a, long i) { long offset = i * a->strides[0]; return NA_get_Float64(a, offset); } Float64 NA_get2_Float64(PyArrayObject *a, long i, long j) { long offset = i * a->strides[0] + j * a->strides[1]; return NA_get_Float64(a, offset); } Float64 NA_get3_Float64(PyArrayObject *a, long i, long j, long k) { long offset = i * a->strides[0] + j * a->strides[1] + k * a->strides[2]; return NA_get_Float64(a, offset); } void NA_set1_Float64(PyArrayObject *a, long i, Float64 v) { long offset = i * a->strides[0]; NA_set_Float64(a, offset, v); } void NA_set2_Float64(PyArrayObject *a, long i, long j, Float64 v) { long offset = i * a->strides[0] + j * a->strides[1]; NA_set_Float64(a, offset, v); } void NA_set3_Float64(PyArrayObject *a, long i, long j, long k, Float64 v) { long offset = i * a->strides[0] + j * a->strides[1] + k * a->strides[2]; NA_set_Float64(a, offset, v); } Complex64 NA_get1_Complex64(PyArrayObject *a, long i) { long offset = i * a->strides[0]; return NA_get_Complex64(a, offset); } Complex64 NA_get2_Complex64(PyArrayObject *a, long i, long j) { long offset = i * a->strides[0] + j * a->strides[1]; return NA_get_Complex64(a, offset); } Complex64 NA_get3_Complex64(PyArrayObject *a, long i, long j, long k) { long offset = i * a->strides[0] + j * a->strides[1] + k * a->strides[2]; return NA_get_Complex64(a, offset); } void NA_set1_Complex64(PyArrayObject *a, long i, Complex64 v) { long offset = i * a->strides[0]; NA_set_Complex64(a, offset, v); } void NA_set2_Complex64(PyArrayObject *a, long i, long j, Complex64 v) { long offset = i * a->strides[0] + j * a->strides[1]; NA_set_Complex64(a, offset, v); } void NA_set3_Complex64(PyArrayObject *a, long i, long j, long k, Complex64 v) { long offset = i * a->strides[0] + j * a->strides[1] + k * a->strides[2]; NA_set_Complex64(a, offset, v); } Int64 NA_get1_Int64(PyArrayObject *a, long i) { long offset = i * a->strides[0]; return NA_get_Int64(a, offset); } Int64 NA_get2_Int64(PyArrayObject *a, long i, long j) { long offset = i * a->strides[0] + j * a->strides[1]; return NA_get_Int64(a, offset); } Int64 NA_get3_Int64(PyArrayObject *a, long i, long j, long k) { long offset = i * a->strides[0] + j * a->strides[1] + k * a->strides[2]; return NA_get_Int64(a, offset); } void NA_set1_Int64(PyArrayObject *a, long i, Int64 v) { long offset = i * a->strides[0]; NA_set_Int64(a, offset, v); } void NA_set2_Int64(PyArrayObject *a, long i, long j, Int64 v) { long offset = i * a->strides[0] + j * a->strides[1]; NA_set_Int64(a, offset, v); } void NA_set3_Int64(PyArrayObject *a, long i, long j, long k, Int64 v) { long offset = i * a->strides[0] + j * a->strides[1] + k * a->strides[2]; NA_set_Int64(a, offset, v); } /* SET_CMPLX could be made faster by factoring it into 3 seperate loops. */ #define NA_SET_CMPLX(a, type, base, cnt, in) \ { \ int i; \ int stride = a->strides[ a->nd - 1]; \ NA_SET1D(a, type, base, cnt, in); \ base = NA_PTR(a) + offset + sizeof(type); \ for(i=0; idescr->type_num) { case tBool: NA_GET1D(a, Bool, base, cnt, out); break; case tInt8: NA_GET1D(a, Int8, base, cnt, out); break; case tUInt8: NA_GET1D(a, UInt8, base, cnt, out); break; case tInt16: NA_GET1D(a, Int16, base, cnt, out); break; case tUInt16: NA_GET1D(a, UInt16, base, cnt, out); break; case tInt32: NA_GET1D(a, Int32, base, cnt, out); break; case tUInt32: NA_GET1D(a, UInt32, base, cnt, out); break; case tInt64: NA_GET1D(a, Int64, base, cnt, out); break; #if HAS_UINT64 case tUInt64: NA_GET1D(a, UInt64, base, cnt, out); break; #endif case tFloat32: NA_GET1D(a, Float32, base, cnt, out); break; case tFloat64: NA_GET1D(a, Float64, base, cnt, out); break; case tComplex32: NA_GET1D(a, Float32, base, cnt, out); break; case tComplex64: NA_GET1D(a, Float64, base, cnt, out); break; default: PyErr_Format( PyExc_TypeError, "Unknown type %d in NA_get1D_Float64", a->descr->type_num); PyErr_Print(); return -1; } return 0; } static Float64 * NA_alloc1D_Float64(PyArrayObject *a, long offset, int cnt) { Float64 *result = PyMem_New(Float64, cnt); if (!result) return NULL; if (NA_get1D_Float64(a, offset, cnt, result) < 0) { PyMem_Free(result); return NULL; } return result; } static int NA_set1D_Float64(PyArrayObject *a, long offset, int cnt, Float64*in) { char *base = NA_PTR(a) + offset; switch(a->descr->type_num) { case tBool: NA_SET1D(a, Bool, base, cnt, in); break; case tInt8: NA_SET1D(a, Int8, base, cnt, in); break; case tUInt8: NA_SET1D(a, UInt8, base, cnt, in); break; case tInt16: NA_SET1D(a, Int16, base, cnt, in); break; case tUInt16: NA_SET1D(a, UInt16, base, cnt, in); break; case tInt32: NA_SET1D(a, Int32, base, cnt, in); break; case tUInt32: NA_SET1D(a, UInt32, base, cnt, in); break; case tInt64: NA_SET1D(a, Int64, base, cnt, in); break; #if HAS_UINT64 case tUInt64: NA_SET1D(a, UInt64, base, cnt, in); break; #endif case tFloat32: NA_SET1D(a, Float32, base, cnt, in); break; case tFloat64: NA_SET1D(a, Float64, base, cnt, in); break; case tComplex32: NA_SET_CMPLX(a, Float32, base, cnt, in); break; case tComplex64: NA_SET_CMPLX(a, Float64, base, cnt, in); break; default: PyErr_Format( PyExc_TypeError, "Unknown type %d in NA_set1D_Float64", a->descr->type_num); PyErr_Print(); return -1; } return 0; } static int NA_get1D_Int64(PyArrayObject *a, long offset, int cnt, Int64*out) { char *base = NA_PTR(a) + offset; switch(a->descr->type_num) { case tBool: NA_GET1D(a, Bool, base, cnt, out); break; case tInt8: NA_GET1D(a, Int8, base, cnt, out); break; case tUInt8: NA_GET1D(a, UInt8, base, cnt, out); break; case tInt16: NA_GET1D(a, Int16, base, cnt, out); break; case tUInt16: NA_GET1D(a, UInt16, base, cnt, out); break; case tInt32: NA_GET1D(a, Int32, base, cnt, out); break; case tUInt32: NA_GET1D(a, UInt32, base, cnt, out); break; case tInt64: NA_GET1D(a, Int64, base, cnt, out); break; case tUInt64: NA_GET1D(a, UInt64, base, cnt, out); break; case tFloat32: NA_GET1D(a, Float32, base, cnt, out); break; case tFloat64: NA_GET1D(a, Float64, base, cnt, out); break; case tComplex32: NA_GET1D(a, Float32, base, cnt, out); break; case tComplex64: NA_GET1D(a, Float64, base, cnt, out); break; default: PyErr_Format( PyExc_TypeError, "Unknown type %d in NA_get1D_Int64", a->descr->type_num); PyErr_Print(); return -1; } return 0; } static Int64 * NA_alloc1D_Int64(PyArrayObject *a, long offset, int cnt) { Int64 *result = PyMem_New(Int64, cnt); if (!result) return NULL; if (NA_get1D_Int64(a, offset, cnt, result) < 0) { PyMem_Free(result); return NULL; } return result; } static int NA_set1D_Int64(PyArrayObject *a, long offset, int cnt, Int64*in) { char *base = NA_PTR(a) + offset; switch(a->descr->type_num) { case tBool: NA_SET1D(a, Bool, base, cnt, in); break; case tInt8: NA_SET1D(a, Int8, base, cnt, in); break; case tUInt8: NA_SET1D(a, UInt8, base, cnt, in); break; case tInt16: NA_SET1D(a, Int16, base, cnt, in); break; case tUInt16: NA_SET1D(a, UInt16, base, cnt, in); break; case tInt32: NA_SET1D(a, Int32, base, cnt, in); break; case tUInt32: NA_SET1D(a, UInt32, base, cnt, in); break; case tInt64: NA_SET1D(a, Int64, base, cnt, in); break; case tUInt64: NA_SET1D(a, UInt64, base, cnt, in); break; case tFloat32: NA_SET1D(a, Float32, base, cnt, in); break; case tFloat64: NA_SET1D(a, Float64, base, cnt, in); break; case tComplex32: NA_SET_CMPLX(a, Float32, base, cnt, in); break; case tComplex64: NA_SET_CMPLX(a, Float64, base, cnt, in); break; default: PyErr_Format( PyExc_TypeError, "Unknown type %d in NA_set1D_Int64", a->descr->type_num); PyErr_Print(); return -1; } return 0; } static int NA_get1D_Complex64(PyArrayObject *a, long offset, int cnt, Complex64*out) { char *base = NA_PTR(a) + offset; switch(a->descr->type_num) { case tComplex64: NA_GET1D(a, Complex64, base, cnt, out); break; default: PyErr_Format( PyExc_TypeError, "Unsupported type %d in NA_get1D_Complex64", a->descr->type_num); PyErr_Print(); return -1; } return 0; } static int NA_set1D_Complex64(PyArrayObject *a, long offset, int cnt, Complex64*in) { char *base = NA_PTR(a) + offset; switch(a->descr->type_num) { case tComplex64: NA_SET1D(a, Complex64, base, cnt, in); break; default: PyErr_Format( PyExc_TypeError, "Unsupported type %d in NA_set1D_Complex64", a->descr->type_num); PyErr_Print(); return -1; } return 0; } #if LP64 #define PlatBigInt PyInt_FromLong #define PlatBigUInt PyLong_FromUnsignedLong #else #define PlatBigInt PyLong_FromLongLong #define PlatBigUInt PyLong_FromUnsignedLongLong #endif static int _checkOffset(PyArrayObject *a, long offset) { long finaloffset = a->byteoffset + offset; long size = getBufferSize(a->_data); if (size < 0) { PyErr_Format(_Error, "can't get buffer size"); return -1; } if (finaloffset < 0 || finaloffset > size) { PyErr_Format(_Error, "invalid buffer offset"); return -1; } return 0; } static PyObject * NA_getPythonScalar(PyArrayObject *a, long offset) { int type = a->descr->type_num; PyObject *rval = NULL; if (_checkOffset(a, offset) < 0) goto _exit; switch(type) { case tBool: case tInt8: case tUInt8: case tInt16: case tUInt16: case tInt32: { Int64 v = NA_get_Int64(a, offset); rval = PyInt_FromLong(v); break; } case tUInt32: { Int64 v = NA_get_Int64(a, offset); rval = PlatBigUInt(v); break; } case tInt64: { Int64 v = NA_get_Int64(a, offset); rval = PlatBigInt( v); break; } case tUInt64: { Int64 v = NA_get_Int64(a, offset); rval = PlatBigUInt( v); break; } case tFloat32: case tFloat64: { Float64 v = NA_get_Float64(a, offset); rval = PyFloat_FromDouble( v ); break; } case tComplex32: case tComplex64: { Complex64 v = NA_get_Complex64(a, offset); rval = PyComplex_FromDoubles(v.r, v.i); break; } default: rval = PyErr_Format(PyExc_TypeError, "NA_getPythonScalar: bad type %d\n", type); } _exit: return rval; } static int _setFromPythonScalarCore(PyArrayObject *a, long offset, PyObject*value, int entries) { Int64 v; if (entries >= 100) { PyErr_Format(PyExc_RuntimeError, "NA_setFromPythonScalar: __tonumtype__ conversion chain too long"); return -1; } else if (PyInt_Check(value)) { v = PyInt_AsLong(value); if (NA_overflow(a, v) < 0) return -1; NA_set_Int64(a, offset, v); } else if (PyLong_Check(value)) { if (a->descr->type_num == tInt64) { v = (Int64) PyLong_AsLongLong( value ); } else if (a->descr->type_num == tUInt64) { v = (UInt64) PyLong_AsUnsignedLongLong( value ); } else if (a->descr->type_num == tUInt32) { v = PyLong_AsUnsignedLong(value); } else { v = PyLong_AsLongLong(value); } if (PyErr_Occurred()) return -1; if (NA_overflow(a, v) < 0) return -1; NA_set_Int64(a, offset, v); } else if (PyFloat_Check(value)) { Float64 v = PyFloat_AsDouble(value); if (NA_overflow(a, v) < 0) return -1; NA_set_Float64(a, offset, v); } else if (PyComplex_Check(value)) { Complex64 vc; vc.r = PyComplex_RealAsDouble(value); vc.i = PyComplex_ImagAsDouble(value); if (NA_overflow(a, vc.r) < 0) return -1; if (NA_overflow(a, vc.i) < 0) return -1; NA_set_Complex64(a, offset, vc); } else if (PyObject_HasAttrString(value, "__tonumtype__")) { int rval; PyObject *type = NA_typeNoToTypeObject(a->descr->type_num); if (!type) return -1; value = PyObject_CallMethod( value, "__tonumtype__", "(N)", type); if (!value) return -1; rval = _setFromPythonScalarCore(a, offset, value, entries+1); Py_DECREF(value); return rval; } else if (PyString_Check(value)) { long size = PyString_Size(value); if ((size <= 0) || (size > 1)) { PyErr_Format( PyExc_ValueError, "NA_setFromPythonScalar: len(string) must be 1."); return -1; } NA_set_Int64(a, offset, *PyString_AsString(value)); } else { PyErr_Format(PyExc_TypeError, "NA_setFromPythonScalar: bad value type."); return -1; } return 0; } static int NA_setFromPythonScalar(PyArrayObject *a, long offset, PyObject *value) { if (_checkOffset(a, offset) < 0) return -1; if (a->flags & WRITABLE) return _setFromPythonScalarCore(a, offset, value, 0); else { PyErr_Format( PyExc_ValueError, "NA_setFromPythonScalar: assigment to readonly array buffer"); return -1; } } static int NA_isPythonScalar(PyObject *o) { int rval; rval = PyInt_Check(o) || PyLong_Check(o) || PyFloat_Check(o) || PyComplex_Check(o) || (PyString_Check(o) && (PyString_Size(o) == 1)); return rval; } static unsigned long NA_elements(PyArrayObject *a) { int i; unsigned long n = 1; for(i = 0; ind; i++) n *= a->dimensions[i]; return n; } staticforward PyTypeObject CfuncType; static void cfunc_dealloc(PyObject* self) { PyObject_Del(self); } static PyObject * cfunc_repr(PyObject *self) { char buf[256]; CfuncObject *me = (CfuncObject *) self; sprintf(buf, "", me->descr.name, (unsigned long ) me->descr.fptr, me->descr.chkself, me->descr.align, me->descr.wantIn, me->descr.wantOut); return PyString_FromString(buf); } /* Call a standard "stride" function ** ** Stride functions always take one input and one output array. ** They can handle n-dimensional data with arbitrary strides (of ** either sign) for both the input and output numarray. Typically ** these functions are used to copy data, byteswap, or align data. ** ** ** It expects the following arguments: ** ** Number of iterations for each dimension as a tuple ** Input Buffer Object ** Offset in bytes for input buffer ** Input strides (in bytes) for each dimension as a tuple ** Output Buffer Object ** Offset in bytes for output buffer ** Output strides (in bytes) for each dimension as a tuple ** An integer (Optional), typically the number of bytes to copy per * element. ** ** Returns None ** ** The arguments expected by the standard stride functions that this ** function calls are: ** ** Number of dimensions to iterate over ** Long int value (from the optional last argument to ** callStrideConvCFunc) ** often unused by the C Function ** An array of long ints. Each is the number of iterations for each ** dimension. NOTE: the previous argument as well as the stride ** arguments are reversed in order with respect to how they are ** used in Python. Fastest changing dimension is the first element ** in the numarray! ** A void pointer to the input data buffer. ** The starting offset for the input data buffer in bytes (long int). ** An array of long int input strides (in bytes) [reversed as with ** the iteration array] ** A void pointer to the output data buffer. ** The starting offset for the output data buffer in bytes (long int). ** An array of long int output strides (in bytes) [also reversed] */ static PyObject * NA_callStrideConvCFuncCore( PyObject *self, int nshape, maybelong *shape, PyObject *inbuffObj, long inboffset, int ninbstrides, maybelong *inbstrides, PyObject *outbuffObj, long outboffset, int noutbstrides, maybelong *outbstrides, long nbytes) { CfuncObject *me = (CfuncObject *) self; CFUNC_STRIDE_CONV_FUNC funcptr; void *inbuffer, *outbuffer; long inbsize, outbsize; maybelong i, lshape[MAXDIM], in_strides[MAXDIM], out_strides[MAXDIM]; maybelong shape_0, inbstr_0, outbstr_0; if (nshape == 0) { /* handle rank-0 numarray. */ nshape = 1; shape = &shape_0; inbstrides = &inbstr_0; outbstrides = &outbstr_0; shape[0] = 1; inbstrides[0] = outbstrides[0] = 0; } for(i=0; idescr.type != CFUNC_STRIDING) return PyErr_Format(PyExc_TypeError, "NA_callStrideConvCFuncCore: problem with cfunc"); if ((inbsize = NA_getBufferPtrAndSize(inbuffObj, 1, &inbuffer)) < 0) return PyErr_Format(_Error, "%s: Problem with input buffer", me->descr.name); if ((outbsize = NA_getBufferPtrAndSize(outbuffObj, 0, &outbuffer)) < 0) return PyErr_Format(_Error, "%s: Problem with output buffer (read only?)", me->descr.name); /* Check buffer alignment and bounds */ if (NA_checkOneStriding(me->descr.name, nshape, lshape, inboffset, in_strides, inbsize, (me->descr.sizes[0] == -1) ? nbytes : me->descr.sizes[0], me->descr.align) || NA_checkOneStriding(me->descr.name, nshape, lshape, outboffset, out_strides, outbsize, (me->descr.sizes[1] == -1) ? nbytes : me->descr.sizes[1], me->descr.align)) return NULL; /* Cast function pointer and perform stride operation */ funcptr = (CFUNC_STRIDE_CONV_FUNC) me->descr.fptr; if ((*funcptr)(nshape-1, nbytes, lshape, inbuffer, inboffset, in_strides, outbuffer, outboffset, out_strides) == 0) { Py_INCREF(Py_None); return Py_None; } else { return NULL; } } static PyObject * callStrideConvCFunc(PyObject *self, PyObject *args) { PyObject *inbuffObj, *outbuffObj, *shapeObj; PyObject *inbstridesObj, *outbstridesObj; CfuncObject *me = (CfuncObject *) self; int nshape, ninbstrides, noutbstrides, nargs; maybelong shape[MAXDIM], inbstrides[MAXDIM], outbstrides[MAXDIM], *outbstrides1 = outbstrides; long inboffset, outboffset, nbytes=0; nargs = PyObject_Length(args); if (!PyArg_ParseTuple(args, "OOlOOlO|l", &shapeObj, &inbuffObj, &inboffset, &inbstridesObj, &outbuffObj, &outboffset, &outbstridesObj, &nbytes)) { return PyErr_Format(_Error, "%s: Problem with argument list", me->descr.name); } nshape = NA_maybeLongsFromIntTuple(MAXDIM, shape, shapeObj); if (nshape < 0) return NULL; ninbstrides = NA_maybeLongsFromIntTuple(MAXDIM, inbstrides, inbstridesObj); if (ninbstrides < 0) return NULL; noutbstrides= NA_maybeLongsFromIntTuple(MAXDIM, outbstrides, outbstridesObj); if (noutbstrides < 0) return NULL; if (nshape && (nshape != ninbstrides)) { return PyErr_Format(_Error, "%s: Missmatch between input iteration and strides tuples", me->descr.name); } if (nshape && (nshape != noutbstrides)) { if (noutbstrides < 1 || outbstrides[ noutbstrides - 1 ])/* allow 0 for reductions. */ return PyErr_Format(_Error, "%s: Missmatch between output " "iteration and strides tuples", me->descr.name); } #if 0 /* reductions slow mode hack... wrong place to do it. */ _dump_hex("shape: ", nshape, shape); _dump_hex("instrides: ", ninbstrides, inbstrides); _dump_hex("outstrides: ", noutbstrides, outbstrides); if (ninbstrides != noutbstrides) { outbstrides1 = outbstrides + (noutbstrides - ninbstrides); noutbstrides = ninbstrides; } #endif return NA_callStrideConvCFuncCore( self, nshape, shape, inbuffObj, inboffset, ninbstrides, inbstrides, outbuffObj, outboffset, noutbstrides, outbstrides1, nbytes); } static int _NA_callStridingHelper(PyObject *aux, long dim, long nnumarray, PyArrayObject *numarray[], char *data[], CFUNC_STRIDED_FUNC f) { int i, j, status=0; dim -= 1; for(i=0; idimensions[dim]; i++) { for (j=0; jstrides[dim]*i; if (dim == 0) status |= f(aux, nnumarray, numarray, data); else status |= _NA_callStridingHelper( aux, dim, nnumarray, numarray, data, f); for (j=0; jstrides[dim]*i; } return status; } static PyObject * callStridingCFunc(PyObject *self, PyObject *args) { CfuncObject *me = (CfuncObject *) self; PyObject *aux; PyArrayObject *numarray[MAXARRAYS]; char *data[MAXARRAYS]; CFUNC_STRIDED_FUNC f; int i; int nnumarray = PySequence_Length(args)-1; if ((nnumarray < 1) || (nnumarray > MAXARRAYS)) return PyErr_Format(_Error, "%s, too many or too few numarray.", me->descr.name); aux = PySequence_GetItem(args, 0); if (!aux) return NULL; for(i=0; idescr.name, i); if (!NA_NDArrayCheck(otemp)) return PyErr_Format(PyExc_TypeError, "%s arg[%d] is not an array.", me->descr.name, i); numarray[i] = (PyArrayObject *) otemp; data[i] = numarray[i]->data; Py_DECREF(otemp); if (!NA_updateDataPtr(numarray[i])) return NULL; } /* Cast function pointer and perform stride operation */ f = (CFUNC_STRIDED_FUNC) me->descr.fptr; if (_NA_callStridingHelper(aux, numarray[0]->nd, nnumarray, numarray, data, f)) { return NULL; } else { Py_INCREF(Py_None); return Py_None; } } /* Convert a standard C numeric value to a Python numeric value. ** ** Handles both nonaligned and/or byteswapped C data. ** ** Input arguments are: ** ** Buffer object that contains the C numeric value. ** Offset (in bytes) into the buffer that the data is located at. ** The size of the C numeric data item in bytes. ** Flag indicating if the C data is byteswapped from the processor's ** natural representation. ** ** Returns a Python numeric value. */ static PyObject * NumTypeAsPyValue(PyObject *self, PyObject *args) { PyObject *bufferObj; long offset, itemsize, byteswap, i, buffersize; Py_complex temp; /* to hold copies of largest possible type */ void *buffer; char *tempptr; CFUNCasPyValue funcptr; CfuncObject *me = (CfuncObject *) self; if (!PyArg_ParseTuple(args, "Olll", &bufferObj, &offset, &itemsize, &byteswap)) return PyErr_Format(_Error, "NumTypeAsPyValue: Problem with argument list"); if ((buffersize = NA_getBufferPtrAndSize(bufferObj, 1, &buffer)) < 0) return PyErr_Format(_Error, "NumTypeAsPyValue: Problem with array buffer"); if (offset < 0) return PyErr_Format(_Error, "NumTypeAsPyValue: invalid negative offset: %d", (int) offset); /* Guarantee valid buffer pointer */ if (offset+itemsize > buffersize) return PyErr_Format(_Error, "NumTypeAsPyValue: buffer too small for offset and itemsize."); /* Do byteswapping. Guarantee double alignment by using temp. */ tempptr = (char *) &temp; if (!byteswap) { for (i=0; idescr.fptr; /* Call function to build PyObject. Bad parameters to this function may render call meaningless, but "temp" guarantees that its safe. */ return (*funcptr)((void *)(&temp)); } /* Convert a Python numeric value to a standard C numeric value. ** ** Handles both nonaligned and/or byteswapped C data. ** ** Input arguments are: ** ** The Python numeric value to be converted. ** Buffer object to contain the C numeric value. ** Offset (in bytes) into the buffer that the data is to be copied to. ** The size of the C numeric data item in bytes. ** Flag indicating if the C data is byteswapped from the processor's ** natural representation. ** ** Returns None */ static PyObject * NumTypeFromPyValue(PyObject *self, PyObject *args) { PyObject *bufferObj, *valueObj; long offset, itemsize, byteswap, i, buffersize; Py_complex temp; /* to hold copies of largest possible type */ void *buffer; char *tempptr; CFUNCfromPyValue funcptr; CfuncObject *me = (CfuncObject *) self; if (!PyArg_ParseTuple(args, "OOlll", &valueObj, &bufferObj, &offset, &itemsize, &byteswap)) return PyErr_Format(_Error, "%s: Problem with argument list", me->descr.name); if ((buffersize = NA_getBufferPtrAndSize(bufferObj, 0, &buffer)) < 0) return PyErr_Format(_Error, "%s: Problem with array buffer (read only?)", me->descr.name); funcptr = (CFUNCfromPyValue) me->descr.fptr; /* Convert python object into "temp". Always safe. */ if (!((*funcptr)(valueObj, (void *)( &temp)))) return PyErr_Format(_Error, "%s: Problem converting value", me->descr.name); /* Check buffer offset. */ if (offset < 0) return PyErr_Format(_Error, "%s: invalid negative offset: %d", me->descr.name, (int) offset); if (offset+itemsize > buffersize) return PyErr_Format(_Error, "%s: buffer too small(%d) for offset(%d) and itemsize(%d)", me->descr.name, (int) buffersize, (int) offset, (int) itemsize); /* Copy "temp" to array buffer. */ tempptr = (char *) &temp; if (!byteswap) { for (i=0; i MAXARGS) return PyErr_Format(PyExc_RuntimeError, "NA_callCUFuncCore: too many parameters"); if (!PyObject_IsInstance(self, (PyObject *) &CfuncType) || me->descr.type != CFUNC_UFUNC) return PyErr_Format(PyExc_TypeError, "NA_callCUFuncCore: problem with cfunc."); for (i=0; idescr.name, (int) offset[i], (int) i); if ((bsizes[i] = NA_getBufferPtrAndSize(BufferObj[i], readonly, (void *) &buffers[i])) < 0) return PyErr_Format(_Error, "%s: Problem with %s buffer[%d].", me->descr.name, readonly ? "read" : "write", (int) i); buffers[i] += offset[i]; bsizes[i] -= offset[i]; /* "shorten" buffer size by offset. */ } ufuncptr = (UFUNC) me->descr.fptr; /* If it's not a self-checking ufunc, check arg count match, buffer size, and alignment for all buffers */ if (!me->descr.chkself && (NA_checkIo(me->descr.name, me->descr.wantIn, me->descr.wantOut, ninargs, noutargs) || NA_checkNCBuffers(me->descr.name, pnargs, niter, (void **) buffers, bsizes, me->descr.sizes, me->descr.iters))) return NULL; /* Since the parameters are valid, call the C Ufunc */ if (!(*ufuncptr)(niter, ninargs, noutargs, (void **)buffers, bsizes)) { Py_INCREF(Py_None); return Py_None; } else { return NULL; } } static PyObject * callCUFunc(PyObject *self, PyObject *args) { PyObject *DataArgs, *ArgTuple; long pnargs, ninargs, noutargs, niter, i; CfuncObject *me = (CfuncObject *) self; PyObject *BufferObj[MAXARGS]; long offset[MAXARGS]; if (!PyArg_ParseTuple(args, "lllO", &niter, &ninargs, &noutargs, &DataArgs)) return PyErr_Format(_Error, "%s: Problem with argument list", me->descr.name); /* check consistency of stated inputs/outputs and supplied buffers */ pnargs = PyObject_Length(DataArgs); if ((pnargs != (ninargs+noutargs)) || (pnargs > MAXARGS)) return PyErr_Format(_Error, "%s: wrong buffer count for function", me->descr.name); /* Unpack buffers and offsets, get data pointers */ for (i=0; idescr.name); } return NA_callCUFuncCore(self, niter, ninargs, noutargs, BufferObj, offset); } /* Handle "calling" the cfunc object at the python level. Dispatch the call to the appropriate python-c wrapper based on the cfunc type. Do this dispatch to avoid having to check that python code didn't somehow create a mismatch between cfunc and wrapper. */ static PyObject * cfunc_call(PyObject *self, PyObject *argsTuple, PyObject *argsDict) { CfuncObject *me = (CfuncObject *) self; switch(me->descr.type) { case CFUNC_UFUNC: return callCUFunc(self, argsTuple); break; case CFUNC_STRIDING: return callStrideConvCFunc(self, argsTuple); break; case CFUNC_NSTRIDING: return callStridingCFunc(self, argsTuple); case CFUNC_FROM_PY_VALUE: return NumTypeFromPyValue(self, argsTuple); break; case CFUNC_AS_PY_VALUE: return NumTypeAsPyValue(self, argsTuple); break; default: return PyErr_Format( _Error, "cfunc_call: Can't dispatch cfunc '%s' with type: %d.", me->descr.name, me->descr.type); } } static PyTypeObject CfuncType = { PyObject_HEAD_INIT(NULL) 0, "Cfunc", sizeof(CfuncObject), 0, cfunc_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ cfunc_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ cfunc_call, /* tp_call */ }; /* CfuncObjects are created at the c-level only. They ensure that each cfunc is called via the correct python-c-wrapper as defined by its CfuncDescriptor. The wrapper, in turn, does conversions and buffer size and alignment checking. Allowing these to be created at the python level would enable them to be created *wrong* at the python level, and thereby enable python code to *crash* python. */ static PyObject* NA_new_cfunc(CfuncDescriptor *cfd) { CfuncObject* cfunc; CfuncType.ob_type = &PyType_Type; /* Should be done once at init. Do now since there is no init. */ cfunc = PyObject_New(CfuncObject, &CfuncType); if (!cfunc) { return PyErr_Format(_Error, "NA_new_cfunc: failed creating '%s'", cfd->name); } cfunc->descr = *cfd; return (PyObject*)cfunc; } static int NA_add_cfunc(PyObject *dict, char *keystr, CfuncDescriptor *descr) { PyObject *c = (PyObject *) NA_new_cfunc(descr); if (!c) return -1; return PyDict_SetItemString(dict, keystr, c); } #define WITHIN32(v, f) (((v) >= f##_MIN32) && ((v) <= f##_MAX32)) #define WITHIN64(v, f) (((v) >= f##_MIN64) && ((v) <= f##_MAX64)) static Bool NA_IeeeMask32( Float32 f, Int32 mask) { Int32 category; UInt32 v = *(UInt32 *) &f; if (v & BIT(31)) { if (WITHIN32(v, NEG_NORMALIZED)) { category = MSK_NEG_NOR; } else if (WITHIN32(v, NEG_DENORMALIZED)) { category = MSK_NEG_DEN; } else if (WITHIN32(v, NEG_SIGNAL_NAN)) { category = MSK_NEG_SNAN; } else if (WITHIN32(v, NEG_QUIET_NAN)) { category = MSK_NEG_QNAN; } else if (v == NEG_INFINITY_MIN32) { category = MSK_NEG_INF; } else if (v == NEG_ZERO_MIN32) { category = MSK_NEG_ZERO; } else if (v == INDETERMINATE_MIN32) { category = MSK_INDETERM; } else { category = MSK_BUG; } } else { if (WITHIN32(v, POS_NORMALIZED)) { category = MSK_POS_NOR; } else if (WITHIN32(v, POS_DENORMALIZED)) { category = MSK_POS_DEN; } else if (WITHIN32(v, POS_SIGNAL_NAN)) { category = MSK_POS_SNAN; } else if (WITHIN32(v, POS_QUIET_NAN)) { category = MSK_POS_QNAN; } else if (v == POS_INFINITY_MIN32) { category = MSK_POS_INF; } else if (v == POS_ZERO_MIN32) { category = MSK_POS_ZERO; } else { category = MSK_BUG; } } return (category & mask) != 0; } static Bool NA_IeeeMask64( Float64 f, Int32 mask) { Int32 category; UInt64 v = *(UInt64 *) &f; if (v & BIT(63)) { if (WITHIN64(v, NEG_NORMALIZED)) { category = MSK_NEG_NOR; } else if (WITHIN64(v, NEG_DENORMALIZED)) { category = MSK_NEG_DEN; } else if (WITHIN64(v, NEG_SIGNAL_NAN)) { category = MSK_NEG_SNAN; } else if (WITHIN64(v, NEG_QUIET_NAN)) { category = MSK_NEG_QNAN; } else if (v == NEG_INFINITY_MIN64) { category = MSK_NEG_INF; } else if (v == NEG_ZERO_MIN64) { category = MSK_NEG_ZERO; } else if (v == INDETERMINATE_MIN64) { category = MSK_INDETERM; } else { category = MSK_BUG; } } else { if (WITHIN64(v, POS_NORMALIZED)) { category = MSK_POS_NOR; } else if (WITHIN64(v, POS_DENORMALIZED)) { category = MSK_POS_DEN; } else if (WITHIN64(v, POS_SIGNAL_NAN)) { category = MSK_POS_SNAN; } else if (WITHIN64(v, POS_QUIET_NAN)) { category = MSK_POS_QNAN; } else if (v == POS_INFINITY_MIN64) { category = MSK_POS_INF; } else if (v == POS_ZERO_MIN64) { category = MSK_POS_ZERO; } else { category = MSK_BUG; } } return (category & mask) != 0; } static Bool NA_IeeeSpecial32( Float32 *f, Int32 *mask) { return NA_IeeeMask32(*f, *mask); } static Bool NA_IeeeSpecial64( Float64 *f, Int32 *mask) { return NA_IeeeMask64(*f, *mask); } static double numarray_zero = 0.0; static double raiseDivByZero(void) { return 1.0/numarray_zero; } static double raiseNegDivByZero(void) { return -1.0/numarray_zero; } static double num_log(double x) { if (x == 0.0) return raiseNegDivByZero(); else return log(x); } static double num_log10(double x) { if (x == 0.0) return raiseNegDivByZero(); else return log10(x); } static double num_pow(double x, double y) { int z = (int) y; if ((x < 0.0) && (y != z)) return raiseDivByZero(); else return pow(x, y); } /* Inverse hyperbolic trig functions from Numeric */ static double num_acosh(double x) { return log(x + sqrt((x-1.0)*(x+1.0))); } static double num_asinh(double xx) { double x; int sign; if (xx < 0.0) { sign = -1; x = -xx; } else { sign = 1; x = xx; } return sign*log(x + sqrt(x*x+1.0)); } static double num_atanh(double x) { return 0.5*log((1.0+x)/(1.0-x)); } /* NUM_CROUND (in numcomplex.h) also calls num_round */ static double num_round(double x) { return (x >= 0) ? floor(x+0.5) : ceil(x-0.5); } /* The following routine is used in the event of a detected integer * ** divide by zero so that a floating divide by zero is generated. * ** This is done since numarray uses the floating point exception * ** sticky bits to detect errors. The last bit is an attempt to * ** prevent optimization of the divide by zero away, the input value * ** should always be 0 * */ static int int_dividebyzero_error(long value, long unused) { double dummy; dummy = 1./numarray_zero; if (dummy) /* to prevent optimizer from eliminating expression */ return 0; else return 1; } /* Likewise for Integer overflows */ #if defined(linux) static int int_overflow_error(Float64 value) { /* For x86_64 */ feraiseexcept(FE_OVERFLOW); return (int) value; } #else static int int_overflow_error(Float64 value) { double dummy; dummy = pow(1.e10, fabs(value/2)); if (dummy) /* to prevent optimizer from eliminating expression */ return (int) value; else return 1; } #endif static int umult64_overflow(UInt64 a, UInt64 b) { UInt64 ah, al, bh, bl, w, x, y, z; ah = (a >> 32); al = (a & 0xFFFFFFFFL); bh = (b >> 32); bl = (b & 0xFFFFFFFFL); /* 128-bit product: z*2**64 + (x+y)*2**32 + w */ w = al*bl; x = bh*al; y = ah*bl; z = ah*bh; /* *c = ((x + y)<<32) + w; */ return z || (x>>32) || (y>>32) || (((x & 0xFFFFFFFFL) + (y & 0xFFFFFFFFL) + (w >> 32)) >> 32); } static int smult64_overflow(Int64 a0, Int64 b0) { UInt64 a, b; UInt64 ah, al, bh, bl, w, x, y, z; /* Convert to non-negative quantities */ if (a0 < 0) { a = -a0; } else { a = a0; } if (b0 < 0) { b = -b0; } else { b = b0; } ah = (a >> 32); al = (a & 0xFFFFFFFFL); bh = (b >> 32); bl = (b & 0xFFFFFFFFL); w = al*bl; x = bh*al; y = ah*bl; z = ah*bh; /* UInt64 c = ((x + y)<<32) + w; if ((a0 < 0) ^ (b0 < 0)) *c = -c; else *c = c */ return z || (x>>31) || (y>>31) || (((x & 0xFFFFFFFFL) + (y & 0xFFFFFFFFL) + (w >> 32)) >> 31); } static PyObject *_Error; void *libnumarray_API[] = { (void*) getBuffer, (void*) isBuffer, (void*) getWriteBufferDataPtr, (void*) isBufferWriteable, (void*) getReadBufferDataPtr, (void*) getBufferSize, (void*) num_log, (void*) num_log10, (void*) num_pow, (void*) num_acosh, (void*) num_asinh, (void*) num_atanh, (void*) num_round, (void*) int_dividebyzero_error, (void*) int_overflow_error, (void*) umult64_overflow, (void*) smult64_overflow, (void*) NA_Done, (void*) NA_NewAll, (void*) NA_NewAllStrides, (void*) NA_New, (void*) NA_Empty, (void*) NA_NewArray, (void*) NA_vNewArray, (void*) NA_ReturnOutput, (void*) NA_getBufferPtrAndSize, (void*) NA_checkIo, (void*) NA_checkOneCBuffer, (void*) NA_checkNCBuffers, (void*) NA_checkOneStriding, (void*) NA_new_cfunc, (void*) NA_add_cfunc, (void*) NA_InputArray, (void*) NA_OutputArray, (void*) NA_IoArray, (void*) NA_OptionalOutputArray, (void*) NA_get_offset, (void*) NA_get_Float64, (void*) NA_set_Float64, (void*) NA_get_Complex64, (void*) NA_set_Complex64, (void*) NA_get_Int64, (void*) NA_set_Int64, (void*) NA_get1_Float64, (void*) NA_get2_Float64, (void*) NA_get3_Float64, (void*) NA_set1_Float64, (void*) NA_set2_Float64, (void*) NA_set3_Float64, (void*) NA_get1_Complex64, (void*) NA_get2_Complex64, (void*) NA_get3_Complex64, (void*) NA_set1_Complex64, (void*) NA_set2_Complex64, (void*) NA_set3_Complex64, (void*) NA_get1_Int64, (void*) NA_get2_Int64, (void*) NA_get3_Int64, (void*) NA_set1_Int64, (void*) NA_set2_Int64, (void*) NA_set3_Int64, (void*) NA_get1D_Float64, (void*) NA_set1D_Float64, (void*) NA_get1D_Int64, (void*) NA_set1D_Int64, (void*) NA_get1D_Complex64, (void*) NA_set1D_Complex64, (void*) NA_ShapeEqual, (void*) NA_ShapeLessThan, (void*) NA_ByteOrder, (void*) NA_IeeeSpecial32, (void*) NA_IeeeSpecial64, (void*) NA_updateDataPtr, (void*) NA_typeNoToName, (void*) NA_nameToTypeNo, (void*) NA_typeNoToTypeObject, (void*) NA_intTupleFromMaybeLongs, (void*) NA_maybeLongsFromIntTuple, (void*) NA_intTupleProduct, (void*) NA_isIntegerSequence, (void*) NA_setArrayFromSequence, (void*) NA_maxType, (void*) NA_isPythonScalar, (void*) NA_getPythonScalar, (void*) NA_setFromPythonScalar, (void*) NA_NDArrayCheck, (void*) NA_NumArrayCheck, (void*) NA_ComplexArrayCheck, (void*) NA_elements, (void*) NA_typeObjectToTypeNo, (void*) NA_copyArray, (void*) NA_copy, (void*) NA_getType, (void*) NA_callCUFuncCore, (void*) NA_callStrideConvCFuncCore, (void*) NA_stridesFromShape, (void*) NA_OperatorCheck, (void*) NA_ConverterCheck, (void*) NA_UfuncCheck, (void*) NA_CfuncCheck, (void*) NA_getByteOffset, (void*) NA_swapAxes, (void*) NA_initModuleGlobal, (void*) NA_NumarrayType, (void*) NA_NewAllFromBuffer, (void*) NA_alloc1D_Float64, (void*) NA_alloc1D_Int64, (void*) NA_updateAlignment, (void*) NA_updateContiguous, (void*) NA_updateStatus, (void*) NA_NumArrayCheckExact, (void*) NA_NDArrayCheckExact, (void*) NA_OperatorCheckExact, (void*) NA_ConverterCheckExact, (void*) NA_UfuncCheckExact, (void*) NA_CfuncCheckExact, (void*) NA_getArrayData, (void*) NA_updateByteswap, (void*) NA_DescrFromType, (void*) NA_Cast, (void*) NA_checkFPErrors, (void*) NA_clearFPErrors, (void*) NA_checkAndReportFPErrors, (void*) NA_IeeeMask32, (void*) NA_IeeeMask64, (void*) _NA_callStridingHelper, (void*) NA_FromDimsStridesDescrAndData, (void*) NA_FromDimsTypeAndData, (void*) NA_FromDimsStridesTypeAndData, (void*) NA_scipy_typestr, (void*) NA_FromArrayStruct }; #if (!defined(METHOD_TABLE_EXISTS)) static PyMethodDef _libnumarrayMethods[] = { {NULL, NULL} /* Sentinel */ }; #endif /* platform independent*/ #ifdef MS_WIN32 __declspec(dllexport) #endif /* boiler plate API init */ void initlibnumarray(void) { PyObject *m = Py_InitModule("libnumarray", _libnumarrayMethods); PyObject *c_api_object; _Error = PyErr_NewException("numarray.libnumarray.error", NULL, NULL); /* Create a CObject containing the API pointer array's address */ c_api_object = PyCObject_FromVoidPtr((void *)libnumarray_API, NULL); if (c_api_object != NULL) { /* Create a name for this object in the module's namespace */ PyObject *d = PyModule_GetDict(m); PyDict_SetItemString(d, "_C_API", c_api_object); PyDict_SetItemString(d, "error", _Error); Py_DECREF(c_api_object); } else { return; } ADD_VERSION(m); libnumarray_init(); /* module customized init */ }