summaryrefslogtreecommitdiff
path: root/Cython/Utility/MemoryView.pyx
diff options
context:
space:
mode:
Diffstat (limited to 'Cython/Utility/MemoryView.pyx')
-rw-r--r--Cython/Utility/MemoryView.pyx452
1 files changed, 228 insertions, 224 deletions
diff --git a/Cython/Utility/MemoryView.pyx b/Cython/Utility/MemoryView.pyx
index 277c0bd87..40572d60e 100644
--- a/Cython/Utility/MemoryView.pyx
+++ b/Cython/Utility/MemoryView.pyx
@@ -1,5 +1,8 @@
#################### View.MemoryView ####################
+# cython: language_level=3str
+# cython: binding=False
+
# This utility provides cython.array and cython.view.memoryview
from __future__ import absolute_import
@@ -8,22 +11,22 @@ cimport cython
# from cpython cimport ...
cdef extern from "Python.h":
+ ctypedef struct PyObject
int PyIndex_Check(object)
- object PyLong_FromVoidPtr(void *)
+ PyObject *PyExc_IndexError
+ PyObject *PyExc_ValueError
cdef extern from "pythread.h":
ctypedef void *PyThread_type_lock
PyThread_type_lock PyThread_allocate_lock()
void PyThread_free_lock(PyThread_type_lock)
- int PyThread_acquire_lock(PyThread_type_lock, int mode) nogil
- void PyThread_release_lock(PyThread_type_lock) nogil
cdef extern from "<string.h>":
void *memset(void *b, int c, size_t len)
cdef extern from *:
- bint __PYX_CYTHON_ATOMICS_ENABLED() noexcept
+ bint __PYX_CYTHON_ATOMICS_ENABLED()
int __Pyx_GetBuffer(object, Py_buffer *, int) except -1
void __Pyx_ReleaseBuffer(Py_buffer *)
@@ -50,7 +53,7 @@ cdef extern from *:
Py_ssize_t suboffsets[{{max_dims}}]
void __PYX_INC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil)
- void __PYX_XDEC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil)
+ void __PYX_XCLEAR_MEMVIEW({{memviewslice_name}} *memslice, int have_gil)
ctypedef struct __pyx_buffer "Py_buffer":
PyObject *obj
@@ -72,17 +75,13 @@ cdef extern from *:
ctypedef struct __Pyx_TypeInfo:
pass
- cdef object capsule "__pyx_capsule_create" (void *p, char *sig)
- cdef int __pyx_array_getbuffer(PyObject *obj, Py_buffer view, int flags)
- cdef int __pyx_memoryview_getbuffer(PyObject *obj, Py_buffer view, int flags)
-
cdef extern from *:
ctypedef int __pyx_atomic_int
{{memviewslice_name}} slice_copy_contig "__pyx_memoryview_copy_new_contig"(
__Pyx_memviewslice *from_mvs,
char *mode, int ndim,
size_t sizeof_dtype, int contig_flag,
- bint dtype_is_object) nogil except *
+ bint dtype_is_object) except * nogil
bint slice_is_contig "__pyx_memviewslice_is_contig" (
{{memviewslice_name}} mvs, char order, int ndim) nogil
bint slices_overlap "__pyx_slices_overlap" ({{memviewslice_name}} *slice1,
@@ -95,13 +94,22 @@ cdef extern from "<stdlib.h>":
void free(void *) nogil
void *memcpy(void *dest, void *src, size_t n) nogil
-
-
+# the sequence abstract base class
+cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence"
+try:
+ if __import__("sys").version_info >= (3, 3):
+ __pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence
+ else:
+ __pyx_collections_abc_Sequence = __import__("collections").Sequence
+except:
+ # it isn't a big problem if this fails
+ __pyx_collections_abc_Sequence = None
#
### cython.array class
#
+@cython.collection_type("sequence")
@cname("__pyx_array")
cdef class array:
@@ -115,7 +123,7 @@ cdef class array:
Py_ssize_t itemsize
unicode mode # FIXME: this should have been a simple 'char'
bytes _format
- void (*callback_free_data)(void *data)
+ void (*callback_free_data)(void *data) noexcept
# cdef object _memview
cdef bint free_data
cdef bint dtype_is_object
@@ -124,17 +132,16 @@ cdef class array:
mode="c", bint allocate_buffer=True):
cdef int idx
- cdef Py_ssize_t i, dim
- cdef PyObject **p
+ cdef Py_ssize_t dim
self.ndim = <int> len(shape)
self.itemsize = itemsize
if not self.ndim:
- raise ValueError("Empty shape tuple for cython.array")
+ raise ValueError, "Empty shape tuple for cython.array"
if itemsize <= 0:
- raise ValueError("itemsize <= 0 for cython.array")
+ raise ValueError, "itemsize <= 0 for cython.array"
if not isinstance(format, bytes):
format = format.encode('ASCII')
@@ -146,76 +153,66 @@ cdef class array:
self._strides = self._shape + self.ndim
if not self._shape:
- raise MemoryError("unable to allocate shape and strides.")
+ raise MemoryError, "unable to allocate shape and strides."
# cdef Py_ssize_t dim, stride
for idx, dim in enumerate(shape):
if dim <= 0:
- raise ValueError("Invalid shape in axis %d: %d." % (idx, dim))
+ raise ValueError, f"Invalid shape in axis {idx}: {dim}."
self._shape[idx] = dim
cdef char order
- if mode == 'fortran':
- order = b'F'
- self.mode = u'fortran'
- elif mode == 'c':
+ if mode == 'c':
order = b'C'
self.mode = u'c'
+ elif mode == 'fortran':
+ order = b'F'
+ self.mode = u'fortran'
else:
- raise ValueError("Invalid mode, expected 'c' or 'fortran', got %s" % mode)
+ raise ValueError, f"Invalid mode, expected 'c' or 'fortran', got {mode}"
- self.len = fill_contig_strides_array(self._shape, self._strides,
- itemsize, self.ndim, order)
+ self.len = fill_contig_strides_array(self._shape, self._strides, itemsize, self.ndim, order)
self.free_data = allocate_buffer
self.dtype_is_object = format == b'O'
- if allocate_buffer:
- # use malloc() for backwards compatibility
- # in case external code wants to change the data pointer
- self.data = <char *>malloc(self.len)
- if not self.data:
- raise MemoryError("unable to allocate array data.")
- if self.dtype_is_object:
- p = <PyObject **> self.data
- for i in range(self.len / itemsize):
- p[i] = Py_None
- Py_INCREF(Py_None)
+ if allocate_buffer:
+ _allocate_buffer(self)
@cname('getbuffer')
def __getbuffer__(self, Py_buffer *info, int flags):
cdef int bufmode = -1
- if self.mode == u"c":
- bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS
- elif self.mode == u"fortran":
- bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS
- if not (flags & bufmode):
- raise ValueError("Can only create a buffer that is contiguous in memory.")
+ if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS):
+ if self.mode == u"c":
+ bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS
+ elif self.mode == u"fortran":
+ bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS
+ if not (flags & bufmode):
+ raise ValueError, "Can only create a buffer that is contiguous in memory."
info.buf = self.data
info.len = self.len
- info.ndim = self.ndim
- info.shape = self._shape
- info.strides = self._strides
- info.suboffsets = NULL
- info.itemsize = self.itemsize
- info.readonly = 0
- if flags & PyBUF_FORMAT:
- info.format = self.format
+ if flags & PyBUF_STRIDES:
+ info.ndim = self.ndim
+ info.shape = self._shape
+ info.strides = self._strides
else:
- info.format = NULL
+ info.ndim = 1
+ info.shape = &self.len if flags & PyBUF_ND else NULL
+ info.strides = NULL
+ info.suboffsets = NULL
+ info.itemsize = self.itemsize
+ info.readonly = 0
+ info.format = self.format if flags & PyBUF_FORMAT else NULL
info.obj = self
- __pyx_getbuffer = capsule(<void *> &__pyx_array_getbuffer, "getbuffer(obj, view, flags)")
-
def __dealloc__(array self):
if self.callback_free_data != NULL:
self.callback_free_data(self.data)
- elif self.free_data:
+ elif self.free_data and self.data is not NULL:
if self.dtype_is_object:
- refcount_objects_in_slice(self.data, self._shape,
- self._strides, self.ndim, False)
+ refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False)
free(self.data)
PyObject_Free(self._shape)
@@ -240,17 +237,42 @@ cdef class array:
def __setitem__(self, item, value):
self.memview[item] = value
+ # Sequence methods
+ try:
+ count = __pyx_collections_abc_Sequence.count
+ index = __pyx_collections_abc_Sequence.index
+ except:
+ pass
+
+@cname("__pyx_array_allocate_buffer")
+cdef int _allocate_buffer(array self) except -1:
+ # use malloc() for backwards compatibility
+ # in case external code wants to change the data pointer
+ cdef Py_ssize_t i
+ cdef PyObject **p
+
+ self.free_data = True
+ self.data = <char *>malloc(self.len)
+ if not self.data:
+ raise MemoryError, "unable to allocate array data."
+
+ if self.dtype_is_object:
+ p = <PyObject **> self.data
+ for i in range(self.len // self.itemsize):
+ p[i] = Py_None
+ Py_INCREF(Py_None)
+ return 0
+
@cname("__pyx_array_new")
-cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format,
- char *mode, char *buf):
+cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *c_mode, char *buf):
cdef array result
+ cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string.
- if buf == NULL:
- result = array(shape, itemsize, format, mode.decode('ASCII'))
+ if buf is NULL:
+ result = array.__new__(array, shape, itemsize, format, mode)
else:
- result = array(shape, itemsize, format, mode.decode('ASCII'),
- allocate_buffer=False)
+ result = array.__new__(array, shape, itemsize, format, mode, allocate_buffer=False)
result.data = buf
return result
@@ -296,7 +318,7 @@ cdef indirect_contiguous = Enum("<contiguous and indirect>")
@cname('__pyx_align_pointer')
-cdef void *align_pointer(void *memory, size_t alignment) nogil:
+cdef void *align_pointer(void *memory, size_t alignment) noexcept nogil:
"Align pointer memory on a given boundary"
cdef Py_intptr_t aligned_p = <Py_intptr_t> memory
cdef size_t offset
@@ -313,22 +335,16 @@ cdef void *align_pointer(void *memory, size_t alignment) nogil:
# pre-allocate thread locks for reuse
## note that this could be implemented in a more beautiful way in "normal" Cython,
## but this code gets merged into the user module and not everything works there.
-DEF THREAD_LOCKS_PREALLOCATED = 8
cdef int __pyx_memoryview_thread_locks_used = 0
-cdef PyThread_type_lock[THREAD_LOCKS_PREALLOCATED] __pyx_memoryview_thread_locks = [
- PyThread_allocate_lock(),
- PyThread_allocate_lock(),
- PyThread_allocate_lock(),
- PyThread_allocate_lock(),
- PyThread_allocate_lock(),
- PyThread_allocate_lock(),
- PyThread_allocate_lock(),
+cdef PyThread_type_lock[{{THREAD_LOCKS_PREALLOCATED}}] __pyx_memoryview_thread_locks = [
+{{for _ in range(THREAD_LOCKS_PREALLOCATED)}}
PyThread_allocate_lock(),
+{{endfor}}
]
@cname('__pyx_memoryview')
-cdef class memoryview(object):
+cdef class memoryview:
cdef object obj
cdef object _size
@@ -354,7 +370,7 @@ cdef class memoryview(object):
if not __PYX_CYTHON_ATOMICS_ENABLED():
global __pyx_memoryview_thread_locks_used
- if __pyx_memoryview_thread_locks_used < THREAD_LOCKS_PREALLOCATED:
+ if __pyx_memoryview_thread_locks_used < {{THREAD_LOCKS_PREALLOCATED}}:
self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used]
__pyx_memoryview_thread_locks_used += 1
if self.lock is NULL:
@@ -417,7 +433,7 @@ cdef class memoryview(object):
def __setitem__(memoryview self, object index, object value):
if self.view.readonly:
- raise TypeError("Cannot assign to read-only memoryview")
+ raise TypeError, "Cannot assign to read-only memoryview"
have_slices, index = _unellipsify(index, self.view.ndim)
@@ -443,10 +459,10 @@ cdef class memoryview(object):
cdef setitem_slice_assignment(self, dst, src):
cdef {{memviewslice_name}} dst_slice
cdef {{memviewslice_name}} src_slice
+ cdef {{memviewslice_name}} msrc = get_slice_from_memview(src, &src_slice)[0]
+ cdef {{memviewslice_name}} mdst = get_slice_from_memview(dst, &dst_slice)[0]
- memoryview_copy_contents(get_slice_from_memview(src, &src_slice)[0],
- get_slice_from_memview(dst, &dst_slice)[0],
- src.ndim, dst.ndim, self.dtype_is_object)
+ memoryview_copy_contents(msrc, mdst, src.ndim, dst.ndim, self.dtype_is_object)
cdef setitem_slice_assign_scalar(self, memoryview dst, value):
cdef int array[128]
@@ -494,7 +510,7 @@ cdef class memoryview(object):
try:
result = struct.unpack(self.view.format, bytesitem)
except struct.error:
- raise ValueError("Unable to convert item to object")
+ raise ValueError, "Unable to convert item to object"
else:
if len(self.view.format) == 1:
return result[0]
@@ -519,7 +535,7 @@ cdef class memoryview(object):
@cname('getbuffer')
def __getbuffer__(self, Py_buffer *info, int flags):
if flags & PyBUF_WRITABLE and self.view.readonly:
- raise ValueError("Cannot create writable memory view from read-only memoryview")
+ raise ValueError, "Cannot create writable memory view from read-only memoryview"
if flags & PyBUF_ND:
info.shape = self.view.shape
@@ -548,8 +564,6 @@ cdef class memoryview(object):
info.readonly = self.view.readonly
info.obj = self
- __pyx_getbuffer = capsule(<void *> &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)")
-
# Some properties that have the same semantics as in NumPy
@property
def T(self):
@@ -559,6 +573,9 @@ cdef class memoryview(object):
@property
def base(self):
+ return self._get_base()
+
+ cdef _get_base(self):
return self.obj
@property
@@ -569,7 +586,7 @@ cdef class memoryview(object):
def strides(self):
if self.view.strides == NULL:
# Note: we always ask for strides, so if this is not set it's a bug
- raise ValueError("Buffer view does not expose strides")
+ raise ValueError, "Buffer view does not expose strides"
return tuple([stride for stride in self.view.strides[:self.view.ndim]])
@@ -662,7 +679,7 @@ cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeIn
return result
@cname('__pyx_memoryview_check')
-cdef inline bint memoryview_check(object o):
+cdef inline bint memoryview_check(object o) noexcept:
return isinstance(o, memoryview)
cdef tuple _unellipsify(object index, int ndim):
@@ -670,39 +687,35 @@ cdef tuple _unellipsify(object index, int ndim):
Replace all ellipses with full slices and fill incomplete indices with
full slices.
"""
- if not isinstance(index, tuple):
- tup = (index,)
- else:
- tup = index
+ cdef Py_ssize_t idx
+ tup = <tuple>index if isinstance(index, tuple) else (index,)
- result = []
+ result = [slice(None)] * ndim
have_slices = False
seen_ellipsis = False
- for idx, item in enumerate(tup):
+ idx = 0
+ for item in tup:
if item is Ellipsis:
if not seen_ellipsis:
- result.extend([slice(None)] * (ndim - len(tup) + 1))
+ idx += ndim - len(tup)
seen_ellipsis = True
- else:
- result.append(slice(None))
have_slices = True
else:
- if not isinstance(item, slice) and not PyIndex_Check(item):
- raise TypeError("Cannot index with type '%s'" % type(item))
-
- have_slices = have_slices or isinstance(item, slice)
- result.append(item)
-
- nslices = ndim - len(result)
- if nslices:
- result.extend([slice(None)] * nslices)
-
+ if isinstance(item, slice):
+ have_slices = True
+ elif not PyIndex_Check(item):
+ raise TypeError, f"Cannot index with type '{type(item)}'"
+ result[idx] = item
+ idx += 1
+
+ nslices = ndim - idx
return have_slices or nslices, tuple(result)
-cdef assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim):
+cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1:
for suboffset in suboffsets[:ndim]:
if suboffset >= 0:
- raise ValueError("Indirect dimensions not supported")
+ raise ValueError, "Indirect dimensions not supported"
+ return 0 # return type just used as an error flag
#
### Slicing a memoryview
@@ -742,15 +755,16 @@ cdef memoryview memview_slice(memoryview memview, object indices):
# may not be as expected"
cdef {{memviewslice_name}} *p_dst = &dst
cdef int *p_suboffset_dim = &suboffset_dim
- cdef Py_ssize_t start, stop, step
+ cdef Py_ssize_t start, stop, step, cindex
cdef bint have_start, have_stop, have_step
for dim, index in enumerate(indices):
if PyIndex_Check(index):
+ cindex = index
slice_memviewslice(
p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim],
dim, new_ndim, p_suboffset_dim,
- index, 0, 0, # start, stop, step
+ cindex, 0, 0, # start, stop, step
0, 0, 0, # have_{start,stop,step}
False)
elif index is None:
@@ -789,22 +803,6 @@ cdef memoryview memview_slice(memoryview memview, object indices):
### Slicing in a single dimension of a memoryviewslice
#
-cdef extern from "<stdlib.h>":
- void abort() nogil
- void printf(char *s, ...) nogil
-
-cdef extern from "<stdio.h>":
- ctypedef struct FILE
- FILE *stderr
- int fputs(char *s, FILE *stream)
-
-cdef extern from "pystate.h":
- void PyThreadState_Get() nogil
-
- # These are not actually nogil, but we check for the GIL before calling them
- void PyErr_SetString(PyObject *type, char *msg) nogil
- PyObject *PyErr_Format(PyObject *exc, char *msg, ...) nogil
-
@cname('__pyx_memoryview_slice_memviewslice')
cdef int slice_memviewslice(
{{memviewslice_name}} *dst,
@@ -812,7 +810,7 @@ cdef int slice_memviewslice(
int dim, int new_ndim, int *suboffset_dim,
Py_ssize_t start, Py_ssize_t stop, Py_ssize_t step,
int have_start, int have_stop, int have_step,
- bint is_slice) nogil except -1:
+ bint is_slice) except -1 nogil:
"""
Create a new slice dst given slice src.
@@ -831,13 +829,16 @@ cdef int slice_memviewslice(
if start < 0:
start += shape
if not 0 <= start < shape:
- _err_dim(IndexError, "Index out of bounds (axis %d)", dim)
+ _err_dim(PyExc_IndexError, "Index out of bounds (axis %d)", dim)
else:
# index is a slice
- negative_step = have_step != 0 and step < 0
-
- if have_step and step == 0:
- _err_dim(ValueError, "Step may not be zero (axis %d)", dim)
+ if have_step:
+ negative_step = step < 0
+ if step == 0:
+ _err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim)
+ else:
+ negative_step = False
+ step = 1
# check our bounds and set defaults
if have_start:
@@ -869,9 +870,6 @@ cdef int slice_memviewslice(
else:
stop = shape
- if not have_step:
- step = 1
-
# len = ceil( (stop - start) / step )
with cython.cdivision(True):
new_shape = (stop - start) // step
@@ -887,7 +885,7 @@ cdef int slice_memviewslice(
dst.shape[new_ndim] = new_shape
dst.suboffsets[new_ndim] = suboffset
- # Add the slicing or idexing offsets to the right suboffset or base data *
+ # Add the slicing or indexing offsets to the right suboffset or base data *
if suboffset_dim[0] < 0:
dst.data += start * stride
else:
@@ -898,7 +896,7 @@ cdef int slice_memviewslice(
if new_ndim == 0:
dst.data = (<char **> dst.data)[0] + suboffset
else:
- _err_dim(IndexError, "All dimensions preceding dimension %d "
+ _err_dim(PyExc_IndexError, "All dimensions preceding dimension %d "
"must be indexed and not sliced", dim)
else:
suboffset_dim[0] = new_ndim
@@ -916,7 +914,7 @@ cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index,
cdef char *resultp
if view.ndim == 0:
- shape = view.len / itemsize
+ shape = view.len // itemsize
stride = itemsize
else:
shape = view.shape[dim]
@@ -927,10 +925,10 @@ cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index,
if index < 0:
index += view.shape[dim]
if index < 0:
- raise IndexError("Out of bounds on buffer access (axis %d)" % dim)
+ raise IndexError, f"Out of bounds on buffer access (axis {dim})"
if index >= shape:
- raise IndexError("Out of bounds on buffer access (axis %d)" % dim)
+ raise IndexError, f"Out of bounds on buffer access (axis {dim})"
resultp = bufp + index * stride
if suboffset >= 0:
@@ -942,7 +940,7 @@ cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index,
### Transposing a memoryviewslice
#
@cname('__pyx_memslice_transpose')
-cdef int transpose_memslice({{memviewslice_name}} *memslice) nogil except 0:
+cdef int transpose_memslice({{memviewslice_name}} *memslice) except -1 nogil:
cdef int ndim = memslice.memview.view.ndim
cdef Py_ssize_t *shape = memslice.shape
@@ -950,19 +948,20 @@ cdef int transpose_memslice({{memviewslice_name}} *memslice) nogil except 0:
# reverse strides and shape
cdef int i, j
- for i in range(ndim / 2):
+ for i in range(ndim // 2):
j = ndim - 1 - i
strides[i], strides[j] = strides[j], strides[i]
shape[i], shape[j] = shape[j], shape[i]
if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0:
- _err(ValueError, "Cannot transpose memoryview with indirect dimensions")
+ _err(PyExc_ValueError, "Cannot transpose memoryview with indirect dimensions")
- return 1
+ return 0
#
### Creating new memoryview objects from slices and memoryviews
#
+@cython.collection_type("sequence")
@cname('__pyx_memoryviewslice')
cdef class _memoryviewslice(memoryview):
"Internal class for passing memoryview slices to Python"
@@ -976,7 +975,7 @@ cdef class _memoryviewslice(memoryview):
cdef int (*to_dtype_func)(char *, object) except 0
def __dealloc__(self):
- __PYX_XDEC_MEMVIEW(&self.from_slice, 1)
+ __PYX_XCLEAR_MEMVIEW(&self.from_slice, 1)
cdef convert_item_to_object(self, char *itemp):
if self.to_object_func != NULL:
@@ -990,12 +989,25 @@ cdef class _memoryviewslice(memoryview):
else:
memoryview.assign_item_from_object(self, itemp, value)
- @property
- def base(self):
+ cdef _get_base(self):
return self.from_object
- __pyx_getbuffer = capsule(<void *> &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)")
+ # Sequence methods
+ try:
+ count = __pyx_collections_abc_Sequence.count
+ index = __pyx_collections_abc_Sequence.index
+ except:
+ pass
+try:
+ if __pyx_collections_abc_Sequence:
+ # The main value of registering _memoryviewslice as a
+ # Sequence is that it can be used in structural pattern
+ # matching in Python 3.10+
+ __pyx_collections_abc_Sequence.register(_memoryviewslice)
+ __pyx_collections_abc_Sequence.register(array)
+except:
+ pass # ignore failure, it's a minor issue
@cname('__pyx_memoryview_fromslice')
cdef memoryview_fromslice({{memviewslice_name}} memviewslice,
@@ -1012,12 +1024,12 @@ cdef memoryview_fromslice({{memviewslice_name}} memviewslice,
# assert 0 < ndim <= memviewslice.memview.view.ndim, (
# ndim, memviewslice.memview.view.ndim)
- result = _memoryviewslice(None, 0, dtype_is_object)
+ result = _memoryviewslice.__new__(_memoryviewslice, None, 0, dtype_is_object)
result.from_slice = memviewslice
__PYX_INC_MEMVIEW(&memviewslice, 1)
- result.from_object = (<memoryview> memviewslice.memview).base
+ result.from_object = (<memoryview> memviewslice.memview)._get_base()
result.typeinfo = memviewslice.memview.typeinfo
result.view = memviewslice.memview.view
@@ -1062,7 +1074,7 @@ cdef {{memviewslice_name}} *get_slice_from_memview(memoryview memview,
return mslice
@cname('__pyx_memoryview_slice_copy')
-cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst):
+cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst) noexcept:
cdef int dim
cdef (Py_ssize_t*) shape, strides, suboffsets
@@ -1108,14 +1120,11 @@ cdef memoryview_copy_from_slice(memoryview memview, {{memviewslice_name}} *memvi
#
### Copy the contents of a memoryview slices
#
-cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) nogil:
- if arg < 0:
- return -arg
- else:
- return arg
+cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) noexcept nogil:
+ return -arg if arg < 0 else arg
@cname('__pyx_get_best_slice_order')
-cdef char get_best_order({{memviewslice_name}} *mslice, int ndim) nogil:
+cdef char get_best_order({{memviewslice_name}} *mslice, int ndim) noexcept nogil:
"""
Figure out the best memory access order for a given slice.
"""
@@ -1142,7 +1151,7 @@ cdef char get_best_order({{memviewslice_name}} *mslice, int ndim) nogil:
cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides,
char *dst_data, Py_ssize_t *dst_strides,
Py_ssize_t *src_shape, Py_ssize_t *dst_shape,
- int ndim, size_t itemsize) nogil:
+ int ndim, size_t itemsize) noexcept nogil:
# Note: src_extent is 1 if we're broadcasting
# dst_extent always >= src_extent as we don't do reductions
cdef Py_ssize_t i
@@ -1152,14 +1161,14 @@ cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides,
cdef Py_ssize_t dst_stride = dst_strides[0]
if ndim == 1:
- if (src_stride > 0 and dst_stride > 0 and
- <size_t> src_stride == itemsize == <size_t> dst_stride):
- memcpy(dst_data, src_data, itemsize * dst_extent)
- else:
- for i in range(dst_extent):
- memcpy(dst_data, src_data, itemsize)
- src_data += src_stride
- dst_data += dst_stride
+ if (src_stride > 0 and dst_stride > 0 and
+ <size_t> src_stride == itemsize == <size_t> dst_stride):
+ memcpy(dst_data, src_data, itemsize * dst_extent)
+ else:
+ for i in range(dst_extent):
+ memcpy(dst_data, src_data, itemsize)
+ src_data += src_stride
+ dst_data += dst_stride
else:
for i in range(dst_extent):
_copy_strided_to_strided(src_data, src_strides + 1,
@@ -1171,12 +1180,12 @@ cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides,
cdef void copy_strided_to_strided({{memviewslice_name}} *src,
{{memviewslice_name}} *dst,
- int ndim, size_t itemsize) nogil:
+ int ndim, size_t itemsize) noexcept nogil:
_copy_strided_to_strided(src.data, src.strides, dst.data, dst.strides,
src.shape, dst.shape, ndim, itemsize)
@cname('__pyx_memoryview_slice_get_size')
-cdef Py_ssize_t slice_get_size({{memviewslice_name}} *src, int ndim) nogil:
+cdef Py_ssize_t slice_get_size({{memviewslice_name}} *src, int ndim) noexcept nogil:
"Return the size of the memory occupied by the slice in number of bytes"
cdef Py_ssize_t shape, size = src.memview.view.itemsize
@@ -1188,7 +1197,7 @@ cdef Py_ssize_t slice_get_size({{memviewslice_name}} *src, int ndim) nogil:
@cname('__pyx_fill_contig_strides_array')
cdef Py_ssize_t fill_contig_strides_array(
Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t stride,
- int ndim, char order) nogil:
+ int ndim, char order) noexcept nogil:
"""
Fill the strides array for a slice with C or F contiguous strides.
This is like PyBuffer_FillContiguousStrides, but compatible with py < 2.6
@@ -1210,7 +1219,7 @@ cdef Py_ssize_t fill_contig_strides_array(
cdef void *copy_data_to_temp({{memviewslice_name}} *src,
{{memviewslice_name}} *tmpslice,
char order,
- int ndim) nogil except NULL:
+ int ndim) except NULL nogil:
"""
Copy a direct slice to temporary contiguous memory. The caller should free
the result when done.
@@ -1223,7 +1232,7 @@ cdef void *copy_data_to_temp({{memviewslice_name}} *src,
result = malloc(size)
if not result:
- _err(MemoryError, NULL)
+ _err_no_memory()
# tmpslice[0] = src
tmpslice.data = <char *> result
@@ -1232,8 +1241,7 @@ cdef void *copy_data_to_temp({{memviewslice_name}} *src,
tmpslice.shape[i] = src.shape[i]
tmpslice.suboffsets[i] = -1
- fill_contig_strides_array(&tmpslice.shape[0], &tmpslice.strides[0], itemsize,
- ndim, order)
+ fill_contig_strides_array(&tmpslice.shape[0], &tmpslice.strides[0], itemsize, ndim, order)
# We need to broadcast strides again
for i in range(ndim):
@@ -1252,25 +1260,26 @@ cdef void *copy_data_to_temp({{memviewslice_name}} *src,
@cname('__pyx_memoryview_err_extents')
cdef int _err_extents(int i, Py_ssize_t extent1,
Py_ssize_t extent2) except -1 with gil:
- raise ValueError("got differing extents in dimension %d (got %d and %d)" %
- (i, extent1, extent2))
+ raise ValueError, f"got differing extents in dimension {i} (got {extent1} and {extent2})"
@cname('__pyx_memoryview_err_dim')
-cdef int _err_dim(object error, char *msg, int dim) except -1 with gil:
- raise error(msg.decode('ascii') % dim)
+cdef int _err_dim(PyObject *error, str msg, int dim) except -1 with gil:
+ raise <object>error, msg % dim
@cname('__pyx_memoryview_err')
-cdef int _err(object error, char *msg) except -1 with gil:
- if msg != NULL:
- raise error(msg.decode('ascii'))
- else:
- raise error
+cdef int _err(PyObject *error, str msg) except -1 with gil:
+ raise <object>error, msg
+
+@cname('__pyx_memoryview_err_no_memory')
+cdef int _err_no_memory() except -1 with gil:
+ raise MemoryError
+
@cname('__pyx_memoryview_copy_contents')
cdef int memoryview_copy_contents({{memviewslice_name}} src,
{{memviewslice_name}} dst,
int src_ndim, int dst_ndim,
- bint dtype_is_object) nogil except -1:
+ bint dtype_is_object) except -1 nogil:
"""
Copy memory from slice src to slice dst.
Check for overlapping memory and verify the shapes.
@@ -1299,7 +1308,7 @@ cdef int memoryview_copy_contents({{memviewslice_name}} src,
_err_extents(i, dst.shape[i], src.shape[i])
if src.suboffsets[i] >= 0:
- _err_dim(ValueError, "Dimension %d is not direct", i)
+ _err_dim(PyExc_ValueError, "Dimension %d is not direct", i)
if slices_overlap(&src, &dst, ndim, itemsize):
# slices overlap, copy to temp, copy temp to dst
@@ -1319,9 +1328,9 @@ cdef int memoryview_copy_contents({{memviewslice_name}} src,
if direct_copy:
# Contiguous slices with same order
- refcount_copying(&dst, dtype_is_object, ndim, False)
+ refcount_copying(&dst, dtype_is_object, ndim, inc=False)
memcpy(dst.data, src.data, slice_get_size(&src, ndim))
- refcount_copying(&dst, dtype_is_object, ndim, True)
+ refcount_copying(&dst, dtype_is_object, ndim, inc=True)
free(tmpdata)
return 0
@@ -1331,9 +1340,9 @@ cdef int memoryview_copy_contents({{memviewslice_name}} src,
transpose_memslice(&src)
transpose_memslice(&dst)
- refcount_copying(&dst, dtype_is_object, ndim, False)
+ refcount_copying(&dst, dtype_is_object, ndim, inc=False)
copy_strided_to_strided(&src, &dst, ndim, itemsize)
- refcount_copying(&dst, dtype_is_object, ndim, True)
+ refcount_copying(&dst, dtype_is_object, ndim, inc=True)
free(tmpdata)
return 0
@@ -1341,7 +1350,7 @@ cdef int memoryview_copy_contents({{memviewslice_name}} src,
@cname('__pyx_memoryview_broadcast_leading')
cdef void broadcast_leading({{memviewslice_name}} *mslice,
int ndim,
- int ndim_other) nogil:
+ int ndim_other) noexcept nogil:
cdef int i
cdef int offset = ndim_other - ndim
@@ -1361,24 +1370,22 @@ cdef void broadcast_leading({{memviewslice_name}} *mslice,
#
@cname('__pyx_memoryview_refcount_copying')
-cdef void refcount_copying({{memviewslice_name}} *dst, bint dtype_is_object,
- int ndim, bint inc) nogil:
- # incref or decref the objects in the destination slice if the dtype is
- # object
+cdef void refcount_copying({{memviewslice_name}} *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil:
+ # incref or decref the objects in the destination slice if the dtype is object
if dtype_is_object:
- refcount_objects_in_slice_with_gil(dst.data, dst.shape,
- dst.strides, ndim, inc)
+ refcount_objects_in_slice_with_gil(dst.data, dst.shape, dst.strides, ndim, inc)
@cname('__pyx_memoryview_refcount_objects_in_slice_with_gil')
cdef void refcount_objects_in_slice_with_gil(char *data, Py_ssize_t *shape,
Py_ssize_t *strides, int ndim,
- bint inc) with gil:
+ bint inc) noexcept with gil:
refcount_objects_in_slice(data, shape, strides, ndim, inc)
@cname('__pyx_memoryview_refcount_objects_in_slice')
cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape,
- Py_ssize_t *strides, int ndim, bint inc):
+ Py_ssize_t *strides, int ndim, bint inc) noexcept:
cdef Py_ssize_t i
+ cdef Py_ssize_t stride = strides[0]
for i in range(shape[0]):
if ndim == 1:
@@ -1387,10 +1394,9 @@ cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape,
else:
Py_DECREF((<PyObject **> data)[0])
else:
- refcount_objects_in_slice(data, shape + 1, strides + 1,
- ndim - 1, inc)
+ refcount_objects_in_slice(data, shape + 1, strides + 1, ndim - 1, inc)
- data += strides[0]
+ data += stride
#
### Scalar to slice assignment
@@ -1398,17 +1404,16 @@ cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape,
@cname('__pyx_memoryview_slice_assign_scalar')
cdef void slice_assign_scalar({{memviewslice_name}} *dst, int ndim,
size_t itemsize, void *item,
- bint dtype_is_object) nogil:
- refcount_copying(dst, dtype_is_object, ndim, False)
- _slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim,
- itemsize, item)
- refcount_copying(dst, dtype_is_object, ndim, True)
+ bint dtype_is_object) noexcept nogil:
+ refcount_copying(dst, dtype_is_object, ndim, inc=False)
+ _slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, itemsize, item)
+ refcount_copying(dst, dtype_is_object, ndim, inc=True)
@cname('__pyx_memoryview__slice_assign_scalar')
cdef void _slice_assign_scalar(char *data, Py_ssize_t *shape,
Py_ssize_t *strides, int ndim,
- size_t itemsize, void *item) nogil:
+ size_t itemsize, void *item) noexcept nogil:
cdef Py_ssize_t i
cdef Py_ssize_t stride = strides[0]
cdef Py_ssize_t extent = shape[0]
@@ -1419,8 +1424,7 @@ cdef void _slice_assign_scalar(char *data, Py_ssize_t *shape,
data += stride
else:
for i in range(extent):
- _slice_assign_scalar(data, shape + 1, strides + 1,
- ndim - 1, itemsize, item)
+ _slice_assign_scalar(data, shape + 1, strides + 1, ndim - 1, itemsize, item)
data += stride
@@ -1433,27 +1437,27 @@ cdef extern from *:
__PYX_BUF_FLAGS_INTEGER_COMPLEX
ctypedef struct __Pyx_TypeInfo:
- char* name
- __Pyx_StructField* fields
- size_t size
- size_t arraysize[8]
- int ndim
- char typegroup
- char is_unsigned
- int flags
+ char* name
+ __Pyx_StructField* fields
+ size_t size
+ size_t arraysize[8]
+ int ndim
+ char typegroup
+ char is_unsigned
+ int flags
ctypedef struct __Pyx_StructField:
- __Pyx_TypeInfo* type
- char* name
- size_t offset
+ __Pyx_TypeInfo* type
+ char* name
+ size_t offset
ctypedef struct __Pyx_BufFmt_StackElem:
- __Pyx_StructField* field
- size_t parent_offset
+ __Pyx_StructField* field
+ size_t parent_offset
#ctypedef struct __Pyx_BufFmt_Context:
# __Pyx_StructField root
- __Pyx_BufFmt_StackElem* head
+ __Pyx_BufFmt_StackElem* head
struct __pyx_typeinfo_string:
char string[3]
@@ -1466,6 +1470,7 @@ cdef bytes format_from_typeinfo(__Pyx_TypeInfo *type):
cdef __Pyx_StructField *field
cdef __pyx_typeinfo_string fmt
cdef bytes part, result
+ cdef Py_ssize_t i
if type.typegroup == 'S':
assert type.fields != NULL
@@ -1487,10 +1492,9 @@ cdef bytes format_from_typeinfo(__Pyx_TypeInfo *type):
result = alignment.join(parts) + b'}'
else:
fmt = __Pyx_TypeInfoToFormat(type)
+ result = fmt.string
if type.arraysize[0]:
- extents = [unicode(type.arraysize[i]) for i in range(type.ndim)]
- result = (u"(%s)" % u','.join(extents)).encode('ascii') + fmt.string
- else:
- result = fmt.string
+ extents = [f"{type.arraysize[i]}" for i in range(type.ndim)]
+ result = f"({u','.join(extents)})".encode('ascii') + result
return result