LCOV - code coverage report
Current view: | top level - Objects - memoryobject.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 274 | 1391 | 19.7 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 34 | 107 | 31.8 %
|  |  | Branches: | 117 | 1058 | 11.1 %

               Branch data     Line data    Source code
           1                 :            : /*
           2                 :            :  * Memoryview object implementation
           3                 :            :  * --------------------------------
           4                 :            :  *
           5                 :            :  *   This implementation is a complete rewrite contributed by Stefan Krah in
           6                 :            :  *   Python 3.3.  Substantial credit goes to Antoine Pitrou (who had already
           7                 :            :  *   fortified and rewritten the previous implementation) and Nick Coghlan
           8                 :            :  *   (who came up with the idea of the ManagedBuffer) for analyzing the complex
           9                 :            :  *   ownership rules.
          10                 :            :  *
          11                 :            :  */
          12                 :            :
          13                 :            : #include "Python.h"
          14                 :            : #include "pycore_abstract.h"      // _PyIndex_Check()
          15                 :            : #include "pycore_object.h"        // _PyObject_GC_UNTRACK()
          16                 :            : #include "pycore_strhex.h"        // _Py_strhex_with_sep()
          17                 :            : #include <stddef.h>               // offsetof()
          18                 :            :
          19                 :            : /*[clinic input]
          20                 :            : class memoryview "PyMemoryViewObject *" "&PyMemoryView_Type"
          21                 :            : [clinic start generated code]*/
          22                 :            : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e2e49d2192835219]*/
          23                 :            :
          24                 :            : #include "clinic/memoryobject.c.h"
          25                 :            :
          26                 :            : /****************************************************************************/
          27                 :            : /*                           ManagedBuffer Object                           */
          28                 :            : /****************************************************************************/
          29                 :            :
          30                 :            : /*
          31                 :            :    ManagedBuffer Object:
          32                 :            :    ---------------------
          33                 :            :
          34                 :            :      The purpose of this object is to facilitate the handling of chained
          35                 :            :      memoryviews that have the same underlying exporting object. PEP-3118
          36                 :            :      allows the underlying object to change while a view is exported. This
          37                 :            :      could lead to unexpected results when constructing a new memoryview
          38                 :            :      from an existing memoryview.
          39                 :            :
          40                 :            :      Rather than repeatedly redirecting buffer requests to the original base
          41                 :            :      object, all chained memoryviews use a single buffer snapshot. This
          42                 :            :      snapshot is generated by the constructor _PyManagedBuffer_FromObject().
          43                 :            :
          44                 :            :    Ownership rules:
          45                 :            :    ----------------
          46                 :            :
          47                 :            :      The master buffer inside a managed buffer is filled in by the original
          48                 :            :      base object. shape, strides, suboffsets and format are read-only for
          49                 :            :      all consumers.
          50                 :            :
          51                 :            :      A memoryview's buffer is a private copy of the exporter's buffer. shape,
          52                 :            :      strides and suboffsets belong to the memoryview and are thus writable.
          53                 :            :
          54                 :            :      If a memoryview itself exports several buffers via memory_getbuf(), all
          55                 :            :      buffer copies share shape, strides and suboffsets. In this case, the
          56                 :            :      arrays are NOT writable.
          57                 :            :
          58                 :            :    Reference count assumptions:
          59                 :            :    ----------------------------
          60                 :            :
          61                 :            :      The 'obj' member of a Py_buffer must either be NULL or refer to the
          62                 :            :      exporting base object. In the Python codebase, all getbufferprocs
          63                 :            :      return a new reference to view.obj (example: bytes_buffer_getbuffer()).
          64                 :            :
          65                 :            :      PyBuffer_Release() decrements view.obj (if non-NULL), so the
          66                 :            :      releasebufferprocs must NOT decrement view.obj.
          67                 :            : */
          68                 :            :
          69                 :            :
          70                 :            : static inline _PyManagedBufferObject *
          71                 :       5241 : mbuf_alloc(void)
          72                 :            : {
          73                 :            :     _PyManagedBufferObject *mbuf;
          74                 :            :
          75                 :            :     mbuf = (_PyManagedBufferObject *)
          76                 :       5241 :         PyObject_GC_New(_PyManagedBufferObject, &_PyManagedBuffer_Type);
          77         [ -  + ]:       5241 :     if (mbuf == NULL)
          78                 :          0 :         return NULL;
          79                 :       5241 :     mbuf->flags = 0;
          80                 :       5241 :     mbuf->exports = 0;
          81                 :       5241 :     mbuf->master.obj = NULL;
          82                 :       5241 :     _PyObject_GC_TRACK(mbuf);
          83                 :            :
          84                 :       5241 :     return mbuf;
          85                 :            : }
          86                 :            :
          87                 :            : static PyObject *
          88                 :        389 : _PyManagedBuffer_FromObject(PyObject *base)
          89                 :            : {
          90                 :            :     _PyManagedBufferObject *mbuf;
          91                 :            :
          92                 :        389 :     mbuf = mbuf_alloc();
          93         [ -  + ]:        389 :     if (mbuf == NULL)
          94                 :          0 :         return NULL;
          95                 :            :
          96         [ -  + ]:        389 :     if (PyObject_GetBuffer(base, &mbuf->master, PyBUF_FULL_RO) < 0) {
          97                 :          0 :         mbuf->master.obj = NULL;
          98                 :          0 :         Py_DECREF(mbuf);
          99                 :          0 :         return NULL;
         100                 :            :     }
         101                 :            :
         102                 :        389 :     return (PyObject *)mbuf;
         103                 :            : }
         104                 :            :
         105                 :            : static void
         106                 :      10482 : mbuf_release(_PyManagedBufferObject *self)
         107                 :            : {
         108         [ +  + ]:      10482 :     if (self->flags&_Py_MANAGED_BUFFER_RELEASED)
         109                 :       5241 :         return;
         110                 :            :
         111                 :            :     /* NOTE: at this point self->exports can still be > 0 if this function
         112                 :            :        is called from mbuf_clear() to break up a reference cycle. */
         113                 :       5241 :     self->flags |= _Py_MANAGED_BUFFER_RELEASED;
         114                 :            :
         115                 :            :     /* PyBuffer_Release() decrements master->obj and sets it to NULL. */
         116                 :       5241 :     _PyObject_GC_UNTRACK(self);
         117                 :       5241 :     PyBuffer_Release(&self->master);
         118                 :            : }
         119                 :            :
         120                 :            : static void
         121                 :       5241 : mbuf_dealloc(_PyManagedBufferObject *self)
         122                 :            : {
         123                 :            :     assert(self->exports == 0);
         124                 :       5241 :     mbuf_release(self);
         125         [ -  + ]:       5241 :     if (self->flags&_Py_MANAGED_BUFFER_FREE_FORMAT)
         126                 :          0 :         PyMem_Free(self->master.format);
         127                 :       5241 :     PyObject_GC_Del(self);
         128                 :       5241 : }
         129                 :            :
         130                 :            : static int
         131                 :         72 : mbuf_traverse(_PyManagedBufferObject *self, visitproc visit, void *arg)
         132                 :            : {
         133   [ +  -  -  + ]:         72 :     Py_VISIT(self->master.obj);
         134                 :         72 :     return 0;
         135                 :            : }
         136                 :            :
         137                 :            : static int
         138                 :          0 : mbuf_clear(_PyManagedBufferObject *self)
         139                 :            : {
         140                 :            :     assert(self->exports >= 0);
         141                 :          0 :     mbuf_release(self);
         142                 :          0 :     return 0;
         143                 :            : }
         144                 :            :
         145                 :            : PyTypeObject _PyManagedBuffer_Type = {
         146                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
         147                 :            :     "managedbuffer",
         148                 :            :     sizeof(_PyManagedBufferObject),
         149                 :            :     0,
         150                 :            :     (destructor)mbuf_dealloc,                /* tp_dealloc */
         151                 :            :     0,                                       /* tp_vectorcall_offset */
         152                 :            :     0,                                       /* tp_getattr */
         153                 :            :     0,                                       /* tp_setattr */
         154                 :            :     0,                                       /* tp_as_async */
         155                 :            :     0,                                       /* tp_repr */
         156                 :            :     0,                                       /* tp_as_number */
         157                 :            :     0,                                       /* tp_as_sequence */
         158                 :            :     0,                                       /* tp_as_mapping */
         159                 :            :     0,                                       /* tp_hash */
         160                 :            :     0,                                       /* tp_call */
         161                 :            :     0,                                       /* tp_str */
         162                 :            :     PyObject_GenericGetAttr,                 /* tp_getattro */
         163                 :            :     0,                                       /* tp_setattro */
         164                 :            :     0,                                       /* tp_as_buffer */
         165                 :            :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
         166                 :            :     0,                                       /* tp_doc */
         167                 :            :     (traverseproc)mbuf_traverse,             /* tp_traverse */
         168                 :            :     (inquiry)mbuf_clear                      /* tp_clear */
         169                 :            : };
         170                 :            :
         171                 :            :
         172                 :            : /****************************************************************************/
         173                 :            : /*                             MemoryView Object                            */
         174                 :            : /****************************************************************************/
         175                 :            :
         176                 :            : /* In the process of breaking reference cycles mbuf_release() can be
         177                 :            :    called before memory_release(). */
         178                 :            : #define BASE_INACCESSIBLE(mv) \
         179                 :            :     (((PyMemoryViewObject *)mv)->flags&_Py_MEMORYVIEW_RELEASED || \
         180                 :            :      ((PyMemoryViewObject *)mv)->mbuf->flags&_Py_MANAGED_BUFFER_RELEASED)
         181                 :            :
         182                 :            : #define CHECK_RELEASED(mv) \
         183                 :            :     if (BASE_INACCESSIBLE(mv)) {                                  \
         184                 :            :         PyErr_SetString(PyExc_ValueError,                         \
         185                 :            :             "operation forbidden on released memoryview object"); \
         186                 :            :         return NULL;                                              \
         187                 :            :     }
         188                 :            :
         189                 :            : #define CHECK_RELEASED_INT(mv) \
         190                 :            :     if (BASE_INACCESSIBLE(mv)) {                                  \
         191                 :            :         PyErr_SetString(PyExc_ValueError,                         \
         192                 :            :             "operation forbidden on released memoryview object"); \
         193                 :            :         return -1;                                                \
         194                 :            :     }
         195                 :            :
         196                 :            : /* See gh-92888. These macros signal that we need to check the memoryview
         197                 :            :    again due to possible read after frees. */
         198                 :            : #define CHECK_RELEASED_AGAIN(mv) CHECK_RELEASED(mv)
         199                 :            : #define CHECK_RELEASED_INT_AGAIN(mv) CHECK_RELEASED_INT(mv)
         200                 :            :
         201                 :            : #define CHECK_LIST_OR_TUPLE(v) \
         202                 :            :     if (!PyList_Check(v) && !PyTuple_Check(v)) { \
         203                 :            :         PyErr_SetString(PyExc_TypeError,         \
         204                 :            :             #v " must be a list or a tuple");    \
         205                 :            :         return NULL;                             \
         206                 :            :     }
         207                 :            :
         208                 :            : #define VIEW_ADDR(mv) (&((PyMemoryViewObject *)mv)->view)
         209                 :            :
         210                 :            : /* Check for the presence of suboffsets in the first dimension. */
         211                 :            : #define HAVE_PTR(suboffsets, dim) (suboffsets && suboffsets[dim] >= 0)
         212                 :            : /* Adjust ptr if suboffsets are present. */
         213                 :            : #define ADJUST_PTR(ptr, suboffsets, dim) \
         214                 :            :     (HAVE_PTR(suboffsets, dim) ? *((char**)ptr) + suboffsets[dim] : ptr)
         215                 :            :
         216                 :            : /* Memoryview buffer properties */
         217                 :            : #define MV_C_CONTIGUOUS(flags) (flags&(_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_C))
         218                 :            : #define MV_F_CONTIGUOUS(flags) \
         219                 :            :     (flags&(_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_FORTRAN))
         220                 :            : #define MV_ANY_CONTIGUOUS(flags) \
         221                 :            :     (flags&(_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_C|_Py_MEMORYVIEW_FORTRAN))
         222                 :            :
         223                 :            : /* Fast contiguity test. Caller must ensure suboffsets==NULL and ndim==1. */
         224                 :            : #define MV_CONTIGUOUS_NDIM1(view) \
         225                 :            :     ((view)->shape[0] == 1 || (view)->strides[0] == (view)->itemsize)
         226                 :            :
         227                 :            : /* getbuffer() requests */
         228                 :            : #define REQ_INDIRECT(flags) ((flags&PyBUF_INDIRECT) == PyBUF_INDIRECT)
         229                 :            : #define REQ_C_CONTIGUOUS(flags) ((flags&PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS)
         230                 :            : #define REQ_F_CONTIGUOUS(flags) ((flags&PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS)
         231                 :            : #define REQ_ANY_CONTIGUOUS(flags) ((flags&PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS)
         232                 :            : #define REQ_STRIDES(flags) ((flags&PyBUF_STRIDES) == PyBUF_STRIDES)
         233                 :            : #define REQ_SHAPE(flags) ((flags&PyBUF_ND) == PyBUF_ND)
         234                 :            : #define REQ_WRITABLE(flags) (flags&PyBUF_WRITABLE)
         235                 :            : #define REQ_FORMAT(flags) (flags&PyBUF_FORMAT)
         236                 :            :
         237                 :            :
         238                 :            : /**************************************************************************/
         239                 :            : /*                       Copy memoryview buffers                          */
         240                 :            : /**************************************************************************/
         241                 :            :
         242                 :            : /* The functions in this section take a source and a destination buffer
         243                 :            :    with the same logical structure: format, itemsize, ndim and shape
         244                 :            :    are identical, with ndim > 0.
         245                 :            :
         246                 :            :    NOTE: All buffers are assumed to have PyBUF_FULL information, which
         247                 :            :    is the case for memoryviews! */
         248                 :            :
         249                 :            :
         250                 :            : /* Assumptions: ndim >= 1. The macro tests for a corner case that should
         251                 :            :    perhaps be explicitly forbidden in the PEP. */
         252                 :            : #define HAVE_SUBOFFSETS_IN_LAST_DIM(view) \
         253                 :            :     (view->suboffsets && view->suboffsets[dest->ndim-1] >= 0)
         254                 :            :
         255                 :            : static inline int
         256                 :          0 : last_dim_is_contiguous(const Py_buffer *dest, const Py_buffer *src)
         257                 :            : {
         258                 :            :     assert(dest->ndim > 0 && src->ndim > 0);
         259         [ #  # ]:          0 :     return (!HAVE_SUBOFFSETS_IN_LAST_DIM(dest) &&
         260   [ #  #  #  # ]:          0 :             !HAVE_SUBOFFSETS_IN_LAST_DIM(src) &&
         261   [ #  #  #  # ]:          0 :             dest->strides[dest->ndim-1] == dest->itemsize &&
         262         [ #  # ]:          0 :             src->strides[src->ndim-1] == src->itemsize);
         263                 :            : }
         264                 :            :
         265                 :            : /* This is not a general function for determining format equivalence.
         266                 :            :    It is used in copy_single() and copy_buffer() to weed out non-matching
         267                 :            :    formats. Skipping the '@' character is specifically used in slice
         268                 :            :    assignments, where the lvalue is already known to have a single character
         269                 :            :    format. This is a performance hack that could be rewritten (if properly
         270                 :            :    benchmarked). */
         271                 :            : static inline int
         272                 :          0 : equiv_format(const Py_buffer *dest, const Py_buffer *src)
         273                 :            : {
         274                 :            :     const char *dfmt, *sfmt;
         275                 :            :
         276                 :            :     assert(dest->format && src->format);
         277         [ #  # ]:          0 :     dfmt = dest->format[0] == '@' ? dest->format+1 : dest->format;
         278         [ #  # ]:          0 :     sfmt = src->format[0] == '@' ? src->format+1 : src->format;
         279                 :            :
         280         [ #  # ]:          0 :     if (strcmp(dfmt, sfmt) != 0 ||
         281         [ #  # ]:          0 :         dest->itemsize != src->itemsize) {
         282                 :          0 :         return 0;
         283                 :            :     }
         284                 :            :
         285                 :          0 :     return 1;
         286                 :            : }
         287                 :            :
         288                 :            : /* Two shapes are equivalent if they are either equal or identical up
         289                 :            :    to a zero element at the same position. For example, in NumPy arrays
         290                 :            :    the shapes [1, 0, 5] and [1, 0, 7] are equivalent. */
         291                 :            : static inline int
         292                 :          0 : equiv_shape(const Py_buffer *dest, const Py_buffer *src)
         293                 :            : {
         294                 :            :     int i;
         295                 :            :
         296         [ #  # ]:          0 :     if (dest->ndim != src->ndim)
         297                 :          0 :         return 0;
         298                 :            :
         299         [ #  # ]:          0 :     for (i = 0; i < dest->ndim; i++) {
         300         [ #  # ]:          0 :         if (dest->shape[i] != src->shape[i])
         301                 :          0 :             return 0;
         302         [ #  # ]:          0 :         if (dest->shape[i] == 0)
         303                 :          0 :             break;
         304                 :            :     }
         305                 :            :
         306                 :          0 :     return 1;
         307                 :            : }
         308                 :            :
         309                 :            : /* Check that the logical structure of the destination and source buffers
         310                 :            :    is identical. */
         311                 :            : static int
         312                 :          0 : equiv_structure(const Py_buffer *dest, const Py_buffer *src)
         313                 :            : {
         314   [ #  #  #  # ]:          0 :     if (!equiv_format(dest, src) ||
         315                 :          0 :         !equiv_shape(dest, src)) {
         316                 :          0 :         PyErr_SetString(PyExc_ValueError,
         317                 :            :             "memoryview assignment: lvalue and rvalue have different "
         318                 :            :             "structures");
         319                 :          0 :         return 0;
         320                 :            :     }
         321                 :            :
         322                 :          0 :     return 1;
         323                 :            : }
         324                 :            :
         325                 :            : /* Base case for recursive multi-dimensional copying. Contiguous arrays are
         326                 :            :    copied with very little overhead. Assumptions: ndim == 1, mem == NULL or
         327                 :            :    sizeof(mem) == shape[0] * itemsize. */
         328                 :            : static void
         329                 :          0 : copy_base(const Py_ssize_t *shape, Py_ssize_t itemsize,
         330                 :            :           char *dptr, const Py_ssize_t *dstrides, const Py_ssize_t *dsuboffsets,
         331                 :            :           char *sptr, const Py_ssize_t *sstrides, const Py_ssize_t *ssuboffsets,
         332                 :            :           char *mem)
         333                 :            : {
         334         [ #  # ]:          0 :     if (mem == NULL) { /* contiguous */
         335                 :          0 :         Py_ssize_t size = shape[0] * itemsize;
         336   [ #  #  #  # ]:          0 :         if (dptr + size < sptr || sptr + size < dptr)
         337                 :          0 :             memcpy(dptr, sptr, size); /* no overlapping */
         338                 :            :         else
         339                 :          0 :             memmove(dptr, sptr, size);
         340                 :            :     }
         341                 :            :     else {
         342                 :            :         char *p;
         343                 :            :         Py_ssize_t i;
         344         [ #  # ]:          0 :         for (i=0, p=mem; i < shape[0]; p+=itemsize, sptr+=sstrides[0], i++) {
         345   [ #  #  #  # ]:          0 :             char *xsptr = ADJUST_PTR(sptr, ssuboffsets, 0);
         346                 :          0 :             memcpy(p, xsptr, itemsize);
         347                 :            :         }
         348         [ #  # ]:          0 :         for (i=0, p=mem; i < shape[0]; p+=itemsize, dptr+=dstrides[0], i++) {
         349   [ #  #  #  # ]:          0 :             char *xdptr = ADJUST_PTR(dptr, dsuboffsets, 0);
         350                 :          0 :             memcpy(xdptr, p, itemsize);
         351                 :            :         }
         352                 :            :     }
         353                 :            :
         354                 :          0 : }
         355                 :            :
         356                 :            : /* Recursively copy a source buffer to a destination buffer. The two buffers
         357                 :            :    have the same ndim, shape and itemsize. */
         358                 :            : static void
         359                 :          0 : copy_rec(const Py_ssize_t *shape, Py_ssize_t ndim, Py_ssize_t itemsize,
         360                 :            :          char *dptr, const Py_ssize_t *dstrides, const Py_ssize_t *dsuboffsets,
         361                 :            :          char *sptr, const Py_ssize_t *sstrides, const Py_ssize_t *ssuboffsets,
         362                 :            :          char *mem)
         363                 :            : {
         364                 :            :     Py_ssize_t i;
         365                 :            :
         366                 :            :     assert(ndim >= 1);
         367                 :            :
         368         [ #  # ]:          0 :     if (ndim == 1) {
         369                 :          0 :         copy_base(shape, itemsize,
         370                 :            :                   dptr, dstrides, dsuboffsets,
         371                 :            :                   sptr, sstrides, ssuboffsets,
         372                 :            :                   mem);
         373                 :          0 :         return;
         374                 :            :     }
         375                 :            :
         376         [ #  # ]:          0 :     for (i = 0; i < shape[0]; dptr+=dstrides[0], sptr+=sstrides[0], i++) {
         377   [ #  #  #  # ]:          0 :         char *xdptr = ADJUST_PTR(dptr, dsuboffsets, 0);
         378   [ #  #  #  # ]:          0 :         char *xsptr = ADJUST_PTR(sptr, ssuboffsets, 0);
         379                 :            :
         380   [ #  #  #  # ]:          0 :         copy_rec(shape+1, ndim-1, itemsize,
         381                 :            :                  xdptr, dstrides+1, dsuboffsets ? dsuboffsets+1 : NULL,
         382                 :            :                  xsptr, sstrides+1, ssuboffsets ? ssuboffsets+1 : NULL,
         383                 :            :                  mem);
         384                 :            :     }
         385                 :            : }
         386                 :            :
         387                 :            : /* Faster copying of one-dimensional arrays. */
         388                 :            : static int
         389                 :          0 : copy_single(PyMemoryViewObject *self, const Py_buffer *dest, const Py_buffer *src)
         390                 :            : {
         391   [ #  #  #  # ]:          0 :     CHECK_RELEASED_INT_AGAIN(self);
         392                 :          0 :     char *mem = NULL;
         393                 :            :
         394                 :            :     assert(dest->ndim == 1);
         395                 :            :
         396         [ #  # ]:          0 :     if (!equiv_structure(dest, src))
         397                 :          0 :         return -1;
         398                 :            :
         399         [ #  # ]:          0 :     if (!last_dim_is_contiguous(dest, src)) {
         400                 :          0 :         mem = PyMem_Malloc(dest->shape[0] * dest->itemsize);
         401         [ #  # ]:          0 :         if (mem == NULL) {
         402                 :          0 :             PyErr_NoMemory();
         403                 :          0 :             return -1;
         404                 :            :         }
         405                 :            :     }
         406                 :            :
         407                 :          0 :     copy_base(dest->shape, dest->itemsize,
         408                 :          0 :               dest->buf, dest->strides, dest->suboffsets,
         409                 :          0 :               src->buf, src->strides, src->suboffsets,
         410                 :            :               mem);
         411                 :            :
         412         [ #  # ]:          0 :     if (mem)
         413                 :          0 :         PyMem_Free(mem);
         414                 :            :
         415                 :          0 :     return 0;
         416                 :            : }
         417                 :            :
         418                 :            : /* Recursively copy src to dest. Both buffers must have the same basic
         419                 :            :    structure. Copying is atomic, the function never fails with a partial
         420                 :            :    copy. */
         421                 :            : static int
         422                 :          0 : copy_buffer(const Py_buffer *dest, const Py_buffer *src)
         423                 :            : {
         424                 :          0 :     char *mem = NULL;
         425                 :            :
         426                 :            :     assert(dest->ndim > 0);
         427                 :            :
         428         [ #  # ]:          0 :     if (!equiv_structure(dest, src))
         429                 :          0 :         return -1;
         430                 :            :
         431         [ #  # ]:          0 :     if (!last_dim_is_contiguous(dest, src)) {
         432                 :          0 :         mem = PyMem_Malloc(dest->shape[dest->ndim-1] * dest->itemsize);
         433         [ #  # ]:          0 :         if (mem == NULL) {
         434                 :          0 :             PyErr_NoMemory();
         435                 :          0 :             return -1;
         436                 :            :         }
         437                 :            :     }
         438                 :            :
         439                 :          0 :     copy_rec(dest->shape, dest->ndim, dest->itemsize,
         440                 :          0 :              dest->buf, dest->strides, dest->suboffsets,
         441                 :          0 :              src->buf, src->strides, src->suboffsets,
         442                 :            :              mem);
         443                 :            :
         444         [ #  # ]:          0 :     if (mem)
         445                 :          0 :         PyMem_Free(mem);
         446                 :            :
         447                 :          0 :     return 0;
         448                 :            : }
         449                 :            :
         450                 :            : /* Initialize strides for a C-contiguous array. */
         451                 :            : static inline void
         452                 :          0 : init_strides_from_shape(Py_buffer *view)
         453                 :            : {
         454                 :            :     Py_ssize_t i;
         455                 :            :
         456                 :            :     assert(view->ndim > 0);
         457                 :            :
         458                 :          0 :     view->strides[view->ndim-1] = view->itemsize;
         459         [ #  # ]:          0 :     for (i = view->ndim-2; i >= 0; i--)
         460                 :          0 :         view->strides[i] = view->strides[i+1] * view->shape[i+1];
         461                 :          0 : }
         462                 :            :
         463                 :            : /* Initialize strides for a Fortran-contiguous array. */
         464                 :            : static inline void
         465                 :          0 : init_fortran_strides_from_shape(Py_buffer *view)
         466                 :            : {
         467                 :            :     Py_ssize_t i;
         468                 :            :
         469                 :            :     assert(view->ndim > 0);
         470                 :            :
         471                 :          0 :     view->strides[0] = view->itemsize;
         472         [ #  # ]:          0 :     for (i = 1; i < view->ndim; i++)
         473                 :          0 :         view->strides[i] = view->strides[i-1] * view->shape[i-1];
         474                 :          0 : }
         475                 :            :
         476                 :            : /* Copy src to a contiguous representation. order is one of 'C', 'F' (Fortran)
         477                 :            :    or 'A' (Any). Assumptions: src has PyBUF_FULL information, src->ndim >= 1,
         478                 :            :    len(mem) == src->len. */
         479                 :            : static int
         480                 :          0 : buffer_to_contiguous(char *mem, const Py_buffer *src, char order)
         481                 :            : {
         482                 :            :     Py_buffer dest;
         483                 :            :     Py_ssize_t *strides;
         484                 :            :     int ret;
         485                 :            :
         486                 :            :     assert(src->ndim >= 1);
         487                 :            :     assert(src->shape != NULL);
         488                 :            :     assert(src->strides != NULL);
         489                 :            :
         490                 :          0 :     strides = PyMem_Malloc(src->ndim * (sizeof *src->strides));
         491         [ #  # ]:          0 :     if (strides == NULL) {
         492                 :          0 :         PyErr_NoMemory();
         493                 :          0 :         return -1;
         494                 :            :     }
         495                 :            :
         496                 :            :     /* initialize dest */
         497                 :          0 :     dest = *src;
         498                 :          0 :     dest.buf = mem;
         499                 :            :     /* shape is constant and shared: the logical representation of the
         500                 :            :        array is unaltered. */
         501                 :            :
         502                 :            :     /* The physical representation determined by strides (and possibly
         503                 :            :        suboffsets) may change. */
         504                 :          0 :     dest.strides = strides;
         505   [ #  #  #  # ]:          0 :     if (order == 'C' || order == 'A') {
         506                 :          0 :         init_strides_from_shape(&dest);
         507                 :            :     }
         508                 :            :     else {
         509                 :          0 :         init_fortran_strides_from_shape(&dest);
         510                 :            :     }
         511                 :            :
         512                 :          0 :     dest.suboffsets = NULL;
         513                 :            :
         514                 :          0 :     ret = copy_buffer(&dest, src);
         515                 :            :
         516                 :          0 :     PyMem_Free(strides);
         517                 :          0 :     return ret;
         518                 :            : }
         519                 :            :
         520                 :            :
         521                 :            : /****************************************************************************/
         522                 :            : /*                               Constructors                               */
         523                 :            : /****************************************************************************/
         524                 :            :
         525                 :            : /* Initialize values that are shared with the managed buffer. */
         526                 :            : static inline void
         527                 :       5630 : init_shared_values(Py_buffer *dest, const Py_buffer *src)
         528                 :            : {
         529                 :       5630 :     dest->obj = src->obj;
         530                 :       5630 :     dest->buf = src->buf;
         531                 :       5630 :     dest->len = src->len;
         532                 :       5630 :     dest->itemsize = src->itemsize;
         533                 :       5630 :     dest->readonly = src->readonly;
         534         [ +  + ]:       5630 :     dest->format = src->format ? src->format : "B";
         535                 :       5630 :     dest->internal = src->internal;
         536                 :       5630 : }
         537                 :            :
         538                 :            : /* Copy shape and strides. Reconstruct missing values. */
         539                 :            : static void
         540                 :       5627 : init_shape_strides(Py_buffer *dest, const Py_buffer *src)
         541                 :            : {
         542                 :            :     Py_ssize_t i;
         543                 :            :
         544         [ -  + ]:       5627 :     if (src->ndim == 0) {
         545                 :          0 :         dest->shape = NULL;
         546                 :          0 :         dest->strides = NULL;
         547                 :          0 :         return;
         548                 :            :     }
         549         [ +  - ]:       5627 :     if (src->ndim == 1) {
         550         [ +  - ]:       5627 :         dest->shape[0] = src->shape ? src->shape[0] : src->len / src->itemsize;
         551         [ +  + ]:       5627 :         dest->strides[0] = src->strides ? src->strides[0] : src->itemsize;
         552                 :       5627 :         return;
         553                 :            :     }
         554                 :            :
         555         [ #  # ]:          0 :     for (i = 0; i < src->ndim; i++)
         556                 :          0 :         dest->shape[i] = src->shape[i];
         557         [ #  # ]:          0 :     if (src->strides) {
         558         [ #  # ]:          0 :         for (i = 0; i < src->ndim; i++)
         559                 :          0 :             dest->strides[i] = src->strides[i];
         560                 :            :     }
         561                 :            :     else {
         562                 :          0 :         init_strides_from_shape(dest);
         563                 :            :     }
         564                 :            : }
         565                 :            :
         566                 :            : static inline void
         567                 :       5627 : init_suboffsets(Py_buffer *dest, const Py_buffer *src)
         568                 :            : {
         569                 :            :     Py_ssize_t i;
         570                 :            :
         571         [ +  - ]:       5627 :     if (src->suboffsets == NULL) {
         572                 :       5627 :         dest->suboffsets = NULL;
         573                 :       5627 :         return;
         574                 :            :     }
         575         [ #  # ]:          0 :     for (i = 0; i < src->ndim; i++)
         576                 :          0 :         dest->suboffsets[i] = src->suboffsets[i];
         577                 :            : }
         578                 :            :
         579                 :            : /* len = product(shape) * itemsize */
         580                 :            : static inline void
         581                 :        386 : init_len(Py_buffer *view)
         582                 :            : {
         583                 :            :     Py_ssize_t i, len;
         584                 :            :
         585                 :        386 :     len = 1;
         586         [ +  + ]:        772 :     for (i = 0; i < view->ndim; i++)
         587                 :        386 :         len *= view->shape[i];
         588                 :        386 :     len *= view->itemsize;
         589                 :            :
         590                 :        386 :     view->len = len;
         591                 :        386 : }
         592                 :            :
         593                 :            : /* Initialize memoryview buffer properties. */
         594                 :            : static void
         595                 :       6016 : init_flags(PyMemoryViewObject *mv)
         596                 :            : {
         597                 :       6016 :     const Py_buffer *view = &mv->view;
         598                 :       6016 :     int flags = 0;
         599                 :            :
         600      [ -  +  - ]:       6016 :     switch (view->ndim) {
         601                 :          0 :     case 0:
         602                 :          0 :         flags |= (_Py_MEMORYVIEW_SCALAR|_Py_MEMORYVIEW_C|
         603                 :            :                   _Py_MEMORYVIEW_FORTRAN);
         604                 :          0 :         break;
         605                 :       6016 :     case 1:
         606   [ +  +  +  - ]:       6016 :         if (MV_CONTIGUOUS_NDIM1(view))
         607                 :       6016 :             flags |= (_Py_MEMORYVIEW_C|_Py_MEMORYVIEW_FORTRAN);
         608                 :       6016 :         break;
         609                 :          0 :     default:
         610         [ #  # ]:          0 :         if (PyBuffer_IsContiguous(view, 'C'))
         611                 :          0 :             flags |= _Py_MEMORYVIEW_C;
         612         [ #  # ]:          0 :         if (PyBuffer_IsContiguous(view, 'F'))
         613                 :          0 :             flags |= _Py_MEMORYVIEW_FORTRAN;
         614                 :          0 :         break;
         615                 :            :     }
         616                 :            :
         617         [ -  + ]:       6016 :     if (view->suboffsets) {
         618                 :          0 :         flags |= _Py_MEMORYVIEW_PIL;
         619                 :          0 :         flags &= ~(_Py_MEMORYVIEW_C|_Py_MEMORYVIEW_FORTRAN);
         620                 :            :     }
         621                 :            :
         622                 :       6016 :     mv->flags = flags;
         623                 :       6016 : }
         624                 :            :
         625                 :            : /* Allocate a new memoryview and perform basic initialization. New memoryviews
         626                 :            :    are exclusively created through the mbuf_add functions. */
         627                 :            : static inline PyMemoryViewObject *
         628                 :       5630 : memory_alloc(int ndim)
         629                 :            : {
         630                 :            :     PyMemoryViewObject *mv;
         631                 :            :
         632                 :            :     mv = (PyMemoryViewObject *)
         633                 :       5630 :         PyObject_GC_NewVar(PyMemoryViewObject, &PyMemoryView_Type, 3*ndim);
         634         [ -  + ]:       5630 :     if (mv == NULL)
         635                 :          0 :         return NULL;
         636                 :            :
         637                 :       5630 :     mv->mbuf = NULL;
         638                 :       5630 :     mv->hash = -1;
         639                 :       5630 :     mv->flags = 0;
         640                 :       5630 :     mv->exports = 0;
         641                 :       5630 :     mv->view.ndim = ndim;
         642                 :       5630 :     mv->view.shape = mv->ob_array;
         643                 :       5630 :     mv->view.strides = mv->ob_array + ndim;
         644                 :       5630 :     mv->view.suboffsets = mv->ob_array + 2 * ndim;
         645                 :       5630 :     mv->weakreflist = NULL;
         646                 :            :
         647                 :       5630 :     _PyObject_GC_TRACK(mv);
         648                 :       5630 :     return mv;
         649                 :            : }
         650                 :            :
         651                 :            : /*
         652                 :            :    Return a new memoryview that is registered with mbuf. If src is NULL,
         653                 :            :    use mbuf->master as the underlying buffer. Otherwise, use src.
         654                 :            :
         655                 :            :    The new memoryview has full buffer information: shape and strides
         656                 :            :    are always present, suboffsets as needed. Arrays are copied to
         657                 :            :    the memoryview's ob_array field.
         658                 :            :  */
         659                 :            : static PyObject *
         660                 :       5627 : mbuf_add_view(_PyManagedBufferObject *mbuf, const Py_buffer *src)
         661                 :            : {
         662                 :            :     PyMemoryViewObject *mv;
         663                 :            :     Py_buffer *dest;
         664                 :            :
         665         [ +  + ]:       5627 :     if (src == NULL)
         666                 :       5241 :         src = &mbuf->master;
         667                 :            :
         668         [ -  + ]:       5627 :     if (src->ndim > PyBUF_MAX_NDIM) {
         669                 :          0 :         PyErr_SetString(PyExc_ValueError,
         670                 :            :             "memoryview: number of dimensions must not exceed "
         671                 :            :             Py_STRINGIFY(PyBUF_MAX_NDIM));
         672                 :          0 :         return NULL;
         673                 :            :     }
         674                 :            :
         675                 :       5627 :     mv = memory_alloc(src->ndim);
         676         [ -  + ]:       5627 :     if (mv == NULL)
         677                 :          0 :         return NULL;
         678                 :            :
         679                 :       5627 :     dest = &mv->view;
         680                 :       5627 :     init_shared_values(dest, src);
         681                 :       5627 :     init_shape_strides(dest, src);
         682                 :       5627 :     init_suboffsets(dest, src);
         683                 :       5627 :     init_flags(mv);
         684                 :            :
         685                 :       5627 :     mv->mbuf = (_PyManagedBufferObject*)Py_NewRef(mbuf);
         686                 :       5627 :     mbuf->exports++;
         687                 :            :
         688                 :       5627 :     return (PyObject *)mv;
         689                 :            : }
         690                 :            :
         691                 :            : /* Register an incomplete view: shape, strides, suboffsets and flags still
         692                 :            :    need to be initialized. Use 'ndim' instead of src->ndim to determine the
         693                 :            :    size of the memoryview's ob_array.
         694                 :            :
         695                 :            :    Assumption: ndim <= PyBUF_MAX_NDIM. */
         696                 :            : static PyObject *
         697                 :          3 : mbuf_add_incomplete_view(_PyManagedBufferObject *mbuf, const Py_buffer *src,
         698                 :            :                          int ndim)
         699                 :            : {
         700                 :            :     PyMemoryViewObject *mv;
         701                 :            :     Py_buffer *dest;
         702                 :            :
         703         [ -  + ]:          3 :     if (src == NULL)
         704                 :          0 :         src = &mbuf->master;
         705                 :            :
         706                 :            :     assert(ndim <= PyBUF_MAX_NDIM);
         707                 :            :
         708                 :          3 :     mv = memory_alloc(ndim);
         709         [ -  + ]:          3 :     if (mv == NULL)
         710                 :          0 :         return NULL;
         711                 :            :
         712                 :          3 :     dest = &mv->view;
         713                 :          3 :     init_shared_values(dest, src);
         714                 :            :
         715                 :          3 :     mv->mbuf = (_PyManagedBufferObject*)Py_NewRef(mbuf);
         716                 :          3 :     mbuf->exports++;
         717                 :            :
         718                 :          3 :     return (PyObject *)mv;
         719                 :            : }
         720                 :            :
         721                 :            : /* Expose a raw memory area as a view of contiguous bytes. flags can be
         722                 :            :    PyBUF_READ or PyBUF_WRITE. view->format is set to "B" (unsigned bytes).
         723                 :            :    The memoryview has complete buffer information. */
         724                 :            : PyObject *
         725                 :          0 : PyMemoryView_FromMemory(char *mem, Py_ssize_t size, int flags)
         726                 :            : {
         727                 :            :     _PyManagedBufferObject *mbuf;
         728                 :            :     PyObject *mv;
         729                 :            :     int readonly;
         730                 :            :
         731                 :            :     assert(mem != NULL);
         732                 :            :     assert(flags == PyBUF_READ || flags == PyBUF_WRITE);
         733                 :            :
         734                 :          0 :     mbuf = mbuf_alloc();
         735         [ #  # ]:          0 :     if (mbuf == NULL)
         736                 :          0 :         return NULL;
         737                 :            :
         738                 :          0 :     readonly = (flags == PyBUF_WRITE) ? 0 : 1;
         739                 :          0 :     (void)PyBuffer_FillInfo(&mbuf->master, NULL, mem, size, readonly,
         740                 :            :                             PyBUF_FULL_RO);
         741                 :            :
         742                 :          0 :     mv = mbuf_add_view(mbuf, NULL);
         743                 :          0 :     Py_DECREF(mbuf);
         744                 :            :
         745                 :          0 :     return mv;
         746                 :            : }
         747                 :            :
         748                 :            : /* Create a memoryview from a given Py_buffer. For simple byte views,
         749                 :            :    PyMemoryView_FromMemory() should be used instead.
         750                 :            :    This function is the only entry point that can create a master buffer
         751                 :            :    without full information. Because of this fact init_shape_strides()
         752                 :            :    must be able to reconstruct missing values.  */
         753                 :            : PyObject *
         754                 :       4852 : PyMemoryView_FromBuffer(const Py_buffer *info)
         755                 :            : {
         756                 :            :     _PyManagedBufferObject *mbuf;
         757                 :            :     PyObject *mv;
         758                 :            :
         759         [ -  + ]:       4852 :     if (info->buf == NULL) {
         760                 :          0 :         PyErr_SetString(PyExc_ValueError,
         761                 :            :             "PyMemoryView_FromBuffer(): info->buf must not be NULL");
         762                 :          0 :         return NULL;
         763                 :            :     }
         764                 :            :
         765                 :       4852 :     mbuf = mbuf_alloc();
         766         [ -  + ]:       4852 :     if (mbuf == NULL)
         767                 :          0 :         return NULL;
         768                 :            :
         769                 :            :     /* info->obj is either NULL or a borrowed reference. This reference
         770                 :            :        should not be decremented in PyBuffer_Release(). */
         771                 :       4852 :     mbuf->master = *info;
         772                 :       4852 :     mbuf->master.obj = NULL;
         773                 :            :
         774                 :       4852 :     mv = mbuf_add_view(mbuf, NULL);
         775                 :       4852 :     Py_DECREF(mbuf);
         776                 :            :
         777                 :       4852 :     return mv;
         778                 :            : }
         779                 :            :
         780                 :            : /* Create a memoryview from an object that implements the buffer protocol.
         781                 :            :    If the object is a memoryview, the new memoryview must be registered
         782                 :            :    with the same managed buffer. Otherwise, a new managed buffer is created. */
         783                 :            : PyObject *
         784                 :        389 : PyMemoryView_FromObject(PyObject *v)
         785                 :            : {
         786                 :            :     _PyManagedBufferObject *mbuf;
         787                 :            :
         788         [ -  + ]:        389 :     if (PyMemoryView_Check(v)) {
         789                 :          0 :         PyMemoryViewObject *mv = (PyMemoryViewObject *)v;
         790   [ #  #  #  # ]:          0 :         CHECK_RELEASED(mv);
         791                 :          0 :         return mbuf_add_view(mv->mbuf, &mv->view);
         792                 :            :     }
         793         [ +  - ]:        389 :     else if (PyObject_CheckBuffer(v)) {
         794                 :            :         PyObject *ret;
         795                 :        389 :         mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(v);
         796         [ -  + ]:        389 :         if (mbuf == NULL)
         797                 :          0 :             return NULL;
         798                 :        389 :         ret = mbuf_add_view(mbuf, NULL);
         799                 :        389 :         Py_DECREF(mbuf);
         800                 :        389 :         return ret;
         801                 :            :     }
         802                 :            :
         803                 :          0 :     PyErr_Format(PyExc_TypeError,
         804                 :            :         "memoryview: a bytes-like object is required, not '%.200s'",
         805                 :          0 :         Py_TYPE(v)->tp_name);
         806                 :          0 :     return NULL;
         807                 :            : }
         808                 :            :
         809                 :            : /* Copy the format string from a base object that might vanish. */
         810                 :            : static int
         811                 :          0 : mbuf_copy_format(_PyManagedBufferObject *mbuf, const char *fmt)
         812                 :            : {
         813         [ #  # ]:          0 :     if (fmt != NULL) {
         814                 :          0 :         char *cp = PyMem_Malloc(strlen(fmt)+1);
         815         [ #  # ]:          0 :         if (cp == NULL) {
         816                 :          0 :             PyErr_NoMemory();
         817                 :          0 :             return -1;
         818                 :            :         }
         819                 :          0 :         mbuf->master.format = strcpy(cp, fmt);
         820                 :          0 :         mbuf->flags |= _Py_MANAGED_BUFFER_FREE_FORMAT;
         821                 :            :     }
         822                 :            :
         823                 :          0 :     return 0;
         824                 :            : }
         825                 :            :
         826                 :            : /*
         827                 :            :    Return a memoryview that is based on a contiguous copy of src.
         828                 :            :    Assumptions: src has PyBUF_FULL_RO information, src->ndim > 0.
         829                 :            :
         830                 :            :    Ownership rules:
         831                 :            :      1) As usual, the returned memoryview has a private copy
         832                 :            :         of src->shape, src->strides and src->suboffsets.
         833                 :            :      2) src->format is copied to the master buffer and released
         834                 :            :         in mbuf_dealloc(). The releasebufferproc of the bytes
         835                 :            :         object is NULL, so it does not matter that mbuf_release()
         836                 :            :         passes the altered format pointer to PyBuffer_Release().
         837                 :            : */
         838                 :            : static PyObject *
         839                 :          0 : memory_from_contiguous_copy(const Py_buffer *src, char order)
         840                 :            : {
         841                 :            :     _PyManagedBufferObject *mbuf;
         842                 :            :     PyMemoryViewObject *mv;
         843                 :            :     PyObject *bytes;
         844                 :            :     Py_buffer *dest;
         845                 :            :     int i;
         846                 :            :
         847                 :            :     assert(src->ndim > 0);
         848                 :            :     assert(src->shape != NULL);
         849                 :            :
         850                 :          0 :     bytes = PyBytes_FromStringAndSize(NULL, src->len);
         851         [ #  # ]:          0 :     if (bytes == NULL)
         852                 :          0 :         return NULL;
         853                 :            :
         854                 :          0 :     mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(bytes);
         855                 :          0 :     Py_DECREF(bytes);
         856         [ #  # ]:          0 :     if (mbuf == NULL)
         857                 :          0 :         return NULL;
         858                 :            :
         859         [ #  # ]:          0 :     if (mbuf_copy_format(mbuf, src->format) < 0) {
         860                 :          0 :         Py_DECREF(mbuf);
         861                 :          0 :         return NULL;
         862                 :            :     }
         863                 :            :
         864                 :          0 :     mv = (PyMemoryViewObject *)mbuf_add_incomplete_view(mbuf, NULL, src->ndim);
         865                 :          0 :     Py_DECREF(mbuf);
         866         [ #  # ]:          0 :     if (mv == NULL)
         867                 :          0 :         return NULL;
         868                 :            :
         869                 :          0 :     dest = &mv->view;
         870                 :            :
         871                 :            :     /* shared values are initialized correctly except for itemsize */
         872                 :          0 :     dest->itemsize = src->itemsize;
         873                 :            :
         874                 :            :     /* shape and strides */
         875         [ #  # ]:          0 :     for (i = 0; i < src->ndim; i++) {
         876                 :          0 :         dest->shape[i] = src->shape[i];
         877                 :            :     }
         878   [ #  #  #  # ]:          0 :     if (order == 'C' || order == 'A') {
         879                 :          0 :         init_strides_from_shape(dest);
         880                 :            :     }
         881                 :            :     else {
         882                 :          0 :         init_fortran_strides_from_shape(dest);
         883                 :            :     }
         884                 :            :     /* suboffsets */
         885                 :          0 :     dest->suboffsets = NULL;
         886                 :            :
         887                 :            :     /* flags */
         888                 :          0 :     init_flags(mv);
         889                 :            :
         890         [ #  # ]:          0 :     if (copy_buffer(dest, src) < 0) {
         891                 :          0 :         Py_DECREF(mv);
         892                 :          0 :         return NULL;
         893                 :            :     }
         894                 :            :
         895                 :          0 :     return (PyObject *)mv;
         896                 :            : }
         897                 :            :
         898                 :            : /*
         899                 :            :    Return a new memoryview object based on a contiguous exporter with
         900                 :            :    buffertype={PyBUF_READ, PyBUF_WRITE} and order={'C', 'F'ortran, or 'A'ny}.
         901                 :            :    The logical structure of the input and output buffers is the same
         902                 :            :    (i.e. tolist(input) == tolist(output)), but the physical layout in
         903                 :            :    memory can be explicitly chosen.
         904                 :            :
         905                 :            :    As usual, if buffertype=PyBUF_WRITE, the exporter's buffer must be writable,
         906                 :            :    otherwise it may be writable or read-only.
         907                 :            :
         908                 :            :    If the exporter is already contiguous with the desired target order,
         909                 :            :    the memoryview will be directly based on the exporter.
         910                 :            :
         911                 :            :    Otherwise, if the buffertype is PyBUF_READ, the memoryview will be
         912                 :            :    based on a new bytes object. If order={'C', 'A'ny}, use 'C' order,
         913                 :            :    'F'ortran order otherwise.
         914                 :            : */
         915                 :            : PyObject *
         916                 :          0 : PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char order)
         917                 :            : {
         918                 :            :     PyMemoryViewObject *mv;
         919                 :            :     PyObject *ret;
         920                 :            :     Py_buffer *view;
         921                 :            :
         922                 :            :     assert(buffertype == PyBUF_READ || buffertype == PyBUF_WRITE);
         923                 :            :     assert(order == 'C' || order == 'F' || order == 'A');
         924                 :            :
         925                 :          0 :     mv = (PyMemoryViewObject *)PyMemoryView_FromObject(obj);
         926         [ #  # ]:          0 :     if (mv == NULL)
         927                 :          0 :         return NULL;
         928                 :            :
         929                 :          0 :     view = &mv->view;
         930   [ #  #  #  # ]:          0 :     if (buffertype == PyBUF_WRITE && view->readonly) {
         931                 :          0 :         PyErr_SetString(PyExc_BufferError,
         932                 :            :             "underlying buffer is not writable");
         933                 :          0 :         Py_DECREF(mv);
         934                 :          0 :         return NULL;
         935                 :            :     }
         936                 :            :
         937         [ #  # ]:          0 :     if (PyBuffer_IsContiguous(view, order))
         938                 :          0 :         return (PyObject *)mv;
         939                 :            :
         940         [ #  # ]:          0 :     if (buffertype == PyBUF_WRITE) {
         941                 :          0 :         PyErr_SetString(PyExc_BufferError,
         942                 :            :             "writable contiguous buffer requested "
         943                 :            :             "for a non-contiguous object.");
         944                 :          0 :         Py_DECREF(mv);
         945                 :          0 :         return NULL;
         946                 :            :     }
         947                 :            :
         948                 :          0 :     ret = memory_from_contiguous_copy(view, order);
         949                 :          0 :     Py_DECREF(mv);
         950                 :          0 :     return ret;
         951                 :            : }
         952                 :            :
         953                 :            :
         954                 :            : /*[clinic input]
         955                 :            : @classmethod
         956                 :            : memoryview.__new__
         957                 :            :
         958                 :            :     object: object
         959                 :            :
         960                 :            : Create a new memoryview object which references the given object.
         961                 :            : [clinic start generated code]*/
         962                 :            :
         963                 :            : static PyObject *
         964                 :        389 : memoryview_impl(PyTypeObject *type, PyObject *object)
         965                 :            : /*[clinic end generated code: output=7de78e184ed66db8 input=f04429eb0bdf8c6e]*/
         966                 :            : {
         967                 :        389 :     return PyMemoryView_FromObject(object);
         968                 :            : }
         969                 :            :
         970                 :            :
         971                 :            : /****************************************************************************/
         972                 :            : /*                         Previously in abstract.c                         */
         973                 :            : /****************************************************************************/
         974                 :            :
         975                 :            : typedef struct {
         976                 :            :     Py_buffer view;
         977                 :            :     Py_ssize_t array[1];
         978                 :            : } Py_buffer_full;
         979                 :            :
         980                 :            : int
         981                 :        165 : PyBuffer_ToContiguous(void *buf, const Py_buffer *src, Py_ssize_t len, char order)
         982                 :            : {
         983                 :        165 :     Py_buffer_full *fb = NULL;
         984                 :            :     int ret;
         985                 :            :
         986                 :            :     assert(order == 'C' || order == 'F' || order == 'A');
         987                 :            :
         988         [ -  + ]:        165 :     if (len != src->len) {
         989                 :          0 :         PyErr_SetString(PyExc_ValueError,
         990                 :            :             "PyBuffer_ToContiguous: len != view->len");
         991                 :          0 :         return -1;
         992                 :            :     }
         993                 :            :
         994         [ +  - ]:        165 :     if (PyBuffer_IsContiguous(src, order)) {
         995                 :        165 :         memcpy((char *)buf, src->buf, len);
         996                 :        165 :         return 0;
         997                 :            :     }
         998                 :            :
         999                 :            :     /* buffer_to_contiguous() assumes PyBUF_FULL */
        1000                 :          0 :     fb = PyMem_Malloc(sizeof *fb + 3 * src->ndim * (sizeof *fb->array));
        1001         [ #  # ]:          0 :     if (fb == NULL) {
        1002                 :          0 :         PyErr_NoMemory();
        1003                 :          0 :         return -1;
        1004                 :            :     }
        1005                 :          0 :     fb->view.ndim = src->ndim;
        1006                 :          0 :     fb->view.shape = fb->array;
        1007                 :          0 :     fb->view.strides = fb->array + src->ndim;
        1008                 :          0 :     fb->view.suboffsets = fb->array + 2 * src->ndim;
        1009                 :            :
        1010                 :          0 :     init_shared_values(&fb->view, src);
        1011                 :          0 :     init_shape_strides(&fb->view, src);
        1012                 :          0 :     init_suboffsets(&fb->view, src);
        1013                 :            :
        1014                 :          0 :     src = &fb->view;
        1015                 :            :
        1016                 :          0 :     ret = buffer_to_contiguous(buf, src, order);
        1017                 :          0 :     PyMem_Free(fb);
        1018                 :          0 :     return ret;
        1019                 :            : }
        1020                 :            :
        1021                 :            :
        1022                 :            : /****************************************************************************/
        1023                 :            : /*                           Release/GC management                          */
        1024                 :            : /****************************************************************************/
        1025                 :            :
        1026                 :            : /* Inform the managed buffer that this particular memoryview will not access
        1027                 :            :    the underlying buffer again. If no other memoryviews are registered with
        1028                 :            :    the managed buffer, the underlying buffer is released instantly and
        1029                 :            :    marked as inaccessible for both the memoryview and the managed buffer.
        1030                 :            :
        1031                 :            :    This function fails if the memoryview itself has exported buffers. */
        1032                 :            : static int
        1033                 :       5630 : _memory_release(PyMemoryViewObject *self)
        1034                 :            : {
        1035         [ -  + ]:       5630 :     if (self->flags & _Py_MEMORYVIEW_RELEASED)
        1036                 :          0 :         return 0;
        1037                 :            :
        1038         [ +  - ]:       5630 :     if (self->exports == 0) {
        1039                 :       5630 :         self->flags |= _Py_MEMORYVIEW_RELEASED;
        1040                 :            :         assert(self->mbuf->exports > 0);
        1041         [ +  + ]:       5630 :         if (--self->mbuf->exports == 0)
        1042                 :       5241 :             mbuf_release(self->mbuf);
        1043                 :       5630 :         return 0;
        1044                 :            :     }
        1045         [ #  # ]:          0 :     if (self->exports > 0) {
        1046                 :          0 :         PyErr_Format(PyExc_BufferError,
        1047                 :            :             "memoryview has %zd exported buffer%s", self->exports,
        1048         [ #  # ]:          0 :             self->exports==1 ? "" : "s");
        1049                 :          0 :         return -1;
        1050                 :            :     }
        1051                 :            :
        1052                 :          0 :     PyErr_SetString(PyExc_SystemError,
        1053                 :            :                     "_memory_release(): negative export count");
        1054                 :          0 :     return -1;
        1055                 :            : }
        1056                 :            :
        1057                 :            : /*[clinic input]
        1058                 :            : memoryview.release
        1059                 :            :
        1060                 :            : Release the underlying buffer exposed by the memoryview object.
        1061                 :            : [clinic start generated code]*/
        1062                 :            :
        1063                 :            : static PyObject *
        1064                 :          0 : memoryview_release_impl(PyMemoryViewObject *self)
        1065                 :            : /*[clinic end generated code: output=d0b7e3ba95b7fcb9 input=bc71d1d51f4a52f0]*/
        1066                 :            : {
        1067         [ #  # ]:          0 :     if (_memory_release(self) < 0)
        1068                 :          0 :         return NULL;
        1069                 :          0 :     Py_RETURN_NONE;
        1070                 :            : }
        1071                 :            :
        1072                 :            : static void
        1073                 :       5630 : memory_dealloc(PyMemoryViewObject *self)
        1074                 :            : {
        1075                 :            :     assert(self->exports == 0);
        1076                 :       5630 :     _PyObject_GC_UNTRACK(self);
        1077                 :       5630 :     (void)_memory_release(self);
        1078         [ +  - ]:       5630 :     Py_CLEAR(self->mbuf);
        1079         [ -  + ]:       5630 :     if (self->weakreflist != NULL)
        1080                 :          0 :         PyObject_ClearWeakRefs((PyObject *) self);
        1081                 :       5630 :     PyObject_GC_Del(self);
        1082                 :       5630 : }
        1083                 :            :
        1084                 :            : static int
        1085                 :         72 : memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
        1086                 :            : {
        1087   [ +  -  -  + ]:         72 :     Py_VISIT(self->mbuf);
        1088                 :         72 :     return 0;
        1089                 :            : }
        1090                 :            :
        1091                 :            : static int
        1092                 :          0 : memory_clear(PyMemoryViewObject *self)
        1093                 :            : {
        1094                 :          0 :     (void)_memory_release(self);
        1095         [ #  # ]:          0 :     Py_CLEAR(self->mbuf);
        1096                 :          0 :     return 0;
        1097                 :            : }
        1098                 :            :
        1099                 :            : static PyObject *
        1100                 :          0 : memory_enter(PyObject *self, PyObject *args)
        1101                 :            : {
        1102   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        1103                 :          0 :     return Py_NewRef(self);
        1104                 :            : }
        1105                 :            :
        1106                 :            : static PyObject *
        1107                 :          0 : memory_exit(PyObject *self, PyObject *args)
        1108                 :            : {
        1109                 :          0 :     return memoryview_release_impl((PyMemoryViewObject *)self);
        1110                 :            : }
        1111                 :            :
        1112                 :            :
        1113                 :            : /****************************************************************************/
        1114                 :            : /*                         Casting format and shape                         */
        1115                 :            : /****************************************************************************/
        1116                 :            :
        1117                 :            : #define IS_BYTE_FORMAT(f) (f == 'b' || f == 'B' || f == 'c')
        1118                 :            :
        1119                 :            : static inline Py_ssize_t
        1120                 :          6 : get_native_fmtchar(char *result, const char *fmt)
        1121                 :            : {
        1122                 :          6 :     Py_ssize_t size = -1;
        1123                 :            :
        1124         [ -  + ]:          6 :     if (fmt[0] == '@') fmt++;
        1125                 :            :
        1126   [ +  -  +  -  :          6 :     switch (fmt[0]) {
              -  -  -  -  -
                    -  -  - ]
        1127                 :          3 :     case 'c': case 'b': case 'B': size = sizeof(char); break;
        1128                 :          0 :     case 'h': case 'H': size = sizeof(short); break;
        1129                 :          3 :     case 'i': case 'I': size = sizeof(int); break;
        1130                 :          0 :     case 'l': case 'L': size = sizeof(long); break;
        1131                 :          0 :     case 'q': case 'Q': size = sizeof(long long); break;
        1132                 :          0 :     case 'n': case 'N': size = sizeof(Py_ssize_t); break;
        1133                 :          0 :     case 'f': size = sizeof(float); break;
        1134                 :          0 :     case 'd': size = sizeof(double); break;
        1135                 :          0 :     case 'e': size = sizeof(float) / 2; break;
        1136                 :          0 :     case '?': size = sizeof(_Bool); break;
        1137                 :          0 :     case 'P': size = sizeof(void *); break;
        1138                 :            :     }
        1139                 :            :
        1140   [ +  -  +  - ]:          6 :     if (size > 0 && fmt[1] == '\0') {
        1141                 :          6 :         *result = fmt[0];
        1142                 :          6 :         return size;
        1143                 :            :     }
        1144                 :            :
        1145                 :          0 :     return -1;
        1146                 :            : }
        1147                 :            :
        1148                 :            : static inline const char *
        1149                 :          3 : get_native_fmtstr(const char *fmt)
        1150                 :            : {
        1151                 :          3 :     int at = 0;
        1152                 :            :
        1153         [ -  + ]:          3 :     if (fmt[0] == '@') {
        1154                 :          0 :         at = 1;
        1155                 :          0 :         fmt++;
        1156                 :            :     }
        1157   [ +  -  -  + ]:          3 :     if (fmt[0] == '\0' || fmt[1] != '\0') {
        1158                 :          0 :         return NULL;
        1159                 :            :     }
        1160                 :            :
        1161                 :            : #define RETURN(s) do { return at ? "@" s : s; } while (0)
        1162                 :            :
        1163   [ -  -  -  -  :          3 :     switch (fmt[0]) {
              -  -  +  -  -
              -  -  -  -  -
                 -  -  -  -
                          - ]
        1164         [ #  # ]:          0 :     case 'c': RETURN("c");
        1165         [ #  # ]:          0 :     case 'b': RETURN("b");
        1166         [ #  # ]:          0 :     case 'B': RETURN("B");
        1167         [ #  # ]:          0 :     case 'h': RETURN("h");
        1168         [ #  # ]:          0 :     case 'H': RETURN("H");
        1169         [ #  # ]:          0 :     case 'i': RETURN("i");
        1170         [ -  + ]:          3 :     case 'I': RETURN("I");
        1171         [ #  # ]:          0 :     case 'l': RETURN("l");
        1172         [ #  # ]:          0 :     case 'L': RETURN("L");
        1173         [ #  # ]:          0 :     case 'q': RETURN("q");
        1174         [ #  # ]:          0 :     case 'Q': RETURN("Q");
        1175         [ #  # ]:          0 :     case 'n': RETURN("n");
        1176         [ #  # ]:          0 :     case 'N': RETURN("N");
        1177         [ #  # ]:          0 :     case 'f': RETURN("f");
        1178         [ #  # ]:          0 :     case 'd': RETURN("d");
        1179         [ #  # ]:          0 :     case 'e': RETURN("e");
        1180         [ #  # ]:          0 :     case '?': RETURN("?");
        1181         [ #  # ]:          0 :     case 'P': RETURN("P");
        1182                 :            :     }
        1183                 :            :
        1184                 :          0 :     return NULL;
        1185                 :            : }
        1186                 :            :
        1187                 :            :
        1188                 :            : /* Cast a memoryview's data type to 'format'. The input array must be
        1189                 :            :    C-contiguous. At least one of input-format, output-format must have
        1190                 :            :    byte size. The output array is 1-D, with the same byte length as the
        1191                 :            :    input array. Thus, view->len must be a multiple of the new itemsize. */
        1192                 :            : static int
        1193                 :          3 : cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
        1194                 :            : {
        1195                 :          3 :     Py_buffer *view = &mv->view;
        1196                 :            :     PyObject *asciifmt;
        1197                 :            :     char srcchar, destchar;
        1198                 :            :     Py_ssize_t itemsize;
        1199                 :          3 :     int ret = -1;
        1200                 :            :
        1201                 :            :     assert(view->ndim >= 1);
        1202                 :            :     assert(Py_SIZE(mv) == 3*view->ndim);
        1203                 :            :     assert(view->shape == mv->ob_array);
        1204                 :            :     assert(view->strides == mv->ob_array + view->ndim);
        1205                 :            :     assert(view->suboffsets == mv->ob_array + 2*view->ndim);
        1206                 :            :
        1207                 :          3 :     asciifmt = PyUnicode_AsASCIIString(format);
        1208         [ -  + ]:          3 :     if (asciifmt == NULL)
        1209                 :          0 :         return ret;
        1210                 :            :
        1211                 :          3 :     itemsize = get_native_fmtchar(&destchar, PyBytes_AS_STRING(asciifmt));
        1212         [ -  + ]:          3 :     if (itemsize < 0) {
        1213                 :          0 :         PyErr_SetString(PyExc_ValueError,
        1214                 :            :             "memoryview: destination format must be a native single "
        1215                 :            :             "character format prefixed with an optional '@'");
        1216                 :          0 :         goto out;
        1217                 :            :     }
        1218                 :            :
        1219         [ +  - ]:          3 :     if ((get_native_fmtchar(&srcchar, view->format) < 0 ||
        1220   [ +  -  -  +  :          3 :          !IS_BYTE_FORMAT(srcchar)) && !IS_BYTE_FORMAT(destchar)) {
              -  -  -  -  -
                    -  -  - ]
        1221                 :          0 :         PyErr_SetString(PyExc_TypeError,
        1222                 :            :             "memoryview: cannot cast between two non-byte formats");
        1223                 :          0 :         goto out;
        1224                 :            :     }
        1225         [ -  + ]:          3 :     if (view->len % itemsize) {
        1226                 :          0 :         PyErr_SetString(PyExc_TypeError,
        1227                 :            :             "memoryview: length is not a multiple of itemsize");
        1228                 :          0 :         goto out;
        1229                 :            :     }
        1230                 :            :
        1231                 :          3 :     view->format = (char *)get_native_fmtstr(PyBytes_AS_STRING(asciifmt));
        1232         [ -  + ]:          3 :     if (view->format == NULL) {
        1233                 :            :         /* NOT_REACHED: get_native_fmtchar() already validates the format. */
        1234                 :          0 :         PyErr_SetString(PyExc_RuntimeError,
        1235                 :            :             "memoryview: internal error");
        1236                 :          0 :         goto out;
        1237                 :            :     }
        1238                 :          3 :     view->itemsize = itemsize;
        1239                 :            :
        1240                 :          3 :     view->ndim = 1;
        1241                 :          3 :     view->shape[0] = view->len / view->itemsize;
        1242                 :          3 :     view->strides[0] = view->itemsize;
        1243                 :          3 :     view->suboffsets = NULL;
        1244                 :            :
        1245                 :          3 :     init_flags(mv);
        1246                 :            :
        1247                 :          3 :     ret = 0;
        1248                 :            :
        1249                 :          3 : out:
        1250                 :          3 :     Py_DECREF(asciifmt);
        1251                 :          3 :     return ret;
        1252                 :            : }
        1253                 :            :
        1254                 :            : /* The memoryview must have space for 3*len(seq) elements. */
        1255                 :            : static Py_ssize_t
        1256                 :          0 : copy_shape(Py_ssize_t *shape, const PyObject *seq, Py_ssize_t ndim,
        1257                 :            :            Py_ssize_t itemsize)
        1258                 :            : {
        1259                 :            :     Py_ssize_t x, i;
        1260                 :          0 :     Py_ssize_t len = itemsize;
        1261                 :            :
        1262         [ #  # ]:          0 :     for (i = 0; i < ndim; i++) {
        1263         [ #  # ]:          0 :         PyObject *tmp = PySequence_Fast_GET_ITEM(seq, i);
        1264         [ #  # ]:          0 :         if (!PyLong_Check(tmp)) {
        1265                 :          0 :             PyErr_SetString(PyExc_TypeError,
        1266                 :            :                 "memoryview.cast(): elements of shape must be integers");
        1267                 :          0 :             return -1;
        1268                 :            :         }
        1269                 :          0 :         x = PyLong_AsSsize_t(tmp);
        1270   [ #  #  #  # ]:          0 :         if (x == -1 && PyErr_Occurred()) {
        1271                 :          0 :             return -1;
        1272                 :            :         }
        1273         [ #  # ]:          0 :         if (x <= 0) {
        1274                 :            :             /* In general elements of shape may be 0, but not for casting. */
        1275                 :          0 :             PyErr_Format(PyExc_ValueError,
        1276                 :            :                 "memoryview.cast(): elements of shape must be integers > 0");
        1277                 :          0 :             return -1;
        1278                 :            :         }
        1279         [ #  # ]:          0 :         if (x > PY_SSIZE_T_MAX / len) {
        1280                 :          0 :             PyErr_Format(PyExc_ValueError,
        1281                 :            :                 "memoryview.cast(): product(shape) > SSIZE_MAX");
        1282                 :          0 :             return -1;
        1283                 :            :         }
        1284                 :          0 :         len *= x;
        1285                 :          0 :         shape[i] = x;
        1286                 :            :     }
        1287                 :            :
        1288                 :          0 :     return len;
        1289                 :            : }
        1290                 :            :
        1291                 :            : /* Cast a 1-D array to a new shape. The result array will be C-contiguous.
        1292                 :            :    If the result array does not have exactly the same byte length as the
        1293                 :            :    input array, raise ValueError. */
        1294                 :            : static int
        1295                 :          0 : cast_to_ND(PyMemoryViewObject *mv, const PyObject *shape, int ndim)
        1296                 :            : {
        1297                 :          0 :     Py_buffer *view = &mv->view;
        1298                 :            :     Py_ssize_t len;
        1299                 :            :
        1300                 :            :     assert(view->ndim == 1); /* ndim from cast_to_1D() */
        1301                 :            :     assert(Py_SIZE(mv) == 3*(ndim==0?1:ndim)); /* ndim of result array */
        1302                 :            :     assert(view->shape == mv->ob_array);
        1303                 :            :     assert(view->strides == mv->ob_array + (ndim==0?1:ndim));
        1304                 :            :     assert(view->suboffsets == NULL);
        1305                 :            :
        1306                 :          0 :     view->ndim = ndim;
        1307         [ #  # ]:          0 :     if (view->ndim == 0) {
        1308                 :          0 :         view->shape = NULL;
        1309                 :          0 :         view->strides = NULL;
        1310                 :          0 :         len = view->itemsize;
        1311                 :            :     }
        1312                 :            :     else {
        1313                 :          0 :         len = copy_shape(view->shape, shape, ndim, view->itemsize);
        1314         [ #  # ]:          0 :         if (len < 0)
        1315                 :          0 :             return -1;
        1316                 :          0 :         init_strides_from_shape(view);
        1317                 :            :     }
        1318                 :            :
        1319         [ #  # ]:          0 :     if (view->len != len) {
        1320                 :          0 :         PyErr_SetString(PyExc_TypeError,
        1321                 :            :             "memoryview: product(shape) * itemsize != buffer size");
        1322                 :          0 :         return -1;
        1323                 :            :     }
        1324                 :            :
        1325                 :          0 :     init_flags(mv);
        1326                 :            :
        1327                 :          0 :     return 0;
        1328                 :            : }
        1329                 :            :
        1330                 :            : static int
        1331                 :          0 : zero_in_shape(PyMemoryViewObject *mv)
        1332                 :            : {
        1333                 :          0 :     Py_buffer *view = &mv->view;
        1334                 :            :     Py_ssize_t i;
        1335                 :            :
        1336         [ #  # ]:          0 :     for (i = 0; i < view->ndim; i++)
        1337         [ #  # ]:          0 :         if (view->shape[i] == 0)
        1338                 :          0 :             return 1;
        1339                 :            :
        1340                 :          0 :     return 0;
        1341                 :            : }
        1342                 :            :
        1343                 :            : /*
        1344                 :            :    Cast a copy of 'self' to a different view. The input view must
        1345                 :            :    be C-contiguous. The function always casts the input view to a
        1346                 :            :    1-D output according to 'format'. At least one of input-format,
        1347                 :            :    output-format must have byte size.
        1348                 :            :
        1349                 :            :    If 'shape' is given, the 1-D view from the previous step will
        1350                 :            :    be cast to a C-contiguous view with new shape and strides.
        1351                 :            :
        1352                 :            :    All casts must result in views that will have the exact byte
        1353                 :            :    size of the original input. Otherwise, an error is raised.
        1354                 :            : */
        1355                 :            : /*[clinic input]
        1356                 :            : memoryview.cast
        1357                 :            :
        1358                 :            :     format: unicode
        1359                 :            :     shape: object = NULL
        1360                 :            :
        1361                 :            : Cast a memoryview to a new format or shape.
        1362                 :            : [clinic start generated code]*/
        1363                 :            :
        1364                 :            : static PyObject *
        1365                 :          3 : memoryview_cast_impl(PyMemoryViewObject *self, PyObject *format,
        1366                 :            :                      PyObject *shape)
        1367                 :            : /*[clinic end generated code: output=bae520b3a389cbab input=138936cc9041b1a3]*/
        1368                 :            : {
        1369                 :          3 :     PyMemoryViewObject *mv = NULL;
        1370                 :          3 :     Py_ssize_t ndim = 1;
        1371                 :            :
        1372   [ +  -  -  + ]:          3 :     CHECK_RELEASED(self);
        1373                 :            :
        1374         [ -  + ]:          3 :     if (!MV_C_CONTIGUOUS(self->flags)) {
        1375                 :          0 :         PyErr_SetString(PyExc_TypeError,
        1376                 :            :             "memoryview: casts are restricted to C-contiguous views");
        1377                 :          0 :         return NULL;
        1378                 :            :     }
        1379   [ +  -  -  +  :          3 :     if ((shape || self->view.ndim != 1) && zero_in_shape(self)) {
                       -  - ]
        1380                 :          0 :         PyErr_SetString(PyExc_TypeError,
        1381                 :            :             "memoryview: cannot cast view with zeros in shape or strides");
        1382                 :          0 :         return NULL;
        1383                 :            :     }
        1384         [ -  + ]:          3 :     if (shape) {
        1385   [ #  #  #  # ]:          0 :         CHECK_LIST_OR_TUPLE(shape)
        1386         [ #  # ]:          0 :         ndim = PySequence_Fast_GET_SIZE(shape);
        1387         [ #  # ]:          0 :         if (ndim > PyBUF_MAX_NDIM) {
        1388                 :          0 :             PyErr_SetString(PyExc_ValueError,
        1389                 :            :                 "memoryview: number of dimensions must not exceed "
        1390                 :            :                 Py_STRINGIFY(PyBUF_MAX_NDIM));
        1391                 :          0 :             return NULL;
        1392                 :            :         }
        1393   [ #  #  #  # ]:          0 :         if (self->view.ndim != 1 && ndim != 1) {
        1394                 :          0 :             PyErr_SetString(PyExc_TypeError,
        1395                 :            :                 "memoryview: cast must be 1D -> ND or ND -> 1D");
        1396                 :          0 :             return NULL;
        1397                 :            :         }
        1398                 :            :     }
        1399                 :            :
        1400                 :            :     mv = (PyMemoryViewObject *)
        1401         [ +  - ]:          3 :         mbuf_add_incomplete_view(self->mbuf, &self->view, ndim==0 ? 1 : (int)ndim);
        1402         [ -  + ]:          3 :     if (mv == NULL)
        1403                 :          0 :         return NULL;
        1404                 :            :
        1405         [ -  + ]:          3 :     if (cast_to_1D(mv, format) < 0)
        1406                 :          0 :         goto error;
        1407   [ -  +  -  - ]:          3 :     if (shape && cast_to_ND(mv, shape, (int)ndim) < 0)
        1408                 :          0 :         goto error;
        1409                 :            :
        1410                 :          3 :     return (PyObject *)mv;
        1411                 :            :
        1412                 :          0 : error:
        1413                 :          0 :     Py_DECREF(mv);
        1414                 :          0 :     return NULL;
        1415                 :            : }
        1416                 :            :
        1417                 :            : /*[clinic input]
        1418                 :            : memoryview.toreadonly
        1419                 :            :
        1420                 :            : Return a readonly version of the memoryview.
        1421                 :            : [clinic start generated code]*/
        1422                 :            :
        1423                 :            : static PyObject *
        1424                 :          0 : memoryview_toreadonly_impl(PyMemoryViewObject *self)
        1425                 :            : /*[clinic end generated code: output=2c7e056f04c99e62 input=dc06d20f19ba236f]*/
        1426                 :            : {
        1427   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        1428                 :            :     /* Even if self is already readonly, we still need to create a new
        1429                 :            :      * object for .release() to work correctly.
        1430                 :            :      */
        1431                 :          0 :     self = (PyMemoryViewObject *) mbuf_add_view(self->mbuf, &self->view);
        1432         [ #  # ]:          0 :     if (self != NULL) {
        1433                 :          0 :         self->view.readonly = 1;
        1434                 :            :     };
        1435                 :          0 :     return (PyObject *) self;
        1436                 :            : }
        1437                 :            :
        1438                 :            :
        1439                 :            : /**************************************************************************/
        1440                 :            : /*                               getbuffer                                */
        1441                 :            : /**************************************************************************/
        1442                 :            :
        1443                 :            : static int
        1444                 :       5238 : memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
        1445                 :            : {
        1446                 :       5238 :     Py_buffer *base = &self->view;
        1447                 :       5238 :     int baseflags = self->flags;
        1448                 :            :
        1449   [ +  -  -  + ]:       5238 :     CHECK_RELEASED_INT(self);
        1450                 :            :
        1451                 :            :     /* start with complete information */
        1452                 :       5238 :     *view = *base;
        1453                 :       5238 :     view->obj = NULL;
        1454                 :            :
        1455   [ +  +  -  + ]:       5238 :     if (REQ_WRITABLE(flags) && base->readonly) {
        1456                 :          0 :         PyErr_SetString(PyExc_BufferError,
        1457                 :            :             "memoryview: underlying buffer is not writable");
        1458                 :          0 :         return -1;
        1459                 :            :     }
        1460         [ +  - ]:       5238 :     if (!REQ_FORMAT(flags)) {
        1461                 :            :         /* NULL indicates that the buffer's data type has been cast to 'B'.
        1462                 :            :            view->itemsize is the _previous_ itemsize. If shape is present,
        1463                 :            :            the equality product(shape) * itemsize = len still holds at this
        1464                 :            :            point. The equality calcsize(format) = itemsize does _not_ hold
        1465                 :            :            from here on! */
        1466                 :       5238 :         view->format = NULL;
        1467                 :            :     }
        1468                 :            :
        1469   [ -  +  -  - ]:       5238 :     if (REQ_C_CONTIGUOUS(flags) && !MV_C_CONTIGUOUS(baseflags)) {
        1470                 :          0 :         PyErr_SetString(PyExc_BufferError,
        1471                 :            :             "memoryview: underlying buffer is not C-contiguous");
        1472                 :          0 :         return -1;
        1473                 :            :     }
        1474   [ -  +  -  - ]:       5238 :     if (REQ_F_CONTIGUOUS(flags) && !MV_F_CONTIGUOUS(baseflags)) {
        1475                 :          0 :         PyErr_SetString(PyExc_BufferError,
        1476                 :            :             "memoryview: underlying buffer is not Fortran contiguous");
        1477                 :          0 :         return -1;
        1478                 :            :     }
        1479   [ -  +  -  - ]:       5238 :     if (REQ_ANY_CONTIGUOUS(flags) && !MV_ANY_CONTIGUOUS(baseflags)) {
        1480                 :          0 :         PyErr_SetString(PyExc_BufferError,
        1481                 :            :             "memoryview: underlying buffer is not contiguous");
        1482                 :          0 :         return -1;
        1483                 :            :     }
        1484   [ +  -  -  + ]:       5238 :     if (!REQ_INDIRECT(flags) && (baseflags & _Py_MEMORYVIEW_PIL)) {
        1485                 :          0 :         PyErr_SetString(PyExc_BufferError,
        1486                 :            :             "memoryview: underlying buffer requires suboffsets");
        1487                 :          0 :         return -1;
        1488                 :            :     }
        1489         [ +  - ]:       5238 :     if (!REQ_STRIDES(flags)) {
        1490         [ -  + ]:       5238 :         if (!MV_C_CONTIGUOUS(baseflags)) {
        1491                 :          0 :             PyErr_SetString(PyExc_BufferError,
        1492                 :            :                 "memoryview: underlying buffer is not C-contiguous");
        1493                 :          0 :             return -1;
        1494                 :            :         }
        1495                 :       5238 :         view->strides = NULL;
        1496                 :            :     }
        1497         [ +  - ]:       5238 :     if (!REQ_SHAPE(flags)) {
        1498                 :            :         /* PyBUF_SIMPLE or PyBUF_WRITABLE: at this point buf is C-contiguous,
        1499                 :            :            so base->buf = ndbuf->data. */
        1500         [ -  + ]:       5238 :         if (view->format != NULL) {
        1501                 :            :             /* PyBUF_SIMPLE|PyBUF_FORMAT and PyBUF_WRITABLE|PyBUF_FORMAT do
        1502                 :            :                not make sense. */
        1503                 :          0 :             PyErr_Format(PyExc_BufferError,
        1504                 :            :                 "memoryview: cannot cast to unsigned bytes if the format flag "
        1505                 :            :                 "is present");
        1506                 :          0 :             return -1;
        1507                 :            :         }
        1508                 :            :         /* product(shape) * itemsize = len and calcsize(format) = itemsize
        1509                 :            :            do _not_ hold from here on! */
        1510                 :       5238 :         view->ndim = 1;
        1511                 :       5238 :         view->shape = NULL;
        1512                 :            :     }
        1513                 :            :
        1514                 :            :
        1515                 :       5238 :     view->obj = Py_NewRef(self);
        1516                 :       5238 :     self->exports++;
        1517                 :            :
        1518                 :       5238 :     return 0;
        1519                 :            : }
        1520                 :            :
        1521                 :            : static void
        1522                 :       5238 : memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
        1523                 :            : {
        1524                 :       5238 :     self->exports--;
        1525                 :       5238 :     return;
        1526                 :            :     /* PyBuffer_Release() decrements view->obj after this function returns. */
        1527                 :            : }
        1528                 :            :
        1529                 :            : /* Buffer methods */
        1530                 :            : static PyBufferProcs memory_as_buffer = {
        1531                 :            :     (getbufferproc)memory_getbuf,         /* bf_getbuffer */
        1532                 :            :     (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
        1533                 :            : };
        1534                 :            :
        1535                 :            :
        1536                 :            : /****************************************************************************/
        1537                 :            : /*           Optimized pack/unpack for all native format specifiers         */
        1538                 :            : /****************************************************************************/
        1539                 :            :
        1540                 :            : /*
        1541                 :            :   Fix exceptions:
        1542                 :            :      1) Include format string in the error message.
        1543                 :            :      2) OverflowError -> ValueError.
        1544                 :            :      3) The error message from PyNumber_Index() is not ideal.
        1545                 :            : */
        1546                 :            : static int
        1547                 :          0 : type_error_int(const char *fmt)
        1548                 :            : {
        1549                 :          0 :     PyErr_Format(PyExc_TypeError,
        1550                 :            :         "memoryview: invalid type for format '%s'", fmt);
        1551                 :          0 :     return -1;
        1552                 :            : }
        1553                 :            :
        1554                 :            : static int
        1555                 :          0 : value_error_int(const char *fmt)
        1556                 :            : {
        1557                 :          0 :     PyErr_Format(PyExc_ValueError,
        1558                 :            :         "memoryview: invalid value for format '%s'", fmt);
        1559                 :          0 :     return -1;
        1560                 :            : }
        1561                 :            :
        1562                 :            : static int
        1563                 :          0 : fix_error_int(const char *fmt)
        1564                 :            : {
        1565                 :            :     assert(PyErr_Occurred());
        1566         [ #  # ]:          0 :     if (PyErr_ExceptionMatches(PyExc_TypeError)) {
        1567                 :          0 :         PyErr_Clear();
        1568                 :          0 :         return type_error_int(fmt);
        1569                 :            :     }
        1570   [ #  #  #  # ]:          0 :     else if (PyErr_ExceptionMatches(PyExc_OverflowError) ||
        1571                 :          0 :              PyErr_ExceptionMatches(PyExc_ValueError)) {
        1572                 :          0 :         PyErr_Clear();
        1573                 :          0 :         return value_error_int(fmt);
        1574                 :            :     }
        1575                 :            :
        1576                 :          0 :     return -1;
        1577                 :            : }
        1578                 :            :
        1579                 :            : /* Accept integer objects or objects with an __index__() method. */
        1580                 :            : static long
        1581                 :          0 : pylong_as_ld(PyObject *item)
        1582                 :            : {
        1583                 :            :     PyObject *tmp;
        1584                 :            :     long ld;
        1585                 :            :
        1586                 :          0 :     tmp = _PyNumber_Index(item);
        1587         [ #  # ]:          0 :     if (tmp == NULL)
        1588                 :          0 :         return -1;
        1589                 :            :
        1590                 :          0 :     ld = PyLong_AsLong(tmp);
        1591                 :          0 :     Py_DECREF(tmp);
        1592                 :          0 :     return ld;
        1593                 :            : }
        1594                 :            :
        1595                 :            : static unsigned long
        1596                 :          0 : pylong_as_lu(PyObject *item)
        1597                 :            : {
        1598                 :            :     PyObject *tmp;
        1599                 :            :     unsigned long lu;
        1600                 :            :
        1601                 :          0 :     tmp = _PyNumber_Index(item);
        1602         [ #  # ]:          0 :     if (tmp == NULL)
        1603                 :          0 :         return (unsigned long)-1;
        1604                 :            :
        1605                 :          0 :     lu = PyLong_AsUnsignedLong(tmp);
        1606                 :          0 :     Py_DECREF(tmp);
        1607                 :          0 :     return lu;
        1608                 :            : }
        1609                 :            :
        1610                 :            : static long long
        1611                 :          0 : pylong_as_lld(PyObject *item)
        1612                 :            : {
        1613                 :            :     PyObject *tmp;
        1614                 :            :     long long lld;
        1615                 :            :
        1616                 :          0 :     tmp = _PyNumber_Index(item);
        1617         [ #  # ]:          0 :     if (tmp == NULL)
        1618                 :          0 :         return -1;
        1619                 :            :
        1620                 :          0 :     lld = PyLong_AsLongLong(tmp);
        1621                 :          0 :     Py_DECREF(tmp);
        1622                 :          0 :     return lld;
        1623                 :            : }
        1624                 :            :
        1625                 :            : static unsigned long long
        1626                 :          0 : pylong_as_llu(PyObject *item)
        1627                 :            : {
        1628                 :            :     PyObject *tmp;
        1629                 :            :     unsigned long long llu;
        1630                 :            :
        1631                 :          0 :     tmp = _PyNumber_Index(item);
        1632         [ #  # ]:          0 :     if (tmp == NULL)
        1633                 :          0 :         return (unsigned long long)-1;
        1634                 :            :
        1635                 :          0 :     llu = PyLong_AsUnsignedLongLong(tmp);
        1636                 :          0 :     Py_DECREF(tmp);
        1637                 :          0 :     return llu;
        1638                 :            : }
        1639                 :            :
        1640                 :            : static Py_ssize_t
        1641                 :          0 : pylong_as_zd(PyObject *item)
        1642                 :            : {
        1643                 :            :     PyObject *tmp;
        1644                 :            :     Py_ssize_t zd;
        1645                 :            :
        1646                 :          0 :     tmp = _PyNumber_Index(item);
        1647         [ #  # ]:          0 :     if (tmp == NULL)
        1648                 :          0 :         return -1;
        1649                 :            :
        1650                 :          0 :     zd = PyLong_AsSsize_t(tmp);
        1651                 :          0 :     Py_DECREF(tmp);
        1652                 :          0 :     return zd;
        1653                 :            : }
        1654                 :            :
        1655                 :            : static size_t
        1656                 :          0 : pylong_as_zu(PyObject *item)
        1657                 :            : {
        1658                 :            :     PyObject *tmp;
        1659                 :            :     size_t zu;
        1660                 :            :
        1661                 :          0 :     tmp = _PyNumber_Index(item);
        1662         [ #  # ]:          0 :     if (tmp == NULL)
        1663                 :          0 :         return (size_t)-1;
        1664                 :            :
        1665                 :          0 :     zu = PyLong_AsSize_t(tmp);
        1666                 :          0 :     Py_DECREF(tmp);
        1667                 :          0 :     return zu;
        1668                 :            : }
        1669                 :            :
        1670                 :            : /* Timings with the ndarray from _testbuffer.c indicate that using the
        1671                 :            :    struct module is around 15x slower than the two functions below. */
        1672                 :            :
        1673                 :            : #define UNPACK_SINGLE(dest, ptr, type) \
        1674                 :            :     do {                                   \
        1675                 :            :         type x;                            \
        1676                 :            :         memcpy((char *)&x, ptr, sizeof x); \
        1677                 :            :         dest = x;                          \
        1678                 :            :     } while (0)
        1679                 :            :
        1680                 :            : /* Unpack a single item. 'fmt' can be any native format character in struct
        1681                 :            :    module syntax. This function is very sensitive to small changes. With this
        1682                 :            :    layout gcc automatically generates a fast jump table. */
        1683                 :            : static inline PyObject *
        1684                 :        192 : unpack_single(PyMemoryViewObject *self, const char *ptr, const char *fmt)
        1685                 :            : {
        1686                 :            :     unsigned long long llu;
        1687                 :            :     unsigned long lu;
        1688                 :            :     size_t zu;
        1689                 :            :     long long lld;
        1690                 :            :     long ld;
        1691                 :            :     Py_ssize_t zd;
        1692                 :            :     double d;
        1693                 :            :     unsigned char uc;
        1694                 :            :     void *p;
        1695                 :            :
        1696   [ +  -  -  + ]:        192 :     CHECK_RELEASED_AGAIN(self);
        1697                 :            :
        1698                 :            : #if PY_LITTLE_ENDIAN
        1699                 :        192 :     int endian = 1;
        1700                 :            : #else
        1701                 :            :     int endian = 0;
        1702                 :            : #endif
        1703                 :            :
        1704   [ -  -  -  -  :        192 :     switch (fmt[0]) {
              -  -  -  +  -
              -  -  -  -  -
                 -  -  -  -
                          - ]
        1705                 :            :
        1706                 :            :     /* signed integers and fast path for 'B' */
        1707                 :          0 :     case 'B': uc = *((const unsigned char *)ptr); goto convert_uc;
        1708                 :          0 :     case 'b': ld =   *((const signed char *)ptr); goto convert_ld;
        1709                 :          0 :     case 'h': UNPACK_SINGLE(ld, ptr, short); goto convert_ld;
        1710                 :          0 :     case 'i': UNPACK_SINGLE(ld, ptr, int); goto convert_ld;
        1711                 :          0 :     case 'l': UNPACK_SINGLE(ld, ptr, long); goto convert_ld;
        1712                 :            :
        1713                 :            :     /* boolean */
        1714                 :          0 :     case '?': UNPACK_SINGLE(ld, ptr, _Bool); goto convert_bool;
        1715                 :            :
        1716                 :            :     /* unsigned integers */
        1717                 :          0 :     case 'H': UNPACK_SINGLE(lu, ptr, unsigned short); goto convert_lu;
        1718                 :        192 :     case 'I': UNPACK_SINGLE(lu, ptr, unsigned int); goto convert_lu;
        1719                 :          0 :     case 'L': UNPACK_SINGLE(lu, ptr, unsigned long); goto convert_lu;
        1720                 :            :
        1721                 :            :     /* native 64-bit */
        1722                 :          0 :     case 'q': UNPACK_SINGLE(lld, ptr, long long); goto convert_lld;
        1723                 :          0 :     case 'Q': UNPACK_SINGLE(llu, ptr, unsigned long long); goto convert_llu;
        1724                 :            :
        1725                 :            :     /* ssize_t and size_t */
        1726                 :          0 :     case 'n': UNPACK_SINGLE(zd, ptr, Py_ssize_t); goto convert_zd;
        1727                 :          0 :     case 'N': UNPACK_SINGLE(zu, ptr, size_t); goto convert_zu;
        1728                 :            :
        1729                 :            :     /* floats */
        1730                 :          0 :     case 'f': UNPACK_SINGLE(d, ptr, float); goto convert_double;
        1731                 :          0 :     case 'd': UNPACK_SINGLE(d, ptr, double); goto convert_double;
        1732                 :          0 :     case 'e': d = PyFloat_Unpack2(ptr, endian); goto convert_double;
        1733                 :            :
        1734                 :            :     /* bytes object */
        1735                 :          0 :     case 'c': goto convert_bytes;
        1736                 :            :
        1737                 :            :     /* pointer */
        1738                 :          0 :     case 'P': UNPACK_SINGLE(p, ptr, void *); goto convert_pointer;
        1739                 :            :
        1740                 :            :     /* default */
        1741                 :          0 :     default: goto err_format;
        1742                 :            :     }
        1743                 :            :
        1744                 :          0 : convert_uc:
        1745                 :            :     /* PyLong_FromUnsignedLong() is slower */
        1746                 :          0 :     return PyLong_FromLong(uc);
        1747                 :          0 : convert_ld:
        1748                 :          0 :     return PyLong_FromLong(ld);
        1749                 :        192 : convert_lu:
        1750                 :        192 :     return PyLong_FromUnsignedLong(lu);
        1751                 :          0 : convert_lld:
        1752                 :          0 :     return PyLong_FromLongLong(lld);
        1753                 :          0 : convert_llu:
        1754                 :          0 :     return PyLong_FromUnsignedLongLong(llu);
        1755                 :          0 : convert_zd:
        1756                 :          0 :     return PyLong_FromSsize_t(zd);
        1757                 :          0 : convert_zu:
        1758                 :          0 :     return PyLong_FromSize_t(zu);
        1759                 :          0 : convert_double:
        1760                 :          0 :     return PyFloat_FromDouble(d);
        1761                 :          0 : convert_bool:
        1762                 :          0 :     return PyBool_FromLong(ld);
        1763                 :          0 : convert_bytes:
        1764                 :          0 :     return PyBytes_FromStringAndSize(ptr, 1);
        1765                 :          0 : convert_pointer:
        1766                 :          0 :     return PyLong_FromVoidPtr(p);
        1767                 :          0 : err_format:
        1768                 :          0 :     PyErr_Format(PyExc_NotImplementedError,
        1769                 :            :         "memoryview: format %s not supported", fmt);
        1770                 :          0 :     return NULL;
        1771                 :            : }
        1772                 :            :
        1773                 :            : #define PACK_SINGLE(ptr, src, type) \
        1774                 :            :     do {                                     \
        1775                 :            :         type x;                              \
        1776                 :            :         x = (type)src;                       \
        1777                 :            :         memcpy(ptr, (char *)&x, sizeof x);   \
        1778                 :            :     } while (0)
        1779                 :            :
        1780                 :            : /* Pack a single item. 'fmt' can be any native format character in
        1781                 :            :    struct module syntax. */
        1782                 :            : static int
        1783                 :          0 : pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt)
        1784                 :            : {
        1785                 :            :     unsigned long long llu;
        1786                 :            :     unsigned long lu;
        1787                 :            :     size_t zu;
        1788                 :            :     long long lld;
        1789                 :            :     long ld;
        1790                 :            :     Py_ssize_t zd;
        1791                 :            :     double d;
        1792                 :            :     void *p;
        1793                 :            :
        1794                 :            : #if PY_LITTLE_ENDIAN
        1795                 :          0 :     int endian = 1;
        1796                 :            : #else
        1797                 :            :     int endian = 0;
        1798                 :            : #endif
        1799   [ #  #  #  #  :          0 :     switch (fmt[0]) {
              #  #  #  #  #
                       #  # ]
        1800                 :            :     /* signed integers */
        1801                 :          0 :     case 'b': case 'h': case 'i': case 'l':
        1802                 :          0 :         ld = pylong_as_ld(item);
        1803   [ #  #  #  # ]:          0 :         if (ld == -1 && PyErr_Occurred())
        1804                 :          0 :             goto err_occurred;
        1805   [ #  #  #  # ]:          0 :         CHECK_RELEASED_INT_AGAIN(self);
        1806   [ #  #  #  # ]:          0 :         switch (fmt[0]) {
        1807                 :          0 :         case 'b':
        1808   [ #  #  #  # ]:          0 :             if (ld < SCHAR_MIN || ld > SCHAR_MAX) goto err_range;
        1809                 :          0 :             *((signed char *)ptr) = (signed char)ld; break;
        1810                 :          0 :         case 'h':
        1811   [ #  #  #  # ]:          0 :             if (ld < SHRT_MIN || ld > SHRT_MAX) goto err_range;
        1812                 :          0 :             PACK_SINGLE(ptr, ld, short); break;
        1813                 :          0 :         case 'i':
        1814   [ #  #  #  # ]:          0 :             if (ld < INT_MIN || ld > INT_MAX) goto err_range;
        1815                 :          0 :             PACK_SINGLE(ptr, ld, int); break;
        1816                 :          0 :         default: /* 'l' */
        1817                 :          0 :             PACK_SINGLE(ptr, ld, long); break;
        1818                 :            :         }
        1819                 :          0 :         break;
        1820                 :            :
        1821                 :            :     /* unsigned integers */
        1822                 :          0 :     case 'B': case 'H': case 'I': case 'L':
        1823                 :          0 :         lu = pylong_as_lu(item);
        1824   [ #  #  #  # ]:          0 :         if (lu == (unsigned long)-1 && PyErr_Occurred())
        1825                 :          0 :             goto err_occurred;
        1826   [ #  #  #  # ]:          0 :         CHECK_RELEASED_INT_AGAIN(self);
        1827   [ #  #  #  # ]:          0 :         switch (fmt[0]) {
        1828                 :          0 :         case 'B':
        1829         [ #  # ]:          0 :             if (lu > UCHAR_MAX) goto err_range;
        1830                 :          0 :             *((unsigned char *)ptr) = (unsigned char)lu; break;
        1831                 :          0 :         case 'H':
        1832         [ #  # ]:          0 :             if (lu > USHRT_MAX) goto err_range;
        1833                 :          0 :             PACK_SINGLE(ptr, lu, unsigned short); break;
        1834                 :          0 :         case 'I':
        1835         [ #  # ]:          0 :             if (lu > UINT_MAX) goto err_range;
        1836                 :          0 :             PACK_SINGLE(ptr, lu, unsigned int); break;
        1837                 :          0 :         default: /* 'L' */
        1838                 :          0 :             PACK_SINGLE(ptr, lu, unsigned long); break;
        1839                 :            :         }
        1840                 :          0 :         break;
        1841                 :            :
        1842                 :            :     /* native 64-bit */
        1843                 :          0 :     case 'q':
        1844                 :          0 :         lld = pylong_as_lld(item);
        1845   [ #  #  #  # ]:          0 :         if (lld == -1 && PyErr_Occurred())
        1846                 :          0 :             goto err_occurred;
        1847   [ #  #  #  # ]:          0 :         CHECK_RELEASED_INT_AGAIN(self);
        1848                 :          0 :         PACK_SINGLE(ptr, lld, long long);
        1849                 :          0 :         break;
        1850                 :          0 :     case 'Q':
        1851                 :          0 :         llu = pylong_as_llu(item);
        1852   [ #  #  #  # ]:          0 :         if (llu == (unsigned long long)-1 && PyErr_Occurred())
        1853                 :          0 :             goto err_occurred;
        1854   [ #  #  #  # ]:          0 :         CHECK_RELEASED_INT_AGAIN(self);
        1855                 :          0 :         PACK_SINGLE(ptr, llu, unsigned long long);
        1856                 :          0 :         break;
        1857                 :            :
        1858                 :            :     /* ssize_t and size_t */
        1859                 :          0 :     case 'n':
        1860                 :          0 :         zd = pylong_as_zd(item);
        1861   [ #  #  #  # ]:          0 :         if (zd == -1 && PyErr_Occurred())
        1862                 :          0 :             goto err_occurred;
        1863   [ #  #  #  # ]:          0 :         CHECK_RELEASED_INT_AGAIN(self);
        1864                 :          0 :         PACK_SINGLE(ptr, zd, Py_ssize_t);
        1865                 :          0 :         break;
        1866                 :          0 :     case 'N':
        1867                 :          0 :         zu = pylong_as_zu(item);
        1868   [ #  #  #  # ]:          0 :         if (zu == (size_t)-1 && PyErr_Occurred())
        1869                 :          0 :             goto err_occurred;
        1870   [ #  #  #  # ]:          0 :         CHECK_RELEASED_INT_AGAIN(self);
        1871                 :          0 :         PACK_SINGLE(ptr, zu, size_t);
        1872                 :          0 :         break;
        1873                 :            :
        1874                 :            :     /* floats */
        1875                 :          0 :     case 'f': case 'd': case 'e':
        1876                 :          0 :         d = PyFloat_AsDouble(item);
        1877   [ #  #  #  # ]:          0 :         if (d == -1.0 && PyErr_Occurred())
        1878                 :          0 :             goto err_occurred;
        1879   [ #  #  #  # ]:          0 :         CHECK_RELEASED_INT_AGAIN(self);
        1880         [ #  # ]:          0 :         if (fmt[0] == 'f') {
        1881                 :          0 :             PACK_SINGLE(ptr, d, float);
        1882                 :            :         }
        1883         [ #  # ]:          0 :         else if (fmt[0] == 'd') {
        1884                 :          0 :             PACK_SINGLE(ptr, d, double);
        1885                 :            :         }
        1886                 :            :         else {
        1887         [ #  # ]:          0 :             if (PyFloat_Pack2(d, ptr, endian) < 0) {
        1888                 :          0 :                 goto err_occurred;
        1889                 :            :             }
        1890                 :            :         }
        1891                 :          0 :         break;
        1892                 :            :
        1893                 :            :     /* bool */
        1894                 :          0 :     case '?':
        1895                 :          0 :         ld = PyObject_IsTrue(item);
        1896         [ #  # ]:          0 :         if (ld < 0)
        1897                 :          0 :             return -1; /* preserve original error */
        1898   [ #  #  #  # ]:          0 :         CHECK_RELEASED_INT_AGAIN(self);
        1899                 :          0 :         PACK_SINGLE(ptr, ld, _Bool);
        1900                 :          0 :         break;
        1901                 :            :
        1902                 :            :     /* bytes object */
        1903                 :          0 :     case 'c':
        1904         [ #  # ]:          0 :         if (!PyBytes_Check(item))
        1905                 :          0 :             return type_error_int(fmt);
        1906         [ #  # ]:          0 :         if (PyBytes_GET_SIZE(item) != 1)
        1907                 :          0 :             return value_error_int(fmt);
        1908                 :          0 :         *ptr = PyBytes_AS_STRING(item)[0];
        1909                 :          0 :         break;
        1910                 :            :
        1911                 :            :     /* pointer */
        1912                 :          0 :     case 'P':
        1913                 :          0 :         p = PyLong_AsVoidPtr(item);
        1914   [ #  #  #  # ]:          0 :         if (p == NULL && PyErr_Occurred())
        1915                 :          0 :             goto err_occurred;
        1916   [ #  #  #  # ]:          0 :         CHECK_RELEASED_INT_AGAIN(self);
        1917                 :          0 :         PACK_SINGLE(ptr, p, void *);
        1918                 :          0 :         break;
        1919                 :            :
        1920                 :            :     /* default */
        1921                 :          0 :     default: goto err_format;
        1922                 :            :     }
        1923                 :            :
        1924                 :          0 :     return 0;
        1925                 :            :
        1926                 :          0 : err_occurred:
        1927                 :          0 :     return fix_error_int(fmt);
        1928                 :          0 : err_range:
        1929                 :          0 :     return value_error_int(fmt);
        1930                 :          0 : err_format:
        1931                 :          0 :     PyErr_Format(PyExc_NotImplementedError,
        1932                 :            :         "memoryview: format %s not supported", fmt);
        1933                 :          0 :     return -1;
        1934                 :            : }
        1935                 :            :
        1936                 :            :
        1937                 :            : /****************************************************************************/
        1938                 :            : /*                       unpack using the struct module                     */
        1939                 :            : /****************************************************************************/
        1940                 :            :
        1941                 :            : /* For reasonable performance it is necessary to cache all objects required
        1942                 :            :    for unpacking. An unpacker can handle the format passed to unpack_from().
        1943                 :            :    Invariant: All pointer fields of the struct should either be NULL or valid
        1944                 :            :    pointers. */
        1945                 :            : struct unpacker {
        1946                 :            :     PyObject *unpack_from; /* Struct.unpack_from(format) */
        1947                 :            :     PyObject *mview;       /* cached memoryview */
        1948                 :            :     char *item;            /* buffer for mview */
        1949                 :            :     Py_ssize_t itemsize;   /* len(item) */
        1950                 :            : };
        1951                 :            :
        1952                 :            : static struct unpacker *
        1953                 :          0 : unpacker_new(void)
        1954                 :            : {
        1955                 :          0 :     struct unpacker *x = PyMem_Malloc(sizeof *x);
        1956                 :            :
        1957         [ #  # ]:          0 :     if (x == NULL) {
        1958                 :          0 :         PyErr_NoMemory();
        1959                 :          0 :         return NULL;
        1960                 :            :     }
        1961                 :            :
        1962                 :          0 :     x->unpack_from = NULL;
        1963                 :          0 :     x->mview = NULL;
        1964                 :          0 :     x->item = NULL;
        1965                 :          0 :     x->itemsize = 0;
        1966                 :            :
        1967                 :          0 :     return x;
        1968                 :            : }
        1969                 :            :
        1970                 :            : static void
        1971                 :          0 : unpacker_free(struct unpacker *x)
        1972                 :            : {
        1973         [ #  # ]:          0 :     if (x) {
        1974                 :          0 :         Py_XDECREF(x->unpack_from);
        1975                 :          0 :         Py_XDECREF(x->mview);
        1976                 :          0 :         PyMem_Free(x->item);
        1977                 :          0 :         PyMem_Free(x);
        1978                 :            :     }
        1979                 :          0 : }
        1980                 :            :
        1981                 :            : /* Return a new unpacker for the given format. */
        1982                 :            : static struct unpacker *
        1983                 :          0 : struct_get_unpacker(const char *fmt, Py_ssize_t itemsize)
        1984                 :            : {
        1985                 :          0 :     PyObject *Struct = NULL;    /* XXX cache it in globals? */
        1986                 :          0 :     PyObject *structobj = NULL;
        1987                 :          0 :     PyObject *format = NULL;
        1988                 :          0 :     struct unpacker *x = NULL;
        1989                 :            :
        1990                 :          0 :     Struct = _PyImport_GetModuleAttrString("struct", "Struct");
        1991         [ #  # ]:          0 :     if (Struct == NULL)
        1992                 :          0 :         return NULL;
        1993                 :            :
        1994                 :          0 :     x = unpacker_new();
        1995         [ #  # ]:          0 :     if (x == NULL)
        1996                 :          0 :         goto error;
        1997                 :            :
        1998                 :          0 :     format = PyBytes_FromString(fmt);
        1999         [ #  # ]:          0 :     if (format == NULL)
        2000                 :          0 :         goto error;
        2001                 :            :
        2002                 :          0 :     structobj = PyObject_CallOneArg(Struct, format);
        2003         [ #  # ]:          0 :     if (structobj == NULL)
        2004                 :          0 :         goto error;
        2005                 :            :
        2006                 :          0 :     x->unpack_from = PyObject_GetAttrString(structobj, "unpack_from");
        2007         [ #  # ]:          0 :     if (x->unpack_from == NULL)
        2008                 :          0 :         goto error;
        2009                 :            :
        2010                 :          0 :     x->item = PyMem_Malloc(itemsize);
        2011         [ #  # ]:          0 :     if (x->item == NULL) {
        2012                 :          0 :         PyErr_NoMemory();
        2013                 :          0 :         goto error;
        2014                 :            :     }
        2015                 :          0 :     x->itemsize = itemsize;
        2016                 :            :
        2017                 :          0 :     x->mview = PyMemoryView_FromMemory(x->item, itemsize, PyBUF_WRITE);
        2018         [ #  # ]:          0 :     if (x->mview == NULL)
        2019                 :          0 :         goto error;
        2020                 :            :
        2021                 :            :
        2022                 :          0 : out:
        2023                 :          0 :     Py_XDECREF(Struct);
        2024                 :          0 :     Py_XDECREF(format);
        2025                 :          0 :     Py_XDECREF(structobj);
        2026                 :          0 :     return x;
        2027                 :            :
        2028                 :          0 : error:
        2029                 :          0 :     unpacker_free(x);
        2030                 :          0 :     x = NULL;
        2031                 :          0 :     goto out;
        2032                 :            : }
        2033                 :            :
        2034                 :            : /* unpack a single item */
        2035                 :            : static PyObject *
        2036                 :          0 : struct_unpack_single(const char *ptr, struct unpacker *x)
        2037                 :            : {
        2038                 :            :     PyObject *v;
        2039                 :            :
        2040                 :          0 :     memcpy(x->item, ptr, x->itemsize);
        2041                 :          0 :     v = PyObject_CallOneArg(x->unpack_from, x->mview);
        2042         [ #  # ]:          0 :     if (v == NULL)
        2043                 :          0 :         return NULL;
        2044                 :            :
        2045         [ #  # ]:          0 :     if (PyTuple_GET_SIZE(v) == 1) {
        2046                 :          0 :         PyObject *res = Py_NewRef(PyTuple_GET_ITEM(v, 0));
        2047                 :          0 :         Py_DECREF(v);
        2048                 :          0 :         return res;
        2049                 :            :     }
        2050                 :            :
        2051                 :          0 :     return v;
        2052                 :            : }
        2053                 :            :
        2054                 :            :
        2055                 :            : /****************************************************************************/
        2056                 :            : /*                              Representations                             */
        2057                 :            : /****************************************************************************/
        2058                 :            :
        2059                 :            : /* allow explicit form of native format */
        2060                 :            : static inline const char *
        2061                 :          3 : adjust_fmt(const Py_buffer *view)
        2062                 :            : {
        2063                 :            :     const char *fmt;
        2064                 :            :
        2065         [ -  + ]:          3 :     fmt = (view->format[0] == '@') ? view->format+1 : view->format;
        2066   [ +  -  +  - ]:          3 :     if (fmt[0] && fmt[1] == '\0')
        2067                 :          3 :         return fmt;
        2068                 :            :
        2069                 :          0 :     PyErr_Format(PyExc_NotImplementedError,
        2070                 :            :         "memoryview: unsupported format %s", view->format);
        2071                 :          0 :     return NULL;
        2072                 :            : }
        2073                 :            :
        2074                 :            : /* Base case for multi-dimensional unpacking. Assumption: ndim == 1. */
        2075                 :            : static PyObject *
        2076                 :          3 : tolist_base(PyMemoryViewObject *self, const char *ptr, const Py_ssize_t *shape,
        2077                 :            :             const Py_ssize_t *strides, const Py_ssize_t *suboffsets,
        2078                 :            :             const char *fmt)
        2079                 :            : {
        2080                 :            :     PyObject *lst, *item;
        2081                 :            :     Py_ssize_t i;
        2082                 :            :
        2083                 :          3 :     lst = PyList_New(shape[0]);
        2084         [ -  + ]:          3 :     if (lst == NULL)
        2085                 :          0 :         return NULL;
        2086                 :            :
        2087         [ +  + ]:        195 :     for (i = 0; i < shape[0]; ptr+=strides[0], i++) {
        2088   [ -  +  -  - ]:        192 :         const char *xptr = ADJUST_PTR(ptr, suboffsets, 0);
        2089                 :        192 :         item = unpack_single(self, xptr, fmt);
        2090         [ -  + ]:        192 :         if (item == NULL) {
        2091                 :          0 :             Py_DECREF(lst);
        2092                 :          0 :             return NULL;
        2093                 :            :         }
        2094                 :        192 :         PyList_SET_ITEM(lst, i, item);
        2095                 :            :     }
        2096                 :            :
        2097                 :          3 :     return lst;
        2098                 :            : }
        2099                 :            :
        2100                 :            : /* Unpack a multi-dimensional array into a nested list.
        2101                 :            :    Assumption: ndim >= 1. */
        2102                 :            : static PyObject *
        2103                 :          0 : tolist_rec(PyMemoryViewObject *self, const char *ptr, Py_ssize_t ndim, const Py_ssize_t *shape,
        2104                 :            :            const Py_ssize_t *strides, const Py_ssize_t *suboffsets,
        2105                 :            :            const char *fmt)
        2106                 :            : {
        2107                 :            :     PyObject *lst, *item;
        2108                 :            :     Py_ssize_t i;
        2109                 :            :
        2110                 :            :     assert(ndim >= 1);
        2111                 :            :     assert(shape != NULL);
        2112                 :            :     assert(strides != NULL);
        2113                 :            :
        2114         [ #  # ]:          0 :     if (ndim == 1)
        2115                 :          0 :         return tolist_base(self, ptr, shape, strides, suboffsets, fmt);
        2116                 :            :
        2117                 :          0 :     lst = PyList_New(shape[0]);
        2118         [ #  # ]:          0 :     if (lst == NULL)
        2119                 :          0 :         return NULL;
        2120                 :            :
        2121         [ #  # ]:          0 :     for (i = 0; i < shape[0]; ptr+=strides[0], i++) {
        2122   [ #  #  #  # ]:          0 :         const char *xptr = ADJUST_PTR(ptr, suboffsets, 0);
        2123         [ #  # ]:          0 :         item = tolist_rec(self, xptr, ndim-1, shape+1,
        2124                 :            :                           strides+1, suboffsets ? suboffsets+1 : NULL,
        2125                 :            :                           fmt);
        2126         [ #  # ]:          0 :         if (item == NULL) {
        2127                 :          0 :             Py_DECREF(lst);
        2128                 :          0 :             return NULL;
        2129                 :            :         }
        2130                 :          0 :         PyList_SET_ITEM(lst, i, item);
        2131                 :            :     }
        2132                 :            :
        2133                 :          0 :     return lst;
        2134                 :            : }
        2135                 :            :
        2136                 :            : /* Return a list representation of the memoryview. Currently only buffers
        2137                 :            :    with native format strings are supported. */
        2138                 :            : /*[clinic input]
        2139                 :            : memoryview.tolist
        2140                 :            :
        2141                 :            : Return the data in the buffer as a list of elements.
        2142                 :            : [clinic start generated code]*/
        2143                 :            :
        2144                 :            : static PyObject *
        2145                 :          3 : memoryview_tolist_impl(PyMemoryViewObject *self)
        2146                 :            : /*[clinic end generated code: output=a6cda89214fd5a1b input=21e7d0c1860b211a]*/
        2147                 :            : {
        2148                 :          3 :     const Py_buffer *view = &self->view;
        2149                 :            :     const char *fmt;
        2150                 :            :
        2151   [ +  -  -  + ]:          3 :     CHECK_RELEASED(self);
        2152                 :            :
        2153                 :          3 :     fmt = adjust_fmt(view);
        2154         [ -  + ]:          3 :     if (fmt == NULL)
        2155                 :          0 :         return NULL;
        2156         [ -  + ]:          3 :     if (view->ndim == 0) {
        2157                 :          0 :         return unpack_single(self, view->buf, fmt);
        2158                 :            :     }
        2159         [ +  - ]:          3 :     else if (view->ndim == 1) {
        2160                 :          3 :         return tolist_base(self, view->buf, view->shape,
        2161                 :          3 :                            view->strides, view->suboffsets,
        2162                 :            :                            fmt);
        2163                 :            :     }
        2164                 :            :     else {
        2165                 :          0 :         return tolist_rec(self, view->buf, view->ndim, view->shape,
        2166                 :          0 :                           view->strides, view->suboffsets,
        2167                 :            :                           fmt);
        2168                 :            :     }
        2169                 :            : }
        2170                 :            :
        2171                 :            : /*[clinic input]
        2172                 :            : memoryview.tobytes
        2173                 :            :
        2174                 :            :     order: str(accept={str, NoneType}, c_default="NULL") = 'C'
        2175                 :            :
        2176                 :            : Return the data in the buffer as a byte string.
        2177                 :            :
        2178                 :            : Order can be {'C', 'F', 'A'}. When order is 'C' or 'F', the data of the
        2179                 :            : original array is converted to C or Fortran order. For contiguous views,
        2180                 :            : 'A' returns an exact copy of the physical memory. In particular, in-memory
        2181                 :            : Fortran order is preserved. For non-contiguous views, the data is converted
        2182                 :            : to C first. order=None is the same as order='C'.
        2183                 :            : [clinic start generated code]*/
        2184                 :            :
        2185                 :            : static PyObject *
        2186                 :          0 : memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order)
        2187                 :            : /*[clinic end generated code: output=1288b62560a32a23 input=0efa3ddaeda573a8]*/
        2188                 :            : {
        2189                 :          0 :     Py_buffer *src = VIEW_ADDR(self);
        2190                 :          0 :     char ord = 'C';
        2191                 :            :     PyObject *bytes;
        2192                 :            :
        2193   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        2194                 :            :
        2195         [ #  # ]:          0 :     if (order) {
        2196         [ #  # ]:          0 :         if (strcmp(order, "F") == 0) {
        2197                 :          0 :             ord = 'F';
        2198                 :            :         }
        2199         [ #  # ]:          0 :         else if (strcmp(order, "A") == 0) {
        2200                 :          0 :             ord = 'A';
        2201                 :            :         }
        2202         [ #  # ]:          0 :         else if (strcmp(order, "C") != 0) {
        2203                 :          0 :             PyErr_SetString(PyExc_ValueError,
        2204                 :            :                 "order must be 'C', 'F' or 'A'");
        2205                 :          0 :             return NULL;
        2206                 :            :         }
        2207                 :            :     }
        2208                 :            :
        2209                 :          0 :     bytes = PyBytes_FromStringAndSize(NULL, src->len);
        2210         [ #  # ]:          0 :     if (bytes == NULL)
        2211                 :          0 :         return NULL;
        2212                 :            :
        2213         [ #  # ]:          0 :     if (PyBuffer_ToContiguous(PyBytes_AS_STRING(bytes), src, src->len, ord) < 0) {
        2214                 :          0 :         Py_DECREF(bytes);
        2215                 :          0 :         return NULL;
        2216                 :            :     }
        2217                 :            :
        2218                 :          0 :     return bytes;
        2219                 :            : }
        2220                 :            :
        2221                 :            : /*[clinic input]
        2222                 :            : memoryview.hex
        2223                 :            :
        2224                 :            :     sep: object = NULL
        2225                 :            :         An optional single character or byte to separate hex bytes.
        2226                 :            :     bytes_per_sep: int = 1
        2227                 :            :         How many bytes between separators.  Positive values count from the
        2228                 :            :         right, negative values count from the left.
        2229                 :            :
        2230                 :            : Return the data in the buffer as a str of hexadecimal numbers.
        2231                 :            :
        2232                 :            : Example:
        2233                 :            : >>> value = memoryview(b'\xb9\x01\xef')
        2234                 :            : >>> value.hex()
        2235                 :            : 'b901ef'
        2236                 :            : >>> value.hex(':')
        2237                 :            : 'b9:01:ef'
        2238                 :            : >>> value.hex(':', 2)
        2239                 :            : 'b9:01ef'
        2240                 :            : >>> value.hex(':', -2)
        2241                 :            : 'b901:ef'
        2242                 :            : [clinic start generated code]*/
        2243                 :            :
        2244                 :            : static PyObject *
        2245                 :          0 : memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep,
        2246                 :            :                     int bytes_per_sep)
        2247                 :            : /*[clinic end generated code: output=430ca760f94f3ca7 input=539f6a3a5fb56946]*/
        2248                 :            : {
        2249                 :          0 :     Py_buffer *src = VIEW_ADDR(self);
        2250                 :            :     PyObject *bytes;
        2251                 :            :     PyObject *ret;
        2252                 :            :
        2253   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        2254                 :            :
        2255         [ #  # ]:          0 :     if (MV_C_CONTIGUOUS(self->flags)) {
        2256                 :          0 :         return _Py_strhex_with_sep(src->buf, src->len, sep, bytes_per_sep);
        2257                 :            :     }
        2258                 :            :
        2259                 :          0 :     bytes = PyBytes_FromStringAndSize(NULL, src->len);
        2260         [ #  # ]:          0 :     if (bytes == NULL)
        2261                 :          0 :         return NULL;
        2262                 :            :
        2263         [ #  # ]:          0 :     if (PyBuffer_ToContiguous(PyBytes_AS_STRING(bytes), src, src->len, 'C') < 0) {
        2264                 :          0 :         Py_DECREF(bytes);
        2265                 :          0 :         return NULL;
        2266                 :            :     }
        2267                 :            :
        2268                 :          0 :     ret = _Py_strhex_with_sep(
        2269                 :          0 :             PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes),
        2270                 :            :             sep, bytes_per_sep);
        2271                 :          0 :     Py_DECREF(bytes);
        2272                 :            :
        2273                 :          0 :     return ret;
        2274                 :            : }
        2275                 :            :
        2276                 :            : static PyObject *
        2277                 :          0 : memory_repr(PyMemoryViewObject *self)
        2278                 :            : {
        2279         [ #  # ]:          0 :     if (self->flags & _Py_MEMORYVIEW_RELEASED)
        2280                 :          0 :         return PyUnicode_FromFormat("<released memory at %p>", self);
        2281                 :            :     else
        2282                 :          0 :         return PyUnicode_FromFormat("<memory at %p>", self);
        2283                 :            : }
        2284                 :            :
        2285                 :            :
        2286                 :            : /**************************************************************************/
        2287                 :            : /*                          Indexing and slicing                          */
        2288                 :            : /**************************************************************************/
        2289                 :            :
        2290                 :            : static char *
        2291                 :          0 : lookup_dimension(const Py_buffer *view, char *ptr, int dim, Py_ssize_t index)
        2292                 :            : {
        2293                 :            :     Py_ssize_t nitems; /* items in the given dimension */
        2294                 :            :
        2295                 :            :     assert(view->shape);
        2296                 :            :     assert(view->strides);
        2297                 :            :
        2298                 :          0 :     nitems = view->shape[dim];
        2299         [ #  # ]:          0 :     if (index < 0) {
        2300                 :          0 :         index += nitems;
        2301                 :            :     }
        2302   [ #  #  #  # ]:          0 :     if (index < 0 || index >= nitems) {
        2303                 :          0 :         PyErr_Format(PyExc_IndexError,
        2304                 :            :                      "index out of bounds on dimension %d", dim + 1);
        2305                 :          0 :         return NULL;
        2306                 :            :     }
        2307                 :            :
        2308                 :          0 :     ptr += view->strides[dim] * index;
        2309                 :            :
        2310   [ #  #  #  # ]:          0 :     ptr = ADJUST_PTR(ptr, view->suboffsets, dim);
        2311                 :            :
        2312                 :          0 :     return ptr;
        2313                 :            : }
        2314                 :            :
        2315                 :            : /* Get the pointer to the item at index. */
        2316                 :            : static char *
        2317                 :          0 : ptr_from_index(const Py_buffer *view, Py_ssize_t index)
        2318                 :            : {
        2319                 :          0 :     char *ptr = (char *)view->buf;
        2320                 :          0 :     return lookup_dimension(view, ptr, 0, index);
        2321                 :            : }
        2322                 :            :
        2323                 :            : /* Get the pointer to the item at tuple. */
        2324                 :            : static char *
        2325                 :          0 : ptr_from_tuple(const Py_buffer *view, PyObject *tup)
        2326                 :            : {
        2327                 :          0 :     char *ptr = (char *)view->buf;
        2328                 :          0 :     Py_ssize_t dim, nindices = PyTuple_GET_SIZE(tup);
        2329                 :            :
        2330         [ #  # ]:          0 :     if (nindices > view->ndim) {
        2331                 :          0 :         PyErr_Format(PyExc_TypeError,
        2332                 :            :                      "cannot index %zd-dimension view with %zd-element tuple",
        2333                 :            :                      view->ndim, nindices);
        2334                 :          0 :         return NULL;
        2335                 :            :     }
        2336                 :            :
        2337         [ #  # ]:          0 :     for (dim = 0; dim < nindices; dim++) {
        2338                 :            :         Py_ssize_t index;
        2339                 :          0 :         index = PyNumber_AsSsize_t(PyTuple_GET_ITEM(tup, dim),
        2340                 :            :                                    PyExc_IndexError);
        2341   [ #  #  #  # ]:          0 :         if (index == -1 && PyErr_Occurred())
        2342                 :          0 :             return NULL;
        2343                 :          0 :         ptr = lookup_dimension(view, ptr, (int)dim, index);
        2344         [ #  # ]:          0 :         if (ptr == NULL)
        2345                 :          0 :             return NULL;
        2346                 :            :     }
        2347                 :          0 :     return ptr;
        2348                 :            : }
        2349                 :            :
        2350                 :            : /* Return the item at index. In a one-dimensional view, this is an object
        2351                 :            :    with the type specified by view->format. Otherwise, the item is a sub-view.
        2352                 :            :    The function is used in memory_subscript() and memory_as_sequence. */
        2353                 :            : static PyObject *
        2354                 :          0 : memory_item(PyMemoryViewObject *self, Py_ssize_t index)
        2355                 :            : {
        2356                 :          0 :     Py_buffer *view = &(self->view);
        2357                 :            :     const char *fmt;
        2358                 :            :
        2359   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        2360                 :            :
        2361                 :          0 :     fmt = adjust_fmt(view);
        2362         [ #  # ]:          0 :     if (fmt == NULL)
        2363                 :          0 :         return NULL;
        2364                 :            :
        2365         [ #  # ]:          0 :     if (view->ndim == 0) {
        2366                 :          0 :         PyErr_SetString(PyExc_TypeError, "invalid indexing of 0-dim memory");
        2367                 :          0 :         return NULL;
        2368                 :            :     }
        2369         [ #  # ]:          0 :     if (view->ndim == 1) {
        2370                 :          0 :         char *ptr = ptr_from_index(view, index);
        2371         [ #  # ]:          0 :         if (ptr == NULL)
        2372                 :          0 :             return NULL;
        2373                 :          0 :         return unpack_single(self, ptr, fmt);
        2374                 :            :     }
        2375                 :            :
        2376                 :          0 :     PyErr_SetString(PyExc_NotImplementedError,
        2377                 :            :         "multi-dimensional sub-views are not implemented");
        2378                 :          0 :     return NULL;
        2379                 :            : }
        2380                 :            :
        2381                 :            : /* Return the item at position *key* (a tuple of indices). */
        2382                 :            : static PyObject *
        2383                 :          0 : memory_item_multi(PyMemoryViewObject *self, PyObject *tup)
        2384                 :            : {
        2385                 :          0 :     Py_buffer *view = &(self->view);
        2386                 :            :     const char *fmt;
        2387                 :          0 :     Py_ssize_t nindices = PyTuple_GET_SIZE(tup);
        2388                 :            :     char *ptr;
        2389                 :            :
        2390   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        2391                 :            :
        2392                 :          0 :     fmt = adjust_fmt(view);
        2393         [ #  # ]:          0 :     if (fmt == NULL)
        2394                 :          0 :         return NULL;
        2395                 :            :
        2396         [ #  # ]:          0 :     if (nindices < view->ndim) {
        2397                 :          0 :         PyErr_SetString(PyExc_NotImplementedError,
        2398                 :            :                         "sub-views are not implemented");
        2399                 :          0 :         return NULL;
        2400                 :            :     }
        2401                 :          0 :     ptr = ptr_from_tuple(view, tup);
        2402         [ #  # ]:          0 :     if (ptr == NULL)
        2403                 :          0 :         return NULL;
        2404                 :          0 :     return unpack_single(self, ptr, fmt);
        2405                 :            : }
        2406                 :            :
        2407                 :            : static inline int
        2408                 :        386 : init_slice(Py_buffer *base, PyObject *key, int dim)
        2409                 :            : {
        2410                 :            :     Py_ssize_t start, stop, step, slicelength;
        2411                 :            :
        2412         [ -  + ]:        386 :     if (PySlice_Unpack(key, &start, &stop, &step) < 0) {
        2413                 :          0 :         return -1;
        2414                 :            :     }
        2415                 :        386 :     slicelength = PySlice_AdjustIndices(base->shape[dim], &start, &stop, step);
        2416                 :            :
        2417                 :            :
        2418   [ +  -  -  - ]:        386 :     if (base->suboffsets == NULL || dim == 0) {
        2419                 :        386 :     adjust_buf:
        2420                 :        386 :         base->buf = (char *)base->buf + base->strides[dim] * start;
        2421                 :            :     }
        2422                 :            :     else {
        2423                 :          0 :         Py_ssize_t n = dim-1;
        2424   [ #  #  #  # ]:          0 :         while (n >= 0 && base->suboffsets[n] < 0)
        2425                 :          0 :             n--;
        2426         [ #  # ]:          0 :         if (n < 0)
        2427                 :          0 :             goto adjust_buf; /* all suboffsets are negative */
        2428                 :          0 :         base->suboffsets[n] = base->suboffsets[n] + base->strides[dim] * start;
        2429                 :            :     }
        2430                 :        386 :     base->shape[dim] = slicelength;
        2431                 :        386 :     base->strides[dim] = base->strides[dim] * step;
        2432                 :            :
        2433                 :        386 :     return 0;
        2434                 :            : }
        2435                 :            :
        2436                 :            : static int
        2437                 :          0 : is_multislice(PyObject *key)
        2438                 :            : {
        2439                 :            :     Py_ssize_t size, i;
        2440                 :            :
        2441         [ #  # ]:          0 :     if (!PyTuple_Check(key))
        2442                 :          0 :         return 0;
        2443                 :          0 :     size = PyTuple_GET_SIZE(key);
        2444         [ #  # ]:          0 :     if (size == 0)
        2445                 :          0 :         return 0;
        2446                 :            :
        2447         [ #  # ]:          0 :     for (i = 0; i < size; i++) {
        2448                 :          0 :         PyObject *x = PyTuple_GET_ITEM(key, i);
        2449         [ #  # ]:          0 :         if (!PySlice_Check(x))
        2450                 :          0 :             return 0;
        2451                 :            :     }
        2452                 :          0 :     return 1;
        2453                 :            : }
        2454                 :            :
        2455                 :            : static Py_ssize_t
        2456                 :          0 : is_multiindex(PyObject *key)
        2457                 :            : {
        2458                 :            :     Py_ssize_t size, i;
        2459                 :            :
        2460         [ #  # ]:          0 :     if (!PyTuple_Check(key))
        2461                 :          0 :         return 0;
        2462                 :          0 :     size = PyTuple_GET_SIZE(key);
        2463         [ #  # ]:          0 :     for (i = 0; i < size; i++) {
        2464                 :          0 :         PyObject *x = PyTuple_GET_ITEM(key, i);
        2465         [ #  # ]:          0 :         if (!_PyIndex_Check(x)) {
        2466                 :          0 :             return 0;
        2467                 :            :         }
        2468                 :            :     }
        2469                 :          0 :     return 1;
        2470                 :            : }
        2471                 :            :
        2472                 :            : /* mv[obj] returns an object holding the data for one element if obj
        2473                 :            :    fully indexes the memoryview or another memoryview object if it
        2474                 :            :    does not.
        2475                 :            :
        2476                 :            :    0-d memoryview objects can be referenced using mv[...] or mv[()]
        2477                 :            :    but not with anything else. */
        2478                 :            : static PyObject *
        2479                 :        386 : memory_subscript(PyMemoryViewObject *self, PyObject *key)
        2480                 :            : {
        2481                 :            :     Py_buffer *view;
        2482                 :        386 :     view = &(self->view);
        2483                 :            :
        2484   [ +  -  -  + ]:        386 :     CHECK_RELEASED(self);
        2485                 :            :
        2486         [ -  + ]:        386 :     if (view->ndim == 0) {
        2487   [ #  #  #  # ]:          0 :         if (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0) {
        2488                 :          0 :             const char *fmt = adjust_fmt(view);
        2489         [ #  # ]:          0 :             if (fmt == NULL)
        2490                 :          0 :                 return NULL;
        2491                 :          0 :             return unpack_single(self, view->buf, fmt);
        2492                 :            :         }
        2493         [ #  # ]:          0 :         else if (key == Py_Ellipsis) {
        2494                 :          0 :             return Py_NewRef(self);
        2495                 :            :         }
        2496                 :            :         else {
        2497                 :          0 :             PyErr_SetString(PyExc_TypeError,
        2498                 :            :                 "invalid indexing of 0-dim memory");
        2499                 :          0 :             return NULL;
        2500                 :            :         }
        2501                 :            :     }
        2502                 :            :
        2503         [ -  + ]:        386 :     if (_PyIndex_Check(key)) {
        2504                 :            :         Py_ssize_t index;
        2505                 :          0 :         index = PyNumber_AsSsize_t(key, PyExc_IndexError);
        2506   [ #  #  #  # ]:          0 :         if (index == -1 && PyErr_Occurred())
        2507                 :          0 :             return NULL;
        2508                 :          0 :         return memory_item(self, index);
        2509                 :            :     }
        2510         [ +  - ]:        386 :     else if (PySlice_Check(key)) {
        2511                 :            :         PyMemoryViewObject *sliced;
        2512                 :            :
        2513                 :        386 :         sliced = (PyMemoryViewObject *)mbuf_add_view(self->mbuf, view);
        2514         [ -  + ]:        386 :         if (sliced == NULL)
        2515                 :          0 :             return NULL;
        2516                 :            :
        2517         [ -  + ]:        386 :         if (init_slice(&sliced->view, key, 0) < 0) {
        2518                 :          0 :             Py_DECREF(sliced);
        2519                 :          0 :             return NULL;
        2520                 :            :         }
        2521                 :        386 :         init_len(&sliced->view);
        2522                 :        386 :         init_flags(sliced);
        2523                 :            :
        2524                 :        386 :         return (PyObject *)sliced;
        2525                 :            :     }
        2526         [ #  # ]:          0 :     else if (is_multiindex(key)) {
        2527                 :          0 :         return memory_item_multi(self, key);
        2528                 :            :     }
        2529         [ #  # ]:          0 :     else if (is_multislice(key)) {
        2530                 :          0 :         PyErr_SetString(PyExc_NotImplementedError,
        2531                 :            :             "multi-dimensional slicing is not implemented");
        2532                 :          0 :         return NULL;
        2533                 :            :     }
        2534                 :            :
        2535                 :          0 :     PyErr_SetString(PyExc_TypeError, "memoryview: invalid slice key");
        2536                 :          0 :     return NULL;
        2537                 :            : }
        2538                 :            :
        2539                 :            : static int
        2540                 :          0 : memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
        2541                 :            : {
        2542                 :          0 :     Py_buffer *view = &(self->view);
        2543                 :            :     Py_buffer src;
        2544                 :            :     const char *fmt;
        2545                 :            :     char *ptr;
        2546                 :            :
        2547   [ #  #  #  # ]:          0 :     CHECK_RELEASED_INT(self);
        2548                 :            :
        2549                 :          0 :     fmt = adjust_fmt(view);
        2550         [ #  # ]:          0 :     if (fmt == NULL)
        2551                 :          0 :         return -1;
        2552                 :            :
        2553         [ #  # ]:          0 :     if (view->readonly) {
        2554                 :          0 :         PyErr_SetString(PyExc_TypeError, "cannot modify read-only memory");
        2555                 :          0 :         return -1;
        2556                 :            :     }
        2557         [ #  # ]:          0 :     if (value == NULL) {
        2558                 :          0 :         PyErr_SetString(PyExc_TypeError, "cannot delete memory");
        2559                 :          0 :         return -1;
        2560                 :            :     }
        2561         [ #  # ]:          0 :     if (view->ndim == 0) {
        2562   [ #  #  #  # ]:          0 :         if (key == Py_Ellipsis ||
        2563         [ #  # ]:          0 :             (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
        2564                 :          0 :             ptr = (char *)view->buf;
        2565                 :          0 :             return pack_single(self, ptr, value, fmt);
        2566                 :            :         }
        2567                 :            :         else {
        2568                 :          0 :             PyErr_SetString(PyExc_TypeError,
        2569                 :            :                 "invalid indexing of 0-dim memory");
        2570                 :          0 :             return -1;
        2571                 :            :         }
        2572                 :            :     }
        2573                 :            :
        2574         [ #  # ]:          0 :     if (_PyIndex_Check(key)) {
        2575                 :            :         Py_ssize_t index;
        2576         [ #  # ]:          0 :         if (1 < view->ndim) {
        2577                 :          0 :             PyErr_SetString(PyExc_NotImplementedError,
        2578                 :            :                             "sub-views are not implemented");
        2579                 :          0 :             return -1;
        2580                 :            :         }
        2581                 :          0 :         index = PyNumber_AsSsize_t(key, PyExc_IndexError);
        2582   [ #  #  #  # ]:          0 :         if (index == -1 && PyErr_Occurred())
        2583                 :          0 :             return -1;
        2584                 :          0 :         ptr = ptr_from_index(view, index);
        2585         [ #  # ]:          0 :         if (ptr == NULL)
        2586                 :          0 :             return -1;
        2587                 :          0 :         return pack_single(self, ptr, value, fmt);
        2588                 :            :     }
        2589                 :            :     /* one-dimensional: fast path */
        2590   [ #  #  #  # ]:          0 :     if (PySlice_Check(key) && view->ndim == 1) {
        2591                 :            :         Py_buffer dest; /* sliced view */
        2592                 :            :         Py_ssize_t arrays[3];
        2593                 :          0 :         int ret = -1;
        2594                 :            :
        2595                 :            :         /* rvalue must be an exporter */
        2596         [ #  # ]:          0 :         if (PyObject_GetBuffer(value, &src, PyBUF_FULL_RO) < 0)
        2597                 :          0 :             return ret;
        2598                 :            :
        2599                 :          0 :         dest = *view;
        2600                 :          0 :         dest.shape = &arrays[0]; dest.shape[0] = view->shape[0];
        2601                 :          0 :         dest.strides = &arrays[1]; dest.strides[0] = view->strides[0];
        2602         [ #  # ]:          0 :         if (view->suboffsets) {
        2603                 :          0 :             dest.suboffsets = &arrays[2]; dest.suboffsets[0] = view->suboffsets[0];
        2604                 :            :         }
        2605                 :            :
        2606         [ #  # ]:          0 :         if (init_slice(&dest, key, 0) < 0)
        2607                 :          0 :             goto end_block;
        2608                 :          0 :         dest.len = dest.shape[0] * dest.itemsize;
        2609                 :            :
        2610                 :          0 :         ret = copy_single(self, &dest, &src);
        2611                 :            :
        2612                 :          0 :     end_block:
        2613                 :          0 :         PyBuffer_Release(&src);
        2614                 :          0 :         return ret;
        2615                 :            :     }
        2616         [ #  # ]:          0 :     if (is_multiindex(key)) {
        2617                 :            :         char *ptr;
        2618         [ #  # ]:          0 :         if (PyTuple_GET_SIZE(key) < view->ndim) {
        2619                 :          0 :             PyErr_SetString(PyExc_NotImplementedError,
        2620                 :            :                             "sub-views are not implemented");
        2621                 :          0 :             return -1;
        2622                 :            :         }
        2623                 :          0 :         ptr = ptr_from_tuple(view, key);
        2624         [ #  # ]:          0 :         if (ptr == NULL)
        2625                 :          0 :             return -1;
        2626                 :          0 :         return pack_single(self, ptr, value, fmt);
        2627                 :            :     }
        2628   [ #  #  #  # ]:          0 :     if (PySlice_Check(key) || is_multislice(key)) {
        2629                 :            :         /* Call memory_subscript() to produce a sliced lvalue, then copy
        2630                 :            :            rvalue into lvalue. This is already implemented in _testbuffer.c. */
        2631                 :          0 :         PyErr_SetString(PyExc_NotImplementedError,
        2632                 :            :             "memoryview slice assignments are currently restricted "
        2633                 :            :             "to ndim = 1");
        2634                 :          0 :         return -1;
        2635                 :            :     }
        2636                 :            :
        2637                 :          0 :     PyErr_SetString(PyExc_TypeError, "memoryview: invalid slice key");
        2638                 :          0 :     return -1;
        2639                 :            : }
        2640                 :            :
        2641                 :            : static Py_ssize_t
        2642                 :          3 : memory_length(PyMemoryViewObject *self)
        2643                 :            : {
        2644   [ +  -  -  + ]:          3 :     CHECK_RELEASED_INT(self);
        2645         [ +  - ]:          3 :     return self->view.ndim == 0 ? 1 : self->view.shape[0];
        2646                 :            : }
        2647                 :            :
        2648                 :            : /* As mapping */
        2649                 :            : static PyMappingMethods memory_as_mapping = {
        2650                 :            :     (lenfunc)memory_length,               /* mp_length */
        2651                 :            :     (binaryfunc)memory_subscript,         /* mp_subscript */
        2652                 :            :     (objobjargproc)memory_ass_sub,        /* mp_ass_subscript */
        2653                 :            : };
        2654                 :            :
        2655                 :            : /* As sequence */
        2656                 :            : static PySequenceMethods memory_as_sequence = {
        2657                 :            :         (lenfunc)memory_length,           /* sq_length */
        2658                 :            :         0,                                /* sq_concat */
        2659                 :            :         0,                                /* sq_repeat */
        2660                 :            :         (ssizeargfunc)memory_item,        /* sq_item */
        2661                 :            : };
        2662                 :            :
        2663                 :            :
        2664                 :            : /**************************************************************************/
        2665                 :            : /*                             Comparisons                                */
        2666                 :            : /**************************************************************************/
        2667                 :            :
        2668                 :            : #define MV_COMPARE_EX -1       /* exception */
        2669                 :            : #define MV_COMPARE_NOT_IMPL -2 /* not implemented */
        2670                 :            :
        2671                 :            : /* Translate a StructError to "not equal". Preserve other exceptions. */
        2672                 :            : static int
        2673                 :          0 : fix_struct_error_int(void)
        2674                 :            : {
        2675                 :            :     assert(PyErr_Occurred());
        2676                 :            :     /* XXX Cannot get at StructError directly? */
        2677   [ #  #  #  # ]:          0 :     if (PyErr_ExceptionMatches(PyExc_ImportError) ||
        2678                 :          0 :         PyErr_ExceptionMatches(PyExc_MemoryError)) {
        2679                 :          0 :         return MV_COMPARE_EX;
        2680                 :            :     }
        2681                 :            :     /* StructError: invalid or unknown format -> not equal */
        2682                 :          0 :     PyErr_Clear();
        2683                 :          0 :     return 0;
        2684                 :            : }
        2685                 :            :
        2686                 :            : /* Unpack and compare single items of p and q using the struct module. */
        2687                 :            : static int
        2688                 :          0 : struct_unpack_cmp(const char *p, const char *q,
        2689                 :            :                   struct unpacker *unpack_p, struct unpacker *unpack_q)
        2690                 :            : {
        2691                 :            :     PyObject *v, *w;
        2692                 :            :     int ret;
        2693                 :            :
        2694                 :            :     /* At this point any exception from the struct module should not be
        2695                 :            :        StructError, since both formats have been accepted already. */
        2696                 :          0 :     v = struct_unpack_single(p, unpack_p);
        2697         [ #  # ]:          0 :     if (v == NULL)
        2698                 :          0 :         return MV_COMPARE_EX;
        2699                 :            :
        2700                 :          0 :     w = struct_unpack_single(q, unpack_q);
        2701         [ #  # ]:          0 :     if (w == NULL) {
        2702                 :          0 :         Py_DECREF(v);
        2703                 :          0 :         return MV_COMPARE_EX;
        2704                 :            :     }
        2705                 :            :
        2706                 :            :     /* MV_COMPARE_EX == -1: exceptions are preserved */
        2707                 :          0 :     ret = PyObject_RichCompareBool(v, w, Py_EQ);
        2708                 :          0 :     Py_DECREF(v);
        2709                 :          0 :     Py_DECREF(w);
        2710                 :            :
        2711                 :          0 :     return ret;
        2712                 :            : }
        2713                 :            :
        2714                 :            : /* Unpack and compare single items of p and q. If both p and q have the same
        2715                 :            :    single element native format, the comparison uses a fast path (gcc creates
        2716                 :            :    a jump table and converts memcpy into simple assignments on x86/x64).
        2717                 :            :
        2718                 :            :    Otherwise, the comparison is delegated to the struct module, which is
        2719                 :            :    30-60x slower. */
        2720                 :            : #define CMP_SINGLE(p, q, type) \
        2721                 :            :     do {                                 \
        2722                 :            :         type x;                          \
        2723                 :            :         type y;                          \
        2724                 :            :         memcpy((char *)&x, p, sizeof x); \
        2725                 :            :         memcpy((char *)&y, q, sizeof y); \
        2726                 :            :         equal = (x == y);                \
        2727                 :            :     } while (0)
        2728                 :            :
        2729                 :            : static inline int
        2730                 :          0 : unpack_cmp(const char *p, const char *q, char fmt,
        2731                 :            :            struct unpacker *unpack_p, struct unpacker *unpack_q)
        2732                 :            : {
        2733                 :            :     int equal;
        2734                 :            :
        2735   [ #  #  #  #  :          0 :     switch (fmt) {
              #  #  #  #  #
              #  #  #  #  #
              #  #  #  #  #
                          # ]
        2736                 :            :
        2737                 :            :     /* signed integers and fast path for 'B' */
        2738                 :          0 :     case 'B': return *((const unsigned char *)p) == *((const unsigned char *)q);
        2739                 :          0 :     case 'b': return *((const signed char *)p) == *((const signed char *)q);
        2740                 :          0 :     case 'h': CMP_SINGLE(p, q, short); return equal;
        2741                 :          0 :     case 'i': CMP_SINGLE(p, q, int); return equal;
        2742                 :          0 :     case 'l': CMP_SINGLE(p, q, long); return equal;
        2743                 :            :
        2744                 :            :     /* boolean */
        2745                 :          0 :     case '?': CMP_SINGLE(p, q, _Bool); return equal;
        2746                 :            :
        2747                 :            :     /* unsigned integers */
        2748                 :          0 :     case 'H': CMP_SINGLE(p, q, unsigned short); return equal;
        2749                 :          0 :     case 'I': CMP_SINGLE(p, q, unsigned int); return equal;
        2750                 :          0 :     case 'L': CMP_SINGLE(p, q, unsigned long); return equal;
        2751                 :            :
        2752                 :            :     /* native 64-bit */
        2753                 :          0 :     case 'q': CMP_SINGLE(p, q, long long); return equal;
        2754                 :          0 :     case 'Q': CMP_SINGLE(p, q, unsigned long long); return equal;
        2755                 :            :
        2756                 :            :     /* ssize_t and size_t */
        2757                 :          0 :     case 'n': CMP_SINGLE(p, q, Py_ssize_t); return equal;
        2758                 :          0 :     case 'N': CMP_SINGLE(p, q, size_t); return equal;
        2759                 :            :
        2760                 :            :     /* floats */
        2761                 :            :     /* XXX DBL_EPSILON? */
        2762                 :          0 :     case 'f': CMP_SINGLE(p, q, float); return equal;
        2763                 :          0 :     case 'd': CMP_SINGLE(p, q, double); return equal;
        2764                 :          0 :     case 'e': {
        2765                 :            : #if PY_LITTLE_ENDIAN
        2766                 :          0 :         int endian = 1;
        2767                 :            : #else
        2768                 :            :         int endian = 0;
        2769                 :            : #endif
        2770                 :            :         /* Note: PyFloat_Unpack2 should never fail */
        2771                 :          0 :         double u = PyFloat_Unpack2(p, endian);
        2772                 :          0 :         double v = PyFloat_Unpack2(q, endian);
        2773                 :          0 :         return (u == v);
        2774                 :            :     }
        2775                 :            :
        2776                 :            :     /* bytes object */
        2777                 :          0 :     case 'c': return *p == *q;
        2778                 :            :
        2779                 :            :     /* pointer */
        2780                 :          0 :     case 'P': CMP_SINGLE(p, q, void *); return equal;
        2781                 :            :
        2782                 :            :     /* use the struct module */
        2783                 :          0 :     case '_':
        2784                 :            :         assert(unpack_p);
        2785                 :            :         assert(unpack_q);
        2786                 :          0 :         return struct_unpack_cmp(p, q, unpack_p, unpack_q);
        2787                 :            :     }
        2788                 :            :
        2789                 :            :     /* NOT REACHED */
        2790                 :          0 :     PyErr_SetString(PyExc_RuntimeError,
        2791                 :            :         "memoryview: internal error in richcompare");
        2792                 :          0 :     return MV_COMPARE_EX;
        2793                 :            : }
        2794                 :            :
        2795                 :            : /* Base case for recursive array comparisons. Assumption: ndim == 1. */
        2796                 :            : static int
        2797                 :          0 : cmp_base(const char *p, const char *q, const Py_ssize_t *shape,
        2798                 :            :          const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
        2799                 :            :          const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
        2800                 :            :          char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
        2801                 :            : {
        2802                 :            :     Py_ssize_t i;
        2803                 :            :     int equal;
        2804                 :            :
        2805         [ #  # ]:          0 :     for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) {
        2806   [ #  #  #  # ]:          0 :         const char *xp = ADJUST_PTR(p, psuboffsets, 0);
        2807   [ #  #  #  # ]:          0 :         const char *xq = ADJUST_PTR(q, qsuboffsets, 0);
        2808                 :          0 :         equal = unpack_cmp(xp, xq, fmt, unpack_p, unpack_q);
        2809         [ #  # ]:          0 :         if (equal <= 0)
        2810                 :          0 :             return equal;
        2811                 :            :     }
        2812                 :            :
        2813                 :          0 :     return 1;
        2814                 :            : }
        2815                 :            :
        2816                 :            : /* Recursively compare two multi-dimensional arrays that have the same
        2817                 :            :    logical structure. Assumption: ndim >= 1. */
        2818                 :            : static int
        2819                 :          0 : cmp_rec(const char *p, const char *q,
        2820                 :            :         Py_ssize_t ndim, const Py_ssize_t *shape,
        2821                 :            :         const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
        2822                 :            :         const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
        2823                 :            :         char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
        2824                 :            : {
        2825                 :            :     Py_ssize_t i;
        2826                 :            :     int equal;
        2827                 :            :
        2828                 :            :     assert(ndim >= 1);
        2829                 :            :     assert(shape != NULL);
        2830                 :            :     assert(pstrides != NULL);
        2831                 :            :     assert(qstrides != NULL);
        2832                 :            :
        2833         [ #  # ]:          0 :     if (ndim == 1) {
        2834                 :          0 :         return cmp_base(p, q, shape,
        2835                 :            :                         pstrides, psuboffsets,
        2836                 :            :                         qstrides, qsuboffsets,
        2837                 :            :                         fmt, unpack_p, unpack_q);
        2838                 :            :     }
        2839                 :            :
        2840         [ #  # ]:          0 :     for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) {
        2841   [ #  #  #  # ]:          0 :         const char *xp = ADJUST_PTR(p, psuboffsets, 0);
        2842   [ #  #  #  # ]:          0 :         const char *xq = ADJUST_PTR(q, qsuboffsets, 0);
        2843   [ #  #  #  # ]:          0 :         equal = cmp_rec(xp, xq, ndim-1, shape+1,
        2844                 :            :                         pstrides+1, psuboffsets ? psuboffsets+1 : NULL,
        2845                 :            :                         qstrides+1, qsuboffsets ? qsuboffsets+1 : NULL,
        2846                 :            :                         fmt, unpack_p, unpack_q);
        2847         [ #  # ]:          0 :         if (equal <= 0)
        2848                 :          0 :             return equal;
        2849                 :            :     }
        2850                 :            :
        2851                 :          0 :     return 1;
        2852                 :            : }
        2853                 :            :
        2854                 :            : static PyObject *
        2855                 :          0 : memory_richcompare(PyObject *v, PyObject *w, int op)
        2856                 :            : {
        2857                 :            :     PyObject *res;
        2858                 :            :     Py_buffer wbuf, *vv;
        2859                 :          0 :     Py_buffer *ww = NULL;
        2860                 :          0 :     struct unpacker *unpack_v = NULL;
        2861                 :          0 :     struct unpacker *unpack_w = NULL;
        2862                 :            :     char vfmt, wfmt;
        2863                 :          0 :     int equal = MV_COMPARE_NOT_IMPL;
        2864                 :            :
        2865   [ #  #  #  # ]:          0 :     if (op != Py_EQ && op != Py_NE)
        2866                 :          0 :         goto result; /* Py_NotImplemented */
        2867                 :            :
        2868                 :            :     assert(PyMemoryView_Check(v));
        2869   [ #  #  #  # ]:          0 :     if (BASE_INACCESSIBLE(v)) {
        2870                 :          0 :         equal = (v == w);
        2871                 :          0 :         goto result;
        2872                 :            :     }
        2873                 :          0 :     vv = VIEW_ADDR(v);
        2874                 :            :
        2875         [ #  # ]:          0 :     if (PyMemoryView_Check(w)) {
        2876   [ #  #  #  # ]:          0 :         if (BASE_INACCESSIBLE(w)) {
        2877                 :          0 :             equal = (v == w);
        2878                 :          0 :             goto result;
        2879                 :            :         }
        2880                 :          0 :         ww = VIEW_ADDR(w);
        2881                 :            :     }
        2882                 :            :     else {
        2883         [ #  # ]:          0 :         if (PyObject_GetBuffer(w, &wbuf, PyBUF_FULL_RO) < 0) {
        2884                 :          0 :             PyErr_Clear();
        2885                 :          0 :             goto result; /* Py_NotImplemented */
        2886                 :            :         }
        2887                 :          0 :         ww = &wbuf;
        2888                 :            :     }
        2889                 :            :
        2890         [ #  # ]:          0 :     if (!equiv_shape(vv, ww)) {
        2891                 :          0 :         PyErr_Clear();
        2892                 :          0 :         equal = 0;
        2893                 :          0 :         goto result;
        2894                 :            :     }
        2895                 :            :
        2896                 :            :     /* Use fast unpacking for identical primitive C type formats. */
        2897         [ #  # ]:          0 :     if (get_native_fmtchar(&vfmt, vv->format) < 0)
        2898                 :          0 :         vfmt = '_';
        2899         [ #  # ]:          0 :     if (get_native_fmtchar(&wfmt, ww->format) < 0)
        2900                 :          0 :         wfmt = '_';
        2901   [ #  #  #  #  :          0 :     if (vfmt == '_' || wfmt == '_' || vfmt != wfmt) {
                       #  # ]
        2902                 :            :         /* Use struct module unpacking. NOTE: Even for equal format strings,
        2903                 :            :            memcmp() cannot be used for item comparison since it would give
        2904                 :            :            incorrect results in the case of NaNs or uninitialized padding
        2905                 :            :            bytes. */
        2906                 :          0 :         vfmt = '_';
        2907                 :          0 :         unpack_v = struct_get_unpacker(vv->format, vv->itemsize);
        2908         [ #  # ]:          0 :         if (unpack_v == NULL) {
        2909                 :          0 :             equal = fix_struct_error_int();
        2910                 :          0 :             goto result;
        2911                 :            :         }
        2912                 :          0 :         unpack_w = struct_get_unpacker(ww->format, ww->itemsize);
        2913         [ #  # ]:          0 :         if (unpack_w == NULL) {
        2914                 :          0 :             equal = fix_struct_error_int();
        2915                 :          0 :             goto result;
        2916                 :            :         }
        2917                 :            :     }
        2918                 :            :
        2919         [ #  # ]:          0 :     if (vv->ndim == 0) {
        2920                 :          0 :         equal = unpack_cmp(vv->buf, ww->buf,
        2921                 :            :                            vfmt, unpack_v, unpack_w);
        2922                 :            :     }
        2923         [ #  # ]:          0 :     else if (vv->ndim == 1) {
        2924                 :          0 :         equal = cmp_base(vv->buf, ww->buf, vv->shape,
        2925                 :          0 :                          vv->strides, vv->suboffsets,
        2926                 :          0 :                          ww->strides, ww->suboffsets,
        2927                 :            :                          vfmt, unpack_v, unpack_w);
        2928                 :            :     }
        2929                 :            :     else {
        2930                 :          0 :         equal = cmp_rec(vv->buf, ww->buf, vv->ndim, vv->shape,
        2931                 :          0 :                         vv->strides, vv->suboffsets,
        2932                 :          0 :                         ww->strides, ww->suboffsets,
        2933                 :            :                         vfmt, unpack_v, unpack_w);
        2934                 :            :     }
        2935                 :            :
        2936                 :          0 : result:
        2937         [ #  # ]:          0 :     if (equal < 0) {
        2938         [ #  # ]:          0 :         if (equal == MV_COMPARE_NOT_IMPL)
        2939                 :          0 :             res = Py_NotImplemented;
        2940                 :            :         else /* exception */
        2941                 :          0 :             res = NULL;
        2942                 :            :     }
        2943   [ #  #  #  #  :          0 :     else if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
                 #  #  #  # ]
        2944                 :          0 :         res = Py_True;
        2945                 :            :     else
        2946                 :          0 :         res = Py_False;
        2947                 :            :
        2948         [ #  # ]:          0 :     if (ww == &wbuf)
        2949                 :          0 :         PyBuffer_Release(ww);
        2950                 :            :
        2951                 :          0 :     unpacker_free(unpack_v);
        2952                 :          0 :     unpacker_free(unpack_w);
        2953                 :            :
        2954                 :          0 :     return Py_XNewRef(res);
        2955                 :            : }
        2956                 :            :
        2957                 :            : /**************************************************************************/
        2958                 :            : /*                                Hash                                    */
        2959                 :            : /**************************************************************************/
        2960                 :            :
        2961                 :            : static Py_hash_t
        2962                 :          0 : memory_hash(PyMemoryViewObject *self)
        2963                 :            : {
        2964         [ #  # ]:          0 :     if (self->hash == -1) {
        2965                 :          0 :         Py_buffer *view = &self->view;
        2966                 :          0 :         char *mem = view->buf;
        2967                 :            :         Py_ssize_t ret;
        2968                 :            :         char fmt;
        2969                 :            :
        2970   [ #  #  #  # ]:          0 :         CHECK_RELEASED_INT(self);
        2971                 :            :
        2972         [ #  # ]:          0 :         if (!view->readonly) {
        2973                 :          0 :             PyErr_SetString(PyExc_ValueError,
        2974                 :            :                 "cannot hash writable memoryview object");
        2975                 :          0 :             return -1;
        2976                 :            :         }
        2977                 :          0 :         ret = get_native_fmtchar(&fmt, view->format);
        2978   [ #  #  #  #  :          0 :         if (ret < 0 || !IS_BYTE_FORMAT(fmt)) {
                 #  #  #  # ]
        2979                 :          0 :             PyErr_SetString(PyExc_ValueError,
        2980                 :            :                 "memoryview: hashing is restricted to formats 'B', 'b' or 'c'");
        2981                 :          0 :             return -1;
        2982                 :            :         }
        2983   [ #  #  #  # ]:          0 :         if (view->obj != NULL && PyObject_Hash(view->obj) == -1) {
        2984                 :            :             /* Keep the original error message */
        2985                 :          0 :             return -1;
        2986                 :            :         }
        2987                 :            :
        2988         [ #  # ]:          0 :         if (!MV_C_CONTIGUOUS(self->flags)) {
        2989                 :          0 :             mem = PyMem_Malloc(view->len);
        2990         [ #  # ]:          0 :             if (mem == NULL) {
        2991                 :          0 :                 PyErr_NoMemory();
        2992                 :          0 :                 return -1;
        2993                 :            :             }
        2994         [ #  # ]:          0 :             if (buffer_to_contiguous(mem, view, 'C') < 0) {
        2995                 :          0 :                 PyMem_Free(mem);
        2996                 :          0 :                 return -1;
        2997                 :            :             }
        2998                 :            :         }
        2999                 :            :
        3000                 :            :         /* Can't fail */
        3001                 :          0 :         self->hash = _Py_HashBytes(mem, view->len);
        3002                 :            :
        3003         [ #  # ]:          0 :         if (mem != view->buf)
        3004                 :          0 :             PyMem_Free(mem);
        3005                 :            :     }
        3006                 :            :
        3007                 :          0 :     return self->hash;
        3008                 :            : }
        3009                 :            :
        3010                 :            :
        3011                 :            : /**************************************************************************/
        3012                 :            : /*                                 getters                                */
        3013                 :            : /**************************************************************************/
        3014                 :            :
        3015                 :            : static PyObject *
        3016                 :          0 : _IntTupleFromSsizet(int len, Py_ssize_t *vals)
        3017                 :            : {
        3018                 :            :     int i;
        3019                 :            :     PyObject *o;
        3020                 :            :     PyObject *intTuple;
        3021                 :            :
        3022         [ #  # ]:          0 :     if (vals == NULL)
        3023                 :          0 :         return PyTuple_New(0);
        3024                 :            :
        3025                 :          0 :     intTuple = PyTuple_New(len);
        3026         [ #  # ]:          0 :     if (!intTuple)
        3027                 :          0 :         return NULL;
        3028         [ #  # ]:          0 :     for (i=0; i<len; i++) {
        3029                 :          0 :         o = PyLong_FromSsize_t(vals[i]);
        3030         [ #  # ]:          0 :         if (!o) {
        3031                 :          0 :             Py_DECREF(intTuple);
        3032                 :          0 :             return NULL;
        3033                 :            :         }
        3034                 :          0 :         PyTuple_SET_ITEM(intTuple, i, o);
        3035                 :            :     }
        3036                 :          0 :     return intTuple;
        3037                 :            : }
        3038                 :            :
        3039                 :            : static PyObject *
        3040                 :          0 : memory_obj_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
        3041                 :            : {
        3042                 :          0 :     Py_buffer *view = &self->view;
        3043                 :            :
        3044   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3045         [ #  # ]:          0 :     if (view->obj == NULL) {
        3046                 :          0 :         Py_RETURN_NONE;
        3047                 :            :     }
        3048                 :          0 :     return Py_NewRef(view->obj);
        3049                 :            : }
        3050                 :            :
        3051                 :            : static PyObject *
        3052                 :          0 : memory_nbytes_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
        3053                 :            : {
        3054   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3055                 :          0 :     return PyLong_FromSsize_t(self->view.len);
        3056                 :            : }
        3057                 :            :
        3058                 :            : static PyObject *
        3059                 :          0 : memory_format_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
        3060                 :            : {
        3061   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3062                 :          0 :     return PyUnicode_FromString(self->view.format);
        3063                 :            : }
        3064                 :            :
        3065                 :            : static PyObject *
        3066                 :          6 : memory_itemsize_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
        3067                 :            : {
        3068   [ +  -  -  + ]:          6 :     CHECK_RELEASED(self);
        3069                 :          6 :     return PyLong_FromSsize_t(self->view.itemsize);
        3070                 :            : }
        3071                 :            :
        3072                 :            : static PyObject *
        3073                 :          0 : memory_shape_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
        3074                 :            : {
        3075   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3076                 :          0 :     return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
        3077                 :            : }
        3078                 :            :
        3079                 :            : static PyObject *
        3080                 :          0 : memory_strides_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
        3081                 :            : {
        3082   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3083                 :          0 :     return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
        3084                 :            : }
        3085                 :            :
        3086                 :            : static PyObject *
        3087                 :          0 : memory_suboffsets_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
        3088                 :            : {
        3089   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3090                 :          0 :     return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
        3091                 :            : }
        3092                 :            :
        3093                 :            : static PyObject *
        3094                 :          0 : memory_readonly_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
        3095                 :            : {
        3096   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3097                 :          0 :     return PyBool_FromLong(self->view.readonly);
        3098                 :            : }
        3099                 :            :
        3100                 :            : static PyObject *
        3101                 :          0 : memory_ndim_get(PyMemoryViewObject *self, void *Py_UNUSED(ignored))
        3102                 :            : {
        3103   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3104                 :          0 :     return PyLong_FromLong(self->view.ndim);
        3105                 :            : }
        3106                 :            :
        3107                 :            : static PyObject *
        3108                 :          0 : memory_c_contiguous(PyMemoryViewObject *self, PyObject *dummy)
        3109                 :            : {
        3110   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3111                 :          0 :     return PyBool_FromLong(MV_C_CONTIGUOUS(self->flags));
        3112                 :            : }
        3113                 :            :
        3114                 :            : static PyObject *
        3115                 :          0 : memory_f_contiguous(PyMemoryViewObject *self, PyObject *dummy)
        3116                 :            : {
        3117   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3118                 :          0 :     return PyBool_FromLong(MV_F_CONTIGUOUS(self->flags));
        3119                 :            : }
        3120                 :            :
        3121                 :            : static PyObject *
        3122                 :          0 : memory_contiguous(PyMemoryViewObject *self, PyObject *dummy)
        3123                 :            : {
        3124   [ #  #  #  # ]:          0 :     CHECK_RELEASED(self);
        3125                 :          0 :     return PyBool_FromLong(MV_ANY_CONTIGUOUS(self->flags));
        3126                 :            : }
        3127                 :            :
        3128                 :            : PyDoc_STRVAR(memory_obj_doc,
        3129                 :            :              "The underlying object of the memoryview.");
        3130                 :            : PyDoc_STRVAR(memory_nbytes_doc,
        3131                 :            :              "The amount of space in bytes that the array would use in\n"
        3132                 :            :              " a contiguous representation.");
        3133                 :            : PyDoc_STRVAR(memory_readonly_doc,
        3134                 :            :              "A bool indicating whether the memory is read only.");
        3135                 :            : PyDoc_STRVAR(memory_itemsize_doc,
        3136                 :            :              "The size in bytes of each element of the memoryview.");
        3137                 :            : PyDoc_STRVAR(memory_format_doc,
        3138                 :            :              "A string containing the format (in struct module style)\n"
        3139                 :            :              " for each element in the view.");
        3140                 :            : PyDoc_STRVAR(memory_ndim_doc,
        3141                 :            :              "An integer indicating how many dimensions of a multi-dimensional\n"
        3142                 :            :              " array the memory represents.");
        3143                 :            : PyDoc_STRVAR(memory_shape_doc,
        3144                 :            :              "A tuple of ndim integers giving the shape of the memory\n"
        3145                 :            :              " as an N-dimensional array.");
        3146                 :            : PyDoc_STRVAR(memory_strides_doc,
        3147                 :            :              "A tuple of ndim integers giving the size in bytes to access\n"
        3148                 :            :              " each element for each dimension of the array.");
        3149                 :            : PyDoc_STRVAR(memory_suboffsets_doc,
        3150                 :            :              "A tuple of integers used internally for PIL-style arrays.");
        3151                 :            : PyDoc_STRVAR(memory_c_contiguous_doc,
        3152                 :            :              "A bool indicating whether the memory is C contiguous.");
        3153                 :            : PyDoc_STRVAR(memory_f_contiguous_doc,
        3154                 :            :              "A bool indicating whether the memory is Fortran contiguous.");
        3155                 :            : PyDoc_STRVAR(memory_contiguous_doc,
        3156                 :            :              "A bool indicating whether the memory is contiguous.");
        3157                 :            :
        3158                 :            :
        3159                 :            : static PyGetSetDef memory_getsetlist[] = {
        3160                 :            :     {"obj",             (getter)memory_obj_get,        NULL, memory_obj_doc},
        3161                 :            :     {"nbytes",          (getter)memory_nbytes_get,     NULL, memory_nbytes_doc},
        3162                 :            :     {"readonly",        (getter)memory_readonly_get,   NULL, memory_readonly_doc},
        3163                 :            :     {"itemsize",        (getter)memory_itemsize_get,   NULL, memory_itemsize_doc},
        3164                 :            :     {"format",          (getter)memory_format_get,     NULL, memory_format_doc},
        3165                 :            :     {"ndim",            (getter)memory_ndim_get,       NULL, memory_ndim_doc},
        3166                 :            :     {"shape",           (getter)memory_shape_get,      NULL, memory_shape_doc},
        3167                 :            :     {"strides",         (getter)memory_strides_get,    NULL, memory_strides_doc},
        3168                 :            :     {"suboffsets",      (getter)memory_suboffsets_get, NULL, memory_suboffsets_doc},
        3169                 :            :     {"c_contiguous",    (getter)memory_c_contiguous,   NULL, memory_c_contiguous_doc},
        3170                 :            :     {"f_contiguous",    (getter)memory_f_contiguous,   NULL, memory_f_contiguous_doc},
        3171                 :            :     {"contiguous",      (getter)memory_contiguous,     NULL, memory_contiguous_doc},
        3172                 :            :     {NULL, NULL, NULL, NULL},
        3173                 :            : };
        3174                 :            :
        3175                 :            :
        3176                 :            : static PyMethodDef memory_methods[] = {
        3177                 :            :     MEMORYVIEW_RELEASE_METHODDEF
        3178                 :            :     MEMORYVIEW_TOBYTES_METHODDEF
        3179                 :            :     MEMORYVIEW_HEX_METHODDEF
        3180                 :            :     MEMORYVIEW_TOLIST_METHODDEF
        3181                 :            :     MEMORYVIEW_CAST_METHODDEF
        3182                 :            :     MEMORYVIEW_TOREADONLY_METHODDEF
        3183                 :            :     {"__enter__",   memory_enter, METH_NOARGS, NULL},
        3184                 :            :     {"__exit__",    memory_exit, METH_VARARGS, NULL},
        3185                 :            :     {NULL,          NULL}
        3186                 :            : };
        3187                 :            :
        3188                 :            : /**************************************************************************/
        3189                 :            : /*                          Memoryview Iterator                           */
        3190                 :            : /**************************************************************************/
        3191                 :            :
        3192                 :            : PyTypeObject _PyMemoryIter_Type;
        3193                 :            :
        3194                 :            : typedef struct {
        3195                 :            :     PyObject_HEAD
        3196                 :            :     Py_ssize_t it_index;
        3197                 :            :     PyMemoryViewObject *it_seq; // Set to NULL when iterator is exhausted
        3198                 :            :     Py_ssize_t it_length;
        3199                 :            :     const char *it_fmt;
        3200                 :            : } memoryiterobject;
        3201                 :            :
        3202                 :            : static void
        3203                 :          0 : memoryiter_dealloc(memoryiterobject *it)
        3204                 :            : {
        3205                 :          0 :     _PyObject_GC_UNTRACK(it);
        3206                 :          0 :     Py_XDECREF(it->it_seq);
        3207                 :          0 :     PyObject_GC_Del(it);
        3208                 :          0 : }
        3209                 :            :
        3210                 :            : static int
        3211                 :          0 : memoryiter_traverse(memoryiterobject *it, visitproc visit, void *arg)
        3212                 :            : {
        3213   [ #  #  #  # ]:          0 :     Py_VISIT(it->it_seq);
        3214                 :          0 :     return 0;
        3215                 :            : }
        3216                 :            :
        3217                 :            : static PyObject *
        3218                 :          0 : memoryiter_next(memoryiterobject *it)
        3219                 :            : {
        3220                 :            :     PyMemoryViewObject *seq;
        3221                 :          0 :     seq = it->it_seq;
        3222         [ #  # ]:          0 :     if (seq == NULL) {
        3223                 :          0 :         return NULL;
        3224                 :            :     }
        3225                 :            :
        3226         [ #  # ]:          0 :     if (it->it_index < it->it_length) {
        3227   [ #  #  #  # ]:          0 :         CHECK_RELEASED(seq);
        3228                 :          0 :         Py_buffer *view = &(seq->view);
        3229                 :          0 :         char *ptr = (char *)seq->view.buf;
        3230                 :            :
        3231                 :          0 :         ptr += view->strides[0] * it->it_index++;
        3232   [ #  #  #  # ]:          0 :         ptr = ADJUST_PTR(ptr, view->suboffsets, 0);
        3233         [ #  # ]:          0 :         if (ptr == NULL) {
        3234                 :          0 :             return NULL;
        3235                 :            :         }
        3236                 :          0 :         return unpack_single(seq, ptr, it->it_fmt);
        3237                 :            :     }
        3238                 :            :
        3239                 :          0 :     it->it_seq = NULL;
        3240                 :          0 :     Py_DECREF(seq);
        3241                 :          0 :     return NULL;
        3242                 :            : }
        3243                 :            :
        3244                 :            : static PyObject *
        3245                 :          0 : memory_iter(PyObject *seq)
        3246                 :            : {
        3247         [ #  # ]:          0 :     if (!PyMemoryView_Check(seq)) {
        3248                 :          0 :         PyErr_BadInternalCall();
        3249                 :          0 :         return NULL;
        3250                 :            :     }
        3251                 :          0 :     PyMemoryViewObject *obj = (PyMemoryViewObject *)seq;
        3252                 :          0 :     int ndims = obj->view.ndim;
        3253         [ #  # ]:          0 :     if (ndims == 0) {
        3254                 :          0 :         PyErr_SetString(PyExc_TypeError, "invalid indexing of 0-dim memory");
        3255                 :          0 :         return NULL;
        3256                 :            :     }
        3257         [ #  # ]:          0 :     if (ndims != 1) {
        3258                 :          0 :         PyErr_SetString(PyExc_NotImplementedError,
        3259                 :            :             "multi-dimensional sub-views are not implemented");
        3260                 :          0 :         return NULL;
        3261                 :            :     }
        3262                 :            :
        3263                 :          0 :     const char *fmt = adjust_fmt(&obj->view);
        3264         [ #  # ]:          0 :     if (fmt == NULL) {
        3265                 :          0 :         return NULL;
        3266                 :            :     }
        3267                 :            :
        3268                 :            :     memoryiterobject *it;
        3269                 :          0 :     it = PyObject_GC_New(memoryiterobject, &_PyMemoryIter_Type);
        3270         [ #  # ]:          0 :     if (it == NULL) {
        3271                 :          0 :         return NULL;
        3272                 :            :     }
        3273                 :          0 :     it->it_fmt = fmt;
        3274                 :          0 :     it->it_length = memory_length(obj);
        3275                 :          0 :     it->it_index = 0;
        3276                 :          0 :     it->it_seq = (PyMemoryViewObject*)Py_NewRef(obj);
        3277                 :          0 :     _PyObject_GC_TRACK(it);
        3278                 :          0 :     return (PyObject *)it;
        3279                 :            : }
        3280                 :            :
        3281                 :            : PyTypeObject _PyMemoryIter_Type = {
        3282                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
        3283                 :            :     .tp_name = "memory_iterator",
        3284                 :            :     .tp_basicsize = sizeof(memoryiterobject),
        3285                 :            :     // methods
        3286                 :            :     .tp_dealloc = (destructor)memoryiter_dealloc,
        3287                 :            :     .tp_getattro = PyObject_GenericGetAttr,
        3288                 :            :     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
        3289                 :            :     .tp_traverse = (traverseproc)memoryiter_traverse,
        3290                 :            :     .tp_iter = PyObject_SelfIter,
        3291                 :            :     .tp_iternext = (iternextfunc)memoryiter_next,
        3292                 :            : };
        3293                 :            :
        3294                 :            : PyTypeObject PyMemoryView_Type = {
        3295                 :            :     PyVarObject_HEAD_INIT(&PyType_Type, 0)
        3296                 :            :     "memoryview",                             /* tp_name */
        3297                 :            :     offsetof(PyMemoryViewObject, ob_array),   /* tp_basicsize */
        3298                 :            :     sizeof(Py_ssize_t),                       /* tp_itemsize */
        3299                 :            :     (destructor)memory_dealloc,               /* tp_dealloc */
        3300                 :            :     0,                                        /* tp_vectorcall_offset */
        3301                 :            :     0,                                        /* tp_getattr */
        3302                 :            :     0,                                        /* tp_setattr */
        3303                 :            :     0,                                        /* tp_as_async */
        3304                 :            :     (reprfunc)memory_repr,                    /* tp_repr */
        3305                 :            :     0,                                        /* tp_as_number */
        3306                 :            :     &memory_as_sequence,                      /* tp_as_sequence */
        3307                 :            :     &memory_as_mapping,                       /* tp_as_mapping */
        3308                 :            :     (hashfunc)memory_hash,                    /* tp_hash */
        3309                 :            :     0,                                        /* tp_call */
        3310                 :            :     0,                                        /* tp_str */
        3311                 :            :     PyObject_GenericGetAttr,                  /* tp_getattro */
        3312                 :            :     0,                                        /* tp_setattro */
        3313                 :            :     &memory_as_buffer,                        /* tp_as_buffer */
        3314                 :            :     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
        3315                 :            :        Py_TPFLAGS_SEQUENCE,                   /* tp_flags */
        3316                 :            :     memoryview__doc__,                        /* tp_doc */
        3317                 :            :     (traverseproc)memory_traverse,            /* tp_traverse */
        3318                 :            :     (inquiry)memory_clear,                    /* tp_clear */
        3319                 :            :     memory_richcompare,                       /* tp_richcompare */
        3320                 :            :     offsetof(PyMemoryViewObject, weakreflist),/* tp_weaklistoffset */
        3321                 :            :     memory_iter,                              /* tp_iter */
        3322                 :            :     0,                                        /* tp_iternext */
        3323                 :            :     memory_methods,                           /* tp_methods */
        3324                 :            :     0,                                        /* tp_members */
        3325                 :            :     memory_getsetlist,                        /* tp_getset */
        3326                 :            :     0,                                        /* tp_base */
        3327                 :            :     0,                                        /* tp_dict */
        3328                 :            :     0,                                        /* tp_descr_get */
        3329                 :            :     0,                                        /* tp_descr_set */
        3330                 :            :     0,                                        /* tp_dictoffset */
        3331                 :            :     0,                                        /* tp_init */
        3332                 :            :     0,                                        /* tp_alloc */
        3333                 :            :     memoryview,                               /* tp_new */
        3334                 :            : };

Generated by: LCOV version 1.14