/* -*-c-*- */ #define PY_SSIZE_T_CLEAN #include #define NPY_NO_DEPRECATED_API NPY_API_VERSION #include "numpy/arrayobject.h" #include "numpy/arrayscalars.h" #include "numpy/npy_math.h" #include "numpy/halffloat.h" #include "common.h" #include "npy_argparse.h" #include "mem_overlap.h" #include "npy_extint128.h" #include "array_method.h" #include "npy_hashtable.h" #include "dtypemeta.h" #if defined(MS_WIN32) || defined(__CYGWIN__) #define EXPORT(x) __declspec(dllexport) x #else #define EXPORT(x) x #endif #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) static PyObject * argparse_example_function(PyObject *NPY_UNUSED(mod), PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) { NPY_PREPARE_ARGPARSER; int arg1; PyObject *arg2, *arg3, *arg4; if (npy_parse_arguments("func", args, len_args, kwnames, "", &PyArray_PythonPyIntFromInt, &arg1, "arg2", NULL, &arg2, "|arg3", NULL, &arg3, "$arg3", NULL, &arg4, NULL, NULL, NULL) < 0) { return NULL; } Py_RETURN_NONE; } /* * Tests that argparse cache creation is thread-safe. *must* be called only * by the python-level test_thread_safe_argparse_cache function, otherwise * the cache might be created before the test to make sure cache creation is * thread-safe runs */ static PyObject * threaded_argparse_example_function(PyObject *NPY_UNUSED(mod), PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) { NPY_PREPARE_ARGPARSER; int arg1; PyObject *arg2; if (npy_parse_arguments("thread_func", args, len_args, kwnames, "$arg1", &PyArray_PythonPyIntFromInt, &arg1, "$arg2", NULL, &arg2, NULL, NULL, NULL) < 0) { return NULL; } Py_RETURN_NONE; } /* test PyArray_IsPythonScalar, before including private py3 compat header */ static PyObject * IsPythonScalar(PyObject * dummy, PyObject *args) { PyObject *arg = NULL; if (!PyArg_ParseTuple(args, "O", &arg)) { return NULL; } if (PyArray_IsPythonScalar(arg)) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } /** Function to test calling via ctypes */ EXPORT(void*) forward_pointer(void *x) { return x; } /* * TODO: * - Handle mode */ /**begin repeat * #name = double, int# * #type = npy_double, npy_int# * #typenum = NPY_DOUBLE, NPY_INT# */ static int copy_@name@(PyArrayIterObject *itx, PyArrayNeighborhoodIterObject *niterx, npy_intp const *bounds, PyObject **out) { npy_intp i, j; @type@ *ptr; npy_intp odims[NPY_MAXDIMS_LEGACY_ITERS]; PyArrayObject *aout; /* * For each point in itx, copy the current neighborhood into an array which * is appended at the output list */ for (i = itx->index; i < itx->size; ++i) { PyArrayNeighborhoodIter_Reset(niterx); for (j = 0; j < PyArray_NDIM(itx->ao); ++j) { odims[j] = bounds[2 * j + 1] - bounds[2 * j] + 1; } aout = (PyArrayObject*)PyArray_SimpleNew( PyArray_NDIM(itx->ao), odims, @typenum@); if (aout == NULL) { return -1; } ptr = (@type@*)PyArray_DATA(aout); for (j = 0; j < niterx->size; ++j) { *ptr = *((@type@*)niterx->dataptr); PyArrayNeighborhoodIter_Next(niterx); ptr += 1; } PyList_Append(*out, (PyObject*)aout); Py_DECREF(aout); PyArray_ITER_NEXT(itx); } return 0; } /**end repeat**/ static int copy_object(PyArrayIterObject *itx, PyArrayNeighborhoodIterObject *niterx, npy_intp const *bounds, PyObject **out) { npy_intp i, j; npy_intp odims[NPY_MAXDIMS_LEGACY_ITERS]; PyArrayObject *aout; PyArray_CopySwapFunc *copyswap = PyDataType_GetArrFuncs(PyArray_DESCR(itx->ao))->copyswap; npy_int itemsize = PyArray_ITEMSIZE(itx->ao); /* * For each point in itx, copy the current neighborhood into an array which * is appended at the output list */ for (i = itx->index; i < itx->size; ++i) { PyArrayNeighborhoodIter_Reset(niterx); for (j = 0; j < PyArray_NDIM(itx->ao); ++j) { odims[j] = bounds[2 * j + 1] - bounds[2 * j] + 1; } aout = (PyArrayObject*)PyArray_SimpleNew(PyArray_NDIM(itx->ao), odims, NPY_OBJECT); if (aout == NULL) { return -1; } for (j = 0; j < niterx->size; ++j) { copyswap(PyArray_BYTES(aout) + j * itemsize, niterx->dataptr, 0, NULL); PyArrayNeighborhoodIter_Next(niterx); } PyList_Append(*out, (PyObject*)aout); Py_DECREF(aout); PyArray_ITER_NEXT(itx); } return 0; } static PyObject* test_neighborhood_iterator(PyObject* NPY_UNUSED(self), PyObject* args) { PyObject *x, *fill, *out, *b; PyArrayObject *ax, *afill; PyArrayIterObject *itx; int i, typenum, mode, st; Py_ssize_t idxstart = 0; npy_intp bounds[NPY_MAXDIMS_LEGACY_ITERS*2]; PyArrayNeighborhoodIterObject *niterx; if (!PyArg_ParseTuple(args, "OOOi|n", &x, &b, &fill, &mode, &idxstart)) { return NULL; } if (!PySequence_Check(b)) { return NULL; } typenum = PyArray_ObjectType(x, NPY_NOTYPE); if (typenum == NPY_NOTYPE) { return NULL; } typenum = PyArray_ObjectType(fill, typenum); if (typenum == NPY_NOTYPE) { return NULL; } ax = (PyArrayObject*)PyArray_FromObject(x, typenum, 1, 10); if (ax == NULL) { return NULL; } if (PySequence_Size(b) != 2 * PyArray_NDIM(ax)) { PyErr_SetString(PyExc_ValueError, "bounds sequence size not compatible with x input"); goto clean_ax; } out = PyList_New(0); if (out == NULL) { goto clean_ax; } itx = (PyArrayIterObject*)PyArray_IterNew(x); if (itx == NULL) { goto clean_out; } /* Compute boundaries for the neighborhood iterator */ for (i = 0; i < 2 * PyArray_NDIM(ax); ++i) { PyObject* bound; bound = PySequence_GetItem(b, i); if (bound == NULL) { goto clean_itx; } /* PyLong_AsSsize checks for PyLong */ bounds[i] = PyLong_AsSsize_t(bound); if (error_converting(bounds[i])) { PyErr_Clear(); PyErr_SetString(PyExc_ValueError, "bound is invalid"); Py_DECREF(bound); goto clean_itx; } Py_DECREF(bound); } /* Create the neighborhood iterator */ afill = NULL; if (mode == NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING) { afill = (PyArrayObject *)PyArray_FromObject(fill, typenum, 0, 0); if (afill == NULL) { goto clean_itx; } } if (idxstart >= itx->size) { PyErr_SetString(PyExc_ValueError, "start index not compatible with x input"); goto clean_itx; } niterx = (PyArrayNeighborhoodIterObject*)PyArray_NeighborhoodIterNew( (PyArrayIterObject*)itx, bounds, mode, afill); if (niterx == NULL) { goto clean_afill; } PyArray_ITER_GOTO1D((PyArrayIterObject*)itx, idxstart); switch (typenum) { case NPY_OBJECT: st = copy_object(itx, niterx, bounds, &out); break; case NPY_INT: st = copy_int(itx, niterx, bounds, &out); break; case NPY_DOUBLE: st = copy_double(itx, niterx, bounds, &out); break; default: PyErr_SetString(PyExc_ValueError, "Type not supported"); goto clean_niterx; } if (st) { goto clean_niterx; } Py_DECREF(niterx); Py_XDECREF(afill); Py_DECREF(itx); Py_DECREF(ax); return out; clean_niterx: Py_DECREF(niterx); clean_afill: Py_XDECREF(afill); clean_itx: Py_DECREF(itx); clean_out: Py_DECREF(out); clean_ax: Py_DECREF(ax); return NULL; } static int copy_double_double(PyArrayNeighborhoodIterObject *itx, PyArrayNeighborhoodIterObject *niterx, npy_intp const *bounds, PyObject **out) { npy_intp i, j; double *ptr; npy_intp odims[NPY_MAXDIMS_LEGACY_ITERS]; PyArrayObject *aout; /* * For each point in itx, copy the current neighborhood into an array which * is appended at the output list */ PyArrayNeighborhoodIter_Reset(itx); for (i = 0; i < itx->size; ++i) { for (j = 0; j < PyArray_NDIM(itx->ao); ++j) { odims[j] = bounds[2 * j + 1] - bounds[2 * j] + 1; } aout = (PyArrayObject*)PyArray_SimpleNew( PyArray_NDIM(itx->ao), odims, NPY_DOUBLE); if (aout == NULL) { return -1; } ptr = (double*)PyArray_DATA(aout); PyArrayNeighborhoodIter_Reset(niterx); for (j = 0; j < niterx->size; ++j) { *ptr = *((double*)niterx->dataptr); ptr += 1; PyArrayNeighborhoodIter_Next(niterx); } PyList_Append(*out, (PyObject*)aout); Py_DECREF(aout); PyArrayNeighborhoodIter_Next(itx); } return 0; } static PyObject* test_neighborhood_iterator_oob(PyObject* NPY_UNUSED(self), PyObject* args) { PyObject *x, *out, *b1, *b2; PyArrayObject *ax; PyArrayIterObject *itx; int i, typenum, mode1, mode2, st; npy_intp bounds[NPY_MAXDIMS_LEGACY_ITERS*2]; PyArrayNeighborhoodIterObject *niterx1, *niterx2; if (!PyArg_ParseTuple(args, "OOiOi", &x, &b1, &mode1, &b2, &mode2)) { return NULL; } if (!PySequence_Check(b1) || !PySequence_Check(b2)) { return NULL; } typenum = PyArray_ObjectType(x, NPY_NOTYPE); if (typenum == NPY_NOTYPE) { return NULL; } ax = (PyArrayObject*)PyArray_FromObject(x, typenum, 1, 10); if (ax == NULL) { return NULL; } if (PyArray_NDIM(ax) > NPY_MAXDIMS_LEGACY_ITERS) { PyErr_SetString(PyExc_TypeError, "too many dimensions."); goto clean_ax; } if (PySequence_Size(b1) != 2 * PyArray_NDIM(ax)) { PyErr_SetString(PyExc_ValueError, "bounds sequence 1 size not compatible with x input"); goto clean_ax; } if (PySequence_Size(b2) != 2 * PyArray_NDIM(ax)) { PyErr_SetString(PyExc_ValueError, "bounds sequence 2 size not compatible with x input"); goto clean_ax; } out = PyList_New(0); if (out == NULL) { goto clean_ax; } itx = (PyArrayIterObject*)PyArray_IterNew(x); if (itx == NULL) { goto clean_out; } /* Compute boundaries for the neighborhood iterator */ for (i = 0; i < 2 * PyArray_NDIM(ax); ++i) { PyObject* bound; bound = PySequence_GetItem(b1, i); if (bound == NULL) { goto clean_itx; } /* PyLong_AsSsize checks for PyLong */ bounds[i] = PyLong_AsSsize_t(bound); if (error_converting(bounds[i])) { PyErr_Clear(); PyErr_SetString(PyExc_ValueError, "bound is invalid"); Py_DECREF(bound); goto clean_itx; } Py_DECREF(bound); } /* Create the neighborhood iterator */ niterx1 = (PyArrayNeighborhoodIterObject*)PyArray_NeighborhoodIterNew( (PyArrayIterObject*)itx, bounds, mode1, NULL); if (niterx1 == NULL) { goto clean_out; } for (i = 0; i < 2 * PyArray_NDIM(ax); ++i) { PyObject* bound; bound = PySequence_GetItem(b2, i); if (bound == NULL) { goto clean_itx; } /* PyLong_AsSsize checks for PyLong */ bounds[i] = PyLong_AsSsize_t(bound); if (error_converting(bounds[i])) { PyErr_Clear(); PyErr_SetString(PyExc_ValueError, "bound is invalid"); Py_DECREF(bound); goto clean_itx; } Py_DECREF(bound); } niterx2 = (PyArrayNeighborhoodIterObject*)PyArray_NeighborhoodIterNew( (PyArrayIterObject*)niterx1, bounds, mode2, NULL); if (niterx2 == NULL) { goto clean_niterx1; } switch (typenum) { case NPY_DOUBLE: st = copy_double_double(niterx1, niterx2, bounds, &out); break; default: PyErr_SetString(PyExc_ValueError, "Type not supported"); goto clean_niterx2; } if (st) { goto clean_niterx2; } Py_DECREF(niterx2); Py_DECREF(niterx1); Py_DECREF(itx); Py_DECREF(ax); return out; clean_niterx2: Py_DECREF(niterx2); clean_niterx1: Py_DECREF(niterx1); clean_itx: Py_DECREF(itx); clean_out: Py_DECREF(out); clean_ax: Py_DECREF(ax); return NULL; } /* * Helper to test fromstring of 0 terminated strings, as the C-API supports * the -1 length identifier. */ static PyObject * fromstring_null_term_c_api(PyObject *dummy, PyObject *byte_obj) { char *string; string = PyBytes_AsString(byte_obj); if (string == NULL) { return NULL; } return PyArray_FromString(string, -1, NULL, -1, " "); } /* * Create a custom field dtype from an existing void one (and test some errors). * The dtypes created by this function may be not be usable (or even crash * while using). */ static PyObject * create_custom_field_dtype(PyObject *NPY_UNUSED(mod), PyObject *args) { PyArray_DescrProto proto; _PyArray_LegacyDescr *dtype; /* Is checked for void, so legacy is OK */ PyTypeObject *scalar_type; int error_path; if (!PyArg_ParseTuple(args, "O!O!i", &PyArrayDescr_Type, &dtype, &PyType_Type, &scalar_type, &error_path)) { return NULL; } /* check that the result should be more or less valid */ if (dtype->type_num != NPY_VOID || dtype->fields == NULL || !PyDict_CheckExact(dtype->fields) || PyTuple_Size(dtype->names) != 1 || !PyDataType_REFCHK((PyArray_Descr *)dtype) || dtype->elsize != sizeof(PyObject *)) { PyErr_SetString(PyExc_ValueError, "Bad dtype passed to test function, must be an object " "containing void with a single field."); return NULL; } /* Set all fields, mostly copying them from the passed in dtype: */ Py_SET_TYPE(&proto, Py_TYPE(dtype)); proto.typeobj = scalar_type; proto.kind = dtype->kind; proto.type = dtype->type; proto.byteorder = dtype->byteorder; proto.flags = dtype->flags; proto.type_num = dtype->type_num; proto.elsize = dtype->elsize; proto.alignment = dtype->alignment; proto.subarray = dtype->subarray; proto.fields = dtype->fields; proto.names = dtype->names; proto.f = PyDataType_GetArrFuncs((PyArray_Descr *)dtype); proto.metadata = dtype->metadata; proto.c_metadata = dtype->c_metadata; if (error_path == 1) { /* Test that we reject this, if fields was not already set */ proto.fields = NULL; } else if (error_path == 2) { /* * Test that we reject this if the type is not set to something that * we are pretty sure can be safely replaced. */ Py_SET_TYPE(&proto, scalar_type); } else if (error_path != 0) { PyErr_SetString(PyExc_ValueError, "invalid error argument to test function."); } int new_typenum = PyArray_RegisterDataType(&proto); if (new_typenum < 0) { return NULL; } return (PyObject *)PyArray_DescrFromType(new_typenum); } PyObject * corrupt_or_fix_bufferinfo(PyObject *dummy, PyObject *obj) { void **buffer_info_ptr; if (PyArray_Check(obj)) { buffer_info_ptr = &((PyArrayObject_fields *)obj)->_buffer_info; } else if (PyArray_IsScalar(obj, Void)) { buffer_info_ptr = &((PyVoidScalarObject *)obj)->_buffer_info; } else { PyErr_SetString(PyExc_TypeError, "argument must be an array or void scalar"); return NULL; } if (*buffer_info_ptr == NULL) { /* set to an invalid value (as a subclass might accidentally) */ *buffer_info_ptr = obj; assert(((uintptr_t)obj & 7) == 0); } else if (*buffer_info_ptr == obj) { /* Reset to a NULL (good value) */ *buffer_info_ptr = NULL; } else { PyErr_SetString(PyExc_TypeError, "buffer was already exported, this test doesn't support that"); return NULL; } Py_RETURN_NONE; } /* check no elison for avoided increfs */ static PyObject * incref_elide(PyObject *dummy, PyObject *args) { PyObject *arg = NULL, *res, *tup; if (!PyArg_ParseTuple(args, "O", &arg)) { return NULL; } /* refcount 1 array but should not be elided */ arg = PyArray_NewCopy((PyArrayObject*)arg, NPY_KEEPORDER); res = PyNumber_Add(arg, arg); /* return original copy, should be equal to input */ tup = PyTuple_Pack(2, arg, res); Py_DECREF(arg); Py_DECREF(res); return tup; } /* check no elison for get from list without incref */ static PyObject * incref_elide_l(PyObject *dummy, PyObject *args) { PyObject *arg = NULL, *r, *res; if (!PyArg_ParseTuple(args, "O", &arg)) { return NULL; } /* get item without increasing refcount, item may still be on the python * stack but above the inaccessible top */ r = PyList_GetItem(arg, 4); res = PyNumber_Add(r, r); return res; } /* used to test NPY_CHAR usage raises an error */ static PyObject* npy_char_deprecation(PyObject* NPY_UNUSED(self), PyObject* NPY_UNUSED(args)) { PyArray_Descr * descr = PyArray_DescrFromType(NPY_CHAR); return (PyObject *)descr; } /* used to create array with WRITEBACKIFCOPY flag */ static PyObject* npy_create_writebackifcopy(PyObject* NPY_UNUSED(self), PyObject* args) { int flags; PyObject* array; if (!PyArray_Check(args)) { PyErr_SetString(PyExc_TypeError, "test needs ndarray input"); return NULL; } flags = NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY; array = PyArray_FromArray((PyArrayObject*)args, NULL, flags); if (array == NULL) return NULL; return array; } /* used to test WRITEBACKIFCOPY without resolution emits runtime warning */ static PyObject* npy_abuse_writebackifcopy(PyObject* NPY_UNUSED(self), PyObject* args) { int flags; PyObject* array; if (!PyArray_Check(args)) { PyErr_SetString(PyExc_TypeError, "test needs ndarray input"); return NULL; } flags = NPY_ARRAY_CARRAY | NPY_ARRAY_WRITEBACKIFCOPY; array = PyArray_FromArray((PyArrayObject*)args, NULL, flags); if (array == NULL) return NULL; Py_DECREF(array); /* calls array_dealloc even on PyPy */ Py_RETURN_NONE; } /* resolve WRITEBACKIFCOPY */ static PyObject* npy_resolve(PyObject* NPY_UNUSED(self), PyObject* args) { if (!PyArray_Check(args)) { PyErr_SetString(PyExc_TypeError, "test needs ndarray input"); return NULL; } PyArray_ResolveWritebackIfCopy((PyArrayObject*)args); Py_RETURN_NONE; } /* resolve WRITEBACKIFCOPY */ static PyObject* npy_discard(PyObject* NPY_UNUSED(self), PyObject* args) { if (!PyArray_Check(args)) { PyErr_SetString(PyExc_TypeError, "test needs ndarray input"); return NULL; } PyArray_DiscardWritebackIfCopy((PyArrayObject*)args); Py_RETURN_NONE; } /* * Create python string from a FLAG and or the corresponding PyBuf flag * for the use in get_buffer_info. */ #define GET_PYBUF_FLAG(FLAG) \ buf_flag = PyUnicode_FromString(#FLAG); \ flag_matches = PyObject_RichCompareBool(buf_flag, tmp, Py_EQ); \ Py_DECREF(buf_flag); \ if (flag_matches == 1) { \ Py_DECREF(tmp); \ flags |= PyBUF_##FLAG; \ continue; \ } \ else if (flag_matches == -1) { \ Py_DECREF(tmp); \ return NULL; \ } /* * Get information for a buffer through PyBuf_GetBuffer with the * corresponding flags or'ed. Note that the python caller has to * make sure that or'ing those flags actually makes sense. * More information should probably be returned for future tests. */ static PyObject * get_buffer_info(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *buffer_obj, *pyflags; PyObject *tmp, *buf_flag; Py_buffer buffer; PyObject *shape, *strides; Py_ssize_t i, n; int flag_matches; int flags = 0; if (!PyArg_ParseTuple(args, "OO", &buffer_obj, &pyflags)) { return NULL; } n = PySequence_Length(pyflags); if (n < 0) { return NULL; } for (i=0; i < n; i++) { tmp = PySequence_GetItem(pyflags, i); if (tmp == NULL) { return NULL; } GET_PYBUF_FLAG(SIMPLE); GET_PYBUF_FLAG(WRITABLE); GET_PYBUF_FLAG(STRIDES); GET_PYBUF_FLAG(ND); GET_PYBUF_FLAG(C_CONTIGUOUS); GET_PYBUF_FLAG(F_CONTIGUOUS); GET_PYBUF_FLAG(ANY_CONTIGUOUS); GET_PYBUF_FLAG(INDIRECT); GET_PYBUF_FLAG(FORMAT); GET_PYBUF_FLAG(STRIDED); GET_PYBUF_FLAG(STRIDED_RO); GET_PYBUF_FLAG(RECORDS); GET_PYBUF_FLAG(RECORDS_RO); GET_PYBUF_FLAG(FULL); GET_PYBUF_FLAG(FULL_RO); GET_PYBUF_FLAG(CONTIG); GET_PYBUF_FLAG(CONTIG_RO); Py_DECREF(tmp); /* One of the flags must match */ PyErr_SetString(PyExc_ValueError, "invalid flag used."); return NULL; } if (PyObject_GetBuffer(buffer_obj, &buffer, flags) < 0) { return NULL; } if (buffer.shape == NULL) { Py_INCREF(Py_None); shape = Py_None; } else { shape = PyTuple_New(buffer.ndim); for (i=0; i < buffer.ndim; i++) { PyTuple_SET_ITEM(shape, i, PyLong_FromSsize_t(buffer.shape[i])); } } if (buffer.strides == NULL) { Py_INCREF(Py_None); strides = Py_None; } else { strides = PyTuple_New(buffer.ndim); for (i=0; i < buffer.ndim; i++) { PyTuple_SET_ITEM(strides, i, PyLong_FromSsize_t(buffer.strides[i])); } } PyBuffer_Release(&buffer); return Py_BuildValue("(NN)", shape, strides); } #undef GET_PYBUF_FLAG /* * Return a new array object wrapping existing C-allocated (dummy) data. * Such an array does not own its data (must not free it), but because it * wraps C data, it also has no base object. Used to test arr.flags.writeable * setting behaviour. */ static PyObject* get_c_wrapping_array(PyObject* NPY_UNUSED(self), PyObject* arg) { int writeable, flags; PyArray_Descr *descr; npy_intp zero = 0; writeable = PyObject_IsTrue(arg); if (error_converting(writeable)) { return NULL; } flags = writeable ? NPY_ARRAY_WRITEABLE : 0; /* Create an empty array (which points to a random place) */ descr = PyArray_DescrNewFromType(NPY_INTP); return PyArray_NewFromDescr(&PyArray_Type, descr, 1, &zero, NULL, &zero, flags, NULL); } static PyObject * get_all_cast_information(PyObject *NPY_UNUSED(mod), PyObject *NPY_UNUSED(args)) { PyObject *result = PyList_New(0); if (result == NULL) { return NULL; } PyObject *classes = PyObject_CallMethod( (PyObject *)&PyArrayDescr_Type, "__subclasses__", ""); if (classes == NULL) { goto fail; } Py_SETREF(classes, PySequence_Fast(classes, NULL)); if (classes == NULL) { goto fail; } Py_ssize_t nclass = PySequence_Length(classes); for (Py_ssize_t i = 0; i < nclass; i++) { PyArray_DTypeMeta *from_dtype = ( (PyArray_DTypeMeta *)PySequence_Fast_GET_ITEM(classes, i)); if (NPY_DT_is_abstract(from_dtype)) { /* * TODO: In principle probably needs to recursively check this, * also we may allow casts to abstract dtypes at some point. */ continue; } PyObject *to_dtype, *cast_obj; Py_ssize_t pos = 0; while (PyDict_Next(NPY_DT_SLOTS(from_dtype)->castingimpls, &pos, &to_dtype, &cast_obj)) { if (cast_obj == Py_None) { continue; } PyArrayMethodObject *cast = (PyArrayMethodObject *)cast_obj; /* Pass some information about this cast out! */ PyObject *cast_info = Py_BuildValue("{sOsOsisisisisiss}", "from", from_dtype, "to", to_dtype, "legacy", (cast->name != NULL && strncmp(cast->name, "legacy_", 7) == 0), "casting", cast->casting, "requires_pyapi", cast->flags & NPY_METH_REQUIRES_PYAPI, "supports_unaligned", cast->flags & NPY_METH_SUPPORTS_UNALIGNED, "no_floatingpoint_errors", cast->flags & NPY_METH_NO_FLOATINGPOINT_ERRORS, "name", cast->name); if (cast_info == NULL) { goto fail; } int res = PyList_Append(result, cast_info); Py_DECREF(cast_info); if (res < 0) { goto fail; } } } Py_DECREF(classes); return result; fail: Py_XDECREF(classes); Py_XDECREF(result); return NULL; } /* * Helper to test the identity cache, takes a list of values and adds * all to the cache except the last key/value pair. The last value is * ignored, instead the last key is looked up. * None is returned, if the key is not found. * If `replace` is True, duplicate entries are ignored when adding to the * hashtable. */ static PyObject * identityhash_tester(PyObject *NPY_UNUSED(mod), PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames) { NPY_PREPARE_ARGPARSER; int key_len; int replace; PyObject *replace_obj = Py_False; PyObject *sequence; PyObject *result = NULL; if (npy_parse_arguments("identityhash_tester", args, len_args, kwnames, "key_len", &PyArray_PythonPyIntFromInt, &key_len, "sequence", NULL, &sequence, "|replace", NULL, &replace_obj, NULL, NULL, NULL) < 0) { return NULL; } replace = PyObject_IsTrue(replace_obj); if (error_converting(replace)) { return NULL; } if (key_len < 1 || key_len >= NPY_MAXARGS) { PyErr_SetString(PyExc_ValueError, "must have 1 to max-args keys."); return NULL; } PyArrayIdentityHash *tb = PyArrayIdentityHash_New(key_len); if (tb == NULL) { return NULL; } /* Replace the sequence with a guaranteed fast-sequence */ sequence = PySequence_Fast(sequence, "converting sequence."); if (sequence == NULL) { goto finish; } Py_ssize_t length = PySequence_Fast_GET_SIZE(sequence); for (Py_ssize_t i = 0; i < length; i++) { PyObject *key_val = PySequence_Fast_GET_ITEM(sequence, i); if (!PyTuple_CheckExact(key_val) || PyTuple_GET_SIZE(key_val) != 2) { PyErr_SetString(PyExc_TypeError, "bad key-value pair."); goto finish; } PyObject *key = PyTuple_GET_ITEM(key_val, 0); PyObject *value = PyTuple_GET_ITEM(key_val, 1); if (!PyTuple_CheckExact(key) || PyTuple_GET_SIZE(key) != key_len) { PyErr_SetString(PyExc_TypeError, "bad key tuple."); goto finish; } PyObject *keys[NPY_MAXARGS]; for (int j = 0; j < key_len; j++) { keys[j] = PyTuple_GET_ITEM(key, j); } if (i != length - 1) { if (PyArrayIdentityHash_SetItem(tb, keys, value, replace) < 0) { goto finish; } } else { result = PyArrayIdentityHash_GetItem(tb, keys); if (result == NULL) { result = Py_None; } Py_INCREF(result); } } finish: Py_DECREF(sequence); PyArrayIdentityHash_Dealloc(tb); return result; } /* * Test C-api level item getting. */ static PyObject * array_indexing(PyObject *NPY_UNUSED(self), PyObject *args) { int mode; Py_ssize_t i; PyObject *arr, *op = NULL; if (!PyArg_ParseTuple(args, "iOn|O", &mode, &arr, &i, &op)) { return NULL; } if (mode == 0) { return PySequence_GetItem(arr, i); } if (mode == 1) { if (PySequence_SetItem(arr, i, op) < 0) { return NULL; } Py_RETURN_NONE; } PyErr_SetString(PyExc_ValueError, "invalid mode. 0: item 1: assign"); return NULL; } /* * Test C-api PyArray_AsCArray item getter */ static PyObject * test_as_c_array(PyObject *NPY_UNUSED(self), PyObject *args) { PyArrayObject *array_obj; npy_intp dims[3]; /* max 3-dim */ npy_intp i=0, j=0, k=0; npy_intp num_dims = 0; PyArray_Descr *descr = NULL; double *array1 = NULL; double **array2 = NULL; double ***array3 = NULL; double temp = 9999; if (!PyArg_ParseTuple(args, "O!l|ll", &PyArray_Type, &array_obj, &i, &j, &k)) { return NULL; } if (NULL == array_obj) { return NULL; } num_dims = PyArray_NDIM(array_obj); descr = PyArray_DESCR(array_obj); Py_INCREF(descr); /* PyArray_AsCArray steals a reference to this */ switch (num_dims) { case 1: if (PyArray_AsCArray( (PyObject **) &array_obj, (void *) &array1, dims, 1, descr) < 0) { PyErr_SetString(PyExc_RuntimeError, "error converting 1D array"); return NULL; } temp = array1[i]; PyArray_Free((PyObject *) array_obj, (void *) array1); break; case 2: if (PyArray_AsCArray( (PyObject **) &array_obj, (void **) &array2, dims, 2, descr) < 0) { PyErr_SetString(PyExc_RuntimeError, "error converting 2D array"); return NULL; } temp = array2[i][j]; PyArray_Free((PyObject *) array_obj, (void *) array2); break; case 3: if (PyArray_AsCArray( (PyObject **) &array_obj, (void ***) &array3, dims, 3, descr) < 0) { PyErr_SetString(PyExc_RuntimeError, "error converting 3D array"); return NULL; } temp = array3[i][j][k]; PyArray_Free((PyObject *) array_obj, (void *) array3); break; default: Py_DECREF(descr); PyErr_SetString(PyExc_ValueError, "array.ndim not in [1, 3]"); return NULL; } return Py_BuildValue("f", temp); } /* * Test nditer of too large arrays using remove axis, etc. */ static PyObject * test_nditer_too_large(PyObject *NPY_UNUSED(self), PyObject *args) { NpyIter *iter; PyObject *array_tuple, *arr; PyArrayObject *arrays[NPY_MAXARGS]; npy_uint32 op_flags[NPY_MAXARGS]; Py_ssize_t nop; int i, axis, mode; npy_intp index[NPY_MAXARGS] = {0}; char *msg; if (!PyArg_ParseTuple(args, "Oii", &array_tuple, &axis, &mode)) { return NULL; } if (!PyTuple_CheckExact(array_tuple)) { PyErr_SetString(PyExc_ValueError, "tuple required as first argument"); return NULL; } nop = PyTuple_Size(array_tuple); if (nop > NPY_MAXARGS) { PyErr_SetString(PyExc_ValueError, "tuple must be smaller then maxargs"); return NULL; } for (i=0; i < nop; i++) { arr = PyTuple_GET_ITEM(array_tuple, i); if (!PyArray_CheckExact(arr)) { PyErr_SetString(PyExc_ValueError, "require base class ndarray"); return NULL; } arrays[i] = (PyArrayObject *)arr; op_flags[i] = NPY_ITER_READONLY; } iter = NpyIter_MultiNew(nop, arrays, NPY_ITER_MULTI_INDEX | NPY_ITER_RANGED, NPY_KEEPORDER, NPY_NO_CASTING, op_flags, NULL); if (iter == NULL) { return NULL; } /* Remove an axis (negative, do not remove any) */ if (axis >= 0) { if (!NpyIter_RemoveAxis(iter, axis)) { goto fail; } } switch (mode) { /* Test IterNext getting */ case 0: if (NpyIter_GetIterNext(iter, NULL) == NULL) { goto fail; } break; case 1: if (NpyIter_GetIterNext(iter, &msg) == NULL) { PyErr_SetString(PyExc_ValueError, msg); goto fail; } break; /* Test Multi Index removal */ case 2: if (!NpyIter_RemoveMultiIndex(iter)) { goto fail; } break; /* Test GotoMultiIndex (just 0 hardcoded) */ case 3: if (!NpyIter_GotoMultiIndex(iter, index)) { goto fail; } break; /* Test setting iterrange (hardcoded range of 0, 1) */ case 4: if (!NpyIter_ResetToIterIndexRange(iter, 0, 1, NULL)) { goto fail; } break; case 5: if (!NpyIter_ResetToIterIndexRange(iter, 0, 1, &msg)) { PyErr_SetString(PyExc_ValueError, msg); goto fail; } break; /* Do nothing */ default: break; } NpyIter_Deallocate(iter); Py_RETURN_NONE; fail: NpyIter_Deallocate(iter); return NULL; } static PyObject * array_solve_diophantine(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) { PyObject *A = NULL; PyObject *U = NULL; Py_ssize_t b_input = 0; Py_ssize_t max_work = -1; int simplify = 0; int require_ub_nontrivial = 0; static char *kwlist[] = {"A", "U", "b", "max_work", "simplify", "require_ub_nontrivial", NULL}; diophantine_term_t terms[2*NPY_MAXDIMS+2]; npy_int64 x[2*NPY_MAXDIMS+2]; npy_int64 b; unsigned int nterms, j; mem_overlap_t result = MEM_OVERLAP_YES; PyObject *retval = NULL; NPY_BEGIN_THREADS_DEF; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!n|nii", kwlist, &PyTuple_Type, &A, &PyTuple_Type, &U, &b_input, &max_work, &simplify, &require_ub_nontrivial)) { return NULL; } if (PyTuple_GET_SIZE(A) > (Py_ssize_t)ARRAY_SIZE(terms)) { PyErr_SetString(PyExc_ValueError, "too many terms in equation"); goto fail; } nterms = PyTuple_GET_SIZE(A); if (PyTuple_GET_SIZE(U) != nterms) { PyErr_SetString(PyExc_ValueError, "A, U must be tuples of equal length"); goto fail; } for (j = 0; j < nterms; ++j) { terms[j].a = (npy_int64)PyLong_AsSsize_t(PyTuple_GET_ITEM(A, j)); if (error_converting(terms[j].a)) { goto fail; } terms[j].ub = (npy_int64)PyLong_AsSsize_t(PyTuple_GET_ITEM(U, j)); if (error_converting(terms[j].ub)) { goto fail; } } b = b_input; NPY_BEGIN_THREADS; if (simplify && !require_ub_nontrivial) { if (diophantine_simplify(&nterms, terms, b)) { result = MEM_OVERLAP_OVERFLOW; } } if (result == MEM_OVERLAP_YES) { result = solve_diophantine(nterms, terms, b, max_work, require_ub_nontrivial, x); } NPY_END_THREADS; if (result == MEM_OVERLAP_YES) { retval = PyTuple_New(nterms); if (retval == NULL) { goto fail; } for (j = 0; j < nterms; ++j) { PyObject *obj; obj = PyLong_FromSsize_t(x[j]); if (obj == NULL) { goto fail; } PyTuple_SET_ITEM(retval, j, obj); } } else if (result == MEM_OVERLAP_NO) { retval = Py_None; Py_INCREF(retval); } else if (result == MEM_OVERLAP_ERROR) { PyErr_SetString(PyExc_ValueError, "Invalid arguments"); } else if (result == MEM_OVERLAP_OVERFLOW) { PyErr_SetString(PyExc_OverflowError, "Integer overflow"); } else if (result == MEM_OVERLAP_TOO_HARD) { PyErr_SetString(PyExc_RuntimeError, "Too much work done"); } else { PyErr_SetString(PyExc_RuntimeError, "Unknown error"); } return retval; fail: Py_XDECREF(retval); return NULL; } static PyObject * array_internal_overlap(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kwds) { PyArrayObject * self = NULL; static char *kwlist[] = {"self", "max_work", NULL}; mem_overlap_t result; Py_ssize_t max_work = NPY_MAY_SHARE_EXACT; NPY_BEGIN_THREADS_DEF; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|n", kwlist, PyArray_Converter, &self, &max_work)) { return NULL; } if (max_work < -2) { PyErr_SetString(PyExc_ValueError, "Invalid value for max_work"); goto fail; } NPY_BEGIN_THREADS; result = solve_may_have_internal_overlap(self, max_work); NPY_END_THREADS; Py_XDECREF(self); if (result == MEM_OVERLAP_NO) { Py_RETURN_FALSE; } else if (result == MEM_OVERLAP_YES) { Py_RETURN_TRUE; } else if (result == MEM_OVERLAP_OVERFLOW) { PyErr_SetString(PyExc_OverflowError, "Integer overflow in computing overlap"); return NULL; } else if (result == MEM_OVERLAP_TOO_HARD) { PyErr_SetString(PyExc_ValueError, "Exceeded max_work"); return NULL; } else { /* Doesn't happen usually */ PyErr_SetString(PyExc_RuntimeError, "Error in computing overlap"); return NULL; } fail: Py_XDECREF(self); return NULL; } static PyObject * pylong_from_int128(npy_extint128_t value) { PyObject *val_64 = NULL, *val = NULL, *tmp = NULL, *tmp2 = NULL; val_64 = PyLong_FromLong(64); if (val_64 == NULL) { goto fail; } val = PyLong_FromUnsignedLongLong(value.hi); if (val == NULL) { goto fail; } tmp = PyNumber_Lshift(val, val_64); if (tmp == NULL) { goto fail; } Py_DECREF(val); Py_DECREF(val_64); val = tmp; val_64 = NULL; tmp = PyLong_FromUnsignedLongLong(value.lo); if (tmp == NULL) { goto fail; } tmp2 = PyNumber_Or(val, tmp); if (tmp2 == NULL) { goto fail; } Py_DECREF(val); Py_DECREF(tmp); val = NULL; tmp = NULL; if (value.sign < 0) { val = PyNumber_Negative(tmp2); if (val == NULL) { goto fail; } Py_DECREF(tmp2); return val; } else { val = tmp2; } return val; fail: Py_XDECREF(val_64); Py_XDECREF(tmp); Py_XDECREF(tmp2); Py_XDECREF(val); return NULL; } static int int128_from_pylong(PyObject *obj, npy_extint128_t *result) { PyObject *long_obj = NULL, *val_64 = NULL, *val_0 = NULL, *mask_64 = NULL, *max_128 = NULL, *hi_bits = NULL, *lo_bits = NULL, *tmp = NULL; int cmp; int negative_zero = 0; if (PyBool_Check(obj)) { /* False means negative zero */ negative_zero = 1; } long_obj = PyObject_CallFunction((PyObject*)&PyLong_Type, "O", obj); if (long_obj == NULL) { goto fail; } val_0 = PyLong_FromLong(0); if (val_0 == NULL) { goto fail; } val_64 = PyLong_FromLong(64); if (val_64 == NULL) { goto fail; } mask_64 = PyLong_FromUnsignedLongLong(0xffffffffffffffffULL); if (mask_64 == NULL) { goto fail; } tmp = PyNumber_Lshift(mask_64, val_64); if (tmp == NULL) { goto fail; } max_128 = PyNumber_Or(tmp, mask_64); if (max_128 == NULL) { goto fail; } Py_DECREF(tmp); tmp = NULL; cmp = PyObject_RichCompareBool(long_obj, val_0, Py_LT); if (cmp == -1) { goto fail; } else if (cmp == 1) { tmp = PyNumber_Negative(long_obj); if (tmp == NULL) { goto fail; } Py_DECREF(long_obj); long_obj = tmp; tmp = NULL; result->sign = -1; } else { result->sign = 1; } cmp = PyObject_RichCompareBool(long_obj, max_128, Py_GT); if (cmp == 1) { PyErr_SetString(PyExc_OverflowError, ""); goto fail; } else if (cmp == -1) { goto fail; } hi_bits = PyNumber_Rshift(long_obj, val_64); if (hi_bits == NULL) { goto fail; } lo_bits = PyNumber_And(long_obj, mask_64); if (lo_bits == NULL) { goto fail; } result->hi = PyLong_AsUnsignedLongLong(hi_bits); if (result->hi == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) { goto fail; } result->lo = PyLong_AsUnsignedLongLong(lo_bits); if (result->lo == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) { goto fail; } if (negative_zero && result->hi == 0 && result->lo == 0) { result->sign = -1; } Py_XDECREF(long_obj); Py_XDECREF(val_64); Py_XDECREF(val_0); Py_XDECREF(mask_64); Py_XDECREF(max_128); Py_XDECREF(hi_bits); Py_XDECREF(lo_bits); Py_XDECREF(tmp); return 0; fail: Py_XDECREF(long_obj); Py_XDECREF(val_64); Py_XDECREF(val_0); Py_XDECREF(mask_64); Py_XDECREF(max_128); Py_XDECREF(hi_bits); Py_XDECREF(lo_bits); Py_XDECREF(tmp); return -1; } static PyObject * extint_safe_binop(PyObject *NPY_UNUSED(self), PyObject *args) { PY_LONG_LONG a, b, c; int op; char overflow = 0; if (!PyArg_ParseTuple(args, "LLi", &a, &b, &op)) { return NULL; } if (op == 1) { c = safe_add(a, b, &overflow); } else if (op == 2) { c = safe_sub(a, b, &overflow); } else if (op == 3) { c = safe_mul(a, b, &overflow); } else { PyErr_SetString(PyExc_ValueError, "invalid op"); return NULL; } if (overflow) { PyErr_SetString(PyExc_OverflowError, ""); return NULL; } return PyLong_FromLongLong(c); } static PyObject * extint_to_128(PyObject *NPY_UNUSED(self), PyObject *args) { PY_LONG_LONG a; if (!PyArg_ParseTuple(args, "L", &a)) { return NULL; } return pylong_from_int128(to_128(a)); } static PyObject * extint_to_64(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *a_obj; npy_extint128_t a; PY_LONG_LONG r; char overflow = 0; if (!PyArg_ParseTuple(args, "O", &a_obj)) { return NULL; } if (int128_from_pylong(a_obj, &a)) { return NULL; } r = to_64(a, &overflow); if (overflow) { PyErr_SetString(PyExc_OverflowError, ""); return NULL; } return PyLong_FromLongLong(r); } static PyObject * extint_mul_64_64(PyObject *NPY_UNUSED(self), PyObject *args) { PY_LONG_LONG a, b; npy_extint128_t c; if (!PyArg_ParseTuple(args, "LL", &a, &b)) { return NULL; } c = mul_64_64(a, b); return pylong_from_int128(c); } static PyObject * extint_add_128(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *a_obj, *b_obj; npy_extint128_t a, b, c; char overflow = 0; if (!PyArg_ParseTuple(args, "OO", &a_obj, &b_obj)) { return NULL; } if (int128_from_pylong(a_obj, &a) || int128_from_pylong(b_obj, &b)) { return NULL; } c = add_128(a, b, &overflow); if (overflow) { PyErr_SetString(PyExc_OverflowError, ""); return NULL; } return pylong_from_int128(c); } static PyObject * extint_sub_128(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *a_obj, *b_obj; npy_extint128_t a, b, c; char overflow = 0; if (!PyArg_ParseTuple(args, "OO", &a_obj, &b_obj)) { return NULL; } if (int128_from_pylong(a_obj, &a) || int128_from_pylong(b_obj, &b)) { return NULL; } c = sub_128(a, b, &overflow); if (overflow) { PyErr_SetString(PyExc_OverflowError, ""); return NULL; } return pylong_from_int128(c); } static PyObject * extint_neg_128(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *a_obj; npy_extint128_t a, b; if (!PyArg_ParseTuple(args, "O", &a_obj)) { return NULL; } if (int128_from_pylong(a_obj, &a)) { return NULL; } b = neg_128(a); return pylong_from_int128(b); } static PyObject * extint_shl_128(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *a_obj; npy_extint128_t a, b; if (!PyArg_ParseTuple(args, "O", &a_obj)) { return NULL; } if (int128_from_pylong(a_obj, &a)) { return NULL; } b = shl_128(a); return pylong_from_int128(b); } static PyObject * extint_shr_128(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *a_obj; npy_extint128_t a, b; if (!PyArg_ParseTuple(args, "O", &a_obj)) { return NULL; } if (int128_from_pylong(a_obj, &a)) { return NULL; } b = shr_128(a); return pylong_from_int128(b); } static PyObject * extint_gt_128(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *a_obj, *b_obj; npy_extint128_t a, b; if (!PyArg_ParseTuple(args, "OO", &a_obj, &b_obj)) { return NULL; } if (int128_from_pylong(a_obj, &a) || int128_from_pylong(b_obj, &b)) { return NULL; } if (gt_128(a, b)) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static PyObject * extint_divmod_128_64(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *a_obj, *ret = NULL, *tmp = NULL; npy_extint128_t a, c; PY_LONG_LONG b; npy_int64 mod; if (!PyArg_ParseTuple(args, "OL", &a_obj, &b)) { goto fail; } if (b <= 0) { PyErr_SetString(PyExc_ValueError, ""); goto fail; } if (int128_from_pylong(a_obj, &a)) { goto fail; } c = divmod_128_64(a, b, &mod); ret = PyTuple_New(2); tmp = pylong_from_int128(c); if (tmp == NULL) { goto fail; } PyTuple_SET_ITEM(ret, 0, tmp); tmp = PyLong_FromLongLong(mod); if (tmp == NULL) { goto fail; } PyTuple_SET_ITEM(ret, 1, tmp); return ret; fail: Py_XDECREF(ret); Py_XDECREF(tmp); return NULL; } static PyObject * extint_floordiv_128_64(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *a_obj; npy_extint128_t a, c; PY_LONG_LONG b; if (!PyArg_ParseTuple(args, "OL", &a_obj, &b)) { return NULL; } if (b <= 0) { PyErr_SetString(PyExc_ValueError, ""); return NULL; } if (int128_from_pylong(a_obj, &a)) { return NULL; } c = floordiv_128_64(a, b); return pylong_from_int128(c); } static PyObject * extint_ceildiv_128_64(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *a_obj; npy_extint128_t a, c; PY_LONG_LONG b; if (!PyArg_ParseTuple(args, "OL", &a_obj, &b)) { return NULL; } if (b <= 0) { PyErr_SetString(PyExc_ValueError, ""); return NULL; } if (int128_from_pylong(a_obj, &a)) { return NULL; } c = ceildiv_128_64(a, b); return pylong_from_int128(c); } struct TestStruct1 { npy_uint8 a; npy_complex64 b; }; struct TestStruct2 { npy_uint32 a; npy_complex64 b; }; struct TestStruct3 { npy_uint8 a; struct TestStruct1 b; }; static PyObject * get_struct_alignments(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *ret = PyTuple_New(3); PyObject *alignment, *size, *val; if (ret == NULL) { return NULL; } /**begin repeat * #N = 1,2,3# */ alignment = PyLong_FromLong(NPY_ALIGNOF(struct TestStruct@N@)); size = PyLong_FromLong(sizeof(struct TestStruct@N@)); val = PyTuple_Pack(2, alignment, size); Py_DECREF(alignment); Py_DECREF(size); if (val == NULL) { Py_DECREF(ret); return NULL; } PyTuple_SET_ITEM(ret, @N@-1, val); /**end repeat**/ return ret; } static char get_fpu_mode_doc[] = ( "get_fpu_mode()\n" "\n" "Get the current FPU control word, in a platform-dependent format.\n" "Returns None if not implemented on current platform."); static PyObject * get_fpu_mode(PyObject *NPY_UNUSED(self), PyObject *args) { if (!PyArg_ParseTuple(args, "")) { return NULL; } #if defined(_MSC_VER) && !defined(__clang__) { unsigned int result = 0; result = _controlfp(0, 0); return PyLong_FromLongLong(result); } #elif (defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))) \ || (defined(_MSC_VER) && defined(__clang__) && \ (defined(_M_IX86) || defined(_M_AMD64))) { unsigned short cw = 0; __asm__("fstcw %w0" : "=m" (cw)); return PyLong_FromLongLong(cw); } #else Py_RETURN_NONE; #endif } /* * npymath wrappers */ /**begin repeat * #name = cabs, carg# */ /**begin repeat1 * #itype = npy_cfloat, npy_cdouble, npy_clongdouble# * #ITYPE = NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE# * #otype = npy_float, npy_double, npy_longdouble# * #OTYPE = NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE# * #suffix= f, , l# */ static PyObject * call_npy_@name@@suffix@(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *z_py = NULL, *z_arr = NULL, *w_arr = NULL; if (!PyArg_ParseTuple(args, "O", &z_py)) { return NULL; } z_arr = PyArray_FROMANY(z_py, @ITYPE@, 0, 0, NPY_ARRAY_CARRAY_RO); if (z_arr == NULL) { return NULL; } w_arr = PyArray_SimpleNew(0, NULL, @OTYPE@); if (w_arr == NULL) { Py_DECREF(z_arr); return NULL; } *(@otype@*)PyArray_DATA((PyArrayObject *)w_arr) = npy_@name@@suffix@(*(@itype@*)PyArray_DATA((PyArrayObject *)z_arr)); Py_DECREF(z_arr); return w_arr; } /**end repeat1**/ /**end repeat**/ /**begin repeat * #name = log10, cosh, sinh, tan, tanh# */ /**begin repeat1 * #type = npy_float, npy_double, npy_longdouble# * #TYPE = NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE# * #suffix= f, , l# */ static PyObject * call_npy_@name@@suffix@(PyObject *NPY_UNUSED(self), PyObject *args) { PyObject *z_py = NULL, *z_arr = NULL, *w_arr = NULL; if (!PyArg_ParseTuple(args, "O", &z_py)) { return NULL; } z_arr = PyArray_FROMANY(z_py, @TYPE@, 0, 0, NPY_ARRAY_CARRAY_RO); if (z_arr == NULL) { return NULL; } w_arr = PyArray_SimpleNew(0, NULL, @TYPE@); if (w_arr == NULL) { Py_DECREF(z_arr); return NULL; } *(@type@*)PyArray_DATA((PyArrayObject *)w_arr) = npy_@name@@suffix@(*(@type@*)PyArray_DATA((PyArrayObject *)z_arr)); Py_DECREF(z_arr); return w_arr; } /**end repeat1**/ /**end repeat**/ /* * For development/testing purposes, it's convenient to have access to the * system printf for floats. This is a very simple printf interface. */ PyObject * PrintFloat_Printf_g(PyObject *obj, int precision) { char str[1024]; if (PyArray_IsScalar(obj, Half)) { npy_half x = PyArrayScalar_VAL(obj, Half); PyOS_snprintf(str, sizeof(str), "%.*g", precision, npy_half_to_double(x)); } else if (PyArray_IsScalar(obj, Float)) { npy_float x = PyArrayScalar_VAL(obj, Float); PyOS_snprintf(str, sizeof(str), "%.*g", precision, x); } else if (PyArray_IsScalar(obj, Double)) { npy_double x = PyArrayScalar_VAL(obj, Double); PyOS_snprintf(str, sizeof(str), "%.*g", precision, x); /* would be better to use lg, but not available in C90 */ } else if (PyArray_IsScalar(obj, LongDouble)) { npy_longdouble x = PyArrayScalar_VAL(obj, LongDouble); PyOS_snprintf(str, sizeof(str), "%.*" NPY_LONGDOUBLE_FMT, precision, x); } else{ double val = PyFloat_AsDouble(obj); if (error_converting(val)) { return NULL; } PyOS_snprintf(str, sizeof(str), "%.*g", precision, val); } return PyUnicode_FromString(str); } /* * format_float_OSprintf_g(val, precision) * * Print a floating point scalar using the system's printf function, * equivalent to: * * printf("%.*g", precision, val); * * for half/float/double, or replacing 'g' by 'Lg' for longdouble. This * method is designed to help cross-validate the format_float_* methods. * * Parameters * ---------- * val : python float or numpy floating scalar * Value to format. * * precision : non-negative integer, optional * Precision given to printf. * * Returns * ------- * rep : string * The string representation of the floating point value * * See Also * -------- * format_float_scientific * format_float_positional */ static PyObject * printf_float_g(PyObject *NPY_UNUSED(dummy), PyObject *args, PyObject *kwds) { PyObject *obj; int precision; if (!PyArg_ParseTuple(args,"Oi:format_float_OSprintf_g", &obj, &precision)) { return NULL; } if (precision < 0) { PyErr_SetString(PyExc_TypeError, "precision must be non-negative"); return NULL; } return PrintFloat_Printf_g(obj, precision); } static PyObject * run_byteorder_converter(PyObject* NPY_UNUSED(self), PyObject *args) { char byteorder; if (!PyArg_ParseTuple(args, "O&", PyArray_ByteorderConverter, &byteorder)) { return NULL; } switch (byteorder) { case NPY_BIG: return PyUnicode_FromString("NPY_BIG"); case NPY_LITTLE: return PyUnicode_FromString("NPY_LITTLE"); case NPY_NATIVE: return PyUnicode_FromString("NPY_NATIVE"); case NPY_SWAP: return PyUnicode_FromString("NPY_SWAP"); case NPY_IGNORE: return PyUnicode_FromString("NPY_IGNORE"); } return PyLong_FromLong(byteorder); } static PyObject * run_sortkind_converter(PyObject* NPY_UNUSED(self), PyObject *args) { NPY_SORTKIND kind; if (!PyArg_ParseTuple(args, "O&", PyArray_SortkindConverter, &kind)) { return NULL; } switch (kind) { case _NPY_SORT_UNDEFINED: return PyUnicode_FromString("_NPY_SORT_UNDEFINED"); case NPY_QUICKSORT: return PyUnicode_FromString("NPY_QUICKSORT"); case NPY_HEAPSORT: return PyUnicode_FromString("NPY_HEAPSORT"); case NPY_STABLESORT: return PyUnicode_FromString("NPY_STABLESORT"); } return PyLong_FromLong(kind); } static PyObject * run_selectkind_converter(PyObject* NPY_UNUSED(self), PyObject *args) { NPY_SELECTKIND kind; if (!PyArg_ParseTuple(args, "O&", PyArray_SelectkindConverter, &kind)) { return NULL; } switch (kind) { case NPY_INTROSELECT: return PyUnicode_FromString("NPY_INTROSELECT"); } return PyLong_FromLong(kind); } static PyObject * run_searchside_converter(PyObject* NPY_UNUSED(self), PyObject *args) { NPY_SEARCHSIDE side; if (!PyArg_ParseTuple(args, "O&", PyArray_SearchsideConverter, &side)) { return NULL; } switch (side) { case NPY_SEARCHLEFT: return PyUnicode_FromString("NPY_SEARCHLEFT"); case NPY_SEARCHRIGHT: return PyUnicode_FromString("NPY_SEARCHRIGHT"); } return PyLong_FromLong(side); } static PyObject * run_order_converter(PyObject* NPY_UNUSED(self), PyObject *args) { NPY_ORDER order; if (!PyArg_ParseTuple(args, "O&", PyArray_OrderConverter, &order)) { return NULL; } switch (order) { case NPY_ANYORDER: return PyUnicode_FromString("NPY_ANYORDER"); case NPY_CORDER: return PyUnicode_FromString("NPY_CORDER"); case NPY_FORTRANORDER: return PyUnicode_FromString("NPY_FORTRANORDER"); case NPY_KEEPORDER: return PyUnicode_FromString("NPY_KEEPORDER"); } return PyLong_FromLong(order); } static PyObject * run_clipmode_converter(PyObject* NPY_UNUSED(self), PyObject *args) { NPY_CLIPMODE mode; if (!PyArg_ParseTuple(args, "O&", PyArray_ClipmodeConverter, &mode)) { return NULL; } switch (mode) { case NPY_CLIP: return PyUnicode_FromString("NPY_CLIP"); case NPY_WRAP: return PyUnicode_FromString("NPY_WRAP"); case NPY_RAISE: return PyUnicode_FromString("NPY_RAISE"); } return PyLong_FromLong(mode); } static PyObject * run_casting_converter(PyObject* NPY_UNUSED(self), PyObject *args) { NPY_CASTING casting; if (!PyArg_ParseTuple(args, "O&", PyArray_CastingConverter, &casting)) { return NULL; } switch (casting) { case NPY_NO_CASTING: return PyUnicode_FromString("NPY_NO_CASTING"); case NPY_EQUIV_CASTING: return PyUnicode_FromString("NPY_EQUIV_CASTING"); case NPY_SAFE_CASTING: return PyUnicode_FromString("NPY_SAFE_CASTING"); case NPY_SAME_KIND_CASTING: return PyUnicode_FromString("NPY_SAME_KIND_CASTING"); case NPY_UNSAFE_CASTING: return PyUnicode_FromString("NPY_UNSAFE_CASTING"); default: return PyLong_FromLong(casting); } } static PyObject * run_intp_converter(PyObject* NPY_UNUSED(self), PyObject *args) { PyArray_Dims dims = {NULL, -1}; if (!PyArg_ParseTuple(args, "O&", PyArray_IntpConverter, &dims)) { return NULL; } if (dims.len == -1) { Py_RETURN_NONE; } PyObject *tup = PyArray_IntTupleFromIntp(dims.len, dims.ptr); PyDimMem_FREE(dims.ptr); return tup; } /* used to test NPY_ARRAY_ENSURENOCOPY raises ValueError */ static PyObject* npy_ensurenocopy(PyObject* NPY_UNUSED(self), PyObject* args) { int flags = NPY_ARRAY_ENSURENOCOPY; if (!PyArray_CheckFromAny(args, NULL, 0, 0, flags, NULL)) { return NULL; } Py_RETURN_NONE; } static PyObject * run_scalar_intp_converter(PyObject *NPY_UNUSED(self), PyObject *obj) { PyArray_Dims dims; if (!PyArray_IntpConverter(obj, &dims)) { return NULL; } else { PyObject *result = PyArray_IntTupleFromIntp(dims.len, dims.ptr); PyDimMem_FREE(dims.ptr); return result; } } static PyObject * run_scalar_intp_from_sequence(PyObject *NPY_UNUSED(self), PyObject *obj) { npy_intp vals[1]; int output = PyArray_IntpFromSequence(obj, vals, 1); if (output == -1) { return NULL; } return PyArray_IntTupleFromIntp(1, vals); } static PyMethodDef Multiarray_TestsMethods[] = { {"argparse_example_function", (PyCFunction)argparse_example_function, METH_KEYWORDS | METH_FASTCALL, NULL}, {"threaded_argparse_example_function", (PyCFunction)threaded_argparse_example_function, METH_KEYWORDS | METH_FASTCALL, NULL}, {"IsPythonScalar", IsPythonScalar, METH_VARARGS, NULL}, {"test_neighborhood_iterator", test_neighborhood_iterator, METH_VARARGS, NULL}, {"test_neighborhood_iterator_oob", test_neighborhood_iterator_oob, METH_VARARGS, NULL}, {"fromstring_null_term_c_api", fromstring_null_term_c_api, METH_O, NULL}, {"create_custom_field_dtype", create_custom_field_dtype, METH_VARARGS, NULL}, {"corrupt_or_fix_bufferinfo", corrupt_or_fix_bufferinfo, METH_O, NULL}, {"incref_elide", incref_elide, METH_VARARGS, NULL}, {"incref_elide_l", incref_elide_l, METH_VARARGS, NULL}, {"npy_char_deprecation", npy_char_deprecation, METH_NOARGS, NULL}, {"npy_create_writebackifcopy", npy_create_writebackifcopy, METH_O, NULL}, {"npy_abuse_writebackifcopy", npy_abuse_writebackifcopy, METH_O, NULL}, {"npy_resolve", npy_resolve, METH_O, NULL}, {"npy_discard", npy_discard, METH_O, NULL}, {"npy_ensurenocopy", npy_ensurenocopy, METH_O, NULL}, {"get_buffer_info", get_buffer_info, METH_VARARGS, NULL}, {"get_c_wrapping_array", get_c_wrapping_array, METH_O, NULL}, {"get_all_cast_information", get_all_cast_information, METH_NOARGS, "Return a list with info on all available casts. Some of the info" "may differ for an actual cast if it uses value-based casting " "(flexible types)."}, {"identityhash_tester", (PyCFunction)identityhash_tester, METH_KEYWORDS | METH_FASTCALL, NULL}, {"array_indexing", array_indexing, METH_VARARGS, NULL}, {"test_as_c_array", test_as_c_array, METH_VARARGS, NULL}, {"test_nditer_too_large", test_nditer_too_large, METH_VARARGS, NULL}, {"solve_diophantine", (PyCFunction)array_solve_diophantine, METH_VARARGS | METH_KEYWORDS, NULL}, {"internal_overlap", (PyCFunction)array_internal_overlap, METH_VARARGS | METH_KEYWORDS, NULL}, {"extint_safe_binop", extint_safe_binop, METH_VARARGS, NULL}, {"extint_to_128", extint_to_128, METH_VARARGS, NULL}, {"extint_to_64", extint_to_64, METH_VARARGS, NULL}, {"extint_mul_64_64", extint_mul_64_64, METH_VARARGS, NULL}, {"extint_add_128", extint_add_128, METH_VARARGS, NULL}, {"extint_sub_128", extint_sub_128, METH_VARARGS, NULL}, {"extint_neg_128", extint_neg_128, METH_VARARGS, NULL}, {"extint_shl_128", extint_shl_128, METH_VARARGS, NULL}, {"extint_shr_128", extint_shr_128, METH_VARARGS, NULL}, {"extint_gt_128", extint_gt_128, METH_VARARGS, NULL}, {"extint_divmod_128_64", extint_divmod_128_64, METH_VARARGS, NULL}, {"extint_floordiv_128_64", extint_floordiv_128_64, METH_VARARGS, NULL}, {"extint_ceildiv_128_64", extint_ceildiv_128_64, METH_VARARGS, NULL}, {"get_fpu_mode", get_fpu_mode, METH_VARARGS, get_fpu_mode_doc}, /**begin repeat * #name = cabs, carg# */ /**begin repeat1 * #suffix = f, , l# */ {"npy_@name@@suffix@", call_npy_@name@@suffix@, METH_VARARGS, NULL}, /**end repeat1**/ /**end repeat**/ /**begin repeat * #name = log10, cosh, sinh, tan, tanh# */ /**begin repeat1 * #suffix= f, , l# */ {"npy_@name@@suffix@", call_npy_@name@@suffix@, METH_VARARGS, NULL}, /**end repeat1**/ /**end repeat**/ {"format_float_OSprintf_g", (PyCFunction)printf_float_g, METH_VARARGS , NULL}, {"get_struct_alignments", get_struct_alignments, METH_VARARGS, NULL}, {"run_byteorder_converter", run_byteorder_converter, METH_VARARGS, NULL}, {"run_sortkind_converter", run_sortkind_converter, METH_VARARGS, NULL}, {"run_selectkind_converter", run_selectkind_converter, METH_VARARGS, NULL}, {"run_searchside_converter", run_searchside_converter, METH_VARARGS, NULL}, {"run_order_converter", run_order_converter, METH_VARARGS, NULL}, {"run_clipmode_converter", run_clipmode_converter, METH_VARARGS, NULL}, {"run_casting_converter", run_casting_converter, METH_VARARGS, NULL}, {"run_scalar_intp_converter", run_scalar_intp_converter, METH_O, NULL}, {"run_scalar_intp_from_sequence", run_scalar_intp_from_sequence, METH_O, NULL}, {"run_intp_converter", run_intp_converter, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} /* Sentinel */ }; static int module_loaded = 0; static int _multiarray_tests_exec(PyObject *m) { // https://docs.python.org/3/howto/isolating-extensions.html#opt-out-limiting-to-one-module-object-per-process if (module_loaded) { PyErr_SetString(PyExc_ImportError, "cannot load module more than once per process"); return -1; } module_loaded = 1; if (PyArray_ImportNumPyAPI() < 0) { return -1; } if (init_argparse_mutex() < 0) { return -1; } if (PyErr_Occurred()) { PyErr_SetString(PyExc_RuntimeError, "cannot load _multiarray_tests module."); } return 0; } static struct PyModuleDef_Slot _multiarray_tests_slots[] = { {Py_mod_exec, _multiarray_tests_exec}, #if PY_VERSION_HEX >= 0x030c00f0 // Python 3.12+ {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, #endif #if PY_VERSION_HEX >= 0x030d00f0 // Python 3.13+ // signal that this module supports running without an active GIL {Py_mod_gil, Py_MOD_GIL_NOT_USED}, #endif {0, NULL}, }; static struct PyModuleDef moduledef = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "_multiarray_tests", .m_size = 0, .m_methods = Multiarray_TestsMethods, .m_slots = _multiarray_tests_slots, }; PyMODINIT_FUNC PyInit__multiarray_tests(void) { return PyModuleDef_Init(&moduledef); } NPY_NO_EXPORT int test_not_exported(void) { return 1; }