Coverage Report

Created: 2026-01-17 06:16

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