Line data Source code
1 :
2 : /* Memoryview object implementation */
3 :
4 : #include "Python.h"
5 :
6 : static Py_ssize_t
7 0 : get_shape0(Py_buffer *buf)
8 : {
9 0 : if (buf->shape != NULL)
10 0 : return buf->shape[0];
11 0 : if (buf->ndim == 0)
12 0 : return 1;
13 0 : PyErr_SetString(PyExc_TypeError,
14 : "exported buffer does not have any shape information associated "
15 : "to it");
16 0 : return -1;
17 : }
18 :
19 : static void
20 0 : dup_buffer(Py_buffer *dest, Py_buffer *src)
21 : {
22 0 : *dest = *src;
23 0 : if (src->ndim == 1 && src->shape != NULL) {
24 0 : dest->shape = &(dest->smalltable[0]);
25 0 : dest->shape[0] = get_shape0(src);
26 : }
27 0 : if (src->ndim == 1 && src->strides != NULL) {
28 0 : dest->strides = &(dest->smalltable[1]);
29 0 : dest->strides[0] = src->strides[0];
30 : }
31 0 : }
32 :
33 : static int
34 0 : memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
35 : {
36 0 : int res = 0;
37 0 : if (self->view.obj != NULL)
38 0 : res = PyObject_GetBuffer(self->view.obj, view, flags);
39 0 : if (view)
40 0 : dup_buffer(view, &self->view);
41 0 : return res;
42 : }
43 :
44 : static void
45 0 : memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
46 : {
47 0 : PyBuffer_Release(view);
48 0 : }
49 :
50 : PyDoc_STRVAR(memory_doc,
51 : "memoryview(object)\n\
52 : \n\
53 : Create a new memoryview object which references the given object.");
54 :
55 : PyObject *
56 0 : PyMemoryView_FromBuffer(Py_buffer *info)
57 : {
58 : PyMemoryViewObject *mview;
59 :
60 0 : mview = (PyMemoryViewObject *)
61 : PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
62 0 : if (mview == NULL)
63 0 : return NULL;
64 0 : mview->base = NULL;
65 0 : dup_buffer(&mview->view, info);
66 : /* NOTE: mview->view.obj should already have been incref'ed as
67 : part of PyBuffer_FillInfo(). */
68 0 : _PyObject_GC_TRACK(mview);
69 0 : return (PyObject *)mview;
70 : }
71 :
72 : PyObject *
73 0 : PyMemoryView_FromObject(PyObject *base)
74 : {
75 : PyMemoryViewObject *mview;
76 : Py_buffer view;
77 :
78 0 : if (!PyObject_CheckBuffer(base)) {
79 0 : PyErr_SetString(PyExc_TypeError,
80 : "cannot make memory view because object does "
81 : "not have the buffer interface");
82 0 : return NULL;
83 : }
84 :
85 0 : if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
86 0 : return NULL;
87 :
88 0 : mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
89 0 : if (mview == NULL) {
90 0 : PyBuffer_Release(&view);
91 0 : return NULL;
92 : }
93 :
94 0 : mview->base = base;
95 0 : Py_INCREF(base);
96 0 : return (PyObject *)mview;
97 : }
98 :
99 : static PyObject *
100 0 : memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
101 : {
102 : PyObject *obj;
103 : static char *kwlist[] = {"object", 0};
104 :
105 0 : if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
106 : &obj)) {
107 0 : return NULL;
108 : }
109 :
110 0 : return PyMemoryView_FromObject(obj);
111 : }
112 :
113 :
114 : static void
115 0 : _strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
116 : Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
117 : {
118 : int k;
119 : Py_ssize_t outstride;
120 :
121 0 : if (nd==0) {
122 0 : memcpy(dest, src, itemsize);
123 : }
124 0 : else if (nd == 1) {
125 0 : for (k = 0; k<shape[0]; k++) {
126 0 : memcpy(dest, src, itemsize);
127 0 : dest += itemsize;
128 0 : src += strides[0];
129 : }
130 : }
131 : else {
132 0 : if (fort == 'F') {
133 : /* Copy first dimension first,
134 : second dimension second, etc...
135 : Set up the recursive loop backwards so that final
136 : dimension is actually copied last.
137 : */
138 0 : outstride = itemsize;
139 0 : for (k=1; k<nd-1;k++) {
140 0 : outstride *= shape[k];
141 : }
142 0 : for (k=0; k<shape[nd-1]; k++) {
143 0 : _strided_copy_nd(dest, src, nd-1, shape,
144 : strides, itemsize, fort);
145 0 : dest += outstride;
146 0 : src += strides[nd-1];
147 : }
148 : }
149 :
150 : else {
151 : /* Copy last dimension first,
152 : second-to-last dimension second, etc.
153 : Set up the recursion so that the
154 : first dimension is copied last
155 : */
156 0 : outstride = itemsize;
157 0 : for (k=1; k < nd; k++) {
158 0 : outstride *= shape[k];
159 : }
160 0 : for (k=0; k<shape[0]; k++) {
161 0 : _strided_copy_nd(dest, src, nd-1, shape+1,
162 : strides+1, itemsize,
163 : fort);
164 0 : dest += outstride;
165 0 : src += strides[0];
166 : }
167 : }
168 : }
169 0 : return;
170 : }
171 :
172 : static int
173 0 : _indirect_copy_nd(char *dest, Py_buffer *view, char fort)
174 : {
175 : Py_ssize_t *indices;
176 : int k;
177 : Py_ssize_t elements;
178 : char *ptr;
179 : void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
180 :
181 0 : if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
182 0 : PyErr_NoMemory();
183 0 : return -1;
184 : }
185 :
186 0 : indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
187 0 : if (indices == NULL) {
188 0 : PyErr_NoMemory();
189 0 : return -1;
190 : }
191 0 : for (k=0; k<view->ndim;k++) {
192 0 : indices[k] = 0;
193 : }
194 :
195 0 : elements = 1;
196 0 : for (k=0; k<view->ndim; k++) {
197 0 : elements *= view->shape[k];
198 : }
199 0 : if (fort == 'F') {
200 0 : func = _Py_add_one_to_index_F;
201 : }
202 : else {
203 0 : func = _Py_add_one_to_index_C;
204 : }
205 0 : while (elements--) {
206 0 : func(view->ndim, indices, view->shape);
207 0 : ptr = PyBuffer_GetPointer(view, indices);
208 0 : memcpy(dest, ptr, view->itemsize);
209 0 : dest += view->itemsize;
210 : }
211 :
212 0 : PyMem_Free(indices);
213 0 : return 0;
214 : }
215 :
216 : /*
217 : Get a the data from an object as a contiguous chunk of memory (in
218 : either 'C' or 'F'ortran order) even if it means copying it into a
219 : separate memory area.
220 :
221 : Returns a new reference to a Memory view object. If no copy is needed,
222 : the memory view object points to the original memory and holds a
223 : lock on the original. If a copy is needed, then the memory view object
224 : points to a brand-new Bytes object (and holds a memory lock on it).
225 :
226 : buffertype
227 :
228 : PyBUF_READ buffer only needs to be read-only
229 : PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
230 : PyBUF_SHADOW buffer needs to be writable so shadow it with
231 : a contiguous buffer if it is not. The view will point to
232 : the shadow buffer which can be written to and then
233 : will be copied back into the other buffer when the memory
234 : view is de-allocated. While the shadow buffer is
235 : being used, it will have an exclusive write lock on
236 : the original buffer.
237 : */
238 :
239 : PyObject *
240 0 : PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
241 : {
242 : PyMemoryViewObject *mem;
243 : PyObject *bytes;
244 : Py_buffer *view;
245 : int flags;
246 : char *dest;
247 :
248 0 : if (!PyObject_CheckBuffer(obj)) {
249 0 : PyErr_SetString(PyExc_TypeError,
250 : "object does not have the buffer interface");
251 0 : return NULL;
252 : }
253 :
254 0 : mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
255 0 : if (mem == NULL)
256 0 : return NULL;
257 :
258 0 : view = &mem->view;
259 0 : flags = PyBUF_FULL_RO;
260 0 : switch(buffertype) {
261 : case PyBUF_WRITE:
262 0 : flags = PyBUF_FULL;
263 0 : break;
264 : }
265 :
266 0 : if (PyObject_GetBuffer(obj, view, flags) != 0) {
267 0 : Py_DECREF(mem);
268 0 : return NULL;
269 : }
270 :
271 0 : if (PyBuffer_IsContiguous(view, fort)) {
272 : /* no copy needed */
273 0 : Py_INCREF(obj);
274 0 : mem->base = obj;
275 0 : _PyObject_GC_TRACK(mem);
276 0 : return (PyObject *)mem;
277 : }
278 : /* otherwise a copy is needed */
279 0 : if (buffertype == PyBUF_WRITE) {
280 0 : Py_DECREF(mem);
281 0 : PyErr_SetString(PyExc_BufferError,
282 : "writable contiguous buffer requested "
283 : "for a non-contiguousobject.");
284 0 : return NULL;
285 : }
286 0 : bytes = PyBytes_FromStringAndSize(NULL, view->len);
287 0 : if (bytes == NULL) {
288 0 : Py_DECREF(mem);
289 0 : return NULL;
290 : }
291 0 : dest = PyBytes_AS_STRING(bytes);
292 : /* different copying strategy depending on whether
293 : or not any pointer de-referencing is needed
294 : */
295 : /* strided or in-direct copy */
296 0 : if (view->suboffsets==NULL) {
297 0 : _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
298 : view->strides, view->itemsize, fort);
299 : }
300 : else {
301 0 : if (_indirect_copy_nd(dest, view, fort) < 0) {
302 0 : Py_DECREF(bytes);
303 0 : Py_DECREF(mem);
304 0 : return NULL;
305 : }
306 : }
307 0 : if (buffertype == PyBUF_SHADOW) {
308 : /* return a shadowed memory-view object */
309 0 : view->buf = dest;
310 0 : mem->base = PyTuple_Pack(2, obj, bytes);
311 0 : Py_DECREF(bytes);
312 0 : if (mem->base == NULL) {
313 0 : Py_DECREF(mem);
314 0 : return NULL;
315 : }
316 : }
317 : else {
318 0 : PyBuffer_Release(view); /* XXX ? */
319 : /* steal the reference */
320 0 : mem->base = bytes;
321 : }
322 0 : _PyObject_GC_TRACK(mem);
323 0 : return (PyObject *)mem;
324 : }
325 :
326 :
327 : static PyObject *
328 0 : memory_format_get(PyMemoryViewObject *self)
329 : {
330 0 : return PyString_FromString(self->view.format);
331 : }
332 :
333 : static PyObject *
334 0 : memory_itemsize_get(PyMemoryViewObject *self)
335 : {
336 0 : return PyLong_FromSsize_t(self->view.itemsize);
337 : }
338 :
339 : static PyObject *
340 0 : _IntTupleFromSsizet(int len, Py_ssize_t *vals)
341 : {
342 : int i;
343 : PyObject *o;
344 : PyObject *intTuple;
345 :
346 0 : if (vals == NULL) {
347 0 : Py_INCREF(Py_None);
348 0 : return Py_None;
349 : }
350 0 : intTuple = PyTuple_New(len);
351 0 : if (!intTuple) return NULL;
352 0 : for(i=0; i<len; i++) {
353 0 : o = PyLong_FromSsize_t(vals[i]);
354 0 : if (!o) {
355 0 : Py_DECREF(intTuple);
356 0 : return NULL;
357 : }
358 0 : PyTuple_SET_ITEM(intTuple, i, o);
359 : }
360 0 : return intTuple;
361 : }
362 :
363 : static PyObject *
364 0 : memory_shape_get(PyMemoryViewObject *self)
365 : {
366 0 : return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
367 : }
368 :
369 : static PyObject *
370 0 : memory_strides_get(PyMemoryViewObject *self)
371 : {
372 0 : return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
373 : }
374 :
375 : static PyObject *
376 0 : memory_suboffsets_get(PyMemoryViewObject *self)
377 : {
378 0 : return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
379 : }
380 :
381 : static PyObject *
382 0 : memory_readonly_get(PyMemoryViewObject *self)
383 : {
384 0 : return PyBool_FromLong(self->view.readonly);
385 : }
386 :
387 : static PyObject *
388 0 : memory_ndim_get(PyMemoryViewObject *self)
389 : {
390 0 : return PyLong_FromLong(self->view.ndim);
391 : }
392 :
393 : static PyGetSetDef memory_getsetlist[] ={
394 : {"format", (getter)memory_format_get, NULL, NULL},
395 : {"itemsize", (getter)memory_itemsize_get, NULL, NULL},
396 : {"shape", (getter)memory_shape_get, NULL, NULL},
397 : {"strides", (getter)memory_strides_get, NULL, NULL},
398 : {"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
399 : {"readonly", (getter)memory_readonly_get, NULL, NULL},
400 : {"ndim", (getter)memory_ndim_get, NULL, NULL},
401 : {NULL, NULL, NULL, NULL},
402 : };
403 :
404 :
405 : static PyObject *
406 0 : memory_tobytes(PyMemoryViewObject *self, PyObject *noargs)
407 : {
408 : Py_buffer view;
409 : PyObject *res;
410 :
411 0 : if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_SIMPLE) < 0)
412 0 : return NULL;
413 :
414 0 : res = PyBytes_FromStringAndSize(NULL, view.len);
415 0 : PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
416 0 : PyBuffer_Release(&view);
417 0 : return res;
418 : }
419 :
420 : /* TODO: rewrite this function using the struct module to unpack
421 : each buffer item */
422 :
423 : static PyObject *
424 0 : memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
425 : {
426 0 : Py_buffer *view = &(mem->view);
427 : Py_ssize_t i;
428 : PyObject *res, *item;
429 : char *buf;
430 :
431 0 : if (strcmp(view->format, "B") || view->itemsize != 1) {
432 0 : PyErr_SetString(PyExc_NotImplementedError,
433 : "tolist() only supports byte views");
434 0 : return NULL;
435 : }
436 0 : if (view->ndim != 1) {
437 0 : PyErr_SetString(PyExc_NotImplementedError,
438 : "tolist() only supports one-dimensional objects");
439 0 : return NULL;
440 : }
441 0 : res = PyList_New(view->len);
442 0 : if (res == NULL)
443 0 : return NULL;
444 0 : buf = view->buf;
445 0 : for (i = 0; i < view->len; i++) {
446 0 : item = PyInt_FromLong((unsigned char) *buf);
447 0 : if (item == NULL) {
448 0 : Py_DECREF(res);
449 0 : return NULL;
450 : }
451 0 : PyList_SET_ITEM(res, i, item);
452 0 : buf++;
453 : }
454 0 : return res;
455 : }
456 :
457 : static PyMethodDef memory_methods[] = {
458 : {"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
459 : {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
460 : {NULL, NULL} /* sentinel */
461 : };
462 :
463 :
464 : static void
465 0 : memory_dealloc(PyMemoryViewObject *self)
466 : {
467 0 : _PyObject_GC_UNTRACK(self);
468 0 : if (self->view.obj != NULL) {
469 0 : if (self->base && PyTuple_Check(self->base)) {
470 : /* Special case when first element is generic object
471 : with buffer interface and the second element is a
472 : contiguous "shadow" that must be copied back into
473 : the data areay of the first tuple element before
474 : releasing the buffer on the first element.
475 : */
476 :
477 0 : PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
478 0 : PyTuple_GET_ITEM(self->base,1));
479 :
480 : /* The view member should have readonly == -1 in
481 : this instance indicating that the memory can
482 : be "locked" and was locked and will be unlocked
483 : again after this call.
484 : */
485 0 : PyBuffer_Release(&(self->view));
486 : }
487 : else {
488 0 : PyBuffer_Release(&(self->view));
489 : }
490 0 : Py_CLEAR(self->base);
491 : }
492 0 : PyObject_GC_Del(self);
493 0 : }
494 :
495 : static PyObject *
496 0 : memory_repr(PyMemoryViewObject *self)
497 : {
498 0 : return PyString_FromFormat("<memory at %p>", self);
499 : }
500 :
501 : /* Sequence methods */
502 : static Py_ssize_t
503 0 : memory_length(PyMemoryViewObject *self)
504 : {
505 0 : return get_shape0(&self->view);
506 : }
507 :
508 : /* Alternate version of memory_subcript that only accepts indices.
509 : Used by PySeqIter_New().
510 : */
511 : static PyObject *
512 0 : memory_item(PyMemoryViewObject *self, Py_ssize_t result)
513 : {
514 0 : Py_buffer *view = &(self->view);
515 :
516 0 : if (view->ndim == 0) {
517 0 : PyErr_SetString(PyExc_IndexError,
518 : "invalid indexing of 0-dim memory");
519 0 : return NULL;
520 : }
521 0 : if (view->ndim == 1) {
522 : /* Return a bytes object */
523 : char *ptr;
524 0 : ptr = (char *)view->buf;
525 0 : if (result < 0) {
526 0 : result += get_shape0(view);
527 : }
528 0 : if ((result < 0) || (result >= get_shape0(view))) {
529 0 : PyErr_SetString(PyExc_IndexError,
530 : "index out of bounds");
531 0 : return NULL;
532 : }
533 0 : if (view->strides == NULL)
534 0 : ptr += view->itemsize * result;
535 : else
536 0 : ptr += view->strides[0] * result;
537 0 : if (view->suboffsets != NULL &&
538 0 : view->suboffsets[0] >= 0) {
539 0 : ptr = *((char **)ptr) + view->suboffsets[0];
540 : }
541 0 : return PyBytes_FromStringAndSize(ptr, view->itemsize);
542 : } else {
543 : /* Return a new memory-view object */
544 : Py_buffer newview;
545 0 : memset(&newview, 0, sizeof(newview));
546 : /* XXX: This needs to be fixed so it actually returns a sub-view */
547 0 : return PyMemoryView_FromBuffer(&newview);
548 : }
549 : }
550 :
551 : /*
552 : mem[obj] returns a bytes object holding the data for one element if
553 : obj fully indexes the memory view or another memory-view object
554 : if it does not.
555 :
556 : 0-d memory-view objects can be referenced using ... or () but
557 : not with anything else.
558 : */
559 : static PyObject *
560 0 : memory_subscript(PyMemoryViewObject *self, PyObject *key)
561 : {
562 : Py_buffer *view;
563 0 : view = &(self->view);
564 :
565 0 : if (view->ndim == 0) {
566 0 : if (key == Py_Ellipsis ||
567 0 : (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
568 0 : Py_INCREF(self);
569 0 : return (PyObject *)self;
570 : }
571 : else {
572 0 : PyErr_SetString(PyExc_IndexError,
573 : "invalid indexing of 0-dim memory");
574 0 : return NULL;
575 : }
576 : }
577 0 : if (PyIndex_Check(key)) {
578 : Py_ssize_t result;
579 0 : result = PyNumber_AsSsize_t(key, NULL);
580 0 : if (result == -1 && PyErr_Occurred())
581 0 : return NULL;
582 0 : return memory_item(self, result);
583 : }
584 0 : else if (PySlice_Check(key)) {
585 : Py_ssize_t start, stop, step, slicelength;
586 :
587 0 : if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
588 : &start, &stop, &step, &slicelength) < 0) {
589 0 : return NULL;
590 : }
591 :
592 0 : if (step == 1 && view->ndim == 1) {
593 : Py_buffer newview;
594 0 : void *newbuf = (char *) view->buf
595 0 : + start * view->itemsize;
596 0 : int newflags = view->readonly
597 0 : ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
598 :
599 : /* XXX There should be an API to create a subbuffer */
600 0 : if (view->obj != NULL) {
601 0 : if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
602 0 : return NULL;
603 : }
604 : else {
605 0 : newview = *view;
606 : }
607 0 : newview.buf = newbuf;
608 0 : newview.len = slicelength * newview.itemsize;
609 0 : newview.format = view->format;
610 0 : newview.shape = &(newview.smalltable[0]);
611 0 : newview.shape[0] = slicelength;
612 0 : newview.strides = &(newview.itemsize);
613 0 : return PyMemoryView_FromBuffer(&newview);
614 : }
615 0 : PyErr_SetNone(PyExc_NotImplementedError);
616 0 : return NULL;
617 : }
618 0 : PyErr_Format(PyExc_TypeError,
619 : "cannot index memory using \"%.200s\"",
620 0 : key->ob_type->tp_name);
621 0 : return NULL;
622 : }
623 :
624 :
625 : /* Need to support assigning memory if we can */
626 : static int
627 0 : memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
628 : {
629 : Py_ssize_t start, len, bytelen;
630 : Py_buffer srcview;
631 0 : Py_buffer *view = &(self->view);
632 : char *srcbuf, *destbuf;
633 :
634 0 : if (view->readonly) {
635 0 : PyErr_SetString(PyExc_TypeError,
636 : "cannot modify read-only memory");
637 0 : return -1;
638 : }
639 0 : if (value == NULL) {
640 0 : PyErr_SetString(PyExc_TypeError,
641 : "cannot delete memory");
642 0 : return -1;
643 : }
644 0 : if (view->ndim != 1) {
645 0 : PyErr_SetNone(PyExc_NotImplementedError);
646 0 : return -1;
647 : }
648 0 : if (PyIndex_Check(key)) {
649 0 : start = PyNumber_AsSsize_t(key, NULL);
650 0 : if (start == -1 && PyErr_Occurred())
651 0 : return -1;
652 0 : if (start < 0) {
653 0 : start += get_shape0(view);
654 : }
655 0 : if ((start < 0) || (start >= get_shape0(view))) {
656 0 : PyErr_SetString(PyExc_IndexError,
657 : "index out of bounds");
658 0 : return -1;
659 : }
660 0 : len = 1;
661 : }
662 0 : else if (PySlice_Check(key)) {
663 : Py_ssize_t stop, step;
664 :
665 0 : if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
666 : &start, &stop, &step, &len) < 0) {
667 0 : return -1;
668 : }
669 0 : if (step != 1) {
670 0 : PyErr_SetNone(PyExc_NotImplementedError);
671 0 : return -1;
672 : }
673 : }
674 : else {
675 0 : PyErr_Format(PyExc_TypeError,
676 : "cannot index memory using \"%.200s\"",
677 0 : key->ob_type->tp_name);
678 0 : return -1;
679 : }
680 0 : if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
681 0 : return -1;
682 : }
683 : /* XXX should we allow assignment of different item sizes
684 : as long as the byte length is the same?
685 : (e.g. assign 2 shorts to a 4-byte slice) */
686 0 : if (srcview.itemsize != view->itemsize) {
687 0 : PyErr_Format(PyExc_TypeError,
688 : "mismatching item sizes for \"%.200s\" and \"%.200s\"",
689 0 : view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
690 0 : goto _error;
691 : }
692 0 : bytelen = len * view->itemsize;
693 0 : if (bytelen != srcview.len) {
694 0 : PyErr_SetString(PyExc_ValueError,
695 : "cannot modify size of memoryview object");
696 0 : goto _error;
697 : }
698 : /* Do the actual copy */
699 0 : destbuf = (char *) view->buf + start * view->itemsize;
700 0 : srcbuf = (char *) srcview.buf;
701 0 : if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
702 : /* No overlapping */
703 0 : memcpy(destbuf, srcbuf, bytelen);
704 : else
705 0 : memmove(destbuf, srcbuf, bytelen);
706 :
707 0 : PyBuffer_Release(&srcview);
708 0 : return 0;
709 :
710 : _error:
711 0 : PyBuffer_Release(&srcview);
712 0 : return -1;
713 : }
714 :
715 : static PyObject *
716 0 : memory_richcompare(PyObject *v, PyObject *w, int op)
717 : {
718 : Py_buffer vv, ww;
719 0 : int equal = 0;
720 : PyObject *res;
721 :
722 0 : vv.obj = NULL;
723 0 : ww.obj = NULL;
724 0 : if (op != Py_EQ && op != Py_NE)
725 0 : goto _notimpl;
726 0 : if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
727 0 : PyErr_Clear();
728 0 : goto _notimpl;
729 : }
730 0 : if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
731 0 : PyErr_Clear();
732 0 : goto _notimpl;
733 : }
734 :
735 0 : if (vv.itemsize != ww.itemsize || vv.len != ww.len)
736 : goto _end;
737 :
738 0 : equal = !memcmp(vv.buf, ww.buf, vv.len);
739 :
740 : _end:
741 0 : PyBuffer_Release(&vv);
742 0 : PyBuffer_Release(&ww);
743 0 : if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
744 0 : res = Py_True;
745 : else
746 0 : res = Py_False;
747 0 : Py_INCREF(res);
748 0 : return res;
749 :
750 : _notimpl:
751 0 : PyBuffer_Release(&vv);
752 0 : PyBuffer_Release(&ww);
753 0 : Py_INCREF(Py_NotImplemented);
754 0 : return Py_NotImplemented;
755 : }
756 :
757 :
758 : static int
759 0 : memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
760 : {
761 0 : if (self->base != NULL)
762 0 : Py_VISIT(self->base);
763 0 : if (self->view.obj != NULL)
764 0 : Py_VISIT(self->view.obj);
765 0 : return 0;
766 : }
767 :
768 : static int
769 0 : memory_clear(PyMemoryViewObject *self)
770 : {
771 0 : Py_CLEAR(self->base);
772 0 : PyBuffer_Release(&self->view);
773 0 : return 0;
774 : }
775 :
776 :
777 : /* As mapping */
778 : static PyMappingMethods memory_as_mapping = {
779 : (lenfunc)memory_length, /* mp_length */
780 : (binaryfunc)memory_subscript, /* mp_subscript */
781 : (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
782 : };
783 :
784 : static PySequenceMethods memory_as_sequence = {
785 : 0, /* sq_length */
786 : 0, /* sq_concat */
787 : 0, /* sq_repeat */
788 : (ssizeargfunc)memory_item, /* sq_item */
789 : };
790 :
791 : /* Buffer methods */
792 : static PyBufferProcs memory_as_buffer = {
793 : 0, /* bf_getreadbuffer */
794 : 0, /* bf_getwritebuffer */
795 : 0, /* bf_getsegcount */
796 : 0, /* bf_getcharbuffer */
797 : (getbufferproc)memory_getbuf, /* bf_getbuffer */
798 : (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
799 : };
800 :
801 :
802 : PyTypeObject PyMemoryView_Type = {
803 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
804 : "memoryview",
805 : sizeof(PyMemoryViewObject),
806 : 0,
807 : (destructor)memory_dealloc, /* tp_dealloc */
808 : 0, /* tp_print */
809 : 0, /* tp_getattr */
810 : 0, /* tp_setattr */
811 : 0, /* tp_compare */
812 : (reprfunc)memory_repr, /* tp_repr */
813 : 0, /* tp_as_number */
814 : &memory_as_sequence, /* tp_as_sequence */
815 : &memory_as_mapping, /* tp_as_mapping */
816 : 0, /* tp_hash */
817 : 0, /* tp_call */
818 : 0, /* tp_str */
819 : PyObject_GenericGetAttr, /* tp_getattro */
820 : 0, /* tp_setattro */
821 : &memory_as_buffer, /* tp_as_buffer */
822 : Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
823 : Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */
824 : memory_doc, /* tp_doc */
825 : (traverseproc)memory_traverse, /* tp_traverse */
826 : (inquiry)memory_clear, /* tp_clear */
827 : memory_richcompare, /* tp_richcompare */
828 : 0, /* tp_weaklistoffset */
829 : 0, /* tp_iter */
830 : 0, /* tp_iternext */
831 : memory_methods, /* tp_methods */
832 : 0, /* tp_members */
833 : memory_getsetlist, /* tp_getset */
834 : 0, /* tp_base */
835 : 0, /* tp_dict */
836 : 0, /* tp_descr_get */
837 : 0, /* tp_descr_set */
838 : 0, /* tp_dictoffset */
839 : 0, /* tp_init */
840 : 0, /* tp_alloc */
841 : memory_new, /* tp_new */
842 : };
|