blob: 6fcd995a83d22fab83dfdf1d626010b1ac360911 [file] [log] [blame]
Antoine Pitrou789be0c2009-04-02 21:18:34 +00001
2/* Memoryview object implementation */
3
4#include "Python.h"
5
6static Py_ssize_t
7get_shape0(Py_buffer *buf)
8{
9 if (buf->shape != NULL)
10 return buf->shape[0];
11 if (buf->ndim == 0)
12 return 1;
13 PyErr_SetString(PyExc_TypeError,
14 "exported buffer does not have any shape information associated "
15 "to it");
16 return -1;
17}
18
19static void
20dup_buffer(Py_buffer *dest, Py_buffer *src)
21{
22 *dest = *src;
23 if (src->ndim == 1 && src->shape != NULL) {
24 dest->shape = &(dest->smalltable[0]);
25 dest->shape[0] = get_shape0(src);
26 }
27 if (src->ndim == 1 && src->strides != NULL) {
28 dest->strides = &(dest->smalltable[1]);
29 dest->strides[0] = src->strides[0];
30 }
31}
32
33static int
34memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
35{
36 int res = 0;
Antoine Pitrou789be0c2009-04-02 21:18:34 +000037 if (self->view.obj != NULL)
38 res = PyObject_GetBuffer(self->view.obj, view, flags);
39 if (view)
40 dup_buffer(view, &self->view);
41 return res;
42}
43
44static void
45memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
46{
47 PyBuffer_Release(view);
48}
49
50PyDoc_STRVAR(memory_doc,
51"memoryview(object)\n\
52\n\
53Create a new memoryview object which references the given object.");
54
55PyObject *
56PyMemoryView_FromBuffer(Py_buffer *info)
57{
58 PyMemoryViewObject *mview;
59
60 mview = (PyMemoryViewObject *)
61 PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
62 if (mview == NULL)
63 return NULL;
64 mview->base = NULL;
65 dup_buffer(&mview->view, info);
66 /* NOTE: mview->view.obj should already have been incref'ed as
67 part of PyBuffer_FillInfo(). */
68 _PyObject_GC_TRACK(mview);
69 return (PyObject *)mview;
70}
71
72PyObject *
73PyMemoryView_FromObject(PyObject *base)
74{
75 PyMemoryViewObject *mview;
Antoine Pitrou526e4212010-02-02 22:36:17 +000076 Py_buffer view;
Antoine Pitrou789be0c2009-04-02 21:18:34 +000077
78 if (!PyObject_CheckBuffer(base)) {
79 PyErr_SetString(PyExc_TypeError,
80 "cannot make memory view because object does "
81 "not have the buffer interface");
82 return NULL;
83 }
84
Antoine Pitrou526e4212010-02-02 22:36:17 +000085 if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
Antoine Pitrou789be0c2009-04-02 21:18:34 +000086 return NULL;
87
Antoine Pitrou526e4212010-02-02 22:36:17 +000088 mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
89 if (mview == NULL) {
90 PyBuffer_Release(&view);
Antoine Pitrou789be0c2009-04-02 21:18:34 +000091 return NULL;
92 }
93
94 mview->base = base;
95 Py_INCREF(base);
Antoine Pitrou789be0c2009-04-02 21:18:34 +000096 return (PyObject *)mview;
97}
98
99static PyObject *
100memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
101{
102 PyObject *obj;
103 static char *kwlist[] = {"object", 0};
104
105 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
106 &obj)) {
107 return NULL;
108 }
109
110 return PyMemoryView_FromObject(obj);
111}
112
113
114static void
115_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 if (nd==0) {
122 memcpy(dest, src, itemsize);
123 }
124 else if (nd == 1) {
125 for (k = 0; k<shape[0]; k++) {
126 memcpy(dest, src, itemsize);
127 dest += itemsize;
128 src += strides[0];
129 }
130 }
131 else {
132 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 outstride = itemsize;
139 for (k=1; k<nd-1;k++) {
140 outstride *= shape[k];
141 }
142 for (k=0; k<shape[nd-1]; k++) {
143 _strided_copy_nd(dest, src, nd-1, shape,
144 strides, itemsize, fort);
145 dest += outstride;
146 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 outstride = itemsize;
157 for (k=1; k < nd; k++) {
158 outstride *= shape[k];
159 }
160 for (k=0; k<shape[0]; k++) {
161 _strided_copy_nd(dest, src, nd-1, shape+1,
162 strides+1, itemsize,
163 fort);
164 dest += outstride;
165 src += strides[0];
166 }
167 }
168 }
169 return;
170}
171
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000172static int
173_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;
Antoine Pitrou9cf85f12010-09-01 21:17:34 +0000179 void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000180
181 if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
182 PyErr_NoMemory();
183 return -1;
184 }
185
186 indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
187 if (indices == NULL) {
188 PyErr_NoMemory();
189 return -1;
190 }
191 for (k=0; k<view->ndim;k++) {
192 indices[k] = 0;
193 }
194
195 elements = 1;
196 for (k=0; k<view->ndim; k++) {
197 elements *= view->shape[k];
198 }
199 if (fort == 'F') {
Antoine Pitrou1fcdba82010-09-01 13:02:50 +0000200 func = _Py_add_one_to_index_F;
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000201 }
202 else {
Antoine Pitrou1fcdba82010-09-01 13:02:50 +0000203 func = _Py_add_one_to_index_C;
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000204 }
205 while (elements--) {
206 func(view->ndim, indices, view->shape);
207 ptr = PyBuffer_GetPointer(view, indices);
208 memcpy(dest, ptr, view->itemsize);
209 dest += view->itemsize;
210 }
211
212 PyMem_Free(indices);
213 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
239PyObject *
240PyMemoryView_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 if (!PyObject_CheckBuffer(obj)) {
249 PyErr_SetString(PyExc_TypeError,
250 "object does not have the buffer interface");
251 return NULL;
252 }
253
254 mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
255 if (mem == NULL)
256 return NULL;
257
258 view = &mem->view;
259 flags = PyBUF_FULL_RO;
260 switch(buffertype) {
261 case PyBUF_WRITE:
262 flags = PyBUF_FULL;
263 break;
264 }
265
266 if (PyObject_GetBuffer(obj, view, flags) != 0) {
267 Py_DECREF(mem);
268 return NULL;
269 }
270
271 if (PyBuffer_IsContiguous(view, fort)) {
272 /* no copy needed */
273 Py_INCREF(obj);
274 mem->base = obj;
275 _PyObject_GC_TRACK(mem);
276 return (PyObject *)mem;
277 }
278 /* otherwise a copy is needed */
279 if (buffertype == PyBUF_WRITE) {
280 Py_DECREF(mem);
281 PyErr_SetString(PyExc_BufferError,
282 "writable contiguous buffer requested "
283 "for a non-contiguousobject.");
284 return NULL;
285 }
286 bytes = PyBytes_FromStringAndSize(NULL, view->len);
287 if (bytes == NULL) {
288 Py_DECREF(mem);
289 return NULL;
290 }
291 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 if (view->suboffsets==NULL) {
297 _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
298 view->strides, view->itemsize, fort);
299 }
300 else {
301 if (_indirect_copy_nd(dest, view, fort) < 0) {
302 Py_DECREF(bytes);
303 Py_DECREF(mem);
304 return NULL;
305 }
306 }
307 if (buffertype == PyBUF_SHADOW) {
308 /* return a shadowed memory-view object */
309 view->buf = dest;
310 mem->base = PyTuple_Pack(2, obj, bytes);
311 Py_DECREF(bytes);
312 if (mem->base == NULL) {
313 Py_DECREF(mem);
314 return NULL;
315 }
316 }
317 else {
318 PyBuffer_Release(view); /* XXX ? */
319 /* steal the reference */
320 mem->base = bytes;
321 }
322 _PyObject_GC_TRACK(mem);
323 return (PyObject *)mem;
324}
325
326
327static PyObject *
328memory_format_get(PyMemoryViewObject *self)
329{
Mark Dickinson08133af2009-10-15 15:53:58 +0000330 return PyString_FromString(self->view.format);
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000331}
332
333static PyObject *
334memory_itemsize_get(PyMemoryViewObject *self)
335{
336 return PyLong_FromSsize_t(self->view.itemsize);
337}
338
339static PyObject *
340_IntTupleFromSsizet(int len, Py_ssize_t *vals)
341{
342 int i;
343 PyObject *o;
344 PyObject *intTuple;
345
346 if (vals == NULL) {
347 Py_INCREF(Py_None);
348 return Py_None;
349 }
350 intTuple = PyTuple_New(len);
351 if (!intTuple) return NULL;
352 for(i=0; i<len; i++) {
353 o = PyLong_FromSsize_t(vals[i]);
354 if (!o) {
355 Py_DECREF(intTuple);
356 return NULL;
357 }
358 PyTuple_SET_ITEM(intTuple, i, o);
359 }
360 return intTuple;
361}
362
363static PyObject *
364memory_shape_get(PyMemoryViewObject *self)
365{
366 return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
367}
368
369static PyObject *
370memory_strides_get(PyMemoryViewObject *self)
371{
372 return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
373}
374
375static PyObject *
376memory_suboffsets_get(PyMemoryViewObject *self)
377{
378 return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
379}
380
381static PyObject *
382memory_readonly_get(PyMemoryViewObject *self)
383{
384 return PyBool_FromLong(self->view.readonly);
385}
386
387static PyObject *
388memory_ndim_get(PyMemoryViewObject *self)
389{
390 return PyLong_FromLong(self->view.ndim);
391}
392
393static 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
405static PyObject *
406memory_tobytes(PyMemoryViewObject *self, PyObject *noargs)
407{
408 Py_buffer view;
409 PyObject *res;
410
Antoine Pitrou3013b162011-01-18 19:06:19 +0000411 if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_SIMPLE) < 0)
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000412 return NULL;
413
414 res = PyBytes_FromStringAndSize(NULL, view.len);
415 PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
416 PyBuffer_Release(&view);
417 return res;
418}
419
420/* TODO: rewrite this function using the struct module to unpack
421 each buffer item */
422
423static PyObject *
424memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
425{
426 Py_buffer *view = &(mem->view);
427 Py_ssize_t i;
428 PyObject *res, *item;
429 char *buf;
430
431 if (strcmp(view->format, "B") || view->itemsize != 1) {
432 PyErr_SetString(PyExc_NotImplementedError,
433 "tolist() only supports byte views");
434 return NULL;
435 }
436 if (view->ndim != 1) {
437 PyErr_SetString(PyExc_NotImplementedError,
438 "tolist() only supports one-dimensional objects");
439 return NULL;
440 }
441 res = PyList_New(view->len);
442 if (res == NULL)
443 return NULL;
444 buf = view->buf;
445 for (i = 0; i < view->len; i++) {
446 item = PyInt_FromLong((unsigned char) *buf);
447 if (item == NULL) {
448 Py_DECREF(res);
449 return NULL;
450 }
451 PyList_SET_ITEM(res, i, item);
452 buf++;
453 }
454 return res;
455}
456
457static 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
464static void
465memory_dealloc(PyMemoryViewObject *self)
466{
467 _PyObject_GC_UNTRACK(self);
468 if (self->view.obj != NULL) {
469 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 PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
478 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 PyBuffer_Release(&(self->view));
486 }
487 else {
488 PyBuffer_Release(&(self->view));
489 }
490 Py_CLEAR(self->base);
491 }
492 PyObject_GC_Del(self);
493}
494
495static PyObject *
496memory_repr(PyMemoryViewObject *self)
497{
Mark Dickinson08133af2009-10-15 15:53:58 +0000498 return PyString_FromFormat("<memory at %p>", self);
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000499}
500
501/* Sequence methods */
502static Py_ssize_t
503memory_length(PyMemoryViewObject *self)
504{
505 return get_shape0(&self->view);
506}
507
Raymond Hettinger62641e92009-06-23 20:59:43 +0000508/* Alternate version of memory_subcript that only accepts indices.
509 Used by PySeqIter_New().
510*/
511static PyObject *
512memory_item(PyMemoryViewObject *self, Py_ssize_t result)
513{
514 Py_buffer *view = &(self->view);
515
516 if (view->ndim == 0) {
517 PyErr_SetString(PyExc_IndexError,
518 "invalid indexing of 0-dim memory");
519 return NULL;
520 }
521 if (view->ndim == 1) {
522 /* Return a bytes object */
523 char *ptr;
524 ptr = (char *)view->buf;
525 if (result < 0) {
526 result += get_shape0(view);
527 }
528 if ((result < 0) || (result >= get_shape0(view))) {
529 PyErr_SetString(PyExc_IndexError,
530 "index out of bounds");
531 return NULL;
532 }
533 if (view->strides == NULL)
534 ptr += view->itemsize * result;
535 else
536 ptr += view->strides[0] * result;
537 if (view->suboffsets != NULL &&
538 view->suboffsets[0] >= 0) {
539 ptr = *((char **)ptr) + view->suboffsets[0];
540 }
541 return PyBytes_FromStringAndSize(ptr, view->itemsize);
542 } else {
543 /* Return a new memory-view object */
544 Py_buffer newview;
545 memset(&newview, 0, sizeof(newview));
546 /* XXX: This needs to be fixed so it actually returns a sub-view */
547 return PyMemoryView_FromBuffer(&newview);
548 }
549}
550
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000551/*
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 */
559static PyObject *
560memory_subscript(PyMemoryViewObject *self, PyObject *key)
561{
562 Py_buffer *view;
563 view = &(self->view);
564
565 if (view->ndim == 0) {
566 if (key == Py_Ellipsis ||
567 (PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
568 Py_INCREF(self);
569 return (PyObject *)self;
570 }
571 else {
572 PyErr_SetString(PyExc_IndexError,
573 "invalid indexing of 0-dim memory");
574 return NULL;
575 }
576 }
577 if (PyIndex_Check(key)) {
578 Py_ssize_t result;
579 result = PyNumber_AsSsize_t(key, NULL);
580 if (result == -1 && PyErr_Occurred())
581 return NULL;
Raymond Hettinger62641e92009-06-23 20:59:43 +0000582 return memory_item(self, result);
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000583 }
584 else if (PySlice_Check(key)) {
585 Py_ssize_t start, stop, step, slicelength;
586
Serhiy Storchaka5e793212017-04-15 20:11:12 +0300587 if (_PySlice_Unpack(key, &start, &stop, &step) < 0) {
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000588 return NULL;
589 }
Serhiy Storchakae41390a2017-04-08 11:48:57 +0300590 slicelength = _PySlice_AdjustIndices(get_shape0(view), &start, &stop,
591 step);
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000592
593 if (step == 1 && view->ndim == 1) {
594 Py_buffer newview;
595 void *newbuf = (char *) view->buf
596 + start * view->itemsize;
597 int newflags = view->readonly
598 ? PyBUF_CONTIG_RO : PyBUF_CONTIG;
599
600 /* XXX There should be an API to create a subbuffer */
601 if (view->obj != NULL) {
602 if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
603 return NULL;
604 }
605 else {
606 newview = *view;
607 }
608 newview.buf = newbuf;
609 newview.len = slicelength * newview.itemsize;
610 newview.format = view->format;
611 newview.shape = &(newview.smalltable[0]);
612 newview.shape[0] = slicelength;
613 newview.strides = &(newview.itemsize);
614 return PyMemoryView_FromBuffer(&newview);
615 }
616 PyErr_SetNone(PyExc_NotImplementedError);
617 return NULL;
618 }
619 PyErr_Format(PyExc_TypeError,
620 "cannot index memory using \"%.200s\"",
621 key->ob_type->tp_name);
622 return NULL;
623}
624
625
626/* Need to support assigning memory if we can */
627static int
628memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
629{
Antoine Pitrou32669782010-07-11 12:14:05 +0000630 Py_ssize_t start, len, bytelen;
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000631 Py_buffer srcview;
632 Py_buffer *view = &(self->view);
633 char *srcbuf, *destbuf;
634
635 if (view->readonly) {
636 PyErr_SetString(PyExc_TypeError,
637 "cannot modify read-only memory");
638 return -1;
639 }
Antoine Pitrou9cf85f12010-09-01 21:17:34 +0000640 if (value == NULL) {
641 PyErr_SetString(PyExc_TypeError,
642 "cannot delete memory");
643 return -1;
644 }
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000645 if (view->ndim != 1) {
646 PyErr_SetNone(PyExc_NotImplementedError);
647 return -1;
648 }
649 if (PyIndex_Check(key)) {
650 start = PyNumber_AsSsize_t(key, NULL);
651 if (start == -1 && PyErr_Occurred())
652 return -1;
653 if (start < 0) {
654 start += get_shape0(view);
655 }
656 if ((start < 0) || (start >= get_shape0(view))) {
657 PyErr_SetString(PyExc_IndexError,
658 "index out of bounds");
659 return -1;
660 }
661 len = 1;
662 }
663 else if (PySlice_Check(key)) {
664 Py_ssize_t stop, step;
665
Serhiy Storchaka5e793212017-04-15 20:11:12 +0300666 if (_PySlice_Unpack(key, &start, &stop, &step) < 0) {
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000667 return -1;
668 }
Serhiy Storchakae41390a2017-04-08 11:48:57 +0300669 len = _PySlice_AdjustIndices(get_shape0(view), &start, &stop, step);
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000670 if (step != 1) {
671 PyErr_SetNone(PyExc_NotImplementedError);
672 return -1;
673 }
674 }
675 else {
676 PyErr_Format(PyExc_TypeError,
677 "cannot index memory using \"%.200s\"",
678 key->ob_type->tp_name);
679 return -1;
680 }
681 if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
682 return -1;
683 }
684 /* XXX should we allow assignment of different item sizes
685 as long as the byte length is the same?
686 (e.g. assign 2 shorts to a 4-byte slice) */
687 if (srcview.itemsize != view->itemsize) {
688 PyErr_Format(PyExc_TypeError,
689 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
690 view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
691 goto _error;
692 }
693 bytelen = len * view->itemsize;
694 if (bytelen != srcview.len) {
695 PyErr_SetString(PyExc_ValueError,
696 "cannot modify size of memoryview object");
697 goto _error;
698 }
699 /* Do the actual copy */
700 destbuf = (char *) view->buf + start * view->itemsize;
701 srcbuf = (char *) srcview.buf;
702 if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
703 /* No overlapping */
704 memcpy(destbuf, srcbuf, bytelen);
Antoine Pitrou32669782010-07-11 12:14:05 +0000705 else
706 memmove(destbuf, srcbuf, bytelen);
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000707
708 PyBuffer_Release(&srcview);
709 return 0;
710
711_error:
712 PyBuffer_Release(&srcview);
713 return -1;
714}
715
716static PyObject *
717memory_richcompare(PyObject *v, PyObject *w, int op)
718{
719 Py_buffer vv, ww;
720 int equal = 0;
721 PyObject *res;
722
723 vv.obj = NULL;
724 ww.obj = NULL;
725 if (op != Py_EQ && op != Py_NE)
726 goto _notimpl;
727 if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
728 PyErr_Clear();
729 goto _notimpl;
730 }
731 if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
732 PyErr_Clear();
733 goto _notimpl;
734 }
735
736 if (vv.itemsize != ww.itemsize || vv.len != ww.len)
737 goto _end;
738
739 equal = !memcmp(vv.buf, ww.buf, vv.len);
740
741_end:
742 PyBuffer_Release(&vv);
743 PyBuffer_Release(&ww);
744 if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
745 res = Py_True;
746 else
747 res = Py_False;
748 Py_INCREF(res);
749 return res;
750
751_notimpl:
752 PyBuffer_Release(&vv);
753 PyBuffer_Release(&ww);
754 Py_INCREF(Py_NotImplemented);
755 return Py_NotImplemented;
756}
757
758
759static int
760memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
761{
762 if (self->base != NULL)
763 Py_VISIT(self->base);
764 if (self->view.obj != NULL)
765 Py_VISIT(self->view.obj);
766 return 0;
767}
768
769static int
770memory_clear(PyMemoryViewObject *self)
771{
772 Py_CLEAR(self->base);
773 PyBuffer_Release(&self->view);
774 return 0;
775}
776
777
778/* As mapping */
779static PyMappingMethods memory_as_mapping = {
780 (lenfunc)memory_length, /* mp_length */
781 (binaryfunc)memory_subscript, /* mp_subscript */
782 (objobjargproc)memory_ass_sub, /* mp_ass_subscript */
783};
784
Raymond Hettinger62641e92009-06-23 20:59:43 +0000785static PySequenceMethods memory_as_sequence = {
786 0, /* sq_length */
787 0, /* sq_concat */
788 0, /* sq_repeat */
789 (ssizeargfunc)memory_item, /* sq_item */
790};
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000791
792/* Buffer methods */
793static PyBufferProcs memory_as_buffer = {
794 0, /* bf_getreadbuffer */
795 0, /* bf_getwritebuffer */
796 0, /* bf_getsegcount */
797 0, /* bf_getcharbuffer */
798 (getbufferproc)memory_getbuf, /* bf_getbuffer */
799 (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
800};
801
802
803PyTypeObject PyMemoryView_Type = {
804 PyVarObject_HEAD_INIT(&PyType_Type, 0)
805 "memoryview",
806 sizeof(PyMemoryViewObject),
807 0,
808 (destructor)memory_dealloc, /* tp_dealloc */
809 0, /* tp_print */
810 0, /* tp_getattr */
811 0, /* tp_setattr */
812 0, /* tp_compare */
813 (reprfunc)memory_repr, /* tp_repr */
814 0, /* tp_as_number */
Raymond Hettinger62641e92009-06-23 20:59:43 +0000815 &memory_as_sequence, /* tp_as_sequence */
Antoine Pitrou789be0c2009-04-02 21:18:34 +0000816 &memory_as_mapping, /* tp_as_mapping */
817 0, /* tp_hash */
818 0, /* tp_call */
819 0, /* tp_str */
820 PyObject_GenericGetAttr, /* tp_getattro */
821 0, /* tp_setattro */
822 &memory_as_buffer, /* tp_as_buffer */
823 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
824 Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */
825 memory_doc, /* tp_doc */
826 (traverseproc)memory_traverse, /* tp_traverse */
827 (inquiry)memory_clear, /* tp_clear */
828 memory_richcompare, /* tp_richcompare */
829 0, /* tp_weaklistoffset */
830 0, /* tp_iter */
831 0, /* tp_iternext */
832 memory_methods, /* tp_methods */
833 0, /* tp_members */
834 memory_getsetlist, /* tp_getset */
835 0, /* tp_base */
836 0, /* tp_dict */
837 0, /* tp_descr_get */
838 0, /* tp_descr_set */
839 0, /* tp_dictoffset */
840 0, /* tp_init */
841 0, /* tp_alloc */
842 memory_new, /* tp_new */
843};