diff options
Diffstat (limited to 'Cython/Utility/MemoryView.pyx')
-rw-r--r-- | Cython/Utility/MemoryView.pyx | 165 |
1 files changed, 155 insertions, 10 deletions
diff --git a/Cython/Utility/MemoryView.pyx b/Cython/Utility/MemoryView.pyx index 1266b5287..4df327ea2 100644 --- a/Cython/Utility/MemoryView.pyx +++ b/Cython/Utility/MemoryView.pyx @@ -10,7 +10,10 @@ cdef extern from "Python.h": PyBUF_C_CONTIGUOUS, PyBUF_F_CONTIGUOUS, PyBUF_ANY_CONTIGUOUS + PyBUF_FORMAT +cdef extern from *: + object __pyx_memoryview_new(object obj, int flags) @cname("__pyx_array") cdef class array: @@ -105,7 +108,12 @@ cdef class array: info.strides = self.strides info.suboffsets = NULL info.itemsize = self.itemsize - info.format = self.format + + if flags & PyBUF_FORMAT: + info.format = self.format + else: + info.format = NULL + # we do not need to call releasebuffer info.obj = None @@ -130,6 +138,15 @@ cdef class array: self.format = NULL self.itemsize = 0 + def __getitem__(self, index): + view = __pyx_memoryview_new(self, PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT) + return view[index] + + def __setitem__(self, index, value): + view = __pyx_memoryview_new(self, PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT) + view[index] = value + + @cname("__pyx_array_new") cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char *mode): return array(shape, itemsize, format, mode.decode('ASCII')) @@ -137,8 +154,10 @@ cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, char * ########## View.MemoryView ########## # from cpython cimport ... -cdef extern from "pythread.h": +cdef extern from "Python.h": + int PyIndex_Check(object) +cdef extern from "pythread.h": ctypedef void *PyThread_type_lock PyThread_type_lock PyThread_allocate_lock() @@ -150,6 +169,12 @@ cdef extern from *: int __Pyx_GetBuffer(object, Py_buffer *, int) void __Pyx_ReleaseBuffer(Py_buffer *) + ctypedef struct {{memviewslice_name}}: + char *data + Py_ssize_t shape[{{max_dims}}] + Py_ssize_t strides[{{max_dims}}] + Py_ssize_t suboffsets[{{max_dims}}] + @cname('__pyx_MemviewEnum') cdef class Enum(object): @@ -173,23 +198,143 @@ cdef class memoryview(object): cdef object obj cdef Py_buffer view - cdef PyThread_type_lock acqcnt_lock + cdef PyThread_type_lock lock cdef int acquisition_count + def __cinit__(memoryview self, object obj, int flags): self.obj = obj - #self.acqcnt_lock = PyThread_allocate_lock() - #if self.acqcnt_lock == NULL: - # raise MemoryError - __Pyx_GetBuffer(obj, &self.view, flags) + self.lock = PyThread_allocate_lock() + if self.lock == NULL: + raise MemoryError + def __dealloc__(memoryview self): - #PyThread_free_lock(self.acqcnt_lock) - self.obj = None __Pyx_ReleaseBuffer(&self.view) + PyThread_free_lock(self.lock) + + @cname('__pyx_memoryview_getitem') + def __getitem__(memoryview self, object index): + # cdef Py_ssize_t idx + cdef char *itemp = <char *> self.view.buf + cdef bytes bytesitem + cdef str fmt = self.view.format + + import struct + try: + itemsize = struct.calcsize(fmt) + except struct.error: + raise TypeError("Unsupported format: %r" % fmt) + + if index is Ellipsis: + return self + + elif isinstance(index, slice): + if index == slice(None): + return self + + raise NotImplementedError + + else: + if not isinstance(index, tuple): + index = (index,) + + tup = _unellipsify(index, self.view.ndim) + + if len(tup) != self.view.ndim: + raise NotImplementedError( + "Expected %d indices (got %d)" % + (self.view.ndim, len(tup))) + + for dim, idx in enumerate(tup): + _check_index(idx) + itemp = pybuffer_index(&self.view, itemp, idx, dim + 1) + + # Do a manual and complete check here instead of this easy hack + bytesitem = itemp[:self.view.itemsize] + return struct.unpack(fmt, bytesitem) + + +@cname('__pyx_memoryviewslice') +cdef class _memoryviewslice(memoryview): + "Internal class for passing memory view slices to Python" + + # We need this to keep our shape/strides/suboffset pointers valid + cdef {{memviewslice_name}} from_slice + # Restore the original Py_buffer before releasing + cdef Py_buffer orig_view + + def __cinit__(self, object obj, int flags): + self.orig_view = self.view + + def __dealloc__(self): + self.view = self.orig_view @cname('__pyx_memoryview_new') -cdef memoryview memoryview_cwrapper(object o, int flags): +cdef memoryview_cwrapper(object o, int flags): return memoryview(o, flags) + +@cname('__pyx_memoryview_fromslice') +cdef memoryview memoryview_from_memview_cwrapper(memoryview m, int flags, + int new_ndim, {{memviewslice_name}} *memviewslice): + cdef _memoryviewslice result = _memoryviewslice(m.obj, flags) + + result.from_slice = memviewslice[0] + + result.view.shape = <Py_ssize_t *> (&result.from_slice.shape + new_ndim) + result.view.strides = <Py_ssize_t *> (&result.from_slice.strides + new_ndim) + result.view.suboffsets = <Py_ssize_t *> (&result.from_slice.suboffsets + new_ndim) + result.view.ndim = new_ndim + + return result + +cdef _check_index(index): + if not PyIndex_Check(index): + raise TypeError("Cannot index with %s" % type(index)) + +cdef tuple _unellipsify(tuple tup, int ndim): + if Ellipsis in tup: + result = [] + for idx, item in enumerate(tup): + if item is Ellipsis: + result.extend([slice(None)] * (ndim - len(tup) + 1)) + result.extend(tup[idx + 1:]) + break + + result.append(item) + + return tuple(result) + + return tup + +@cname('__pyx_pybuffer_index') +cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, int 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 in dimension %d" % dim) + + if index > shape: + raise IndexError("Out of bounds in dimension %d" % dim) + + resultp = bufp + index * stride + + if suboffset >= 0: + resultp = (<char **> resultp)[0] + suboffset + + return resultp |