Coverage Report

Created: 2026-04-12 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython3/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
159k
{
74
159k
    _PyManagedBufferObject *mbuf;
75
76
159k
    mbuf = (_PyManagedBufferObject *)
77
159k
        PyObject_GC_New(_PyManagedBufferObject, &_PyManagedBuffer_Type);
78
159k
    if (mbuf == NULL)
79
0
        return NULL;
80
159k
    mbuf->flags = 0;
81
159k
    mbuf->exports = 0;
82
159k
    mbuf->master.obj = NULL;
83
159k
    _PyObject_GC_TRACK(mbuf);
84
85
159k
    return mbuf;
86
159k
}
87
88
static PyObject *
89
_PyManagedBuffer_FromObject(PyObject *base, int flags)
90
335
{
91
335
    _PyManagedBufferObject *mbuf;
92
93
335
    mbuf = mbuf_alloc();
94
335
    if (mbuf == NULL)
95
0
        return NULL;
96
97
335
    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
335
    return (PyObject *)mbuf;
104
335
}
105
106
static void
107
mbuf_release(_PyManagedBufferObject *self)
108
318k
{
109
318k
    if (self->flags&_Py_MANAGED_BUFFER_RELEASED)
110
159k
        return;
111
112
159k
    self->flags |= _Py_MANAGED_BUFFER_RELEASED;
113
114
    /* PyBuffer_Release() decrements master->obj and sets it to NULL. */
115
159k
    _PyObject_GC_UNTRACK(self);
116
159k
    PyBuffer_Release(&self->master);
117
159k
}
118
119
static void
120
mbuf_dealloc(PyObject *_self)
121
159k
{
122
159k
    _PyManagedBufferObject *self = (_PyManagedBufferObject *)_self;
123
159k
    assert(self->exports == 0);
124
159k
    mbuf_release(self);
125
159k
    if (self->flags&_Py_MANAGED_BUFFER_FREE_FORMAT)
126
0
        PyMem_Free(self->master.format);
127
159k
    PyObject_GC_Del(self);
128
159k
}
129
130
static int
131
mbuf_traverse(PyObject *_self, visitproc visit, void *arg)
132
3
{
133
3
    _PyManagedBufferObject *self = (_PyManagedBufferObject *)_self;
134
3
    Py_VISIT(self->master.obj);
135
3
    return 0;
136
3
}
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
162k
    (((PyMemoryViewObject *)mv)->flags&_Py_MEMORYVIEW_RELEASED || \
182
162k
     ((PyMemoryViewObject *)mv)->mbuf->flags&_Py_MANAGED_BUFFER_RELEASED)
183
184
#define CHECK_RELEASED(mv) \
185
1.59k
    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
160k
    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
1.46k
    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
158k
    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
128
#define CHECK_RELEASED_AGAIN(mv) CHECK_RELEASED(mv)
215
0
#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
565
#define VIEW_ADDR(mv) (&((PyMemoryViewObject *)mv)->view)
225
226
/* Check for the presence of suboffsets in the first dimension. */
227
3.51k
#define HAVE_PTR(suboffsets, dim) (suboffsets && suboffsets[dim] >= 0)
228
/* Adjust ptr if suboffsets are present. */
229
#define ADJUST_PTR(ptr, suboffsets, dim) \
230
3.51k
    (HAVE_PTR(suboffsets, dim) ? *((char**)ptr) + suboffsets[dim] : ptr)
231
232
/* Memoryview buffer properties */
233
156k
#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
162k
    ((view)->shape[0] == 1 || (view)->strides[0] == (view)->itemsize)
242
243
/* getbuffer() requests */
244
317k
#define REQ_INDIRECT(flags) ((flags&PyBUF_INDIRECT) == PyBUF_INDIRECT)
245
317k
#define REQ_C_CONTIGUOUS(flags) ((flags&PyBUF_C_CONTIGUOUS) == PyBUF_C_CONTIGUOUS)
246
317k
#define REQ_F_CONTIGUOUS(flags) ((flags&PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS)
247
317k
#define REQ_ANY_CONTIGUOUS(flags) ((flags&PyBUF_ANY_CONTIGUOUS) == PyBUF_ANY_CONTIGUOUS)
248
158k
#define REQ_STRIDES(flags) ((flags&PyBUF_STRIDES) == PyBUF_STRIDES)
249
158k
#define REQ_SHAPE(flags) ((flags&PyBUF_ND) == PyBUF_ND)
250
317k
#define REQ_WRITABLE(flags) (flags&PyBUF_WRITABLE)
251
158k
#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
0
    (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
0
{
274
0
    assert(dest->ndim > 0 && src->ndim > 0);
275
0
    return (!HAVE_SUBOFFSETS_IN_LAST_DIM(dest) &&
276
0
            !HAVE_SUBOFFSETS_IN_LAST_DIM(src) &&
277
0
            dest->strides[dest->ndim-1] == dest->itemsize &&
278
0
            src->strides[src->ndim-1] == src->itemsize);
279
0
}
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
0
{
290
0
    const char *dfmt, *sfmt;
291
292
0
    assert(dest->format && src->format);
293
0
    dfmt = dest->format[0] == '@' ? dest->format+1 : dest->format;
294
0
    sfmt = src->format[0] == '@' ? src->format+1 : src->format;
295
296
0
    if (strcmp(dfmt, sfmt) != 0 ||
297
0
        dest->itemsize != src->itemsize) {
298
0
        return 0;
299
0
    }
300
301
0
    return 1;
302
0
}
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
565
{
310
565
    int i;
311
312
565
    if (dest->ndim != src->ndim)
313
0
        return 0;
314
315
1.13k
    for (i = 0; i < dest->ndim; i++) {
316
565
        if (dest->shape[i] != src->shape[i])
317
0
            return 0;
318
565
        if (dest->shape[i] == 0)
319
0
            break;
320
565
    }
321
322
565
    return 1;
323
565
}
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
0
{
330
0
    if (!equiv_format(dest, src) ||
331
0
        !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
0
    return 1;
339
0
}
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
0
{
350
0
    if (mem == NULL) { /* contiguous */
351
0
        Py_ssize_t size = shape[0] * itemsize;
352
0
        if (dptr + size < sptr || sptr + size < dptr)
353
0
            memcpy(dptr, sptr, size); /* no overlapping */
354
0
        else
355
0
            memmove(dptr, sptr, size);
356
0
    }
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
0
}
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
0
{
407
0
    CHECK_RELEASED_INT_AGAIN(self);
408
0
    char *mem = NULL;
409
410
0
    assert(dest->ndim == 1);
411
412
0
    if (!equiv_structure(dest, src))
413
0
        return -1;
414
415
0
    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
0
    copy_base(dest->shape, dest->itemsize,
424
0
              dest->buf, dest->strides, dest->suboffsets,
425
0
              src->buf, src->strides, src->suboffsets,
426
0
              mem);
427
428
0
    if (mem)
429
0
        PyMem_Free(mem);
430
431
0
    return 0;
432
0
}
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
160k
{
545
160k
    dest->obj = src->obj;
546
160k
    dest->buf = src->buf;
547
160k
    dest->len = src->len;
548
160k
    dest->itemsize = src->itemsize;
549
160k
    dest->readonly = src->readonly;
550
160k
    dest->format = src->format ? src->format : "B";
551
160k
    dest->internal = src->internal;
552
160k
}
553
554
/* Copy shape and strides. Reconstruct missing values. */
555
static void
556
init_shape_strides(Py_buffer *dest, const Py_buffer *src)
557
160k
{
558
160k
    Py_ssize_t i;
559
560
160k
    if (src->ndim == 0) {
561
0
        dest->shape = NULL;
562
0
        dest->strides = NULL;
563
0
        return;
564
0
    }
565
160k
    if (src->ndim == 1) {
566
160k
        dest->shape[0] = src->shape ? src->shape[0] : src->len / src->itemsize;
567
160k
        dest->strides[0] = src->strides ? src->strides[0] : src->itemsize;
568
160k
        return;
569
160k
    }
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
160k
{
585
160k
    Py_ssize_t i;
586
587
160k
    if (src->suboffsets == NULL) {
588
160k
        dest->suboffsets = NULL;
589
160k
        return;
590
160k
    }
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
1.46k
{
599
1.46k
    Py_ssize_t i, len;
600
601
1.46k
    len = 1;
602
2.92k
    for (i = 0; i < view->ndim; i++)
603
1.46k
        len *= view->shape[i];
604
1.46k
    len *= view->itemsize;
605
606
1.46k
    view->len = len;
607
1.46k
}
608
609
/* Initialize memoryview buffer properties. */
610
static void
611
init_flags(PyMemoryViewObject *mv)
612
162k
{
613
162k
    const Py_buffer *view = &mv->view;
614
162k
    int flags = 0;
615
616
162k
    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
162k
    case 1:
622
162k
        if (MV_CONTIGUOUS_NDIM1(view))
623
162k
            flags |= (_Py_MEMORYVIEW_C|_Py_MEMORYVIEW_FORTRAN);
624
162k
        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
162k
    }
632
633
162k
    if (view->suboffsets) {
634
0
        flags |= _Py_MEMORYVIEW_PIL;
635
0
        flags &= ~(_Py_MEMORYVIEW_C|_Py_MEMORYVIEW_FORTRAN);
636
0
    }
637
638
162k
    mv->flags = flags;
639
162k
}
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
160k
{
646
160k
    PyMemoryViewObject *mv;
647
648
160k
    mv = (PyMemoryViewObject *)
649
160k
        PyObject_GC_NewVar(PyMemoryViewObject, &PyMemoryView_Type, 3*ndim);
650
160k
    if (mv == NULL)
651
0
        return NULL;
652
653
160k
    mv->mbuf = NULL;
654
160k
    mv->hash = -1;
655
160k
    mv->flags = 0;
656
160k
    mv->exports = 0;
657
160k
    mv->view.ndim = ndim;
658
160k
    mv->view.shape = mv->ob_array;
659
160k
    mv->view.strides = mv->ob_array + ndim;
660
160k
    mv->view.suboffsets = mv->ob_array + 2 * ndim;
661
160k
    mv->weakreflist = NULL;
662
663
160k
    _PyObject_GC_TRACK(mv);
664
160k
    return mv;
665
160k
}
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
160k
{
678
160k
    PyMemoryViewObject *mv;
679
160k
    Py_buffer *dest;
680
681
160k
    if (src == NULL)
682
159k
        src = &mbuf->master;
683
684
160k
    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
160k
    mv = memory_alloc(src->ndim);
692
160k
    if (mv == NULL)
693
0
        return NULL;
694
695
160k
    dest = &mv->view;
696
160k
    init_shared_values(dest, src);
697
160k
    init_shape_strides(dest, src);
698
160k
    init_suboffsets(dest, src);
699
160k
    init_flags(mv);
700
701
160k
    mv->mbuf = (_PyManagedBufferObject*)Py_NewRef(mbuf);
702
160k
    mbuf->exports++;
703
704
160k
    return (PyObject *)mv;
705
160k
}
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
2
{
716
2
    PyMemoryViewObject *mv;
717
2
    Py_buffer *dest;
718
719
2
    if (src == NULL)
720
0
        src = &mbuf->master;
721
722
2
    assert(ndim <= PyBUF_MAX_NDIM);
723
724
2
    mv = memory_alloc(ndim);
725
2
    if (mv == NULL)
726
0
        return NULL;
727
728
2
    dest = &mv->view;
729
2
    init_shared_values(dest, src);
730
731
2
    mv->mbuf = (_PyManagedBufferObject*)Py_NewRef(mbuf);
732
2
    mbuf->exports++;
733
734
2
    return (PyObject *)mv;
735
2
}
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
158k
{
772
158k
    _PyManagedBufferObject *mbuf;
773
158k
    PyObject *mv;
774
775
158k
    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
158k
    mbuf = mbuf_alloc();
782
158k
    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
158k
    mbuf->master = *info;
788
158k
    mbuf->master.obj = NULL;
789
790
158k
    mv = mbuf_add_view(mbuf, NULL);
791
158k
    Py_DECREF(mbuf);
792
793
158k
    return mv;
794
158k
}
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
335
{
803
335
    _PyManagedBufferObject *mbuf;
804
805
335
    if (PyMemoryView_Check(v)) {
806
0
        PyMemoryViewObject *mv = (PyMemoryViewObject *)v;
807
0
        CHECK_RELEASED(mv);
808
0
        CHECK_RESTRICTED(mv);
809
0
        return mbuf_add_view(mv->mbuf, &mv->view);
810
0
    }
811
335
    else if (PyObject_CheckBuffer(v)) {
812
335
        PyObject *ret;
813
335
        mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(v, flags);
814
335
        if (mbuf == NULL)
815
0
            return NULL;
816
335
        ret = mbuf_add_view(mbuf, NULL);
817
335
        Py_DECREF(mbuf);
818
335
        return ret;
819
335
    }
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
335
}
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
335
{
856
335
    return PyMemoryView_FromObjectAndFlags(v, PyBUF_FULL_RO);
857
335
}
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
335
{
1017
335
    return PyMemoryView_FromObject(object);
1018
335
}
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
1.94k
{
1051
1.94k
    Py_buffer_full *fb = NULL;
1052
1.94k
    int ret;
1053
1054
1.94k
    assert(order == 'C' || order == 'F' || order == 'A');
1055
1056
1.94k
    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
1.94k
    if (PyBuffer_IsContiguous(src, order)) {
1063
1.94k
        memcpy((char *)buf, src->buf, len);
1064
1.94k
        return 0;
1065
1.94k
    }
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
321k
{
1092
#ifdef Py_GIL_DISABLED
1093
    return _Py_atomic_load_ssize_relaxed(&buf->exports);
1094
#else
1095
321k
    return buf->exports;
1096
321k
#endif
1097
321k
}
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
160k
{
1111
160k
    assert(get_exports(self) == 0);
1112
160k
    if (self->flags & _Py_MEMORYVIEW_RELEASED)
1113
0
        return;
1114
1115
160k
    self->flags |= _Py_MEMORYVIEW_RELEASED;
1116
160k
    assert(self->mbuf->exports > 0);
1117
160k
    if (--self->mbuf->exports == 0) {
1118
159k
        mbuf_release(self->mbuf);
1119
159k
    }
1120
160k
}
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
0
{
1132
0
    Py_ssize_t exports = get_exports(self);
1133
0
    if (exports == 0) {
1134
0
        _memory_release(self);
1135
0
        Py_RETURN_NONE;
1136
0
    }
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
160k
{
1153
160k
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
1154
160k
    assert(get_exports(self) == 0);
1155
160k
    _PyObject_GC_UNTRACK(self);
1156
160k
    _memory_release(self);
1157
160k
    Py_CLEAR(self->mbuf);
1158
160k
    if (self->weakreflist != NULL)
1159
0
        PyObject_ClearWeakRefs((PyObject *) self);
1160
160k
    PyObject_GC_Del(self);
1161
160k
}
1162
1163
static int
1164
memory_traverse(PyObject *_self, visitproc visit, void *arg)
1165
3
{
1166
3
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
1167
3
    Py_VISIT(self->mbuf);
1168
3
    return 0;
1169
3
}
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
0
{
1185
0
    CHECK_RELEASED(self);
1186
0
    return Py_NewRef(self);
1187
0
}
1188
1189
static PyObject *
1190
memory_exit(PyObject *self, PyObject *args)
1191
0
{
1192
0
    return memoryview_release_impl((PyMemoryViewObject *)self);
1193
0
}
1194
1195
1196
/****************************************************************************/
1197
/*                         Casting format and shape                         */
1198
/****************************************************************************/
1199
1200
2
#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
1.13k
{
1205
1.13k
    Py_ssize_t size = -1;
1206
1207
1.13k
    if (fmt[0] == '@') fmt++;
1208
1209
1.13k
    switch (fmt[0]) {
1210
1.13k
    case 'c': case 'b': case 'B': size = sizeof(char); break;
1211
0
    case 'h': case 'H': size = sizeof(short); break;
1212
2
    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 'F': size = 2*sizeof(float); break;
1220
0
    case 'D': size = 2*sizeof(double); break;
1221
0
    case '?': size = sizeof(_Bool); break;
1222
0
    case 'P': size = sizeof(void *); break;
1223
1.13k
    }
1224
1225
1.13k
    if (size > 0 && fmt[1] == '\0') {
1226
1.13k
        *result = fmt[0];
1227
1.13k
        return size;
1228
1.13k
    }
1229
1230
0
    return -1;
1231
1.13k
}
1232
1233
static inline const char *
1234
get_native_fmtstr(const char *fmt)
1235
2
{
1236
2
    int at = 0;
1237
1238
2
    if (fmt[0] == '@') {
1239
0
        at = 1;
1240
0
        fmt++;
1241
0
    }
1242
2
    if (fmt[0] == '\0' || fmt[1] != '\0') {
1243
0
        return NULL;
1244
0
    }
1245
1246
2
#define RETURN(s) do { return at ? "@" s : s; } while (0)
1247
1248
2
    switch (fmt[0]) {
1249
0
    case 'c': RETURN("c");
1250
0
    case 'b': RETURN("b");
1251
0
    case 'B': RETURN("B");
1252
0
    case 'h': RETURN("h");
1253
0
    case 'H': RETURN("H");
1254
0
    case 'i': RETURN("i");
1255
2
    case 'I': RETURN("I");
1256
0
    case 'l': RETURN("l");
1257
0
    case 'L': RETURN("L");
1258
0
    case 'q': RETURN("q");
1259
0
    case 'Q': RETURN("Q");
1260
0
    case 'n': RETURN("n");
1261
0
    case 'N': RETURN("N");
1262
0
    case 'f': RETURN("f");
1263
0
    case 'd': RETURN("d");
1264
0
    case 'e': RETURN("e");
1265
0
    case 'F': RETURN("F");
1266
0
    case 'D': RETURN("D");
1267
0
    case '?': RETURN("?");
1268
0
    case 'P': RETURN("P");
1269
2
    }
1270
1271
0
    return NULL;
1272
2
}
1273
1274
1275
/* Cast a memoryview's data type to 'format'. The input array must be
1276
   C-contiguous. At least one of input-format, output-format must have
1277
   byte size. The output array is 1-D, with the same byte length as the
1278
   input array. Thus, view->len must be a multiple of the new itemsize. */
1279
static int
1280
cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
1281
2
{
1282
2
    Py_buffer *view = &mv->view;
1283
2
    PyObject *asciifmt;
1284
2
    char srcchar, destchar;
1285
2
    Py_ssize_t itemsize;
1286
2
    int ret = -1;
1287
1288
2
    assert(view->ndim >= 1);
1289
2
    assert(Py_SIZE(mv) == 3*view->ndim);
1290
2
    assert(view->shape == mv->ob_array);
1291
2
    assert(view->strides == mv->ob_array + view->ndim);
1292
2
    assert(view->suboffsets == mv->ob_array + 2*view->ndim);
1293
1294
2
    asciifmt = PyUnicode_AsASCIIString(format);
1295
2
    if (asciifmt == NULL)
1296
0
        return ret;
1297
1298
2
    itemsize = get_native_fmtchar(&destchar, PyBytes_AS_STRING(asciifmt));
1299
2
    if (itemsize < 0) {
1300
0
        PyErr_SetString(PyExc_ValueError,
1301
0
            "memoryview: destination format must be a native single "
1302
0
            "character format prefixed with an optional '@'");
1303
0
        goto out;
1304
0
    }
1305
1306
2
    if ((get_native_fmtchar(&srcchar, view->format) < 0 ||
1307
2
         !IS_BYTE_FORMAT(srcchar)) && !IS_BYTE_FORMAT(destchar)) {
1308
0
        PyErr_SetString(PyExc_TypeError,
1309
0
            "memoryview: cannot cast between two non-byte formats");
1310
0
        goto out;
1311
0
    }
1312
2
    if (view->len % itemsize) {
1313
0
        PyErr_SetString(PyExc_TypeError,
1314
0
            "memoryview: length is not a multiple of itemsize");
1315
0
        goto out;
1316
0
    }
1317
1318
2
    view->format = (char *)get_native_fmtstr(PyBytes_AS_STRING(asciifmt));
1319
2
    if (view->format == NULL) {
1320
        /* NOT_REACHED: get_native_fmtchar() already validates the format. */
1321
0
        PyErr_SetString(PyExc_RuntimeError,
1322
0
            "memoryview: internal error");
1323
0
        goto out;
1324
0
    }
1325
2
    view->itemsize = itemsize;
1326
1327
2
    view->ndim = 1;
1328
2
    view->shape[0] = view->len / view->itemsize;
1329
2
    view->strides[0] = view->itemsize;
1330
2
    view->suboffsets = NULL;
1331
1332
2
    init_flags(mv);
1333
1334
2
    ret = 0;
1335
1336
2
out:
1337
2
    Py_DECREF(asciifmt);
1338
2
    return ret;
1339
2
}
1340
1341
/* The memoryview must have space for 3*len(seq) elements. */
1342
static Py_ssize_t
1343
copy_shape(Py_ssize_t *shape, const PyObject *seq, Py_ssize_t ndim,
1344
           Py_ssize_t itemsize)
1345
0
{
1346
0
    Py_ssize_t x, i;
1347
0
    Py_ssize_t len = itemsize;
1348
1349
0
    for (i = 0; i < ndim; i++) {
1350
0
        PyObject *tmp = PySequence_Fast_GET_ITEM(seq, i);
1351
0
        if (!PyLong_Check(tmp)) {
1352
0
            PyErr_SetString(PyExc_TypeError,
1353
0
                "memoryview.cast(): elements of shape must be integers");
1354
0
            return -1;
1355
0
        }
1356
0
        x = PyLong_AsSsize_t(tmp);
1357
0
        if (x == -1 && PyErr_Occurred()) {
1358
0
            return -1;
1359
0
        }
1360
0
        if (x <= 0) {
1361
            /* In general elements of shape may be 0, but not for casting. */
1362
0
            PyErr_Format(PyExc_ValueError,
1363
0
                "memoryview.cast(): elements of shape must be integers > 0");
1364
0
            return -1;
1365
0
        }
1366
0
        if (x > PY_SSIZE_T_MAX / len) {
1367
0
            PyErr_Format(PyExc_ValueError,
1368
0
                "memoryview.cast(): product(shape) > SSIZE_MAX");
1369
0
            return -1;
1370
0
        }
1371
0
        len *= x;
1372
0
        shape[i] = x;
1373
0
    }
1374
1375
0
    return len;
1376
0
}
1377
1378
/* Cast a 1-D array to a new shape. The result array will be C-contiguous.
1379
   If the result array does not have exactly the same byte length as the
1380
   input array, raise ValueError. */
1381
static int
1382
cast_to_ND(PyMemoryViewObject *mv, const PyObject *shape, int ndim)
1383
0
{
1384
0
    Py_buffer *view = &mv->view;
1385
0
    Py_ssize_t len;
1386
1387
0
    assert(view->ndim == 1); /* ndim from cast_to_1D() */
1388
0
    assert(Py_SIZE(mv) == 3*(ndim==0?1:ndim)); /* ndim of result array */
1389
0
    assert(view->shape == mv->ob_array);
1390
0
    assert(view->strides == mv->ob_array + (ndim==0?1:ndim));
1391
0
    assert(view->suboffsets == NULL);
1392
1393
0
    view->ndim = ndim;
1394
0
    if (view->ndim == 0) {
1395
0
        view->shape = NULL;
1396
0
        view->strides = NULL;
1397
0
        len = view->itemsize;
1398
0
    }
1399
0
    else {
1400
0
        len = copy_shape(view->shape, shape, ndim, view->itemsize);
1401
0
        if (len < 0)
1402
0
            return -1;
1403
0
        init_strides_from_shape(view);
1404
0
    }
1405
1406
0
    if (view->len != len) {
1407
0
        PyErr_SetString(PyExc_TypeError,
1408
0
            "memoryview: product(shape) * itemsize != buffer size");
1409
0
        return -1;
1410
0
    }
1411
1412
0
    init_flags(mv);
1413
1414
0
    return 0;
1415
0
}
1416
1417
static int
1418
zero_in_shape(PyMemoryViewObject *mv)
1419
0
{
1420
0
    Py_buffer *view = &mv->view;
1421
0
    Py_ssize_t i;
1422
1423
0
    for (i = 0; i < view->ndim; i++)
1424
0
        if (view->shape[i] == 0)
1425
0
            return 1;
1426
1427
0
    return 0;
1428
0
}
1429
1430
/*
1431
   Cast a copy of 'self' to a different view. The input view must
1432
   be C-contiguous. The function always casts the input view to a
1433
   1-D output according to 'format'. At least one of input-format,
1434
   output-format must have byte size.
1435
1436
   If 'shape' is given, the 1-D view from the previous step will
1437
   be cast to a C-contiguous view with new shape and strides.
1438
1439
   All casts must result in views that will have the exact byte
1440
   size of the original input. Otherwise, an error is raised.
1441
*/
1442
/*[clinic input]
1443
memoryview.cast
1444
1445
    format: unicode
1446
    shape: object = NULL
1447
1448
Cast a memoryview to a new format or shape.
1449
[clinic start generated code]*/
1450
1451
static PyObject *
1452
memoryview_cast_impl(PyMemoryViewObject *self, PyObject *format,
1453
                     PyObject *shape)
1454
/*[clinic end generated code: output=bae520b3a389cbab input=138936cc9041b1a3]*/
1455
2
{
1456
2
    PyMemoryViewObject *mv = NULL;
1457
2
    Py_ssize_t ndim = 1;
1458
1459
2
    CHECK_RELEASED(self);
1460
2
    CHECK_RESTRICTED(self);
1461
1462
2
    if (!MV_C_CONTIGUOUS(self->flags)) {
1463
0
        PyErr_SetString(PyExc_TypeError,
1464
0
            "memoryview: casts are restricted to C-contiguous views");
1465
0
        return NULL;
1466
0
    }
1467
2
    if ((shape || self->view.ndim != 1) && zero_in_shape(self)) {
1468
0
        PyErr_SetString(PyExc_TypeError,
1469
0
            "memoryview: cannot cast view with zeros in shape or strides");
1470
0
        return NULL;
1471
0
    }
1472
2
    if (shape) {
1473
0
        CHECK_LIST_OR_TUPLE(shape)
1474
0
        ndim = PySequence_Fast_GET_SIZE(shape);
1475
0
        if (ndim > PyBUF_MAX_NDIM) {
1476
0
            PyErr_SetString(PyExc_ValueError,
1477
0
                "memoryview: number of dimensions must not exceed "
1478
0
                Py_STRINGIFY(PyBUF_MAX_NDIM));
1479
0
            return NULL;
1480
0
        }
1481
0
        if (self->view.ndim != 1 && ndim != 1) {
1482
0
            PyErr_SetString(PyExc_TypeError,
1483
0
                "memoryview: cast must be 1D -> ND or ND -> 1D");
1484
0
            return NULL;
1485
0
        }
1486
0
    }
1487
1488
2
    mv = (PyMemoryViewObject *)
1489
2
        mbuf_add_incomplete_view(self->mbuf, &self->view, ndim==0 ? 1 : (int)ndim);
1490
2
    if (mv == NULL)
1491
0
        return NULL;
1492
1493
2
    if (cast_to_1D(mv, format) < 0)
1494
0
        goto error;
1495
2
    if (shape && cast_to_ND(mv, shape, (int)ndim) < 0)
1496
0
        goto error;
1497
1498
2
    return (PyObject *)mv;
1499
1500
0
error:
1501
0
    Py_DECREF(mv);
1502
0
    return NULL;
1503
2
}
1504
1505
/*[clinic input]
1506
memoryview.toreadonly
1507
1508
Return a readonly version of the memoryview.
1509
[clinic start generated code]*/
1510
1511
static PyObject *
1512
memoryview_toreadonly_impl(PyMemoryViewObject *self)
1513
/*[clinic end generated code: output=2c7e056f04c99e62 input=dc06d20f19ba236f]*/
1514
0
{
1515
0
    CHECK_RELEASED(self);
1516
0
    CHECK_RESTRICTED(self);
1517
    /* Even if self is already readonly, we still need to create a new
1518
     * object for .release() to work correctly.
1519
     */
1520
0
    self = (PyMemoryViewObject *) mbuf_add_view(self->mbuf, &self->view);
1521
0
    if (self != NULL) {
1522
0
        self->view.readonly = 1;
1523
0
    };
1524
0
    return (PyObject *) self;
1525
0
}
1526
1527
1528
/**************************************************************************/
1529
/*                               getbuffer                                */
1530
/**************************************************************************/
1531
1532
static int
1533
memory_getbuf(PyObject *_self, Py_buffer *view, int flags)
1534
158k
{
1535
158k
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
1536
158k
    Py_buffer *base = &self->view;
1537
158k
    int baseflags = self->flags;
1538
1539
158k
    CHECK_RELEASED_INT(self);
1540
158k
    CHECK_RESTRICTED_INT(self);
1541
1542
    /* start with complete information */
1543
158k
    *view = *base;
1544
158k
    view->obj = NULL;
1545
1546
158k
    if (REQ_WRITABLE(flags) && base->readonly) {
1547
0
        PyErr_SetString(PyExc_BufferError,
1548
0
            "memoryview: underlying buffer is not writable");
1549
0
        return -1;
1550
0
    }
1551
158k
    if (!REQ_FORMAT(flags)) {
1552
        /* NULL indicates that the buffer's data type has been cast to 'B'.
1553
           view->itemsize is the _previous_ itemsize. If shape is present,
1554
           the equality product(shape) * itemsize = len still holds at this
1555
           point. The equality calcsize(format) = itemsize does _not_ hold
1556
           from here on! */
1557
156k
        view->format = NULL;
1558
156k
    }
1559
1560
158k
    if (REQ_C_CONTIGUOUS(flags) && !MV_C_CONTIGUOUS(baseflags)) {
1561
0
        PyErr_SetString(PyExc_BufferError,
1562
0
            "memoryview: underlying buffer is not C-contiguous");
1563
0
        return -1;
1564
0
    }
1565
158k
    if (REQ_F_CONTIGUOUS(flags) && !MV_F_CONTIGUOUS(baseflags)) {
1566
0
        PyErr_SetString(PyExc_BufferError,
1567
0
            "memoryview: underlying buffer is not Fortran contiguous");
1568
0
        return -1;
1569
0
    }
1570
158k
    if (REQ_ANY_CONTIGUOUS(flags) && !MV_ANY_CONTIGUOUS(baseflags)) {
1571
0
        PyErr_SetString(PyExc_BufferError,
1572
0
            "memoryview: underlying buffer is not contiguous");
1573
0
        return -1;
1574
0
    }
1575
158k
    if (!REQ_INDIRECT(flags) && (baseflags & _Py_MEMORYVIEW_PIL)) {
1576
0
        PyErr_SetString(PyExc_BufferError,
1577
0
            "memoryview: underlying buffer requires suboffsets");
1578
0
        return -1;
1579
0
    }
1580
158k
    if (!REQ_STRIDES(flags)) {
1581
156k
        if (!MV_C_CONTIGUOUS(baseflags)) {
1582
0
            PyErr_SetString(PyExc_BufferError,
1583
0
                "memoryview: underlying buffer is not C-contiguous");
1584
0
            return -1;
1585
0
        }
1586
156k
        view->strides = NULL;
1587
156k
    }
1588
158k
    if (!REQ_SHAPE(flags)) {
1589
        /* PyBUF_SIMPLE or PyBUF_WRITABLE: at this point buf is C-contiguous,
1590
           so base->buf = ndbuf->data. */
1591
156k
        if (view->format != NULL) {
1592
            /* PyBUF_SIMPLE|PyBUF_FORMAT and PyBUF_WRITABLE|PyBUF_FORMAT do
1593
               not make sense. */
1594
0
            PyErr_Format(PyExc_BufferError,
1595
0
                "memoryview: cannot cast to unsigned bytes if the format flag "
1596
0
                "is present");
1597
0
            return -1;
1598
0
        }
1599
        /* product(shape) * itemsize = len and calcsize(format) = itemsize
1600
           do _not_ hold from here on! */
1601
156k
        view->ndim = 1;
1602
156k
        view->shape = NULL;
1603
156k
    }
1604
1605
1606
158k
    view->obj = Py_NewRef(self);
1607
#ifdef Py_GIL_DISABLED
1608
    _Py_atomic_add_ssize(&self->exports, 1);
1609
#else
1610
158k
    self->exports++;
1611
158k
#endif
1612
1613
158k
    return 0;
1614
158k
}
1615
1616
static void
1617
memory_releasebuf(PyObject *_self, Py_buffer *view)
1618
158k
{
1619
158k
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
1620
#ifdef Py_GIL_DISABLED
1621
    _Py_atomic_add_ssize(&self->exports, -1);
1622
#else
1623
158k
    self->exports--;
1624
158k
#endif
1625
158k
    return;
1626
    /* PyBuffer_Release() decrements view->obj after this function returns. */
1627
158k
}
1628
1629
/* Buffer methods */
1630
static PyBufferProcs memory_as_buffer = {
1631
    memory_getbuf,         /* bf_getbuffer */
1632
    memory_releasebuf,                    /* bf_releasebuffer */
1633
};
1634
1635
1636
/****************************************************************************/
1637
/*           Optimized pack/unpack for all native format specifiers         */
1638
/****************************************************************************/
1639
1640
/*
1641
  Fix exceptions:
1642
     1) Include format string in the error message.
1643
     2) OverflowError -> ValueError.
1644
     3) The error message from PyNumber_Index() is not ideal.
1645
*/
1646
static int
1647
type_error_int(const char *fmt)
1648
0
{
1649
0
    PyErr_Format(PyExc_TypeError,
1650
0
        "memoryview: invalid type for format '%s'", fmt);
1651
0
    return -1;
1652
0
}
1653
1654
static int
1655
value_error_int(const char *fmt)
1656
0
{
1657
0
    PyErr_Format(PyExc_ValueError,
1658
0
        "memoryview: invalid value for format '%s'", fmt);
1659
0
    return -1;
1660
0
}
1661
1662
static int
1663
fix_error_int(const char *fmt)
1664
0
{
1665
0
    assert(PyErr_Occurred());
1666
0
    if (PyErr_ExceptionMatches(PyExc_TypeError)) {
1667
0
        PyErr_Clear();
1668
0
        return type_error_int(fmt);
1669
0
    }
1670
0
    else if (PyErr_ExceptionMatches(PyExc_OverflowError) ||
1671
0
             PyErr_ExceptionMatches(PyExc_ValueError)) {
1672
0
        PyErr_Clear();
1673
0
        return value_error_int(fmt);
1674
0
    }
1675
1676
0
    return -1;
1677
0
}
1678
1679
/* Accept integer objects or objects with an __index__() method. */
1680
static long
1681
pylong_as_ld(PyObject *item)
1682
0
{
1683
0
    PyObject *tmp;
1684
0
    long ld;
1685
1686
0
    tmp = _PyNumber_Index(item);
1687
0
    if (tmp == NULL)
1688
0
        return -1;
1689
1690
0
    ld = PyLong_AsLong(tmp);
1691
0
    Py_DECREF(tmp);
1692
0
    return ld;
1693
0
}
1694
1695
static unsigned long
1696
pylong_as_lu(PyObject *item)
1697
0
{
1698
0
    PyObject *tmp;
1699
0
    unsigned long lu;
1700
1701
0
    tmp = _PyNumber_Index(item);
1702
0
    if (tmp == NULL)
1703
0
        return (unsigned long)-1;
1704
1705
0
    lu = PyLong_AsUnsignedLong(tmp);
1706
0
    Py_DECREF(tmp);
1707
0
    return lu;
1708
0
}
1709
1710
static long long
1711
pylong_as_lld(PyObject *item)
1712
0
{
1713
0
    PyObject *tmp;
1714
0
    long long lld;
1715
1716
0
    tmp = _PyNumber_Index(item);
1717
0
    if (tmp == NULL)
1718
0
        return -1;
1719
1720
0
    lld = PyLong_AsLongLong(tmp);
1721
0
    Py_DECREF(tmp);
1722
0
    return lld;
1723
0
}
1724
1725
static unsigned long long
1726
pylong_as_llu(PyObject *item)
1727
0
{
1728
0
    PyObject *tmp;
1729
0
    unsigned long long llu;
1730
1731
0
    tmp = _PyNumber_Index(item);
1732
0
    if (tmp == NULL)
1733
0
        return (unsigned long long)-1;
1734
1735
0
    llu = PyLong_AsUnsignedLongLong(tmp);
1736
0
    Py_DECREF(tmp);
1737
0
    return llu;
1738
0
}
1739
1740
static Py_ssize_t
1741
pylong_as_zd(PyObject *item)
1742
0
{
1743
0
    PyObject *tmp;
1744
0
    Py_ssize_t zd;
1745
1746
0
    tmp = _PyNumber_Index(item);
1747
0
    if (tmp == NULL)
1748
0
        return -1;
1749
1750
0
    zd = PyLong_AsSsize_t(tmp);
1751
0
    Py_DECREF(tmp);
1752
0
    return zd;
1753
0
}
1754
1755
static size_t
1756
pylong_as_zu(PyObject *item)
1757
0
{
1758
0
    PyObject *tmp;
1759
0
    size_t zu;
1760
1761
0
    tmp = _PyNumber_Index(item);
1762
0
    if (tmp == NULL)
1763
0
        return (size_t)-1;
1764
1765
0
    zu = PyLong_AsSize_t(tmp);
1766
0
    Py_DECREF(tmp);
1767
0
    return zu;
1768
0
}
1769
1770
/* Timings with the ndarray from _testbuffer.c indicate that using the
1771
   struct module is around 15x slower than the two functions below. */
1772
1773
#define UNPACK_SINGLE(dest, ptr, type) \
1774
128
    do {                                   \
1775
128
        type x;                            \
1776
128
        memcpy((char *)&x, ptr, sizeof x); \
1777
128
        dest = x;                          \
1778
128
    } while (0)
1779
1780
/* Unpack a single item. 'fmt' can be any native format character in struct
1781
   module syntax. This function is very sensitive to small changes. With this
1782
   layout gcc automatically generates a fast jump table. */
1783
static inline PyObject *
1784
unpack_single(PyMemoryViewObject *self, const char *ptr, const char *fmt)
1785
128
{
1786
128
    unsigned long long llu;
1787
128
    unsigned long lu;
1788
128
    size_t zu;
1789
128
    long long lld;
1790
128
    long ld;
1791
128
    Py_ssize_t zd;
1792
128
    double d[2];
1793
128
    unsigned char uc;
1794
128
    void *p;
1795
1796
128
    CHECK_RELEASED_AGAIN(self);
1797
1798
128
#if PY_LITTLE_ENDIAN
1799
128
    int endian = 1;
1800
#else
1801
    int endian = 0;
1802
#endif
1803
1804
128
    switch (fmt[0]) {
1805
1806
    /* signed integers and fast path for 'B' */
1807
0
    case 'B': uc = *((const unsigned char *)ptr); goto convert_uc;
1808
0
    case 'b': ld =   *((const signed char *)ptr); goto convert_ld;
1809
0
    case 'h': UNPACK_SINGLE(ld, ptr, short); goto convert_ld;
1810
0
    case 'i': UNPACK_SINGLE(ld, ptr, int); goto convert_ld;
1811
0
    case 'l': UNPACK_SINGLE(ld, ptr, long); goto convert_ld;
1812
1813
    /* boolean */
1814
0
    case '?': UNPACK_SINGLE(ld, ptr, _Bool); goto convert_bool;
1815
1816
    /* unsigned integers */
1817
0
    case 'H': UNPACK_SINGLE(lu, ptr, unsigned short); goto convert_lu;
1818
128
    case 'I': UNPACK_SINGLE(lu, ptr, unsigned int); goto convert_lu;
1819
0
    case 'L': UNPACK_SINGLE(lu, ptr, unsigned long); goto convert_lu;
1820
1821
    /* native 64-bit */
1822
0
    case 'q': UNPACK_SINGLE(lld, ptr, long long); goto convert_lld;
1823
0
    case 'Q': UNPACK_SINGLE(llu, ptr, unsigned long long); goto convert_llu;
1824
1825
    /* ssize_t and size_t */
1826
0
    case 'n': UNPACK_SINGLE(zd, ptr, Py_ssize_t); goto convert_zd;
1827
0
    case 'N': UNPACK_SINGLE(zu, ptr, size_t); goto convert_zu;
1828
1829
    /* floats */
1830
0
    case 'f': UNPACK_SINGLE(d[0], ptr, float); goto convert_double;
1831
0
    case 'd': UNPACK_SINGLE(d[0], ptr, double); goto convert_double;
1832
0
    case 'e': d[0] = PyFloat_Unpack2(ptr, endian); goto convert_double;
1833
1834
    /* complexes */
1835
0
    case 'F':
1836
0
        d[0] = PyFloat_Unpack4(ptr, endian);
1837
0
        d[1] = PyFloat_Unpack4(ptr + sizeof(float), endian);
1838
0
        goto convert_double_complex;
1839
1840
0
    case 'D':
1841
0
        d[0] = PyFloat_Unpack8(ptr, endian);
1842
0
        d[1] = PyFloat_Unpack8(ptr + sizeof(double), endian);
1843
0
        goto convert_double_complex;
1844
1845
    /* bytes object */
1846
0
    case 'c': goto convert_bytes;
1847
1848
    /* pointer */
1849
0
    case 'P': UNPACK_SINGLE(p, ptr, void *); goto convert_pointer;
1850
1851
    /* default */
1852
0
    default: goto err_format;
1853
128
    }
1854
1855
0
convert_uc:
1856
    /* PyLong_FromUnsignedLong() is slower */
1857
0
    return PyLong_FromLong(uc);
1858
0
convert_ld:
1859
0
    return PyLong_FromLong(ld);
1860
128
convert_lu:
1861
128
    return PyLong_FromUnsignedLong(lu);
1862
0
convert_lld:
1863
0
    return PyLong_FromLongLong(lld);
1864
0
convert_llu:
1865
0
    return PyLong_FromUnsignedLongLong(llu);
1866
0
convert_zd:
1867
0
    return PyLong_FromSsize_t(zd);
1868
0
convert_zu:
1869
0
    return PyLong_FromSize_t(zu);
1870
0
convert_double:
1871
0
    return PyFloat_FromDouble(d[0]);
1872
0
convert_double_complex:
1873
0
    return PyComplex_FromDoubles(d[0], d[1]);
1874
0
convert_bool:
1875
0
    return PyBool_FromLong(ld);
1876
0
convert_bytes:
1877
0
    return PyBytes_FromStringAndSize(ptr, 1);
1878
0
convert_pointer:
1879
0
    return PyLong_FromVoidPtr(p);
1880
0
err_format:
1881
0
    PyErr_Format(PyExc_NotImplementedError,
1882
0
        "memoryview: format %s not supported", fmt);
1883
0
    return NULL;
1884
128
}
1885
1886
#define PACK_SINGLE(ptr, src, type) \
1887
0
    do {                                     \
1888
0
        type x;                              \
1889
0
        x = (type)src;                       \
1890
0
        memcpy(ptr, (char *)&x, sizeof x);   \
1891
0
    } while (0)
1892
1893
/* Pack a single item. 'fmt' can be any native format character in
1894
   struct module syntax. */
1895
static int
1896
pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt)
1897
0
{
1898
0
    unsigned long long llu;
1899
0
    unsigned long lu;
1900
0
    size_t zu;
1901
0
    long long lld;
1902
0
    long ld;
1903
0
    Py_ssize_t zd;
1904
0
    double d;
1905
0
    Py_complex c;
1906
0
    void *p;
1907
1908
0
#if PY_LITTLE_ENDIAN
1909
0
    int endian = 1;
1910
#else
1911
    int endian = 0;
1912
#endif
1913
0
    switch (fmt[0]) {
1914
    /* signed integers */
1915
0
    case 'b': case 'h': case 'i': case 'l':
1916
0
        ld = pylong_as_ld(item);
1917
0
        if (ld == -1 && PyErr_Occurred())
1918
0
            goto err_occurred;
1919
0
        CHECK_RELEASED_INT_AGAIN(self);
1920
0
        switch (fmt[0]) {
1921
0
        case 'b':
1922
0
            if (ld < SCHAR_MIN || ld > SCHAR_MAX) goto err_range;
1923
0
            *((signed char *)ptr) = (signed char)ld; break;
1924
0
        case 'h':
1925
0
            if (ld < SHRT_MIN || ld > SHRT_MAX) goto err_range;
1926
0
            PACK_SINGLE(ptr, ld, short); break;
1927
0
        case 'i':
1928
0
            if (ld < INT_MIN || ld > INT_MAX) goto err_range;
1929
0
            PACK_SINGLE(ptr, ld, int); break;
1930
0
        default: /* 'l' */
1931
0
            PACK_SINGLE(ptr, ld, long); break;
1932
0
        }
1933
0
        break;
1934
1935
    /* unsigned integers */
1936
0
    case 'B': case 'H': case 'I': case 'L':
1937
0
        lu = pylong_as_lu(item);
1938
0
        if (lu == (unsigned long)-1 && PyErr_Occurred())
1939
0
            goto err_occurred;
1940
0
        CHECK_RELEASED_INT_AGAIN(self);
1941
0
        switch (fmt[0]) {
1942
0
        case 'B':
1943
0
            if (lu > UCHAR_MAX) goto err_range;
1944
0
            *((unsigned char *)ptr) = (unsigned char)lu; break;
1945
0
        case 'H':
1946
0
            if (lu > USHRT_MAX) goto err_range;
1947
0
            PACK_SINGLE(ptr, lu, unsigned short); break;
1948
0
        case 'I':
1949
0
            if (lu > UINT_MAX) goto err_range;
1950
0
            PACK_SINGLE(ptr, lu, unsigned int); break;
1951
0
        default: /* 'L' */
1952
0
            PACK_SINGLE(ptr, lu, unsigned long); break;
1953
0
        }
1954
0
        break;
1955
1956
    /* native 64-bit */
1957
0
    case 'q':
1958
0
        lld = pylong_as_lld(item);
1959
0
        if (lld == -1 && PyErr_Occurred())
1960
0
            goto err_occurred;
1961
0
        CHECK_RELEASED_INT_AGAIN(self);
1962
0
        PACK_SINGLE(ptr, lld, long long);
1963
0
        break;
1964
0
    case 'Q':
1965
0
        llu = pylong_as_llu(item);
1966
0
        if (llu == (unsigned long long)-1 && PyErr_Occurred())
1967
0
            goto err_occurred;
1968
0
        CHECK_RELEASED_INT_AGAIN(self);
1969
0
        PACK_SINGLE(ptr, llu, unsigned long long);
1970
0
        break;
1971
1972
    /* ssize_t and size_t */
1973
0
    case 'n':
1974
0
        zd = pylong_as_zd(item);
1975
0
        if (zd == -1 && PyErr_Occurred())
1976
0
            goto err_occurred;
1977
0
        CHECK_RELEASED_INT_AGAIN(self);
1978
0
        PACK_SINGLE(ptr, zd, Py_ssize_t);
1979
0
        break;
1980
0
    case 'N':
1981
0
        zu = pylong_as_zu(item);
1982
0
        if (zu == (size_t)-1 && PyErr_Occurred())
1983
0
            goto err_occurred;
1984
0
        CHECK_RELEASED_INT_AGAIN(self);
1985
0
        PACK_SINGLE(ptr, zu, size_t);
1986
0
        break;
1987
1988
    /* floats */
1989
0
    case 'f': case 'd': case 'e':
1990
0
        d = PyFloat_AsDouble(item);
1991
0
        if (d == -1.0 && PyErr_Occurred())
1992
0
            goto err_occurred;
1993
0
        CHECK_RELEASED_INT_AGAIN(self);
1994
0
        if (fmt[0] == 'f') {
1995
0
            PACK_SINGLE(ptr, d, float);
1996
0
        }
1997
0
        else if (fmt[0] == 'd') {
1998
0
            PACK_SINGLE(ptr, d, double);
1999
0
        }
2000
0
        else {
2001
0
            if (PyFloat_Pack2(d, ptr, endian) < 0) {
2002
0
                goto err_occurred;
2003
0
            }
2004
0
        }
2005
0
        break;
2006
2007
    /* complexes */
2008
0
    case 'F': case 'D':
2009
0
        c = PyComplex_AsCComplex(item);
2010
0
        if (c.real == -1.0 && PyErr_Occurred()) {
2011
0
            goto err_occurred;
2012
0
        }
2013
0
        CHECK_RELEASED_INT_AGAIN(self);
2014
0
        if (fmt[0] == 'D') {
2015
0
            double x[2] = {c.real, c.imag};
2016
2017
0
            memcpy(ptr, &x, sizeof(x));
2018
0
        }
2019
0
        else {
2020
0
            float x[2] = {(float)c.real, (float)c.imag};
2021
2022
0
            memcpy(ptr, &x, sizeof(x));
2023
0
        }
2024
0
        break;
2025
2026
    /* bool */
2027
0
    case '?':
2028
0
        ld = PyObject_IsTrue(item);
2029
0
        if (ld < 0)
2030
0
            return -1; /* preserve original error */
2031
0
        CHECK_RELEASED_INT_AGAIN(self);
2032
0
        PACK_SINGLE(ptr, ld, _Bool);
2033
0
        break;
2034
2035
    /* bytes object */
2036
0
    case 'c':
2037
0
        if (!PyBytes_Check(item))
2038
0
            return type_error_int(fmt);
2039
0
        if (PyBytes_GET_SIZE(item) != 1)
2040
0
            return value_error_int(fmt);
2041
0
        *ptr = PyBytes_AS_STRING(item)[0];
2042
0
        break;
2043
2044
    /* pointer */
2045
0
    case 'P':
2046
0
        p = PyLong_AsVoidPtr(item);
2047
0
        if (p == NULL && PyErr_Occurred())
2048
0
            goto err_occurred;
2049
0
        CHECK_RELEASED_INT_AGAIN(self);
2050
0
        PACK_SINGLE(ptr, p, void *);
2051
0
        break;
2052
2053
    /* default */
2054
0
    default: goto err_format;
2055
0
    }
2056
2057
0
    return 0;
2058
2059
0
err_occurred:
2060
0
    return fix_error_int(fmt);
2061
0
err_range:
2062
0
    return value_error_int(fmt);
2063
0
err_format:
2064
0
    PyErr_Format(PyExc_NotImplementedError,
2065
0
        "memoryview: format %s not supported", fmt);
2066
0
    return -1;
2067
0
}
2068
2069
2070
/****************************************************************************/
2071
/*                       unpack using the struct module                     */
2072
/****************************************************************************/
2073
2074
/* For reasonable performance it is necessary to cache all objects required
2075
   for unpacking. An unpacker can handle the format passed to unpack_from().
2076
   Invariant: All pointer fields of the struct should either be NULL or valid
2077
   pointers. */
2078
struct unpacker {
2079
    PyObject *unpack_from; /* Struct.unpack_from(format) */
2080
    PyObject *mview;       /* cached memoryview */
2081
    char *item;            /* buffer for mview */
2082
    Py_ssize_t itemsize;   /* len(item) */
2083
};
2084
2085
static struct unpacker *
2086
unpacker_new(void)
2087
0
{
2088
0
    struct unpacker *x = PyMem_Malloc(sizeof *x);
2089
2090
0
    if (x == NULL) {
2091
0
        PyErr_NoMemory();
2092
0
        return NULL;
2093
0
    }
2094
2095
0
    x->unpack_from = NULL;
2096
0
    x->mview = NULL;
2097
0
    x->item = NULL;
2098
0
    x->itemsize = 0;
2099
2100
0
    return x;
2101
0
}
2102
2103
static void
2104
unpacker_free(struct unpacker *x)
2105
1.13k
{
2106
1.13k
    if (x) {
2107
0
        Py_XDECREF(x->unpack_from);
2108
0
        Py_XDECREF(x->mview);
2109
0
        PyMem_Free(x->item);
2110
0
        PyMem_Free(x);
2111
0
    }
2112
1.13k
}
2113
2114
/* Return a new unpacker for the given format. */
2115
static struct unpacker *
2116
struct_get_unpacker(const char *fmt, Py_ssize_t itemsize)
2117
0
{
2118
0
    PyObject *Struct = NULL;    /* XXX cache it in globals? */
2119
0
    PyObject *structobj = NULL;
2120
0
    PyObject *format = NULL;
2121
0
    struct unpacker *x = NULL;
2122
2123
0
    Struct = PyImport_ImportModuleAttrString("struct", "Struct");
2124
0
    if (Struct == NULL)
2125
0
        return NULL;
2126
2127
0
    x = unpacker_new();
2128
0
    if (x == NULL)
2129
0
        goto error;
2130
2131
0
    format = PyBytes_FromString(fmt);
2132
0
    if (format == NULL)
2133
0
        goto error;
2134
2135
0
    structobj = PyObject_CallOneArg(Struct, format);
2136
0
    if (structobj == NULL)
2137
0
        goto error;
2138
2139
0
    x->unpack_from = PyObject_GetAttrString(structobj, "unpack_from");
2140
0
    if (x->unpack_from == NULL)
2141
0
        goto error;
2142
2143
0
    x->item = PyMem_Malloc(itemsize);
2144
0
    if (x->item == NULL) {
2145
0
        PyErr_NoMemory();
2146
0
        goto error;
2147
0
    }
2148
0
    x->itemsize = itemsize;
2149
2150
0
    x->mview = PyMemoryView_FromMemory(x->item, itemsize, PyBUF_WRITE);
2151
0
    if (x->mview == NULL)
2152
0
        goto error;
2153
2154
2155
0
out:
2156
0
    Py_XDECREF(Struct);
2157
0
    Py_XDECREF(format);
2158
0
    Py_XDECREF(structobj);
2159
0
    return x;
2160
2161
0
error:
2162
0
    unpacker_free(x);
2163
0
    x = NULL;
2164
0
    goto out;
2165
0
}
2166
2167
/* unpack a single item */
2168
static PyObject *
2169
struct_unpack_single(const char *ptr, struct unpacker *x)
2170
0
{
2171
0
    PyObject *v;
2172
2173
0
    memcpy(x->item, ptr, x->itemsize);
2174
0
    v = PyObject_CallOneArg(x->unpack_from, x->mview);
2175
0
    if (v == NULL)
2176
0
        return NULL;
2177
2178
0
    if (PyTuple_GET_SIZE(v) == 1) {
2179
0
        PyObject *res = Py_NewRef(PyTuple_GET_ITEM(v, 0));
2180
0
        Py_DECREF(v);
2181
0
        return res;
2182
0
    }
2183
2184
0
    return v;
2185
0
}
2186
2187
2188
/****************************************************************************/
2189
/*                              Representations                             */
2190
/****************************************************************************/
2191
2192
/* allow explicit form of native format */
2193
static inline const char *
2194
adjust_fmt(const Py_buffer *view)
2195
2
{
2196
2
    const char *fmt;
2197
2198
2
    fmt = (view->format[0] == '@') ? view->format+1 : view->format;
2199
2
    if (fmt[0] && fmt[1] == '\0')
2200
2
        return fmt;
2201
2202
0
    PyErr_Format(PyExc_NotImplementedError,
2203
0
        "memoryview: unsupported format %s", view->format);
2204
0
    return NULL;
2205
2
}
2206
2207
/* Base case for multi-dimensional unpacking. Assumption: ndim == 1. */
2208
static PyObject *
2209
tolist_base(PyMemoryViewObject *self, const char *ptr, const Py_ssize_t *shape,
2210
            const Py_ssize_t *strides, const Py_ssize_t *suboffsets,
2211
            const char *fmt)
2212
2
{
2213
2
    PyObject *lst, *item;
2214
2
    Py_ssize_t i;
2215
2216
2
    lst = PyList_New(shape[0]);
2217
2
    if (lst == NULL)
2218
0
        return NULL;
2219
2220
130
    for (i = 0; i < shape[0]; ptr+=strides[0], i++) {
2221
128
        const char *xptr = ADJUST_PTR(ptr, suboffsets, 0);
2222
128
        item = unpack_single(self, xptr, fmt);
2223
128
        if (item == NULL) {
2224
0
            Py_DECREF(lst);
2225
0
            return NULL;
2226
0
        }
2227
128
        PyList_SET_ITEM(lst, i, item);
2228
128
    }
2229
2230
2
    return lst;
2231
2
}
2232
2233
/* Unpack a multi-dimensional array into a nested list.
2234
   Assumption: ndim >= 1. */
2235
static PyObject *
2236
tolist_rec(PyMemoryViewObject *self, const char *ptr, Py_ssize_t ndim, const Py_ssize_t *shape,
2237
           const Py_ssize_t *strides, const Py_ssize_t *suboffsets,
2238
           const char *fmt)
2239
0
{
2240
0
    PyObject *lst, *item;
2241
0
    Py_ssize_t i;
2242
2243
0
    assert(ndim >= 1);
2244
0
    assert(shape != NULL);
2245
0
    assert(strides != NULL);
2246
2247
0
    if (ndim == 1)
2248
0
        return tolist_base(self, ptr, shape, strides, suboffsets, fmt);
2249
2250
0
    lst = PyList_New(shape[0]);
2251
0
    if (lst == NULL)
2252
0
        return NULL;
2253
2254
0
    for (i = 0; i < shape[0]; ptr+=strides[0], i++) {
2255
0
        const char *xptr = ADJUST_PTR(ptr, suboffsets, 0);
2256
0
        item = tolist_rec(self, xptr, ndim-1, shape+1,
2257
0
                          strides+1, suboffsets ? suboffsets+1 : NULL,
2258
0
                          fmt);
2259
0
        if (item == NULL) {
2260
0
            Py_DECREF(lst);
2261
0
            return NULL;
2262
0
        }
2263
0
        PyList_SET_ITEM(lst, i, item);
2264
0
    }
2265
2266
0
    return lst;
2267
0
}
2268
2269
/* Return a list representation of the memoryview. Currently only buffers
2270
   with native format strings are supported. */
2271
/*[clinic input]
2272
memoryview.tolist
2273
2274
Return the data in the buffer as a list of elements.
2275
[clinic start generated code]*/
2276
2277
static PyObject *
2278
memoryview_tolist_impl(PyMemoryViewObject *self)
2279
/*[clinic end generated code: output=a6cda89214fd5a1b input=21e7d0c1860b211a]*/
2280
2
{
2281
2
    const Py_buffer *view = &self->view;
2282
2
    const char *fmt;
2283
2284
2
    CHECK_RELEASED(self);
2285
2286
2
    fmt = adjust_fmt(view);
2287
2
    if (fmt == NULL)
2288
0
        return NULL;
2289
2
    if (view->ndim == 0) {
2290
0
        return unpack_single(self, view->buf, fmt);
2291
0
    }
2292
2
    else if (view->ndim == 1) {
2293
2
        return tolist_base(self, view->buf, view->shape,
2294
2
                           view->strides, view->suboffsets,
2295
2
                           fmt);
2296
2
    }
2297
0
    else {
2298
0
        return tolist_rec(self, view->buf, view->ndim, view->shape,
2299
0
                          view->strides, view->suboffsets,
2300
0
                          fmt);
2301
0
    }
2302
2
}
2303
2304
/*[clinic input]
2305
@permit_long_docstring_body
2306
memoryview.tobytes
2307
2308
    order: str(accept={str, NoneType}, c_default="NULL") = 'C'
2309
2310
Return the data in the buffer as a byte string.
2311
2312
Order can be {'C', 'F', 'A'}. When order is 'C' or 'F', the data of the
2313
original array is converted to C or Fortran order. For contiguous views,
2314
'A' returns an exact copy of the physical memory. In particular, in-memory
2315
Fortran order is preserved. For non-contiguous views, the data is converted
2316
to C first. order=None is the same as order='C'.
2317
[clinic start generated code]*/
2318
2319
static PyObject *
2320
memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order)
2321
/*[clinic end generated code: output=1288b62560a32a23 input=23c9faf372cfdbcc]*/
2322
0
{
2323
0
    Py_buffer *src = VIEW_ADDR(self);
2324
0
    char ord = 'C';
2325
2326
0
    CHECK_RELEASED(self);
2327
2328
0
    if (order) {
2329
0
        if (strcmp(order, "F") == 0) {
2330
0
            ord = 'F';
2331
0
        }
2332
0
        else if (strcmp(order, "A") == 0) {
2333
0
            ord = 'A';
2334
0
        }
2335
0
        else if (strcmp(order, "C") != 0) {
2336
0
            PyErr_SetString(PyExc_ValueError,
2337
0
                "order must be 'C', 'F' or 'A'");
2338
0
            return NULL;
2339
0
        }
2340
0
    }
2341
2342
0
    PyBytesWriter *writer = PyBytesWriter_Create(src->len);
2343
0
    if (writer == NULL) {
2344
0
        return NULL;
2345
0
    }
2346
2347
0
    if (PyBuffer_ToContiguous(PyBytesWriter_GetData(writer),
2348
0
                              src, src->len, ord) < 0) {
2349
0
        PyBytesWriter_Discard(writer);
2350
0
        return NULL;
2351
0
    }
2352
2353
0
    return PyBytesWriter_Finish(writer);
2354
0
}
2355
2356
/*[clinic input]
2357
memoryview.hex
2358
2359
    sep: object = NULL
2360
        An optional single character or byte to separate hex bytes.
2361
    bytes_per_sep: Py_ssize_t = 1
2362
        How many bytes between separators.  Positive values count from the
2363
        right, negative values count from the left.
2364
2365
Return the data in the buffer as a str of hexadecimal numbers.
2366
2367
Example:
2368
>>> value = memoryview(b'\xb9\x01\xef')
2369
>>> value.hex()
2370
'b901ef'
2371
>>> value.hex(':')
2372
'b9:01:ef'
2373
>>> value.hex(':', 2)
2374
'b9:01ef'
2375
>>> value.hex(':', -2)
2376
'b901:ef'
2377
[clinic start generated code]*/
2378
2379
static PyObject *
2380
memoryview_hex_impl(PyMemoryViewObject *self, PyObject *sep,
2381
                    Py_ssize_t bytes_per_sep)
2382
/*[clinic end generated code: output=c9bb00c7a8e86056 input=dc48a56ed3b058ae]*/
2383
0
{
2384
0
    Py_buffer *src = VIEW_ADDR(self);
2385
2386
0
    CHECK_RELEASED(self);
2387
2388
0
    if (MV_C_CONTIGUOUS(self->flags)) {
2389
        // Prevent 'self' from being freed if computing len(sep) mutates 'self'
2390
        // in _Py_strhex_with_sep().
2391
        // See: https://github.com/python/cpython/issues/143195.
2392
0
        self->exports++;
2393
0
        PyObject *ret = _Py_strhex_with_sep(src->buf, src->len, sep, bytes_per_sep);
2394
0
        self->exports--;
2395
0
        return ret;
2396
0
    }
2397
2398
0
    PyBytesWriter *writer = PyBytesWriter_Create(src->len);
2399
0
    if (writer == NULL) {
2400
0
        return NULL;
2401
0
    }
2402
2403
0
    if (PyBuffer_ToContiguous(PyBytesWriter_GetData(writer),
2404
0
                              src, src->len, 'C') < 0) {
2405
0
        PyBytesWriter_Discard(writer);
2406
0
        return NULL;
2407
0
    }
2408
2409
0
    PyObject *ret = _Py_strhex_with_sep(
2410
0
        PyBytesWriter_GetData(writer),
2411
0
        PyBytesWriter_GetSize(writer),
2412
0
        sep, bytes_per_sep);
2413
0
    PyBytesWriter_Discard(writer);
2414
2415
0
    return ret;
2416
0
}
2417
2418
static PyObject *
2419
memory_repr(PyObject *_self)
2420
0
{
2421
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
2422
0
    if (self->flags & _Py_MEMORYVIEW_RELEASED)
2423
0
        return PyUnicode_FromFormat("<released memory at %p>", self);
2424
0
    else
2425
0
        return PyUnicode_FromFormat("<memory at %p>", self);
2426
0
}
2427
2428
2429
/**************************************************************************/
2430
/*                          Indexing and slicing                          */
2431
/**************************************************************************/
2432
2433
static char *
2434
lookup_dimension(const Py_buffer *view, char *ptr, int dim, Py_ssize_t index)
2435
0
{
2436
0
    Py_ssize_t nitems; /* items in the given dimension */
2437
2438
0
    assert(view->shape);
2439
0
    assert(view->strides);
2440
2441
0
    nitems = view->shape[dim];
2442
0
    if (index < 0) {
2443
0
        index += nitems;
2444
0
    }
2445
0
    if (index < 0 || index >= nitems) {
2446
0
        PyErr_Format(PyExc_IndexError,
2447
0
                     "index out of bounds on dimension %d", dim + 1);
2448
0
        return NULL;
2449
0
    }
2450
2451
0
    ptr += view->strides[dim] * index;
2452
2453
0
    ptr = ADJUST_PTR(ptr, view->suboffsets, dim);
2454
2455
0
    return ptr;
2456
0
}
2457
2458
/* Get the pointer to the item at index. */
2459
static char *
2460
ptr_from_index(const Py_buffer *view, Py_ssize_t index)
2461
0
{
2462
0
    char *ptr = (char *)view->buf;
2463
0
    return lookup_dimension(view, ptr, 0, index);
2464
0
}
2465
2466
/* Get the pointer to the item at tuple. */
2467
static char *
2468
ptr_from_tuple(const Py_buffer *view, PyObject *tup)
2469
0
{
2470
0
    char *ptr = (char *)view->buf;
2471
0
    Py_ssize_t dim, nindices = PyTuple_GET_SIZE(tup);
2472
2473
0
    if (nindices > view->ndim) {
2474
0
        PyErr_Format(PyExc_TypeError,
2475
0
                     "cannot index %d-dimension view with %zd-element tuple",
2476
0
                     view->ndim, nindices);
2477
0
        return NULL;
2478
0
    }
2479
2480
0
    for (dim = 0; dim < nindices; dim++) {
2481
0
        Py_ssize_t index;
2482
0
        index = PyNumber_AsSsize_t(PyTuple_GET_ITEM(tup, dim),
2483
0
                                   PyExc_IndexError);
2484
0
        if (index == -1 && PyErr_Occurred())
2485
0
            return NULL;
2486
0
        ptr = lookup_dimension(view, ptr, (int)dim, index);
2487
0
        if (ptr == NULL)
2488
0
            return NULL;
2489
0
    }
2490
0
    return ptr;
2491
0
}
2492
2493
/* Return the item at index. In a one-dimensional view, this is an object
2494
   with the type specified by view->format. Otherwise, the item is a sub-view.
2495
   The function is used in memory_subscript() and memory_as_sequence. */
2496
static PyObject *
2497
memory_item(PyObject *_self, Py_ssize_t index)
2498
0
{
2499
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
2500
0
    Py_buffer *view = &(self->view);
2501
0
    const char *fmt;
2502
2503
0
    CHECK_RELEASED(self);
2504
2505
0
    fmt = adjust_fmt(view);
2506
0
    if (fmt == NULL)
2507
0
        return NULL;
2508
2509
0
    if (view->ndim == 0) {
2510
0
        PyErr_SetString(PyExc_TypeError, "invalid indexing of 0-dim memory");
2511
0
        return NULL;
2512
0
    }
2513
0
    if (view->ndim == 1) {
2514
0
        char *ptr = ptr_from_index(view, index);
2515
0
        if (ptr == NULL)
2516
0
            return NULL;
2517
0
        return unpack_single(self, ptr, fmt);
2518
0
    }
2519
2520
0
    PyErr_SetString(PyExc_NotImplementedError,
2521
0
        "multi-dimensional sub-views are not implemented");
2522
0
    return NULL;
2523
0
}
2524
2525
/* Return the item at position *key* (a tuple of indices). */
2526
static PyObject *
2527
memory_item_multi(PyMemoryViewObject *self, PyObject *tup)
2528
0
{
2529
0
    Py_buffer *view = &(self->view);
2530
0
    const char *fmt;
2531
0
    Py_ssize_t nindices = PyTuple_GET_SIZE(tup);
2532
0
    char *ptr;
2533
2534
0
    CHECK_RELEASED(self);
2535
2536
0
    fmt = adjust_fmt(view);
2537
0
    if (fmt == NULL)
2538
0
        return NULL;
2539
2540
0
    if (nindices < view->ndim) {
2541
0
        PyErr_SetString(PyExc_NotImplementedError,
2542
0
                        "sub-views are not implemented");
2543
0
        return NULL;
2544
0
    }
2545
0
    ptr = ptr_from_tuple(view, tup);
2546
0
    if (ptr == NULL)
2547
0
        return NULL;
2548
0
    return unpack_single(self, ptr, fmt);
2549
0
}
2550
2551
static inline int
2552
init_slice(Py_buffer *base, PyObject *key, int dim)
2553
1.46k
{
2554
1.46k
    Py_ssize_t start, stop, step, slicelength;
2555
2556
1.46k
    if (PySlice_Unpack(key, &start, &stop, &step) < 0) {
2557
0
        return -1;
2558
0
    }
2559
1.46k
    slicelength = PySlice_AdjustIndices(base->shape[dim], &start, &stop, step);
2560
2561
2562
1.46k
    if (base->suboffsets == NULL || dim == 0) {
2563
1.46k
    adjust_buf:
2564
1.46k
        base->buf = (char *)base->buf + base->strides[dim] * start;
2565
1.46k
    }
2566
0
    else {
2567
0
        Py_ssize_t n = dim-1;
2568
0
        while (n >= 0 && base->suboffsets[n] < 0)
2569
0
            n--;
2570
0
        if (n < 0)
2571
0
            goto adjust_buf; /* all suboffsets are negative */
2572
0
        base->suboffsets[n] = base->suboffsets[n] + base->strides[dim] * start;
2573
0
    }
2574
1.46k
    base->shape[dim] = slicelength;
2575
1.46k
    base->strides[dim] = base->strides[dim] * step;
2576
2577
1.46k
    return 0;
2578
1.46k
}
2579
2580
static int
2581
is_multislice(PyObject *key)
2582
0
{
2583
0
    Py_ssize_t size, i;
2584
2585
0
    if (!PyTuple_Check(key))
2586
0
        return 0;
2587
0
    size = PyTuple_GET_SIZE(key);
2588
0
    if (size == 0)
2589
0
        return 0;
2590
2591
0
    for (i = 0; i < size; i++) {
2592
0
        PyObject *x = PyTuple_GET_ITEM(key, i);
2593
0
        if (!PySlice_Check(x))
2594
0
            return 0;
2595
0
    }
2596
0
    return 1;
2597
0
}
2598
2599
static Py_ssize_t
2600
is_multiindex(PyObject *key)
2601
0
{
2602
0
    Py_ssize_t size, i;
2603
2604
0
    if (!PyTuple_Check(key))
2605
0
        return 0;
2606
0
    size = PyTuple_GET_SIZE(key);
2607
0
    for (i = 0; i < size; i++) {
2608
0
        PyObject *x = PyTuple_GET_ITEM(key, i);
2609
0
        if (!_PyIndex_Check(x)) {
2610
0
            return 0;
2611
0
        }
2612
0
    }
2613
0
    return 1;
2614
0
}
2615
2616
/* mv[obj] returns an object holding the data for one element if obj
2617
   fully indexes the memoryview or another memoryview object if it
2618
   does not.
2619
2620
   0-d memoryview objects can be referenced using mv[...] or mv[()]
2621
   but not with anything else. */
2622
static PyObject *
2623
memory_subscript(PyObject *_self, PyObject *key)
2624
1.46k
{
2625
1.46k
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
2626
1.46k
    Py_buffer *view;
2627
1.46k
    view = &(self->view);
2628
2629
1.46k
    CHECK_RELEASED(self);
2630
2631
1.46k
    if (view->ndim == 0) {
2632
0
        if (PyTuple_Check(key) && PyTuple_GET_SIZE(key) == 0) {
2633
0
            const char *fmt = adjust_fmt(view);
2634
0
            if (fmt == NULL)
2635
0
                return NULL;
2636
0
            return unpack_single(self, view->buf, fmt);
2637
0
        }
2638
0
        else if (key == Py_Ellipsis) {
2639
0
            return Py_NewRef(self);
2640
0
        }
2641
0
        else {
2642
0
            PyErr_SetString(PyExc_TypeError,
2643
0
                "invalid indexing of 0-dim memory");
2644
0
            return NULL;
2645
0
        }
2646
0
    }
2647
2648
1.46k
    if (_PyIndex_Check(key)) {
2649
0
        Py_ssize_t index;
2650
0
        index = PyNumber_AsSsize_t(key, PyExc_IndexError);
2651
0
        if (index == -1 && PyErr_Occurred())
2652
0
            return NULL;
2653
0
        return memory_item((PyObject *)self, index);
2654
0
    }
2655
1.46k
    else if (PySlice_Check(key)) {
2656
1.46k
        CHECK_RESTRICTED(self);
2657
1.46k
        PyMemoryViewObject *sliced;
2658
2659
1.46k
        sliced = (PyMemoryViewObject *)mbuf_add_view(self->mbuf, view);
2660
1.46k
        if (sliced == NULL)
2661
0
            return NULL;
2662
2663
1.46k
        if (init_slice(&sliced->view, key, 0) < 0) {
2664
0
            Py_DECREF(sliced);
2665
0
            return NULL;
2666
0
        }
2667
1.46k
        init_len(&sliced->view);
2668
1.46k
        init_flags(sliced);
2669
2670
1.46k
        return (PyObject *)sliced;
2671
1.46k
    }
2672
0
    else if (is_multiindex(key)) {
2673
0
        return memory_item_multi(self, key);
2674
0
    }
2675
0
    else if (is_multislice(key)) {
2676
0
        PyErr_SetString(PyExc_NotImplementedError,
2677
0
            "multi-dimensional slicing is not implemented");
2678
0
        return NULL;
2679
0
    }
2680
2681
0
    PyErr_SetString(PyExc_TypeError, "memoryview: invalid slice key");
2682
0
    return NULL;
2683
1.46k
}
2684
2685
static int
2686
memory_ass_sub(PyObject *_self, PyObject *key, PyObject *value)
2687
0
{
2688
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
2689
0
    Py_buffer *view = &(self->view);
2690
0
    Py_buffer src;
2691
0
    const char *fmt;
2692
0
    char *ptr;
2693
2694
0
    CHECK_RELEASED_INT(self);
2695
2696
0
    fmt = adjust_fmt(view);
2697
0
    if (fmt == NULL)
2698
0
        return -1;
2699
2700
0
    if (view->readonly) {
2701
0
        PyErr_SetString(PyExc_TypeError, "cannot modify read-only memory");
2702
0
        return -1;
2703
0
    }
2704
0
    if (value == NULL) {
2705
0
        PyErr_SetString(PyExc_TypeError, "cannot delete memory");
2706
0
        return -1;
2707
0
    }
2708
0
    if (view->ndim == 0) {
2709
0
        if (key == Py_Ellipsis ||
2710
0
            (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
2711
0
            ptr = (char *)view->buf;
2712
0
            return pack_single(self, ptr, value, fmt);
2713
0
        }
2714
0
        else {
2715
0
            PyErr_SetString(PyExc_TypeError,
2716
0
                "invalid indexing of 0-dim memory");
2717
0
            return -1;
2718
0
        }
2719
0
    }
2720
2721
0
    if (_PyIndex_Check(key)) {
2722
0
        Py_ssize_t index;
2723
0
        if (1 < view->ndim) {
2724
0
            PyErr_SetString(PyExc_NotImplementedError,
2725
0
                            "sub-views are not implemented");
2726
0
            return -1;
2727
0
        }
2728
0
        index = PyNumber_AsSsize_t(key, PyExc_IndexError);
2729
0
        if (index == -1 && PyErr_Occurred())
2730
0
            return -1;
2731
0
        ptr = ptr_from_index(view, index);
2732
0
        if (ptr == NULL)
2733
0
            return -1;
2734
0
        return pack_single(self, ptr, value, fmt);
2735
0
    }
2736
    /* one-dimensional: fast path */
2737
0
    if (PySlice_Check(key) && view->ndim == 1) {
2738
0
        Py_buffer dest; /* sliced view */
2739
0
        Py_ssize_t arrays[3];
2740
0
        int ret = -1;
2741
2742
        /* rvalue must be an exporter */
2743
0
        if (PyObject_GetBuffer(value, &src, PyBUF_FULL_RO) < 0)
2744
0
            return ret;
2745
2746
0
        dest = *view;
2747
0
        dest.shape = &arrays[0]; dest.shape[0] = view->shape[0];
2748
0
        dest.strides = &arrays[1]; dest.strides[0] = view->strides[0];
2749
0
        if (view->suboffsets) {
2750
0
            dest.suboffsets = &arrays[2]; dest.suboffsets[0] = view->suboffsets[0];
2751
0
        }
2752
2753
0
        if (init_slice(&dest, key, 0) < 0)
2754
0
            goto end_block;
2755
0
        dest.len = dest.shape[0] * dest.itemsize;
2756
2757
0
        ret = copy_single(self, &dest, &src);
2758
2759
0
    end_block:
2760
0
        PyBuffer_Release(&src);
2761
0
        return ret;
2762
0
    }
2763
0
    if (is_multiindex(key)) {
2764
0
        char *ptr;
2765
0
        if (PyTuple_GET_SIZE(key) < view->ndim) {
2766
0
            PyErr_SetString(PyExc_NotImplementedError,
2767
0
                            "sub-views are not implemented");
2768
0
            return -1;
2769
0
        }
2770
0
        ptr = ptr_from_tuple(view, key);
2771
0
        if (ptr == NULL)
2772
0
            return -1;
2773
0
        return pack_single(self, ptr, value, fmt);
2774
0
    }
2775
0
    if (PySlice_Check(key) || is_multislice(key)) {
2776
        /* Call memory_subscript() to produce a sliced lvalue, then copy
2777
           rvalue into lvalue. This is already implemented in _testbuffer.c. */
2778
0
        PyErr_SetString(PyExc_NotImplementedError,
2779
0
            "memoryview slice assignments are currently restricted "
2780
0
            "to ndim = 1");
2781
0
        return -1;
2782
0
    }
2783
2784
0
    PyErr_SetString(PyExc_TypeError, "memoryview: invalid slice key");
2785
0
    return -1;
2786
0
}
2787
2788
static Py_ssize_t
2789
memory_length(PyObject *_self)
2790
1.82k
{
2791
1.82k
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
2792
1.82k
    CHECK_RELEASED_INT(self);
2793
1.82k
    if (self->view.ndim == 0) {
2794
0
        PyErr_SetString(PyExc_TypeError, "0-dim memory has no length");
2795
0
        return -1;
2796
0
    }
2797
1.82k
    return self->view.shape[0];
2798
1.82k
}
2799
2800
/* As mapping */
2801
static PyMappingMethods memory_as_mapping = {
2802
    memory_length,                        /* mp_length */
2803
    memory_subscript,                     /* mp_subscript */
2804
    memory_ass_sub,                       /* mp_ass_subscript */
2805
};
2806
2807
/* As sequence */
2808
static PySequenceMethods memory_as_sequence = {
2809
        memory_length,                    /* sq_length */
2810
        0,                                /* sq_concat */
2811
        0,                                /* sq_repeat */
2812
        memory_item,                      /* sq_item */
2813
};
2814
2815
2816
/****************************************************************************/
2817
/*                              Counting                                    */
2818
/****************************************************************************/
2819
2820
/*[clinic input]
2821
memoryview.count
2822
2823
    value: object
2824
    /
2825
2826
Count the number of occurrences of a value.
2827
[clinic start generated code]*/
2828
2829
static PyObject *
2830
memoryview_count_impl(PyMemoryViewObject *self, PyObject *value)
2831
/*[clinic end generated code: output=a15cb19311985063 input=e3036ce1ed7d1823]*/
2832
0
{
2833
0
    PyObject *iter = PyObject_GetIter(_PyObject_CAST(self));
2834
0
    if (iter == NULL) {
2835
0
        return NULL;
2836
0
    }
2837
2838
0
    Py_ssize_t count = 0;
2839
0
    PyObject *item = NULL;
2840
0
    while (PyIter_NextItem(iter, &item)) {
2841
0
        if (item == NULL) {
2842
0
            Py_DECREF(iter);
2843
0
            return NULL;
2844
0
        }
2845
0
        if (item == value) {
2846
0
            Py_DECREF(item);
2847
0
            count++;  // no overflow since count <= len(mv) <= PY_SSIZE_T_MAX
2848
0
            continue;
2849
0
        }
2850
0
        int contained = PyObject_RichCompareBool(item, value, Py_EQ);
2851
0
        Py_DECREF(item);
2852
0
        if (contained > 0) { // more likely than 'contained < 0'
2853
0
            count++;  // no overflow since count <= len(mv) <= PY_SSIZE_T_MAX
2854
0
        }
2855
0
        else if (contained < 0) {
2856
0
            Py_DECREF(iter);
2857
0
            return NULL;
2858
0
        }
2859
0
    }
2860
0
    Py_DECREF(iter);
2861
0
    return PyLong_FromSsize_t(count);
2862
0
}
2863
2864
2865
/**************************************************************************/
2866
/*                             Lookup                                     */
2867
/**************************************************************************/
2868
2869
/*[clinic input]
2870
memoryview.index
2871
2872
    value: object
2873
    start: slice_index(accept={int}) = 0
2874
    stop: slice_index(accept={int}, c_default="PY_SSIZE_T_MAX") = sys.maxsize
2875
    /
2876
2877
Return the index of the first occurrence of a value.
2878
2879
Raises ValueError if the value is not present.
2880
[clinic start generated code]*/
2881
2882
static PyObject *
2883
memoryview_index_impl(PyMemoryViewObject *self, PyObject *value,
2884
                      Py_ssize_t start, Py_ssize_t stop)
2885
/*[clinic end generated code: output=e0185e3819e549df input=0697a0165bf90b5a]*/
2886
0
{
2887
0
    const Py_buffer *view = &self->view;
2888
0
    CHECK_RELEASED(self);
2889
2890
0
    if (view->ndim == 0) {
2891
0
        PyErr_SetString(PyExc_TypeError, "invalid lookup on 0-dim memory");
2892
0
        return NULL;
2893
0
    }
2894
2895
0
    if (view->ndim == 1) {
2896
0
        Py_ssize_t n = view->shape[0];
2897
2898
0
        if (start < 0) {
2899
0
            start = Py_MAX(start + n, 0);
2900
0
        }
2901
2902
0
        if (stop < 0) {
2903
0
            stop = Py_MAX(stop + n, 0);
2904
0
        }
2905
2906
0
        stop = Py_MIN(stop, n);
2907
0
        assert(stop >= 0);
2908
0
        assert(stop <= n);
2909
2910
0
        start = Py_MIN(start, stop);
2911
0
        assert(0 <= start);
2912
0
        assert(start <= stop);
2913
2914
0
        PyObject *obj = _PyObject_CAST(self);
2915
0
        for (Py_ssize_t index = start; index < stop; index++) {
2916
            // Note: while memoryviews can be mutated during iterations
2917
            // when calling the == operator, their shape cannot. As such,
2918
            // it is safe to assume that the index remains valid for the
2919
            // entire loop.
2920
0
            assert(index < n);
2921
2922
0
            PyObject *item = memory_item(obj, index);
2923
0
            if (item == NULL) {
2924
0
                return NULL;
2925
0
            }
2926
0
            if (item == value) {
2927
0
                Py_DECREF(item);
2928
0
                return PyLong_FromSsize_t(index);
2929
0
            }
2930
0
            int contained = PyObject_RichCompareBool(item, value, Py_EQ);
2931
0
            Py_DECREF(item);
2932
0
            if (contained > 0) {  // more likely than 'contained < 0'
2933
0
                return PyLong_FromSsize_t(index);
2934
0
            }
2935
0
            else if (contained < 0) {
2936
0
                return NULL;
2937
0
            }
2938
0
        }
2939
2940
0
        PyErr_SetString(PyExc_ValueError, "memoryview.index(x): x not found");
2941
0
        return NULL;
2942
0
    }
2943
2944
0
    PyErr_SetString(PyExc_NotImplementedError,
2945
0
                    "multi-dimensional lookup is not implemented");
2946
0
    return NULL;
2947
2948
0
}
2949
2950
2951
/**************************************************************************/
2952
/*                             Comparisons                                */
2953
/**************************************************************************/
2954
2955
0
#define MV_COMPARE_EX -1       /* exception */
2956
565
#define MV_COMPARE_NOT_IMPL -2 /* not implemented */
2957
2958
/* Translate a StructError to "not equal". Preserve other exceptions. */
2959
static int
2960
fix_struct_error_int(void)
2961
0
{
2962
0
    assert(PyErr_Occurred());
2963
    /* XXX Cannot get at StructError directly? */
2964
0
    if (PyErr_ExceptionMatches(PyExc_ImportError) ||
2965
0
        PyErr_ExceptionMatches(PyExc_MemoryError)) {
2966
0
        return MV_COMPARE_EX;
2967
0
    }
2968
    /* StructError: invalid or unknown format -> not equal */
2969
0
    PyErr_Clear();
2970
0
    return 0;
2971
0
}
2972
2973
/* Unpack and compare single items of p and q using the struct module. */
2974
static int
2975
struct_unpack_cmp(const char *p, const char *q,
2976
                  struct unpacker *unpack_p, struct unpacker *unpack_q)
2977
0
{
2978
0
    PyObject *v, *w;
2979
0
    int ret;
2980
2981
    /* At this point any exception from the struct module should not be
2982
       StructError, since both formats have been accepted already. */
2983
0
    v = struct_unpack_single(p, unpack_p);
2984
0
    if (v == NULL)
2985
0
        return MV_COMPARE_EX;
2986
2987
0
    w = struct_unpack_single(q, unpack_q);
2988
0
    if (w == NULL) {
2989
0
        Py_DECREF(v);
2990
0
        return MV_COMPARE_EX;
2991
0
    }
2992
2993
    /* MV_COMPARE_EX == -1: exceptions are preserved */
2994
0
    ret = PyObject_RichCompareBool(v, w, Py_EQ);
2995
0
    Py_DECREF(v);
2996
0
    Py_DECREF(w);
2997
2998
0
    return ret;
2999
0
}
3000
3001
/* Unpack and compare single items of p and q. If both p and q have the same
3002
   single element native format, the comparison uses a fast path (gcc creates
3003
   a jump table and converts memcpy into simple assignments on x86/x64).
3004
3005
   Otherwise, the comparison is delegated to the struct module, which is
3006
   30-60x slower. */
3007
#define CMP_SINGLE(p, q, type) \
3008
0
    do {                                 \
3009
0
        type x;                          \
3010
0
        type y;                          \
3011
0
        memcpy((char *)&x, p, sizeof x); \
3012
0
        memcpy((char *)&y, q, sizeof y); \
3013
0
        equal = (x == y);                \
3014
0
    } while (0)
3015
3016
static inline int
3017
unpack_cmp(const char *p, const char *q, char fmt,
3018
           struct unpacker *unpack_p, struct unpacker *unpack_q)
3019
1.69k
{
3020
1.69k
    int equal;
3021
3022
1.69k
    switch (fmt) {
3023
3024
    /* signed integers and fast path for 'B' */
3025
1.69k
    case 'B': return *((const unsigned char *)p) == *((const unsigned char *)q);
3026
0
    case 'b': return *((const signed char *)p) == *((const signed char *)q);
3027
0
    case 'h': CMP_SINGLE(p, q, short); return equal;
3028
0
    case 'i': CMP_SINGLE(p, q, int); return equal;
3029
0
    case 'l': CMP_SINGLE(p, q, long); return equal;
3030
3031
    /* boolean */
3032
0
    case '?': CMP_SINGLE(p, q, _Bool); return equal;
3033
3034
    /* unsigned integers */
3035
0
    case 'H': CMP_SINGLE(p, q, unsigned short); return equal;
3036
0
    case 'I': CMP_SINGLE(p, q, unsigned int); return equal;
3037
0
    case 'L': CMP_SINGLE(p, q, unsigned long); return equal;
3038
3039
    /* native 64-bit */
3040
0
    case 'q': CMP_SINGLE(p, q, long long); return equal;
3041
0
    case 'Q': CMP_SINGLE(p, q, unsigned long long); return equal;
3042
3043
    /* ssize_t and size_t */
3044
0
    case 'n': CMP_SINGLE(p, q, Py_ssize_t); return equal;
3045
0
    case 'N': CMP_SINGLE(p, q, size_t); return equal;
3046
3047
    /* floats */
3048
    /* XXX DBL_EPSILON? */
3049
0
    case 'f': CMP_SINGLE(p, q, float); return equal;
3050
0
    case 'd': CMP_SINGLE(p, q, double); return equal;
3051
0
    case 'e': {
3052
0
#if PY_LITTLE_ENDIAN
3053
0
        int endian = 1;
3054
#else
3055
        int endian = 0;
3056
#endif
3057
        /* Note: PyFloat_Unpack2 should never fail */
3058
0
        double u = PyFloat_Unpack2(p, endian);
3059
0
        double v = PyFloat_Unpack2(q, endian);
3060
0
        return (u == v);
3061
0
    }
3062
3063
    /* complexes */
3064
0
    case 'F':
3065
0
    {
3066
0
         float x[2], y[2];
3067
3068
0
         memcpy(&x, p, sizeof(x));
3069
0
         memcpy(&y, q, sizeof(y));
3070
0
         return (x[0] == y[0]) && (x[1] == y[1]);
3071
0
    }
3072
0
    case 'D':
3073
0
    {
3074
0
         double x[2], y[2];
3075
3076
0
         memcpy(&x, p, sizeof(x));
3077
0
         memcpy(&y, q, sizeof(y));
3078
0
         return (x[0] == y[0]) && (x[1] == y[1]);
3079
0
    }
3080
3081
    /* bytes object */
3082
0
    case 'c': return *p == *q;
3083
3084
    /* pointer */
3085
0
    case 'P': CMP_SINGLE(p, q, void *); return equal;
3086
3087
    /* use the struct module */
3088
0
    case '_':
3089
0
        assert(unpack_p);
3090
0
        assert(unpack_q);
3091
0
        return struct_unpack_cmp(p, q, unpack_p, unpack_q);
3092
1.69k
    }
3093
3094
    /* NOT REACHED */
3095
0
    PyErr_SetString(PyExc_RuntimeError,
3096
0
        "memoryview: internal error in richcompare");
3097
0
    return MV_COMPARE_EX;
3098
1.69k
}
3099
3100
/* Base case for recursive array comparisons. Assumption: ndim == 1. */
3101
static int
3102
cmp_base(const char *p, const char *q, const Py_ssize_t *shape,
3103
         const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
3104
         const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
3105
         char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
3106
565
{
3107
565
    Py_ssize_t i;
3108
565
    int equal;
3109
3110
2.26k
    for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) {
3111
1.69k
        const char *xp = ADJUST_PTR(p, psuboffsets, 0);
3112
1.69k
        const char *xq = ADJUST_PTR(q, qsuboffsets, 0);
3113
1.69k
        equal = unpack_cmp(xp, xq, fmt, unpack_p, unpack_q);
3114
1.69k
        if (equal <= 0)
3115
0
            return equal;
3116
1.69k
    }
3117
3118
565
    return 1;
3119
565
}
3120
3121
/* Recursively compare two multi-dimensional arrays that have the same
3122
   logical structure. Assumption: ndim >= 1. */
3123
static int
3124
cmp_rec(const char *p, const char *q,
3125
        Py_ssize_t ndim, const Py_ssize_t *shape,
3126
        const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
3127
        const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
3128
        char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
3129
0
{
3130
0
    Py_ssize_t i;
3131
0
    int equal;
3132
3133
0
    assert(ndim >= 1);
3134
0
    assert(shape != NULL);
3135
0
    assert(pstrides != NULL);
3136
0
    assert(qstrides != NULL);
3137
3138
0
    if (ndim == 1) {
3139
0
        return cmp_base(p, q, shape,
3140
0
                        pstrides, psuboffsets,
3141
0
                        qstrides, qsuboffsets,
3142
0
                        fmt, unpack_p, unpack_q);
3143
0
    }
3144
3145
0
    for (i = 0; i < shape[0]; p+=pstrides[0], q+=qstrides[0], i++) {
3146
0
        const char *xp = ADJUST_PTR(p, psuboffsets, 0);
3147
0
        const char *xq = ADJUST_PTR(q, qsuboffsets, 0);
3148
0
        equal = cmp_rec(xp, xq, ndim-1, shape+1,
3149
0
                        pstrides+1, psuboffsets ? psuboffsets+1 : NULL,
3150
0
                        qstrides+1, qsuboffsets ? qsuboffsets+1 : NULL,
3151
0
                        fmt, unpack_p, unpack_q);
3152
0
        if (equal <= 0)
3153
0
            return equal;
3154
0
    }
3155
3156
0
    return 1;
3157
0
}
3158
3159
static PyObject *
3160
memory_richcompare(PyObject *v, PyObject *w, int op)
3161
565
{
3162
565
    PyObject *res;
3163
565
    Py_buffer wbuf, *vv;
3164
565
    Py_buffer *ww = NULL;
3165
565
    struct unpacker *unpack_v = NULL;
3166
565
    struct unpacker *unpack_w = NULL;
3167
565
    char vfmt, wfmt;
3168
565
    int equal = MV_COMPARE_NOT_IMPL;
3169
3170
565
    if (op != Py_EQ && op != Py_NE)
3171
0
        goto result; /* Py_NotImplemented */
3172
3173
565
    assert(PyMemoryView_Check(v));
3174
565
    if (BASE_INACCESSIBLE(v)) {
3175
0
        equal = (v == w);
3176
0
        goto result;
3177
0
    }
3178
565
    vv = VIEW_ADDR(v);
3179
3180
    // For formats supported by the struct module a memoryview is equal to
3181
    // itself: there is no need to compare individual values.
3182
    // This is not true for float values since they can be NaN, and NaN
3183
    // is not equal to itself.  So only use this optimization on format known to
3184
    // not use floats.
3185
565
    if (v == w) {
3186
0
        const char *format = vv->format;
3187
0
        if (format != NULL) {
3188
0
            if (*format == '@') {
3189
0
                format++;
3190
0
            }
3191
            // Include only formats known by struct, exclude float formats
3192
            // "d" (double), "f" (float) and "e" (16-bit float).
3193
            // Do not optimize "P" format.
3194
0
            if (format[0] != 0
3195
0
                && strchr("bBchHiIlLnNqQ?", format[0]) != NULL
3196
0
                && format[1] == 0)
3197
0
            {
3198
0
                equal = 1;
3199
0
                goto result;
3200
0
            }
3201
0
        }
3202
0
    }
3203
3204
565
    if (PyMemoryView_Check(w)) {
3205
0
        if (BASE_INACCESSIBLE(w)) {
3206
0
            equal = (v == w);
3207
0
            goto result;
3208
0
        }
3209
0
        ww = VIEW_ADDR(w);
3210
0
    }
3211
565
    else {
3212
565
        if (PyObject_GetBuffer(w, &wbuf, PyBUF_FULL_RO) < 0) {
3213
0
            PyErr_Clear();
3214
0
            goto result; /* Py_NotImplemented */
3215
0
        }
3216
565
        ww = &wbuf;
3217
565
    }
3218
3219
565
    if (!equiv_shape(vv, ww)) {
3220
0
        PyErr_Clear();
3221
0
        equal = 0;
3222
0
        goto result;
3223
0
    }
3224
3225
    /* Use fast unpacking for identical primitive C type formats. */
3226
565
    if (get_native_fmtchar(&vfmt, vv->format) < 0)
3227
0
        vfmt = '_';
3228
565
    if (get_native_fmtchar(&wfmt, ww->format) < 0)
3229
0
        wfmt = '_';
3230
565
    if (vfmt == '_' || wfmt == '_' || vfmt != wfmt) {
3231
        /* Use struct module unpacking. NOTE: Even for equal format strings,
3232
           memcmp() cannot be used for item comparison since it would give
3233
           incorrect results in the case of NaNs or uninitialized padding
3234
           bytes. */
3235
0
        vfmt = '_';
3236
0
        unpack_v = struct_get_unpacker(vv->format, vv->itemsize);
3237
0
        if (unpack_v == NULL) {
3238
0
            equal = fix_struct_error_int();
3239
0
            goto result;
3240
0
        }
3241
0
        unpack_w = struct_get_unpacker(ww->format, ww->itemsize);
3242
0
        if (unpack_w == NULL) {
3243
0
            equal = fix_struct_error_int();
3244
0
            goto result;
3245
0
        }
3246
0
    }
3247
3248
565
    if (vv->ndim == 0) {
3249
0
        equal = unpack_cmp(vv->buf, ww->buf,
3250
0
                           vfmt, unpack_v, unpack_w);
3251
0
    }
3252
565
    else if (vv->ndim == 1) {
3253
565
        equal = cmp_base(vv->buf, ww->buf, vv->shape,
3254
565
                         vv->strides, vv->suboffsets,
3255
565
                         ww->strides, ww->suboffsets,
3256
565
                         vfmt, unpack_v, unpack_w);
3257
565
    }
3258
0
    else {
3259
0
        equal = cmp_rec(vv->buf, ww->buf, vv->ndim, vv->shape,
3260
0
                        vv->strides, vv->suboffsets,
3261
0
                        ww->strides, ww->suboffsets,
3262
0
                        vfmt, unpack_v, unpack_w);
3263
0
    }
3264
3265
565
result:
3266
565
    if (equal < 0) {
3267
0
        if (equal == MV_COMPARE_NOT_IMPL)
3268
0
            res = Py_NotImplemented;
3269
0
        else /* exception */
3270
0
            res = NULL;
3271
0
    }
3272
565
    else if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
3273
565
        res = Py_True;
3274
0
    else
3275
0
        res = Py_False;
3276
3277
565
    if (ww == &wbuf)
3278
565
        PyBuffer_Release(ww);
3279
3280
565
    unpacker_free(unpack_v);
3281
565
    unpacker_free(unpack_w);
3282
3283
565
    return Py_XNewRef(res);
3284
565
}
3285
3286
/**************************************************************************/
3287
/*                                Hash                                    */
3288
/**************************************************************************/
3289
3290
static Py_hash_t
3291
memory_hash(PyObject *_self)
3292
0
{
3293
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3294
0
    if (self->hash == -1) {
3295
0
        Py_buffer *view = &self->view;
3296
0
        char *mem = view->buf;
3297
0
        Py_ssize_t ret;
3298
0
        char fmt;
3299
3300
0
        CHECK_RELEASED_INT(self);
3301
3302
0
        if (!view->readonly) {
3303
0
            PyErr_SetString(PyExc_ValueError,
3304
0
                "cannot hash writable memoryview object");
3305
0
            return -1;
3306
0
        }
3307
0
        ret = get_native_fmtchar(&fmt, view->format);
3308
0
        if (ret < 0 || !IS_BYTE_FORMAT(fmt)) {
3309
0
            PyErr_SetString(PyExc_ValueError,
3310
0
                "memoryview: hashing is restricted to formats 'B', 'b' or 'c'");
3311
0
            return -1;
3312
0
        }
3313
0
        if (view->obj != NULL) {
3314
            // Prevent 'self' from being freed when computing the item's hash.
3315
            // See https://github.com/python/cpython/issues/142664.
3316
0
            self->exports++;
3317
0
            Py_hash_t h = PyObject_Hash(view->obj);
3318
0
            self->exports--;
3319
0
            if (h == -1) {
3320
                /* Keep the original error message */
3321
0
                return -1;
3322
0
            }
3323
0
        }
3324
3325
0
        if (!MV_C_CONTIGUOUS(self->flags)) {
3326
0
            mem = PyMem_Malloc(view->len);
3327
0
            if (mem == NULL) {
3328
0
                PyErr_NoMemory();
3329
0
                return -1;
3330
0
            }
3331
0
            if (buffer_to_contiguous(mem, view, 'C') < 0) {
3332
0
                PyMem_Free(mem);
3333
0
                return -1;
3334
0
            }
3335
0
        }
3336
3337
        /* Can't fail */
3338
0
        self->hash = Py_HashBuffer(mem, view->len);
3339
3340
0
        if (mem != view->buf)
3341
0
            PyMem_Free(mem);
3342
0
    }
3343
3344
0
    return self->hash;
3345
0
}
3346
3347
3348
/**************************************************************************/
3349
/*                                 getters                                */
3350
/**************************************************************************/
3351
3352
static PyObject *
3353
_IntTupleFromSsizet(int len, Py_ssize_t *vals)
3354
0
{
3355
0
    int i;
3356
0
    PyObject *o;
3357
0
    PyObject *intTuple;
3358
3359
0
    if (vals == NULL)
3360
0
        return PyTuple_New(0);
3361
3362
0
    intTuple = PyTuple_New(len);
3363
0
    if (!intTuple)
3364
0
        return NULL;
3365
0
    for (i=0; i<len; i++) {
3366
0
        o = PyLong_FromSsize_t(vals[i]);
3367
0
        if (!o) {
3368
0
            Py_DECREF(intTuple);
3369
0
            return NULL;
3370
0
        }
3371
0
        PyTuple_SET_ITEM(intTuple, i, o);
3372
0
    }
3373
0
    return intTuple;
3374
0
}
3375
3376
static PyObject *
3377
memory_obj_get(PyObject *_self, void *Py_UNUSED(ignored))
3378
0
{
3379
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3380
0
    Py_buffer *view = &self->view;
3381
3382
0
    CHECK_RELEASED(self);
3383
0
    if (view->obj == NULL) {
3384
0
        Py_RETURN_NONE;
3385
0
    }
3386
0
    return Py_NewRef(view->obj);
3387
0
}
3388
3389
static PyObject *
3390
memory_nbytes_get(PyObject *_self, void *Py_UNUSED(ignored))
3391
0
{
3392
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3393
0
    CHECK_RELEASED(self);
3394
0
    return PyLong_FromSsize_t(self->view.len);
3395
0
}
3396
3397
static PyObject *
3398
memory_format_get(PyObject *_self, void *Py_UNUSED(ignored))
3399
0
{
3400
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3401
0
    CHECK_RELEASED(self);
3402
0
    return PyUnicode_FromString(self->view.format);
3403
0
}
3404
3405
static PyObject *
3406
memory_itemsize_get(PyObject *_self, void *Py_UNUSED(ignored))
3407
4
{
3408
4
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3409
4
    CHECK_RELEASED(self);
3410
4
    return PyLong_FromSsize_t(self->view.itemsize);
3411
4
}
3412
3413
static PyObject *
3414
memory_shape_get(PyObject *_self, void *Py_UNUSED(ignored))
3415
0
{
3416
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3417
0
    CHECK_RELEASED(self);
3418
0
    return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
3419
0
}
3420
3421
static PyObject *
3422
memory_strides_get(PyObject *_self, void *Py_UNUSED(ignored))
3423
0
{
3424
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3425
0
    CHECK_RELEASED(self);
3426
0
    return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
3427
0
}
3428
3429
static PyObject *
3430
memory_suboffsets_get(PyObject *_self, void *Py_UNUSED(ignored))
3431
0
{
3432
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3433
0
    CHECK_RELEASED(self);
3434
0
    return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
3435
0
}
3436
3437
static PyObject *
3438
memory_readonly_get(PyObject *_self, void *Py_UNUSED(ignored))
3439
0
{
3440
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3441
0
    CHECK_RELEASED(self);
3442
0
    return PyBool_FromLong(self->view.readonly);
3443
0
}
3444
3445
static PyObject *
3446
memory_ndim_get(PyObject *_self, void *Py_UNUSED(ignored))
3447
0
{
3448
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3449
0
    CHECK_RELEASED(self);
3450
0
    return PyLong_FromLong(self->view.ndim);
3451
0
}
3452
3453
static PyObject *
3454
memory_c_contiguous(PyObject *_self, void *Py_UNUSED(ignored))
3455
0
{
3456
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3457
0
    CHECK_RELEASED(self);
3458
0
    return PyBool_FromLong(MV_C_CONTIGUOUS(self->flags));
3459
0
}
3460
3461
static PyObject *
3462
memory_f_contiguous(PyObject *_self, void *Py_UNUSED(ignored))
3463
0
{
3464
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3465
0
    CHECK_RELEASED(self);
3466
0
    return PyBool_FromLong(MV_F_CONTIGUOUS(self->flags));
3467
0
}
3468
3469
static PyObject *
3470
memory_contiguous(PyObject *_self, void *Py_UNUSED(ignored))
3471
0
{
3472
0
    PyMemoryViewObject *self = (PyMemoryViewObject *)_self;
3473
0
    CHECK_RELEASED(self);
3474
0
    return PyBool_FromLong(MV_ANY_CONTIGUOUS(self->flags));
3475
0
}
3476
3477
PyDoc_STRVAR(memory_obj_doc,
3478
             "The underlying object of the memoryview.");
3479
PyDoc_STRVAR(memory_nbytes_doc,
3480
             "The amount of space in bytes that the array would use in\n"
3481
             " a contiguous representation.");
3482
PyDoc_STRVAR(memory_readonly_doc,
3483
             "A bool indicating whether the memory is read only.");
3484
PyDoc_STRVAR(memory_itemsize_doc,
3485
             "The size in bytes of each element of the memoryview.");
3486
PyDoc_STRVAR(memory_format_doc,
3487
             "A string containing the format (in struct module style)\n"
3488
             " for each element in the view.");
3489
PyDoc_STRVAR(memory_ndim_doc,
3490
             "An integer indicating how many dimensions of a multi-dimensional\n"
3491
             " array the memory represents.");
3492
PyDoc_STRVAR(memory_shape_doc,
3493
             "A tuple of ndim integers giving the shape of the memory\n"
3494
             " as an N-dimensional array.");
3495
PyDoc_STRVAR(memory_strides_doc,
3496
             "A tuple of ndim integers giving the size in bytes to access\n"
3497
             " each element for each dimension of the array.");
3498
PyDoc_STRVAR(memory_suboffsets_doc,
3499
             "A tuple of integers used internally for PIL-style arrays.");
3500
PyDoc_STRVAR(memory_c_contiguous_doc,
3501
             "A bool indicating whether the memory is C contiguous.");
3502
PyDoc_STRVAR(memory_f_contiguous_doc,
3503
             "A bool indicating whether the memory is Fortran contiguous.");
3504
PyDoc_STRVAR(memory_contiguous_doc,
3505
             "A bool indicating whether the memory is contiguous.");
3506
PyDoc_STRVAR(memory_exit_doc,
3507
             "__exit__($self, /, *exc_info)\n--\n\n"
3508
             "Release the underlying buffer exposed by the memoryview object.");
3509
3510
3511
static PyGetSetDef memory_getsetlist[] = {
3512
    {"obj",             memory_obj_get,        NULL, memory_obj_doc},
3513
    {"nbytes",          memory_nbytes_get,     NULL, memory_nbytes_doc},
3514
    {"readonly",        memory_readonly_get,   NULL, memory_readonly_doc},
3515
    {"itemsize",        memory_itemsize_get,   NULL, memory_itemsize_doc},
3516
    {"format",          memory_format_get,     NULL, memory_format_doc},
3517
    {"ndim",            memory_ndim_get,       NULL, memory_ndim_doc},
3518
    {"shape",           memory_shape_get,      NULL, memory_shape_doc},
3519
    {"strides",         memory_strides_get,    NULL, memory_strides_doc},
3520
    {"suboffsets",      memory_suboffsets_get, NULL, memory_suboffsets_doc},
3521
    {"c_contiguous",    memory_c_contiguous,   NULL, memory_c_contiguous_doc},
3522
    {"f_contiguous",    memory_f_contiguous,   NULL, memory_f_contiguous_doc},
3523
    {"contiguous",      memory_contiguous,     NULL, memory_contiguous_doc},
3524
    {NULL, NULL, NULL, NULL},
3525
};
3526
3527
3528
static PyMethodDef memory_methods[] = {
3529
    MEMORYVIEW_RELEASE_METHODDEF
3530
    MEMORYVIEW_TOBYTES_METHODDEF
3531
    MEMORYVIEW_HEX_METHODDEF
3532
    MEMORYVIEW_TOLIST_METHODDEF
3533
    MEMORYVIEW_CAST_METHODDEF
3534
    MEMORYVIEW_TOREADONLY_METHODDEF
3535
    MEMORYVIEW__FROM_FLAGS_METHODDEF
3536
    MEMORYVIEW_COUNT_METHODDEF
3537
    MEMORYVIEW_INDEX_METHODDEF
3538
    {"__enter__",   memory_enter, METH_NOARGS, NULL},
3539
    {"__exit__",    memory_exit, METH_VARARGS, memory_exit_doc},
3540
    {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
3541
    {NULL,          NULL}
3542
};
3543
3544
/**************************************************************************/
3545
/*                          Memoryview Iterator                           */
3546
/**************************************************************************/
3547
3548
PyTypeObject _PyMemoryIter_Type;
3549
3550
typedef struct {
3551
    PyObject_HEAD
3552
    Py_ssize_t it_index;
3553
    PyMemoryViewObject *it_seq; // Set to NULL when iterator is exhausted
3554
    Py_ssize_t it_length;
3555
    const char *it_fmt;
3556
} memoryiterobject;
3557
3558
static void
3559
memoryiter_dealloc(PyObject *self)
3560
0
{
3561
0
    memoryiterobject *it = (memoryiterobject *)self;
3562
0
    _PyObject_GC_UNTRACK(it);
3563
0
    Py_XDECREF(it->it_seq);
3564
0
    PyObject_GC_Del(it);
3565
0
}
3566
3567
static int
3568
memoryiter_traverse(PyObject *self, visitproc visit, void *arg)
3569
0
{
3570
0
    memoryiterobject *it = (memoryiterobject *)self;
3571
0
    Py_VISIT(it->it_seq);
3572
0
    return 0;
3573
0
}
3574
3575
static PyObject *
3576
memoryiter_next(PyObject *self)
3577
0
{
3578
0
    memoryiterobject *it = (memoryiterobject *)self;
3579
0
    PyMemoryViewObject *seq;
3580
0
    seq = it->it_seq;
3581
0
    if (seq == NULL) {
3582
0
        return NULL;
3583
0
    }
3584
3585
0
    if (it->it_index < it->it_length) {
3586
0
        CHECK_RELEASED(seq);
3587
0
        Py_buffer *view = &(seq->view);
3588
0
        char *ptr = (char *)seq->view.buf;
3589
3590
0
        ptr += view->strides[0] * it->it_index++;
3591
0
        ptr = ADJUST_PTR(ptr, view->suboffsets, 0);
3592
0
        if (ptr == NULL) {
3593
0
            return NULL;
3594
0
        }
3595
0
        return unpack_single(seq, ptr, it->it_fmt);
3596
0
    }
3597
3598
0
    it->it_seq = NULL;
3599
0
    Py_DECREF(seq);
3600
0
    return NULL;
3601
0
}
3602
3603
static PyObject *
3604
memory_iter(PyObject *seq)
3605
0
{
3606
0
    if (!PyMemoryView_Check(seq)) {
3607
0
        PyErr_BadInternalCall();
3608
0
        return NULL;
3609
0
    }
3610
0
    CHECK_RELEASED(seq);
3611
0
    PyMemoryViewObject *obj = (PyMemoryViewObject *)seq;
3612
0
    int ndims = obj->view.ndim;
3613
0
    if (ndims == 0) {
3614
0
        PyErr_SetString(PyExc_TypeError, "invalid indexing of 0-dim memory");
3615
0
        return NULL;
3616
0
    }
3617
0
    if (ndims != 1) {
3618
0
        PyErr_SetString(PyExc_NotImplementedError,
3619
0
            "multi-dimensional sub-views are not implemented");
3620
0
        return NULL;
3621
0
    }
3622
3623
0
    const char *fmt = adjust_fmt(&obj->view);
3624
0
    if (fmt == NULL) {
3625
0
        return NULL;
3626
0
    }
3627
3628
0
    memoryiterobject *it;
3629
0
    it = PyObject_GC_New(memoryiterobject, &_PyMemoryIter_Type);
3630
0
    if (it == NULL) {
3631
0
        return NULL;
3632
0
    }
3633
0
    it->it_fmt = fmt;
3634
0
    it->it_length = memory_length((PyObject *)obj);
3635
0
    it->it_index = 0;
3636
0
    it->it_seq = (PyMemoryViewObject*)Py_NewRef(obj);
3637
0
    _PyObject_GC_TRACK(it);
3638
0
    return (PyObject *)it;
3639
0
}
3640
3641
PyTypeObject _PyMemoryIter_Type = {
3642
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
3643
    .tp_name = "memory_iterator",
3644
    .tp_basicsize = sizeof(memoryiterobject),
3645
    // methods
3646
    .tp_dealloc = memoryiter_dealloc,
3647
    .tp_getattro = PyObject_GenericGetAttr,
3648
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
3649
    .tp_traverse = memoryiter_traverse,
3650
    .tp_iter = PyObject_SelfIter,
3651
    .tp_iternext = memoryiter_next,
3652
};
3653
3654
PyTypeObject PyMemoryView_Type = {
3655
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
3656
    "memoryview",                             /* tp_name */
3657
    offsetof(PyMemoryViewObject, ob_array),   /* tp_basicsize */
3658
    sizeof(Py_ssize_t),                       /* tp_itemsize */
3659
    memory_dealloc,                           /* tp_dealloc */
3660
    0,                                        /* tp_vectorcall_offset */
3661
    0,                                        /* tp_getattr */
3662
    0,                                        /* tp_setattr */
3663
    0,                                        /* tp_as_async */
3664
    memory_repr,                              /* tp_repr */
3665
    0,                                        /* tp_as_number */
3666
    &memory_as_sequence,                      /* tp_as_sequence */
3667
    &memory_as_mapping,                       /* tp_as_mapping */
3668
    memory_hash,                              /* tp_hash */
3669
    0,                                        /* tp_call */
3670
    0,                                        /* tp_str */
3671
    PyObject_GenericGetAttr,                  /* tp_getattro */
3672
    0,                                        /* tp_setattro */
3673
    &memory_as_buffer,                        /* tp_as_buffer */
3674
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
3675
       Py_TPFLAGS_SEQUENCE,                   /* tp_flags */
3676
    memoryview__doc__,                        /* tp_doc */
3677
    memory_traverse,                          /* tp_traverse */
3678
    memory_clear,                             /* tp_clear */
3679
    memory_richcompare,                       /* tp_richcompare */
3680
    offsetof(PyMemoryViewObject, weakreflist),/* tp_weaklistoffset */
3681
    memory_iter,                              /* tp_iter */
3682
    0,                                        /* tp_iternext */
3683
    memory_methods,                           /* tp_methods */
3684
    0,                                        /* tp_members */
3685
    memory_getsetlist,                        /* tp_getset */
3686
    0,                                        /* tp_base */
3687
    0,                                        /* tp_dict */
3688
    0,                                        /* tp_descr_get */
3689
    0,                                        /* tp_descr_set */
3690
    0,                                        /* tp_dictoffset */
3691
    0,                                        /* tp_init */
3692
    0,                                        /* tp_alloc */
3693
    memoryview,                               /* tp_new */
3694
};