diff --git a/numpy/core/code_generators/genapi.py b/numpy/core/code_generators/genapi.py index b618dedf562b..a64d62e6eff7 100644 --- a/numpy/core/code_generators/genapi.py +++ b/numpy/core/code_generators/genapi.py @@ -52,6 +52,7 @@ join('multiarray', 'scalarapi.c'), join('multiarray', 'sequence.c'), join('multiarray', 'shape.c'), + join('multiarray', 'strfuncs.c'), join('multiarray', 'usertypes.c'), join('umath', 'loops.c.src'), join('umath', 'ufunc_object.c'), diff --git a/numpy/core/code_generators/generate_numpy_api.py b/numpy/core/code_generators/generate_numpy_api.py index 79d774a89b15..b4aeaa277fd8 100644 --- a/numpy/core/code_generators/generate_numpy_api.py +++ b/numpy/core/code_generators/generate_numpy_api.py @@ -220,8 +220,13 @@ def do_generate_api(targets, sources): multiarray_api_dict[name] = TypeApi(name, index, 'PyTypeObject', api_name) if len(multiarray_api_dict) != len(multiarray_api_index): - raise AssertionError("Multiarray API size mismatch %d %d" % - (len(multiarray_api_dict), len(multiarray_api_index))) + keys_dict = set(multiarray_api_dict.keys()) + keys_index = set(multiarray_api_index.keys()) + raise AssertionError( + "Multiarray API size mismatch - " + "index has extra keys {}, dict has extra keys {}" + .format(keys_index - keys_dict, keys_dict - keys_index) + ) extension_list = [] for name, index in genapi.order_dict(multiarray_api_index): diff --git a/numpy/core/setup.py b/numpy/core/setup.py index e057c56141d3..f268258eea67 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -741,6 +741,7 @@ def get_mathlib_info(*args): join('src', 'multiarray', 'scalartypes.h'), join('src', 'multiarray', 'sequence.h'), join('src', 'multiarray', 'shape.h'), + join('src', 'multiarray', 'strfuncs.h'), join('src', 'multiarray', 'ucsnarrow.h'), join('src', 'multiarray', 'usertypes.h'), join('src', 'multiarray', 'vdot.h'), @@ -814,6 +815,7 @@ def get_mathlib_info(*args): join('src', 'multiarray', 'shape.c'), join('src', 'multiarray', 'scalarapi.c'), join('src', 'multiarray', 'scalartypes.c.src'), + join('src', 'multiarray', 'strfuncs.c'), join('src', 'multiarray', 'temp_elide.c'), join('src', 'multiarray', 'usertypes.c'), join('src', 'multiarray', 'ucsnarrow.c'), diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c index 062fa8879599..0e655d80c1d8 100644 --- a/numpy/core/src/multiarray/arrayobject.c +++ b/numpy/core/src/multiarray/arrayobject.c @@ -53,6 +53,7 @@ maintainer email: oliphant.travis@ieee.org #include "alloc.h" #include "mem_overlap.h" #include "numpyos.h" +#include "strfuncs.h" #include "binop_override.h" @@ -433,93 +434,6 @@ array_dealloc(PyArrayObject *self) Py_TYPE(self)->tp_free((PyObject *)self); } -/* - * Extend string. On failure, returns NULL and leaves *strp alone. - * XXX we do this in multiple places; time for a string library? - */ -static char * -extend(char **strp, Py_ssize_t n, Py_ssize_t *maxp) -{ - char *str = *strp; - Py_ssize_t new_cap; - - if (n >= *maxp - 16) { - new_cap = *maxp * 2; - - if (new_cap <= *maxp) { /* overflow */ - return NULL; - } - str = PyArray_realloc(*strp, new_cap); - if (str != NULL) { - *strp = str; - *maxp = new_cap; - } - } - return str; -} - -static int -dump_data(char **string, Py_ssize_t *n, Py_ssize_t *max_n, char *data, int nd, - npy_intp *dimensions, npy_intp *strides, PyArrayObject* self) -{ - PyArray_Descr *descr=PyArray_DESCR(self); - PyObject *op = NULL, *sp = NULL; - char *ostring; - npy_intp i, N, ret = 0; - -#define CHECK_MEMORY do { \ - if (extend(string, *n, max_n) == NULL) { \ - ret = -1; \ - goto end; \ - } \ - } while (0) - - if (nd == 0) { - if ((op = descr->f->getitem(data, self)) == NULL) { - return -1; - } - sp = PyObject_Repr(op); - if (sp == NULL) { - ret = -1; - goto end; - } - ostring = PyString_AsString(sp); - N = PyString_Size(sp)*sizeof(char); - *n += N; - CHECK_MEMORY; - memmove(*string + (*n - N), ostring, N); - } - else { - CHECK_MEMORY; - (*string)[*n] = '['; - *n += 1; - for (i = 0; i < dimensions[0]; i++) { - if (dump_data(string, n, max_n, - data + (*strides)*i, - nd - 1, dimensions + 1, - strides + 1, self) < 0) { - return -1; - } - CHECK_MEMORY; - if (i < dimensions[0] - 1) { - (*string)[*n] = ','; - (*string)[*n+1] = ' '; - *n += 2; - } - } - CHECK_MEMORY; - (*string)[*n] = ']'; - *n += 1; - } - -#undef CHECK_MEMORY - -end: - Py_XDECREF(op); - Py_XDECREF(sp); - return ret; -} - /*NUMPY_API * Prints the raw data of the ndarray in a form useful for debugging * low-level C issues. @@ -582,72 +496,6 @@ PyArray_DebugPrint(PyArrayObject *obj) fflush(stdout); } -static PyObject * -array_repr_builtin(PyArrayObject *self, int repr) -{ - PyObject *ret; - char *string; - /* max_n initial value is arbitrary, dump_data will extend it */ - Py_ssize_t n = 0, max_n = PyArray_NBYTES(self) * 4 + 7; - - if ((string = PyArray_malloc(max_n)) == NULL) { - return PyErr_NoMemory(); - } - - if (dump_data(&string, &n, &max_n, PyArray_DATA(self), - PyArray_NDIM(self), PyArray_DIMS(self), - PyArray_STRIDES(self), self) < 0) { - PyArray_free(string); - return NULL; - } - - if (repr) { - if (PyArray_ISEXTENDED(self)) { - ret = PyUString_FromFormat("array(%s, '%c%d')", - string, - PyArray_DESCR(self)->type, - PyArray_DESCR(self)->elsize); - } - else { - ret = PyUString_FromFormat("array(%s, '%c')", - string, - PyArray_DESCR(self)->type); - } - } - else { - ret = PyUString_FromStringAndSize(string, n); - } - - PyArray_free(string); - return ret; -} - -static PyObject *PyArray_StrFunction = NULL; -static PyObject *PyArray_ReprFunction = NULL; - -/*NUMPY_API - * Set the array print function to be a Python function. - */ -NPY_NO_EXPORT void -PyArray_SetStringFunction(PyObject *op, int repr) -{ - if (repr) { - /* Dispose of previous callback */ - Py_XDECREF(PyArray_ReprFunction); - /* Add a reference to new callback */ - Py_XINCREF(op); - /* Remember new callback */ - PyArray_ReprFunction = op; - } - else { - /* Dispose of previous callback */ - Py_XDECREF(PyArray_StrFunction); - /* Add a reference to new callback */ - Py_XINCREF(op); - /* Remember new callback */ - PyArray_StrFunction = op; - } -} /*NUMPY_API * This function is scheduled to be removed @@ -660,39 +508,6 @@ PyArray_SetDatetimeParseFunction(PyObject *op) } -static PyObject * -array_repr(PyArrayObject *self) -{ - PyObject *s, *arglist; - - if (PyArray_ReprFunction == NULL) { - s = array_repr_builtin(self, 1); - } - else { - arglist = Py_BuildValue("(O)", self); - s = PyEval_CallObject(PyArray_ReprFunction, arglist); - Py_DECREF(arglist); - } - return s; -} - -static PyObject * -array_str(PyArrayObject *self) -{ - PyObject *s, *arglist; - - if (PyArray_StrFunction == NULL) { - s = array_repr_builtin(self, 0); - } - else { - arglist = Py_BuildValue("(O)", self); - s = PyEval_CallObject(PyArray_StrFunction, arglist); - Py_DECREF(arglist); - } - return s; -} - - /*NUMPY_API */ diff --git a/numpy/core/src/multiarray/strfuncs.c b/numpy/core/src/multiarray/strfuncs.c new file mode 100644 index 000000000000..5a0d203351a7 --- /dev/null +++ b/numpy/core/src/multiarray/strfuncs.c @@ -0,0 +1,200 @@ +#define NPY_NO_DEPRECATED_API NPY_API_VERSION +#define _MULTIARRAYMODULE + +#include +#include + +#include "npy_pycompat.h" + +#include "strfuncs.h" + +static PyObject *PyArray_StrFunction = NULL; +static PyObject *PyArray_ReprFunction = NULL; + +/*NUMPY_API + * Set the array print function to be a Python function. + */ +NPY_NO_EXPORT void +PyArray_SetStringFunction(PyObject *op, int repr) +{ + if (repr) { + /* Dispose of previous callback */ + Py_XDECREF(PyArray_ReprFunction); + /* Add a reference to new callback */ + Py_XINCREF(op); + /* Remember new callback */ + PyArray_ReprFunction = op; + } + else { + /* Dispose of previous callback */ + Py_XDECREF(PyArray_StrFunction); + /* Add a reference to new callback */ + Py_XINCREF(op); + /* Remember new callback */ + PyArray_StrFunction = op; + } +} + + +/* + * Extend string. On failure, returns NULL and leaves *strp alone. + * XXX we do this in multiple places; time for a string library? + */ +static char * +extend(char **strp, Py_ssize_t n, Py_ssize_t *maxp) +{ + char *str = *strp; + Py_ssize_t new_cap; + + if (n >= *maxp - 16) { + new_cap = *maxp * 2; + + if (new_cap <= *maxp) { /* overflow */ + return NULL; + } + str = PyArray_realloc(*strp, new_cap); + if (str != NULL) { + *strp = str; + *maxp = new_cap; + } + } + return str; +} + + +static int +dump_data(char **string, Py_ssize_t *n, Py_ssize_t *max_n, char *data, int nd, + npy_intp *dimensions, npy_intp *strides, PyArrayObject* self) +{ + PyArray_Descr *descr=PyArray_DESCR(self); + PyObject *op = NULL, *sp = NULL; + char *ostring; + npy_intp i, N, ret = 0; + +#define CHECK_MEMORY do { \ + if (extend(string, *n, max_n) == NULL) { \ + ret = -1; \ + goto end; \ + } \ + } while (0) + + if (nd == 0) { + if ((op = descr->f->getitem(data, self)) == NULL) { + return -1; + } + sp = PyObject_Repr(op); + if (sp == NULL) { + ret = -1; + goto end; + } + ostring = PyString_AsString(sp); + N = PyString_Size(sp)*sizeof(char); + *n += N; + CHECK_MEMORY; + memmove(*string + (*n - N), ostring, N); + } + else { + CHECK_MEMORY; + (*string)[*n] = '['; + *n += 1; + for (i = 0; i < dimensions[0]; i++) { + if (dump_data(string, n, max_n, + data + (*strides)*i, + nd - 1, dimensions + 1, + strides + 1, self) < 0) { + return -1; + } + CHECK_MEMORY; + if (i < dimensions[0] - 1) { + (*string)[*n] = ','; + (*string)[*n+1] = ' '; + *n += 2; + } + } + CHECK_MEMORY; + (*string)[*n] = ']'; + *n += 1; + } + +#undef CHECK_MEMORY + +end: + Py_XDECREF(op); + Py_XDECREF(sp); + return ret; +} + + +static PyObject * +array_repr_builtin(PyArrayObject *self, int repr) +{ + PyObject *ret; + char *string; + /* max_n initial value is arbitrary, dump_data will extend it */ + Py_ssize_t n = 0, max_n = PyArray_NBYTES(self) * 4 + 7; + + if ((string = PyArray_malloc(max_n)) == NULL) { + return PyErr_NoMemory(); + } + + if (dump_data(&string, &n, &max_n, PyArray_DATA(self), + PyArray_NDIM(self), PyArray_DIMS(self), + PyArray_STRIDES(self), self) < 0) { + PyArray_free(string); + return NULL; + } + + if (repr) { + if (PyArray_ISEXTENDED(self)) { + ret = PyUString_FromFormat("array(%s, '%c%d')", + string, + PyArray_DESCR(self)->type, + PyArray_DESCR(self)->elsize); + } + else { + ret = PyUString_FromFormat("array(%s, '%c')", + string, + PyArray_DESCR(self)->type); + } + } + else { + ret = PyUString_FromStringAndSize(string, n); + } + + PyArray_free(string); + return ret; +} + + +NPY_NO_EXPORT PyObject * +array_repr(PyArrayObject *self) +{ + PyObject *s, *arglist; + + if (PyArray_ReprFunction == NULL) { + s = array_repr_builtin(self, 1); + } + else { + arglist = Py_BuildValue("(O)", self); + s = PyEval_CallObject(PyArray_ReprFunction, arglist); + Py_DECREF(arglist); + } + return s; +} + + +NPY_NO_EXPORT PyObject * +array_str(PyArrayObject *self) +{ + PyObject *s, *arglist; + + if (PyArray_StrFunction == NULL) { + s = array_repr_builtin(self, 0); + } + else { + arglist = Py_BuildValue("(O)", self); + s = PyEval_CallObject(PyArray_StrFunction, arglist); + Py_DECREF(arglist); + } + return s; +} diff --git a/numpy/core/src/multiarray/strfuncs.h b/numpy/core/src/multiarray/strfuncs.h new file mode 100644 index 000000000000..8e80897c2ccb --- /dev/null +++ b/numpy/core/src/multiarray/strfuncs.h @@ -0,0 +1,13 @@ +#ifndef _NPY_ARRAY_STRFUNCS_H_ +#define _NPY_ARRAY_STRFUNCS_H_ + +NPY_NO_EXPORT void +PyArray_SetStringFunction(PyObject *op, int repr); + +NPY_NO_EXPORT PyObject * +array_repr(PyArrayObject *self); + +NPY_NO_EXPORT PyObject * +array_str(PyArrayObject *self); + +#endif