1#################### View.MemoryView #################### 2 3# This utility provides cython.array and cython.view.memoryview 4 5from __future__ import absolute_import 6 7cimport cython 8 9# from cpython cimport ... 10cdef extern from "Python.h": 11 int PyIndex_Check(object) 12 object PyLong_FromVoidPtr(void *) 13 14cdef extern from "pythread.h": 15 ctypedef void *PyThread_type_lock 16 17 PyThread_type_lock PyThread_allocate_lock() 18 void PyThread_free_lock(PyThread_type_lock) 19 int PyThread_acquire_lock(PyThread_type_lock, int mode) nogil 20 void PyThread_release_lock(PyThread_type_lock) nogil 21 22cdef extern from "<string.h>": 23 void *memset(void *b, int c, size_t len) 24 25cdef extern from *: 26 int __Pyx_GetBuffer(object, Py_buffer *, int) except -1 27 void __Pyx_ReleaseBuffer(Py_buffer *) 28 29 ctypedef struct PyObject 30 ctypedef Py_ssize_t Py_intptr_t 31 void Py_INCREF(PyObject *) 32 void Py_DECREF(PyObject *) 33 34 void* PyMem_Malloc(size_t n) 35 void PyMem_Free(void *p) 36 void* PyObject_Malloc(size_t n) 37 void PyObject_Free(void *p) 38 39 cdef struct __pyx_memoryview "__pyx_memoryview_obj": 40 Py_buffer view 41 PyObject *obj 42 __Pyx_TypeInfo *typeinfo 43 44 ctypedef struct {{memviewslice_name}}: 45 __pyx_memoryview *memview 46 char *data 47 Py_ssize_t shape[{{max_dims}}] 48 Py_ssize_t strides[{{max_dims}}] 49 Py_ssize_t suboffsets[{{max_dims}}] 50 51 void __PYX_INC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil) 52 void __PYX_XDEC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil) 53 54 ctypedef struct __pyx_buffer "Py_buffer": 55 PyObject *obj 56 57 PyObject *Py_None 58 59 cdef enum: 60 PyBUF_C_CONTIGUOUS, 61 PyBUF_F_CONTIGUOUS, 62 PyBUF_ANY_CONTIGUOUS 63 PyBUF_FORMAT 64 PyBUF_WRITABLE 65 PyBUF_STRIDES 66 PyBUF_INDIRECT 67 PyBUF_ND 68 PyBUF_RECORDS 69 PyBUF_RECORDS_RO 70 71 ctypedef struct __Pyx_TypeInfo: 72 pass 73 74 cdef object capsule "__pyx_capsule_create" (void *p, char *sig) 75 cdef int __pyx_array_getbuffer(PyObject *obj, Py_buffer view, int flags) 76 cdef int __pyx_memoryview_getbuffer(PyObject *obj, Py_buffer view, int flags) 77 78cdef extern from *: 79 ctypedef int __pyx_atomic_int 80 {{memviewslice_name}} slice_copy_contig "__pyx_memoryview_copy_new_contig"( 81 __Pyx_memviewslice *from_mvs, 82 char *mode, int ndim, 83 size_t sizeof_dtype, int contig_flag, 84 bint dtype_is_object) nogil except * 85 bint slice_is_contig "__pyx_memviewslice_is_contig" ( 86 {{memviewslice_name}} mvs, char order, int ndim) nogil 87 bint slices_overlap "__pyx_slices_overlap" ({{memviewslice_name}} *slice1, 88 {{memviewslice_name}} *slice2, 89 int ndim, size_t itemsize) nogil 90 91 92cdef extern from "<stdlib.h>": 93 void *malloc(size_t) nogil 94 void free(void *) nogil 95 void *memcpy(void *dest, void *src, size_t n) nogil 96 97 98 99 100# 101### cython.array class 102# 103 104@cname("__pyx_array") 105cdef class array: 106 107 cdef: 108 char *data 109 Py_ssize_t len 110 char *format 111 int ndim 112 Py_ssize_t *_shape 113 Py_ssize_t *_strides 114 Py_ssize_t itemsize 115 unicode mode # FIXME: this should have been a simple 'char' 116 bytes _format 117 void (*callback_free_data)(void *data) 118 # cdef object _memview 119 cdef bint free_data 120 cdef bint dtype_is_object 121 122 def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, 123 mode="c", bint allocate_buffer=True): 124 125 cdef int idx 126 cdef Py_ssize_t i, dim 127 cdef PyObject **p 128 129 self.ndim = <int> len(shape) 130 self.itemsize = itemsize 131 132 if not self.ndim: 133 raise ValueError("Empty shape tuple for cython.array") 134 135 if itemsize <= 0: 136 raise ValueError("itemsize <= 0 for cython.array") 137 138 if not isinstance(format, bytes): 139 format = format.encode('ASCII') 140 self._format = format # keep a reference to the byte string 141 self.format = self._format 142 143 # use single malloc() for both shape and strides 144 self._shape = <Py_ssize_t *> PyObject_Malloc(sizeof(Py_ssize_t)*self.ndim*2) 145 self._strides = self._shape + self.ndim 146 147 if not self._shape: 148 raise MemoryError("unable to allocate shape and strides.") 149 150 # cdef Py_ssize_t dim, stride 151 for idx, dim in enumerate(shape): 152 if dim <= 0: 153 raise ValueError("Invalid shape in axis %d: %d." % (idx, dim)) 154 self._shape[idx] = dim 155 156 cdef char order 157 if mode == 'fortran': 158 order = b'F' 159 self.mode = u'fortran' 160 elif mode == 'c': 161 order = b'C' 162 self.mode = u'c' 163 else: 164 raise ValueError("Invalid mode, expected 'c' or 'fortran', got %s" % mode) 165 166 self.len = fill_contig_strides_array(self._shape, self._strides, 167 itemsize, self.ndim, order) 168 169 self.free_data = allocate_buffer 170 self.dtype_is_object = format == b'O' 171 if allocate_buffer: 172 # use malloc() for backwards compatibility 173 # in case external code wants to change the data pointer 174 self.data = <char *>malloc(self.len) 175 if not self.data: 176 raise MemoryError("unable to allocate array data.") 177 178 if self.dtype_is_object: 179 p = <PyObject **> self.data 180 for i in range(self.len / itemsize): 181 p[i] = Py_None 182 Py_INCREF(Py_None) 183 184 @cname('getbuffer') 185 def __getbuffer__(self, Py_buffer *info, int flags): 186 cdef int bufmode = -1 187 if self.mode == u"c": 188 bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS 189 elif self.mode == u"fortran": 190 bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS 191 if not (flags & bufmode): 192 raise ValueError("Can only create a buffer that is contiguous in memory.") 193 info.buf = self.data 194 info.len = self.len 195 info.ndim = self.ndim 196 info.shape = self._shape 197 info.strides = self._strides 198 info.suboffsets = NULL 199 info.itemsize = self.itemsize 200 info.readonly = 0 201 202 if flags & PyBUF_FORMAT: 203 info.format = self.format 204 else: 205 info.format = NULL 206 207 info.obj = self 208 209 __pyx_getbuffer = capsule(<void *> &__pyx_array_getbuffer, "getbuffer(obj, view, flags)") 210 211 def __dealloc__(array self): 212 if self.callback_free_data != NULL: 213 self.callback_free_data(self.data) 214 elif self.free_data: 215 if self.dtype_is_object: 216 refcount_objects_in_slice(self.data, self._shape, 217 self._strides, self.ndim, False) 218 free(self.data) 219 PyObject_Free(self._shape) 220 221 @property 222 def memview(self): 223 return self.get_memview() 224 225 @cname('get_memview') 226 cdef get_memview(self): 227 flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE 228 return memoryview(self, flags, self.dtype_is_object) 229 230 def __len__(self): 231 return self._shape[0] 232 233 def __getattr__(self, attr): 234 return getattr(self.memview, attr) 235 236 def __getitem__(self, item): 237 return self.memview[item] 238 239 def __setitem__(self, item, value): 240 self.memview[item] = value 241 242 243@cname("__pyx_array_new") 244cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, 245 char *mode, char *buf): 246 cdef array result 247 248 if buf == NULL: 249 result = array(shape, itemsize, format, mode.decode('ASCII')) 250 else: 251 result = array(shape, itemsize, format, mode.decode('ASCII'), 252 allocate_buffer=False) 253 result.data = buf 254 255 return result 256 257 258# 259### Memoryview constants and cython.view.memoryview class 260# 261 262# Disable generic_contiguous, as it makes trouble verifying contiguity: 263# - 'contiguous' or '::1' means the dimension is contiguous with dtype 264# - 'indirect_contiguous' means a contiguous list of pointers 265# - dtype contiguous must be contiguous in the first or last dimension 266# from the start, or from the dimension following the last indirect dimension 267# 268# e.g. 269# int[::indirect_contiguous, ::contiguous, :] 270# 271# is valid (list of pointers to 2d fortran-contiguous array), but 272# 273# int[::generic_contiguous, ::contiguous, :] 274# 275# would mean you'd have assert dimension 0 to be indirect (and pointer contiguous) at runtime. 276# So it doesn't bring any performance benefit, and it's only confusing. 277 278@cname('__pyx_MemviewEnum') 279cdef class Enum(object): 280 cdef object name 281 def __init__(self, name): 282 self.name = name 283 def __repr__(self): 284 return self.name 285 286cdef generic = Enum("<strided and direct or indirect>") 287cdef strided = Enum("<strided and direct>") # default 288cdef indirect = Enum("<strided and indirect>") 289# Disable generic_contiguous, as it is a troublemaker 290#cdef generic_contiguous = Enum("<contiguous and direct or indirect>") 291cdef contiguous = Enum("<contiguous and direct>") 292cdef indirect_contiguous = Enum("<contiguous and indirect>") 293 294# 'follow' is implied when the first or last axis is ::1 295 296 297@cname('__pyx_align_pointer') 298cdef void *align_pointer(void *memory, size_t alignment) nogil: 299 "Align pointer memory on a given boundary" 300 cdef Py_intptr_t aligned_p = <Py_intptr_t> memory 301 cdef size_t offset 302 303 with cython.cdivision(True): 304 offset = aligned_p % alignment 305 306 if offset > 0: 307 aligned_p += alignment - offset 308 309 return <void *> aligned_p 310 311 312# pre-allocate thread locks for reuse 313## note that this could be implemented in a more beautiful way in "normal" Cython, 314## but this code gets merged into the user module and not everything works there. 315DEF THREAD_LOCKS_PREALLOCATED = 8 316cdef int __pyx_memoryview_thread_locks_used = 0 317cdef PyThread_type_lock[THREAD_LOCKS_PREALLOCATED] __pyx_memoryview_thread_locks = [ 318 PyThread_allocate_lock(), 319 PyThread_allocate_lock(), 320 PyThread_allocate_lock(), 321 PyThread_allocate_lock(), 322 PyThread_allocate_lock(), 323 PyThread_allocate_lock(), 324 PyThread_allocate_lock(), 325 PyThread_allocate_lock(), 326] 327 328 329@cname('__pyx_memoryview') 330cdef class memoryview(object): 331 332 cdef object obj 333 cdef object _size 334 cdef object _array_interface 335 cdef PyThread_type_lock lock 336 # the following array will contain a single __pyx_atomic int with 337 # suitable alignment 338 cdef __pyx_atomic_int acquisition_count[2] 339 cdef __pyx_atomic_int *acquisition_count_aligned_p 340 cdef Py_buffer view 341 cdef int flags 342 cdef bint dtype_is_object 343 cdef __Pyx_TypeInfo *typeinfo 344 345 def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): 346 self.obj = obj 347 self.flags = flags 348 if type(self) is memoryview or obj is not None: 349 __Pyx_GetBuffer(obj, &self.view, flags) 350 if <PyObject *> self.view.obj == NULL: 351 (<__pyx_buffer *> &self.view).obj = Py_None 352 Py_INCREF(Py_None) 353 354 global __pyx_memoryview_thread_locks_used 355 if __pyx_memoryview_thread_locks_used < THREAD_LOCKS_PREALLOCATED: 356 self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] 357 __pyx_memoryview_thread_locks_used += 1 358 if self.lock is NULL: 359 self.lock = PyThread_allocate_lock() 360 if self.lock is NULL: 361 raise MemoryError 362 363 if flags & PyBUF_FORMAT: 364 self.dtype_is_object = (self.view.format[0] == b'O' and self.view.format[1] == b'\0') 365 else: 366 self.dtype_is_object = dtype_is_object 367 368 self.acquisition_count_aligned_p = <__pyx_atomic_int *> align_pointer( 369 <void *> &self.acquisition_count[0], sizeof(__pyx_atomic_int)) 370 self.typeinfo = NULL 371 372 def __dealloc__(memoryview self): 373 if self.obj is not None: 374 __Pyx_ReleaseBuffer(&self.view) 375 elif (<__pyx_buffer *> &self.view).obj == Py_None: 376 # Undo the incref in __cinit__() above. 377 (<__pyx_buffer *> &self.view).obj = NULL 378 Py_DECREF(Py_None) 379 380 cdef int i 381 global __pyx_memoryview_thread_locks_used 382 if self.lock != NULL: 383 for i in range(__pyx_memoryview_thread_locks_used): 384 if __pyx_memoryview_thread_locks[i] is self.lock: 385 __pyx_memoryview_thread_locks_used -= 1 386 if i != __pyx_memoryview_thread_locks_used: 387 __pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = ( 388 __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i]) 389 break 390 else: 391 PyThread_free_lock(self.lock) 392 393 cdef char *get_item_pointer(memoryview self, object index) except NULL: 394 cdef Py_ssize_t dim 395 cdef char *itemp = <char *> self.view.buf 396 397 for dim, idx in enumerate(index): 398 itemp = pybuffer_index(&self.view, itemp, idx, dim) 399 400 return itemp 401 402 #@cname('__pyx_memoryview_getitem') 403 def __getitem__(memoryview self, object index): 404 if index is Ellipsis: 405 return self 406 407 have_slices, indices = _unellipsify(index, self.view.ndim) 408 409 cdef char *itemp 410 if have_slices: 411 return memview_slice(self, indices) 412 else: 413 itemp = self.get_item_pointer(indices) 414 return self.convert_item_to_object(itemp) 415 416 def __setitem__(memoryview self, object index, object value): 417 if self.view.readonly: 418 raise TypeError("Cannot assign to read-only memoryview") 419 420 have_slices, index = _unellipsify(index, self.view.ndim) 421 422 if have_slices: 423 obj = self.is_slice(value) 424 if obj: 425 self.setitem_slice_assignment(self[index], obj) 426 else: 427 self.setitem_slice_assign_scalar(self[index], value) 428 else: 429 self.setitem_indexed(index, value) 430 431 cdef is_slice(self, obj): 432 if not isinstance(obj, memoryview): 433 try: 434 obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS, 435 self.dtype_is_object) 436 except TypeError: 437 return None 438 439 return obj 440 441 cdef setitem_slice_assignment(self, dst, src): 442 cdef {{memviewslice_name}} dst_slice 443 cdef {{memviewslice_name}} src_slice 444 445 memoryview_copy_contents(get_slice_from_memview(src, &src_slice)[0], 446 get_slice_from_memview(dst, &dst_slice)[0], 447 src.ndim, dst.ndim, self.dtype_is_object) 448 449 cdef setitem_slice_assign_scalar(self, memoryview dst, value): 450 cdef int array[128] 451 cdef void *tmp = NULL 452 cdef void *item 453 454 cdef {{memviewslice_name}} *dst_slice 455 cdef {{memviewslice_name}} tmp_slice 456 dst_slice = get_slice_from_memview(dst, &tmp_slice) 457 458 if <size_t>self.view.itemsize > sizeof(array): 459 tmp = PyMem_Malloc(self.view.itemsize) 460 if tmp == NULL: 461 raise MemoryError 462 item = tmp 463 else: 464 item = <void *> array 465 466 try: 467 if self.dtype_is_object: 468 (<PyObject **> item)[0] = <PyObject *> value 469 else: 470 self.assign_item_from_object(<char *> item, value) 471 472 # It would be easy to support indirect dimensions, but it's easier 473 # to disallow :) 474 if self.view.suboffsets != NULL: 475 assert_direct_dimensions(self.view.suboffsets, self.view.ndim) 476 slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize, 477 item, self.dtype_is_object) 478 finally: 479 PyMem_Free(tmp) 480 481 cdef setitem_indexed(self, index, value): 482 cdef char *itemp = self.get_item_pointer(index) 483 self.assign_item_from_object(itemp, value) 484 485 cdef convert_item_to_object(self, char *itemp): 486 """Only used if instantiated manually by the user, or if Cython doesn't 487 know how to convert the type""" 488 import struct 489 cdef bytes bytesitem 490 # Do a manual and complete check here instead of this easy hack 491 bytesitem = itemp[:self.view.itemsize] 492 try: 493 result = struct.unpack(self.view.format, bytesitem) 494 except struct.error: 495 raise ValueError("Unable to convert item to object") 496 else: 497 if len(self.view.format) == 1: 498 return result[0] 499 return result 500 501 cdef assign_item_from_object(self, char *itemp, object value): 502 """Only used if instantiated manually by the user, or if Cython doesn't 503 know how to convert the type""" 504 import struct 505 cdef char c 506 cdef bytes bytesvalue 507 cdef Py_ssize_t i 508 509 if isinstance(value, tuple): 510 bytesvalue = struct.pack(self.view.format, *value) 511 else: 512 bytesvalue = struct.pack(self.view.format, value) 513 514 for i, c in enumerate(bytesvalue): 515 itemp[i] = c 516 517 @cname('getbuffer') 518 def __getbuffer__(self, Py_buffer *info, int flags): 519 if flags & PyBUF_WRITABLE and self.view.readonly: 520 raise ValueError("Cannot create writable memory view from read-only memoryview") 521 522 if flags & PyBUF_ND: 523 info.shape = self.view.shape 524 else: 525 info.shape = NULL 526 527 if flags & PyBUF_STRIDES: 528 info.strides = self.view.strides 529 else: 530 info.strides = NULL 531 532 if flags & PyBUF_INDIRECT: 533 info.suboffsets = self.view.suboffsets 534 else: 535 info.suboffsets = NULL 536 537 if flags & PyBUF_FORMAT: 538 info.format = self.view.format 539 else: 540 info.format = NULL 541 542 info.buf = self.view.buf 543 info.ndim = self.view.ndim 544 info.itemsize = self.view.itemsize 545 info.len = self.view.len 546 info.readonly = self.view.readonly 547 info.obj = self 548 549 __pyx_getbuffer = capsule(<void *> &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)") 550 551 # Some properties that have the same semantics as in NumPy 552 @property 553 def T(self): 554 cdef _memoryviewslice result = memoryview_copy(self) 555 transpose_memslice(&result.from_slice) 556 return result 557 558 @property 559 def base(self): 560 return self.obj 561 562 @property 563 def shape(self): 564 return tuple([length for length in self.view.shape[:self.view.ndim]]) 565 566 @property 567 def strides(self): 568 if self.view.strides == NULL: 569 # Note: we always ask for strides, so if this is not set it's a bug 570 raise ValueError("Buffer view does not expose strides") 571 572 return tuple([stride for stride in self.view.strides[:self.view.ndim]]) 573 574 @property 575 def suboffsets(self): 576 if self.view.suboffsets == NULL: 577 return (-1,) * self.view.ndim 578 579 return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]]) 580 581 @property 582 def ndim(self): 583 return self.view.ndim 584 585 @property 586 def itemsize(self): 587 return self.view.itemsize 588 589 @property 590 def nbytes(self): 591 return self.size * self.view.itemsize 592 593 @property 594 def size(self): 595 if self._size is None: 596 result = 1 597 598 for length in self.view.shape[:self.view.ndim]: 599 result *= length 600 601 self._size = result 602 603 return self._size 604 605 def __len__(self): 606 if self.view.ndim >= 1: 607 return self.view.shape[0] 608 609 return 0 610 611 def __repr__(self): 612 return "<MemoryView of %r at 0x%x>" % (self.base.__class__.__name__, 613 id(self)) 614 615 def __str__(self): 616 return "<MemoryView of %r object>" % (self.base.__class__.__name__,) 617 618 # Support the same attributes as memoryview slices 619 def is_c_contig(self): 620 cdef {{memviewslice_name}} *mslice 621 cdef {{memviewslice_name}} tmp 622 mslice = get_slice_from_memview(self, &tmp) 623 return slice_is_contig(mslice[0], 'C', self.view.ndim) 624 625 def is_f_contig(self): 626 cdef {{memviewslice_name}} *mslice 627 cdef {{memviewslice_name}} tmp 628 mslice = get_slice_from_memview(self, &tmp) 629 return slice_is_contig(mslice[0], 'F', self.view.ndim) 630 631 def copy(self): 632 cdef {{memviewslice_name}} mslice 633 cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS 634 635 slice_copy(self, &mslice) 636 mslice = slice_copy_contig(&mslice, "c", self.view.ndim, 637 self.view.itemsize, 638 flags|PyBUF_C_CONTIGUOUS, 639 self.dtype_is_object) 640 641 return memoryview_copy_from_slice(self, &mslice) 642 643 def copy_fortran(self): 644 cdef {{memviewslice_name}} src, dst 645 cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS 646 647 slice_copy(self, &src) 648 dst = slice_copy_contig(&src, "fortran", self.view.ndim, 649 self.view.itemsize, 650 flags|PyBUF_F_CONTIGUOUS, 651 self.dtype_is_object) 652 653 return memoryview_copy_from_slice(self, &dst) 654 655 656@cname('__pyx_memoryview_new') 657cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo): 658 cdef memoryview result = memoryview(o, flags, dtype_is_object) 659 result.typeinfo = typeinfo 660 return result 661 662@cname('__pyx_memoryview_check') 663cdef inline bint memoryview_check(object o): 664 return isinstance(o, memoryview) 665 666cdef tuple _unellipsify(object index, int ndim): 667 """ 668 Replace all ellipses with full slices and fill incomplete indices with 669 full slices. 670 """ 671 if not isinstance(index, tuple): 672 tup = (index,) 673 else: 674 tup = index 675 676 result = [] 677 have_slices = False 678 seen_ellipsis = False 679 for idx, item in enumerate(tup): 680 if item is Ellipsis: 681 if not seen_ellipsis: 682 result.extend([slice(None)] * (ndim - len(tup) + 1)) 683 seen_ellipsis = True 684 else: 685 result.append(slice(None)) 686 have_slices = True 687 else: 688 if not isinstance(item, slice) and not PyIndex_Check(item): 689 raise TypeError("Cannot index with type '%s'" % type(item)) 690 691 have_slices = have_slices or isinstance(item, slice) 692 result.append(item) 693 694 nslices = ndim - len(result) 695 if nslices: 696 result.extend([slice(None)] * nslices) 697 698 return have_slices or nslices, tuple(result) 699 700cdef assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim): 701 for suboffset in suboffsets[:ndim]: 702 if suboffset >= 0: 703 raise ValueError("Indirect dimensions not supported") 704 705# 706### Slicing a memoryview 707# 708 709@cname('__pyx_memview_slice') 710cdef memoryview memview_slice(memoryview memview, object indices): 711 cdef int new_ndim = 0, suboffset_dim = -1, dim 712 cdef bint negative_step 713 cdef {{memviewslice_name}} src, dst 714 cdef {{memviewslice_name}} *p_src 715 716 # dst is copied by value in memoryview_fromslice -- initialize it 717 # src is never copied 718 memset(&dst, 0, sizeof(dst)) 719 720 cdef _memoryviewslice memviewsliceobj 721 722 assert memview.view.ndim > 0 723 724 if isinstance(memview, _memoryviewslice): 725 memviewsliceobj = memview 726 p_src = &memviewsliceobj.from_slice 727 else: 728 slice_copy(memview, &src) 729 p_src = &src 730 731 # Note: don't use variable src at this point 732 # SubNote: we should be able to declare variables in blocks... 733 734 # memoryview_fromslice() will inc our dst slice 735 dst.memview = p_src.memview 736 dst.data = p_src.data 737 738 # Put everything in temps to avoid this bloody warning: 739 # "Argument evaluation order in C function call is undefined and 740 # may not be as expected" 741 cdef {{memviewslice_name}} *p_dst = &dst 742 cdef int *p_suboffset_dim = &suboffset_dim 743 cdef Py_ssize_t start, stop, step 744 cdef bint have_start, have_stop, have_step 745 746 for dim, index in enumerate(indices): 747 if PyIndex_Check(index): 748 slice_memviewslice( 749 p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim], 750 dim, new_ndim, p_suboffset_dim, 751 index, 0, 0, # start, stop, step 752 0, 0, 0, # have_{start,stop,step} 753 False) 754 elif index is None: 755 p_dst.shape[new_ndim] = 1 756 p_dst.strides[new_ndim] = 0 757 p_dst.suboffsets[new_ndim] = -1 758 new_ndim += 1 759 else: 760 start = index.start or 0 761 stop = index.stop or 0 762 step = index.step or 0 763 764 have_start = index.start is not None 765 have_stop = index.stop is not None 766 have_step = index.step is not None 767 768 slice_memviewslice( 769 p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim], 770 dim, new_ndim, p_suboffset_dim, 771 start, stop, step, 772 have_start, have_stop, have_step, 773 True) 774 new_ndim += 1 775 776 if isinstance(memview, _memoryviewslice): 777 return memoryview_fromslice(dst, new_ndim, 778 memviewsliceobj.to_object_func, 779 memviewsliceobj.to_dtype_func, 780 memview.dtype_is_object) 781 else: 782 return memoryview_fromslice(dst, new_ndim, NULL, NULL, 783 memview.dtype_is_object) 784 785 786# 787### Slicing in a single dimension of a memoryviewslice 788# 789 790cdef extern from "<stdlib.h>": 791 void abort() nogil 792 void printf(char *s, ...) nogil 793 794cdef extern from "<stdio.h>": 795 ctypedef struct FILE 796 FILE *stderr 797 int fputs(char *s, FILE *stream) 798 799cdef extern from "pystate.h": 800 void PyThreadState_Get() nogil 801 802 # These are not actually nogil, but we check for the GIL before calling them 803 void PyErr_SetString(PyObject *type, char *msg) nogil 804 PyObject *PyErr_Format(PyObject *exc, char *msg, ...) nogil 805 806@cname('__pyx_memoryview_slice_memviewslice') 807cdef int slice_memviewslice( 808 {{memviewslice_name}} *dst, 809 Py_ssize_t shape, Py_ssize_t stride, Py_ssize_t suboffset, 810 int dim, int new_ndim, int *suboffset_dim, 811 Py_ssize_t start, Py_ssize_t stop, Py_ssize_t step, 812 int have_start, int have_stop, int have_step, 813 bint is_slice) nogil except -1: 814 """ 815 Create a new slice dst given slice src. 816 817 dim - the current src dimension (indexing will make dimensions 818 disappear) 819 new_dim - the new dst dimension 820 suboffset_dim - pointer to a single int initialized to -1 to keep track of 821 where slicing offsets should be added 822 """ 823 824 cdef Py_ssize_t new_shape 825 cdef bint negative_step 826 827 if not is_slice: 828 # index is a normal integer-like index 829 if start < 0: 830 start += shape 831 if not 0 <= start < shape: 832 _err_dim(IndexError, "Index out of bounds (axis %d)", dim) 833 else: 834 # index is a slice 835 negative_step = have_step != 0 and step < 0 836 837 if have_step and step == 0: 838 _err_dim(ValueError, "Step may not be zero (axis %d)", dim) 839 840 # check our bounds and set defaults 841 if have_start: 842 if start < 0: 843 start += shape 844 if start < 0: 845 start = 0 846 elif start >= shape: 847 if negative_step: 848 start = shape - 1 849 else: 850 start = shape 851 else: 852 if negative_step: 853 start = shape - 1 854 else: 855 start = 0 856 857 if have_stop: 858 if stop < 0: 859 stop += shape 860 if stop < 0: 861 stop = 0 862 elif stop > shape: 863 stop = shape 864 else: 865 if negative_step: 866 stop = -1 867 else: 868 stop = shape 869 870 if not have_step: 871 step = 1 872 873 # len = ceil( (stop - start) / step ) 874 with cython.cdivision(True): 875 new_shape = (stop - start) // step 876 877 if (stop - start) - step * new_shape: 878 new_shape += 1 879 880 if new_shape < 0: 881 new_shape = 0 882 883 # shape/strides/suboffsets 884 dst.strides[new_ndim] = stride * step 885 dst.shape[new_ndim] = new_shape 886 dst.suboffsets[new_ndim] = suboffset 887 888 # Add the slicing or idexing offsets to the right suboffset or base data * 889 if suboffset_dim[0] < 0: 890 dst.data += start * stride 891 else: 892 dst.suboffsets[suboffset_dim[0]] += start * stride 893 894 if suboffset >= 0: 895 if not is_slice: 896 if new_ndim == 0: 897 dst.data = (<char **> dst.data)[0] + suboffset 898 else: 899 _err_dim(IndexError, "All dimensions preceding dimension %d " 900 "must be indexed and not sliced", dim) 901 else: 902 suboffset_dim[0] = new_ndim 903 904 return 0 905 906# 907### Index a memoryview 908# 909@cname('__pyx_pybuffer_index') 910cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index, 911 Py_ssize_t dim) except NULL: 912 cdef Py_ssize_t shape, stride, suboffset = -1 913 cdef Py_ssize_t itemsize = view.itemsize 914 cdef char *resultp 915 916 if view.ndim == 0: 917 shape = view.len / itemsize 918 stride = itemsize 919 else: 920 shape = view.shape[dim] 921 stride = view.strides[dim] 922 if view.suboffsets != NULL: 923 suboffset = view.suboffsets[dim] 924 925 if index < 0: 926 index += view.shape[dim] 927 if index < 0: 928 raise IndexError("Out of bounds on buffer access (axis %d)" % dim) 929 930 if index >= shape: 931 raise IndexError("Out of bounds on buffer access (axis %d)" % dim) 932 933 resultp = bufp + index * stride 934 if suboffset >= 0: 935 resultp = (<char **> resultp)[0] + suboffset 936 937 return resultp 938 939# 940### Transposing a memoryviewslice 941# 942@cname('__pyx_memslice_transpose') 943cdef int transpose_memslice({{memviewslice_name}} *memslice) nogil except 0: 944 cdef int ndim = memslice.memview.view.ndim 945 946 cdef Py_ssize_t *shape = memslice.shape 947 cdef Py_ssize_t *strides = memslice.strides 948 949 # reverse strides and shape 950 cdef int i, j 951 for i in range(ndim / 2): 952 j = ndim - 1 - i 953 strides[i], strides[j] = strides[j], strides[i] 954 shape[i], shape[j] = shape[j], shape[i] 955 956 if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0: 957 _err(ValueError, "Cannot transpose memoryview with indirect dimensions") 958 959 return 1 960 961# 962### Creating new memoryview objects from slices and memoryviews 963# 964@cname('__pyx_memoryviewslice') 965cdef class _memoryviewslice(memoryview): 966 "Internal class for passing memoryview slices to Python" 967 968 # We need this to keep our shape/strides/suboffset pointers valid 969 cdef {{memviewslice_name}} from_slice 970 # We need this only to print it's class' name 971 cdef object from_object 972 973 cdef object (*to_object_func)(char *) 974 cdef int (*to_dtype_func)(char *, object) except 0 975 976 def __dealloc__(self): 977 __PYX_XDEC_MEMVIEW(&self.from_slice, 1) 978 979 cdef convert_item_to_object(self, char *itemp): 980 if self.to_object_func != NULL: 981 return self.to_object_func(itemp) 982 else: 983 return memoryview.convert_item_to_object(self, itemp) 984 985 cdef assign_item_from_object(self, char *itemp, object value): 986 if self.to_dtype_func != NULL: 987 self.to_dtype_func(itemp, value) 988 else: 989 memoryview.assign_item_from_object(self, itemp, value) 990 991 @property 992 def base(self): 993 return self.from_object 994 995 __pyx_getbuffer = capsule(<void *> &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)") 996 997 998@cname('__pyx_memoryview_fromslice') 999cdef memoryview_fromslice({{memviewslice_name}} memviewslice, 1000 int ndim, 1001 object (*to_object_func)(char *), 1002 int (*to_dtype_func)(char *, object) except 0, 1003 bint dtype_is_object): 1004 1005 cdef _memoryviewslice result 1006 1007 if <PyObject *> memviewslice.memview == Py_None: 1008 return None 1009 1010 # assert 0 < ndim <= memviewslice.memview.view.ndim, ( 1011 # ndim, memviewslice.memview.view.ndim) 1012 1013 result = _memoryviewslice(None, 0, dtype_is_object) 1014 1015 result.from_slice = memviewslice 1016 __PYX_INC_MEMVIEW(&memviewslice, 1) 1017 1018 result.from_object = (<memoryview> memviewslice.memview).base 1019 result.typeinfo = memviewslice.memview.typeinfo 1020 1021 result.view = memviewslice.memview.view 1022 result.view.buf = <void *> memviewslice.data 1023 result.view.ndim = ndim 1024 (<__pyx_buffer *> &result.view).obj = Py_None 1025 Py_INCREF(Py_None) 1026 1027 if (<memoryview>memviewslice.memview).flags & PyBUF_WRITABLE: 1028 result.flags = PyBUF_RECORDS 1029 else: 1030 result.flags = PyBUF_RECORDS_RO 1031 1032 result.view.shape = <Py_ssize_t *> result.from_slice.shape 1033 result.view.strides = <Py_ssize_t *> result.from_slice.strides 1034 1035 # only set suboffsets if actually used, otherwise set to NULL to improve compatibility 1036 result.view.suboffsets = NULL 1037 for suboffset in result.from_slice.suboffsets[:ndim]: 1038 if suboffset >= 0: 1039 result.view.suboffsets = <Py_ssize_t *> result.from_slice.suboffsets 1040 break 1041 1042 result.view.len = result.view.itemsize 1043 for length in result.view.shape[:ndim]: 1044 result.view.len *= length 1045 1046 result.to_object_func = to_object_func 1047 result.to_dtype_func = to_dtype_func 1048 1049 return result 1050 1051@cname('__pyx_memoryview_get_slice_from_memoryview') 1052cdef {{memviewslice_name}} *get_slice_from_memview(memoryview memview, 1053 {{memviewslice_name}} *mslice) except NULL: 1054 cdef _memoryviewslice obj 1055 if isinstance(memview, _memoryviewslice): 1056 obj = memview 1057 return &obj.from_slice 1058 else: 1059 slice_copy(memview, mslice) 1060 return mslice 1061 1062@cname('__pyx_memoryview_slice_copy') 1063cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst): 1064 cdef int dim 1065 cdef (Py_ssize_t*) shape, strides, suboffsets 1066 1067 shape = memview.view.shape 1068 strides = memview.view.strides 1069 suboffsets = memview.view.suboffsets 1070 1071 dst.memview = <__pyx_memoryview *> memview 1072 dst.data = <char *> memview.view.buf 1073 1074 for dim in range(memview.view.ndim): 1075 dst.shape[dim] = shape[dim] 1076 dst.strides[dim] = strides[dim] 1077 dst.suboffsets[dim] = suboffsets[dim] if suboffsets else -1 1078 1079@cname('__pyx_memoryview_copy_object') 1080cdef memoryview_copy(memoryview memview): 1081 "Create a new memoryview object" 1082 cdef {{memviewslice_name}} memviewslice 1083 slice_copy(memview, &memviewslice) 1084 return memoryview_copy_from_slice(memview, &memviewslice) 1085 1086@cname('__pyx_memoryview_copy_object_from_slice') 1087cdef memoryview_copy_from_slice(memoryview memview, {{memviewslice_name}} *memviewslice): 1088 """ 1089 Create a new memoryview object from a given memoryview object and slice. 1090 """ 1091 cdef object (*to_object_func)(char *) 1092 cdef int (*to_dtype_func)(char *, object) except 0 1093 1094 if isinstance(memview, _memoryviewslice): 1095 to_object_func = (<_memoryviewslice> memview).to_object_func 1096 to_dtype_func = (<_memoryviewslice> memview).to_dtype_func 1097 else: 1098 to_object_func = NULL 1099 to_dtype_func = NULL 1100 1101 return memoryview_fromslice(memviewslice[0], memview.view.ndim, 1102 to_object_func, to_dtype_func, 1103 memview.dtype_is_object) 1104 1105 1106# 1107### Copy the contents of a memoryview slices 1108# 1109cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) nogil: 1110 if arg < 0: 1111 return -arg 1112 else: 1113 return arg 1114 1115@cname('__pyx_get_best_slice_order') 1116cdef char get_best_order({{memviewslice_name}} *mslice, int ndim) nogil: 1117 """ 1118 Figure out the best memory access order for a given slice. 1119 """ 1120 cdef int i 1121 cdef Py_ssize_t c_stride = 0 1122 cdef Py_ssize_t f_stride = 0 1123 1124 for i in range(ndim - 1, -1, -1): 1125 if mslice.shape[i] > 1: 1126 c_stride = mslice.strides[i] 1127 break 1128 1129 for i in range(ndim): 1130 if mslice.shape[i] > 1: 1131 f_stride = mslice.strides[i] 1132 break 1133 1134 if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride): 1135 return 'C' 1136 else: 1137 return 'F' 1138 1139@cython.cdivision(True) 1140cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides, 1141 char *dst_data, Py_ssize_t *dst_strides, 1142 Py_ssize_t *src_shape, Py_ssize_t *dst_shape, 1143 int ndim, size_t itemsize) nogil: 1144 # Note: src_extent is 1 if we're broadcasting 1145 # dst_extent always >= src_extent as we don't do reductions 1146 cdef Py_ssize_t i 1147 cdef Py_ssize_t src_extent = src_shape[0] 1148 cdef Py_ssize_t dst_extent = dst_shape[0] 1149 cdef Py_ssize_t src_stride = src_strides[0] 1150 cdef Py_ssize_t dst_stride = dst_strides[0] 1151 1152 if ndim == 1: 1153 if (src_stride > 0 and dst_stride > 0 and 1154 <size_t> src_stride == itemsize == <size_t> dst_stride): 1155 memcpy(dst_data, src_data, itemsize * dst_extent) 1156 else: 1157 for i in range(dst_extent): 1158 memcpy(dst_data, src_data, itemsize) 1159 src_data += src_stride 1160 dst_data += dst_stride 1161 else: 1162 for i in range(dst_extent): 1163 _copy_strided_to_strided(src_data, src_strides + 1, 1164 dst_data, dst_strides + 1, 1165 src_shape + 1, dst_shape + 1, 1166 ndim - 1, itemsize) 1167 src_data += src_stride 1168 dst_data += dst_stride 1169 1170cdef void copy_strided_to_strided({{memviewslice_name}} *src, 1171 {{memviewslice_name}} *dst, 1172 int ndim, size_t itemsize) nogil: 1173 _copy_strided_to_strided(src.data, src.strides, dst.data, dst.strides, 1174 src.shape, dst.shape, ndim, itemsize) 1175 1176@cname('__pyx_memoryview_slice_get_size') 1177cdef Py_ssize_t slice_get_size({{memviewslice_name}} *src, int ndim) nogil: 1178 "Return the size of the memory occupied by the slice in number of bytes" 1179 cdef Py_ssize_t shape, size = src.memview.view.itemsize 1180 1181 for shape in src.shape[:ndim]: 1182 size *= shape 1183 1184 return size 1185 1186@cname('__pyx_fill_contig_strides_array') 1187cdef Py_ssize_t fill_contig_strides_array( 1188 Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t stride, 1189 int ndim, char order) nogil: 1190 """ 1191 Fill the strides array for a slice with C or F contiguous strides. 1192 This is like PyBuffer_FillContiguousStrides, but compatible with py < 2.6 1193 """ 1194 cdef int idx 1195 1196 if order == 'F': 1197 for idx in range(ndim): 1198 strides[idx] = stride 1199 stride *= shape[idx] 1200 else: 1201 for idx in range(ndim - 1, -1, -1): 1202 strides[idx] = stride 1203 stride *= shape[idx] 1204 1205 return stride 1206 1207@cname('__pyx_memoryview_copy_data_to_temp') 1208cdef void *copy_data_to_temp({{memviewslice_name}} *src, 1209 {{memviewslice_name}} *tmpslice, 1210 char order, 1211 int ndim) nogil except NULL: 1212 """ 1213 Copy a direct slice to temporary contiguous memory. The caller should free 1214 the result when done. 1215 """ 1216 cdef int i 1217 cdef void *result 1218 1219 cdef size_t itemsize = src.memview.view.itemsize 1220 cdef size_t size = slice_get_size(src, ndim) 1221 1222 result = malloc(size) 1223 if not result: 1224 _err(MemoryError, NULL) 1225 1226 # tmpslice[0] = src 1227 tmpslice.data = <char *> result 1228 tmpslice.memview = src.memview 1229 for i in range(ndim): 1230 tmpslice.shape[i] = src.shape[i] 1231 tmpslice.suboffsets[i] = -1 1232 1233 fill_contig_strides_array(&tmpslice.shape[0], &tmpslice.strides[0], itemsize, 1234 ndim, order) 1235 1236 # We need to broadcast strides again 1237 for i in range(ndim): 1238 if tmpslice.shape[i] == 1: 1239 tmpslice.strides[i] = 0 1240 1241 if slice_is_contig(src[0], order, ndim): 1242 memcpy(result, src.data, size) 1243 else: 1244 copy_strided_to_strided(src, tmpslice, ndim, itemsize) 1245 1246 return result 1247 1248# Use 'with gil' functions and avoid 'with gil' blocks, as the code within the blocks 1249# has temporaries that need the GIL to clean up 1250@cname('__pyx_memoryview_err_extents') 1251cdef int _err_extents(int i, Py_ssize_t extent1, 1252 Py_ssize_t extent2) except -1 with gil: 1253 raise ValueError("got differing extents in dimension %d (got %d and %d)" % 1254 (i, extent1, extent2)) 1255 1256@cname('__pyx_memoryview_err_dim') 1257cdef int _err_dim(object error, char *msg, int dim) except -1 with gil: 1258 raise error(msg.decode('ascii') % dim) 1259 1260@cname('__pyx_memoryview_err') 1261cdef int _err(object error, char *msg) except -1 with gil: 1262 if msg != NULL: 1263 raise error(msg.decode('ascii')) 1264 else: 1265 raise error 1266 1267@cname('__pyx_memoryview_copy_contents') 1268cdef int memoryview_copy_contents({{memviewslice_name}} src, 1269 {{memviewslice_name}} dst, 1270 int src_ndim, int dst_ndim, 1271 bint dtype_is_object) nogil except -1: 1272 """ 1273 Copy memory from slice src to slice dst. 1274 Check for overlapping memory and verify the shapes. 1275 """ 1276 cdef void *tmpdata = NULL 1277 cdef size_t itemsize = src.memview.view.itemsize 1278 cdef int i 1279 cdef char order = get_best_order(&src, src_ndim) 1280 cdef bint broadcasting = False 1281 cdef bint direct_copy = False 1282 cdef {{memviewslice_name}} tmp 1283 1284 if src_ndim < dst_ndim: 1285 broadcast_leading(&src, src_ndim, dst_ndim) 1286 elif dst_ndim < src_ndim: 1287 broadcast_leading(&dst, dst_ndim, src_ndim) 1288 1289 cdef int ndim = max(src_ndim, dst_ndim) 1290 1291 for i in range(ndim): 1292 if src.shape[i] != dst.shape[i]: 1293 if src.shape[i] == 1: 1294 broadcasting = True 1295 src.strides[i] = 0 1296 else: 1297 _err_extents(i, dst.shape[i], src.shape[i]) 1298 1299 if src.suboffsets[i] >= 0: 1300 _err_dim(ValueError, "Dimension %d is not direct", i) 1301 1302 if slices_overlap(&src, &dst, ndim, itemsize): 1303 # slices overlap, copy to temp, copy temp to dst 1304 if not slice_is_contig(src, order, ndim): 1305 order = get_best_order(&dst, ndim) 1306 1307 tmpdata = copy_data_to_temp(&src, &tmp, order, ndim) 1308 src = tmp 1309 1310 if not broadcasting: 1311 # See if both slices have equal contiguity, in that case perform a 1312 # direct copy. This only works when we are not broadcasting. 1313 if slice_is_contig(src, 'C', ndim): 1314 direct_copy = slice_is_contig(dst, 'C', ndim) 1315 elif slice_is_contig(src, 'F', ndim): 1316 direct_copy = slice_is_contig(dst, 'F', ndim) 1317 1318 if direct_copy: 1319 # Contiguous slices with same order 1320 refcount_copying(&dst, dtype_is_object, ndim, False) 1321 memcpy(dst.data, src.data, slice_get_size(&src, ndim)) 1322 refcount_copying(&dst, dtype_is_object, ndim, True) 1323 free(tmpdata) 1324 return 0 1325 1326 if order == 'F' == get_best_order(&dst, ndim): 1327 # see if both slices have Fortran order, transpose them to match our 1328 # C-style indexing order 1329 transpose_memslice(&src) 1330 transpose_memslice(&dst) 1331 1332 refcount_copying(&dst, dtype_is_object, ndim, False) 1333 copy_strided_to_strided(&src, &dst, ndim, itemsize) 1334 refcount_copying(&dst, dtype_is_object, ndim, True) 1335 1336 free(tmpdata) 1337 return 0 1338 1339@cname('__pyx_memoryview_broadcast_leading') 1340cdef void broadcast_leading({{memviewslice_name}} *mslice, 1341 int ndim, 1342 int ndim_other) nogil: 1343 cdef int i 1344 cdef int offset = ndim_other - ndim 1345 1346 for i in range(ndim - 1, -1, -1): 1347 mslice.shape[i + offset] = mslice.shape[i] 1348 mslice.strides[i + offset] = mslice.strides[i] 1349 mslice.suboffsets[i + offset] = mslice.suboffsets[i] 1350 1351 for i in range(offset): 1352 mslice.shape[i] = 1 1353 mslice.strides[i] = mslice.strides[0] 1354 mslice.suboffsets[i] = -1 1355 1356# 1357### Take care of refcounting the objects in slices. Do this separately from any copying, 1358### to minimize acquiring the GIL 1359# 1360 1361@cname('__pyx_memoryview_refcount_copying') 1362cdef void refcount_copying({{memviewslice_name}} *dst, bint dtype_is_object, 1363 int ndim, bint inc) nogil: 1364 # incref or decref the objects in the destination slice if the dtype is 1365 # object 1366 if dtype_is_object: 1367 refcount_objects_in_slice_with_gil(dst.data, dst.shape, 1368 dst.strides, ndim, inc) 1369 1370@cname('__pyx_memoryview_refcount_objects_in_slice_with_gil') 1371cdef void refcount_objects_in_slice_with_gil(char *data, Py_ssize_t *shape, 1372 Py_ssize_t *strides, int ndim, 1373 bint inc) with gil: 1374 refcount_objects_in_slice(data, shape, strides, ndim, inc) 1375 1376@cname('__pyx_memoryview_refcount_objects_in_slice') 1377cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape, 1378 Py_ssize_t *strides, int ndim, bint inc): 1379 cdef Py_ssize_t i 1380 1381 for i in range(shape[0]): 1382 if ndim == 1: 1383 if inc: 1384 Py_INCREF((<PyObject **> data)[0]) 1385 else: 1386 Py_DECREF((<PyObject **> data)[0]) 1387 else: 1388 refcount_objects_in_slice(data, shape + 1, strides + 1, 1389 ndim - 1, inc) 1390 1391 data += strides[0] 1392 1393# 1394### Scalar to slice assignment 1395# 1396@cname('__pyx_memoryview_slice_assign_scalar') 1397cdef void slice_assign_scalar({{memviewslice_name}} *dst, int ndim, 1398 size_t itemsize, void *item, 1399 bint dtype_is_object) nogil: 1400 refcount_copying(dst, dtype_is_object, ndim, False) 1401 _slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, 1402 itemsize, item) 1403 refcount_copying(dst, dtype_is_object, ndim, True) 1404 1405 1406@cname('__pyx_memoryview__slice_assign_scalar') 1407cdef void _slice_assign_scalar(char *data, Py_ssize_t *shape, 1408 Py_ssize_t *strides, int ndim, 1409 size_t itemsize, void *item) nogil: 1410 cdef Py_ssize_t i 1411 cdef Py_ssize_t stride = strides[0] 1412 cdef Py_ssize_t extent = shape[0] 1413 1414 if ndim == 1: 1415 for i in range(extent): 1416 memcpy(data, item, itemsize) 1417 data += stride 1418 else: 1419 for i in range(extent): 1420 _slice_assign_scalar(data, shape + 1, strides + 1, 1421 ndim - 1, itemsize, item) 1422 data += stride 1423 1424 1425############### BufferFormatFromTypeInfo ############### 1426cdef extern from *: 1427 ctypedef struct __Pyx_StructField 1428 1429 cdef enum: 1430 __PYX_BUF_FLAGS_PACKED_STRUCT 1431 __PYX_BUF_FLAGS_INTEGER_COMPLEX 1432 1433 ctypedef struct __Pyx_TypeInfo: 1434 char* name 1435 __Pyx_StructField* fields 1436 size_t size 1437 size_t arraysize[8] 1438 int ndim 1439 char typegroup 1440 char is_unsigned 1441 int flags 1442 1443 ctypedef struct __Pyx_StructField: 1444 __Pyx_TypeInfo* type 1445 char* name 1446 size_t offset 1447 1448 ctypedef struct __Pyx_BufFmt_StackElem: 1449 __Pyx_StructField* field 1450 size_t parent_offset 1451 1452 #ctypedef struct __Pyx_BufFmt_Context: 1453 # __Pyx_StructField root 1454 __Pyx_BufFmt_StackElem* head 1455 1456 struct __pyx_typeinfo_string: 1457 char string[3] 1458 1459 __pyx_typeinfo_string __Pyx_TypeInfoToFormat(__Pyx_TypeInfo *) 1460 1461 1462@cname('__pyx_format_from_typeinfo') 1463cdef bytes format_from_typeinfo(__Pyx_TypeInfo *type): 1464 cdef __Pyx_StructField *field 1465 cdef __pyx_typeinfo_string fmt 1466 cdef bytes part, result 1467 1468 if type.typegroup == 'S': 1469 assert type.fields != NULL 1470 assert type.fields.type != NULL 1471 1472 if type.flags & __PYX_BUF_FLAGS_PACKED_STRUCT: 1473 alignment = b'^' 1474 else: 1475 alignment = b'' 1476 1477 parts = [b"T{"] 1478 field = type.fields 1479 1480 while field.type: 1481 part = format_from_typeinfo(field.type) 1482 parts.append(part + b':' + field.name + b':') 1483 field += 1 1484 1485 result = alignment.join(parts) + b'}' 1486 else: 1487 fmt = __Pyx_TypeInfoToFormat(type) 1488 if type.arraysize[0]: 1489 extents = [unicode(type.arraysize[i]) for i in range(type.ndim)] 1490 result = (u"(%s)" % u','.join(extents)).encode('ascii') + fmt.string 1491 else: 1492 result = fmt.string 1493 1494 return result 1495