Coverage Report

Created: 2026-04-20 06:11

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