Permalink
Fetching contributors…
Cannot retrieve contributors at this time
4902 lines (4390 sloc) 127 KB
/* -*- c -*- */
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "structmember.h"
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE
#define _NPY_NO_DEPRECATIONS /* for NPY_CHAR */
#include "numpy/npy_common.h"
#include "numpy/arrayobject.h"
#include "numpy/arrayscalars.h"
#include "npy_pycompat.h"
#include "numpy/npy_math.h"
#include "numpy/halffloat.h"
#include "npy_config.h"
#include "npy_sort.h"
#include "common.h"
#include "ctors.h"
#include "lowlevel_strided_loops.h"
#include "usertypes.h"
#include "_datetime.h"
#include "arrayobject.h"
#include "alloc.h"
#include "typeinfo.h"
#ifdef NPY_HAVE_SSE2_INTRINSICS
#include <emmintrin.h>
#endif
#include "numpyos.h"
#include <string.h>
#include "cblasfuncs.h"
#include "npy_cblas.h"
#include <limits.h>
#include <assert.h>
/* check for sequences, but ignore the types numpy considers scalars */
static NPY_INLINE npy_bool
PySequence_NoString_Check(PyObject *op) {
return
PySequence_Check(op) &&
!PyString_Check(op) &&
!PyUnicode_Check(op) &&
!PyArray_IsZeroDim(op);
}
/*
*****************************************************************************
** PYTHON TYPES TO C TYPES **
*****************************************************************************
*/
static double
MyPyFloat_AsDouble(PyObject *obj)
{
double ret = 0;
PyObject *num;
if (obj == Py_None) {
return NPY_NAN;
}
num = PyNumber_Float(obj);
if (num == NULL) {
return NPY_NAN;
}
ret = PyFloat_AsDouble(num);
Py_DECREF(num);
return ret;
}
static npy_half
MyPyFloat_AsHalf(PyObject *obj)
{
return npy_double_to_half(MyPyFloat_AsDouble(obj));
}
static PyObject *
MyPyFloat_FromHalf(npy_half h)
{
return PyFloat_FromDouble(npy_half_to_double(h));
}
/* Handle case of assigning from an array scalar in setitem */
static int
convert_to_scalar_and_retry(PyObject *op, void *ov, void *vap,
int (*setitem)(PyObject *op, void *ov, void *vap))
{
PyObject *temp;
assert(PyArray_IsZeroDim(op));
temp = PyArray_ToScalar(PyArray_BYTES((PyArrayObject *)op),
(PyArrayObject *)op);
if (temp == NULL) {
return -1;
}
else {
int res = setitem(temp, ov, vap);
Py_DECREF(temp);
return res;
}
}
/**begin repeat
*
* #Type = Long, LongLong#
* #type = npy_long, npy_longlong#
*/
static @type@
MyPyLong_As@Type@ (PyObject *obj)
{
@type@ ret;
PyObject *num = PyNumber_Long(obj);
if (num == NULL) {
return -1;
}
ret = PyLong_As@Type@(num);
Py_DECREF(num);
return ret;
}
/**end repeat**/
/**begin repeat
*
* #Type = Long, LongLong#
* #type = npy_ulong, npy_ulonglong#
*/
static @type@
MyPyLong_AsUnsigned@Type@ (PyObject *obj)
{
@type@ ret;
PyObject *num = PyNumber_Long(obj);
if (num == NULL) {
return -1;
}
ret = PyLong_AsUnsigned@Type@(num);
if (PyErr_Occurred()) {
PyErr_Clear();
ret = PyLong_As@Type@(num);
}
Py_DECREF(num);
return ret;
}
/**end repeat**/
static npy_longlong
npy_strtoll(const char *str, char **endptr, int base)
{
#if defined HAVE_STRTOLL
return strtoll(str, endptr, base);
#elif defined _MSC_VER
return _strtoi64(str, endptr, base);
#else
/* ok on 64 bit posix */
return PyOS_strtol(str, endptr, base);
#endif
}
static npy_ulonglong
npy_strtoull(const char *str, char **endptr, int base)
{
#if defined HAVE_STRTOULL
return strtoull(str, endptr, base);
#elif defined _MSC_VER
return _strtoui64(str, endptr, base);
#else
/* ok on 64 bit posix */
return PyOS_strtoul(str, endptr, base);
#endif
}
/*
*****************************************************************************
** GETITEM AND SETITEM **
*****************************************************************************
*/
/**begin repeat
*
* #TYPE = BOOL, BYTE, UBYTE, SHORT, USHORT, INT, LONG, UINT, ULONG,
* LONGLONG, ULONGLONG, HALF, FLOAT, DOUBLE#
* #func1 = PyBool_FromLong, PyInt_FromLong*6, PyLong_FromUnsignedLong*2,
* PyLong_FromLongLong, PyLong_FromUnsignedLongLong,
* MyPyFloat_FromHalf, PyFloat_FromDouble*2#
* #func2 = PyObject_IsTrue, MyPyLong_AsLong*6, MyPyLong_AsUnsignedLong*2,
* MyPyLong_AsLongLong, MyPyLong_AsUnsignedLongLong,
* MyPyFloat_AsHalf, MyPyFloat_AsDouble*2#
* #type = npy_bool,
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int,
* npy_long, npy_uint, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double#
* #type1 = long*7, npy_ulong*2, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double#
* #kind = Bool, Byte, UByte, Short, UShort, Int, Long, UInt, ULong,
* LongLong, ULongLong, Half, Float, Double#
*/
static PyObject *
@TYPE@_getitem(void *input, void *vap)
{
PyArrayObject *ap = vap;
char *ip = input;
@type@ t1;
if ((ap == NULL) || PyArray_ISBEHAVED_RO(ap)) {
t1 = *((@type@ *)ip);
return @func1@((@type1@)t1);
}
else {
PyArray_DESCR(ap)->f->copyswap(&t1, ip, PyArray_ISBYTESWAPPED(ap), ap);
return @func1@((@type1@)t1);
}
}
static int
@TYPE@_setitem(PyObject *op, void *ov, void *vap)
{
PyArrayObject *ap = vap;
@type@ temp; /* ensures alignment */
if (PyArray_IsScalar(op, @kind@)) {
temp = ((Py@kind@ScalarObject *)op)->obval;
}
else {
temp = (@type@)@func2@(op);
}
if (PyErr_Occurred()) {
PyObject *type, *value, *traceback;
PyErr_Fetch(&type, &value, &traceback);
if (PySequence_NoString_Check(op)) {
PyErr_SetString(PyExc_ValueError,
"setting an array element with a sequence.");
Py_DECREF(type);
Py_XDECREF(value);
Py_XDECREF(traceback);
}
else {
PyErr_Restore(type, value, traceback);
}
return -1;
}
if (ap == NULL || PyArray_ISBEHAVED(ap))
*((@type@ *)ov)=temp;
else {
PyArray_DESCR(ap)->f->copyswap(ov, &temp, PyArray_ISBYTESWAPPED(ap),
ap);
}
return 0;
}
/**end repeat**/
/**begin repeat
*
* #TYPE = CFLOAT, CDOUBLE#
* #type = npy_float, npy_double#
*/
static PyObject *
@TYPE@_getitem(void *input, void *vap)
{
PyArrayObject *ap = vap;
char *ip = input;
@type@ t1, t2;
if ((ap == NULL) || PyArray_ISBEHAVED_RO(ap)) {
return PyComplex_FromDoubles((double)((@type@ *)ip)[0],
(double)((@type@ *)ip)[1]);
}
else {
int size = sizeof(@type@);
npy_bool swap = PyArray_ISBYTESWAPPED(ap);
copy_and_swap(&t1, ip, size, 1, 0, swap);
copy_and_swap(&t2, ip + size, size, 1, 0, swap);
return PyComplex_FromDoubles((double)t1, (double)t2);
}
}
/**end repeat**/
/**begin repeat
*
* #NAME = CFLOAT, CDOUBLE, CLONGDOUBLE#
* #type = npy_cfloat, npy_cdouble, npy_clongdouble#
* #ftype = npy_float, npy_double, npy_longdouble#
* #kind = CFloat, CDouble, CLongDouble#
*/
static int
@NAME@_setitem(PyObject *op, void *ov, void *vap)
{
PyArrayObject *ap = vap;
Py_complex oop;
@type@ temp;
int rsize;
if (PyArray_IsZeroDim(op)) {
return convert_to_scalar_and_retry(op, ov, vap, @NAME@_setitem);
}
if (PyArray_IsScalar(op, @kind@)){
temp = ((Py@kind@ScalarObject *)op)->obval;
}
else {
if (op == Py_None) {
oop.real = NPY_NAN;
oop.imag = NPY_NAN;
}
else {
oop = PyComplex_AsCComplex (op);
if (PyErr_Occurred()) {
return -1;
}
}
temp.real = (@ftype@) oop.real;
temp.imag = (@ftype@) oop.imag;
}
memcpy(ov, &temp, PyArray_DESCR(ap)->elsize);
if (PyArray_ISBYTESWAPPED(ap)) {
byte_swap_vector(ov, 2, sizeof(@ftype@));
}
rsize = sizeof(@ftype@);
copy_and_swap(ov, &temp, rsize, 2, rsize, PyArray_ISBYTESWAPPED(ap));
return 0;
}
/**end repeat**/
static NPY_INLINE npy_longdouble
string_to_long_double(PyObject*op)
{
char *s;
char *end;
npy_longdouble temp;
PyObject* b;
if (PyUnicode_Check(op)) {
b = PyUnicode_AsUTF8String(op);
if (!b) {
return 0;
}
}
else {
b = op;
Py_XINCREF(b);
}
s = PyBytes_AsString(b);
if (s) {
errno = 0;
temp = NumPyOS_ascii_strtold(s, &end);
if (errno == ERANGE) {
if (PyErr_Warn(PyExc_RuntimeWarning,
"overflow encountered in conversion from string") < 0) {
Py_XDECREF(b);
return 0;
}
/* strtold returns INFINITY of the correct sign. */
}
else if (errno) {
PyErr_Format(PyExc_ValueError,
"invalid literal for long double: %s (%s)",
s,
strerror(errno));
Py_XDECREF(b);
return 0;
}
/* Extra characters at the end of the string, or nothing parsed */
if (end == s || *end) {
PyErr_Format(PyExc_ValueError,
"invalid literal for long double: %s",
s);
Py_XDECREF(b);
return 0;
}
Py_XDECREF(b);
}
else {
/* Probably wasn't a string, try converting it via a python double */
PyErr_Clear();
Py_XDECREF(b);
temp = (npy_longdouble) MyPyFloat_AsDouble(op);
}
return temp;
}
/*
* These return array scalars which are different than other date-types.
*/
static PyObject *
LONGDOUBLE_getitem(void *ip, void *ap)
{
return PyArray_Scalar(ip, PyArray_DESCR((PyArrayObject *)ap), NULL);
}
static int
LONGDOUBLE_setitem(PyObject *op, void *ov, void *vap)
{
PyArrayObject *ap = vap;
/* ensure alignment */
npy_longdouble temp;
if (PyArray_IsZeroDim(op)) {
return convert_to_scalar_and_retry(op, ov, vap, LONGDOUBLE_setitem);
}
if (PyArray_IsScalar(op, LongDouble)) {
temp = ((PyLongDoubleScalarObject *)op)->obval;
}
else {
/* In case something funny happened in PyArray_IsScalar */
if (PyErr_Occurred()) {
return -1;
}
temp = string_to_long_double(op);
}
if (PyErr_Occurred()) {
return -1;
}
if (ap == NULL || PyArray_ISBEHAVED(ap)) {
*((npy_longdouble *)ov) = temp;
}
else {
copy_and_swap(ov, &temp, PyArray_DESCR(ap)->elsize, 1, 0,
PyArray_ISBYTESWAPPED(ap));
}
return 0;
}
static PyObject *
CLONGDOUBLE_getitem(void *ip, void *ap)
{
return PyArray_Scalar(ip, PyArray_DESCR((PyArrayObject *)ap), NULL);
}
/* UNICODE */
static PyObject *
UNICODE_getitem(void *ip, void *vap)
{
PyArrayObject *ap = vap;
Py_ssize_t size = PyArray_ITEMSIZE(ap);
int swap = PyArray_ISBYTESWAPPED(ap);
int align = !PyArray_ISALIGNED(ap);
return (PyObject *)PyUnicode_FromUCS4(ip, size, swap, align);
}
static int
UNICODE_setitem(PyObject *op, void *ov, void *vap)
{
PyArrayObject *ap = vap;
PyObject *temp;
Py_UNICODE *ptr;
int datalen;
#ifndef Py_UNICODE_WIDE
char *buffer;
#endif
if (PyArray_IsZeroDim(op)) {
return convert_to_scalar_and_retry(op, ov, vap, UNICODE_setitem);
}
if (PySequence_NoString_Check(op)) {
PyErr_SetString(PyExc_ValueError,
"setting an array element with a sequence");
return -1;
}
#if defined(NPY_PY3K)
if (PyBytes_Check(op)) {
/* Try to decode from ASCII */
temp = PyUnicode_FromEncodedObject(op, "ASCII", "strict");
if (temp == NULL) {
return -1;
}
}
else if ((temp=PyObject_Str(op)) == NULL) {
#else
if ((temp=PyObject_Unicode(op)) == NULL) {
#endif
return -1;
}
ptr = PyUnicode_AS_UNICODE(temp);
if ((ptr == NULL) || (PyErr_Occurred())) {
Py_DECREF(temp);
return -1;
}
datalen = PyUnicode_GET_DATA_SIZE(temp);
#ifdef Py_UNICODE_WIDE
memcpy(ov, ptr, PyArray_MIN(PyArray_DESCR(ap)->elsize, datalen));
#else
if (!PyArray_ISALIGNED(ap)) {
buffer = PyArray_malloc(PyArray_DESCR(ap)->elsize);
if (buffer == NULL) {
Py_DECREF(temp);
PyErr_NoMemory();
return -1;
}
}
else {
buffer = ov;
}
datalen = PyUCS2Buffer_AsUCS4(ptr, (npy_ucs4 *)buffer,
datalen >> 1, PyArray_DESCR(ap)->elsize >> 2);
datalen <<= 2;
if (!PyArray_ISALIGNED(ap)) {
memcpy(ov, buffer, datalen);
PyArray_free(buffer);
}
#endif
/* Fill in the rest of the space with 0 */
if (PyArray_DESCR(ap)->elsize > datalen) {
memset((char*)ov + datalen, 0, (PyArray_DESCR(ap)->elsize - datalen));
}
if (PyArray_ISBYTESWAPPED(ap)) {
byte_swap_vector(ov, PyArray_DESCR(ap)->elsize >> 2, 4);
}
Py_DECREF(temp);
return 0;
}
/* STRING
*
* can handle both NULL-terminated and not NULL-terminated cases
* will truncate all ending NULLs in returned string.
*/
static PyObject *
STRING_getitem(void *ip, void *vap)
{
PyArrayObject *ap = vap;
/* Will eliminate NULLs at the end */
char *ptr;
int size = PyArray_DESCR(ap)->elsize;
ptr = (char *)ip + size - 1;
while (size > 0 && *ptr-- == '\0') {
size--;
}
return PyBytes_FromStringAndSize(ip,size);
}
static int
STRING_setitem(PyObject *op, void *ov, void *vap)
{
PyArrayObject *ap = vap;
char *ptr;
Py_ssize_t len;
PyObject *temp = NULL;
if (PyArray_IsZeroDim(op)) {
return convert_to_scalar_and_retry(op, ov, vap, STRING_setitem);
}
if (PySequence_NoString_Check(op)) {
PyErr_SetString(PyExc_ValueError,
"setting an array element with a sequence");
return -1;
}
#if defined(NPY_PY3K)
if (PyUnicode_Check(op)) {
/* Assume ASCII codec -- function similarly as Python 2 */
temp = PyUnicode_AsASCIIString(op);
if (temp == NULL) {
return -1;
}
}
else if (PyBytes_Check(op) || PyMemoryView_Check(op)) {
temp = PyObject_Bytes(op);
if (temp == NULL) {
return -1;
}
}
else {
/* Emulate similar casting behavior as on Python 2 */
PyObject *str;
str = PyObject_Str(op);
if (str == NULL) {
return -1;
}
temp = PyUnicode_AsASCIIString(str);
Py_DECREF(str);
if (temp == NULL) {
return -1;
}
}
#else
if ((temp = PyObject_Str(op)) == NULL) {
return -1;
}
#endif
if (PyBytes_AsStringAndSize(temp, &ptr, &len) < 0) {
Py_DECREF(temp);
return -1;
}
memcpy(ov, ptr, PyArray_MIN(PyArray_DESCR(ap)->elsize,len));
/*
* If string length is smaller than room in array
* Then fill the rest of the element size with NULL
*/
if (PyArray_DESCR(ap)->elsize > len) {
memset((char *)ov + len, 0, (PyArray_DESCR(ap)->elsize - len));
}
Py_DECREF(temp);
return 0;
}
/* OBJECT */
#define __ALIGNED(obj, sz) ((((size_t) obj) % (sz))==0)
static PyObject *
OBJECT_getitem(void *ip, void *NPY_UNUSED(ap))
{
PyObject *obj;
NPY_COPY_PYOBJECT_PTR(&obj, ip);
if (obj == NULL) {
Py_RETURN_NONE;
}
else {
Py_INCREF(obj);
return obj;
}
}
static int
OBJECT_setitem(PyObject *op, void *ov, void *NPY_UNUSED(ap))
{
PyObject *obj;
NPY_COPY_PYOBJECT_PTR(&obj, ov);
Py_INCREF(op);
Py_XDECREF(obj);
NPY_COPY_PYOBJECT_PTR(ov, &op);
return PyErr_Occurred() ? -1 : 0;
}
/* VOID */
static PyObject *
VOID_getitem(void *input, void *vap)
{
PyArrayObject *ap = vap;
char *ip = input;
PyArray_Descr* descr;
descr = PyArray_DESCR(ap);
if (PyDataType_HASFIELDS(descr)) {
PyObject *key;
PyObject *names;
int i, n;
PyObject *ret;
PyObject *tup;
int savedflags;
/* get the names from the fields dictionary*/
names = descr->names;
n = PyTuple_GET_SIZE(names);
ret = PyTuple_New(n);
savedflags = PyArray_FLAGS(ap);
for (i = 0; i < n; i++) {
npy_intp offset;
PyArray_Descr *new;
key = PyTuple_GET_ITEM(names, i);
tup = PyDict_GetItem(descr->fields, key);
if (_unpack_field(tup, &new, &offset) < 0) {
Py_DECREF(ret);
((PyArrayObject_fields *)ap)->descr = descr;
return NULL;
}
/*
* TODO: temporarily modifying the array like this
* is bad coding style, should be changed.
*/
((PyArrayObject_fields *)ap)->descr = new;
/* update alignment based on offset */
if ((new->alignment > 1)
&& ((((npy_intp)(ip+offset)) % new->alignment) != 0)) {
PyArray_CLEARFLAGS(ap, NPY_ARRAY_ALIGNED);
}
else {
PyArray_ENABLEFLAGS(ap, NPY_ARRAY_ALIGNED);
}
PyTuple_SET_ITEM(ret, i, PyArray_GETITEM(ap, ip+offset));
((PyArrayObject_fields *)ap)->flags = savedflags;
}
((PyArrayObject_fields *)ap)->descr = descr;
return ret;
}
if (descr->subarray) {
/* return an array of the basic type */
PyArray_Dims shape = {NULL, -1};
PyArrayObject *ret;
if (!(PyArray_IntpConverter(descr->subarray->shape, &shape))) {
npy_free_cache_dim_obj(shape);
PyErr_SetString(PyExc_ValueError,
"invalid shape in fixed-type tuple.");
return NULL;
}
Py_INCREF(descr->subarray->base);
ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type,
descr->subarray->base, shape.len, shape.ptr,
NULL, ip, PyArray_FLAGS(ap)&(~NPY_ARRAY_F_CONTIGUOUS), NULL);
npy_free_cache_dim_obj(shape);
if (!ret) {
return NULL;
}
Py_INCREF(ap);
if (PyArray_SetBaseObject(ret, (PyObject *)ap) < 0) {
Py_DECREF(ret);
return NULL;
}
PyArray_UpdateFlags((PyArrayObject *)ret, NPY_ARRAY_UPDATE_ALL);
return (PyObject *)ret;
}
return PyBytes_FromStringAndSize(PyArray_DATA(ap), descr->elsize);
}
NPY_NO_EXPORT int PyArray_CopyObject(PyArrayObject *, PyObject *);
/* Given a structured PyArrayObject arr, index i and structured datatype descr,
* modify the dtype of arr to contain a single field corresponding to the ith
* field of descr, recompute the alignment flag, and return the offset of the
* field (in offset_p). This is useful in preparation for calling copyswap on
* individual fields of a numpy structure, in VOID_setitem. Compare to inner
* loops in VOID_getitem and VOID_nonzero.
*
* WARNING: Clobbers arr's dtype and alignment flag.
*/
NPY_NO_EXPORT int
_setup_field(int i, PyArray_Descr *descr, PyArrayObject *arr,
npy_intp *offset_p)
{
PyObject *key;
PyObject *tup;
PyArray_Descr *new;
npy_intp offset;
key = PyTuple_GET_ITEM(descr->names, i);
tup = PyDict_GetItem(descr->fields, key);
if (_unpack_field(tup, &new, &offset) < 0) {
return -1;
}
((PyArrayObject_fields *)(arr))->descr = new;
if ((new->alignment > 1) && ((offset % new->alignment) != 0)) {
PyArray_CLEARFLAGS(arr, NPY_ARRAY_ALIGNED);
}
else {
PyArray_ENABLEFLAGS(arr, NPY_ARRAY_ALIGNED);
}
*offset_p = offset;
return 0;
}
/* Helper function for VOID_setitem, which uses the copyswap or casting code to
* copy structured datatypes between numpy arrays or scalars.
*/
static int
_copy_and_return_void_setitem(PyArray_Descr *dstdescr, char *dstdata,
PyArray_Descr *srcdescr, char *srcdata){
PyArrayObject_fields dummy_struct;
PyArrayObject *dummy = (PyArrayObject *)&dummy_struct;
npy_int names_size = PyTuple_GET_SIZE(dstdescr->names);
npy_intp offset;
npy_int i;
int ret;
/* Fast path if dtypes are equal */
if (PyArray_EquivTypes(srcdescr, dstdescr)) {
for (i = 0; i < names_size; i++) {
/* neither line can ever fail, in principle */
if (_setup_field(i, dstdescr, dummy, &offset)) {
return -1;
}
PyArray_DESCR(dummy)->f->copyswap(dstdata + offset,
srcdata + offset, 0, dummy);
}
return 0;
}
/* Slow path */
ret = PyArray_CastRawArrays(1, srcdata, dstdata, 0, 0,
srcdescr, dstdescr, 0);
if (ret != NPY_SUCCEED) {
return -1;
}
return 0;
}
static int
VOID_setitem(PyObject *op, void *input, void *vap)
{
char *ip = input;
PyArrayObject *ap = vap;
PyArray_Descr *descr;
int flags;
int itemsize=PyArray_DESCR(ap)->elsize;
int res;
descr = PyArray_DESCR(ap);
flags = PyArray_FLAGS(ap);
if (PyDataType_HASFIELDS(descr)) {
PyObject *errmsg;
npy_int i;
npy_intp offset;
int failed = 0;
/* If op is 0d-ndarray or numpy scalar, directly get dtype & data ptr */
if (PyArray_Check(op)) {
PyArrayObject *oparr = (PyArrayObject *)op;
if (PyArray_SIZE(oparr) != 1) {
PyErr_SetString(PyExc_ValueError,
"setting an array element with a sequence.");
return -1;
}
return _copy_and_return_void_setitem(descr, ip,
PyArray_DESCR(oparr), PyArray_DATA(oparr));
}
else if (PyArray_IsScalar(op, Void)) {
PyArray_Descr *srcdescr = ((PyVoidScalarObject *)op)->descr;
char *srcdata = ((PyVoidScalarObject *)op)->obval;
return _copy_and_return_void_setitem(descr, ip, srcdescr, srcdata);
}
else if (PyTuple_Check(op)) {
/* if it's a tuple, copy field-by-field to ap, */
npy_intp names_size = PyTuple_GET_SIZE(descr->names);
if (names_size != PyTuple_Size(op)) {
errmsg = PyUString_FromFormat(
"could not assign tuple of length %zd to structure "
"with %" NPY_INTP_FMT " fields.",
PyTuple_Size(op), names_size);
PyErr_SetObject(PyExc_ValueError, errmsg);
Py_DECREF(errmsg);
return -1;
}
for (i = 0; i < names_size; i++) {
PyObject *item;
/* temporarily make ap have only this field */
if (_setup_field(i, descr, ap, &offset) == -1) {
failed = 1;
break;
}
item = PyTuple_GetItem(op, i);
if (item == NULL) {
failed = 1;
break;
}
/* use setitem to set this field */
if (PyArray_SETITEM(ap, ip + offset, item) < 0) {
failed = 1;
break;
}
}
}
else {
/* Otherwise must be non-void scalar. Try to assign to each field */
npy_intp names_size = PyTuple_GET_SIZE(descr->names);
for (i = 0; i < names_size; i++) {
/* temporarily make ap have only this field */
if (_setup_field(i, descr, ap, &offset) == -1) {
failed = 1;
break;
}
/* use setitem to set this field */
if (PyArray_SETITEM(ap, ip + offset, op) < 0) {
failed = 1;
break;
}
}
}
/* reset clobbered attributes */
((PyArrayObject_fields *)(ap))->descr = descr;
((PyArrayObject_fields *)(ap))->flags = flags;
if (failed) {
return -1;
}
return 0;
}
else if (PyDataType_HASSUBARRAY(descr)) {
/* copy into an array of the same basic type */
PyArray_Dims shape = {NULL, -1};
PyArrayObject *ret;
if (!(PyArray_IntpConverter(descr->subarray->shape, &shape))) {
npy_free_cache_dim_obj(shape);
PyErr_SetString(PyExc_ValueError,
"invalid shape in fixed-type tuple.");
return -1;
}
Py_INCREF(descr->subarray->base);
ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type,
descr->subarray->base, shape.len, shape.ptr,
NULL, ip, PyArray_FLAGS(ap), NULL);
npy_free_cache_dim_obj(shape);
if (!ret) {
return -1;
}
Py_INCREF(ap);
if (PyArray_SetBaseObject(ret, (PyObject *)ap) < 0) {
Py_DECREF(ret);
return -1;
}
PyArray_UpdateFlags(ret, NPY_ARRAY_UPDATE_ALL);
res = PyArray_CopyObject(ret, op);
Py_DECREF(ret);
return res;
}
/*
* Fall through case - non-structured void datatype. This is a very
* undiscerning case: It interprets any object as a buffer
* and reads as many bytes as possible, padding with 0.
*/
#if defined(NPY_PY3K)
{
Py_buffer view;
if (PyObject_GetBuffer(op, &view, PyBUF_SIMPLE) < 0) {
return -1;
}
memcpy(ip, view.buf, PyArray_MIN(view.len, itemsize));
if (itemsize > view.len) {
memset(ip + view.len, 0, itemsize - view.len);
}
PyBuffer_Release(&view);
}
#else
{
const void *buffer;
Py_ssize_t buflen;
if (PyObject_AsReadBuffer(op, &buffer, &buflen) < 0) {
return -1;
}
memcpy(ip, buffer, PyArray_MIN(buflen, itemsize));
if (itemsize > buflen) {
memset(ip + buflen, 0, itemsize - buflen);
}
}
#endif
return 0;
}
static PyObject *
DATETIME_getitem(void *ip, void *vap)
{
PyArrayObject *ap = vap;
npy_datetime dt;
PyArray_DatetimeMetaData *meta = NULL;
/* Get the datetime units metadata */
meta = get_datetime_metadata_from_dtype(PyArray_DESCR(ap));
if (meta == NULL) {
return NULL;
}
if ((ap == NULL) || PyArray_ISBEHAVED_RO(ap)) {
dt = *((npy_datetime *)ip);
}
else {
PyArray_DESCR(ap)->f->copyswap(&dt, ip, PyArray_ISBYTESWAPPED(ap), ap);
}
return convert_datetime_to_pyobject(dt, meta);
}
static PyObject *
TIMEDELTA_getitem(void *ip, void *vap)
{
PyArrayObject *ap = vap;
npy_timedelta td;
PyArray_DatetimeMetaData *meta = NULL;
/* Get the datetime units metadata */
meta = get_datetime_metadata_from_dtype(PyArray_DESCR(ap));
if (meta == NULL) {
return NULL;
}
if ((ap == NULL) || PyArray_ISBEHAVED_RO(ap)) {
td = *((npy_timedelta *)ip);
}
else {
PyArray_DESCR(ap)->f->copyswap(&td, ip, PyArray_ISBYTESWAPPED(ap), ap);
}
return convert_timedelta_to_pyobject(td, meta);
}
static int
DATETIME_setitem(PyObject *op, void *ov, void *vap)
{
PyArrayObject *ap = vap;
/* ensure alignment */
npy_datetime temp = 0;
PyArray_DatetimeMetaData *meta = NULL;
/* Get the datetime units metadata */
meta = get_datetime_metadata_from_dtype(PyArray_DESCR(ap));
if (meta == NULL) {
return -1;
}
/* Convert the object into a NumPy datetime */
if (convert_pyobject_to_datetime(meta, op,
NPY_SAME_KIND_CASTING, &temp) < 0) {
return -1;
}
/* Copy the value into the output */
if (ap == NULL || PyArray_ISBEHAVED(ap)) {
*((npy_datetime *)ov)=temp;
}
else {
PyArray_DESCR(ap)->f->copyswap(ov, &temp, PyArray_ISBYTESWAPPED(ap),
ap);
}
return 0;
}
static int
TIMEDELTA_setitem(PyObject *op, void *ov, void *vap)
{
PyArrayObject *ap = vap;
/* ensure alignment */
npy_timedelta temp = 0;
PyArray_DatetimeMetaData *meta = NULL;
/* Get the datetime units metadata */
meta = get_datetime_metadata_from_dtype(PyArray_DESCR(ap));
if (meta == NULL) {
return -1;
}
/* Convert the object into a NumPy datetime */
if (convert_pyobject_to_timedelta(meta, op,
NPY_SAME_KIND_CASTING, &temp) < 0) {
return -1;
}
/* Copy the value into the output */
if (ap == NULL || PyArray_ISBEHAVED(ap)) {
*((npy_timedelta *)ov)=temp;
}
else {
PyArray_DESCR(ap)->f->copyswap(ov, &temp, PyArray_ISBYTESWAPPED(ap),
ap);
}
return 0;
}
/*
*****************************************************************************
** TYPE TO TYPE CONVERSIONS **
*****************************************************************************
*/
/* Assumes contiguous, and aligned, from and to */
/**begin repeat
*
* #TOTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
* LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, DATETIME,
* TIMEDELTA#
* #totype = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_float, npy_double, npy_longdouble,
* npy_datetime, npy_timedelta#
*/
/**begin repeat1
*
* #FROMTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
* LONGLONG, ULONGLONG, FLOAT, DOUBLE, LONGDOUBLE, DATETIME,
* TIMEDELTA#
* #fromtype = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_float, npy_double, npy_longdouble,
* npy_datetime, npy_timedelta#
*/
static void
@FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const @fromtype@ *ip = input;
@totype@ *op = output;
while (n--) {
*op++ = (@totype@)*ip++;
}
}
/**end repeat1**/
/**begin repeat1
*
* #FROMTYPE = CFLOAT, CDOUBLE, CLONGDOUBLE#
* #fromtype = npy_float, npy_double, npy_longdouble#
*/
static void
@FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const @fromtype@ *ip = input;
@totype@ *op = output;
while (n--) {
*op++ = (@totype@)*ip;
ip += 2;
}
}
/**end repeat1**/
/**end repeat**/
/**begin repeat
*
* #TYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, LONG, ULONG,
* LONGLONG, ULONGLONG, LONGDOUBLE, DATETIME,
* TIMEDELTA#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_longdouble,
* npy_datetime, npy_timedelta#
*/
static void
@TYPE@_to_HALF(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const @type@ *ip = input;
npy_half *op = output;
while (n--) {
*op++ = npy_float_to_half((float)(*ip++));
}
}
static void
HALF_to_@TYPE@(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const npy_half *ip = input;
@type@ *op = output;
while (n--) {
*op++ = (@type@)npy_half_to_float(*ip++);
}
}
/**end repeat**/
#if NPY_SIZEOF_SHORT == 2
#define HALF_to_HALF SHORT_to_SHORT
#elif NPY_SIZEOF_INT == 2
#define HALF_to_HALF INT_to_INT
#endif
/**begin repeat
*
* #TYPE = FLOAT, DOUBLE, CFLOAT, CDOUBLE#
* #name = float, double, float, double#
* #itype = npy_uint32, npy_uint64, npy_uint32, npy_uint64#
* #iscomplex = 0, 0, 1, 1#
*/
static void
@TYPE@_to_HALF(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const @itype@ *ip = input;
npy_half *op = output;
while (n--) {
*op++ = npy_@name@bits_to_halfbits(*ip);
#if @iscomplex@
ip += 2;
#else
ip++;
#endif
}
}
static void
HALF_to_@TYPE@(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const npy_half *ip = input;
@itype@ *op = output;
while (n--) {
*op++ = npy_halfbits_to_@name@bits(*ip++);
#if @iscomplex@
*op++ = 0;
#endif
}
}
/**end repeat**/
static void
CLONGDOUBLE_to_HALF(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const npy_longdouble *ip = input;
npy_half *op = output;
while (n--) {
*op++ = npy_double_to_half((double) (*ip++));
ip += 2;
}
}
static void
HALF_to_CLONGDOUBLE(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const npy_half *ip = input;
npy_longdouble *op = output;
while (n--) {
*op++ = npy_half_to_double(*ip++);
*op++ = 0;
}
}
/**begin repeat
*
* #FROMTYPE = BOOL,
* BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* FLOAT, DOUBLE, LONGDOUBLE,
* DATETIME, TIMEDELTA#
* #fromtype = npy_bool,
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_float, npy_double, npy_longdouble,
* npy_datetime, npy_timedelta#
*/
static void
@FROMTYPE@_to_BOOL(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const @fromtype@ *ip = input;
npy_bool *op = output;
while (n--) {
*op++ = (npy_bool)(*ip++ != NPY_FALSE);
}
}
/**end repeat**/
static void
HALF_to_BOOL(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const npy_half *ip = input;
npy_bool *op = output;
while (n--) {
*op++ = (npy_bool)(!npy_half_iszero(*ip++));
}
}
/**begin repeat
*
* #FROMTYPE = CFLOAT, CDOUBLE, CLONGDOUBLE#
* #fromtype = npy_cfloat, npy_cdouble, npy_clongdouble#
*/
static void
@FROMTYPE@_to_BOOL(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const @fromtype@ *ip = input;
npy_bool *op = output;
while (n--) {
*op = (npy_bool)((ip->real != NPY_FALSE) ||
(ip->imag != NPY_FALSE));
op++;
ip++;
}
}
/**end repeat**/
/**begin repeat
* #TOTYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* DATETIME, TIMEDELTA#
* #totype = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_datetime, npy_timedelta#
* #one = 1*10, NPY_HALF_ONE, 1*5#
* #zero = 0*10, NPY_HALF_ZERO, 0*5#
*/
static void
BOOL_to_@TOTYPE@(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const npy_bool *ip = input;
@totype@ *op = output;
while (n--) {
*op++ = (@totype@)((*ip++ != NPY_FALSE) ? @one@ : @zero@);
}
}
/**end repeat**/
/**begin repeat
*
* #TOTYPE = CFLOAT, CDOUBLE,CLONGDOUBLE#
* #totype = npy_float, npy_double, npy_longdouble#
*/
/**begin repeat1
* #FROMTYPE = BOOL,
* BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* FLOAT, DOUBLE, LONGDOUBLE,
* DATETIME, TIMEDELTA#
* #fromtype = npy_bool,
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_float, npy_double, npy_longdouble,
* npy_datetime, npy_timedelta#
*/
static void
@FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const @fromtype@ *ip = input;
@totype@ *op = output;
while (n--) {
*op++ = (@totype@)*ip++;
*op++ = 0.0;
}
}
/**end repeat1**/
/**end repeat**/
/**begin repeat
*
* #TOTYPE = CFLOAT,CDOUBLE,CLONGDOUBLE#
* #totype = npy_float, npy_double, npy_longdouble#
*/
/**begin repeat1
* #FROMTYPE = CFLOAT,CDOUBLE,CLONGDOUBLE#
* #fromtype = npy_float, npy_double, npy_longdouble#
*/
static void
@FROMTYPE@_to_@TOTYPE@(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *NPY_UNUSED(aop))
{
const @fromtype@ *ip = input;
@totype@ *op = output;
n <<= 1;
while (n--) {
*op++ = (@totype@)*ip++;
}
}
/**end repeat1**/
/**end repeat**/
/**begin repeat
*
* #FROMTYPE = BOOL,
* BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* CFLOAT, CDOUBLE, CLONGDOUBLE,
* STRING, UNICODE, VOID, OBJECT,
* DATETIME, TIMEDELTA#
* #fromtype = npy_bool,
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble,
* npy_char, npy_char, npy_char, PyObject *,
* npy_datetime, npy_timedelta#
* #skip = 1*18, PyArray_DESCR(aip)->elsize*3, 1*3#
*/
static void
@FROMTYPE@_to_OBJECT(void *input, void *output, npy_intp n,
void *vaip, void *NPY_UNUSED(aop))
{
@fromtype@ *ip = input;
PyObject **op = output;
PyArrayObject *aip = vaip;
npy_intp i;
int skip = @skip@;
PyObject *tmp;
for (i = 0; i < n; i++, ip +=skip, op++) {
tmp = *op;
*op = @FROMTYPE@_getitem(ip, aip);
Py_XDECREF(tmp);
}
}
/**end repeat**/
#define _NPY_UNUSEDBOOL NPY_UNUSED
#define _NPY_UNUSEDBYTE NPY_UNUSED
#define _NPY_UNUSEDUBYTE NPY_UNUSED
#define _NPY_UNUSEDSHORT NPY_UNUSED
#define _NPY_UNUSEDUSHORT NPY_UNUSED
#define _NPY_UNUSEDINT NPY_UNUSED
#define _NPY_UNUSEDUINT NPY_UNUSED
#define _NPY_UNUSEDLONG NPY_UNUSED
#define _NPY_UNUSEDULONG NPY_UNUSED
#define _NPY_UNUSEDLONGLONG NPY_UNUSED
#define _NPY_UNUSEDULONGLONG NPY_UNUSED
#define _NPY_UNUSEDHALF NPY_UNUSED
#define _NPY_UNUSEDFLOAT NPY_UNUSED
#define _NPY_UNUSEDDOUBLE NPY_UNUSED
#define _NPY_UNUSEDLONGDOUBLE NPY_UNUSED
#define _NPY_UNUSEDCFLOAT NPY_UNUSED
#define _NPY_UNUSEDCDOUBLE NPY_UNUSED
#define _NPY_UNUSEDCLONGDOUBLE NPY_UNUSED
#define _NPY_UNUSEDDATETIME NPY_UNUSED
#define _NPY_UNUSEDTIMEDELTA NPY_UNUSED
#define _NPY_UNUSEDHALF NPY_UNUSED
#define _NPY_UNUSEDSTRING
#define _NPY_UNUSEDVOID
#define _NPY_UNUSEDUNICODE
/**begin repeat
*
* #TOTYPE = BOOL,
* BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* CFLOAT, CDOUBLE, CLONGDOUBLE,
* STRING, UNICODE, VOID,
* DATETIME, TIMEDELTA#
* #totype = npy_bool,
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble,
* npy_char, npy_char, npy_char,
* npy_datetime, npy_timedelta#
* #skip = 1*18, PyArray_DESCR(aop)->elsize*3, 1*2#
*/
static void
OBJECT_to_@TOTYPE@(void *input, void *output, npy_intp n,
void *NPY_UNUSED(aip), void *aop)
{
PyObject **ip = input;
@totype@ *op = output;
npy_intp i;
int skip = @skip@;
for (i = 0; i < n; i++, ip++, op += skip) {
if (*ip == NULL) {
@TOTYPE@_setitem(Py_False, op, aop);
}
else {
@TOTYPE@_setitem(*ip, op, aop);
}
}
}
/**end repeat**/
/**begin repeat
*
* #from = STRING*23, UNICODE*23, VOID*23#
* #fromtyp = npy_char*69#
* #to = (BOOL,
* BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* CFLOAT, CDOUBLE, CLONGDOUBLE,
* STRING, UNICODE, VOID,
* DATETIME, TIMEDELTA)*3#
* #totyp = (npy_bool,
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble,
* npy_char, npy_char, npy_char,
* npy_datetime, npy_timedelta)*3#
* #oskip = 1*18,(PyArray_DESCR(aop)->elsize)*3,1*2,
* 1*18,(PyArray_DESCR(aop)->elsize)*3,1*2,
* 1*18,(PyArray_DESCR(aop)->elsize)*3,1*2#
* #convert = 1*18, 0*3, 1*2,
* 1*18, 0*3, 1*2,
* 0*23#
* #convstr = (Int*9, Long*2, Float*4, Complex*3, Tuple*3, Long*2)*3#
*/
#if @convert@
#define IS_@from@
static void
@from@_to_@to@(void *input, void *output, npy_intp n,
void *vaip, void *aop)
{
@fromtyp@ *ip = input;
@totyp@ *op = output;
PyArrayObject *aip = vaip;
npy_intp i;
int skip = PyArray_DESCR(aip)->elsize;
int oskip = @oskip@;
for (i = 0; i < n; i++, ip+=skip, op+=oskip) {
PyObject *new;
PyObject *temp = PyArray_Scalar(ip, PyArray_DESCR(aip), (PyObject *)aip);
if (temp == NULL) {
return;
}
#if defined(NPY_PY3K) && defined(IS_STRING)
/* Work around some Python 3K */
new = PyUnicode_FromEncodedObject(temp, "ascii", "strict");
Py_DECREF(temp);
temp = new;
if (temp == NULL) {
return;
}
#endif
/* convert from Python object to needed one */
{
PyObject *args;
/* call out to the Python builtin given by convstr */
args = Py_BuildValue("(N)", temp);
#if defined(NPY_PY3K)
#define PyInt_Type PyLong_Type
#endif
new = Py@convstr@_Type.tp_new(&Py@convstr@_Type, args, NULL);
#if defined(NPY_PY3K)
#undef PyInt_Type
#endif
Py_DECREF(args);
temp = new;
if (temp == NULL) {
return;
}
}
if (@to@_setitem(temp, op, aop)) {
Py_DECREF(temp);
return;
}
Py_DECREF(temp);
}
}
#undef IS_@from@
#else
static void
@from@_to_@to@(void *input, void *output, npy_intp n,
void *vaip, void *aop)
{
@fromtyp@ *ip = input;
@totyp@ *op = output;
PyArrayObject *aip = vaip;
npy_intp i;
int skip = PyArray_DESCR(aip)->elsize;
int oskip = @oskip@;
for (i = 0; i < n; i++, ip+=skip, op+=oskip) {
PyObject *temp = PyArray_Scalar(ip, PyArray_DESCR(aip), (PyObject *)aip);
if (temp == NULL) {
return;
}
if (@to@_setitem(temp, op, aop)) {
Py_DECREF(temp);
return;
}
Py_DECREF(temp);
}
}
#endif
/**end repeat**/
/**begin repeat
*
* #to = STRING*20, UNICODE*20, VOID*20#
* #totyp = npy_char*20, npy_char*20, npy_char*20#
* #from = (BOOL,
* BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* CFLOAT, CDOUBLE, CLONGDOUBLE,
* DATETIME, TIMEDELTA)*3#
* #fromtyp = (npy_bool,
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble,
* npy_datetime, npy_timedelta)*3#
*/
static void
@from@_to_@to@(void *input, void *output, npy_intp n,
void *vaip, void *vaop)
{
@fromtyp@ *ip = input;
@totyp@ *op = output;
PyArrayObject *aip = vaip;
PyArrayObject *aop = vaop;
npy_intp i;
PyObject *temp = NULL;
int skip = 1;
int oskip = PyArray_DESCR(aop)->elsize;
for (i = 0; i < n; i++, ip += skip, op += oskip) {
temp = PyArray_Scalar(ip, PyArray_DESCR(aip), (PyObject *)aip);
if (temp == NULL) {
Py_INCREF(Py_False);
temp = Py_False;
}
if (@to@_setitem(temp, op, aop)) {
Py_DECREF(temp);
return;
}
Py_DECREF(temp);
}
}
/**end repeat**/
/*
*****************************************************************************
** SCAN **
*****************************************************************************
*/
/*
* The first ignore argument is for backwards compatibility.
* Should be removed when the API version is bumped up.
*/
/**begin repeat
* #fname = SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG#
* #type = npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong#
* #format = "hd", "hu", "d", "u",
* "ld", "lu", NPY_LONGLONG_FMT, NPY_ULONGLONG_FMT#
*/
static int
@fname@_scan(FILE *fp, @type@ *ip, void *NPY_UNUSED(ignore),
PyArray_Descr *NPY_UNUSED(ignored))
{
return fscanf(fp, "%"@format@, ip);
}
/**end repeat**/
/**begin repeat
* #fname = FLOAT, DOUBLE#
* #type = npy_float, npy_double#
*/
static int
@fname@_scan(FILE *fp, @type@ *ip, void *NPY_UNUSED(ignore),
PyArray_Descr *NPY_UNUSED(ignored))
{
double result;
int ret;
ret = NumPyOS_ascii_ftolf(fp, &result);
*ip = (@type@) result;
return ret;
}
/**end repeat**/
static int
LONGDOUBLE_scan(FILE *fp, npy_longdouble *ip, void *NPY_UNUSED(ignore),
PyArray_Descr *NPY_UNUSED(ignored))
{
long double result;
int ret;
ret = NumPyOS_ascii_ftoLf(fp, &result);
*ip = (npy_longdouble) result;
return ret;
}
static int
HALF_scan(FILE *fp, npy_half *ip, void *NPY_UNUSED(ignore),
PyArray_Descr *NPY_UNUSED(ignored))
{
double result;
int ret;
ret = NumPyOS_ascii_ftolf(fp, &result);
*ip = npy_double_to_half(result);
return ret;
}
/**begin repeat
* #fname = BYTE, UBYTE#
* #type = npy_byte, npy_ubyte#
* #btype = npy_int, npy_uint#
* #format = "d", "u"#
*/
static int
@fname@_scan(FILE *fp, @type@ *ip, void *NPY_UNUSED(ignore),
PyArray_Descr *NPY_UNUSED(ignore2))
{
@btype@ temp;
int num;
num = fscanf(fp, "%"@format@, &temp);
*ip = (@type@) temp;
return num;
}
/**end repeat**/
static int
BOOL_scan(FILE *fp, npy_bool *ip, void *NPY_UNUSED(ignore),
PyArray_Descr *NPY_UNUSED(ignore2))
{
double result;
int ret;
ret = NumPyOS_ascii_ftolf(fp, &result);
*ip = (npy_bool) (result != 0.0);
return ret;
}
/**begin repeat
* #fname = CFLOAT, CDOUBLE, CLONGDOUBLE,
* OBJECT, STRING, UNICODE, VOID,
* DATETIME, TIMEDELTA#
*/
#define @fname@_scan NULL
/**end repeat**/
/*
*****************************************************************************
** FROMSTR **
*****************************************************************************
*/
/**begin repeat
* #fname = BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* DATETIME, TIMEDELTA#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_datetime, npy_timedelta#
* #func = (PyOS_strtol, PyOS_strtoul)*4, npy_strtoll, npy_strtoull,
* npy_strtoll*2#
* #btype = (npy_long, npy_ulong)*4, npy_longlong, npy_ulonglong,
* npy_longlong*2#
*/
static int
@fname@_fromstr(char *str, void *ip, char **endptr,
PyArray_Descr *NPY_UNUSED(ignore))
{
@btype@ result;
result = @func@(str, endptr, 10);
*(@type@ *)ip = result;
return 0;
}
/**end repeat**/
/**begin repeat
*
* #fname = FLOAT, DOUBLE#
* #type = npy_float, npy_double#
*/
static int
@fname@_fromstr(char *str, void *ip, char **endptr,
PyArray_Descr *NPY_UNUSED(ignore))
{
double result;
result = NumPyOS_ascii_strtod(str, endptr);
*(@type@ *)ip = result;
return 0;
}
/**end repeat**/
static int
LONGDOUBLE_fromstr(char *str, void *ip, char **endptr,
PyArray_Descr *NPY_UNUSED(ignore))
{
long double result;
result = NumPyOS_ascii_strtold(str, endptr);
*(npy_longdouble *)ip = result;
return 0;
}
static int
HALF_fromstr(char *str, void *ip, char **endptr,
PyArray_Descr *NPY_UNUSED(ignore))
{
double result;
result = NumPyOS_ascii_strtod(str, endptr);
*(npy_half *)ip = npy_double_to_half(result);
return 0;
}
static int
BOOL_fromstr(char *str, void *ip, char **endptr,
PyArray_Descr *NPY_UNUSED(ignore))
{
double result;
result = NumPyOS_ascii_strtod(str, endptr);
*(npy_bool *)ip = (result != 0.0);
return 0;
}
/**begin repeat
* #fname = CFLOAT, CDOUBLE, CLONGDOUBLE,
* OBJECT, STRING, UNICODE, VOID#
*/
#define @fname@_fromstr NULL
/**end repeat**/
/*
*****************************************************************************
** COPYSWAPN **
*****************************************************************************
*/
static NPY_INLINE void
_basic_copyn(void *dst, npy_intp dstride, void *src, npy_intp sstride,
npy_intp n, int elsize) {
if (src == NULL) {
return;
}
if (sstride == elsize && dstride == elsize) {
memcpy(dst, src, n*elsize);
}
else {
_unaligned_strided_byte_copy(dst, dstride, src, sstride,
n, elsize);
}
}
static NPY_INLINE void
_basic_copy(void *dst, void *src, int elsize) {
if (src == NULL) {
return;
}
memcpy(dst, src, elsize);
}
/**begin repeat
*
* #fname = SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* DATETIME, TIMEDELTA#
* #fsize = SHORT, SHORT, INT, INT,
* LONG, LONG, LONGLONG, LONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* DATETIME, TIMEDELTA#
* #type = npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_datetime, npy_timedelta#
*/
static void
@fname@_copyswapn (void *dst, npy_intp dstride, void *src, npy_intp sstride,
npy_intp n, int swap, void *NPY_UNUSED(arr))
{
/* copy first if needed */
_basic_copyn(dst, dstride, src, sstride, n, sizeof(@type@));
if (swap) {
_strided_byte_swap(dst, dstride, n, sizeof(@type@));
}
}
static void
@fname@_copyswap (void *dst, void *src, int swap, void *NPY_UNUSED(arr))
{
/* copy first if needed */
_basic_copy(dst, src, sizeof(@type@));
if (swap) {
char *a, *b, c;
a = (char *)dst;
#if NPY_SIZEOF_@fsize@ == 2
b = a + 1;
c = *a; *a++ = *b; *b = c;
#elif NPY_SIZEOF_@fsize@ == 4
b = a + 3;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
#elif NPY_SIZEOF_@fsize@ == 8
b = a + 7;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
#elif NPY_SIZEOF_@fsize@ == 10
b = a + 9;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
#elif NPY_SIZEOF_@fsize@ == 12
b = a + 11;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
#elif NPY_SIZEOF_@fsize@ == 16
b = a + 15;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
#else
{
int i, nn;
b = a + (NPY_SIZEOF_@fsize@-1);
nn = NPY_SIZEOF_@fsize@ / 2;
for (i = 0; i < nn; i++) {
c = *a;
*a++ = *b;
*b-- = c;
}
}
#endif
}
}
/**end repeat**/
/**begin repeat
*
* #fname = BOOL,
* BYTE, UBYTE#
* #type = npy_bool,
* npy_byte, npy_ubyte#
*/
static void
@fname@_copyswapn (void *dst, npy_intp dstride, void *src, npy_intp sstride,
npy_intp n, int NPY_UNUSED(swap), void *NPY_UNUSED(arr))
{
/* copy first if needed */
_basic_copyn(dst, dstride, src, sstride, n, sizeof(@type@));
/* ignore swap */
}
static void
@fname@_copyswap (void *dst, void *src, int NPY_UNUSED(swap),
void *NPY_UNUSED(arr))
{
/* copy first if needed */
_basic_copy(dst, src, sizeof(@type@));
/* ignore swap */
}
/**end repeat**/
/**begin repeat
*
* #fname = CFLOAT, CDOUBLE, CLONGDOUBLE#
* #fsize = FLOAT, DOUBLE, LONGDOUBLE#
* #type = npy_cfloat, npy_cdouble, npy_clongdouble#
*/
static void
@fname@_copyswapn (void *dst, npy_intp dstride, void *src, npy_intp sstride,
npy_intp n, int swap, void *NPY_UNUSED(arr))
{
/* copy first if needed */
_basic_copyn(dst, dstride, src, sstride, n, sizeof(@type@));
if (swap) {
_strided_byte_swap(dst, dstride, n, NPY_SIZEOF_@fsize@);
_strided_byte_swap(((char *)dst + NPY_SIZEOF_@fsize@), dstride,
n, NPY_SIZEOF_@fsize@);
}
}
static void
@fname@_copyswap (void *dst, void *src, int swap, void *NPY_UNUSED(arr))
{
/* copy first if needed */
_basic_copy(dst, src, sizeof(@type@));
if (swap) {
char *a, *b, c;
a = (char *)dst;
#if NPY_SIZEOF_@fsize@ == 4
b = a + 3;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
a += 2;
b = a + 3;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
#elif NPY_SIZEOF_@fsize@ == 8
b = a + 7;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
a += 4;
b = a + 7;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
#elif NPY_SIZEOF_@fsize@ == 10
b = a + 9;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
a += 5;
b = a + 9;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
#elif NPY_SIZEOF_@fsize@ == 12
b = a + 11;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
a += 6;
b = a + 11;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
#elif NPY_SIZEOF_@fsize@ == 16
b = a + 15;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
a += 8;
b = a + 15;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b-- = c;
c = *a; *a++ = *b; *b = c;
#else
{
int i, nn;
b = a + (NPY_SIZEOF_@fsize@ - 1);
nn = NPY_SIZEOF_@fsize@ / 2;
for (i = 0; i < nn; i++) {
c = *a;
*a++ = *b;
*b-- = c;
}
a += nn;
b = a + (NPY_SIZEOF_@fsize@ - 1);
for (i = 0; i < nn; i++) {
c = *a;
*a++ = *b;
*b-- = c;
}
}
#endif
}
}
/**end repeat**/
static void
OBJECT_copyswapn(PyObject **dst, npy_intp dstride, PyObject **src,
npy_intp sstride, npy_intp n, int NPY_UNUSED(swap),
void *NPY_UNUSED(arr))
{
npy_intp i;
if (src != NULL) {
if (__ALIGNED(dst, sizeof(PyObject **))
&& __ALIGNED(src, sizeof(PyObject **))
&& __ALIGNED(dstride, sizeof(PyObject **))
&& __ALIGNED(sstride, sizeof(PyObject **))) {
dstride /= sizeof(PyObject **);
sstride /= sizeof(PyObject **);
for (i = 0; i < n; i++) {
Py_XINCREF(*src);
Py_XDECREF(*dst);
*dst = *src;
dst += dstride;
src += sstride;
}
}
else {
unsigned char *dstp, *srcp;
PyObject *tmp;
dstp = (unsigned char*)dst;
srcp = (unsigned char*)src;
for (i = 0; i < n; i++) {
NPY_COPY_PYOBJECT_PTR(&tmp, srcp);
Py_XINCREF(tmp);
NPY_COPY_PYOBJECT_PTR(&tmp, dstp);
Py_XDECREF(tmp);
NPY_COPY_PYOBJECT_PTR(dstp, srcp);
dstp += dstride;
srcp += sstride;
}
}
}
/* ignore swap */
return;
}
static void
OBJECT_copyswap(PyObject **dst, PyObject **src, int NPY_UNUSED(swap),
void *NPY_UNUSED(arr))
{
if (src != NULL) {
if (__ALIGNED(dst,sizeof(PyObject **)) &&
__ALIGNED(src,sizeof(PyObject **))) {
Py_XINCREF(*src);
Py_XDECREF(*dst);
*dst = *src;
}
else {
PyObject *tmp;
NPY_COPY_PYOBJECT_PTR(&tmp, src);
Py_XINCREF(tmp);
NPY_COPY_PYOBJECT_PTR(&tmp, dst);
Py_XDECREF(tmp);
NPY_COPY_PYOBJECT_PTR(dst, src);
}
}
}
/* ignore swap */
static void
STRING_copyswapn (char *dst, npy_intp dstride, char *src, npy_intp sstride,
npy_intp n, int NPY_UNUSED(swap), PyArrayObject *arr)
{
if (arr == NULL) {
return;
}
_basic_copyn(dst, dstride, src, sstride, n, PyArray_DESCR(arr)->elsize);
return;
}
/* */
static void
VOID_copyswapn (char *dst, npy_intp dstride, char *src, npy_intp sstride,
npy_intp n, int swap, PyArrayObject *arr)
{
if (arr == NULL) {
return;
}
if (PyArray_HASFIELDS(arr)) {
PyObject *key, *value;
PyArray_Descr *descr;
Py_ssize_t pos = 0;
descr = PyArray_DESCR(arr);
while (PyDict_Next(descr->fields, &pos, &key, &value)) {
npy_intp offset;
PyArray_Descr * new;
if (NPY_TITLE_KEY(key, value)) {
continue;
}
if (_unpack_field(value, &new, &offset) < 0) {
((PyArrayObject_fields *)arr)->descr = descr;
return;
}
/*
* TODO: temporarily modifying the array like this
* is bad coding style, should be changed.
*/
((PyArrayObject_fields *)arr)->descr = new;
new->f->copyswapn(dst+offset, dstride,
(src != NULL ? src+offset : NULL),
sstride, n, swap, arr);
}
((PyArrayObject_fields *)arr)->descr = descr;
return;
}
if (swap && PyArray_DESCR(arr)->subarray != NULL) {
PyArray_Descr *descr, *new;
npy_intp num;
npy_intp i;
int subitemsize;
char *dstptr, *srcptr;
descr = PyArray_DESCR(arr);
new = descr->subarray->base;
/*
* TODO: temporarily modifying the array like this
* is bad coding style, should be changed.
*/
((PyArrayObject_fields *)arr)->descr = new;
dstptr = dst;
srcptr = src;
subitemsize = new->elsize;
num = descr->elsize / subitemsize;
for (i = 0; i < n; i++) {
new->f->copyswapn(dstptr, subitemsize, srcptr,
subitemsize, num, swap, arr);
dstptr += dstride;
if (srcptr) {
srcptr += sstride;
}
}
((PyArrayObject_fields *)arr)->descr = descr;
return;
}
_basic_copyn(dst, dstride, src, sstride, n, PyArray_DESCR(arr)->elsize);
return;
}
static void
VOID_copyswap (char *dst, char *src, int swap, PyArrayObject *arr)
{
if (arr == NULL) {
return;
}
if (PyArray_HASFIELDS(arr)) {
PyObject *key, *value;
PyArray_Descr *descr;
Py_ssize_t pos = 0;
descr = PyArray_DESCR(arr);
while (PyDict_Next(descr->fields, &pos, &key, &value)) {
npy_intp offset;
PyArray_Descr * new;
if (NPY_TITLE_KEY(key, value)) {
continue;
}
if (_unpack_field(value, &new, &offset) < 0) {
((PyArrayObject_fields *)arr)->descr = descr;
return;
}
/*
* TODO: temporarily modifying the array like this
* is bad coding style, should be changed.
*/
((PyArrayObject_fields *)arr)->descr = new;
new->f->copyswap(dst+offset,
(src != NULL ? src+offset : NULL),
swap, arr);
}
((PyArrayObject_fields *)arr)->descr = descr;
return;
}
if (swap && PyArray_DESCR(arr)->subarray != NULL) {
PyArray_Descr *descr, *new;
npy_intp num;
int itemsize;
descr = PyArray_DESCR(arr);
new = descr->subarray->base;
/*
* TODO: temporarily modifying the array like this
* is bad coding style, should be changed.
*/
((PyArrayObject_fields *)arr)->descr = new;
itemsize = new->elsize;
num = descr->elsize / itemsize;
new->f->copyswapn(dst, itemsize, src,
itemsize, num, swap, arr);
((PyArrayObject_fields *)arr)->descr = descr;
return;
}
/* copy first if needed */
_basic_copy(dst, src, PyArray_DESCR(arr)->elsize);
return;
}
static void
UNICODE_copyswapn (char *dst, npy_intp dstride, char *src, npy_intp sstride,
npy_intp n, int swap, PyArrayObject *arr)
{
int itemsize;
if (arr == NULL) {
return;
}
itemsize = PyArray_DESCR(arr)->elsize;
_basic_copyn(dst, dstride, src, sstride, n, itemsize);
if (swap) {
int i;
char *_dst;
itemsize = itemsize / 4;
while (n > 0) {
_dst = dst;
for (i=0; i < itemsize; i++) {
npy_bswap4_unaligned(_dst);
_dst += 4;
}
dst += dstride;
--n;
}
}
}
static void
STRING_copyswap(char *dst, char *src, int NPY_UNUSED(swap), PyArrayObject *arr)
{
if (arr == NULL) {
return;
}
/* copy first if needed */
_basic_copy(dst, src, PyArray_DESCR(arr)->elsize);
}
static void
UNICODE_copyswap (char *dst, char *src, int swap, PyArrayObject *arr)
{
int itemsize;
if (arr == NULL) {
return;
}
itemsize = PyArray_DESCR(arr)->elsize;
_basic_copy(dst, src, itemsize);
if (swap) {
int i;
char *_dst;
itemsize = itemsize / 4;
_dst = dst;
for (i=0; i < itemsize; i++) {
npy_bswap4_unaligned(_dst);
_dst += 4;
}
}
}
/*
*****************************************************************************
** NONZERO **
*****************************************************************************
*/
#define _NONZERO(a) ((a) != 0)
/**begin repeat
*
* #fname = BOOL,
* BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* DATETIME, TIMEDELTA#
* #type = npy_bool,
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_datetime, npy_timedelta#
* #isfloat = 0*11, 1*4, 0*2#
* #nonzero = _NONZERO*11, !npy_half_iszero, _NONZERO*5#
*/
static npy_bool
@fname@_nonzero (char *ip, PyArrayObject *ap)
{
if (ap == NULL || PyArray_ISBEHAVED_RO(ap)) {
@type@ *ptmp = (@type@ *)ip;
return (npy_bool) @nonzero@(*ptmp);
}
else {
/*
* Don't worry about swapping for integer types,
* since we are just testing for equality with 0.
* For float types, the signed zeros require us to swap.
*/
@type@ tmp;
#if @isfloat@
PyArray_DESCR(ap)->f->copyswap(&tmp, ip, PyArray_ISBYTESWAPPED(ap),
ap);
#else
memcpy(&tmp, ip, sizeof(@type@));
#endif
return (npy_bool) @nonzero@(tmp);
}
}
/**end repeat**/
/**begin repeat
*
* #fname = CFLOAT, CDOUBLE, CLONGDOUBLE#
* #type = npy_cfloat, npy_cdouble, npy_clongdouble#
*/
static npy_bool
@fname@_nonzero (char *ip, PyArrayObject *ap)
{
if (ap == NULL || PyArray_ISBEHAVED_RO(ap)) {
@type@ *ptmp = (@type@ *)ip;
return (npy_bool) ((ptmp->real != 0) || (ptmp->imag != 0));
}
else {
@type@ tmp;
PyArray_DESCR(ap)->f->copyswap(&tmp, ip, PyArray_ISBYTESWAPPED(ap),
ap);
return (npy_bool) ((tmp.real != 0) || (tmp.imag != 0));
}
}
/**end repeat**/
#define WHITESPACE " \t\n\r\v\f"
#define WHITELEN 6
static npy_bool
Py_STRING_ISSPACE(char ch)
{
char white[] = WHITESPACE;
int j;
npy_bool space = NPY_FALSE;
for (j = 0; j < WHITELEN; j++) {
if (ch == white[j]) {
space = NPY_TRUE;
break;
}
}
return space;
}
static npy_bool
STRING_nonzero (char *ip, PyArrayObject *ap)
{
int len = PyArray_DESCR(ap)->elsize;
int i;
npy_bool nonz = NPY_FALSE;
npy_bool seen_null = NPY_FALSE;
for (i = 0; i < len; i++) {
if (*ip == '\0') {
seen_null = NPY_TRUE;
}
else if (seen_null || !Py_STRING_ISSPACE(*ip)) {
nonz = NPY_TRUE;
break;
}
ip++;
}
return nonz;
}
#ifdef Py_UNICODE_WIDE
#define PyArray_UCS4_ISSPACE Py_UNICODE_ISSPACE
#else
#define PyArray_UCS4_ISSPACE(ch) Py_STRING_ISSPACE((char)ch)
#endif
static npy_bool
UNICODE_nonzero (npy_ucs4 *ip, PyArrayObject *ap)
{
int len = PyArray_DESCR(ap)->elsize >> 2;
int i;
npy_bool nonz = NPY_FALSE;
npy_bool seen_null = NPY_FALSE;
char *buffer = NULL;
if (PyArray_ISBYTESWAPPED(ap) || !PyArray_ISALIGNED(ap)) {
buffer = PyArray_malloc(PyArray_DESCR(ap)->elsize);
if (buffer == NULL) {
return nonz;
}
memcpy(buffer, ip, PyArray_DESCR(ap)->elsize);
if (PyArray_ISBYTESWAPPED(ap)) {
byte_swap_vector(buffer, len, 4);
}
ip = (npy_ucs4 *)buffer;
}
for (i = 0; i < len; i++) {
if (*ip == '\0') {
seen_null = NPY_TRUE;
}
else if (seen_null || !PyArray_UCS4_ISSPACE(*ip)) {
nonz = NPY_TRUE;
break;
}
ip++;
}
PyArray_free(buffer);
return nonz;
}
static npy_bool
OBJECT_nonzero (PyObject **ip, PyArrayObject *ap)
{
if (PyArray_ISALIGNED(ap)) {
if (*ip == NULL) {
return NPY_FALSE;
}
return (npy_bool) PyObject_IsTrue(*ip);
}
else {
PyObject *obj;
NPY_COPY_PYOBJECT_PTR(&obj, ip);
if (obj == NULL) {
return NPY_FALSE;
}
return (npy_bool) PyObject_IsTrue(obj);
}
}
/*
* if we have fields, then nonzero only if all sub-fields are nonzero.
*/
static npy_bool
VOID_nonzero (char *ip, PyArrayObject *ap)
{
int i;
int len;
npy_bool nonz = NPY_FALSE;
if (PyArray_HASFIELDS(ap)) {
PyArray_Descr *descr;
PyObject *key, *value;
int savedflags;
Py_ssize_t pos = 0;
descr = PyArray_DESCR(ap);
savedflags = PyArray_FLAGS(ap);
while (PyDict_Next(descr->fields, &pos, &key, &value)) {
PyArray_Descr * new;
npy_intp offset;
if (NPY_TITLE_KEY(key, value)) {
continue;
}
if (_unpack_field(value, &new, &offset) < 0) {
PyErr_Clear();
continue;
}
/*
* TODO: temporarily modifying the array like this
* is bad coding style, should be changed.
*/
((PyArrayObject_fields *)ap)->descr = new;
((PyArrayObject_fields *)ap)->flags = savedflags;
if ((new->alignment > 1) && !__ALIGNED(ip + offset,
new->alignment)) {
PyArray_CLEARFLAGS(ap, NPY_ARRAY_ALIGNED);
}
else {
PyArray_ENABLEFLAGS(ap, NPY_ARRAY_ALIGNED);
}
if (new->f->nonzero(ip+offset, ap)) {
nonz = NPY_TRUE;
break;
}
}
((PyArrayObject_fields *)ap)->descr = descr;
((PyArrayObject_fields *)ap)->flags = savedflags;
return nonz;
}
len = PyArray_DESCR(ap)->elsize;
for (i = 0; i < len; i++) {
if (*ip != '\0') {
nonz = NPY_TRUE;
break;
}
ip++;
}
return nonz;
}
#undef __ALIGNED
/*
*****************************************************************************
** COMPARE **
*****************************************************************************
*/
/* boolean type */
static int
BOOL_compare(npy_bool *ip1, npy_bool *ip2, PyArrayObject *NPY_UNUSED(ap))
{
return (*ip1 ? (*ip2 ? 0 : 1) : (*ip2 ? -1 : 0));
}
/* integer types */
/**begin repeat
* #TYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* DATETIME, TIMEDELTA#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_datetime, npy_timedelta#
*/
static int
@TYPE@_compare (@type@ *pa, @type@ *pb, PyArrayObject *NPY_UNUSED(ap))
{
const @type@ a = *pa;
const @type@ b = *pb;
return a < b ? -1 : a == b ? 0 : 1;
}
/**end repeat**/
/* float types */
/*
* The real/complex comparison functions are compatible with the new sort
* order for nans introduced in numpy 1.4.0. All nan values now compare
* larger than non-nan values and are sorted to the end. The comparison
* order is:
*
* Real: [R, nan]
* Complex: [R + Rj, R + nanj, nan + Rj, nan + nanj]
*
* where complex values with the same nan placements are sorted according
* to the non-nan part if it exists. If both the real and imaginary parts
* of complex types are non-nan the order is the same as the real parts
* unless they happen to be equal, in which case the order is that of the
* imaginary parts.
*/
/**begin repeat
*
* #TYPE = FLOAT, DOUBLE, LONGDOUBLE#
* #type = npy_float, npy_double, npy_longdouble#
*/
#define LT(a,b) ((a) < (b) || ((b) != (b) && (a) ==(a)))
static int
@TYPE@_compare(@type@ *pa, @type@ *pb)
{
const @type@ a = *pa;
const @type@ b = *pb;
int ret;
if (LT(a,b)) {
ret = -1;
}
else if (LT(b,a)) {
ret = 1;
}
else {
ret = 0;
}
return ret;
}
static int
C@TYPE@_compare(@type@ *pa, @type@ *pb)
{
const @type@ ar = pa[0];
const @type@ ai = pa[1];
const @type@ br = pb[0];
const @type@ bi = pb[1];
int ret;
if (ar < br) {
if (ai == ai || bi != bi) {
ret = -1;
}
else {
ret = 1;
}
}
else if (br < ar) {
if (bi == bi || ai != ai) {
ret = 1;
}
else {
ret = -1;
}
}
else if (ar == br || (ar != ar && br != br)) {
if (LT(ai,bi)) {
ret = -1;
}
else if (LT(bi,ai)) {
ret = 1;
}
else {
ret = 0;
}
}
else if (ar == ar) {
ret = -1;
}
else {
ret = 1;
}
return ret;
}
#undef LT
/**end repeat**/
static int
HALF_compare (npy_half *pa, npy_half *pb, PyArrayObject *NPY_UNUSED(ap))
{
npy_half a = *pa, b = *pb;
npy_bool a_isnan, b_isnan;
int ret;
a_isnan = npy_half_isnan(a);
b_isnan = npy_half_isnan(b);
if (a_isnan) {
ret = b_isnan ? 0 : -1;
}
else if (b_isnan) {
ret = 1;
}
else if(npy_half_lt_nonan(a, b)) {
ret = -1;
}
else if(npy_half_lt_nonan(b, a)) {
ret = 1;
}
else {
ret = 0;
}
return ret;
}
/* object type */
static int
OBJECT_compare(PyObject **ip1, PyObject **ip2, PyArrayObject *NPY_UNUSED(ap))
{
/*
* ALIGNMENT NOTE: It seems that PyArray_Sort is already handling
* the alignment of pointers, so it doesn't need to be handled
* here.
*/
int ret;
/*
* work around gh-3879, we cannot abort an in-progress quicksort
* so at least do not raise again
*/
if (PyErr_Occurred()) {
return 0;
}
if ((*ip1 == NULL) || (*ip2 == NULL)) {
if (ip1 == ip2) {
return 1;
}
if (ip1 == NULL) {
return -1;
}
return 1;
}
ret = PyObject_RichCompareBool(*ip1, *ip2, Py_LT);
if (ret < 0) {
/* error occurred, avoid the next call to PyObject_RichCompareBool */
return 0;
}
if (ret == 1) {
return -1;
}
else if (PyObject_RichCompareBool(*ip1, *ip2, Py_GT) == 1) {
return 1;
}
else {
return 0;
}
}
/* string type */
static int
STRING_compare(char *ip1, char *ip2, PyArrayObject *ap)
{
const unsigned char *c1 = (unsigned char *)ip1;
const unsigned char *c2 = (unsigned char *)ip2;
const size_t len = PyArray_DESCR(ap)->elsize;
int i;
i = memcmp(c1, c2, len);
if (i > 0) {
return 1;
}
else if (i < 0) {
return -1;
}
return 0;
}
/* unicode type */
static int
UNICODE_compare(npy_ucs4 *ip1, npy_ucs4 *ip2,
PyArrayObject *ap)
{
int itemsize = PyArray_DESCR(ap)->elsize;
if (itemsize < 0) {
return 0;
}
itemsize /= sizeof(npy_ucs4);
while (itemsize-- > 0) {
npy_ucs4 c1 = *ip1++;
npy_ucs4 c2 = *ip2++;
if (c1 != c2) {
return (c1 < c2) ? -1 : 1;
}
}
return 0;
}
/* void type */
/*
* If fields are defined, then compare on first field and if equal
* compare on second field. Continue until done or comparison results
* in not_equal.
*
* Must align data passed on to sub-comparisons.
* Also must swap data based on to sub-comparisons.
*/
static int
VOID_compare(char *ip1, char *ip2, PyArrayObject *ap)
{
PyArray_Descr *descr;
PyObject *names, *key;
PyObject *tup;
PyArrayObject_fields dummy_struct;
PyArrayObject *dummy = (PyArrayObject *)&dummy_struct;
char *nip1, *nip2;
int i, res = 0, swap = 0;
if (!PyArray_HASFIELDS(ap)) {
return STRING_compare(ip1, ip2, ap);
}
descr = PyArray_DESCR(ap);
/*
* Compare on the first-field. If equal, then
* compare on the second-field, etc.
*/
names = descr->names;
for (i = 0; i < PyTuple_GET_SIZE(names); i++) {
PyArray_Descr *new;
npy_intp offset;
key = PyTuple_GET_ITEM(names, i);
tup = PyDict_GetItem(descr->fields, key);
if (_unpack_field(tup, &new, &offset) < 0) {
goto finish;
}
/* descr is the only field checked by compare or copyswap */
dummy_struct.descr = new;
swap = PyArray_ISBYTESWAPPED(dummy);
nip1 = ip1 + offset;
nip2 = ip2 + offset;
if (swap || new->alignment > 1) {
if (swap || !npy_is_aligned(nip1, new->alignment)) {
/* create buffer and copy */
nip1 = npy_alloc_cache(new->elsize);
if (nip1 == NULL) {
goto finish;
}
memcpy(nip1, ip1 + offset, new->elsize);
if (swap)
new->f->copyswap(nip1, NULL, swap, dummy);
}
if (swap || !npy_is_aligned(nip2, new->alignment)) {
/* create buffer and copy */
nip2 = npy_alloc_cache(new->elsize);
if (nip2 == NULL) {
if (nip1 != ip1 + offset) {
npy_free_cache(nip1, new->elsize);
}
goto finish;
}
memcpy(nip2, ip2 + offset, new->elsize);
if (swap)
new->f->copyswap(nip2, NULL, swap, dummy);
}
}
res = new->f->compare(nip1, nip2, dummy);
if (swap || new->alignment > 1) {
if (nip1 != ip1 + offset) {
npy_free_cache(nip1, new->elsize);
}
if (nip2 != ip2 + offset) {
npy_free_cache(nip2, new->elsize);
}
}
if (res != 0) {
break;
}
}
finish:
return res;
}
/*
*****************************************************************************
** ARGFUNC **
*****************************************************************************
*/
#define _LESS_THAN_OR_EQUAL(a,b) ((a) <= (b))
static int
BOOL_argmax(npy_bool *ip, npy_intp n, npy_intp *max_ind,
PyArrayObject *NPY_UNUSED(aip))
{
npy_intp i = 0;
/* memcmp like logical_and on i386 is maybe slower for small arrays */
#ifdef NPY_HAVE_SSE2_INTRINSICS
const __m128i zero = _mm_setzero_si128();
for (; i < n - (n % 32); i+=32) {
__m128i d1 = _mm_loadu_si128((__m128i*)&ip[i]);
__m128i d2 = _mm_loadu_si128((__m128i*)&ip[i + 16]);
d1 = _mm_cmpeq_epi8(d1, zero);
d2 = _mm_cmpeq_epi8(d2, zero);
if (_mm_movemask_epi8(_mm_min_epu8(d1, d2)) != 0xFFFF) {
break;
}
}
#endif
for (; i < n; i++) {
if (ip[i]) {
*max_ind = i;
return 0;
}
}
*max_ind = 0;
return 0;
}
/**begin repeat
*
* #fname = BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* CFLOAT, CDOUBLE, CLONGDOUBLE,
* DATETIME, TIMEDELTA#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_float, npy_double, npy_longdouble,
* npy_datetime, npy_timedelta#
* #isfloat = 0*10, 1*7, 0*2#
* #isnan = nop*10, npy_half_isnan, npy_isnan*6, nop*2#
* #le = _LESS_THAN_OR_EQUAL*10, npy_half_le, _LESS_THAN_OR_EQUAL*8#
* #iscomplex = 0*14, 1*3, 0*2#
* #incr = ip++*14, ip+=2*3, ip++*2#
*/
static int
@fname@_argmax(@type@ *ip, npy_intp n, npy_intp *max_ind,
PyArrayObject *NPY_UNUSED(aip))
{
npy_intp i;
@type@ mp = *ip;
#if @iscomplex@
@type@ mp_im = ip[1];
#endif
*max_ind = 0;
#if @isfloat@
if (@isnan@(mp)) {
/* nan encountered; it's maximal */
return 0;
}
#endif
#if @iscomplex@
if (@isnan@(mp_im)) {
/* nan encountered; it's maximal */
return 0;
}
#endif
for (i = 1; i < n; i++) {
@incr@;
/*
* Propagate nans, similarly as max() and min()
*/
#if @iscomplex@
/* Lexical order for complex numbers */
if ((ip[0] > mp) || ((ip[0] == mp) && (ip[1] > mp_im))
|| @isnan@(ip[0]) || @isnan@(ip[1])) {
mp = ip[0];
mp_im = ip[1];
*max_ind = i;
if (@isnan@(mp) || @isnan@(mp_im)) {
/* nan encountered, it's maximal */
break;
}
}
#else
if (!@le@(*ip, mp)) { /* negated, for correct nan handling */
mp = *ip;
*max_ind = i;
#if @isfloat@
if (@isnan@(mp)) {
/* nan encountered, it's maximal */
break;
}
#endif
}
#endif
}
return 0;
}
/**end repeat**/
static int
BOOL_argmin(npy_bool *ip, npy_intp n, npy_intp *min_ind,
PyArrayObject *NPY_UNUSED(aip))
{
npy_bool * p = memchr(ip, 0, n * sizeof(*ip));
if (p == NULL) {
*min_ind = 0;
return 0;
}
*min_ind = p - ip;
return 0;
}
/**begin repeat
*
* #fname = BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* CFLOAT, CDOUBLE, CLONGDOUBLE#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_float, npy_double, npy_longdouble#
* #isfloat = 0*10, 1*7#
* #isnan = nop*10, npy_half_isnan, npy_isnan*6#
* #le = _LESS_THAN_OR_EQUAL*10, npy_half_le, _LESS_THAN_OR_EQUAL*6#
* #iscomplex = 0*14, 1*3#
* #incr = ip++*14, ip+=2*3#
*/
static int
@fname@_argmin(@type@ *ip, npy_intp n, npy_intp *min_ind,
PyArrayObject *NPY_UNUSED(aip))
{
npy_intp i;
@type@ mp = *ip;
#if @iscomplex@
@type@ mp_im = ip[1];
#endif
*min_ind = 0;
#if @isfloat@
if (@isnan@(mp)) {
/* nan encountered; it's minimal */
return 0;
}
#endif
#if @iscomplex@
if (@isnan@(mp_im)) {
/* nan encountered; it's minimal */
return 0;
}
#endif
for (i = 1; i < n; i++) {
@incr@;
/*
* Propagate nans, similarly as max() and min()
*/
#if @iscomplex@
/* Lexical order for complex numbers */
if ((mp > ip[0]) || ((ip[0] == mp) && (mp_im > ip[1]))
|| @isnan@(ip[0]) || @isnan@(ip[1])) {
mp = ip[0];
mp_im = ip[1];
*min_ind = i;
if (@isnan@(mp) || @isnan@(mp_im)) {
/* nan encountered, it's minimal */
break;
}
}
#else
if (!@le@(mp, *ip)) { /* negated, for correct nan handling */
mp = *ip;
*min_ind = i;
#if @isfloat@
if (@isnan@(mp)) {
/* nan encountered, it's minimal */
break;
}
#endif
}
#endif
}
return 0;
}
/**end repeat**/
#undef _LESS_THAN_OR_EQUAL
/**begin repeat
*
* #fname = DATETIME, TIMEDELTA#
* #type = npy_datetime, npy_timedelta#
*/
static int
@fname@_argmin(@type@ *ip, npy_intp n, npy_intp *min_ind,
PyArrayObject *NPY_UNUSED(aip))
{
/* NPY_DATETIME_NAT is smaller than every other value, we skip
* it for consistency with min().
*/
npy_intp i;
@type@ mp = NPY_DATETIME_NAT;
i = 0;
while (i < n && mp == NPY_DATETIME_NAT) {
mp = ip[i];
i++;
}
if (i == n) {
/* All NaTs: return 0 */
*min_ind = 0;
return 0;
}
*min_ind = i - 1;
for (; i < n; i++) {
if (mp > ip[i] && ip[i] != NPY_DATETIME_NAT) {
mp = ip[i];
*min_ind = i;
}
}
return 0;
}
/**end repeat**/
static int
OBJECT_argmax(PyObject **ip, npy_intp n, npy_intp *max_ind,
PyArrayObject *NPY_UNUSED(aip))
{
npy_intp i;
*max_ind = 0;
/* Skip over all leading NULL entries */
for (i = 0; i < n && ip[i] == NULL; ++i);
if (i < n) {
/* Found first non-NULL entry */
PyObject *mp = ip[i];
*max_ind = i;
for (i = i + 1; i < n; ++i) {
PyObject *val = ip[i];
if (val != NULL) {
int greater_than = PyObject_RichCompareBool(val, mp, Py_GT);
if (greater_than < 0) {
return 0;
}
if (greater_than) {
mp = val;
*max_ind = i;
}
}
}
}
return 0;
}
/**begin repeat
*
* #fname = STRING, UNICODE#
* #type = npy_char, npy_ucs4#
*/
static int
@fname@_argmax(@type@ *ip, npy_intp n, npy_intp *max_ind, PyArrayObject *aip)
{
npy_intp i;
int elsize = PyArray_DESCR(aip)->elsize;
@type@ *mp = (@type@ *)PyArray_malloc(elsize);
if (mp == NULL) {
return 0;
}
memcpy(mp, ip, elsize);
*max_ind = 0;
for (i = 1; i < n; i++) {
ip += elsize / sizeof(@type@);
if (@fname@_compare(ip, mp, aip) > 0) {
memcpy(mp, ip, elsize);
*max_ind = i;
}
}
PyArray_free(mp);
return 0;
}
/**end repeat**/
#define VOID_argmax NULL
static int
OBJECT_argmin(PyObject **ip, npy_intp n, npy_intp *min_ind,
PyArrayObject *NPY_UNUSED(aip))
{
npy_intp i;
*min_ind = 0;
/* Skip over all leading NULL entries */
for (i = 0; i < n && ip[i] == NULL; ++i);
if (i < n) {
/* Found first non-NULL entry */
PyObject *mp = ip[i];
*min_ind = i;
for (i = i + 1; i < n ; ++i) {
PyObject *val = ip[i];
if (val != NULL) {
int less_than = PyObject_RichCompareBool(val, mp, Py_LT);
if (less_than < 0) {
return 0;
}
if (less_than) {
mp = val;
*min_ind = i;
}
}
}
}
return 0;
}
/**begin repeat
*
* #fname = STRING, UNICODE#
* #type = npy_char, npy_ucs4#
*/
static int
@fname@_argmin(@type@ *ip, npy_intp n, npy_intp *min_ind, PyArrayObject *aip)
{
npy_intp i;
int elsize = PyArray_DESCR(aip)->elsize;
@type@ *mp = (@type@ *)PyArray_malloc(elsize);
if (mp==NULL) return 0;
memcpy(mp, ip, elsize);
*min_ind = 0;
for(i=1; i<n; i++) {
ip += elsize / sizeof(@type@);
if (@fname@_compare(mp,ip,aip) > 0) {
memcpy(mp, ip, elsize);
*min_ind=i;
}
}
PyArray_free(mp);
return 0;
}
/**end repeat**/
#define VOID_argmin NULL
/*
*****************************************************************************
** DOT **
*****************************************************************************
*/
/*
* dot means inner product
*/
/************************** MAYBE USE CBLAS *********************************/
/**begin repeat
*
* #name = FLOAT, DOUBLE#
* #type = npy_float, npy_double#
* #prefix = s, d#
*/
NPY_NO_EXPORT void
@name@_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op,
npy_intp n, void *NPY_UNUSED(ignore))
{
#if defined(HAVE_CBLAS)
int is1b = blas_stride(is1, sizeof(@type@));
int is2b = blas_stride(is2, sizeof(@type@));
if (is1b && is2b)
{
double sum = 0.; /* double for stability */
while (n > 0) {
int chunk = n < NPY_CBLAS_CHUNK ? n : NPY_CBLAS_CHUNK;
sum += cblas_@prefix@dot(chunk,
(@type@ *) ip1, is1b,
(@type@ *) ip2, is2b);
/* use char strides here */
ip1 += chunk * is1;
ip2 += chunk * is2;
n -= chunk;
}
*((@type@ *)op) = (@type@)sum;
}
else
#endif
{
@type@ sum = (@type@)0; /* could make this double */
npy_intp i;
for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) {
const @type@ ip1r = *((@type@ *)ip1);
const @type@ ip2r = *((@type@ *)ip2);
sum += ip1r * ip2r;
}
*((@type@ *)op) = sum;
}
}
/**end repeat**/
/**begin repeat
*
* #name = CFLOAT, CDOUBLE#
* #ctype = npy_cfloat, npy_cdouble#
* #type = npy_float, npy_double#
* #prefix = c, z#
*/
NPY_NO_EXPORT void
@name@_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2,
char *op, npy_intp n, void *NPY_UNUSED(ignore))
{
#if defined(HAVE_CBLAS)
int is1b = blas_stride(is1, sizeof(@ctype@));
int is2b = blas_stride(is2, sizeof(@ctype@));
if (is1b && is2b) {
double sum[2] = {0., 0.}; /* double for stability */
while (n > 0) {
int chunk = n < NPY_CBLAS_CHUNK ? n : NPY_CBLAS_CHUNK;
@type@ tmp[2];
cblas_@prefix@dotu_sub((int)n, ip1, is1b, ip2, is2b, tmp);
sum[0] += (double)tmp[0];
sum[1] += (double)tmp[1];
/* use char strides here */
ip1 += chunk * is1;
ip2 += chunk * is2;
n -= chunk;
}
((@type@ *)op)[0] = (@type@)sum[0];
((@type@ *)op)[1] = (@type@)sum[1];
}
else
#endif
{
@type@ sumr = (@type@)0.0;
@type@ sumi = (@type@)0.0;
npy_intp i;
for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) {
const @type@ ip1r = ((@type@ *)ip1)[0];
const @type@ ip1i = ((@type@ *)ip1)[1];
const @type@ ip2r = ((@type@ *)ip2)[0];
const @type@ ip2i = ((@type@ *)ip2)[1];
sumr += ip1r * ip2r - ip1i * ip2i;
sumi += ip1r * ip2i + ip1i * ip2r;
}
((@type@ *)op)[0] = sumr;
((@type@ *)op)[1] = sumi;
}
}
/**end repeat**/
/**************************** NO CBLAS VERSIONS *****************************/
static void
BOOL_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op, npy_intp n,
void *NPY_UNUSED(ignore))
{
npy_bool tmp = NPY_FALSE;
npy_intp i;
for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) {
if ((*((npy_bool *)ip1) != 0) && (*((npy_bool *)ip2) != 0)) {
tmp = NPY_TRUE;
break;
}
}
*((npy_bool *)op) = tmp;
}
/**begin repeat
*
* #name = BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* LONGDOUBLE, DATETIME, TIMEDELTA#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_longdouble, npy_datetime, npy_timedelta#
* #out = npy_long, npy_ulong, npy_long, npy_ulong, npy_long, npy_ulong,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_longdouble, npy_datetime, npy_timedelta#
*/
static void
@name@_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op, npy_intp n,
void *NPY_UNUSED(ignore))
{
@out@ tmp = (@out@)0;
npy_intp i;
for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) {
tmp += (@out@)(*((@type@ *)ip1)) *
(@out@)(*((@type@ *)ip2));
}
*((@type@ *)op) = (@type@) tmp;
}
/**end repeat**/
static void
HALF_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op,
npy_intp n, void *NPY_UNUSED(ignore))
{
float tmp = 0.0f;
npy_intp i;
for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) {
tmp += npy_half_to_float(*((npy_half *)ip1)) *
npy_half_to_float(*((npy_half *)ip2));
}
*((npy_half *)op) = npy_float_to_half(tmp);
}
static void
CLONGDOUBLE_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2,
char *op, npy_intp n, void *NPY_UNUSED(ignore))
{
npy_longdouble tmpr = 0.0L;
npy_longdouble tmpi = 0.0L;
npy_intp i;
for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) {
const npy_longdouble ip1r = ((npy_longdouble *)ip1)[0];
const npy_longdouble ip1i = ((npy_longdouble *)ip1)[1];
const npy_longdouble ip2r = ((npy_longdouble *)ip2)[0];
const npy_longdouble ip2i = ((npy_longdouble *)ip2)[1];
tmpr += ip1r * ip2r - ip1i * ip2i;
tmpi += ip1r * ip2i + ip1i * ip2r;
}
((npy_longdouble *)op)[0] = tmpr;
((npy_longdouble *)op)[1] = tmpi;
}
static void
OBJECT_dot(char *ip1, npy_intp is1, char *ip2, npy_intp is2, char *op, npy_intp n,
void *NPY_UNUSED(ignore))
{
/*
* ALIGNMENT NOTE: np.dot, np.inner etc. enforce that the array is
* BEHAVED before getting to this point, so unaligned pointers aren't
* handled here.
*/
npy_intp i;
PyObject *tmp1, *tmp2, *tmp = NULL;
PyObject **tmp3;
for (i = 0; i < n; i++, ip1 += is1, ip2 += is2) {
if ((*((PyObject **)ip1) == NULL) || (*((PyObject **)ip2) == NULL)) {
tmp1 = Py_False;
Py_INCREF(Py_False);
}
else {
tmp1 = PyNumber_Multiply(*((PyObject **)ip1), *((PyObject **)ip2));
if (!tmp1) {
Py_XDECREF(tmp);
return;
}
}
if (i == 0) {
tmp = tmp1;
}
else {
tmp2 = PyNumber_Add(tmp, tmp1);
Py_XDECREF(tmp);
Py_XDECREF(tmp1);
if (!tmp2) {
return;
}
tmp = tmp2;
}
}
tmp3 = (PyObject**) op;
tmp2 = *tmp3;
*((PyObject **)op) = tmp;
Py_XDECREF(tmp2);
}
/*
*****************************************************************************
** FILL **
*****************************************************************************
*/
#define BOOL_fill NULL
/* this requires buffer to be filled with objects or NULL */
static void
OBJECT_fill(PyObject **buffer, npy_intp length, void *NPY_UNUSED(ignored))
{
npy_intp i;
PyObject *start = buffer[0];
PyObject *delta = buffer[1];
PyObject *second;
delta = PyNumber_Subtract(delta, start);
if (!delta) {
return;
}
second = start = PyNumber_Add(start, delta);
if (!start) {
goto finish;
}
buffer += 2;
for (i = 2; i < length; i++, buffer++) {
start = PyNumber_Add(start, delta);
if (!start) {
goto finish;
}
Py_XDECREF(*buffer);
*buffer = start;
}
finish:
Py_XDECREF(second);
Py_DECREF(delta);
return;
}
/**begin repeat
*
* #NAME = BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* FLOAT, DOUBLE, LONGDOUBLE,
* DATETIME, TIMEDELTA#
* #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_float, npy_double, npy_longdouble,
* npy_datetime, npy_timedelta#
*/
static void
@NAME@_fill(@type@ *buffer, npy_intp length, void *NPY_UNUSED(ignored))
{
npy_intp i;
@type@ start = buffer[0];
@type@ delta = buffer[1];
delta -= start;
for (i = 2; i < length; ++i) {
buffer[i] = start + i*delta;
}
}
/**end repeat**/
static void
HALF_fill(npy_half *buffer, npy_intp length, void *NPY_UNUSED(ignored))
{
npy_intp i;
float start = npy_half_to_float(buffer[0]);
float delta = npy_half_to_float(buffer[1]);
delta -= start;
for (i = 2; i < length; ++i) {
buffer[i] = npy_float_to_half(start + i*delta);
}
}
/**begin repeat
*
* #NAME = CFLOAT, CDOUBLE, CLONGDOUBLE#
* #type = npy_cfloat, npy_cdouble, npy_clongdouble#
*/
static void
@NAME@_fill(@type@ *buffer, npy_intp length, void *NPY_UNUSED(ignore))
{
npy_intp i;
@type@ start;
@type@ delta;
start.real = buffer->real;
start.imag = buffer->imag;
delta.real = buffer[1].real;
delta.imag = buffer[1].imag;
delta.real -= start.real;
delta.imag -= start.imag;
buffer += 2;
for (i = 2; i < length; i++, buffer++) {
buffer->real = start.real + i*delta.real;
buffer->imag = start.imag + i*delta.imag;
}
}
/**end repeat**/
/* this requires buffer to be filled with objects or NULL */
static void
OBJECT_fillwithscalar(PyObject **buffer, npy_intp length, PyObject **value,
void *NPY_UNUSED(ignored))
{
npy_intp i;
PyObject *val = *value;
for (i = 0; i < length; i++) {
Py_XINCREF(val);
Py_XDECREF(buffer[i]);
buffer[i] = val;
}
}
/**begin repeat
*
* #NAME = BOOL, BYTE, UBYTE#
* #type = npy_bool, npy_byte, npy_ubyte#
*/
static void
@NAME@_fillwithscalar(@type@ *buffer, npy_intp length, @type@ *value,
void *NPY_UNUSED(ignored))
{
memset(buffer, *value, length);
}
/**end repeat**/
/**begin repeat
*
* #NAME = SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* CFLOAT, CDOUBLE, CLONGDOUBLE,
* DATETIME, TIMEDELTA#
* #type = npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_cfloat, npy_cdouble, npy_clongdouble,
* npy_datetime, npy_timedelta#
*/
static void
@NAME@_fillwithscalar(@type@ *buffer, npy_intp length, @type@ *value,
void *NPY_UNUSED(ignored))
{
npy_intp i;
@type@ val = *value;
for (i = 0; i < length; ++i) {
buffer[i] = val;
}
}
/**end repeat**/
/*
*****************************************************************************
** FASTCLIP **
*****************************************************************************
*/
#define _LESS_THAN(a, b) ((a) < (b))
#define _GREATER_THAN(a, b) ((a) > (b))
/*
* In fastclip, 'b' was already checked for NaN, so the half comparison
* only needs to check 'a' for NaN.
*/
#define _HALF_LESS_THAN(a, b) (!npy_half_isnan(a) && npy_half_lt_nonan(a, b))
#define _HALF_GREATER_THAN(a, b) (!npy_half_isnan(a) && npy_half_lt_nonan(b, a))
/**begin repeat
*
* #name = BOOL,
* BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* DATETIME, TIMEDELTA#
* #type = npy_bool,
* npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint,
* npy_long, npy_ulong, npy_longlong, npy_ulonglong,
* npy_half, npy_float, npy_double, npy_longdouble,
* npy_datetime, npy_timedelta#
* #isfloat = 0*11, 1*4, 0*2#
* #isnan = nop*11, npy_half_isnan, npy_isnan*3, nop*2#
* #lt = _LESS_THAN*11, _HALF_LESS_THAN, _LESS_THAN*5#
* #gt = _GREATER_THAN*11, _HALF_GREATER_THAN, _GREATER_THAN*5#
*/
static void
@name@_fastclip(@type@ *in, npy_intp ni, @type@ *min, @type@ *max, @type@ *out)
{
npy_intp i;
@type@ max_val = 0, min_val = 0;
if (max != NULL) {
max_val = *max;
#if @isfloat@
/* NaNs result in no clipping, so optimize the case away */
if (@isnan@(max_val)) {
if (min == NULL) {
memmove(out, in, ni * sizeof(@type@));
return;
}
max = NULL;
}
#endif
}
if (min != NULL) {
min_val = *min;
#if @isfloat@
if (@isnan@(min_val)) {
if (max == NULL) {
memmove(out, in, ni * sizeof(@type@));
return;
}
min = NULL;
}
#endif
}
if (max == NULL) {
for (i = 0; i < ni; i++) {
if (@lt@(in[i], min_val)) {
out[i] = min_val;
}
else {
out[i] = in[i];
}
}
}
else if (min == NULL) {
for (i = 0; i < ni; i++) {
if (@gt@(in[i], max_val)) {
out[i] = max_val;
}
else {
out[i] = in[i];
}
}
}
else {
/*
* Visual Studio 2015 loop vectorizer handles NaN in an unexpected
* manner, see: https://github.com/numpy/numpy/issues/7601
*/
#if (_MSC_VER == 1900)
#pragma loop( no_vector )
#endif
for (i = 0; i < ni; i++) {
if (@lt@(in[i], min_val)) {
out[i] = min_val;
}
else if (@gt@(in[i], max_val)) {
out[i] = max_val;
}
else {
out[i] = in[i];
}
}
}
}
/**end repeat**/
#undef _LESS_THAN
#undef _GREATER_THAN
#undef _HALF_LESS_THAN
#undef _HALF_GREATER_THAN
/**begin repeat
*
* #name = CFLOAT, CDOUBLE, CLONGDOUBLE#
* #type = npy_cfloat, npy_cdouble, npy_clongdouble#
*/
static void
@name@_fastclip(@type@ *in, npy_intp ni, @type@ *min, @type@ *max, @type@ *out)
{
npy_intp i;
@type@ max_val, min_val;
if (max != NULL) {
max_val = *max;
}
if (min != NULL) {
min_val = *min;
}
if (max == NULL) {
for (i = 0; i < ni; i++) {
if (PyArray_CLT(in[i],min_val)) {
out[i] = min_val;
}
else {
out[i] = in[i];
}
}
}
else if (min == NULL) {
for (i = 0; i < ni; i++) {
if (PyArray_CGT(in[i], max_val)) {
out[i] = max_val;
}
else {
out[i] = in[i];
}
}
}
else {
for (i = 0; i < ni; i++) {
if (PyArray_CLT(in[i], min_val)) {
out[i] = min_val;
}
else if (PyArray_CGT(in[i], max_val)) {
out[i] = max_val;
}
else {
out[i] = in[i];
}
}
}
}
/**end repeat**/
#define OBJECT_fastclip NULL
/*
*****************************************************************************
** FASTPUTMASK **
*****************************************************************************
*/
/**begin repeat
*
* #name = BOOL,
* BYTE, UBYTE, SHORT, USHORT, INT, UINT,
* LONG, ULONG, LONGLONG, ULONGLONG,
* HALF, FLOAT, DOUBLE, LONGDOUBLE,
* CFLOAT, CDOUBLE, CLONGDOUBLE,