Remove obsolete entries from .gitignore.
[chromium-blink-merge.git] / third_party / cython / src / Cython / Utility / MemoryView.pyx
blob66aab272406e2bc61d3cf7c7fe1bff955032c2b0
1 #################### View.MemoryView ####################
3 # This utility provides cython.array and cython.view.memoryview
5 import cython
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)
23 cdef extern from *:
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":
36 Py_buffer view
37 PyObject *obj
38 __Pyx_TypeInfo *typeinfo
40 ctypedef struct {{memviewslice_name}}:
41 __pyx_memoryview *memview
42 char *data
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":
51 PyObject *obj
53 PyObject *Py_None
55 cdef enum:
56 PyBUF_C_CONTIGUOUS,
57 PyBUF_F_CONTIGUOUS,
58 PyBUF_ANY_CONTIGUOUS
59 PyBUF_FORMAT
60 PyBUF_WRITABLE
61 PyBUF_STRIDES
62 PyBUF_INDIRECT
63 PyBUF_RECORDS
65 ctypedef struct __Pyx_TypeInfo:
66 pass
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)
72 cdef extern from *:
73 ctypedef int __pyx_atomic_int
74 {{memviewslice_name}} slice_copy_contig "__pyx_memoryview_copy_new_contig"(
75 __Pyx_memviewslice *from_mvs,
76 char *mode, int ndim,
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
98 @cname("__pyx_array")
99 cdef class array:
101 cdef:
102 char *data
103 Py_ssize_t len
104 char *format
105 int ndim
106 Py_ssize_t *_shape
107 Py_ssize_t *_strides
108 Py_ssize_t itemsize
109 unicode mode # FIXME: this should have been a simple 'char'
110 bytes _format
111 void (*callback_free_data)(void *data)
112 # cdef object _memview
113 cdef bint free_data
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):
119 cdef int idx
120 cdef Py_ssize_t i, dim
121 cdef PyObject **p
123 self.ndim = <int> len(shape)
124 self.itemsize = itemsize
126 if not self.ndim:
127 raise ValueError("Empty shape tuple for cython.array")
129 if itemsize <= 0:
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
141 if not self._shape:
142 raise MemoryError("unable to allocate shape and strides.")
144 # cdef Py_ssize_t dim, stride
145 for idx, dim in enumerate(shape):
146 if dim <= 0:
147 raise ValueError("Invalid shape in axis %d: %d." % (idx, dim))
148 self._shape[idx] = dim
150 cdef char order
151 if mode == 'fortran':
152 order = b'F'
153 self.mode = u'fortran'
154 elif mode == 'c':
155 order = b'C'
156 self.mode = u'c'
157 else:
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'
165 if allocate_buffer:
166 # use malloc() for backwards compatibility
167 # in case external code wants to change the data pointer
168 self.data = <char *>malloc(self.len)
169 if not self.data:
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):
175 p[i] = Py_None
176 Py_INCREF(Py_None)
178 @cname('getbuffer')
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.")
187 info.buf = self.data
188 info.len = self.len
189 info.ndim = self.ndim
190 info.shape = self._shape
191 info.strides = self._strides
192 info.suboffsets = NULL
193 info.itemsize = self.itemsize
194 info.readonly = 0
196 if flags & PyBUF_FORMAT:
197 info.format = self.format
198 else:
199 info.format = NULL
201 info.obj = self
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)
208 elif self.free_data:
209 if self.dtype_is_object:
210 refcount_objects_in_slice(self.data, self._shape,
211 self._strides, self.ndim, False)
212 free(self.data)
213 PyMem_Free(self._shape)
215 property memview:
216 @cname('get_memview')
217 def __get__(self):
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):
236 cdef array result
238 if buf == NULL:
239 result = array(shape, itemsize, format, mode.decode('ASCII'))
240 else:
241 result = array(shape, itemsize, format, mode.decode('ASCII'),
242 allocate_buffer=False)
243 result.data = buf
245 return result
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
258 # e.g.
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):
270 cdef object name
271 def __init__(self, name):
272 self.name = name
273 def __repr__(self):
274 return 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
291 cdef size_t offset
293 with cython.cdivision(True):
294 offset = aligned_p % alignment
296 if offset > 0:
297 aligned_p += alignment - offset
299 return <void *> aligned_p
301 @cname('__pyx_memoryview')
302 cdef class memoryview(object):
304 cdef object obj
305 cdef object _size
306 cdef object _array_interface
307 cdef PyThread_type_lock lock
308 # the following array will contain a single __pyx_atomic int with
309 # suitable alignment
310 cdef __pyx_atomic_int acquisition_count[2]
311 cdef __pyx_atomic_int *acquisition_count_aligned_p
312 cdef Py_buffer view
313 cdef int flags
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):
318 self.obj = obj
319 self.flags = flags
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
324 Py_INCREF(Py_None)
326 self.lock = PyThread_allocate_lock()
327 if self.lock == NULL:
328 raise MemoryError
330 if flags & PyBUF_FORMAT:
331 self.dtype_is_object = self.view.format == b'O'
332 else:
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))
337 self.typeinfo = NULL
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:
347 cdef Py_ssize_t dim
348 cdef char *itemp = <char *> self.view.buf
350 for dim, idx in enumerate(index):
351 itemp = pybuffer_index(&self.view, itemp, idx, dim)
353 return itemp
355 #@cname('__pyx_memoryview_getitem')
356 def __getitem__(memoryview self, object index):
357 if index is Ellipsis:
358 return self
360 have_slices, indices = _unellipsify(index, self.view.ndim)
362 cdef char *itemp
363 if have_slices:
364 return memview_slice(self, indices)
365 else:
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)
372 if have_slices:
373 obj = self.is_slice(value)
374 if obj:
375 self.setitem_slice_assignment(self[index], obj)
376 else:
377 self.setitem_slice_assign_scalar(self[index], value)
378 else:
379 self.setitem_indexed(index, value)
381 cdef is_slice(self, obj):
382 if not isinstance(obj, memoryview):
383 try:
384 obj = memoryview(obj, self.flags|PyBUF_ANY_CONTIGUOUS,
385 self.dtype_is_object)
386 except TypeError:
387 return None
389 return obj
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):
400 cdef int array[128]
401 cdef void *tmp = NULL
402 cdef void *item
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)
410 if tmp == NULL:
411 raise MemoryError
412 item = tmp
413 else:
414 item = <void *> array
416 try:
417 if self.dtype_is_object:
418 (<PyObject **> item)[0] = <PyObject *> value
419 else:
420 self.assign_item_from_object(<char *> item, value)
422 # It would be easy to support indirect dimensions, but it's easier
423 # to disallow :)
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)
428 finally:
429 PyMem_Free(tmp)
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"""
438 import struct
439 cdef bytes bytesitem
440 # Do a manual and complete check here instead of this easy hack
441 bytesitem = itemp[:self.view.itemsize]
442 try:
443 result = struct.unpack(self.view.format, bytesitem)
444 except struct.error:
445 raise ValueError("Unable to convert item to object")
446 else:
447 if len(self.view.format) == 1:
448 return result[0]
449 return result
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"""
454 import struct
455 cdef char c
456 cdef bytes bytesvalue
457 cdef Py_ssize_t i
459 if isinstance(value, tuple):
460 bytesvalue = struct.pack(self.view.format, *value)
461 else:
462 bytesvalue = struct.pack(self.view.format, value)
464 for i, c in enumerate(bytesvalue):
465 itemp[i] = c
467 @cname('getbuffer')
468 def __getbuffer__(self, Py_buffer *info, int flags):
469 if flags & PyBUF_STRIDES:
470 info.shape = self.view.shape
471 else:
472 info.shape = NULL
474 if flags & PyBUF_STRIDES:
475 info.strides = self.view.strides
476 else:
477 info.strides = NULL
479 if flags & PyBUF_INDIRECT:
480 info.suboffsets = self.view.suboffsets
481 else:
482 info.suboffsets = NULL
484 if flags & PyBUF_FORMAT:
485 info.format = self.view.format
486 else:
487 info.format = NULL
489 info.buf = self.view.buf
490 info.ndim = self.view.ndim
491 info.itemsize = self.view.itemsize
492 info.len = self.view.len
493 info.readonly = 0
494 info.obj = self
496 __pyx_getbuffer = capsule(<void *> &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)")
498 # Some properties that have the same sematics as in NumPy
499 property T:
500 @cname('__pyx_memoryview_transpose')
501 def __get__(self):
502 cdef _memoryviewslice result = memoryview_copy(self)
503 transpose_memslice(&result.from_slice)
504 return result
506 property base:
507 @cname('__pyx_memoryview__get__base')
508 def __get__(self):
509 return self.obj
511 property shape:
512 @cname('__pyx_memoryview_get_shape')
513 def __get__(self):
514 return tuple([self.view.shape[i] for i in xrange(self.view.ndim)])
516 property strides:
517 @cname('__pyx_memoryview_get_strides')
518 def __get__(self):
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)])
525 property suboffsets:
526 @cname('__pyx_memoryview_get_suboffsets')
527 def __get__(self):
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)])
533 property ndim:
534 @cname('__pyx_memoryview_get_ndim')
535 def __get__(self):
536 return self.view.ndim
538 property itemsize:
539 @cname('__pyx_memoryview_get_itemsize')
540 def __get__(self):
541 return self.view.itemsize
543 property nbytes:
544 @cname('__pyx_memoryview_get_nbytes')
545 def __get__(self):
546 return self.size * self.view.itemsize
548 property size:
549 @cname('__pyx_memoryview_get_size')
550 def __get__(self):
551 if self._size is None:
552 result = 1
554 for length in self.shape:
555 result *= length
557 self._size = result
559 return self._size
561 def __len__(self):
562 if self.view.ndim >= 1:
563 return self.view.shape[0]
565 return 0
567 def __repr__(self):
568 return "<MemoryView of %r at 0x%x>" % (self.base.__class__.__name__,
569 id(self))
571 def __str__(self):
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)
587 def copy(self):
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,
593 self.view.itemsize,
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,
605 self.view.itemsize,
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
616 return result
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
625 full slices.
627 if not isinstance(index, tuple):
628 tup = (index,)
629 else:
630 tup = index
632 result = []
633 have_slices = False
634 seen_ellipsis = False
635 for idx, item in enumerate(tup):
636 if item is Ellipsis:
637 if not seen_ellipsis:
638 result.extend([slice(None)] * (ndim - len(tup) + 1))
639 seen_ellipsis = True
640 else:
641 result.append(slice(None))
642 have_slices = True
643 else:
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)
648 result.append(item)
650 nslices = ndim - len(result)
651 if nslices:
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):
657 cdef int i
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
684 else:
685 slice_copy(memview, &src)
686 p_src = &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):
705 slice_memviewslice(
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}
710 False)
711 elif index is None:
712 p_dst.shape[new_ndim] = 1
713 p_dst.strides[new_ndim] = 0
714 p_dst.suboffsets[new_ndim] = -1
715 new_ndim += 1
716 else:
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
725 slice_memviewslice(
726 p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim],
727 dim, new_ndim, p_suboffset_dim,
728 start, stop, step,
729 have_start, have_stop, have_step,
730 True)
731 new_ndim += 1
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)
738 else:
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":
748 void abort() nogil
749 void printf(char *s, ...) nogil
751 cdef extern from "stdio.h":
752 ctypedef struct FILE
753 FILE *stderr
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
775 disappear)
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
784 if not is_slice:
785 # index is a normal integer-like index
786 if start < 0:
787 start += shape
788 if not 0 <= start < shape:
789 _err_dim(IndexError, "Index out of bounds (axis %d)", dim)
790 else:
791 # index is a slice
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
798 if have_start:
799 if start < 0:
800 start += shape
801 if start < 0:
802 start = 0
803 elif start >= shape:
804 if negative_step:
805 start = shape - 1
806 else:
807 start = shape
808 else:
809 if negative_step:
810 start = shape - 1
811 else:
812 start = 0
814 if have_stop:
815 if stop < 0:
816 stop += shape
817 if stop < 0:
818 stop = 0
819 elif stop > shape:
820 stop = shape
821 else:
822 if negative_step:
823 stop = -1
824 else:
825 stop = shape
827 if not have_step:
828 step = 1
830 # len = ceil( (stop - start) / step )
831 with cython.cdivision(True):
832 new_shape = (stop - start) // step
834 if (stop - start) - step * new_shape:
835 new_shape += 1
837 if new_shape < 0:
838 new_shape = 0
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
848 else:
849 dst.suboffsets[suboffset_dim[0]] += start * stride
851 if suboffset >= 0:
852 if not is_slice:
853 if new_ndim == 0:
854 dst.data = (<char **> dst.data)[0] + suboffset
855 else:
856 _err_dim(IndexError, "All dimensions preceding dimension %d "
857 "must be indexed and not sliced", dim)
858 else:
859 suboffset_dim[0] = new_ndim
861 return 0
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
871 cdef char *resultp
873 if view.ndim == 0:
874 shape = view.len / itemsize
875 stride = itemsize
876 else:
877 shape = view.shape[dim]
878 stride = view.strides[dim]
879 if view.suboffsets != NULL:
880 suboffset = view.suboffsets[dim]
882 if index < 0:
883 index += view.shape[dim]
884 if index < 0:
885 raise IndexError("Out of bounds on buffer access (axis %d)" % dim)
887 if index >= shape:
888 raise IndexError("Out of bounds on buffer access (axis %d)" % dim)
890 resultp = bufp + index * stride
891 if suboffset >= 0:
892 resultp = (<char **> resultp)[0] + suboffset
894 return resultp
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
907 cdef int i, j
908 for i in range(ndim / 2):
909 j = ndim - 1 - i
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")
916 return 1
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)
939 else:
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)
945 else:
946 memoryview.assign_item_from_object(self, itemp, value)
948 property base:
949 @cname('__pyx_memoryviewslice__get__base')
950 def __get__(self):
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,
958 int ndim,
959 object (*to_object_func)(char *),
960 int (*to_dtype_func)(char *, object) except 0,
961 bint dtype_is_object):
963 cdef _memoryviewslice result
964 cdef int i
966 if <PyObject *> memviewslice.memview == Py_None:
967 return 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
984 Py_INCREF(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
999 return result
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):
1006 obj = memview
1007 return &obj.from_slice
1008 else:
1009 slice_copy(memview, mslice)
1010 return mslice
1012 @cname('__pyx_memoryview_slice_copy')
1013 cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst):
1014 cdef int dim
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
1029 else:
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
1050 else:
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:
1063 if arg < 0:
1064 return -arg
1065 else:
1066 return arg
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.
1073 cdef int i
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]
1080 break
1082 for i in range(ndim):
1083 if mslice.shape[i] > 1:
1084 f_stride = mslice.strides[i]
1085 break
1087 if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride):
1088 return 'C'
1089 else:
1090 return 'F'
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
1099 cdef Py_ssize_t i
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]
1105 if ndim == 1:
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)
1109 else:
1110 for i in range(dst_extent):
1111 memcpy(dst_data, src_data, itemsize)
1112 src_data += src_stride
1113 dst_data += dst_stride
1114 else:
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,
1119 ndim - 1, itemsize)
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"
1132 cdef int i
1133 cdef Py_ssize_t size = src.memview.view.itemsize
1135 for i in range(ndim):
1136 size *= src.shape[i]
1138 return size
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
1148 cdef int idx
1150 if order == 'F':
1151 for idx in range(ndim):
1152 strides[idx] = stride
1153 stride = stride * shape[idx]
1154 else:
1155 for idx in range(ndim - 1, -1, -1):
1156 strides[idx] = stride
1157 stride = stride * shape[idx]
1159 return stride
1161 @cname('__pyx_memoryview_copy_data_to_temp')
1162 cdef void *copy_data_to_temp({{memviewslice_name}} *src,
1163 {{memviewslice_name}} *tmpslice,
1164 char order,
1165 int ndim) nogil except NULL:
1167 Copy a direct slice to temporary contiguous memory. The caller should free
1168 the result when done.
1170 cdef int i
1171 cdef void *result
1173 cdef size_t itemsize = src.memview.view.itemsize
1174 cdef size_t size = slice_get_size(src, ndim)
1176 result = malloc(size)
1177 if not result:
1178 _err(MemoryError, NULL)
1180 # tmpslice[0] = src
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,
1188 ndim, order)
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)
1197 else:
1198 copy_strided_to_strided(src, tmpslice, ndim, itemsize)
1200 return result
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:
1216 if msg != NULL:
1217 raise error(msg.decode('ascii'))
1218 else:
1219 raise error
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
1232 cdef int i
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:
1248 broadcasting = True
1249 src.strides[i] = 0
1250 else:
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)
1262 src = tmp
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)
1272 if direct_copy:
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)
1277 free(tmpdata)
1278 return 0
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)
1290 free(tmpdata)
1291 return 0
1293 @cname('__pyx_memoryview_broadcast_leading')
1294 cdef void broadcast_leading({{memviewslice_name}} *slice,
1295 int ndim,
1296 int ndim_other) nogil:
1297 cdef int i
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):
1306 slice.shape[i] = 1
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
1319 # object
1320 if dtype_is_object:
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,
1327 bint inc) with gil:
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):
1333 cdef Py_ssize_t i
1335 for i in range(shape[0]):
1336 if ndim == 1:
1337 if inc:
1338 Py_INCREF((<PyObject **> data)[0])
1339 else:
1340 Py_DECREF((<PyObject **> data)[0])
1341 else:
1342 refcount_objects_in_slice(data, shape + 1, strides + 1,
1343 ndim - 1, inc)
1345 data += strides[0]
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,
1356 itemsize, item)
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:
1364 cdef Py_ssize_t i
1365 cdef Py_ssize_t stride = strides[0]
1366 cdef Py_ssize_t extent = shape[0]
1368 if ndim == 1:
1369 for i in range(extent):
1370 memcpy(data, item, itemsize)
1371 data += stride
1372 else:
1373 for i in range(extent):
1374 _slice_assign_scalar(data, shape + 1, strides + 1,
1375 ndim - 1, itemsize, item)
1376 data += stride
1379 ############### BufferFormatFromTypeInfo ###############
1380 cdef extern from *:
1381 ctypedef struct __Pyx_StructField
1383 cdef enum:
1384 __PYX_BUF_FLAGS_PACKED_STRUCT
1385 __PYX_BUF_FLAGS_INTEGER_COMPLEX
1387 ctypedef struct __Pyx_TypeInfo:
1388 char* name
1389 __Pyx_StructField* fields
1390 size_t size
1391 size_t arraysize[8]
1392 int ndim
1393 char typegroup
1394 char is_unsigned
1395 int flags
1397 ctypedef struct __Pyx_StructField:
1398 __Pyx_TypeInfo* type
1399 char* name
1400 size_t offset
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:
1411 char string[3]
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:
1426 alignment = b'^'
1427 else:
1428 alignment = b''
1430 parts = [b"T{"]
1431 field = type.fields
1433 while field.type:
1434 part = format_from_typeinfo(field.type)
1435 parts.append(part + b':' + field.name + b':')
1436 field += 1
1438 result = alignment.join(parts) + b'}'
1439 else:
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
1444 else:
1445 result = fmt.string
1447 return result