| Index: third_party/cython/src/Cython/Utility/MemoryView.pyx
|
| diff --git a/third_party/cython/src/Cython/Utility/MemoryView.pyx b/third_party/cython/src/Cython/Utility/MemoryView.pyx
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..66aab272406e2bc61d3cf7c7fe1bff955032c2b0
|
| --- /dev/null
|
| +++ b/third_party/cython/src/Cython/Utility/MemoryView.pyx
|
| @@ -0,0 +1,1447 @@
|
| +#################### View.MemoryView ####################
|
| +
|
| +# This utility provides cython.array and cython.view.memoryview
|
| +
|
| +import cython
|
| +
|
| +# from cpython cimport ...
|
| +cdef extern from "Python.h":
|
| + int PyIndex_Check "__Pyx_PyIndex_Check" (object)
|
| + object PyLong_FromVoidPtr(void *)
|
| +
|
| +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 *:
|
| + int __Pyx_GetBuffer(object, Py_buffer *, int) except -1
|
| + void __Pyx_ReleaseBuffer(Py_buffer *)
|
| +
|
| + ctypedef struct PyObject
|
| + ctypedef Py_ssize_t Py_intptr_t
|
| + void Py_INCREF(PyObject *)
|
| + void Py_DECREF(PyObject *)
|
| +
|
| + void* PyMem_Malloc(size_t n)
|
| + void PyMem_Free(void *p)
|
| +
|
| + cdef struct __pyx_memoryview "__pyx_memoryview_obj":
|
| + Py_buffer view
|
| + PyObject *obj
|
| + __Pyx_TypeInfo *typeinfo
|
| +
|
| + ctypedef struct {{memviewslice_name}}:
|
| + __pyx_memoryview *memview
|
| + char *data
|
| + Py_ssize_t shape[{{max_dims}}]
|
| + Py_ssize_t strides[{{max_dims}}]
|
| + 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)
|
| +
|
| + ctypedef struct __pyx_buffer "Py_buffer":
|
| + PyObject *obj
|
| +
|
| + PyObject *Py_None
|
| +
|
| + cdef enum:
|
| + PyBUF_C_CONTIGUOUS,
|
| + PyBUF_F_CONTIGUOUS,
|
| + PyBUF_ANY_CONTIGUOUS
|
| + PyBUF_FORMAT
|
| + PyBUF_WRITABLE
|
| + PyBUF_STRIDES
|
| + PyBUF_INDIRECT
|
| + PyBUF_RECORDS
|
| +
|
| + 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 slice_is_contig "__pyx_memviewslice_is_contig" (
|
| + {{memviewslice_name}} *mvs, char order, int ndim) nogil
|
| + bint slices_overlap "__pyx_slices_overlap" ({{memviewslice_name}} *slice1,
|
| + {{memviewslice_name}} *slice2,
|
| + int ndim, size_t itemsize) nogil
|
| +
|
| +
|
| +cdef extern from "stdlib.h":
|
| + void *malloc(size_t) nogil
|
| + void free(void *) nogil
|
| + void *memcpy(void *dest, void *src, size_t n) nogil
|
| +
|
| +
|
| +
|
| +
|
| +#
|
| +### cython.array class
|
| +#
|
| +
|
| +@cname("__pyx_array")
|
| +cdef class array:
|
| +
|
| + cdef:
|
| + char *data
|
| + Py_ssize_t len
|
| + char *format
|
| + int ndim
|
| + Py_ssize_t *_shape
|
| + Py_ssize_t *_strides
|
| + Py_ssize_t itemsize
|
| + unicode mode # FIXME: this should have been a simple 'char'
|
| + bytes _format
|
| + void (*callback_free_data)(void *data)
|
| + # cdef object _memview
|
| + cdef bint free_data
|
| + cdef bint dtype_is_object
|
| +
|
| + def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None,
|
| + mode="c", bint allocate_buffer=True):
|
| +
|
| + cdef int idx
|
| + cdef Py_ssize_t i, dim
|
| + cdef PyObject **p
|
| +
|
| + self.ndim = <int> len(shape)
|
| + self.itemsize = itemsize
|
| +
|
| + if not self.ndim:
|
| + raise ValueError("Empty shape tuple for cython.array")
|
| +
|
| + if itemsize <= 0:
|
| + raise ValueError("itemsize <= 0 for cython.array")
|
| +
|
| + if isinstance(format, unicode):
|
| + format = (<unicode>format).encode('ASCII')
|
| + self._format = format # keep a reference to the byte string
|
| + self.format = self._format
|
| +
|
| + # use single malloc() for both shape and strides
|
| + self._shape = <Py_ssize_t *> PyMem_Malloc(sizeof(Py_ssize_t)*self.ndim*2)
|
| + self._strides = self._shape + self.ndim
|
| +
|
| + if not self._shape:
|
| + 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))
|
| + self._shape[idx] = dim
|
| +
|
| + cdef char order
|
| + if mode == 'fortran':
|
| + order = b'F'
|
| + self.mode = u'fortran'
|
| + elif mode == 'c':
|
| + order = b'C'
|
| + self.mode = u'c'
|
| + else:
|
| + raise ValueError("Invalid mode, expected 'c' or 'fortran', got %s" % mode)
|
| +
|
| + 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)
|
| +
|
| + @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.")
|
| + 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
|
| + else:
|
| + info.format = 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:
|
| + if self.dtype_is_object:
|
| + refcount_objects_in_slice(self.data, self._shape,
|
| + self._strides, self.ndim, False)
|
| + free(self.data)
|
| + PyMem_Free(self._shape)
|
| +
|
| + property memview:
|
| + @cname('get_memview')
|
| + def __get__(self):
|
| + # Make this a property as 'self.data' may be set after instantiation
|
| + flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE
|
| + return memoryview(self, flags, self.dtype_is_object)
|
| +
|
| +
|
| + def __getattr__(self, attr):
|
| + return getattr(self.memview, attr)
|
| +
|
| + def __getitem__(self, item):
|
| + return self.memview[item]
|
| +
|
| + def __setitem__(self, item, value):
|
| + self.memview[item] = value
|
| +
|
| +
|
| +@cname("__pyx_array_new")
|
| +cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format,
|
| + char *mode, char *buf):
|
| + cdef array result
|
| +
|
| + if buf == NULL:
|
| + result = array(shape, itemsize, format, mode.decode('ASCII'))
|
| + else:
|
| + result = array(shape, itemsize, format, mode.decode('ASCII'),
|
| + allocate_buffer=False)
|
| + result.data = buf
|
| +
|
| + return result
|
| +
|
| +
|
| +#
|
| +### Memoryview constants and cython.view.memoryview class
|
| +#
|
| +
|
| +# Disable generic_contiguous, as it makes trouble verifying contiguity:
|
| +# - 'contiguous' or '::1' means the dimension is contiguous with dtype
|
| +# - 'indirect_contiguous' means a contiguous list of pointers
|
| +# - dtype contiguous must be contiguous in the first or last dimension
|
| +# from the start, or from the dimension following the last indirect dimension
|
| +#
|
| +# e.g.
|
| +# int[::indirect_contiguous, ::contiguous, :]
|
| +#
|
| +# is valid (list of pointers to 2d fortran-contiguous array), but
|
| +#
|
| +# int[::generic_contiguous, ::contiguous, :]
|
| +#
|
| +# would mean you'd have assert dimension 0 to be indirect (and pointer contiguous) at runtime.
|
| +# So it doesn't bring any performance benefit, and it's only confusing.
|
| +
|
| +@cname('__pyx_MemviewEnum')
|
| +cdef class Enum(object):
|
| + cdef object name
|
| + def __init__(self, name):
|
| + self.name = name
|
| + def __repr__(self):
|
| + return self.name
|
| +
|
| +cdef generic = Enum("<strided and direct or indirect>")
|
| +cdef strided = Enum("<strided and direct>") # default
|
| +cdef indirect = Enum("<strided and indirect>")
|
| +# Disable generic_contiguous, as it is a troublemaker
|
| +#cdef generic_contiguous = Enum("<contiguous and direct or indirect>")
|
| +cdef contiguous = Enum("<contiguous and direct>")
|
| +cdef indirect_contiguous = Enum("<contiguous and indirect>")
|
| +
|
| +# 'follow' is implied when the first or last axis is ::1
|
| +
|
| +
|
| +@cname('__pyx_align_pointer')
|
| +cdef void *align_pointer(void *memory, size_t alignment) nogil:
|
| + "Align pointer memory on a given boundary"
|
| + cdef Py_intptr_t aligned_p = <Py_intptr_t> memory
|
| + cdef size_t offset
|
| +
|
| + with cython.cdivision(True):
|
| + offset = aligned_p % alignment
|
| +
|
| + if offset > 0:
|
| + aligned_p += alignment - offset
|
| +
|
| + return <void *> aligned_p
|
| +
|
| +@cname('__pyx_memoryview')
|
| +cdef class memoryview(object):
|
| +
|
| + cdef object obj
|
| + cdef object _size
|
| + cdef object _array_interface
|
| + cdef PyThread_type_lock lock
|
| + # the following array will contain a single __pyx_atomic int with
|
| + # suitable alignment
|
| + cdef __pyx_atomic_int acquisition_count[2]
|
| + cdef __pyx_atomic_int *acquisition_count_aligned_p
|
| + cdef Py_buffer view
|
| + cdef int flags
|
| + cdef bint dtype_is_object
|
| + cdef __Pyx_TypeInfo *typeinfo
|
| +
|
| + def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False):
|
| + self.obj = obj
|
| + self.flags = flags
|
| + if type(self) is memoryview or obj is not None:
|
| + __Pyx_GetBuffer(obj, &self.view, flags)
|
| + if <PyObject *> self.view.obj == NULL:
|
| + (<__pyx_buffer *> &self.view).obj = Py_None
|
| + Py_INCREF(Py_None)
|
| +
|
| + self.lock = PyThread_allocate_lock()
|
| + if self.lock == NULL:
|
| + raise MemoryError
|
| +
|
| + if flags & PyBUF_FORMAT:
|
| + self.dtype_is_object = self.view.format == b'O'
|
| + else:
|
| + self.dtype_is_object = dtype_is_object
|
| +
|
| + self.acquisition_count_aligned_p = <__pyx_atomic_int *> align_pointer(
|
| + <void *> &self.acquisition_count[0], sizeof(__pyx_atomic_int))
|
| + self.typeinfo = NULL
|
| +
|
| + def __dealloc__(memoryview self):
|
| + if self.obj is not None:
|
| + __Pyx_ReleaseBuffer(&self.view)
|
| +
|
| + if self.lock != NULL:
|
| + PyThread_free_lock(self.lock)
|
| +
|
| + cdef char *get_item_pointer(memoryview self, object index) except NULL:
|
| + cdef Py_ssize_t dim
|
| + cdef char *itemp = <char *> self.view.buf
|
| +
|
| + for dim, idx in enumerate(index):
|
| + itemp = pybuffer_index(&self.view, itemp, idx, dim)
|
| +
|
| + return itemp
|
| +
|
| + #@cname('__pyx_memoryview_getitem')
|
| + def __getitem__(memoryview self, object index):
|
| + if index is Ellipsis:
|
| + return self
|
| +
|
| + have_slices, indices = _unellipsify(index, self.view.ndim)
|
| +
|
| + cdef char *itemp
|
| + if have_slices:
|
| + return memview_slice(self, indices)
|
| + else:
|
| + itemp = self.get_item_pointer(indices)
|
| + return self.convert_item_to_object(itemp)
|
| +
|
| + def __setitem__(memoryview self, object index, object value):
|
| + have_slices, index = _unellipsify(index, self.view.ndim)
|
| +
|
| + if have_slices:
|
| + obj = self.is_slice(value)
|
| + if obj:
|
| + self.setitem_slice_assignment(self[index], obj)
|
| + else:
|
| + self.setitem_slice_assign_scalar(self[index], value)
|
| + else:
|
| + self.setitem_indexed(index, value)
|
| +
|
| + cdef is_slice(self, obj):
|
| + if not isinstance(obj, memoryview):
|
| + try:
|
| + obj = memoryview(obj, self.flags|PyBUF_ANY_CONTIGUOUS,
|
| + self.dtype_is_object)
|
| + except TypeError:
|
| + return None
|
| +
|
| + return obj
|
| +
|
| + cdef setitem_slice_assignment(self, dst, src):
|
| + cdef {{memviewslice_name}} dst_slice
|
| + cdef {{memviewslice_name}} src_slice
|
| +
|
| + 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)
|
| +
|
| + cdef setitem_slice_assign_scalar(self, memoryview dst, value):
|
| + cdef int array[128]
|
| + cdef void *tmp = NULL
|
| + cdef void *item
|
| +
|
| + cdef {{memviewslice_name}} *dst_slice
|
| + cdef {{memviewslice_name}} tmp_slice
|
| + dst_slice = get_slice_from_memview(dst, &tmp_slice)
|
| +
|
| + if <size_t>self.view.itemsize > sizeof(array):
|
| + tmp = PyMem_Malloc(self.view.itemsize)
|
| + if tmp == NULL:
|
| + raise MemoryError
|
| + item = tmp
|
| + else:
|
| + item = <void *> array
|
| +
|
| + try:
|
| + if self.dtype_is_object:
|
| + (<PyObject **> item)[0] = <PyObject *> value
|
| + else:
|
| + self.assign_item_from_object(<char *> item, value)
|
| +
|
| + # It would be easy to support indirect dimensions, but it's easier
|
| + # to disallow :)
|
| + if self.view.suboffsets != NULL:
|
| + assert_direct_dimensions(self.view.suboffsets, self.view.ndim)
|
| + slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize,
|
| + item, self.dtype_is_object)
|
| + finally:
|
| + PyMem_Free(tmp)
|
| +
|
| + cdef setitem_indexed(self, index, value):
|
| + cdef char *itemp = self.get_item_pointer(index)
|
| + self.assign_item_from_object(itemp, value)
|
| +
|
| + cdef convert_item_to_object(self, char *itemp):
|
| + """Only used if instantiated manually by the user, or if Cython doesn't
|
| + know how to convert the type"""
|
| + import struct
|
| + cdef bytes bytesitem
|
| + # Do a manual and complete check here instead of this easy hack
|
| + bytesitem = itemp[:self.view.itemsize]
|
| + try:
|
| + result = struct.unpack(self.view.format, bytesitem)
|
| + except struct.error:
|
| + raise ValueError("Unable to convert item to object")
|
| + else:
|
| + if len(self.view.format) == 1:
|
| + return result[0]
|
| + return result
|
| +
|
| + cdef assign_item_from_object(self, char *itemp, object value):
|
| + """Only used if instantiated manually by the user, or if Cython doesn't
|
| + know how to convert the type"""
|
| + import struct
|
| + cdef char c
|
| + cdef bytes bytesvalue
|
| + cdef Py_ssize_t i
|
| +
|
| + if isinstance(value, tuple):
|
| + bytesvalue = struct.pack(self.view.format, *value)
|
| + else:
|
| + bytesvalue = struct.pack(self.view.format, value)
|
| +
|
| + for i, c in enumerate(bytesvalue):
|
| + itemp[i] = c
|
| +
|
| + @cname('getbuffer')
|
| + def __getbuffer__(self, Py_buffer *info, int flags):
|
| + if flags & PyBUF_STRIDES:
|
| + info.shape = self.view.shape
|
| + else:
|
| + info.shape = NULL
|
| +
|
| + if flags & PyBUF_STRIDES:
|
| + info.strides = self.view.strides
|
| + else:
|
| + info.strides = NULL
|
| +
|
| + if flags & PyBUF_INDIRECT:
|
| + info.suboffsets = self.view.suboffsets
|
| + else:
|
| + info.suboffsets = NULL
|
| +
|
| + if flags & PyBUF_FORMAT:
|
| + info.format = self.view.format
|
| + else:
|
| + info.format = NULL
|
| +
|
| + info.buf = self.view.buf
|
| + info.ndim = self.view.ndim
|
| + info.itemsize = self.view.itemsize
|
| + info.len = self.view.len
|
| + info.readonly = 0
|
| + info.obj = self
|
| +
|
| + __pyx_getbuffer = capsule(<void *> &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)")
|
| +
|
| + # Some properties that have the same sematics as in NumPy
|
| + property T:
|
| + @cname('__pyx_memoryview_transpose')
|
| + def __get__(self):
|
| + cdef _memoryviewslice result = memoryview_copy(self)
|
| + transpose_memslice(&result.from_slice)
|
| + return result
|
| +
|
| + property base:
|
| + @cname('__pyx_memoryview__get__base')
|
| + def __get__(self):
|
| + return self.obj
|
| +
|
| + property shape:
|
| + @cname('__pyx_memoryview_get_shape')
|
| + def __get__(self):
|
| + return tuple([self.view.shape[i] for i in xrange(self.view.ndim)])
|
| +
|
| + property strides:
|
| + @cname('__pyx_memoryview_get_strides')
|
| + def __get__(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")
|
| +
|
| + return tuple([self.view.strides[i] for i in xrange(self.view.ndim)])
|
| +
|
| + property suboffsets:
|
| + @cname('__pyx_memoryview_get_suboffsets')
|
| + def __get__(self):
|
| + if self.view.suboffsets == NULL:
|
| + return [-1] * self.view.ndim
|
| +
|
| + return tuple([self.view.suboffsets[i] for i in xrange(self.view.ndim)])
|
| +
|
| + property ndim:
|
| + @cname('__pyx_memoryview_get_ndim')
|
| + def __get__(self):
|
| + return self.view.ndim
|
| +
|
| + property itemsize:
|
| + @cname('__pyx_memoryview_get_itemsize')
|
| + def __get__(self):
|
| + return self.view.itemsize
|
| +
|
| + property nbytes:
|
| + @cname('__pyx_memoryview_get_nbytes')
|
| + def __get__(self):
|
| + return self.size * self.view.itemsize
|
| +
|
| + property size:
|
| + @cname('__pyx_memoryview_get_size')
|
| + def __get__(self):
|
| + if self._size is None:
|
| + result = 1
|
| +
|
| + for length in self.shape:
|
| + result *= length
|
| +
|
| + self._size = result
|
| +
|
| + return self._size
|
| +
|
| + def __len__(self):
|
| + if self.view.ndim >= 1:
|
| + return self.view.shape[0]
|
| +
|
| + return 0
|
| +
|
| + def __repr__(self):
|
| + return "<MemoryView of %r at 0x%x>" % (self.base.__class__.__name__,
|
| + id(self))
|
| +
|
| + def __str__(self):
|
| + return "<MemoryView of %r object>" % (self.base.__class__.__name__,)
|
| +
|
| + # Support the same attributes as memoryview slices
|
| + def is_c_contig(self):
|
| + cdef {{memviewslice_name}} *mslice
|
| + cdef {{memviewslice_name}} tmp
|
| + mslice = get_slice_from_memview(self, &tmp)
|
| + return slice_is_contig(mslice, 'C', self.view.ndim)
|
| +
|
| + def is_f_contig(self):
|
| + cdef {{memviewslice_name}} *mslice
|
| + cdef {{memviewslice_name}} tmp
|
| + mslice = get_slice_from_memview(self, &tmp)
|
| + return slice_is_contig(mslice, 'F', self.view.ndim)
|
| +
|
| + def copy(self):
|
| + cdef {{memviewslice_name}} mslice
|
| + cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS
|
| +
|
| + slice_copy(self, &mslice)
|
| + mslice = slice_copy_contig(&mslice, "c", self.view.ndim,
|
| + self.view.itemsize,
|
| + flags|PyBUF_C_CONTIGUOUS,
|
| + self.dtype_is_object)
|
| +
|
| + return memoryview_copy_from_slice(self, &mslice)
|
| +
|
| + def copy_fortran(self):
|
| + cdef {{memviewslice_name}} src, dst
|
| + cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS
|
| +
|
| + slice_copy(self, &src)
|
| + dst = slice_copy_contig(&src, "fortran", self.view.ndim,
|
| + self.view.itemsize,
|
| + flags|PyBUF_F_CONTIGUOUS,
|
| + self.dtype_is_object)
|
| +
|
| + return memoryview_copy_from_slice(self, &dst)
|
| +
|
| +
|
| +@cname('__pyx_memoryview_new')
|
| +cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo):
|
| + cdef memoryview result = memoryview(o, flags, dtype_is_object)
|
| + result.typeinfo = typeinfo
|
| + return result
|
| +
|
| +@cname('__pyx_memoryview_check')
|
| +cdef inline bint memoryview_check(object o):
|
| + return isinstance(o, memoryview)
|
| +
|
| +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
|
| +
|
| + result = []
|
| + have_slices = False
|
| + seen_ellipsis = False
|
| + for idx, item in enumerate(tup):
|
| + if item is Ellipsis:
|
| + if not seen_ellipsis:
|
| + result.extend([slice(None)] * (ndim - len(tup) + 1))
|
| + 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)
|
| +
|
| + return have_slices or nslices, tuple(result)
|
| +
|
| +cdef assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim):
|
| + cdef int i
|
| + for i in range(ndim):
|
| + if suboffsets[i] >= 0:
|
| + raise ValueError("Indirect dimensions not supported")
|
| +
|
| +#
|
| +### Slicing a memoryview
|
| +#
|
| +
|
| +@cname('__pyx_memview_slice')
|
| +cdef memoryview memview_slice(memoryview memview, object indices):
|
| + cdef int new_ndim = 0, suboffset_dim = -1, dim
|
| + cdef bint negative_step
|
| + cdef {{memviewslice_name}} src, dst
|
| + cdef {{memviewslice_name}} *p_src
|
| +
|
| + # dst is copied by value in memoryview_fromslice -- initialize it
|
| + # src is never copied
|
| + memset(&dst, 0, sizeof(dst))
|
| +
|
| + cdef _memoryviewslice memviewsliceobj
|
| +
|
| + assert memview.view.ndim > 0
|
| +
|
| + if isinstance(memview, _memoryviewslice):
|
| + memviewsliceobj = memview
|
| + p_src = &memviewsliceobj.from_slice
|
| + else:
|
| + slice_copy(memview, &src)
|
| + p_src = &src
|
| +
|
| + # Note: don't use variable src at this point
|
| + # SubNote: we should be able to declare variables in blocks...
|
| +
|
| + # memoryview_fromslice() will inc our dst slice
|
| + dst.memview = p_src.memview
|
| + dst.data = p_src.data
|
| +
|
| + # Put everything in temps to avoid this bloody warning:
|
| + # "Argument evaluation order in C function call is undefined and
|
| + # 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 bint have_start, have_stop, have_step
|
| +
|
| + for dim, index in enumerate(indices):
|
| + if PyIndex_Check(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
|
| + 0, 0, 0, # have_{start,stop,step}
|
| + False)
|
| + elif index is None:
|
| + p_dst.shape[new_ndim] = 1
|
| + p_dst.strides[new_ndim] = 0
|
| + p_dst.suboffsets[new_ndim] = -1
|
| + new_ndim += 1
|
| + else:
|
| + start = index.start or 0
|
| + stop = index.stop or 0
|
| + step = index.step or 0
|
| +
|
| + have_start = index.start is not None
|
| + have_stop = index.stop is not None
|
| + have_step = index.step is not None
|
| +
|
| + slice_memviewslice(
|
| + p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim],
|
| + dim, new_ndim, p_suboffset_dim,
|
| + start, stop, step,
|
| + have_start, have_stop, have_step,
|
| + True)
|
| + new_ndim += 1
|
| +
|
| + if isinstance(memview, _memoryviewslice):
|
| + return memoryview_fromslice(dst, new_ndim,
|
| + memviewsliceobj.to_object_func,
|
| + memviewsliceobj.to_dtype_func,
|
| + memview.dtype_is_object)
|
| + else:
|
| + return memoryview_fromslice(dst, new_ndim, NULL, NULL,
|
| + memview.dtype_is_object)
|
| +
|
| +
|
| +#
|
| +### 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,
|
| + Py_ssize_t shape, Py_ssize_t stride, Py_ssize_t suboffset,
|
| + 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:
|
| + """
|
| + Create a new slice dst given slice src.
|
| +
|
| + dim - the current src dimension (indexing will make dimensions
|
| + disappear)
|
| + new_dim - the new dst dimension
|
| + suboffset_dim - pointer to a single int initialized to -1 to keep track of
|
| + where slicing offsets should be added
|
| + """
|
| +
|
| + cdef Py_ssize_t new_shape
|
| + cdef bint negative_step
|
| +
|
| + if not is_slice:
|
| + # index is a normal integer-like index
|
| + if start < 0:
|
| + start += shape
|
| + if not 0 <= start < shape:
|
| + _err_dim(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)
|
| +
|
| + # check our bounds and set defaults
|
| + if have_start:
|
| + if start < 0:
|
| + start += shape
|
| + if start < 0:
|
| + start = 0
|
| + elif start >= shape:
|
| + if negative_step:
|
| + start = shape - 1
|
| + else:
|
| + start = shape
|
| + else:
|
| + if negative_step:
|
| + start = shape - 1
|
| + else:
|
| + start = 0
|
| +
|
| + if have_stop:
|
| + if stop < 0:
|
| + stop += shape
|
| + if stop < 0:
|
| + stop = 0
|
| + elif stop > shape:
|
| + stop = shape
|
| + else:
|
| + if negative_step:
|
| + stop = -1
|
| + else:
|
| + stop = shape
|
| +
|
| + if not have_step:
|
| + step = 1
|
| +
|
| + # len = ceil( (stop - start) / step )
|
| + with cython.cdivision(True):
|
| + new_shape = (stop - start) // step
|
| +
|
| + if (stop - start) - step * new_shape:
|
| + new_shape += 1
|
| +
|
| + if new_shape < 0:
|
| + new_shape = 0
|
| +
|
| + # shape/strides/suboffsets
|
| + dst.strides[new_ndim] = stride * step
|
| + dst.shape[new_ndim] = new_shape
|
| + dst.suboffsets[new_ndim] = suboffset
|
| +
|
| + # Add the slicing or idexing offsets to the right suboffset or base data *
|
| + if suboffset_dim[0] < 0:
|
| + dst.data += start * stride
|
| + else:
|
| + dst.suboffsets[suboffset_dim[0]] += start * stride
|
| +
|
| + if suboffset >= 0:
|
| + if not is_slice:
|
| + if new_ndim == 0:
|
| + dst.data = (<char **> dst.data)[0] + suboffset
|
| + else:
|
| + _err_dim(IndexError, "All dimensions preceding dimension %d "
|
| + "must be indexed and not sliced", dim)
|
| + else:
|
| + suboffset_dim[0] = new_ndim
|
| +
|
| + return 0
|
| +
|
| +#
|
| +### Index a memoryview
|
| +#
|
| +@cname('__pyx_pybuffer_index')
|
| +cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index,
|
| + Py_ssize_t dim) except NULL:
|
| + cdef Py_ssize_t shape, stride, suboffset = -1
|
| + cdef Py_ssize_t itemsize = view.itemsize
|
| + cdef char *resultp
|
| +
|
| + if view.ndim == 0:
|
| + shape = view.len / itemsize
|
| + stride = itemsize
|
| + else:
|
| + shape = view.shape[dim]
|
| + stride = view.strides[dim]
|
| + if view.suboffsets != NULL:
|
| + suboffset = view.suboffsets[dim]
|
| +
|
| + if index < 0:
|
| + index += view.shape[dim]
|
| + if index < 0:
|
| + raise IndexError("Out of bounds on buffer access (axis %d)" % dim)
|
| +
|
| + if index >= shape:
|
| + raise IndexError("Out of bounds on buffer access (axis %d)" % dim)
|
| +
|
| + resultp = bufp + index * stride
|
| + if suboffset >= 0:
|
| + resultp = (<char **> resultp)[0] + suboffset
|
| +
|
| + return resultp
|
| +
|
| +#
|
| +### Transposing a memoryviewslice
|
| +#
|
| +@cname('__pyx_memslice_transpose')
|
| +cdef int transpose_memslice({{memviewslice_name}} *memslice) nogil except 0:
|
| + cdef int ndim = memslice.memview.view.ndim
|
| +
|
| + cdef Py_ssize_t *shape = memslice.shape
|
| + cdef Py_ssize_t *strides = memslice.strides
|
| +
|
| + # reverse strides and shape
|
| + cdef int i, j
|
| + 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")
|
| +
|
| + return 1
|
| +
|
| +#
|
| +### Creating new memoryview objects from slices and memoryviews
|
| +#
|
| +@cname('__pyx_memoryviewslice')
|
| +cdef class _memoryviewslice(memoryview):
|
| + "Internal class for passing memoryview slices to Python"
|
| +
|
| + # We need this to keep our shape/strides/suboffset pointers valid
|
| + cdef {{memviewslice_name}} from_slice
|
| + # We need this only to print it's class' name
|
| + cdef object from_object
|
| +
|
| + cdef object (*to_object_func)(char *)
|
| + cdef int (*to_dtype_func)(char *, object) except 0
|
| +
|
| + def __dealloc__(self):
|
| + __PYX_XDEC_MEMVIEW(&self.from_slice, 1)
|
| +
|
| + cdef convert_item_to_object(self, char *itemp):
|
| + if self.to_object_func != NULL:
|
| + return self.to_object_func(itemp)
|
| + else:
|
| + return memoryview.convert_item_to_object(self, itemp)
|
| +
|
| + cdef assign_item_from_object(self, char *itemp, object value):
|
| + if self.to_dtype_func != NULL:
|
| + self.to_dtype_func(itemp, value)
|
| + else:
|
| + memoryview.assign_item_from_object(self, itemp, value)
|
| +
|
| + property base:
|
| + @cname('__pyx_memoryviewslice__get__base')
|
| + def __get__(self):
|
| + return self.from_object
|
| +
|
| + __pyx_getbuffer = capsule(<void *> &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)")
|
| +
|
| +
|
| +@cname('__pyx_memoryview_fromslice')
|
| +cdef memoryview_fromslice({{memviewslice_name}} memviewslice,
|
| + int ndim,
|
| + object (*to_object_func)(char *),
|
| + int (*to_dtype_func)(char *, object) except 0,
|
| + bint dtype_is_object):
|
| +
|
| + cdef _memoryviewslice result
|
| + cdef int i
|
| +
|
| + if <PyObject *> memviewslice.memview == Py_None:
|
| + return None
|
| +
|
| + # assert 0 < ndim <= memviewslice.memview.view.ndim, (
|
| + # ndim, memviewslice.memview.view.ndim)
|
| +
|
| + result = _memoryviewslice(None, 0, dtype_is_object)
|
| +
|
| + result.from_slice = memviewslice
|
| + __PYX_INC_MEMVIEW(&memviewslice, 1)
|
| +
|
| + result.from_object = (<memoryview> memviewslice.memview).base
|
| + result.typeinfo = memviewslice.memview.typeinfo
|
| +
|
| + result.view = memviewslice.memview.view
|
| + result.view.buf = <void *> memviewslice.data
|
| + result.view.ndim = ndim
|
| + (<__pyx_buffer *> &result.view).obj = Py_None
|
| + Py_INCREF(Py_None)
|
| +
|
| + result.flags = PyBUF_RECORDS
|
| +
|
| + result.view.shape = <Py_ssize_t *> result.from_slice.shape
|
| + result.view.strides = <Py_ssize_t *> result.from_slice.strides
|
| + result.view.suboffsets = <Py_ssize_t *> result.from_slice.suboffsets
|
| +
|
| + result.view.len = result.view.itemsize
|
| + for i in range(ndim):
|
| + result.view.len *= result.view.shape[i]
|
| +
|
| + result.to_object_func = to_object_func
|
| + result.to_dtype_func = to_dtype_func
|
| +
|
| + return result
|
| +
|
| +@cname('__pyx_memoryview_get_slice_from_memoryview')
|
| +cdef {{memviewslice_name}} *get_slice_from_memview(memoryview memview,
|
| + {{memviewslice_name}} *mslice):
|
| + cdef _memoryviewslice obj
|
| + if isinstance(memview, _memoryviewslice):
|
| + obj = memview
|
| + return &obj.from_slice
|
| + else:
|
| + slice_copy(memview, mslice)
|
| + return mslice
|
| +
|
| +@cname('__pyx_memoryview_slice_copy')
|
| +cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst):
|
| + cdef int dim
|
| + cdef (Py_ssize_t*) shape, strides, suboffsets
|
| +
|
| + shape = memview.view.shape
|
| + strides = memview.view.strides
|
| + suboffsets = memview.view.suboffsets
|
| +
|
| + dst.memview = <__pyx_memoryview *> memview
|
| + dst.data = <char *> memview.view.buf
|
| +
|
| + for dim in range(memview.view.ndim):
|
| + dst.shape[dim] = shape[dim]
|
| + dst.strides[dim] = strides[dim]
|
| + if suboffsets == NULL:
|
| + dst.suboffsets[dim] = -1
|
| + else:
|
| + dst.suboffsets[dim] = suboffsets[dim]
|
| +
|
| +@cname('__pyx_memoryview_copy_object')
|
| +cdef memoryview_copy(memoryview memview):
|
| + "Create a new memoryview object"
|
| + cdef {{memviewslice_name}} memviewslice
|
| + slice_copy(memview, &memviewslice)
|
| + return memoryview_copy_from_slice(memview, &memviewslice)
|
| +
|
| +@cname('__pyx_memoryview_copy_object_from_slice')
|
| +cdef memoryview_copy_from_slice(memoryview memview, {{memviewslice_name}} *memviewslice):
|
| + """
|
| + Create a new memoryview object from a given memoryview object and slice.
|
| + """
|
| + cdef object (*to_object_func)(char *)
|
| + cdef int (*to_dtype_func)(char *, object) except 0
|
| +
|
| + if isinstance(memview, _memoryviewslice):
|
| + to_object_func = (<_memoryviewslice> memview).to_object_func
|
| + to_dtype_func = (<_memoryviewslice> memview).to_dtype_func
|
| + else:
|
| + to_object_func = NULL
|
| + to_dtype_func = NULL
|
| +
|
| + return memoryview_fromslice(memviewslice[0], memview.view.ndim,
|
| + to_object_func, to_dtype_func,
|
| + memview.dtype_is_object)
|
| +
|
| +
|
| +#
|
| +### 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
|
| +
|
| +@cname('__pyx_get_best_slice_order')
|
| +cdef char get_best_order({{memviewslice_name}} *mslice, int ndim) nogil:
|
| + """
|
| + Figure out the best memory access order for a given slice.
|
| + """
|
| + cdef int i
|
| + cdef Py_ssize_t c_stride = 0
|
| + cdef Py_ssize_t f_stride = 0
|
| +
|
| + for i in range(ndim - 1, -1, -1):
|
| + if mslice.shape[i] > 1:
|
| + c_stride = mslice.strides[i]
|
| + break
|
| +
|
| + for i in range(ndim):
|
| + if mslice.shape[i] > 1:
|
| + f_stride = mslice.strides[i]
|
| + break
|
| +
|
| + if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride):
|
| + return 'C'
|
| + else:
|
| + return 'F'
|
| +
|
| +@cython.cdivision(True)
|
| +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:
|
| + # 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
|
| + cdef Py_ssize_t src_extent = src_shape[0]
|
| + cdef Py_ssize_t dst_extent = dst_shape[0]
|
| + cdef Py_ssize_t src_stride = src_strides[0]
|
| + 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
|
| + else:
|
| + for i in range(dst_extent):
|
| + _copy_strided_to_strided(src_data, src_strides + 1,
|
| + dst_data, dst_strides + 1,
|
| + src_shape + 1, dst_shape + 1,
|
| + ndim - 1, itemsize)
|
| + src_data += src_stride
|
| + dst_data += dst_stride
|
| +
|
| +cdef void copy_strided_to_strided({{memviewslice_name}} *src,
|
| + {{memviewslice_name}} *dst,
|
| + int ndim, size_t itemsize) 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:
|
| + "Return the size of the memory occupied by the slice in number of bytes"
|
| + cdef int i
|
| + cdef Py_ssize_t size = src.memview.view.itemsize
|
| +
|
| + for i in range(ndim):
|
| + size *= src.shape[i]
|
| +
|
| + return size
|
| +
|
| +@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:
|
| + """
|
| + Fill the strides array for a slice with C or F contiguous strides.
|
| + This is like PyBuffer_FillContiguousStrides, but compatible with py < 2.6
|
| + """
|
| + cdef int idx
|
| +
|
| + if order == 'F':
|
| + for idx in range(ndim):
|
| + strides[idx] = stride
|
| + stride = stride * shape[idx]
|
| + else:
|
| + for idx in range(ndim - 1, -1, -1):
|
| + strides[idx] = stride
|
| + stride = stride * shape[idx]
|
| +
|
| + return stride
|
| +
|
| +@cname('__pyx_memoryview_copy_data_to_temp')
|
| +cdef void *copy_data_to_temp({{memviewslice_name}} *src,
|
| + {{memviewslice_name}} *tmpslice,
|
| + char order,
|
| + int ndim) nogil except NULL:
|
| + """
|
| + Copy a direct slice to temporary contiguous memory. The caller should free
|
| + the result when done.
|
| + """
|
| + cdef int i
|
| + cdef void *result
|
| +
|
| + cdef size_t itemsize = src.memview.view.itemsize
|
| + cdef size_t size = slice_get_size(src, ndim)
|
| +
|
| + result = malloc(size)
|
| + if not result:
|
| + _err(MemoryError, NULL)
|
| +
|
| + # tmpslice[0] = src
|
| + tmpslice.data = <char *> result
|
| + tmpslice.memview = src.memview
|
| + for i in range(ndim):
|
| + tmpslice.shape[i] = src.shape[i]
|
| + tmpslice.suboffsets[i] = -1
|
| +
|
| + fill_contig_strides_array(&tmpslice.shape[0], &tmpslice.strides[0], itemsize,
|
| + ndim, order)
|
| +
|
| + # We need to broadcast strides again
|
| + for i in range(ndim):
|
| + if tmpslice.shape[i] == 1:
|
| + tmpslice.strides[i] = 0
|
| +
|
| + if slice_is_contig(src, order, ndim):
|
| + memcpy(result, src.data, size)
|
| + else:
|
| + copy_strided_to_strided(src, tmpslice, ndim, itemsize)
|
| +
|
| + return result
|
| +
|
| +# Use 'with gil' functions and avoid 'with gil' blocks, as the code within the blocks
|
| +# has temporaries that need the GIL to clean up
|
| +@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))
|
| +
|
| +@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)
|
| +
|
| +@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
|
| +
|
| +@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:
|
| + """
|
| + Copy memory from slice src to slice dst.
|
| + Check for overlapping memory and verify the shapes.
|
| + """
|
| + cdef void *tmpdata = NULL
|
| + cdef size_t itemsize = src.memview.view.itemsize
|
| + cdef int i
|
| + cdef char order = get_best_order(&src, src_ndim)
|
| + cdef bint broadcasting = False
|
| + cdef bint direct_copy = False
|
| + cdef {{memviewslice_name}} tmp
|
| +
|
| + if src_ndim < dst_ndim:
|
| + broadcast_leading(&src, src_ndim, dst_ndim)
|
| + elif dst_ndim < src_ndim:
|
| + broadcast_leading(&dst, dst_ndim, src_ndim)
|
| +
|
| + cdef int ndim = max(src_ndim, dst_ndim)
|
| +
|
| + for i in range(ndim):
|
| + if src.shape[i] != dst.shape[i]:
|
| + if src.shape[i] == 1:
|
| + broadcasting = True
|
| + src.strides[i] = 0
|
| + else:
|
| + _err_extents(i, dst.shape[i], src.shape[i])
|
| +
|
| + if src.suboffsets[i] >= 0:
|
| + _err_dim(ValueError, "Dimension %d is not direct", i)
|
| +
|
| + if slices_overlap(&src, &dst, ndim, itemsize):
|
| + # slices overlap, copy to temp, copy temp to dst
|
| + if not slice_is_contig(&src, order, ndim):
|
| + order = get_best_order(&dst, ndim)
|
| +
|
| + tmpdata = copy_data_to_temp(&src, &tmp, order, ndim)
|
| + src = tmp
|
| +
|
| + if not broadcasting:
|
| + # See if both slices have equal contiguity, in that case perform a
|
| + # direct copy. This only works when we are not broadcasting.
|
| + if slice_is_contig(&src, 'C', ndim):
|
| + direct_copy = slice_is_contig(&dst, 'C', ndim)
|
| + elif slice_is_contig(&src, 'F', ndim):
|
| + direct_copy = slice_is_contig(&dst, 'F', ndim)
|
| +
|
| + if direct_copy:
|
| + # Contiguous slices with same order
|
| + refcount_copying(&dst, dtype_is_object, ndim, False)
|
| + memcpy(dst.data, src.data, slice_get_size(&src, ndim))
|
| + refcount_copying(&dst, dtype_is_object, ndim, True)
|
| + free(tmpdata)
|
| + return 0
|
| +
|
| + if order == 'F' == get_best_order(&dst, ndim):
|
| + # see if both slices have Fortran order, transpose them to match our
|
| + # C-style indexing order
|
| + transpose_memslice(&src)
|
| + transpose_memslice(&dst)
|
| +
|
| + refcount_copying(&dst, dtype_is_object, ndim, False)
|
| + copy_strided_to_strided(&src, &dst, ndim, itemsize)
|
| + refcount_copying(&dst, dtype_is_object, ndim, True)
|
| +
|
| + free(tmpdata)
|
| + return 0
|
| +
|
| +@cname('__pyx_memoryview_broadcast_leading')
|
| +cdef void broadcast_leading({{memviewslice_name}} *slice,
|
| + int ndim,
|
| + int ndim_other) nogil:
|
| + cdef int i
|
| + cdef int offset = ndim_other - ndim
|
| +
|
| + for i in range(ndim - 1, -1, -1):
|
| + slice.shape[i + offset] = slice.shape[i]
|
| + slice.strides[i + offset] = slice.strides[i]
|
| + slice.suboffsets[i + offset] = slice.suboffsets[i]
|
| +
|
| + for i in range(offset):
|
| + slice.shape[i] = 1
|
| + slice.strides[i] = slice.strides[0]
|
| + slice.suboffsets[i] = -1
|
| +
|
| +#
|
| +### Take care of refcounting the objects in slices. Do this seperately from any copying,
|
| +### to minimize acquiring the GIL
|
| +#
|
| +
|
| +@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
|
| + if dtype_is_object:
|
| + 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:
|
| + 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):
|
| + cdef Py_ssize_t i
|
| +
|
| + for i in range(shape[0]):
|
| + if ndim == 1:
|
| + if inc:
|
| + Py_INCREF((<PyObject **> data)[0])
|
| + else:
|
| + Py_DECREF((<PyObject **> data)[0])
|
| + else:
|
| + refcount_objects_in_slice(data, shape + 1, strides + 1,
|
| + ndim - 1, inc)
|
| +
|
| + data += strides[0]
|
| +
|
| +#
|
| +### Scalar to slice assignment
|
| +#
|
| +@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)
|
| +
|
| +
|
| +@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:
|
| + cdef Py_ssize_t i
|
| + cdef Py_ssize_t stride = strides[0]
|
| + cdef Py_ssize_t extent = shape[0]
|
| +
|
| + if ndim == 1:
|
| + for i in range(extent):
|
| + memcpy(data, item, itemsize)
|
| + data += stride
|
| + else:
|
| + for i in range(extent):
|
| + _slice_assign_scalar(data, shape + 1, strides + 1,
|
| + ndim - 1, itemsize, item)
|
| + data += stride
|
| +
|
| +
|
| +############### BufferFormatFromTypeInfo ###############
|
| +cdef extern from *:
|
| + ctypedef struct __Pyx_StructField
|
| +
|
| + cdef enum:
|
| + __PYX_BUF_FLAGS_PACKED_STRUCT
|
| + __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
|
| +
|
| + ctypedef struct __Pyx_StructField:
|
| + __Pyx_TypeInfo* type
|
| + char* name
|
| + size_t offset
|
| +
|
| + ctypedef struct __Pyx_BufFmt_StackElem:
|
| + __Pyx_StructField* field
|
| + size_t parent_offset
|
| +
|
| + #ctypedef struct __Pyx_BufFmt_Context:
|
| + # __Pyx_StructField root
|
| + __Pyx_BufFmt_StackElem* head
|
| +
|
| + struct __pyx_typeinfo_string:
|
| + char string[3]
|
| +
|
| + __pyx_typeinfo_string __Pyx_TypeInfoToFormat(__Pyx_TypeInfo *)
|
| +
|
| +
|
| +@cname('__pyx_format_from_typeinfo')
|
| +cdef bytes format_from_typeinfo(__Pyx_TypeInfo *type):
|
| + cdef __Pyx_StructField *field
|
| + cdef __pyx_typeinfo_string fmt
|
| + cdef bytes part, result
|
| +
|
| + if type.typegroup == 'S':
|
| + assert type.fields != NULL and type.fields.type != NULL
|
| +
|
| + if type.flags & __PYX_BUF_FLAGS_PACKED_STRUCT:
|
| + alignment = b'^'
|
| + else:
|
| + alignment = b''
|
| +
|
| + parts = [b"T{"]
|
| + field = type.fields
|
| +
|
| + while field.type:
|
| + part = format_from_typeinfo(field.type)
|
| + parts.append(part + b':' + field.name + b':')
|
| + field += 1
|
| +
|
| + result = alignment.join(parts) + b'}'
|
| + else:
|
| + fmt = __Pyx_TypeInfoToFormat(type)
|
| + 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
|
| +
|
| + return result
|
|
|