diff options
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/include/numpy/arrayscalars.h | 1 | ||||
-rw-r--r-- | numpy/core/src/multiarray/arraytypes.c.src | 1 | ||||
-rw-r--r-- | numpy/core/src/multiarray/buffer.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/common.c | 10 | ||||
-rw-r--r-- | numpy/core/src/multiarray/conversion_utils.c | 1 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/descriptor.c | 1 | ||||
-rw-r--r-- | numpy/core/src/multiarray/getset.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/npy_buffer.h | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/scalartypes.c.src | 174 | ||||
-rw-r--r-- | numpy/core/tests/test_scalarinherit.py | 16 |
11 files changed, 182 insertions, 30 deletions
diff --git a/numpy/core/include/numpy/arrayscalars.h b/numpy/core/include/numpy/arrayscalars.h index 42a0df76a..6dce88df3 100644 --- a/numpy/core/include/numpy/arrayscalars.h +++ b/numpy/core/include/numpy/arrayscalars.h @@ -140,6 +140,7 @@ typedef struct { /* note that the PyObject_HEAD macro lives right here */ PyUnicodeObject base; Py_UCS4 *obval; + char *buffer_fmt; } PyUnicodeScalarObject; diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src index 38d5f21eb..0cde3a78a 100644 --- a/numpy/core/src/multiarray/arraytypes.c.src +++ b/numpy/core/src/multiarray/arraytypes.c.src @@ -924,7 +924,6 @@ VOID_setitem(PyObject *op, void *input, void *vap) memset(ip + view.len, 0, itemsize - view.len); } PyBuffer_Release(&view); - _dealloc_cached_buffer_info(op); } return 0; } diff --git a/numpy/core/src/multiarray/buffer.c b/numpy/core/src/multiarray/buffer.c index 9a1f7b230..232176011 100644 --- a/numpy/core/src/multiarray/buffer.c +++ b/numpy/core/src/multiarray/buffer.c @@ -802,7 +802,7 @@ fail: * Retrieving buffers for scalars */ int -gentype_getbuffer(PyObject *self, Py_buffer *view, int flags) +void_getbuffer(PyObject *self, Py_buffer *view, int flags) { _buffer_info_t *info = NULL; PyArray_Descr *descr = NULL; diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c index 0150ae10e..55ae73779 100644 --- a/numpy/core/src/multiarray/common.c +++ b/numpy/core/src/multiarray/common.c @@ -299,7 +299,6 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, PyErr_Clear(); dtype = _descriptor_from_pep3118_format(buffer_view.format); PyBuffer_Release(&buffer_view); - _dealloc_cached_buffer_info(obj); if (dtype) { goto promote_types; } @@ -311,7 +310,6 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, dtype = PyArray_DescrNewFromType(NPY_VOID); dtype->elsize = buffer_view.itemsize; PyBuffer_Release(&buffer_view); - _dealloc_cached_buffer_info(obj); goto promote_types; } else { @@ -626,14 +624,6 @@ _IsWriteable(PyArrayObject *ap) return NPY_FALSE; } PyBuffer_Release(&view); - /* - * The first call to PyObject_GetBuffer stores a reference to a struct - * _buffer_info_t (from buffer.c, with format, ndim, strides and shape) in - * a static dictionary, with id(base) as the key. Usually we release it - * after the call to PyBuffer_Release, via a call to - * _dealloc_cached_buffer_info, but in this case leave it in the cache to - * speed up future calls to _IsWriteable. - */ return NPY_TRUE; } diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c index 14d546867..33f909e3f 100644 --- a/numpy/core/src/multiarray/conversion_utils.c +++ b/numpy/core/src/multiarray/conversion_utils.c @@ -195,7 +195,6 @@ PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf) * sticks around after the release. */ PyBuffer_Release(&view); - _dealloc_cached_buffer_info(obj); /* Point to the base of the buffer object if present */ if (PyMemoryView_Check(obj)) { diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 14e64b647..3c3bcb387 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -2576,7 +2576,6 @@ PyArray_FromInterface(PyObject *origin) * sticks around after the release. */ PyBuffer_Release(&view); - _dealloc_cached_buffer_info(base); /* Get offset number from interface specification */ attr = _PyDict_GetItemStringWithError(iface, "offset"); @@ -3801,7 +3800,6 @@ PyArray_FromBuffer(PyObject *buf, PyArray_Descr *type, * sticks around after the release. */ PyBuffer_Release(&view); - _dealloc_cached_buffer_info(buf); if ((offset < 0) || (offset > ts)) { PyErr_Format(PyExc_ValueError, diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c index b26a26abf..c2b90141a 100644 --- a/numpy/core/src/multiarray/descriptor.c +++ b/numpy/core/src/multiarray/descriptor.c @@ -1808,7 +1808,6 @@ arraydescr_dealloc(PyArray_Descr *self) Py_INCREF(self); return; } - _dealloc_cached_buffer_info((PyObject*)self); Py_XDECREF(self->typeobj); Py_XDECREF(self->names); Py_XDECREF(self->fields); diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c index 80a1cd4a1..5405a25db 100644 --- a/numpy/core/src/multiarray/getset.c +++ b/numpy/core/src/multiarray/getset.c @@ -147,7 +147,6 @@ array_strides_set(PyArrayObject *self, PyObject *obj) offset = PyArray_BYTES(self) - (char *)view.buf; numbytes = view.len + offset; PyBuffer_Release(&view); - _dealloc_cached_buffer_info((PyObject*)new); } else { PyErr_Clear(); @@ -376,7 +375,6 @@ array_data_set(PyArrayObject *self, PyObject *op) * sticks around after the release. */ PyBuffer_Release(&view); - _dealloc_cached_buffer_info(op); if (!PyArray_ISONESEGMENT(self)) { PyErr_SetString(PyExc_AttributeError, diff --git a/numpy/core/src/multiarray/npy_buffer.h b/numpy/core/src/multiarray/npy_buffer.h index 2eb97c4b9..5ff8b6c2c 100644 --- a/numpy/core/src/multiarray/npy_buffer.h +++ b/numpy/core/src/multiarray/npy_buffer.h @@ -10,6 +10,6 @@ NPY_NO_EXPORT PyArray_Descr* _descriptor_from_pep3118_format(char const *s); NPY_NO_EXPORT int -gentype_getbuffer(PyObject *obj, Py_buffer *view, int flags); +void_getbuffer(PyObject *obj, Py_buffer *view, int flags); #endif diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index f13f50759..ae33bbedf 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -85,7 +85,6 @@ gentype_alloc(PyTypeObject *type, Py_ssize_t nitems) static void gentype_dealloc(PyObject *v) { - _dealloc_cached_buffer_info(v); Py_TYPE(v)->tp_free(v); } @@ -1691,7 +1690,6 @@ gentype_reduce(PyObject *self, PyObject *NPY_UNUSED(args)) * sticks around after the release. */ PyBuffer_Release(&view); - _dealloc_cached_buffer_info(self); } else { Py_DECREF(ret); @@ -2365,9 +2363,167 @@ static PySequenceMethods voidtype_as_sequence = { }; -static PyBufferProcs gentype_as_buffer = { - .bf_getbuffer = gentype_getbuffer, - /* release buffer not defined (see buffer.c) */ + +/**begin repeat + * #name = bool, byte, short, int, long, longlong, ubyte, ushort, uint, ulong, + * ulonglong, half, float, double, longdouble, cfloat, cdouble, + * clongdouble# + * #Name = Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong, + * ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, + * CLongDouble# + * #NAME = BOOL, BYTE, SHORT, INT, LONG, LONGLONG, UBYTE, USHORT, UINT, ULONG, + * ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, + * CLONGDOUBLE# + * #fmt = ?, b, h, i, l, q, B, H, I, L, Q, e, f, d, g, Zf, Zd, Zg# + */ + +static int +@name@_getbuffer(PyObject *self, Py_buffer *view, int flags) +{ + if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { + return -1; + } + Py@Name@ScalarObject *scalar = (Py@Name@ScalarObject *)self; + + static char fmt[3] = "@fmt@"; + + view->ndim = 0; + view->len = sizeof(scalar->obval); + view->itemsize = sizeof(scalar->obval); + view->shape = NULL; + view->strides = NULL; + view->suboffsets = NULL; + Py_INCREF(self); + view->obj = self; + view->buf = &(scalar->obval); + + if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) { + /* It is unnecessary to find the correct format */ + view->format = NULL; + return 0; + } + + view->format = fmt; + + return 0; +} + +static PyBufferProcs @name@_arrtype_as_buffer = { + .bf_getbuffer = @name@_getbuffer, + /* No need to release the buffer */ +}; + +/**end repeat**/ + +static int +unicode_getbuffer(PyObject *self, Py_buffer *view, int flags) +{ + if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { + return -1; + } + PyUnicodeScalarObject *scalar = (PyUnicodeScalarObject *)self; + Py_ssize_t length = PyUnicode_GetLength(self); + + view->ndim = 0; + view->len = length * 4; + view->itemsize = length * 4; + view->shape = NULL; + view->strides = NULL; + view->suboffsets = NULL; + Py_INCREF(self); + view->obj = self; + + if (scalar->obval == NULL) { + /* + * Unicode may not have the representation available, `scalar_value` + * ensures materialization. + */ + PyArray_Descr *descr = PyArray_DescrFromType(NPY_UNICODE); + scalar_value(self, descr); + Py_DECREF(descr); + if (scalar->obval == NULL) { + /* allocating memory failed */ + Py_SETREF(view->obj, NULL); + return -1; + } + } + view->buf = scalar->obval; + + if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) { + /* It is unnecessary to find the correct format */ + view->format = NULL; + return 0; + } + + if (scalar->buffer_fmt != NULL) { + view->format = scalar->buffer_fmt; + } + else { + scalar->buffer_fmt = PyObject_Malloc(22); + if (scalar->buffer_fmt == NULL) { + Py_SETREF(view->obj, NULL); + return -1; + } + PyOS_snprintf(scalar->buffer_fmt, 22, "%" NPY_INTP_FMT "w", length); + view->format = scalar->buffer_fmt; + } + + return 0; +} + +static PyBufferProcs unicode_arrtype_as_buffer = { + .bf_getbuffer = unicode_getbuffer, + /* No need to release the buffer */ +}; + + +/**begin repeat + * #name = datetime, timedelta# + * #Name = Datetime, Timedelta# + */ + +static int +@name@_getbuffer(PyObject *self, Py_buffer *view, int flags) +{ + if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { + return -1; + } + Py@Name@ScalarObject *scalar = (Py@Name@ScalarObject *)self; + + view->ndim = 1; + view->len = 8; + view->itemsize = 1; + static Py_ssize_t length = 8; + view->shape = &length; + view->strides = NULL; + view->suboffsets = NULL; + Py_INCREF(self); + view->obj = self; + + view->buf = &(scalar->obval); + + if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) { + /* It is unnecessary to find the correct format */ + view->format = NULL; + return 0; + } + + /* export datetime scalars as bytes (although arrays are not exported) */ + view->format = "B"; + + return 0; +} + +static PyBufferProcs @name@_arrtype_as_buffer = { + .bf_getbuffer = @name@_getbuffer, + /* No need to release the buffer */ +}; + +/**end repeat**/ + +static PyBufferProcs void_arrtype_as_buffer = { + .bf_getbuffer = void_getbuffer, /* defined in buffer.c */ + /* No need to release the buffer */ }; @@ -3584,7 +3740,6 @@ initialize_numeric_types(void) init_basetypes(); PyGenericArrType_Type.tp_dealloc = (destructor)gentype_dealloc; PyGenericArrType_Type.tp_as_number = &gentype_as_number; - PyGenericArrType_Type.tp_as_buffer = &gentype_as_buffer; PyGenericArrType_Type.tp_as_mapping = &gentype_as_mapping; PyGenericArrType_Type.tp_flags = BASEFLAGS; PyGenericArrType_Type.tp_methods = gentype_methods; @@ -3668,10 +3823,15 @@ initialize_numeric_types(void) Py@NAME@ArrType_Type.tp_new = @name@_arrtype_new; Py@NAME@ArrType_Type.tp_richcompare = gentype_richcompare; +#define _IS_@NAME@ /* inherit string buffer */ +#if !defined(_IS_String) + Py@NAME@ArrType_Type.tp_as_buffer = &@name@_arrtype_as_buffer; +#endif +#undef _IS_@NAME@ + /**end repeat**/ PyUnicodeArrType_Type.tp_dealloc = unicode_arrtype_dealloc; - PyUnicodeArrType_Type.tp_as_buffer = &gentype_as_buffer; /**begin repeat * #name = bool, byte, short, ubyte, ushort, uint, ulong, ulonglong, diff --git a/numpy/core/tests/test_scalarinherit.py b/numpy/core/tests/test_scalarinherit.py index 74829986c..cc53eb244 100644 --- a/numpy/core/tests/test_scalarinherit.py +++ b/numpy/core/tests/test_scalarinherit.py @@ -5,7 +5,7 @@ import pytest import numpy as np -from numpy.testing import assert_ +from numpy.testing import assert_, assert_raises class A: @@ -74,13 +74,21 @@ class TestCharacter: assert_(s + np_s == b'defabc') assert_(u + np_u == u'defabc') + class MyStr(str, np.generic): + # would segfault + pass + + with assert_raises(TypeError): + # Previously worked, but gave completely wrong result + ret = s + MyStr('abc') - class Mystr(str, np.generic): + class MyBytes(bytes, np.generic): # would segfault pass - ret = s + Mystr('abc') - assert_(type(ret) is type(s)) + ret = s + MyBytes(b'abc') + assert(type(ret) is type(s)) + assert ret == b"defabc" def test_char_repeat(self): np_s = np.string_('abc') |