Coverage Report

Created: 2026-05-30 06:18

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