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