2 /* Memoryview object implementation */
7 get_shape0(Py_buffer
*buf
)
9 if (buf
->shape
!= NULL
)
13 PyErr_SetString(PyExc_TypeError
,
14 "exported buffer does not have any shape information associated "
20 dup_buffer(Py_buffer
*dest
, Py_buffer
*src
)
23 if (src
->ndim
== 1 && src
->shape
!= NULL
) {
24 dest
->shape
= &(dest
->smalltable
[0]);
25 dest
->shape
[0] = get_shape0(src
);
27 if (src
->ndim
== 1 && src
->strides
!= NULL
) {
28 dest
->strides
= &(dest
->smalltable
[1]);
29 dest
->strides
[0] = src
->strides
[0];
34 memory_getbuf(PyMemoryViewObject
*self
, Py_buffer
*view
, int flags
)
37 if (self
->view
.obj
!= NULL
)
38 res
= PyObject_GetBuffer(self
->view
.obj
, view
, flags
);
40 dup_buffer(view
, &self
->view
);
45 memory_releasebuf(PyMemoryViewObject
*self
, Py_buffer
*view
)
47 PyBuffer_Release(view
);
50 PyDoc_STRVAR(memory_doc
,
51 "memoryview(object)\n\
53 Create a new memoryview object which references the given object.");
56 PyMemoryView_FromBuffer(Py_buffer
*info
)
58 PyMemoryViewObject
*mview
;
60 mview
= (PyMemoryViewObject
*)
61 PyObject_GC_New(PyMemoryViewObject
, &PyMemoryView_Type
);
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
;
73 PyMemoryView_FromObject(PyObject
*base
)
75 PyMemoryViewObject
*mview
;
78 if (!PyObject_CheckBuffer(base
)) {
79 PyErr_SetString(PyExc_TypeError
,
80 "cannot make memory view because object does "
81 "not have the buffer interface");
85 if (PyObject_GetBuffer(base
, &view
, PyBUF_FULL_RO
) < 0)
88 mview
= (PyMemoryViewObject
*)PyMemoryView_FromBuffer(&view
);
90 PyBuffer_Release(&view
);
96 return (PyObject
*)mview
;
100 memory_new(PyTypeObject
*subtype
, PyObject
*args
, PyObject
*kwds
)
103 static char *kwlist
[] = {"object", 0};
105 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O:memoryview", kwlist
,
110 return PyMemoryView_FromObject(obj
);
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
)
119 Py_ssize_t outstride
;
122 memcpy(dest
, src
, itemsize
);
125 for (k
= 0; k
<shape
[0]; k
++) {
126 memcpy(dest
, src
, itemsize
);
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.
138 outstride
= itemsize
;
139 for (k
=1; k
<nd
-1;k
++) {
140 outstride
*= shape
[k
];
142 for (k
=0; k
<shape
[nd
-1]; k
++) {
143 _strided_copy_nd(dest
, src
, nd
-1, shape
,
144 strides
, itemsize
, fort
);
146 src
+= strides
[nd
-1];
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
156 outstride
= itemsize
;
157 for (k
=1; k
< nd
; k
++) {
158 outstride
*= shape
[k
];
160 for (k
=0; k
<shape
[0]; k
++) {
161 _strided_copy_nd(dest
, src
, nd
-1, shape
+1,
173 _indirect_copy_nd(char *dest
, Py_buffer
*view
, char fort
)
179 void (*func
)(int, Py_ssize_t
*, const Py_ssize_t
*);
181 if (view
->ndim
> PY_SSIZE_T_MAX
/ sizeof(Py_ssize_t
)) {
186 indices
= (Py_ssize_t
*)PyMem_Malloc(sizeof(Py_ssize_t
)*view
->ndim
);
187 if (indices
== NULL
) {
191 for (k
=0; k
<view
->ndim
;k
++) {
196 for (k
=0; k
<view
->ndim
; k
++) {
197 elements
*= view
->shape
[k
];
200 func
= _Py_add_one_to_index_F
;
203 func
= _Py_add_one_to_index_C
;
206 func(view
->ndim
, indices
, view
->shape
);
207 ptr
= PyBuffer_GetPointer(view
, indices
);
208 memcpy(dest
, ptr
, view
->itemsize
);
209 dest
+= view
->itemsize
;
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.
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).
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
240 PyMemoryView_GetContiguous(PyObject
*obj
, int buffertype
, char fort
)
242 PyMemoryViewObject
*mem
;
248 if (!PyObject_CheckBuffer(obj
)) {
249 PyErr_SetString(PyExc_TypeError
,
250 "object does not have the buffer interface");
254 mem
= PyObject_GC_New(PyMemoryViewObject
, &PyMemoryView_Type
);
259 flags
= PyBUF_FULL_RO
;
266 if (PyObject_GetBuffer(obj
, view
, flags
) != 0) {
271 if (PyBuffer_IsContiguous(view
, fort
)) {
275 _PyObject_GC_TRACK(mem
);
276 return (PyObject
*)mem
;
278 /* otherwise a copy is needed */
279 if (buffertype
== PyBUF_WRITE
) {
281 PyErr_SetString(PyExc_BufferError
,
282 "writable contiguous buffer requested "
283 "for a non-contiguousobject.");
286 bytes
= PyBytes_FromStringAndSize(NULL
, view
->len
);
291 dest
= PyBytes_AS_STRING(bytes
);
292 /* different copying strategy depending on whether
293 or not any pointer de-referencing is needed
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
);
301 if (_indirect_copy_nd(dest
, view
, fort
) < 0) {
307 if (buffertype
== PyBUF_SHADOW
) {
308 /* return a shadowed memory-view object */
310 mem
->base
= PyTuple_Pack(2, obj
, bytes
);
312 if (mem
->base
== NULL
) {
318 PyBuffer_Release(view
); /* XXX ? */
319 /* steal the reference */
322 _PyObject_GC_TRACK(mem
);
323 return (PyObject
*)mem
;
328 memory_format_get(PyMemoryViewObject
*self
)
330 return PyString_FromString(self
->view
.format
);
334 memory_itemsize_get(PyMemoryViewObject
*self
)
336 return PyLong_FromSsize_t(self
->view
.itemsize
);
340 _IntTupleFromSsizet(int len
, Py_ssize_t
*vals
)
350 intTuple
= PyTuple_New(len
);
351 if (!intTuple
) return NULL
;
352 for(i
=0; i
<len
; i
++) {
353 o
= PyLong_FromSsize_t(vals
[i
]);
358 PyTuple_SET_ITEM(intTuple
, i
, o
);
364 memory_shape_get(PyMemoryViewObject
*self
)
366 return _IntTupleFromSsizet(self
->view
.ndim
, self
->view
.shape
);
370 memory_strides_get(PyMemoryViewObject
*self
)
372 return _IntTupleFromSsizet(self
->view
.ndim
, self
->view
.strides
);
376 memory_suboffsets_get(PyMemoryViewObject
*self
)
378 return _IntTupleFromSsizet(self
->view
.ndim
, self
->view
.suboffsets
);
382 memory_readonly_get(PyMemoryViewObject
*self
)
384 return PyBool_FromLong(self
->view
.readonly
);
388 memory_ndim_get(PyMemoryViewObject
*self
)
390 return PyLong_FromLong(self
->view
.ndim
);
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
},
406 memory_tobytes(PyMemoryViewObject
*self
, PyObject
*noargs
)
411 if (PyObject_GetBuffer((PyObject
*)self
, &view
, PyBUF_SIMPLE
) < 0)
414 res
= PyBytes_FromStringAndSize(NULL
, view
.len
);
415 PyBuffer_ToContiguous(PyBytes_AS_STRING(res
), &view
, view
.len
, 'C');
416 PyBuffer_Release(&view
);
420 /* TODO: rewrite this function using the struct module to unpack
424 memory_tolist(PyMemoryViewObject
*mem
, PyObject
*noargs
)
426 Py_buffer
*view
= &(mem
->view
);
428 PyObject
*res
, *item
;
431 if (strcmp(view
->format
, "B") || view
->itemsize
!= 1) {
432 PyErr_SetString(PyExc_NotImplementedError
,
433 "tolist() only supports byte views");
436 if (view
->ndim
!= 1) {
437 PyErr_SetString(PyExc_NotImplementedError
,
438 "tolist() only supports one-dimensional objects");
441 res
= PyList_New(view
->len
);
445 for (i
= 0; i
< view
->len
; i
++) {
446 item
= PyInt_FromLong((unsigned char) *buf
);
451 PyList_SET_ITEM(res
, i
, item
);
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 */
465 memory_dealloc(PyMemoryViewObject
*self
)
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.
477 PyObject_CopyData(PyTuple_GET_ITEM(self
->base
,0),
478 PyTuple_GET_ITEM(self
->base
,1));
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.
485 PyBuffer_Release(&(self
->view
));
488 PyBuffer_Release(&(self
->view
));
490 Py_CLEAR(self
->base
);
492 PyObject_GC_Del(self
);
496 memory_repr(PyMemoryViewObject
*self
)
498 return PyString_FromFormat("<memory at %p>", self
);
501 /* Sequence methods */
503 memory_length(PyMemoryViewObject
*self
)
505 return get_shape0(&self
->view
);
508 /* Alternate version of memory_subcript that only accepts indices.
509 Used by PySeqIter_New().
512 memory_item(PyMemoryViewObject
*self
, Py_ssize_t result
)
514 Py_buffer
*view
= &(self
->view
);
516 if (view
->ndim
== 0) {
517 PyErr_SetString(PyExc_IndexError
,
518 "invalid indexing of 0-dim memory");
521 if (view
->ndim
== 1) {
522 /* Return a bytes object */
524 ptr
= (char *)view
->buf
;
526 result
+= get_shape0(view
);
528 if ((result
< 0) || (result
>= get_shape0(view
))) {
529 PyErr_SetString(PyExc_IndexError
,
530 "index out of bounds");
533 if (view
->strides
== NULL
)
534 ptr
+= view
->itemsize
* result
;
536 ptr
+= view
->strides
[0] * result
;
537 if (view
->suboffsets
!= NULL
&&
538 view
->suboffsets
[0] >= 0) {
539 ptr
= *((char **)ptr
) + view
->suboffsets
[0];
541 return PyBytes_FromStringAndSize(ptr
, view
->itemsize
);
543 /* Return a new memory-view object */
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
);
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
556 0-d memory-view objects can be referenced using ... or () but
557 not with anything else.
560 memory_subscript(PyMemoryViewObject
*self
, PyObject
*key
)
563 view
= &(self
->view
);
565 if (view
->ndim
== 0) {
566 if (key
== Py_Ellipsis
||
567 (PyTuple_Check(key
) && PyTuple_GET_SIZE(key
)==0)) {
569 return (PyObject
*)self
;
572 PyErr_SetString(PyExc_IndexError
,
573 "invalid indexing of 0-dim memory");
577 if (PyIndex_Check(key
)) {
579 result
= PyNumber_AsSsize_t(key
, NULL
);
580 if (result
== -1 && PyErr_Occurred())
582 return memory_item(self
, result
);
584 else if (PySlice_Check(key
)) {
585 Py_ssize_t start
, stop
, step
, slicelength
;
587 if (PySlice_GetIndicesEx((PySliceObject
*)key
, get_shape0(view
),
588 &start
, &stop
, &step
, &slicelength
) < 0) {
592 if (step
== 1 && view
->ndim
== 1) {
594 void *newbuf
= (char *) view
->buf
595 + start
* view
->itemsize
;
596 int newflags
= view
->readonly
597 ? PyBUF_CONTIG_RO
: PyBUF_CONTIG
;
599 /* XXX There should be an API to create a subbuffer */
600 if (view
->obj
!= NULL
) {
601 if (PyObject_GetBuffer(view
->obj
, &newview
, newflags
) == -1)
607 newview
.buf
= newbuf
;
608 newview
.len
= slicelength
* newview
.itemsize
;
609 newview
.format
= view
->format
;
610 newview
.shape
= &(newview
.smalltable
[0]);
611 newview
.shape
[0] = slicelength
;
612 newview
.strides
= &(newview
.itemsize
);
613 return PyMemoryView_FromBuffer(&newview
);
615 PyErr_SetNone(PyExc_NotImplementedError
);
618 PyErr_Format(PyExc_TypeError
,
619 "cannot index memory using \"%.200s\"",
620 key
->ob_type
->tp_name
);
625 /* Need to support assigning memory if we can */
627 memory_ass_sub(PyMemoryViewObject
*self
, PyObject
*key
, PyObject
*value
)
629 Py_ssize_t start
, len
, bytelen
;
631 Py_buffer
*view
= &(self
->view
);
632 char *srcbuf
, *destbuf
;
634 if (view
->readonly
) {
635 PyErr_SetString(PyExc_TypeError
,
636 "cannot modify read-only memory");
640 PyErr_SetString(PyExc_TypeError
,
641 "cannot delete memory");
644 if (view
->ndim
!= 1) {
645 PyErr_SetNone(PyExc_NotImplementedError
);
648 if (PyIndex_Check(key
)) {
649 start
= PyNumber_AsSsize_t(key
, NULL
);
650 if (start
== -1 && PyErr_Occurred())
653 start
+= get_shape0(view
);
655 if ((start
< 0) || (start
>= get_shape0(view
))) {
656 PyErr_SetString(PyExc_IndexError
,
657 "index out of bounds");
662 else if (PySlice_Check(key
)) {
663 Py_ssize_t stop
, step
;
665 if (PySlice_GetIndicesEx((PySliceObject
*)key
, get_shape0(view
),
666 &start
, &stop
, &step
, &len
) < 0) {
670 PyErr_SetNone(PyExc_NotImplementedError
);
675 PyErr_Format(PyExc_TypeError
,
676 "cannot index memory using \"%.200s\"",
677 key
->ob_type
->tp_name
);
680 if (PyObject_GetBuffer(value
, &srcview
, PyBUF_CONTIG_RO
) == -1) {
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 if (srcview
.itemsize
!= view
->itemsize
) {
687 PyErr_Format(PyExc_TypeError
,
688 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
689 view
->obj
->ob_type
->tp_name
, srcview
.obj
->ob_type
->tp_name
);
692 bytelen
= len
* view
->itemsize
;
693 if (bytelen
!= srcview
.len
) {
694 PyErr_SetString(PyExc_ValueError
,
695 "cannot modify size of memoryview object");
698 /* Do the actual copy */
699 destbuf
= (char *) view
->buf
+ start
* view
->itemsize
;
700 srcbuf
= (char *) srcview
.buf
;
701 if (destbuf
+ bytelen
< srcbuf
|| srcbuf
+ bytelen
< destbuf
)
703 memcpy(destbuf
, srcbuf
, bytelen
);
705 memmove(destbuf
, srcbuf
, bytelen
);
707 PyBuffer_Release(&srcview
);
711 PyBuffer_Release(&srcview
);
716 memory_richcompare(PyObject
*v
, PyObject
*w
, int op
)
724 if (op
!= Py_EQ
&& op
!= Py_NE
)
726 if (PyObject_GetBuffer(v
, &vv
, PyBUF_CONTIG_RO
) == -1) {
730 if (PyObject_GetBuffer(w
, &ww
, PyBUF_CONTIG_RO
) == -1) {
735 if (vv
.itemsize
!= ww
.itemsize
|| vv
.len
!= ww
.len
)
738 equal
= !memcmp(vv
.buf
, ww
.buf
, vv
.len
);
741 PyBuffer_Release(&vv
);
742 PyBuffer_Release(&ww
);
743 if ((equal
&& op
== Py_EQ
) || (!equal
&& op
== Py_NE
))
751 PyBuffer_Release(&vv
);
752 PyBuffer_Release(&ww
);
753 Py_INCREF(Py_NotImplemented
);
754 return Py_NotImplemented
;
759 memory_traverse(PyMemoryViewObject
*self
, visitproc visit
, void *arg
)
761 if (self
->base
!= NULL
)
762 Py_VISIT(self
->base
);
763 if (self
->view
.obj
!= NULL
)
764 Py_VISIT(self
->view
.obj
);
769 memory_clear(PyMemoryViewObject
*self
)
771 Py_CLEAR(self
->base
);
772 PyBuffer_Release(&self
->view
);
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 */
784 static PySequenceMethods memory_as_sequence
= {
788 (ssizeargfunc
)memory_item
, /* sq_item */
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 */
802 PyTypeObject PyMemoryView_Type
= {
803 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
805 sizeof(PyMemoryViewObject
),
807 (destructor
)memory_dealloc
, /* tp_dealloc */
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 */
819 PyObject_GenericGetAttr
, /* tp_getattro */
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 */
831 memory_methods
, /* tp_methods */
833 memory_getsetlist
, /* tp_getset */
836 0, /* tp_descr_get */
837 0, /* tp_descr_set */
838 0, /* tp_dictoffset */
841 memory_new
, /* tp_new */