From c6c3f19d4968ca1971830fddfe391a942ec29edb Mon Sep 17 00:00:00 2001 From: Travis Oliphant Date: Tue, 20 Jun 2006 00:45:43 +0000 Subject: Draft of libnumarray C-API. --- numpy/numarray/_capi.c | 5038 +++++++++++++++++++----------------------------- 1 file changed, 2014 insertions(+), 3024 deletions(-) (limited to 'numpy/numarray/_capi.c') diff --git a/numpy/numarray/_capi.c b/numpy/numarray/_capi.c index 0e6b593c2..7c3ac1721 100644 --- a/numpy/numarray/_capi.c +++ b/numpy/numarray/_capi.c @@ -2,181 +2,24 @@ #include #define _libnumarray_MODULE - -#include "Python.h" -#include "pystate.h" #include "libnumarray.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 PyObject *pCfuncClass; static PyTypeObject CfuncType; +static PyObject *pHandleErrorFunc; -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; + static initialized=0; 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; iob_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; + } } -static void -NA_Done(void) +/* 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) { - 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; iob_type->tp_as_buffer != NULL; + Py_DECREF(buf); + } else { + PyErr_Clear(); } + return ans; } -#ifdef MS_WIN32 -#pragma warning(once : 4244) -#endif - -#define ELEM(x) (sizeof(x)/sizeof(x[0])) +/**********************************************************************/ -typedef struct +static int +getWriteBufferDataPtr(PyObject *buffobj, void **buff) { - char *name; - int typeno; -} NumarrayTypeNameMapping; - -static PyArray_Descr descriptors[ ] = { - { tAny, 0, '*'}, - - { tBool, sizeof(Bool), '?'}, - - { tInt8, sizeof(Int8), '1'}, - { tUInt8, sizeof(UInt8), 'b'}, - - { tInt16, sizeof(Int16), 's'}, - { tUInt16, sizeof(UInt16), 'w'}, - - { tInt32, sizeof(Int32), 'i'}, - { tUInt32, sizeof(UInt32), 'u'}, - - { tInt64, sizeof(Int64), 'N'}, - { tUInt64, sizeof(UInt64), 'U'}, - - { tFloat32, sizeof(Float32), 'f'}, - { tFloat64, sizeof(Float64), 'd'}, + 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; +} - { tComplex32, sizeof(Complex32), 'F'}, - { tComplex64, sizeof(Complex64), 'D'} -}; +/**********************************************************************/ -static PyArray_Descr * -NA_DescrFromType(int type) +static int +isBufferWriteable (PyObject *buffobj) { - if ((type >= tAny) && (type <= tComplex64)) { - return &descriptors[ type ]; - } else { - int i; - for(i=0; iob_type->tp_as_buffer->bf_getreadbuffer) + rval = buff2->ob_type->tp_as_buffer->bf_getreadbuffer(buff2, + 0, buff); + Py_DECREF(buff2); + } + return rval; +} - { tInt16, "i2", 2}, - { tUInt16, "u2", 2}, +/**********************************************************************/ - { tInt32, "i4", 4}, - { tUInt32, "u4", 4}, +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; +} - { tInt64, "i8", 8}, - { tUInt64, "u8", 8}, - { tFloat32, "f4", 4}, - { tFloat64, "f8", 8}, +static double numarray_zero = 0.0; - { tComplex32, "c8", 8}, - { tComplex64, "c16", 16} -}; +static double raiseDivByZero(void) +{ + return 1.0/numarray_zero; +} -static PyObject * -setTypeException(int type) +static double raiseNegDivByZero(void) { - /* Check if it is a printable character */ - if ((type >= 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; + return -1.0/numarray_zero; } -static PyObject * -getTypeObject(NumarrayType type) +static double num_log(double x) { - 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); - } + if (x == 0.0) + return raiseNegDivByZero(); + else + return log(x); } -static PyObject * -NA_getType( PyObject *type) +static double num_log10(double x) { - 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; + if (x == 0.0) + return raiseNegDivByZero(); + else + return log10(x); } -/* Look up the NumarrayType which corresponds to typename */ +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); +} -static int -NA_nameToTypeNo(char *typename) +/* Inverse hyperbolic trig functions from Numeric */ +static double num_acosh(double x) { - int i; - for(i=0; i= 0) ? floor(x+0.5) : ceil(x-0.5); +} - /* Handle Numeric typecodes */ - typeObj = NA_typeNoToTypeObject(typeno); - if (!typeObj) return 0; - typeno2 = NA_typeObjectToTypeNo(typeObj); - Py_DECREF(typeObj); - return NA_typeNoToName(typeno2); +/* 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; } -static PyObject * -NA_typeNoToTypeObject(int typeno) +/* 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) { - PyObject *o; - o = getTypeObject(typeno); - if (o) Py_INCREF(o); - return o; + 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 -NA_typeObjectToTypeNo(PyObject *typeObj) +static int smult64_overflow(Int64 a0, Int64 b0) { - int i; - if (deferred_libnumarray_init() < 0) return -1; - for(i=0; i> 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 NumarrayType -_scipy_typekind_to_typeNo(char typekind, int itemsize) + +static void +NA_Done(void) { - int i; - for(i=0; isuffix[0]) && - (itemsize == ts->itemsize)) - return i; - } - PyErr_Format(PyExc_TypeError, - "Unknown __array_struct__ typekind"); - return -1; + return; } -static int -NA_scipy_typestr(NumarrayType t, int byteorder, char *typestr) +static PyArrayObject * +NA_NewAll(int ndim, maybelong *shape, NumarrayType type, + void *buffer, maybelong byteoffset, maybelong bytestride, + int byteorder, int aligned, int writeable) { - int i; - if (byteorder) - strcpy(typestr, ">"); - else - strcpy(typestr, "<"); - for(i=0; itype_num == t) { - strncat(typestr, ts->suffix, 4); - return 0; + 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 -1; + return result; } -static long -NA_isIntegerSequence(PyObject *sequence) +static PyArrayObject * +NA_NewAllStrides(int ndim, maybelong *shape, maybelong *strides, + NumarrayType type, void *buffer, maybelong byteoffset, + int byteorder, int aligned, int writeable) { - 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; istrides[i] = strides[i]; + result->nstrides = ndim; + return result; } -static PyObject * -NA_intTupleFromMaybeLongs(int len, maybelong *Longs) + +static PyArrayObject * +NA_New(void *buffer, NumarrayType type, int ndim, ...) { int i; - PyObject *intTuple = PyTuple_New(len); - if (!intTuple) 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; -} - -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); - 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); + return NA_NewAll(ndim, shape, type, NULL, 0, 0, + NA_ByteOrder(), 1, 1); } -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, ... @@ -932,316 +420,329 @@ NA_NewArray(void *buffer, NumarrayType type, int ndim, ...) return NA_vNewArray(buffer, type, ndim, shape); } -/* Original deprecated versions of new array and empty array */ -static PyArrayObject * -NA_New(void *buffer, NumarrayType type, int ndim, ...) -{ - int i; - maybelong shape[MAXDIM]; - va_list ap; - va_start(ap, ndim); - for(i=0; i out.copyFrom(shadow) */ + Py_DECREF(shadow); + Py_INCREF(Py_None); + rval = Py_None; + return rval; + } } - -/* getArray creates a new array of type 't' from the given array 'a' -using the specified 'method', probably 'new' or 'astype'. */ - -static PyArrayObject * -getArray(PyArrayObject *a, NumarrayType t, char *method) +static long NA_getBufferPtrAndSize(PyObject *buffobj, int readonly, void **ptr) { - char *name; - - if (deferred_libnumarray_init() < 0) return NULL; - - if (t == tAny) - t = a->descr->type_num; - name = NA_typeNoToName(t); - if (!name) return (PyArrayObject *) setTypeException(t); - return (PyArrayObject *) - PyObject_CallMethod((PyObject *) a, method, "s", name); + long rval; + if (readonly) + rval = getReadBufferDataPtr(buffobj, ptr); + else + rval = getWriteBufferDataPtr(buffobj, ptr); + return rval; } -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) { +static int NA_checkIo(char *name, + int wantIn, int wantOut, int gotIn, int gotOut) +{ + if (wantIn != gotIn) { PyErr_Format(_Error, - "getShape: couldn't get sequence length."); + "%s: wrong # of input buffers. Expected %d. Got %d.", + name, wantIn, gotIn); 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."); + if (wantOut != gotOut) { + PyErr_Format(_Error, + "%s: wrong # of output buffers. Expected %d. Got %d.", + name, wantOut, gotOut); return -1; } - return dims; + return 0; } -typedef enum { - NOTHING, - NUMBER, - SEQUENCE -} SequenceConstraint; - -static int -setArrayFromSequence(PyArrayObject *a, PyObject *s, int dim, long offset) +static int NA_checkOneCBuffer(char *name, long niter, + void *buffer, long bsize, size_t typesize) { - SequenceConstraint mustbe = NOTHING; - int i, seqlen=-1, slen = PySequence_Length(s); + Int64 lniter = niter, ltypesize = typesize; - if (dim > a->nd) { - PyErr_Format(PyExc_ValueError, - "setArrayFromSequence: sequence/array dimensions mismatch."); + 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 (slen != a->dimensions[dim]) { - PyErr_Format(PyExc_ValueError, - "setArrayFromSequence: sequence/array shape mismatch."); + 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; +} - 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 int NA_checkOneStriding(char *name, long dim, maybelong *shape, + long offset, maybelong *stride, long buffersize, long itemsize, + int align) +{ + int i; + long omin=offset, omax=offset; + long alignsize = (itemsize <= sizeof(Float64) ? itemsize : sizeof(Float64)); + + if (align && (offset % alignsize)) { + PyErr_Format(_Error, + "%s: buffer not aligned on %d byte boundary.", + name, (int) alignsize); + return -1; + } + 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) { + 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; +} + +/* Function to call standard C Ufuncs +** +** The C Ufuncs expect contiguous 1-d data numarray, input and output numarray +** iterate with standard increments of one data element over all numarray. +** (There are some exceptions like arrayrangexxx which use one or more of +** the data numarray as parameter or other sources of information and do not +** iterate over every buffer). +** +** Arguments: +** +** Number of iterations (simple integer value). +** Number of input numarray. +** Number of output numarray. +** Tuple of tuples, one tuple per input/output array. Each of these +** tuples consists of a buffer object and a byte offset to start. +** +** Returns None +*/ + static PyObject * -NA_setArrayFromSequence(PyArrayObject *a, PyObject *s) +NA_callCUFuncCore(PyObject *self, + long niter, long ninargs, long noutargs, + PyObject **BufferObj, long *offset) { - maybelong shape[MAXDIM]; + CfuncObject *me = (CfuncObject *) self; + char *buffers[MAXARGS]; + long bsizes[MAXARGS]; + long i, pnargs = ninargs + noutargs; + UFUNC ufuncptr; - if (!PySequence_Check(s)) - return PyErr_Format( PyExc_TypeError, - "NA_setArrayFromSequence: (array, seq) expected."); + if (pnargs > MAXARGS) + return PyErr_Format(PyExc_RuntimeError, "NA_callCUFuncCore: too many parameters"); - if (getShape(s, shape, 0) < 0) - return NULL; + if (!PyObject_IsInstance(self, (PyObject *) &CfuncType) + || me->descr.type != CFUNC_UFUNC) + return PyErr_Format(PyExc_TypeError, + "NA_callCUFuncCore: problem with cfunc."); - if (!NA_updateDataPtr(a)) - return NULL; + 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. */ + } - if (setArrayFromSequence(a, s, 0, 0) < 0) + 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; - Py_INCREF(Py_None); - return Py_None; + /* 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 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; +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); +} - 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; - } +/* 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 int -NA_maxType(PyObject *seq) +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) { - int rval; - rval = _NA_maxType(seq, 0); - return rval; + 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; } -NumarrayType -NA_NumarrayType(PyObject *seq) +static int NA_add_cfunc(PyObject *dict, char *keystr, CfuncDescriptor *descr) { - 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; + PyObject *c = (PyObject *) NA_new_cfunc(descr); + if (!c) return -1; + return PyDict_SetItemString(dict, keystr, c); } -/* 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) +NA_InputArray(PyObject *a, NumarrayType t, int requires) { - 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; + PyArray_Descr *descr; + if (type == tAny) descr = NULL; + else descr = PyArray_DescrFromType(type); + return PyArray_CheckFromAny(a, descr, 0, 0, requires, NULL); } /* satisfies ensures that 'a' meets a set of requirements and matches @@ -1267,151 +768,69 @@ satisfies(PyArrayObject *a, int requirements, NumarrayType t) 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; - - a->base = cobj; - - return a; - - _fail: - Py_XDECREF(cobj); - return NULL; +NA_OutputArray(PyObject *a, NumarrayType t, int requires) +{ + PyObject *dtype; + PyArrayObject *ret; + + if (!PyArray_Check(a) || !PyArray_ISWRITEABLE(a)) { + PyErr_Format(PyExc_TypeError, + "NA_OutputArray: only writeable arrays work for output."); + return NULL; + } + + if (satisfies((PyArrayObject *)a, requires, t)) { + Py_INCREF(a); + return a; + } + if (t == tAny) { + dtype = PyArray_DESCR(a); + Py_INCREF(dtype): + } + else { + dtype = PyArray_DescrFromType(t); + } + ret = (PyArrayObject *)PyArray_Empty(PyArray_NDIM(a), PyArray_DIMS(a), + dtype, 0); + ret->flags |= UPDATEIFCOPY; + ret->base = a; + PyArray_FLAGS(a) &= ~WRITEABLE; + Py_INCREF(a); + return ret; } -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. +/* 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. -The contents of the resulting array are undefined, assumed to be filled in by -the caller. +Unlike NA_InputArray, deallocating any resulting temporary array results in a +copy from the temporary back to the original. */ static PyArrayObject * -NA_OutputArray(PyObject *a0, NumarrayType t, int requires) +NA_IoArray(PyObject *a, NumarrayType t, int requires) { - PyArrayObject *a = (PyArrayObject *) a0; + PyArrayObject *shadow = NA_InputArray(a, t, requires | UPDATEIFCOPY ); - if (!NA_NumArrayCheck(a0) || !PyArray_ISWRITABLE(a)) { - PyErr_Format(PyExc_TypeError, - "NA_OutputArray: only writable NumArrays work for output."); - a = NULL; - goto _exit; - } + if (!shadow) return NULL; - 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; + /* 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 array must be writable array"); + PyArray_XDECREF_ERR(shadow); + return NULL; } - _exit: - return a; + + return shadow; } -/* NA_OptionalOutputArray works like NA_ShadowOutput, but handles the case +/* NA_OptionalOutputArray works like NA_OutputArray, 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 @@ -1423,1501 +842,1161 @@ NA_OptionalOutputArray(PyObject *optional, NumarrayType t, int requires, { if ((optional == Py_None) || (optional == NULL)) { PyArrayObject *rval; - rval = getArray(master, t, "new"); + rval = PyArray_FromArray(master, descr, 0); 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) +Complex64 NA_get_Complex64(PyArrayObject *a, long offset) { - 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; - } + Complex32 v0; + Complex64 v; - 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; + 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; } -/* NA_ShapeEqual returns 1 if 'a' and 'b' have the same shape, 0 otherwise. -*/ -static int -NA_ShapeEqual(PyArrayObject *a, PyArrayObject *b) +void NA_set_Complex64(PyArrayObject *a, long offset, Complex64 v) { - 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; -} + Complex32 v0; -/* 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; + 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; } - 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) +Int64 NA_get_Int64(PyArrayObject *a, long offset) { - 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; - } + 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 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; + return 0; /* suppress warning */ } -static int -NA_copyArray(PyArrayObject *to, const PyArrayObject *from) +void NA_set_Int64(PyArrayObject *a, long offset, Int64 v) { - 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; -} + Bool b; -static PyArrayObject * -NA_copy(PyArrayObject *from) -{ - PyArrayObject * rval; - rval = (PyArrayObject *) - PyObject_CallMethod((PyObject *) from, "copy", NULL); - return rval; + 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(); + } } -static void -NA_stridesFromShape(int nshape, maybelong *shape, maybelong bytestride, - maybelong *strides) +/* 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; - if (nshape > 0) { - for(i=0; i=0; i--) - strides[i] = strides[i+1]*shape[i+1]; - } + 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; } -static int -NA_getByteOffset(PyArrayObject *array, int nindices, maybelong *indices, - long *offset) +Float64 NA_get_Float64(PyArrayObject *a, 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]; + 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; + return 0; /* suppress warning */ } -static int -NA_swapAxes(PyArrayObject *array, int x, int y) +void NA_set_Float64(PyArrayObject *a, long offset, Float64 v) { - 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; + Bool b; - if ((x < 0) || (x >= array->nd) || - (y < 0) || (y >= array->nd)) { - PyErr_Format(PyExc_ValueError, - "Specified dimension does not exist"); - return -1; + 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; } - - 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; + case tComplex64: { + NA_SETP(a, Float64, (NA_PTR(a)+offset), v); + NA_SETP(a, Float64, (NA_PTR(a)+offset+sizeof(Float64)), 0); + break; } - 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; + default: + PyErr_Format( PyExc_TypeError, + "Unknown type %d in NA_set_Float64", + a->descr->type_num ); + PyErr_Print(); } - Py_DECREF(module); - Py_INCREF(global); - _exit: - return global; } -static long -_isaligned(PyArrayObject *self) +Float64 NA_get1_Float64(PyArrayObject *a, long i) { - 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; + long offset = i * a->strides[0]; + return NA_get_Float64(a, offset); } -static void -NA_updateAlignment(PyArrayObject *self) +Float64 NA_get2_Float64(PyArrayObject *a, long i, long j) { - if (_isaligned(self)) - self->flags |= ALIGNED; - else - self->flags &= ~ALIGNED; - + long offset = i * a->strides[0] + + j * a->strides[1]; + return NA_get_Float64(a, offset); } -static long -_is_contiguous(PyArrayObject *self, maybelong elements) +Float64 NA_get3_Float64(PyArrayObject *a, long i, long j, long k) { - long i, ndim, nstrides; - - ndim = self->nd; - nstrides = self->nstrides; - - /* rank-0 numarray are always contiguous */ - if (ndim == 0) return 1; + long offset = i * a->strides[0] + + j * a->strides[1] + + k * a->strides[2]; + return NA_get_Float64(a, offset); +} - /* zero-length arrays are also contiguous */ - if (elements == 0) return 1; +void NA_set1_Float64(PyArrayObject *a, long i, Float64 v) +{ + long offset = i * a->strides[0]; + NA_set_Float64(a, offset, v); +} - /* Strides must be in decreasing order. ndim >= 1 */ - for(i=0; istrides[i] != - self->strides[i+1]*self->dimensions[i+1]) - return 0; +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); +} - /* Broadcast numarray have 0 in some stride and are discontiguous */ - for(i=0; istrides[i]) - return 0; +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); +} - if ((self->strides[nstrides-1] == self->itemsize) && - (self->bytestride == self->itemsize)) - return 1; +Complex64 NA_get1_Complex64(PyArrayObject *a, long i) +{ + long offset = i * a->strides[0]; + return NA_get_Complex64(a, offset); +} - if ((self->strides[nstrides-1] == 0) && (nstrides > 1)) - return 1; - - return 0; +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); } -static long -_is_fortran_contiguous(PyArrayObject *self, maybelong elements) +Complex64 NA_get3_Complex64(PyArrayObject *a, long i, long j, long k) { - long i, sd; + long offset = i * a->strides[0] + + j * a->strides[1] + + k * a->strides[2]; + return NA_get_Complex64(a, offset); +} - /* rank-0 numarray are always fortran_contiguous */ - if (self->nd == 0) return 1; +void NA_set1_Complex64(PyArrayObject *a, long i, Complex64 v) +{ + long offset = i * a->strides[0]; + NA_set_Complex64(a, offset, v); +} - /* zero-length arrays are also fortran_contiguous */ - if (elements == 0) return 1; +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); +} - 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]; - } +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); +} - return 1; +Int64 NA_get1_Int64(PyArrayObject *a, long i) +{ + long offset = i * a->strides[0]; + return NA_get_Int64(a, offset); } -static void -NA_updateContiguous(PyArrayObject *self) +Int64 NA_get2_Int64(PyArrayObject *a, long i, long j) { - 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; + long offset = i * a->strides[0] + + j * a->strides[1]; + return NA_get_Int64(a, offset); } -static int -_isbyteswapped(PyArrayObject *self) +Int64 NA_get3_Int64(PyArrayObject *a, long i, long j, long k) { - int syslittle = (NA_ByteOrder() == NUM_LITTLE_ENDIAN); - int selflittle = (self->byteorder == NUM_LITTLE_ENDIAN); - int byteswapped = (syslittle != selflittle); - return byteswapped; + long offset = i * a->strides[0] + + j * a->strides[1] + + k * a->strides[2]; + return NA_get_Int64(a, offset); } -static void -NA_updateByteswap(PyArrayObject *self) +void NA_set1_Int64(PyArrayObject *a, long i, Int64 v) { - if (!_isbyteswapped(self)) - self->flags |= NOTSWAPPED; - else - self->flags &= ~NOTSWAPPED; + long offset = i * a->strides[0]; + NA_set_Int64(a, offset, v); } -static void -NA_updateStatus(PyArrayObject *self) +void NA_set2_Int64(PyArrayObject *a, long i, long j, Int64 v) { - NA_updateAlignment(self); - NA_updateContiguous(self); - NA_updateByteswap(self); + long offset = i * a->strides[0] + + j * a->strides[1]; + NA_set_Int64(a, offset, v); } -static char * -NA_getArrayData(PyArrayObject *obj) +void NA_set3_Int64(PyArrayObject *a, long i, long j, long k, Int64 v) { - if (!NA_NDArrayCheck((PyObject *) obj)) { - PyErr_Format(PyExc_TypeError, - "expected an NDArray"); - } - if (!NA_updateDataPtr(obj)) - return NULL; - return obj->data; + long offset = i * a->strides[0] + + j * a->strides[1] + + k * a->strides[2]; + NA_set_Int64(a, offset, v); } -/* The following function has much platform dependent code since -** there is no platform-independent way of checking Floating Point -** status bits +/* SET_CMPLX could be made faster by factoring it into 3 seperate loops. */ - -/* 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; +#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; i -#elif defined(__CYGWIN__) -#include -#endif - -static int -NA_checkFPErrors(void) +static int +NA_get1D_Float64(PyArrayObject *a, long offset, int cnt, Float64*out) { - 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 + char *base = NA_PTR(a) + offset; -static int -NA_checkFPErrors(void) -{ + 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; + #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; } -#endif - -static void -NA_clearFPErrors() +static Float64 * +NA_alloc1D_Float64(PyArrayObject *a, long offset, int cnt) { - NA_checkFPErrors(); + 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_checkAndReportFPErrors(char *name) +NA_set1D_Float64(PyArrayObject *a, long offset, int cnt, Float64*in) { - 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 */ + 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; } -/**********************************************************************/ -/* Buffer Utility Functions */ -/**********************************************************************/ - -static PyObject * -getBuffer( PyObject *obj) +static int +NA_get1D_Int64(PyArrayObject *a, long offset, int cnt, Int64*out) { - 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; - } -} + char *base = NA_PTR(a) + offset; -/* 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(); + 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 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; + return 0; } -static long NA_getBufferPtrAndSize(PyObject *buffobj, int readonly, void **ptr) +static Int64 * +NA_alloc1D_Int64(PyArrayObject *a, long offset, int cnt) { - long rval; - if (readonly) - rval = getReadBufferDataPtr(buffobj, ptr); - else - rval = getWriteBufferDataPtr(buffobj, ptr); - return rval; + 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_checkOneCBuffer(char *name, long niter, - void *buffer, long bsize, size_t typesize) +static int +NA_set1D_Int64(PyArrayObject *a, long offset, int cnt, Int64*in) { - Int64 lniter = niter, ltypesize = typesize; + char *base = NA_PTR(a) + offset; - 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); + 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_checkIo(char *name, - int wantIn, int wantOut, int gotIn, int gotOut) +static int +NA_get1D_Complex64(PyArrayObject *a, long offset, int cnt, Complex64*out) { - 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); + 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_checkNCBuffers(char *name, int N, long niter, - void **buffers, long *bsizes, - Int8 *typesizes, Int8 *iters) +static int +NA_set1D_Complex64(PyArrayObject *a, long offset, int cnt, Complex64*in) { - int i; - for (i=0; idescr->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 0 -static void -_dump_hex(char *name, int ndata, maybelong *data) +/* NA_ShapeEqual returns 1 if 'a' and 'b' have the same shape, 0 otherwise. +*/ +static int +NA_ShapeEqual(PyArrayObject *a, PyArrayObject *b) { int i; - fprintf(stderr, name); - 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); + + if (!NA_NDArrayCheck((PyObject *) a) || + !NA_NDArrayCheck((PyObject*) b)) { + PyErr_Format( + PyExc_TypeError, + "NA_ShapeEqual: non-array as parameter."); + return -1; } - return 0; /* suppress warning */ + if (a->nd != b->nd) + return 0; + for(i=0; ind; i++) + if (a->dimensions[i] != b->dimensions[i]) + return 0; + return 1; } -void NA_set_Float64(PyArrayObject *a, long offset, Float64 v) +/* 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) { - 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(); + 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; } static int -NA_overflow(PyArrayObject *a, Float64 v) +NA_ByteOrder(void) { - 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; + unsigned long byteorder_test; + byteorder_test = 1; + if (*((char *) &byteorder_test)) + return NUM_LITTLE_ENDIAN; + else + return NUM_BIG_ENDIAN; } -Complex64 NA_get_Complex64(PyArrayObject *a, long offset) +static Bool +NA_IeeeSpecial32( Float32 *f, Int32 *mask) { - 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; + return NA_IeeeMask32(*f, *mask); } -void NA_set_Complex64(PyArrayObject *a, long offset, Complex64 v) +static Bool +NA_IeeeSpecial64( Float64 *f, Int32 *mask) { - Complex32 v0; + return NA_IeeeMask64(*f, *mask); +} - 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; - } +static PyArrayObject * +NA_updateDataPtr(PyArrayObject *me) +{ + return me; } -Int64 NA_get_Int64(PyArrayObject *a, long offset) + +#define ELEM(x) (sizeof(x)/sizeof(x[0])) + +typedef struct { - 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 */ -} + char *name; + int typeno; +} NumarrayTypeNameMapping; -void NA_set_Int64(PyArrayObject *a, long offset, Int64 v) -{ - Bool b; +static NumarrayTypeNameMapping NumarrayTypeNameMap[] = { + {"Any", tAny}, + {"Bool", tBool}, + {"Int8", tInt8}, + {"UInt8", tUInt8}, + {"Int16", tInt16}, + {"UInt16", tUInt16}, + {"Int32", tInt32}, + {"UInt32", tUInt32}, + {"Int64", tInt64}, + {"UInt64", tUInt64}, + {"Float32", tFloat32}, + {"Float64", tFloat64}, + {"Complex32", tComplex32}, + {"Complex64", tComplex64}, + {"Object", tObject}, + {"Long", tLong}, +}; - 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, ...) +/* Convert NumarrayType 'typeno' into the string of the type's name. */ +static char * +NA_typeNoToName(int typeno) { 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; -} + PyObject *typeObj; + int typeno2; -Float64 NA_get1_Float64(PyArrayObject *a, long i) -{ - long offset = i * a->strides[0]; - return NA_get_Float64(a, offset); -} + for(i=0; istrides[0] - + j * a->strides[1]; - return NA_get_Float64(a, offset); + /* Handle Numeric typecodes */ + typeObj = NA_typeNoToTypeObject(typeno); + if (!typeObj) return 0; + typeno2 = NA_typeObjectToTypeNo(typeObj); + Py_DECREF(typeObj); + + return NA_typeNoToName(typeno2); } -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); -} +/* Look up the NumarrayType which corresponds to typename */ -void NA_set1_Float64(PyArrayObject *a, long i, Float64 v) +static int +NA_nameToTypeNo(char *typename) { - long offset = i * a->strides[0]; - NA_set_Float64(a, offset, v); + int i; + for(i=0; istrides[0] - + j * a->strides[1]; - NA_set_Float64(a, offset, v); + /* Check if it is a printable character */ + if ((type >= 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; } -void NA_set3_Float64(PyArrayObject *a, long i, long j, long k, Float64 v) +static PyObject * +getTypeObject(NumarrayType type) { - long offset = i * a->strides[0] - + j * a->strides[1] - + k * a->strides[2]; - NA_set_Float64(a, offset, v); + return PyArray_DescrFromType(type) } -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) +static PyObject * +NA_typeNoToTypeObject(int typeno) { - long offset = i * a->strides[0] - + j * a->strides[1]; - return NA_get_Complex64(a, offset); + PyObject *o; + o = getTypeObject(typeno); + if (o) Py_INCREF(o); + return o; } -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) +static PyObject * +NA_intTupleFromMaybeLongs(int len, maybelong *Longs) { - long offset = i * a->strides[0]; - NA_set_Complex64(a, offset, v); + return PyArray_IntTupleFromIntp(len, Longs); } -void NA_set2_Complex64(PyArrayObject *a, long i, long j, Complex64 v) +static long +NA_maybeLongsFromIntTuple(int len, maybelong *arr, PyObject *sequence) { - long offset = i * a->strides[0] - + j * a->strides[1]; - NA_set_Complex64(a, offset, v); + return PyArray_IntpFromSequence(sequence, arr, len); } -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) +static int +NA_intTupleProduct(PyObject *shape, long *prod) { - long offset = i * a->strides[0]; - return NA_get_Int64(a, offset); -} + int i, nshape, rval = -1; -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); + if (!PySequence_Check(shape)) { + PyErr_Format(PyExc_TypeError, + "NA_intSequenceProduct: object is not a sequence."); + goto _exit; + } + nshape = PySequence_Size(shape); + + for(i=0, *prod=1; istrides[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(); + if (PyString_Check(a)) { + PyErr_Format(PyExc_TypeError, + "getShape: numerical sequences can't contain strings."); 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; + 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; } - return result; + 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; } -static int -NA_set1D_Float64(PyArrayObject *a, long offset, int cnt, Float64*in) + + +typedef enum { + NOTHING, + NUMBER, + SEQUENCE +} SequenceConstraint; + +static int +setArrayFromSequence(PyArrayObject *a, PyObject *s, int dim, long offset) { - char *base = NA_PTR(a) + offset; + SequenceConstraint mustbe = NOTHING; + int i, seqlen=-1, slen = PySequence_Length(s); - 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(); + if (dim > a->nd) { + PyErr_Format(PyExc_ValueError, + "setArrayFromSequence: sequence/array dimensions mismatch."); 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(); + 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 Int64 * -NA_alloc1D_Int64(PyArrayObject *a, long offset, int cnt) +static PyObject * +NA_setArrayFromSequence(PyArrayObject *a, PyObject *s) { - Int64 *result = PyMem_New(Int64, cnt); - if (!result) return NULL; - if (NA_get1D_Int64(a, offset, cnt, result) < 0) { - PyMem_Free(result); + 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; - } - return result; + + if (!NA_updateDataPtr(a)) + return NULL; + + if (setArrayFromSequence(a, s, 0, 0) < 0) + return NULL; + + Py_INCREF(Py_None); + return Py_None; } +enum { + BOOL_SCALAR, + INT_SCALAR, + LONG_SCALAR, + FLOAT_SCALAR, + COMPLEX_SCALAR +}; + + static int -NA_set1D_Int64(PyArrayObject *a, long offset, int cnt, Int64*in) +_NA_maxType(PyObject *seq, int limit) { - 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(); + if (limit > MAXDIM) { + PyErr_Format( PyExc_ValueError, + "NA_maxType: sequence nested too deep." ); return -1; } - return 0; -} + 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; -static int -NA_get1D_Complex64(PyArrayObject *a, long offset, int cnt, Complex64*out) -{ - char *base = NA_PTR(a) + offset; + slen = PySequence_Length(seq); + if (slen < 0) return -1; - 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; + 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; + } } - return 0; } static int -NA_set1D_Complex64(PyArrayObject *a, long offset, int cnt, Complex64*in) +NA_maxType(PyObject *seq) { - char *base = NA_PTR(a) + offset; + int rval; + rval = _NA_maxType(seq, 0); + return rval; +} - 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; +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; } -#if LP64 +#if (SIZEOF_INTP == 8) #define PlatBigInt PyInt_FromLong #define PlatBigUInt PyLong_FromUnsignedLong #else @@ -3080,17 +2159,32 @@ NA_setFromPythonScalar(PyArrayObject *a, long offset, PyObject *value) 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)); +} + + +static int +NA_NDArrayCheck(PyObject *obj) { + return PyArray_Check(obj); +} + +static int +NA_NumArrayCheck(PyObject *obj) { + return PyArray_Check(obj); +} + +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; } @@ -3104,26 +2198,42 @@ NA_elements(PyArrayObject *a) return n; } -staticforward PyTypeObject CfuncType; +static int +NA_typeObjectToTypeNo(PyObject *typeObj) +{ + PyArray_Descr *dtype; + int i; + if (PyArray_DescrConverter(typeObj, &dtype) == PY_FAIL) i=-1; + else i=dtype->type_num; + return i; +} + +static int +NA_copyArray(PyArrayObject *to, const PyArrayObject *from) +{ + PyArrayObject *from0 = from; + return PyArray_CopyInto(to, from0); +} -static void -cfunc_dealloc(PyObject* self) +static PyArrayObject * +NA_copy(PyArrayObject *from) { - PyObject_Del(self); + return (PyArrayObject *)PyArray_NewCopy(from, 0); } + static PyObject * -cfunc_repr(PyObject *self) +NA_getType( PyObject *type) { - 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); + PyArray_Descr *typeobj = NULL; + if (!type && PyArray_DescrConverter(type, &typeobj) == PY_FAIL) { + PyErr_Format(PyExc_ValueError, "NA_getType: unknown type."); + typeobj = NULL; + } + return typeobj; } + /* Call a standard "stride" function ** ** Stride functions always take one input and one output array. @@ -3239,453 +2349,402 @@ NA_callStrideConvCFuncCore( } } -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); - } +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]; + } +} - nshape = NA_maybeLongsFromIntTuple(MAXDIM, shape, shapeObj); - if (nshape < 0) return NULL; - - ninbstrides = NA_maybeLongsFromIntTuple(MAXDIM, inbstrides, inbstridesObj); - if (ninbstrides < 0) return NULL; +static int +NA_OperatorCheck(PyObject *op) { + return 0; +} - noutbstrides= NA_maybeLongsFromIntTuple(MAXDIM, outbstrides, outbstridesObj); - if (noutbstrides < 0) return NULL; +static int +NA_ConverterCheck(PyObject *op) { + return 0; +} - if (nshape && (nshape != ninbstrides)) { - return PyErr_Format(_Error, - "%s: Missmatch between input iteration and strides tuples", - me->descr.name); - } +static int +NA_UfuncCheck(PyObject *op) { + return 0; +} - 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 +static int +NA_CfuncCheck(PyObject *op) { + return PyObject_TypeCheck(ob, &CfuncType); +} + +static int +NA_getByteOffset(PyArrayObject *array, int nindices, maybelong *indices, + long *offset) +{ + 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; - return NA_callStrideConvCFuncCore( - self, nshape, shape, - inbuffObj, inboffset, ninbstrides, inbstrides, - outbuffObj, outboffset, noutbstrides, outbstrides1, nbytes); + PyArray_UpdateFlags(array, UPDATE_ALL_FLAGS); + + return 0; } -static int -_NA_callStridingHelper(PyObject *aux, long dim, - long nnumarray, PyArrayObject *numarray[], char *data[], - CFUNC_STRIDED_FUNC f) +static PyObject * +NA_initModuleGlobal(char *modulename, char *globalname) { - 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; + PyObject *module, *dict, *global = NULL; + module = PyImport_ImportModule(modulename); + if (!module) { + PyErr_Format(PyExc_RuntimeError, + "Can't import '%s' module", + modulename); + goto _exit; } - return status; + 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; +} + +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; +} + +/* ignores bytestride */ +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; + PyArray_Descr *dtype; + + if (type == tAny) + type = tDefault; + + dtype = PyArray_DescrFromType(type); + if (dtype == NULL) return NULL; + + if (byteorder != NA_ByteOrder()) { + PyArray_Descr *temp; + temp = PyArray_DescrNewByteorder(dtype, PyArray_SWAP); + Py_DECREF(dtype); + if (temp == NULL) return NULL; + dtype = temp; + } + + if (bufferObject == Py_None || bufferObject == NULL) { + self = PyArray_NewFromDescr(&PyArray_Type, dtype, + ndim, shape, NULL, NULL, 0, NULL); + } + else { + intp size = dtype->elsize; + int i; + for(i=0; ind; i++) { + size *= self->dimensions[i]; + } + self = PyArray_FromBuffer(bufferObject, dtype, size, byteoffset); + } + + return self; +} + +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 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 void +NA_updateAlignment(PyArrayObject *self) +{ + return PyArray_UpdateFlags(self, ALIGNED); +} + +static void +NA_updateContiguous(PyArrayObject *self) +{ + return PyArray_UpdateFlags(self, CONTIGUOUS | FORTRAN); +} + + +static void +NA_updateStatus(PyArrayObject *self) +{ + return PyArray_UpdateFlags(self, UPDATE_ALL_FLAGS); +} + +static int +NA_NumArrayCheckExact(PyObject *op) { + return (op->ob_type == &PyArray_Type); +} + +static int +NA_NDArrayCheckExact(PyObject *op) { + return (op->ob_type == &PyArray_Type); +} + +static int +NA_OperatorCheckExact(PyObject *op) { + return 0; +} + +static int +NA_ConverterCheckExact(PyObject *op) { + return 0; +} + +static int +NA_UfuncCheckExact(PyObject *op) { + return 0; +} + + +static int +NA_CfuncCheckExact(PyObject *op) { + return op->ob_type == &CfuncType; +} + +static char * +NA_getArrayData(PyArrayObject *obj) +{ + if (!NA_NDArrayCheck((PyObject *) obj)) { + PyErr_Format(PyExc_TypeError, + "expected an NDArray"); + } + return obj->data; +} + +/* Byteswap is not a flag of the array --- it is implicit in the data-type */ +static void +NA_updateByteswap(PyArrayObject *self) +{ + return; } +static PyArray_Descr * +NA_DescrFromType(int type) +{ + if (type == tAny) + type = tDefault; + return PyArray_DescrFromType(type); +} -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; - } +static PyObject * +NA_Cast(PyArrayObject *a, int type) +{ + return PyArray_Cast(a, type); } -/* 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."); +/* The following function has much platform dependent code since +** there is no platform-independent way of checking Floating Point +** status bits +*/ - /* Do byteswapping. Guarantee double alignment by using temp. */ - tempptr = (char *) &temp; - if (!byteswap) { - for (i=0; idescr.fptr; +static int +NA_checkFPErrors(void) +{ + unsigned long fpstatus; + int retstatus; - /* Call function to build PyObject. Bad parameters to this function - may render call meaningless, but "temp" guarantees that its safe. */ - return (*funcptr)((void *)(&temp)); -} +#include /* Should migrate to global scope */ -/* 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 -*/ + 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); -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 - if (pnargs > MAXARGS) - return PyErr_Format(PyExc_RuntimeError, "NA_callCUFuncCore: too many parameters"); +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); - 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); + return retstatus; } +/* Solaris --------------------------------------------------------*/ +/* --------ignoring SunOS ieee_flags approach, someone else can +** deal with that! */ +#elif defined(sun) +#include -/* 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) +static int +NA_checkFPErrors(void) { - 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); - } + 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; } -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 */ -}; +#elif defined(linux) || defined(darwin) || defined(__CYGWIN__) +#if defined(__GLIBC__) || defined(darwin) || defined(__MINGW32__) +#include +#elif defined(__CYGWIN__) +#include +#endif -/* 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) +static int +NA_checkFPErrors(void) { - CfuncObject* cfunc; - - CfuncType.ob_type = &PyType_Type; /* Should be done once at init. - Do now since there is no init. */ + 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; +} - cfunc = PyObject_New(CfuncObject, &CfuncType); - - if (!cfunc) { - return PyErr_Format(_Error, - "NA_new_cfunc: failed creating '%s'", - cfd->name); - } +#else - cfunc->descr = *cfd; +static int +NA_checkFPErrors(void) +{ + return 0; +} - return (PyObject*)cfunc; +#endif + +static void +NA_clearFPErrors() +{ + NA_checkFPErrors(); } -static int NA_add_cfunc(PyObject *dict, char *keystr, CfuncDescriptor *descr) +/* Not supported yet */ +static int +NA_checkAndReportFPErrors(char *name) { - PyObject *c = (PyObject *) NA_new_cfunc(descr); - if (!c) return -1; - return PyDict_SetItemString(dict, keystr, c); + int error = NA_checkFPErrors(); + if (error) { + PyObject *ans; + char msg[128]; + 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; + } @@ -3780,174 +2839,107 @@ NA_IeeeMask64( Float64 f, Int32 mask) 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) +static int +_NA_callStridingHelper(PyObject *aux, long dim, + long nnumarray, PyArrayObject *numarray[], char *data[], + CFUNC_STRIDED_FUNC f) { - return -1.0/numarray_zero; + 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 double num_log(double x) +static PyArrayObject * +NA_FromDimsStridesDescrAndData(int nd, maybelong *d, maybelong *s, PyArray_Descr *descr, char *data) { - if (x == 0.0) - return raiseNegDivByZero(); - else - return log(x); + return PyArray_NewFromDescr(&PyArray_Type, descr, nd, d, s, data, 0, NULL); } -static double num_log10(double x) +static PyArrayObject * +NA_FromDimsTypeAndData(int nd, maybelong *d, int type, char *data) { - if (x == 0.0) - return raiseNegDivByZero(); - else - return log10(x); + PyArray_Descr *descr = NA_DescrFromType(type); + return NA_FromDimsStridesDescrAndData(nd, d, NULL, descr, data); } -static double num_pow(double x, double y) +static PyArrayObject * +NA_FromDimsStridesTypeAndData(int nd, maybelong *shape, maybelong *strides, + int type, char *data) { - int z = (int) y; - if ((x < 0.0) && (y != z)) - return raiseDivByZero(); - else - return pow(x, y); + PyArray_Descr *descr = NA_DescrFromType(type); + return NA_FromDimsStridesDescrAndData(nd, shape, strides, descr, data); } -/* 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) +typedef struct { - 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)); -} + NumarrayType type_num; + char suffix[5]; + int itemsize; +} scipy_typestr; -static double num_atanh(double x) -{ - return 0.5*log((1.0+x)/(1.0-x)); -} +static scipy_typestr scipy_descriptors[ ] = { + { tAny, ""}, + + { tBool, "b1", 1}, -/* 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); -} + { tInt8, "i1", 1}, + { tUInt8, "u1", 1}, -/* 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 * -*/ + { tInt16, "i2", 2}, + { tUInt16, "u2", 2}, -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; -} + { tInt32, "i4", 4}, + { tUInt32, "u4", 4}, -/* 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 + { tInt64, "i8", 8}, + { tUInt64, "u8", 8}, -static int umult64_overflow(UInt64 a, UInt64 b) -{ - UInt64 ah, al, bh, bl, w, x, y, z; + { tFloat32, "f4", 4}, + { tFloat64, "f8", 8}, - ah = (a >> 32); - al = (a & 0xFFFFFFFFL); - bh = (b >> 32); - bl = (b & 0xFFFFFFFFL); + { tComplex32, "c8", 8}, + { tComplex64, "c16", 16} +}; - /* 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 +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 int smult64_overflow(Int64 a0, Int64 b0) +static PyArrayObject * +NA_FromArrayStruct(PyObject *obj) { - 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); + return (PyArrayObject *)PyArray_FromStructInterface(obj); } - static PyObject *_Error; void *libnumarray_API[] = { @@ -4090,11 +3082,6 @@ static PyMethodDef _libnumarrayMethods[] = { }; #endif -/* platform independent*/ -#ifdef MS_WIN32 -__declspec(dllexport) -#endif - /* boiler plate API init */ PyMODINIT_FUNC init_capi(void) { @@ -4118,6 +3105,9 @@ PyMODINIT_FUNC init_capi(void) } if (PyModule_AddObject(m, "__version__", PyString_FromString("0.9")) < 0) return; + + if (_import_array() < 0) return; + deferred_libnumarray_init(); return; } -- cgit v1.2.1