Home | History | Annotate | Download | only in Utility
      1 ////////// MemviewSliceStruct.proto //////////
      2 
      3 /* memoryview slice struct */
      4 struct {{memview_struct_name}};
      5 
      6 typedef struct {
      7   struct {{memview_struct_name}} *memview;
      8   char *data;
      9   Py_ssize_t shape[{{max_dims}}];
     10   Py_ssize_t strides[{{max_dims}}];
     11   Py_ssize_t suboffsets[{{max_dims}}];
     12 } {{memviewslice_name}};
     13 
     14 
     15 /////////// Atomics.proto /////////////
     16 
     17 #include <pythread.h>
     18 
     19 #ifndef CYTHON_ATOMICS
     20     #define CYTHON_ATOMICS 1
     21 #endif
     22 
     23 #define __pyx_atomic_int_type int
     24 // todo: Portland pgcc, maybe OS X's OSAtomicIncrement32,
     25 //       libatomic + autotools-like distutils support? Such a pain...
     26 #if CYTHON_ATOMICS && __GNUC__ >= 4 && (__GNUC_MINOR__ > 1 ||           \
     27                     (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL >= 2)) && \
     28                     !defined(__i386__)
     29     /* gcc >= 4.1.2 */
     30     #define __pyx_atomic_incr_aligned(value, lock) __sync_fetch_and_add(value, 1)
     31     #define __pyx_atomic_decr_aligned(value, lock) __sync_fetch_and_sub(value, 1)
     32 
     33     #ifdef __PYX_DEBUG_ATOMICS
     34         #warning "Using GNU atomics"
     35     #endif
     36 #elif CYTHON_ATOMICS && MSC_VER
     37     /* msvc */
     38     #include <Windows.h>
     39     #define __pyx_atomic_int_type LONG
     40     #define __pyx_atomic_incr_aligned(value, lock) InterlockedIncrement(value)
     41     #define __pyx_atomic_decr_aligned(value, lock) InterlockedDecrement(value)
     42 
     43     #ifdef __PYX_DEBUG_ATOMICS
     44         #warning "Using MSVC atomics"
     45     #endif
     46 #elif CYTHON_ATOMICS && (defined(__ICC) || defined(__INTEL_COMPILER)) && 0
     47     #define __pyx_atomic_incr_aligned(value, lock) _InterlockedIncrement(value)
     48     #define __pyx_atomic_decr_aligned(value, lock) _InterlockedDecrement(value)
     49 
     50     #ifdef __PYX_DEBUG_ATOMICS
     51         #warning "Using Intel atomics"
     52     #endif
     53 #else
     54     #undef CYTHON_ATOMICS
     55     #define CYTHON_ATOMICS 0
     56 
     57     #ifdef __PYX_DEBUG_ATOMICS
     58         #warning "Not using atomics"
     59     #endif
     60 #endif
     61 
     62 typedef volatile __pyx_atomic_int_type __pyx_atomic_int;
     63 
     64 #if CYTHON_ATOMICS
     65     #define __pyx_add_acquisition_count(memview) \
     66              __pyx_atomic_incr_aligned(__pyx_get_slice_count_pointer(memview), memview->lock)
     67     #define __pyx_sub_acquisition_count(memview) \
     68             __pyx_atomic_decr_aligned(__pyx_get_slice_count_pointer(memview), memview->lock)
     69 #else
     70     #define __pyx_add_acquisition_count(memview) \
     71             __pyx_add_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock)
     72     #define __pyx_sub_acquisition_count(memview) \
     73             __pyx_sub_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock)
     74 #endif
     75 
     76 
     77 /////////////// ObjectToMemviewSlice.proto ///////////////
     78 
     79 static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *);
     80 
     81 
     82 ////////// MemviewSliceInit.proto //////////
     83 
     84 #define __Pyx_BUF_MAX_NDIMS %(BUF_MAX_NDIMS)d
     85 
     86 #define __Pyx_MEMVIEW_DIRECT   1
     87 #define __Pyx_MEMVIEW_PTR      2
     88 #define __Pyx_MEMVIEW_FULL     4
     89 #define __Pyx_MEMVIEW_CONTIG   8
     90 #define __Pyx_MEMVIEW_STRIDED  16
     91 #define __Pyx_MEMVIEW_FOLLOW   32
     92 
     93 #define __Pyx_IS_C_CONTIG 1
     94 #define __Pyx_IS_F_CONTIG 2
     95 
     96 static int __Pyx_init_memviewslice(
     97                 struct __pyx_memoryview_obj *memview,
     98                 int ndim,
     99                 __Pyx_memviewslice *memviewslice,
    100                 int memview_is_new_reference);
    101 
    102 static CYTHON_INLINE int __pyx_add_acquisition_count_locked(
    103     __pyx_atomic_int *acquisition_count, PyThread_type_lock lock);
    104 static CYTHON_INLINE int __pyx_sub_acquisition_count_locked(
    105     __pyx_atomic_int *acquisition_count, PyThread_type_lock lock);
    106 
    107 #define __pyx_get_slice_count_pointer(memview) (memview->acquisition_count_aligned_p)
    108 #define __pyx_get_slice_count(memview) (*__pyx_get_slice_count_pointer(memview))
    109 #define __PYX_INC_MEMVIEW(slice, have_gil) __Pyx_INC_MEMVIEW(slice, have_gil, __LINE__)
    110 #define __PYX_XDEC_MEMVIEW(slice, have_gil) __Pyx_XDEC_MEMVIEW(slice, have_gil, __LINE__)
    111 static CYTHON_INLINE void __Pyx_INC_MEMVIEW({{memviewslice_name}} *, int, int);
    112 static CYTHON_INLINE void __Pyx_XDEC_MEMVIEW({{memviewslice_name}} *, int, int);
    113 
    114 
    115 /////////////// MemviewSliceIndex.proto ///////////////
    116 
    117 static CYTHON_INLINE char *__pyx_memviewslice_index_full(
    118     const char *bufp, Py_ssize_t idx, Py_ssize_t stride, Py_ssize_t suboffset);
    119 
    120 
    121 /////////////// ObjectToMemviewSlice ///////////////
    122 //@requires: MemviewSliceValidateAndInit
    123 
    124 static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *obj) {
    125     {{memviewslice_name}} result = {{memslice_init}};
    126     __Pyx_BufFmt_StackElem stack[{{struct_nesting_depth}}];
    127     int axes_specs[] = { {{axes_specs}} };
    128     int retcode;
    129 
    130     if (obj == Py_None) {
    131         /* We don't bother to refcount None */
    132         result.memview = (struct __pyx_memoryview_obj *) Py_None;
    133         return result;
    134     }
    135 
    136     retcode = __Pyx_ValidateAndInit_memviewslice(axes_specs, {{c_or_f_flag}},
    137                                                  {{buf_flag}}, {{ndim}},
    138                                                  &{{dtype_typeinfo}}, stack,
    139                                                  &result, obj);
    140 
    141     if (unlikely(retcode == -1))
    142         goto __pyx_fail;
    143 
    144     return result;
    145 __pyx_fail:
    146     result.memview = NULL;
    147     result.data = NULL;
    148     return result;
    149 }
    150 
    151 
    152 /////////////// MemviewSliceValidateAndInit.proto ///////////////
    153 
    154 static int __Pyx_ValidateAndInit_memviewslice(
    155                 int *axes_specs,
    156                 int c_or_f_flag,
    157                 int buf_flags,
    158                 int ndim,
    159                 __Pyx_TypeInfo *dtype,
    160                 __Pyx_BufFmt_StackElem stack[],
    161                 __Pyx_memviewslice *memviewslice,
    162                 PyObject *original_obj);
    163 
    164 /////////////// MemviewSliceValidateAndInit ///////////////
    165 //@requires: Buffer.c::TypeInfoCompare
    166 
    167 static int
    168 __pyx_check_strides(Py_buffer *buf, int dim, int ndim, int spec)
    169 {
    170     if (buf->shape[dim] <= 1)
    171         return 1;
    172 
    173     if (buf->strides) {
    174         if (spec & __Pyx_MEMVIEW_CONTIG) {
    175             if (spec & (__Pyx_MEMVIEW_PTR|__Pyx_MEMVIEW_FULL)) {
    176                 if (buf->strides[dim] != sizeof(void *)) {
    177                     PyErr_Format(PyExc_ValueError,
    178                                  "Buffer is not indirectly contiguous "
    179                                  "in dimension %d.", dim);
    180                     goto fail;
    181                 }
    182             } else if (buf->strides[dim] != buf->itemsize) {
    183                 PyErr_SetString(PyExc_ValueError,
    184                                 "Buffer and memoryview are not contiguous "
    185                                 "in the same dimension.");
    186                 goto fail;
    187             }
    188         }
    189 
    190         if (spec & __Pyx_MEMVIEW_FOLLOW) {
    191             Py_ssize_t stride = buf->strides[dim];
    192             if (stride < 0)
    193                 stride = -stride;
    194             if (stride < buf->itemsize) {
    195                 PyErr_SetString(PyExc_ValueError,
    196                                 "Buffer and memoryview are not contiguous "
    197                                 "in the same dimension.");
    198                 goto fail;
    199             }
    200         }
    201     } else {
    202         if (spec & __Pyx_MEMVIEW_CONTIG && dim != ndim - 1) {
    203             PyErr_Format(PyExc_ValueError,
    204                          "C-contiguous buffer is not contiguous in "
    205                          "dimension %d", dim);
    206             goto fail;
    207         } else if (spec & (__Pyx_MEMVIEW_PTR)) {
    208             PyErr_Format(PyExc_ValueError,
    209                          "C-contiguous buffer is not indirect in "
    210                          "dimension %d", dim);
    211             goto fail;
    212         } else if (buf->suboffsets) {
    213             PyErr_SetString(PyExc_ValueError,
    214                             "Buffer exposes suboffsets but no strides");
    215             goto fail;
    216         }
    217     }
    218 
    219     return 1;
    220 fail:
    221     return 0;
    222 }
    223 
    224 static int
    225 __pyx_check_suboffsets(Py_buffer *buf, int dim, CYTHON_UNUSED int ndim, int spec)
    226 {
    227     // Todo: without PyBUF_INDIRECT we may not have suboffset information, i.e., the
    228     //       ptr may not be set to NULL but may be uninitialized?
    229     if (spec & __Pyx_MEMVIEW_DIRECT) {
    230         if (buf->suboffsets && buf->suboffsets[dim] >= 0) {
    231             PyErr_Format(PyExc_ValueError,
    232                          "Buffer not compatible with direct access "
    233                          "in dimension %d.", dim);
    234             goto fail;
    235         }
    236     }
    237 
    238     if (spec & __Pyx_MEMVIEW_PTR) {
    239         if (!buf->suboffsets || (buf->suboffsets && buf->suboffsets[dim] < 0)) {
    240             PyErr_Format(PyExc_ValueError,
    241                          "Buffer is not indirectly accessible "
    242                          "in dimension %d.", dim);
    243             goto fail;
    244         }
    245     }
    246 
    247     return 1;
    248 fail:
    249     return 0;
    250 }
    251 
    252 static int
    253 __pyx_verify_contig(Py_buffer *buf, int ndim, int c_or_f_flag)
    254 {
    255     int i;
    256 
    257     if (c_or_f_flag & __Pyx_IS_F_CONTIG) {
    258         Py_ssize_t stride = 1;
    259         for (i = 0; i < ndim; i++) {
    260             if (stride * buf->itemsize != buf->strides[i] &&
    261                     buf->shape[i] > 1)
    262             {
    263                 PyErr_SetString(PyExc_ValueError,
    264                     "Buffer not fortran contiguous.");
    265                 goto fail;
    266             }
    267             stride = stride * buf->shape[i];
    268         }
    269     } else if (c_or_f_flag & __Pyx_IS_C_CONTIG) {
    270         Py_ssize_t stride = 1;
    271         for (i = ndim - 1; i >- 1; i--) {
    272             if (stride * buf->itemsize != buf->strides[i] &&
    273                     buf->shape[i] > 1) {
    274                 PyErr_SetString(PyExc_ValueError,
    275                     "Buffer not C contiguous.");
    276                 goto fail;
    277             }
    278             stride = stride * buf->shape[i];
    279         }
    280     }
    281 
    282     return 1;
    283 fail:
    284     return 0;
    285 }
    286 
    287 static int __Pyx_ValidateAndInit_memviewslice(
    288                 int *axes_specs,
    289                 int c_or_f_flag,
    290                 int buf_flags,
    291                 int ndim,
    292                 __Pyx_TypeInfo *dtype,
    293                 __Pyx_BufFmt_StackElem stack[],
    294                 __Pyx_memviewslice *memviewslice,
    295                 PyObject *original_obj)
    296 {
    297     struct __pyx_memoryview_obj *memview, *new_memview;
    298     __Pyx_RefNannyDeclarations
    299     Py_buffer *buf;
    300     int i, spec = 0, retval = -1;
    301     __Pyx_BufFmt_Context ctx;
    302     int from_memoryview = __pyx_memoryview_check(original_obj);
    303 
    304     __Pyx_RefNannySetupContext("ValidateAndInit_memviewslice", 0);
    305 
    306     if (from_memoryview && __pyx_typeinfo_cmp(dtype, ((struct __pyx_memoryview_obj *)
    307                                                             original_obj)->typeinfo)) {
    308         /* We have a matching dtype, skip format parsing */
    309         memview = (struct __pyx_memoryview_obj *) original_obj;
    310         new_memview = NULL;
    311     } else {
    312         memview = (struct __pyx_memoryview_obj *) __pyx_memoryview_new(
    313                                             original_obj, buf_flags, 0, dtype);
    314         new_memview = memview;
    315         if (unlikely(!memview))
    316             goto fail;
    317     }
    318 
    319     buf = &memview->view;
    320     if (buf->ndim != ndim) {
    321         PyErr_Format(PyExc_ValueError,
    322                 "Buffer has wrong number of dimensions (expected %d, got %d)",
    323                 ndim, buf->ndim);
    324         goto fail;
    325     }
    326 
    327     if (new_memview) {
    328         __Pyx_BufFmt_Init(&ctx, stack, dtype);
    329         if (!__Pyx_BufFmt_CheckString(&ctx, buf->format)) goto fail;
    330     }
    331 
    332     if ((unsigned) buf->itemsize != dtype->size) {
    333         PyErr_Format(PyExc_ValueError,
    334                      "Item size of buffer (%" CYTHON_FORMAT_SSIZE_T "u byte%s) "
    335                      "does not match size of '%s' (%" CYTHON_FORMAT_SSIZE_T "u byte%s)",
    336                      buf->itemsize,
    337                      (buf->itemsize > 1) ? "s" : "",
    338                      dtype->name,
    339                      dtype->size,
    340                      (dtype->size > 1) ? "s" : "");
    341         goto fail;
    342     }
    343 
    344     /* Check axes */
    345     for (i = 0; i < ndim; i++) {
    346         spec = axes_specs[i];
    347         if (!__pyx_check_strides(buf, i, ndim, spec))
    348             goto fail;
    349         if (!__pyx_check_suboffsets(buf, i, ndim, spec))
    350             goto fail;
    351     }
    352 
    353     /* Check contiguity */
    354     if (buf->strides && !__pyx_verify_contig(buf, ndim, c_or_f_flag))
    355         goto fail;
    356 
    357     /* Initialize */
    358     if (unlikely(__Pyx_init_memviewslice(memview, ndim, memviewslice,
    359                                          new_memview != NULL) == -1)) {
    360         goto fail;
    361     }
    362 
    363     retval = 0;
    364     goto no_fail;
    365 
    366 fail:
    367     Py_XDECREF(new_memview);
    368     retval = -1;
    369 
    370 no_fail:
    371     __Pyx_RefNannyFinishContext();
    372     return retval;
    373 }
    374 
    375 
    376 ////////// MemviewSliceInit //////////
    377 
    378 static int
    379 __Pyx_init_memviewslice(struct __pyx_memoryview_obj *memview,
    380                         int ndim,
    381                         {{memviewslice_name}} *memviewslice,
    382                         int memview_is_new_reference)
    383 {
    384     __Pyx_RefNannyDeclarations
    385     int i, retval=-1;
    386     Py_buffer *buf = &memview->view;
    387     __Pyx_RefNannySetupContext("init_memviewslice", 0);
    388 
    389     if (!buf) {
    390         PyErr_SetString(PyExc_ValueError,
    391             "buf is NULL.");
    392         goto fail;
    393     } else if (memviewslice->memview || memviewslice->data) {
    394         PyErr_SetString(PyExc_ValueError,
    395             "memviewslice is already initialized!");
    396         goto fail;
    397     }
    398 
    399     if (buf->strides) {
    400         for (i = 0; i < ndim; i++) {
    401             memviewslice->strides[i] = buf->strides[i];
    402         }
    403     } else {
    404         Py_ssize_t stride = buf->itemsize;
    405         for (i = ndim - 1; i >= 0; i--) {
    406             memviewslice->strides[i] = stride;
    407             stride *= buf->shape[i];
    408         }
    409     }
    410 
    411     for (i = 0; i < ndim; i++) {
    412         memviewslice->shape[i]   = buf->shape[i];
    413         if (buf->suboffsets) {
    414             memviewslice->suboffsets[i] = buf->suboffsets[i];
    415         } else {
    416             memviewslice->suboffsets[i] = -1;
    417         }
    418     }
    419 
    420     memviewslice->memview = memview;
    421     memviewslice->data = (char *)buf->buf;
    422     if (__pyx_add_acquisition_count(memview) == 0 && !memview_is_new_reference) {
    423         Py_INCREF(memview);
    424     }
    425     retval = 0;
    426     goto no_fail;
    427 
    428 fail:
    429     /* Don't decref, the memoryview may be borrowed. Let the caller do the cleanup */
    430     /* __Pyx_XDECREF(memviewslice->memview); */
    431     memviewslice->memview = 0;
    432     memviewslice->data = 0;
    433     retval = -1;
    434 no_fail:
    435     __Pyx_RefNannyFinishContext();
    436     return retval;
    437 }
    438 
    439 
    440 static CYTHON_INLINE void __pyx_fatalerror(const char *fmt, ...) {
    441     va_list vargs;
    442     char msg[200];
    443 
    444     va_start(vargs, fmt);
    445 
    446 #ifdef HAVE_STDARG_PROTOTYPES
    447     va_start(vargs, fmt);
    448 #else
    449     va_start(vargs);
    450 #endif
    451 
    452     vsnprintf(msg, 200, fmt, vargs);
    453     Py_FatalError(msg);
    454 
    455     va_end(vargs);
    456 }
    457 
    458 static CYTHON_INLINE int
    459 __pyx_add_acquisition_count_locked(__pyx_atomic_int *acquisition_count,
    460                                    PyThread_type_lock lock)
    461 {
    462     int result;
    463     PyThread_acquire_lock(lock, 1);
    464     result = (*acquisition_count)++;
    465     PyThread_release_lock(lock);
    466     return result;
    467 }
    468 
    469 static CYTHON_INLINE int
    470 __pyx_sub_acquisition_count_locked(__pyx_atomic_int *acquisition_count,
    471                                    PyThread_type_lock lock)
    472 {
    473     int result;
    474     PyThread_acquire_lock(lock, 1);
    475     result = (*acquisition_count)--;
    476     PyThread_release_lock(lock);
    477     return result;
    478 }
    479 
    480 
    481 static CYTHON_INLINE void
    482 __Pyx_INC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil, int lineno)
    483 {
    484     int first_time;
    485     struct {{memview_struct_name}} *memview = memslice->memview;
    486     if (!memview || (PyObject *) memview == Py_None)
    487         return; /* allow uninitialized memoryview assignment */
    488 
    489     if (__pyx_get_slice_count(memview) < 0)
    490         __pyx_fatalerror("Acquisition count is %d (line %d)",
    491                          __pyx_get_slice_count(memview), lineno);
    492 
    493     first_time = __pyx_add_acquisition_count(memview) == 0;
    494 
    495     if (first_time) {
    496         if (have_gil) {
    497             Py_INCREF((PyObject *) memview);
    498         } else {
    499             PyGILState_STATE _gilstate = PyGILState_Ensure();
    500             Py_INCREF((PyObject *) memview);
    501             PyGILState_Release(_gilstate);
    502         }
    503     }
    504 }
    505 
    506 static CYTHON_INLINE void __Pyx_XDEC_MEMVIEW({{memviewslice_name}} *memslice,
    507                                              int have_gil, int lineno) {
    508     int last_time;
    509     struct {{memview_struct_name}} *memview = memslice->memview;
    510 
    511     if (!memview ) {
    512         return;
    513     } else if ((PyObject *) memview == Py_None) {
    514         memslice->memview = NULL;
    515         return;
    516     }
    517 
    518     if (__pyx_get_slice_count(memview) <= 0)
    519         __pyx_fatalerror("Acquisition count is %d (line %d)",
    520                          __pyx_get_slice_count(memview), lineno);
    521 
    522     last_time = __pyx_sub_acquisition_count(memview) == 1;
    523     memslice->data = NULL;
    524     if (last_time) {
    525         if (have_gil) {
    526             Py_CLEAR(memslice->memview);
    527         } else {
    528             PyGILState_STATE _gilstate = PyGILState_Ensure();
    529             Py_CLEAR(memslice->memview);
    530             PyGILState_Release(_gilstate);
    531         }
    532     } else {
    533         memslice->memview = NULL;
    534     }
    535 }
    536 
    537 
    538 ////////// MemviewSliceCopyTemplate.proto //////////
    539 
    540 static {{memviewslice_name}}
    541 __pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs,
    542                                  const char *mode, int ndim,
    543                                  size_t sizeof_dtype, int contig_flag,
    544                                  int dtype_is_object);
    545 
    546 
    547 ////////// MemviewSliceCopyTemplate //////////
    548 
    549 static {{memviewslice_name}}
    550 __pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs,
    551                                  const char *mode, int ndim,
    552                                  size_t sizeof_dtype, int contig_flag,
    553                                  int dtype_is_object)
    554 {
    555     __Pyx_RefNannyDeclarations
    556     int i;
    557     __Pyx_memviewslice new_mvs = {{memslice_init}};
    558     struct __pyx_memoryview_obj *from_memview = from_mvs->memview;
    559     Py_buffer *buf = &from_memview->view;
    560     PyObject *shape_tuple = NULL;
    561     PyObject *temp_int = NULL;
    562     struct __pyx_array_obj *array_obj = NULL;
    563     struct __pyx_memoryview_obj *memview_obj = NULL;
    564 
    565     __Pyx_RefNannySetupContext("__pyx_memoryview_copy_new_contig", 0);
    566 
    567     for (i = 0; i < ndim; i++) {
    568         if (from_mvs->suboffsets[i] >= 0) {
    569             PyErr_Format(PyExc_ValueError, "Cannot copy memoryview slice with "
    570                                            "indirect dimensions (axis %d)", i);
    571             goto fail;
    572         }
    573     }
    574 
    575     shape_tuple = PyTuple_New(ndim);
    576     if (unlikely(!shape_tuple)) {
    577         goto fail;
    578     }
    579     __Pyx_GOTREF(shape_tuple);
    580 
    581 
    582     for(i = 0; i < ndim; i++) {
    583         temp_int = PyInt_FromSsize_t(from_mvs->shape[i]);
    584         if(unlikely(!temp_int)) {
    585             goto fail;
    586         } else {
    587             PyTuple_SET_ITEM(shape_tuple, i, temp_int);
    588             temp_int = NULL;
    589         }
    590     }
    591 
    592     array_obj = __pyx_array_new(shape_tuple, sizeof_dtype, buf->format, (char *) mode, NULL);
    593     if (unlikely(!array_obj)) {
    594         goto fail;
    595     }
    596     __Pyx_GOTREF(array_obj);
    597 
    598     memview_obj = (struct __pyx_memoryview_obj *) __pyx_memoryview_new(
    599                                     (PyObject *) array_obj, contig_flag,
    600                                     dtype_is_object,
    601                                     from_mvs->memview->typeinfo);
    602     if (unlikely(!memview_obj))
    603         goto fail;
    604 
    605     /* initialize new_mvs */
    606     if (unlikely(__Pyx_init_memviewslice(memview_obj, ndim, &new_mvs, 1) < 0))
    607         goto fail;
    608 
    609     if (unlikely(__pyx_memoryview_copy_contents(*from_mvs, new_mvs, ndim, ndim,
    610                                                 dtype_is_object) < 0))
    611         goto fail;
    612 
    613     goto no_fail;
    614 
    615 fail:
    616     __Pyx_XDECREF(new_mvs.memview);
    617     new_mvs.memview = NULL;
    618     new_mvs.data = NULL;
    619 no_fail:
    620     __Pyx_XDECREF(shape_tuple);
    621     __Pyx_XDECREF(temp_int);
    622     __Pyx_XDECREF(array_obj);
    623     __Pyx_RefNannyFinishContext();
    624     return new_mvs;
    625 }
    626 
    627 
    628 ////////// CopyContentsUtility.proto /////////
    629 
    630 #define {{func_cname}}(slice) \
    631         __pyx_memoryview_copy_new_contig(&slice, "{{mode}}", {{ndim}},            \
    632                                          sizeof({{dtype_decl}}), {{contig_flag}}, \
    633                                          {{dtype_is_object}})
    634 
    635 
    636 ////////// OverlappingSlices.proto //////////
    637 
    638 static int __pyx_slices_overlap({{memviewslice_name}} *slice1,
    639                                 {{memviewslice_name}} *slice2,
    640                                 int ndim, size_t itemsize);
    641 
    642 
    643 ////////// OverlappingSlices //////////
    644 
    645 /* Based on numpy's core/src/multiarray/array_assign.c */
    646 
    647 /* Gets a half-open range [start, end) which contains the array data */
    648 static void
    649 __pyx_get_array_memory_extents({{memviewslice_name}} *slice,
    650                                void **out_start, void **out_end,
    651                                int ndim, size_t itemsize)
    652 {
    653     char *start, *end;
    654     int i;
    655 
    656     start = end = slice->data;
    657 
    658     for (i = 0; i < ndim; i++) {
    659         Py_ssize_t stride = slice->strides[i];
    660         Py_ssize_t extent = slice->shape[i];
    661 
    662         if (extent == 0) {
    663             *out_start = *out_end = start;
    664             return;
    665         } else {
    666             if (stride > 0)
    667                 end += stride * (extent - 1);
    668             else
    669                 start += stride * (extent - 1);
    670         }
    671     }
    672 
    673     /* Return a half-open range */
    674     *out_start = start;
    675     *out_end = end + itemsize;
    676 }
    677 
    678 /* Returns 1 if the arrays have overlapping data, 0 otherwise */
    679 static int
    680 __pyx_slices_overlap({{memviewslice_name}} *slice1,
    681                      {{memviewslice_name}} *slice2,
    682                      int ndim, size_t itemsize)
    683 {
    684     void *start1, *end1, *start2, *end2;
    685 
    686     __pyx_get_array_memory_extents(slice1, &start1, &end1, ndim, itemsize);
    687     __pyx_get_array_memory_extents(slice2, &start2, &end2, ndim, itemsize);
    688 
    689     return (start1 < end2) && (start2 < end1);
    690 }
    691 
    692 
    693 ////////// MemviewSliceIsCContig.proto //////////
    694 
    695 #define __pyx_memviewslice_is_c_contig{{ndim}}(slice) \
    696         __pyx_memviewslice_is_contig(&slice, 'C', {{ndim}})
    697 
    698 
    699 ////////// MemviewSliceIsFContig.proto //////////
    700 
    701 #define __pyx_memviewslice_is_f_contig{{ndim}}(slice) \
    702         __pyx_memviewslice_is_contig(&slice, 'F', {{ndim}})
    703 
    704 
    705 ////////// MemviewSliceIsContig.proto //////////
    706 
    707 static int __pyx_memviewslice_is_contig(const {{memviewslice_name}} *mvs,
    708                                         char order, int ndim);
    709 
    710 
    711 ////////// MemviewSliceIsContig //////////
    712 
    713 static int
    714 __pyx_memviewslice_is_contig(const {{memviewslice_name}} *mvs,
    715                              char order, int ndim)
    716 {
    717     int i, index, step, start;
    718     Py_ssize_t itemsize = mvs->memview->view.itemsize;
    719 
    720     if (order == 'F') {
    721         step = 1;
    722         start = 0;
    723     } else {
    724         step = -1;
    725         start = ndim - 1;
    726     }
    727 
    728     for (i = 0; i < ndim; i++) {
    729         index = start + step * i;
    730         if (mvs->suboffsets[index] >= 0 || mvs->strides[index] != itemsize)
    731             return 0;
    732 
    733         itemsize *= mvs->shape[index];
    734     }
    735 
    736     return 1;
    737 }
    738 
    739 
    740 /////////////// MemviewSliceIndex ///////////////
    741 
    742 static CYTHON_INLINE char *
    743 __pyx_memviewslice_index_full(const char *bufp, Py_ssize_t idx,
    744                               Py_ssize_t stride, Py_ssize_t suboffset)
    745 {
    746     bufp = bufp + idx * stride;
    747     if (suboffset >= 0) {
    748         bufp = *((char **) bufp) + suboffset;
    749     }
    750     return (char *) bufp;
    751 }
    752 
    753 
    754 /////////////// MemviewDtypeToObject.proto ///////////////
    755 
    756 {{if to_py_function}}
    757 static PyObject *{{get_function}}(const char *itemp); /* proto */
    758 {{endif}}
    759 
    760 {{if from_py_function}}
    761 static int {{set_function}}(const char *itemp, PyObject *obj); /* proto */
    762 {{endif}}
    763 
    764 /////////////// MemviewDtypeToObject ///////////////
    765 
    766 {{#__pyx_memview_<dtype_name>_to_object}}
    767 
    768 /* Convert a dtype to or from a Python object */
    769 
    770 {{if to_py_function}}
    771 static PyObject *{{get_function}}(const char *itemp) {
    772     return (PyObject *) {{to_py_function}}(*({{dtype}} *) itemp);
    773 }
    774 {{endif}}
    775 
    776 {{if from_py_function}}
    777 static int {{set_function}}(const char *itemp, PyObject *obj) {
    778     {{dtype}} value = {{from_py_function}}(obj);
    779     if ({{error_condition}})
    780         return 0;
    781     *({{dtype}} *) itemp = value;
    782     return 1;
    783 }
    784 {{endif}}
    785 
    786 
    787 /////////////// MemviewObjectToObject.proto ///////////////
    788 
    789 /* Function callbacks (for memoryview object) for dtype object */
    790 static PyObject *{{get_function}}(const char *itemp); /* proto */
    791 static int {{set_function}}(const char *itemp, PyObject *obj); /* proto */
    792 
    793 
    794 /////////////// MemviewObjectToObject ///////////////
    795 
    796 static PyObject *{{get_function}}(const char *itemp) {
    797     PyObject *result = *(PyObject **) itemp;
    798     Py_INCREF(result);
    799     return result;
    800 }
    801 
    802 static int {{set_function}}(const char *itemp, PyObject *obj) {
    803     Py_INCREF(obj);
    804     Py_DECREF(*(PyObject **) itemp);
    805     *(PyObject **) itemp = obj;
    806     return 1;
    807 }
    808 
    809 /////////// ToughSlice //////////
    810 
    811 /* Dimension is indexed with 'start:stop:step' */
    812 
    813 if (unlikely(__pyx_memoryview_slice_memviewslice(
    814     &{{dst}},
    815     {{src}}.shape[{{dim}}], {{src}}.strides[{{dim}}], {{src}}.suboffsets[{{dim}}],
    816     {{dim}},
    817     {{new_ndim}},
    818     &{{suboffset_dim}},
    819     {{start}},
    820     {{stop}},
    821     {{step}},
    822     {{int(have_start)}},
    823     {{int(have_stop)}},
    824     {{int(have_step)}},
    825     1) < 0))
    826 {
    827     {{error_goto}}
    828 }
    829 
    830 
    831 ////////// SimpleSlice //////////
    832 
    833 /* Dimension is indexed with ':' only */
    834 
    835 {{dst}}.shape[{{new_ndim}}] = {{src}}.shape[{{dim}}];
    836 {{dst}}.strides[{{new_ndim}}] = {{src}}.strides[{{dim}}];
    837 
    838 {{if access == 'direct'}}
    839     {{dst}}.suboffsets[{{new_ndim}}] = -1;
    840 {{else}}
    841     {{dst}}.suboffsets[{{new_ndim}}] = {{src}}.suboffsets[{{dim}}];
    842     if ({{src}}.suboffsets[{{dim}}] >= 0)
    843         {{suboffset_dim}} = {{new_ndim}};
    844 {{endif}}
    845 
    846 
    847 ////////// SliceIndex //////////
    848 
    849 // Dimension is indexed with an integer, we could use the ToughSlice
    850 // approach, but this is faster
    851 
    852 {
    853     Py_ssize_t __pyx_tmp_idx = {{idx}};
    854     Py_ssize_t __pyx_tmp_shape = {{src}}.shape[{{dim}}];
    855     Py_ssize_t __pyx_tmp_stride = {{src}}.strides[{{dim}}];
    856     if ({{wraparound}} && (__pyx_tmp_idx < 0))
    857         __pyx_tmp_idx += __pyx_tmp_shape;
    858 
    859     if ({{boundscheck}} && (__pyx_tmp_idx < 0 || __pyx_tmp_idx >= __pyx_tmp_shape)) {
    860         {{if not have_gil}}
    861             #ifdef WITH_THREAD
    862             PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();
    863             #endif
    864         {{endif}}
    865 
    866         PyErr_SetString(PyExc_IndexError, "Index out of bounds (axis {{dim}})");
    867 
    868         {{if not have_gil}}
    869             #ifdef WITH_THREAD
    870             PyGILState_Release(__pyx_gilstate_save);
    871             #endif
    872         {{endif}}
    873 
    874         {{error_goto}}
    875     }
    876 
    877     {{if all_dimensions_direct}}
    878         {{dst}}.data += __pyx_tmp_idx * __pyx_tmp_stride;
    879     {{else}}
    880         if ({{suboffset_dim}} < 0) {
    881             {{dst}}.data += __pyx_tmp_idx * __pyx_tmp_stride;
    882 
    883             /* This dimension is the first dimension, or is preceded by    */
    884             /* direct or indirect dimensions that are indexed away.        */
    885             /* Hence suboffset_dim must be less than zero, and we can have */
    886             /* our data pointer refer to another block by dereferencing.   */
    887             /*   slice.data -> B -> C     becomes     slice.data -> C      */
    888 
    889             {{if indirect}}
    890               {
    891                 Py_ssize_t __pyx_tmp_suboffset = {{src}}.suboffsets[{{dim}}];
    892 
    893                 {{if generic}}
    894                     if (__pyx_tmp_suboffset >= 0)
    895                 {{endif}}
    896 
    897                     {{dst}}.data = *((char **) {{dst}}.data) + __pyx_tmp_suboffset;
    898               }
    899             {{endif}}
    900 
    901         } else {
    902             {{dst}}.suboffsets[{{suboffset_dim}}] += __pyx_tmp_idx * __pyx_tmp_stride;
    903 
    904             /* Note: dimension can not be indirect, the compiler will have */
    905             /*       issued an error */
    906         }
    907 
    908     {{endif}}
    909 }
    910 
    911 
    912 ////////// FillStrided1DScalar.proto //////////
    913 
    914 static void
    915 __pyx_fill_slice_{{dtype_name}}({{type_decl}} *p, Py_ssize_t extent, Py_ssize_t stride,
    916                                 size_t itemsize, void *itemp);
    917 
    918 ////////// FillStrided1DScalar //////////
    919 
    920 /* Fill a slice with a scalar value. The dimension is direct and strided or contiguous */
    921 /* This can be used as a callback for the memoryview object to efficienty assign a scalar */
    922 /* Currently unused */
    923 static void
    924 __pyx_fill_slice_{{dtype_name}}({{type_decl}} *p, Py_ssize_t extent, Py_ssize_t stride,
    925                                 size_t itemsize, void *itemp)
    926 {
    927     Py_ssize_t i;
    928     {{type_decl}} item = *(({{type_decl}} *) itemp);
    929     {{type_decl}} *endp;
    930 
    931     stride /= sizeof({{type_decl}});
    932     endp = p + stride * extent;
    933 
    934     while (p < endp) {
    935         *p = item;
    936         p += stride;
    937     }
    938 }
    939