1 #################### View.MemoryView ####################
3 # This utility provides cython.array and cython.view.memoryview
7 # from cpython cimport ...
8 cdef extern from "Python.h":
9 int PyIndex_Check
"__Pyx_PyIndex_Check" (object)
10 object PyLong_FromVoidPtr
(void *)
12 cdef extern from "pythread.h":
13 ctypedef void *PyThread_type_lock
15 PyThread_type_lock PyThread_allocate_lock
()
16 void PyThread_free_lock
(PyThread_type_lock
)
17 int PyThread_acquire_lock
(PyThread_type_lock
, int mode
) nogil
18 void PyThread_release_lock
(PyThread_type_lock
) nogil
20 cdef extern from "string.h":
21 void *memset
(void *b
, int c
, size_t
len)
24 int __Pyx_GetBuffer
(object, Py_buffer
*, int) except -1
25 void __Pyx_ReleaseBuffer
(Py_buffer
*)
27 ctypedef struct PyObject
28 ctypedef Py_ssize_t Py_intptr_t
29 void Py_INCREF
(PyObject
*)
30 void Py_DECREF
(PyObject
*)
32 void* PyMem_Malloc
(size_t n
)
33 void PyMem_Free
(void *p
)
35 cdef struct __pyx_memoryview
"__pyx_memoryview_obj":
38 __Pyx_TypeInfo
*typeinfo
40 ctypedef struct {{memviewslice_name
}}:
41 __pyx_memoryview
*memview
43 Py_ssize_t shape
[{{max_dims
}}]
44 Py_ssize_t strides
[{{max_dims
}}]
45 Py_ssize_t suboffsets
[{{max_dims
}}]
47 void __PYX_INC_MEMVIEW
({{memviewslice_name
}} *memslice
, int have_gil
)
48 void __PYX_XDEC_MEMVIEW
({{memviewslice_name
}} *memslice
, int have_gil
)
50 ctypedef struct __pyx_buffer
"Py_buffer":
65 ctypedef struct __Pyx_TypeInfo
:
68 cdef object capsule
"__pyx_capsule_create" (void *p
, char *sig
)
69 cdef int __pyx_array_getbuffer
(PyObject
*obj
, Py_buffer view
, int flags
)
70 cdef int __pyx_memoryview_getbuffer
(PyObject
*obj
, Py_buffer view
, int flags
)
73 ctypedef int __pyx_atomic_int
74 {{memviewslice_name
}} slice_copy_contig
"__pyx_memoryview_copy_new_contig"(
75 __Pyx_memviewslice
*from_mvs
,
77 size_t sizeof_dtype
, int contig_flag
,
78 bint dtype_is_object
) nogil
except *
79 bint slice_is_contig
"__pyx_memviewslice_is_contig" (
80 {{memviewslice_name
}} *mvs
, char order
, int ndim
) nogil
81 bint slices_overlap
"__pyx_slices_overlap" ({{memviewslice_name
}} *slice1
,
82 {{memviewslice_name
}} *slice2
,
83 int ndim
, size_t itemsize
) nogil
86 cdef extern from "stdlib.h":
87 void *malloc
(size_t
) nogil
88 void free
(void *) nogil
89 void *memcpy
(void *dest
, void *src
, size_t n
) nogil
95 ### cython.array class
109 unicode mode
# FIXME: this should have been a simple 'char'
111 void (*callback_free_data
)(void *data
)
112 # cdef object _memview
114 cdef bint dtype_is_object
116 def __cinit__
(array
self, tuple shape
, Py_ssize_t itemsize
, format
not None
,
117 mode
="c", bint allocate_buffer
=True
):
120 cdef Py_ssize_t i
, dim
123 self.ndim
= <int> len(shape
)
124 self.itemsize
= itemsize
127 raise ValueError("Empty shape tuple for cython.array")
130 raise ValueError("itemsize <= 0 for cython.array")
132 if isinstance(format
, unicode
):
133 format
= (<unicode
>format
).encode
('ASCII')
134 self._format
= format
# keep a reference to the byte string
135 self.format
= self._format
137 # use single malloc() for both shape and strides
138 self._shape
= <Py_ssize_t
*> PyMem_Malloc
(sizeof(Py_ssize_t
)*self.ndim
*2)
139 self._strides
= self._shape
+ self.ndim
142 raise MemoryError("unable to allocate shape and strides.")
144 # cdef Py_ssize_t dim, stride
145 for idx
, dim
in enumerate
(shape
):
147 raise ValueError("Invalid shape in axis %d: %d." % (idx
, dim
))
148 self._shape
[idx
] = dim
151 if mode
== 'fortran':
153 self.mode
= u
'fortran'
158 raise ValueError("Invalid mode, expected 'c' or 'fortran', got %s" % mode
)
160 self.len = fill_contig_strides_array
(self._shape
, self._strides
,
161 itemsize
, self.ndim
, order
)
163 self.free_data
= allocate_buffer
164 self.dtype_is_object
= format
== b
'O'
166 # use malloc() for backwards compatibility
167 # in case external code wants to change the data pointer
168 self.data
= <char *>malloc
(self.len)
170 raise MemoryError("unable to allocate array data.")
172 if self.dtype_is_object
:
173 p
= <PyObject
**> self.data
174 for i
in range(self.len / itemsize
):
179 def __getbuffer__
(self, Py_buffer
*info
, int flags
):
180 cdef int bufmode
= -1
181 if self.mode
== u
"c":
182 bufmode
= PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS
183 elif self.mode
== u
"fortran":
184 bufmode
= PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS
185 if not (flags
& bufmode
):
186 raise ValueError("Can only create a buffer that is contiguous in memory.")
189 info
.ndim
= self.ndim
190 info
.shape
= self._shape
191 info
.strides
= self._strides
192 info
.suboffsets
= NULL
193 info
.itemsize
= self.itemsize
196 if flags
& PyBUF_FORMAT
:
197 info
.format
= self.format
203 __pyx_getbuffer
= capsule
(<void *> &__pyx_array_getbuffer
, "getbuffer(obj, view, flags)")
205 def __dealloc__
(array
self):
206 if self.callback_free_data
!= NULL
:
207 self.callback_free_data
(self.data
)
209 if self.dtype_is_object
:
210 refcount_objects_in_slice
(self.data
, self._shape
,
211 self._strides
, self.ndim
, False
)
213 PyMem_Free
(self._shape
)
216 @cname
('get_memview')
218 # Make this a property as 'self.data' may be set after instantiation
219 flags
= PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE
220 return memoryview
(self, flags
, self.dtype_is_object
)
223 def __getattr__
(self, attr
):
224 return getattr(self.memview
, attr
)
226 def __getitem__
(self, item
):
227 return self.memview
[item
]
229 def __setitem__
(self, item
, value
):
230 self.memview
[item
] = value
233 @cname
("__pyx_array_new")
234 cdef array array_cwrapper
(tuple shape
, Py_ssize_t itemsize
, char *format
,
235 char *mode
, char *buf
):
239 result
= array
(shape
, itemsize
, format
, mode
.decode
('ASCII'))
241 result
= array
(shape
, itemsize
, format
, mode
.decode
('ASCII'),
242 allocate_buffer
=False
)
249 ### Memoryview constants and cython.view.memoryview class
252 # Disable generic_contiguous, as it makes trouble verifying contiguity:
253 # - 'contiguous' or '::1' means the dimension is contiguous with dtype
254 # - 'indirect_contiguous' means a contiguous list of pointers
255 # - dtype contiguous must be contiguous in the first or last dimension
256 # from the start, or from the dimension following the last indirect dimension
259 # int[::indirect_contiguous, ::contiguous, :]
261 # is valid (list of pointers to 2d fortran-contiguous array), but
263 # int[::generic_contiguous, ::contiguous, :]
265 # would mean you'd have assert dimension 0 to be indirect (and pointer contiguous) at runtime.
266 # So it doesn't bring any performance benefit, and it's only confusing.
268 @cname
('__pyx_MemviewEnum')
269 cdef class Enum
(object):
271 def __init__
(self, name
):
276 cdef generic
= Enum
("<strided and direct or indirect>")
277 cdef strided
= Enum
("<strided and direct>") # default
278 cdef indirect
= Enum
("<strided and indirect>")
279 # Disable generic_contiguous, as it is a troublemaker
280 #cdef generic_contiguous = Enum("<contiguous and direct or indirect>")
281 cdef contiguous
= Enum
("<contiguous and direct>")
282 cdef indirect_contiguous
= Enum
("<contiguous and indirect>")
284 # 'follow' is implied when the first or last axis is ::1
287 @cname
('__pyx_align_pointer')
288 cdef void *align_pointer
(void *memory
, size_t alignment
) nogil
:
289 "Align pointer memory on a given boundary"
290 cdef Py_intptr_t aligned_p
= <Py_intptr_t
> memory
293 with cython
.cdivision
(True
):
294 offset
= aligned_p
% alignment
297 aligned_p
+= alignment
- offset
299 return <void *> aligned_p
301 @cname
('__pyx_memoryview')
302 cdef class memoryview
(object):
306 cdef object _array_interface
307 cdef PyThread_type_lock lock
308 # the following array will contain a single __pyx_atomic int with
310 cdef __pyx_atomic_int acquisition_count
[2]
311 cdef __pyx_atomic_int
*acquisition_count_aligned_p
314 cdef bint dtype_is_object
315 cdef __Pyx_TypeInfo
*typeinfo
317 def __cinit__
(memoryview
self, object obj
, int flags
, bint dtype_is_object
=False
):
320 if type(self) is memoryview
or obj
is not None
:
321 __Pyx_GetBuffer
(obj
, &self.view
, flags
)
322 if <PyObject
*> self.view
.obj
== NULL
:
323 (<__pyx_buffer
*> &self.view
).obj
= Py_None
326 self.lock
= PyThread_allocate_lock
()
327 if self.lock
== NULL
:
330 if flags
& PyBUF_FORMAT
:
331 self.dtype_is_object
= self.view
.format
== b
'O'
333 self.dtype_is_object
= dtype_is_object
335 self.acquisition_count_aligned_p
= <__pyx_atomic_int
*> align_pointer
(
336 <void *> &self.acquisition_count
[0], sizeof(__pyx_atomic_int
))
339 def __dealloc__
(memoryview
self):
340 if self.obj
is not None
:
341 __Pyx_ReleaseBuffer
(&self.view
)
343 if self.lock
!= NULL
:
344 PyThread_free_lock
(self.lock
)
346 cdef char *get_item_pointer
(memoryview
self, object index
) except NULL
:
348 cdef char *itemp
= <char *> self.view
.buf
350 for dim
, idx
in enumerate
(index
):
351 itemp
= pybuffer_index
(&self.view
, itemp
, idx
, dim
)
355 #@cname('__pyx_memoryview_getitem')
356 def __getitem__
(memoryview
self, object index
):
357 if index
is Ellipsis
:
360 have_slices
, indices
= _unellipsify
(index
, self.view
.ndim
)
364 return memview_slice
(self, indices
)
366 itemp
= self.get_item_pointer
(indices
)
367 return self.convert_item_to_object
(itemp
)
369 def __setitem__
(memoryview
self, object index
, object value
):
370 have_slices
, index
= _unellipsify
(index
, self.view
.ndim
)
373 obj
= self.is_slice
(value
)
375 self.setitem_slice_assignment
(self[index
], obj
)
377 self.setitem_slice_assign_scalar
(self[index
], value
)
379 self.setitem_indexed
(index
, value
)
381 cdef is_slice
(self, obj
):
382 if not isinstance(obj
, memoryview
):
384 obj
= memoryview
(obj
, self.flags|PyBUF_ANY_CONTIGUOUS
,
385 self.dtype_is_object
)
391 cdef setitem_slice_assignment
(self, dst
, src
):
392 cdef {{memviewslice_name
}} dst_slice
393 cdef {{memviewslice_name
}} src_slice
395 memoryview_copy_contents
(get_slice_from_memview
(src
, &src_slice
)[0],
396 get_slice_from_memview
(dst
, &dst_slice
)[0],
397 src
.ndim
, dst
.ndim
, self.dtype_is_object
)
399 cdef setitem_slice_assign_scalar
(self, memoryview dst
, value
):
401 cdef void *tmp
= NULL
404 cdef {{memviewslice_name
}} *dst_slice
405 cdef {{memviewslice_name
}} tmp_slice
406 dst_slice
= get_slice_from_memview
(dst
, &tmp_slice
)
408 if <size_t
>self.view
.itemsize
> sizeof(array
):
409 tmp
= PyMem_Malloc
(self.view
.itemsize
)
414 item
= <void *> array
417 if self.dtype_is_object
:
418 (<PyObject
**> item
)[0] = <PyObject
*> value
420 self.assign_item_from_object
(<char *> item
, value
)
422 # It would be easy to support indirect dimensions, but it's easier
424 if self.view
.suboffsets
!= NULL
:
425 assert_direct_dimensions
(self.view
.suboffsets
, self.view
.ndim
)
426 slice_assign_scalar
(dst_slice
, dst
.view
.ndim
, self.view
.itemsize
,
427 item
, self.dtype_is_object
)
431 cdef setitem_indexed
(self, index
, value
):
432 cdef char *itemp
= self.get_item_pointer
(index
)
433 self.assign_item_from_object
(itemp
, value
)
435 cdef convert_item_to_object
(self, char *itemp
):
436 """Only used if instantiated manually by the user, or if Cython doesn't
437 know how to convert the type"""
440 # Do a manual and complete check here instead of this easy hack
441 bytesitem
= itemp
[:self.view
.itemsize
]
443 result
= struct.unpack
(self.view
.format
, bytesitem
)
445 raise ValueError("Unable to convert item to object")
447 if len(self.view
.format
) == 1:
451 cdef assign_item_from_object
(self, char *itemp
, object value
):
452 """Only used if instantiated manually by the user, or if Cython doesn't
453 know how to convert the type"""
456 cdef bytes bytesvalue
459 if isinstance(value
, tuple):
460 bytesvalue
= struct.pack
(self.view
.format
, *value
)
462 bytesvalue
= struct.pack
(self.view
.format
, value
)
464 for i
, c
in enumerate
(bytesvalue
):
468 def __getbuffer__
(self, Py_buffer
*info
, int flags
):
469 if flags
& PyBUF_STRIDES
:
470 info
.shape
= self.view
.shape
474 if flags
& PyBUF_STRIDES
:
475 info
.strides
= self.view
.strides
479 if flags
& PyBUF_INDIRECT
:
480 info
.suboffsets
= self.view
.suboffsets
482 info
.suboffsets
= NULL
484 if flags
& PyBUF_FORMAT
:
485 info
.format
= self.view
.format
489 info
.buf
= self.view
.buf
490 info
.ndim
= self.view
.ndim
491 info
.itemsize
= self.view
.itemsize
492 info
.len = self.view
.len
496 __pyx_getbuffer
= capsule
(<void *> &__pyx_memoryview_getbuffer
, "getbuffer(obj, view, flags)")
498 # Some properties that have the same sematics as in NumPy
500 @cname
('__pyx_memoryview_transpose')
502 cdef _memoryviewslice result
= memoryview_copy
(self)
503 transpose_memslice
(&result
.from_slice
)
507 @cname
('__pyx_memoryview__get__base')
512 @cname
('__pyx_memoryview_get_shape')
514 return tuple([self.view
.shape
[i
] for i
in xrange(self.view
.ndim
)])
517 @cname
('__pyx_memoryview_get_strides')
519 if self.view
.strides
== NULL
:
520 # Note: we always ask for strides, so if this is not set it's a bug
521 raise ValueError("Buffer view does not expose strides")
523 return tuple([self.view
.strides
[i
] for i
in xrange(self.view
.ndim
)])
526 @cname
('__pyx_memoryview_get_suboffsets')
528 if self.view
.suboffsets
== NULL
:
529 return [-1] * self.view
.ndim
531 return tuple([self.view
.suboffsets
[i
] for i
in xrange(self.view
.ndim
)])
534 @cname
('__pyx_memoryview_get_ndim')
536 return self.view
.ndim
539 @cname
('__pyx_memoryview_get_itemsize')
541 return self.view
.itemsize
544 @cname
('__pyx_memoryview_get_nbytes')
546 return self.size
* self.view
.itemsize
549 @cname
('__pyx_memoryview_get_size')
551 if self._size
is None
:
554 for length
in self.shape
:
562 if self.view
.ndim
>= 1:
563 return self.view
.shape
[0]
568 return "<MemoryView of %r at 0x%x>" % (self.base
.__class__
.__name__
,
572 return "<MemoryView of %r object>" % (self.base
.__class__
.__name__
,)
574 # Support the same attributes as memoryview slices
575 def is_c_contig
(self):
576 cdef {{memviewslice_name
}} *mslice
577 cdef {{memviewslice_name
}} tmp
578 mslice
= get_slice_from_memview
(self, &tmp
)
579 return slice_is_contig
(mslice
, 'C', self.view
.ndim
)
581 def is_f_contig
(self):
582 cdef {{memviewslice_name
}} *mslice
583 cdef {{memviewslice_name
}} tmp
584 mslice
= get_slice_from_memview
(self, &tmp
)
585 return slice_is_contig
(mslice
, 'F', self.view
.ndim
)
588 cdef {{memviewslice_name
}} mslice
589 cdef int flags
= self.flags
& ~PyBUF_F_CONTIGUOUS
591 slice_copy
(self, &mslice
)
592 mslice
= slice_copy_contig
(&mslice
, "c", self.view
.ndim
,
594 flags|PyBUF_C_CONTIGUOUS
,
595 self.dtype_is_object
)
597 return memoryview_copy_from_slice
(self, &mslice
)
599 def copy_fortran
(self):
600 cdef {{memviewslice_name
}} src
, dst
601 cdef int flags
= self.flags
& ~PyBUF_C_CONTIGUOUS
603 slice_copy
(self, &src
)
604 dst
= slice_copy_contig
(&src
, "fortran", self.view
.ndim
,
606 flags|PyBUF_F_CONTIGUOUS
,
607 self.dtype_is_object
)
609 return memoryview_copy_from_slice
(self, &dst
)
612 @cname
('__pyx_memoryview_new')
613 cdef memoryview_cwrapper
(object o
, int flags
, bint dtype_is_object
, __Pyx_TypeInfo
*typeinfo
):
614 cdef memoryview result
= memoryview
(o
, flags
, dtype_is_object
)
615 result
.typeinfo
= typeinfo
618 @cname
('__pyx_memoryview_check')
619 cdef inline bint memoryview_check
(object o
):
620 return isinstance(o
, memoryview
)
622 cdef tuple _unellipsify
(object index
, int ndim
):
624 Replace all ellipses with full slices and fill incomplete indices with
627 if not isinstance(index
, tuple):
634 seen_ellipsis
= False
635 for idx
, item
in enumerate
(tup
):
637 if not seen_ellipsis
:
638 result
.extend
([slice(None
)] * (ndim
- len(tup
) + 1))
641 result
.append
(slice(None
))
644 if not isinstance(item
, slice) and not PyIndex_Check
(item
):
645 raise TypeError("Cannot index with type '%s'" % type(item
))
647 have_slices
= have_slices
or isinstance(item
, slice)
650 nslices
= ndim
- len(result
)
652 result
.extend
([slice(None
)] * nslices
)
654 return have_slices
or nslices
, tuple(result
)
656 cdef assert_direct_dimensions
(Py_ssize_t
*suboffsets
, int ndim
):
658 for i
in range(ndim
):
659 if suboffsets
[i
] >= 0:
660 raise ValueError("Indirect dimensions not supported")
663 ### Slicing a memoryview
666 @cname
('__pyx_memview_slice')
667 cdef memoryview memview_slice
(memoryview memview
, object indices
):
668 cdef int new_ndim
= 0, suboffset_dim
= -1, dim
669 cdef bint negative_step
670 cdef {{memviewslice_name
}} src
, dst
671 cdef {{memviewslice_name
}} *p_src
673 # dst is copied by value in memoryview_fromslice -- initialize it
674 # src is never copied
675 memset
(&dst
, 0, sizeof(dst
))
677 cdef _memoryviewslice memviewsliceobj
679 assert memview
.view
.ndim
> 0
681 if isinstance(memview
, _memoryviewslice
):
682 memviewsliceobj
= memview
683 p_src
= &memviewsliceobj
.from_slice
685 slice_copy
(memview
, &src
)
688 # Note: don't use variable src at this point
689 # SubNote: we should be able to declare variables in blocks...
691 # memoryview_fromslice() will inc our dst slice
692 dst
.memview
= p_src
.memview
693 dst
.data
= p_src
.data
695 # Put everything in temps to avoid this bloody warning:
696 # "Argument evaluation order in C function call is undefined and
697 # may not be as expected"
698 cdef {{memviewslice_name
}} *p_dst
= &dst
699 cdef int *p_suboffset_dim
= &suboffset_dim
700 cdef Py_ssize_t start
, stop
, step
701 cdef bint have_start
, have_stop
, have_step
703 for dim
, index
in enumerate
(indices
):
704 if PyIndex_Check
(index
):
706 p_dst
, p_src
.shape
[dim
], p_src
.strides
[dim
], p_src
.suboffsets
[dim
],
707 dim
, new_ndim
, p_suboffset_dim
,
708 index
, 0, 0, # start, stop, step
709 0, 0, 0, # have_{start,stop,step}
712 p_dst
.shape
[new_ndim
] = 1
713 p_dst
.strides
[new_ndim
] = 0
714 p_dst
.suboffsets
[new_ndim
] = -1
717 start
= index
.start
or 0
718 stop
= index
.stop
or 0
719 step
= index
.step
or 0
721 have_start
= index
.start
is not None
722 have_stop
= index
.stop
is not None
723 have_step
= index
.step
is not None
726 p_dst
, p_src
.shape
[dim
], p_src
.strides
[dim
], p_src
.suboffsets
[dim
],
727 dim
, new_ndim
, p_suboffset_dim
,
729 have_start
, have_stop
, have_step
,
733 if isinstance(memview
, _memoryviewslice
):
734 return memoryview_fromslice
(dst
, new_ndim
,
735 memviewsliceobj
.to_object_func
,
736 memviewsliceobj
.to_dtype_func
,
737 memview
.dtype_is_object
)
739 return memoryview_fromslice
(dst
, new_ndim
, NULL
, NULL
,
740 memview
.dtype_is_object
)
744 ### Slicing in a single dimension of a memoryviewslice
747 cdef extern from "stdlib.h":
749 void printf
(char *s
, ...) nogil
751 cdef extern from "stdio.h":
754 int fputs
(char *s
, FILE
*stream
)
756 cdef extern from "pystate.h":
757 void PyThreadState_Get
() nogil
759 # These are not actually nogil, but we check for the GIL before calling them
760 void PyErr_SetString
(PyObject
*type, char *msg
) nogil
761 PyObject
*PyErr_Format
(PyObject
*exc
, char *msg
, ...) nogil
763 @cname
('__pyx_memoryview_slice_memviewslice')
764 cdef int slice_memviewslice
(
765 {{memviewslice_name
}} *dst
,
766 Py_ssize_t shape
, Py_ssize_t stride
, Py_ssize_t suboffset
,
767 int dim
, int new_ndim
, int *suboffset_dim
,
768 Py_ssize_t start
, Py_ssize_t stop
, Py_ssize_t step
,
769 int have_start
, int have_stop
, int have_step
,
770 bint is_slice
) nogil
except -1:
772 Create a new slice dst given slice src.
774 dim - the current src dimension (indexing will make dimensions
776 new_dim - the new dst dimension
777 suboffset_dim - pointer to a single int initialized to -1 to keep track of
778 where slicing offsets should be added
781 cdef Py_ssize_t new_shape
782 cdef bint negative_step
785 # index is a normal integer-like index
788 if not 0 <= start
< shape
:
789 _err_dim
(IndexError, "Index out of bounds (axis %d)", dim
)
792 negative_step
= have_step
!= 0 and step
< 0
794 if have_step
and step
== 0:
795 _err_dim
(ValueError, "Step may not be zero (axis %d)", dim
)
797 # check our bounds and set defaults
830 # len = ceil( (stop - start) / step )
831 with cython
.cdivision
(True
):
832 new_shape
= (stop
- start
) // step
834 if (stop
- start
) - step
* new_shape
:
840 # shape/strides/suboffsets
841 dst
.strides
[new_ndim
] = stride
* step
842 dst
.shape
[new_ndim
] = new_shape
843 dst
.suboffsets
[new_ndim
] = suboffset
845 # Add the slicing or idexing offsets to the right suboffset or base data *
846 if suboffset_dim
[0] < 0:
847 dst
.data
+= start
* stride
849 dst
.suboffsets
[suboffset_dim
[0]] += start
* stride
854 dst
.data
= (<char **> dst
.data
)[0] + suboffset
856 _err_dim
(IndexError, "All dimensions preceding dimension %d "
857 "must be indexed and not sliced", dim
)
859 suboffset_dim
[0] = new_ndim
864 ### Index a memoryview
866 @cname
('__pyx_pybuffer_index')
867 cdef char *pybuffer_index
(Py_buffer
*view
, char *bufp
, Py_ssize_t index
,
868 Py_ssize_t dim
) except NULL
:
869 cdef Py_ssize_t shape
, stride
, suboffset
= -1
870 cdef Py_ssize_t itemsize
= view
.itemsize
874 shape
= view
.len / itemsize
877 shape
= view
.shape
[dim
]
878 stride
= view
.strides
[dim
]
879 if view
.suboffsets
!= NULL
:
880 suboffset
= view
.suboffsets
[dim
]
883 index
+= view
.shape
[dim
]
885 raise IndexError("Out of bounds on buffer access (axis %d)" % dim
)
888 raise IndexError("Out of bounds on buffer access (axis %d)" % dim
)
890 resultp
= bufp
+ index
* stride
892 resultp
= (<char **> resultp
)[0] + suboffset
897 ### Transposing a memoryviewslice
899 @cname
('__pyx_memslice_transpose')
900 cdef int transpose_memslice
({{memviewslice_name
}} *memslice
) nogil
except 0:
901 cdef int ndim
= memslice
.memview
.view
.ndim
903 cdef Py_ssize_t
*shape
= memslice
.shape
904 cdef Py_ssize_t
*strides
= memslice
.strides
906 # reverse strides and shape
908 for i
in range(ndim
/ 2):
910 strides
[i
], strides
[j
] = strides
[j
], strides
[i
]
911 shape
[i
], shape
[j
] = shape
[j
], shape
[i
]
913 if memslice
.suboffsets
[i
] >= 0 or memslice
.suboffsets
[j
] >= 0:
914 _err
(ValueError, "Cannot transpose memoryview with indirect dimensions")
919 ### Creating new memoryview objects from slices and memoryviews
921 @cname
('__pyx_memoryviewslice')
922 cdef class _memoryviewslice
(memoryview
):
923 "Internal class for passing memoryview slices to Python"
925 # We need this to keep our shape/strides/suboffset pointers valid
926 cdef {{memviewslice_name
}} from_slice
927 # We need this only to print it's class' name
928 cdef object from_object
930 cdef object (*to_object_func
)(char *)
931 cdef int (*to_dtype_func
)(char *, object) except 0
933 def __dealloc__
(self):
934 __PYX_XDEC_MEMVIEW
(&self.from_slice
, 1)
936 cdef convert_item_to_object
(self, char *itemp
):
937 if self.to_object_func
!= NULL
:
938 return self.to_object_func
(itemp
)
940 return memoryview
.convert_item_to_object
(self, itemp
)
942 cdef assign_item_from_object
(self, char *itemp
, object value
):
943 if self.to_dtype_func
!= NULL
:
944 self.to_dtype_func
(itemp
, value
)
946 memoryview
.assign_item_from_object
(self, itemp
, value
)
949 @cname
('__pyx_memoryviewslice__get__base')
951 return self.from_object
953 __pyx_getbuffer
= capsule
(<void *> &__pyx_memoryview_getbuffer
, "getbuffer(obj, view, flags)")
956 @cname
('__pyx_memoryview_fromslice')
957 cdef memoryview_fromslice
({{memviewslice_name
}} memviewslice
,
959 object (*to_object_func
)(char *),
960 int (*to_dtype_func
)(char *, object) except 0,
961 bint dtype_is_object
):
963 cdef _memoryviewslice result
966 if <PyObject
*> memviewslice
.memview
== Py_None
:
969 # assert 0 < ndim <= memviewslice.memview.view.ndim, (
970 # ndim, memviewslice.memview.view.ndim)
972 result
= _memoryviewslice
(None
, 0, dtype_is_object
)
974 result
.from_slice
= memviewslice
975 __PYX_INC_MEMVIEW
(&memviewslice
, 1)
977 result
.from_object
= (<memoryview
> memviewslice
.memview
).base
978 result
.typeinfo
= memviewslice
.memview
.typeinfo
980 result
.view
= memviewslice
.memview
.view
981 result
.view
.buf
= <void *> memviewslice
.data
982 result
.view
.ndim
= ndim
983 (<__pyx_buffer
*> &result
.view
).obj
= Py_None
986 result
.flags
= PyBUF_RECORDS
988 result
.view
.shape
= <Py_ssize_t
*> result
.from_slice
.shape
989 result
.view
.strides
= <Py_ssize_t
*> result
.from_slice
.strides
990 result
.view
.suboffsets
= <Py_ssize_t
*> result
.from_slice
.suboffsets
992 result
.view
.len = result
.view
.itemsize
993 for i
in range(ndim
):
994 result
.view
.len *= result
.view
.shape
[i
]
996 result
.to_object_func
= to_object_func
997 result
.to_dtype_func
= to_dtype_func
1001 @cname
('__pyx_memoryview_get_slice_from_memoryview')
1002 cdef {{memviewslice_name
}} *get_slice_from_memview
(memoryview memview
,
1003 {{memviewslice_name
}} *mslice
):
1004 cdef _memoryviewslice obj
1005 if isinstance(memview
, _memoryviewslice
):
1007 return &obj
.from_slice
1009 slice_copy
(memview
, mslice
)
1012 @cname
('__pyx_memoryview_slice_copy')
1013 cdef void slice_copy
(memoryview memview
, {{memviewslice_name
}} *dst
):
1015 cdef (Py_ssize_t
*) shape
, strides
, suboffsets
1017 shape
= memview
.view
.shape
1018 strides
= memview
.view
.strides
1019 suboffsets
= memview
.view
.suboffsets
1021 dst
.memview
= <__pyx_memoryview
*> memview
1022 dst
.data
= <char *> memview
.view
.buf
1024 for dim
in range(memview
.view
.ndim
):
1025 dst
.shape
[dim
] = shape
[dim
]
1026 dst
.strides
[dim
] = strides
[dim
]
1027 if suboffsets
== NULL
:
1028 dst
.suboffsets
[dim
] = -1
1030 dst
.suboffsets
[dim
] = suboffsets
[dim
]
1032 @cname
('__pyx_memoryview_copy_object')
1033 cdef memoryview_copy
(memoryview memview
):
1034 "Create a new memoryview object"
1035 cdef {{memviewslice_name
}} memviewslice
1036 slice_copy
(memview
, &memviewslice
)
1037 return memoryview_copy_from_slice
(memview
, &memviewslice
)
1039 @cname
('__pyx_memoryview_copy_object_from_slice')
1040 cdef memoryview_copy_from_slice
(memoryview memview
, {{memviewslice_name
}} *memviewslice
):
1042 Create a new memoryview object from a given memoryview object and slice.
1044 cdef object (*to_object_func
)(char *)
1045 cdef int (*to_dtype_func
)(char *, object) except 0
1047 if isinstance(memview
, _memoryviewslice
):
1048 to_object_func
= (<_memoryviewslice
> memview
).to_object_func
1049 to_dtype_func
= (<_memoryviewslice
> memview
).to_dtype_func
1051 to_object_func
= NULL
1052 to_dtype_func
= NULL
1054 return memoryview_fromslice
(memviewslice
[0], memview
.view
.ndim
,
1055 to_object_func
, to_dtype_func
,
1056 memview
.dtype_is_object
)
1060 ### Copy the contents of a memoryview slices
1062 cdef Py_ssize_t abs_py_ssize_t
(Py_ssize_t arg
) nogil
:
1068 @cname
('__pyx_get_best_slice_order')
1069 cdef char get_best_order
({{memviewslice_name
}} *mslice
, int ndim
) nogil
:
1071 Figure out the best memory access order for a given slice.
1074 cdef Py_ssize_t c_stride
= 0
1075 cdef Py_ssize_t f_stride
= 0
1077 for i
in range(ndim
- 1, -1, -1):
1078 if mslice
.shape
[i
] > 1:
1079 c_stride
= mslice
.strides
[i
]
1082 for i
in range(ndim
):
1083 if mslice
.shape
[i
] > 1:
1084 f_stride
= mslice
.strides
[i
]
1087 if abs_py_ssize_t
(c_stride
) <= abs_py_ssize_t
(f_stride
):
1092 @cython
.cdivision
(True
)
1093 cdef void _copy_strided_to_strided
(char *src_data
, Py_ssize_t
*src_strides
,
1094 char *dst_data
, Py_ssize_t
*dst_strides
,
1095 Py_ssize_t
*src_shape
, Py_ssize_t
*dst_shape
,
1096 int ndim
, size_t itemsize
) nogil
:
1097 # Note: src_extent is 1 if we're broadcasting
1098 # dst_extent always >= src_extent as we don't do reductions
1100 cdef Py_ssize_t src_extent
= src_shape
[0]
1101 cdef Py_ssize_t dst_extent
= dst_shape
[0]
1102 cdef Py_ssize_t src_stride
= src_strides
[0]
1103 cdef Py_ssize_t dst_stride
= dst_strides
[0]
1106 if (src_stride
> 0 and dst_stride
> 0 and
1107 <size_t
> src_stride
== itemsize
== <size_t
> dst_stride
):
1108 memcpy
(dst_data
, src_data
, itemsize
* dst_extent
)
1110 for i
in range(dst_extent
):
1111 memcpy
(dst_data
, src_data
, itemsize
)
1112 src_data
+= src_stride
1113 dst_data
+= dst_stride
1115 for i
in range(dst_extent
):
1116 _copy_strided_to_strided
(src_data
, src_strides
+ 1,
1117 dst_data
, dst_strides
+ 1,
1118 src_shape
+ 1, dst_shape
+ 1,
1120 src_data
+= src_stride
1121 dst_data
+= dst_stride
1123 cdef void copy_strided_to_strided
({{memviewslice_name
}} *src
,
1124 {{memviewslice_name
}} *dst
,
1125 int ndim
, size_t itemsize
) nogil
:
1126 _copy_strided_to_strided
(src
.data
, src
.strides
, dst
.data
, dst
.strides
,
1127 src
.shape
, dst
.shape
, ndim
, itemsize
)
1129 @cname
('__pyx_memoryview_slice_get_size')
1130 cdef Py_ssize_t slice_get_size
({{memviewslice_name
}} *src
, int ndim
) nogil
:
1131 "Return the size of the memory occupied by the slice in number of bytes"
1133 cdef Py_ssize_t size
= src
.memview
.view
.itemsize
1135 for i
in range(ndim
):
1136 size
*= src
.shape
[i
]
1140 @cname
('__pyx_fill_contig_strides_array')
1141 cdef Py_ssize_t fill_contig_strides_array
(
1142 Py_ssize_t
*shape
, Py_ssize_t
*strides
, Py_ssize_t stride
,
1143 int ndim
, char order
) nogil
:
1145 Fill the strides array for a slice with C or F contiguous strides.
1146 This is like PyBuffer_FillContiguousStrides, but compatible with py < 2.6
1151 for idx
in range(ndim
):
1152 strides
[idx
] = stride
1153 stride
= stride
* shape
[idx
]
1155 for idx
in range(ndim
- 1, -1, -1):
1156 strides
[idx
] = stride
1157 stride
= stride
* shape
[idx
]
1161 @cname
('__pyx_memoryview_copy_data_to_temp')
1162 cdef void *copy_data_to_temp
({{memviewslice_name
}} *src
,
1163 {{memviewslice_name
}} *tmpslice
,
1165 int ndim
) nogil
except NULL
:
1167 Copy a direct slice to temporary contiguous memory. The caller should free
1168 the result when done.
1173 cdef size_t itemsize
= src
.memview
.view
.itemsize
1174 cdef size_t size
= slice_get_size
(src
, ndim
)
1176 result
= malloc
(size
)
1178 _err
(MemoryError, NULL
)
1181 tmpslice
.data
= <char *> result
1182 tmpslice
.memview
= src
.memview
1183 for i
in range(ndim
):
1184 tmpslice
.shape
[i
] = src
.shape
[i
]
1185 tmpslice
.suboffsets
[i
] = -1
1187 fill_contig_strides_array
(&tmpslice
.shape
[0], &tmpslice
.strides
[0], itemsize
,
1190 # We need to broadcast strides again
1191 for i
in range(ndim
):
1192 if tmpslice
.shape
[i
] == 1:
1193 tmpslice
.strides
[i
] = 0
1195 if slice_is_contig
(src
, order
, ndim
):
1196 memcpy
(result
, src
.data
, size
)
1198 copy_strided_to_strided
(src
, tmpslice
, ndim
, itemsize
)
1202 # Use 'with gil' functions and avoid 'with gil' blocks, as the code within the blocks
1203 # has temporaries that need the GIL to clean up
1204 @cname
('__pyx_memoryview_err_extents')
1205 cdef int _err_extents
(int i
, Py_ssize_t extent1
,
1206 Py_ssize_t extent2
) except -1 with gil
:
1207 raise ValueError("got differing extents in dimension %d (got %d and %d)" %
1208 (i
, extent1
, extent2
))
1210 @cname
('__pyx_memoryview_err_dim')
1211 cdef int _err_dim
(object error
, char *msg
, int dim
) except -1 with gil
:
1212 raise error
(msg
.decode
('ascii') % dim
)
1214 @cname
('__pyx_memoryview_err')
1215 cdef int _err
(object error
, char *msg
) except -1 with gil
:
1217 raise error
(msg
.decode
('ascii'))
1221 @cname
('__pyx_memoryview_copy_contents')
1222 cdef int memoryview_copy_contents
({{memviewslice_name
}} src
,
1223 {{memviewslice_name
}} dst
,
1224 int src_ndim
, int dst_ndim
,
1225 bint dtype_is_object
) nogil
except -1:
1227 Copy memory from slice src to slice dst.
1228 Check for overlapping memory and verify the shapes.
1230 cdef void *tmpdata
= NULL
1231 cdef size_t itemsize
= src
.memview
.view
.itemsize
1233 cdef char order
= get_best_order
(&src
, src_ndim
)
1234 cdef bint broadcasting
= False
1235 cdef bint direct_copy
= False
1236 cdef {{memviewslice_name
}} tmp
1238 if src_ndim
< dst_ndim
:
1239 broadcast_leading
(&src
, src_ndim
, dst_ndim
)
1240 elif dst_ndim
< src_ndim
:
1241 broadcast_leading
(&dst
, dst_ndim
, src_ndim
)
1243 cdef int ndim
= max(src_ndim
, dst_ndim
)
1245 for i
in range(ndim
):
1246 if src
.shape
[i
] != dst
.shape
[i
]:
1247 if src
.shape
[i
] == 1:
1251 _err_extents
(i
, dst
.shape
[i
], src
.shape
[i
])
1253 if src
.suboffsets
[i
] >= 0:
1254 _err_dim
(ValueError, "Dimension %d is not direct", i
)
1256 if slices_overlap
(&src
, &dst
, ndim
, itemsize
):
1257 # slices overlap, copy to temp, copy temp to dst
1258 if not slice_is_contig
(&src
, order
, ndim
):
1259 order
= get_best_order
(&dst
, ndim
)
1261 tmpdata
= copy_data_to_temp
(&src
, &tmp
, order
, ndim
)
1264 if not broadcasting
:
1265 # See if both slices have equal contiguity, in that case perform a
1266 # direct copy. This only works when we are not broadcasting.
1267 if slice_is_contig
(&src
, 'C', ndim
):
1268 direct_copy
= slice_is_contig
(&dst
, 'C', ndim
)
1269 elif slice_is_contig
(&src
, 'F', ndim
):
1270 direct_copy
= slice_is_contig
(&dst
, 'F', ndim
)
1273 # Contiguous slices with same order
1274 refcount_copying
(&dst
, dtype_is_object
, ndim
, False
)
1275 memcpy
(dst
.data
, src
.data
, slice_get_size
(&src
, ndim
))
1276 refcount_copying
(&dst
, dtype_is_object
, ndim
, True
)
1280 if order
== 'F' == get_best_order
(&dst
, ndim
):
1281 # see if both slices have Fortran order, transpose them to match our
1282 # C-style indexing order
1283 transpose_memslice
(&src
)
1284 transpose_memslice
(&dst
)
1286 refcount_copying
(&dst
, dtype_is_object
, ndim
, False
)
1287 copy_strided_to_strided
(&src
, &dst
, ndim
, itemsize
)
1288 refcount_copying
(&dst
, dtype_is_object
, ndim
, True
)
1293 @cname
('__pyx_memoryview_broadcast_leading')
1294 cdef void broadcast_leading
({{memviewslice_name
}} *slice,
1296 int ndim_other
) nogil
:
1298 cdef int offset
= ndim_other
- ndim
1300 for i
in range(ndim
- 1, -1, -1):
1301 slice.shape
[i
+ offset
] = slice.shape
[i
]
1302 slice.strides
[i
+ offset
] = slice.strides
[i
]
1303 slice.suboffsets
[i
+ offset
] = slice.suboffsets
[i
]
1305 for i
in range(offset
):
1307 slice.strides
[i
] = slice.strides
[0]
1308 slice.suboffsets
[i
] = -1
1311 ### Take care of refcounting the objects in slices. Do this seperately from any copying,
1312 ### to minimize acquiring the GIL
1315 @cname
('__pyx_memoryview_refcount_copying')
1316 cdef void refcount_copying
({{memviewslice_name
}} *dst
, bint dtype_is_object
,
1317 int ndim
, bint inc
) nogil
:
1318 # incref or decref the objects in the destination slice if the dtype is
1321 refcount_objects_in_slice_with_gil
(dst
.data
, dst
.shape
,
1322 dst
.strides
, ndim
, inc
)
1324 @cname
('__pyx_memoryview_refcount_objects_in_slice_with_gil')
1325 cdef void refcount_objects_in_slice_with_gil
(char *data
, Py_ssize_t
*shape
,
1326 Py_ssize_t
*strides
, int ndim
,
1328 refcount_objects_in_slice
(data
, shape
, strides
, ndim
, inc
)
1330 @cname
('__pyx_memoryview_refcount_objects_in_slice')
1331 cdef void refcount_objects_in_slice
(char *data
, Py_ssize_t
*shape
,
1332 Py_ssize_t
*strides
, int ndim
, bint inc
):
1335 for i
in range(shape
[0]):
1338 Py_INCREF
((<PyObject
**> data
)[0])
1340 Py_DECREF
((<PyObject
**> data
)[0])
1342 refcount_objects_in_slice
(data
, shape
+ 1, strides
+ 1,
1348 ### Scalar to slice assignment
1350 @cname
('__pyx_memoryview_slice_assign_scalar')
1351 cdef void slice_assign_scalar
({{memviewslice_name
}} *dst
, int ndim
,
1352 size_t itemsize
, void *item
,
1353 bint dtype_is_object
) nogil
:
1354 refcount_copying
(dst
, dtype_is_object
, ndim
, False
)
1355 _slice_assign_scalar
(dst
.data
, dst
.shape
, dst
.strides
, ndim
,
1357 refcount_copying
(dst
, dtype_is_object
, ndim
, True
)
1360 @cname
('__pyx_memoryview__slice_assign_scalar')
1361 cdef void _slice_assign_scalar
(char *data
, Py_ssize_t
*shape
,
1362 Py_ssize_t
*strides
, int ndim
,
1363 size_t itemsize
, void *item
) nogil
:
1365 cdef Py_ssize_t stride
= strides
[0]
1366 cdef Py_ssize_t extent
= shape
[0]
1369 for i
in range(extent
):
1370 memcpy
(data
, item
, itemsize
)
1373 for i
in range(extent
):
1374 _slice_assign_scalar
(data
, shape
+ 1, strides
+ 1,
1375 ndim
- 1, itemsize
, item
)
1379 ############### BufferFormatFromTypeInfo ###############
1381 ctypedef struct __Pyx_StructField
1384 __PYX_BUF_FLAGS_PACKED_STRUCT
1385 __PYX_BUF_FLAGS_INTEGER_COMPLEX
1387 ctypedef struct __Pyx_TypeInfo
:
1389 __Pyx_StructField
* fields
1397 ctypedef struct __Pyx_StructField
:
1398 __Pyx_TypeInfo
* type
1402 ctypedef struct __Pyx_BufFmt_StackElem
:
1403 __Pyx_StructField
* field
1404 size_t parent_offset
1406 #ctypedef struct __Pyx_BufFmt_Context:
1407 # __Pyx_StructField root
1408 __Pyx_BufFmt_StackElem
* head
1410 struct __pyx_typeinfo_string
:
1413 __pyx_typeinfo_string __Pyx_TypeInfoToFormat
(__Pyx_TypeInfo
*)
1416 @cname
('__pyx_format_from_typeinfo')
1417 cdef bytes format_from_typeinfo
(__Pyx_TypeInfo
*type):
1418 cdef __Pyx_StructField
*field
1419 cdef __pyx_typeinfo_string fmt
1420 cdef bytes part
, result
1422 if type.typegroup
== 'S':
1423 assert type.fields
!= NULL
and type.fields
.type != NULL
1425 if type.flags
& __PYX_BUF_FLAGS_PACKED_STRUCT
:
1434 part
= format_from_typeinfo
(field
.type)
1435 parts
.append
(part
+ b
':' + field
.name
+ b
':')
1438 result
= alignment
.join
(parts
) + b
'}'
1440 fmt
= __Pyx_TypeInfoToFormat
(type)
1441 if type.arraysize
[0]:
1442 extents
= [unicode
(type.arraysize
[i
]) for i
in range(type.ndim
)]
1443 result
= (u
"(%s)" % u
','.join
(extents
)).encode
('ascii') + fmt
.string