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 /* XXX for whatever reason fixing the flags seems necessary */
38 if (self
->view
.readonly
)
39 flags
&= ~PyBUF_WRITABLE
;
40 if (self
->view
.obj
!= NULL
)
41 res
= PyObject_GetBuffer(self
->view
.obj
, view
, flags
);
43 dup_buffer(view
, &self
->view
);
48 memory_releasebuf(PyMemoryViewObject
*self
, Py_buffer
*view
)
50 PyBuffer_Release(view
);
53 PyDoc_STRVAR(memory_doc
,
54 "memoryview(object)\n\
56 Create a new memoryview object which references the given object.");
59 PyMemoryView_FromBuffer(Py_buffer
*info
)
61 PyMemoryViewObject
*mview
;
63 mview
= (PyMemoryViewObject
*)
64 PyObject_GC_New(PyMemoryViewObject
, &PyMemoryView_Type
);
68 dup_buffer(&mview
->view
, info
);
69 /* NOTE: mview->view.obj should already have been incref'ed as
70 part of PyBuffer_FillInfo(). */
71 _PyObject_GC_TRACK(mview
);
72 return (PyObject
*)mview
;
76 PyMemoryView_FromObject(PyObject
*base
)
78 PyMemoryViewObject
*mview
;
80 if (!PyObject_CheckBuffer(base
)) {
81 PyErr_SetString(PyExc_TypeError
,
82 "cannot make memory view because object does "
83 "not have the buffer interface");
87 mview
= (PyMemoryViewObject
*)
88 PyObject_GC_New(PyMemoryViewObject
, &PyMemoryView_Type
);
93 if (PyObject_GetBuffer(base
, &(mview
->view
), PyBUF_FULL_RO
) < 0) {
100 _PyObject_GC_TRACK(mview
);
101 return (PyObject
*)mview
;
105 memory_new(PyTypeObject
*subtype
, PyObject
*args
, PyObject
*kwds
)
108 static char *kwlist
[] = {"object", 0};
110 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O:memoryview", kwlist
,
115 return PyMemoryView_FromObject(obj
);
120 _strided_copy_nd(char *dest
, char *src
, int nd
, Py_ssize_t
*shape
,
121 Py_ssize_t
*strides
, Py_ssize_t itemsize
, char fort
)
124 Py_ssize_t outstride
;
127 memcpy(dest
, src
, itemsize
);
130 for (k
= 0; k
<shape
[0]; k
++) {
131 memcpy(dest
, src
, itemsize
);
138 /* Copy first dimension first,
139 second dimension second, etc...
140 Set up the recursive loop backwards so that final
141 dimension is actually copied last.
143 outstride
= itemsize
;
144 for (k
=1; k
<nd
-1;k
++) {
145 outstride
*= shape
[k
];
147 for (k
=0; k
<shape
[nd
-1]; k
++) {
148 _strided_copy_nd(dest
, src
, nd
-1, shape
,
149 strides
, itemsize
, fort
);
151 src
+= strides
[nd
-1];
156 /* Copy last dimension first,
157 second-to-last dimension second, etc.
158 Set up the recursion so that the
159 first dimension is copied last
161 outstride
= itemsize
;
162 for (k
=1; k
< nd
; k
++) {
163 outstride
*= shape
[k
];
165 for (k
=0; k
<shape
[0]; k
++) {
166 _strided_copy_nd(dest
, src
, nd
-1, shape
+1,
177 void _add_one_to_index_F(int nd
, Py_ssize_t
*index
, Py_ssize_t
*shape
);
178 void _add_one_to_index_C(int nd
, Py_ssize_t
*index
, Py_ssize_t
*shape
);
181 _indirect_copy_nd(char *dest
, Py_buffer
*view
, char fort
)
187 void (*func
)(int, Py_ssize_t
*, Py_ssize_t
*);
189 if (view
->ndim
> PY_SSIZE_T_MAX
/ sizeof(Py_ssize_t
)) {
194 indices
= (Py_ssize_t
*)PyMem_Malloc(sizeof(Py_ssize_t
)*view
->ndim
);
195 if (indices
== NULL
) {
199 for (k
=0; k
<view
->ndim
;k
++) {
204 for (k
=0; k
<view
->ndim
; k
++) {
205 elements
*= view
->shape
[k
];
208 func
= _add_one_to_index_F
;
211 func
= _add_one_to_index_C
;
214 func(view
->ndim
, indices
, view
->shape
);
215 ptr
= PyBuffer_GetPointer(view
, indices
);
216 memcpy(dest
, ptr
, view
->itemsize
);
217 dest
+= view
->itemsize
;
225 Get a the data from an object as a contiguous chunk of memory (in
226 either 'C' or 'F'ortran order) even if it means copying it into a
227 separate memory area.
229 Returns a new reference to a Memory view object. If no copy is needed,
230 the memory view object points to the original memory and holds a
231 lock on the original. If a copy is needed, then the memory view object
232 points to a brand-new Bytes object (and holds a memory lock on it).
236 PyBUF_READ buffer only needs to be read-only
237 PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
238 PyBUF_SHADOW buffer needs to be writable so shadow it with
239 a contiguous buffer if it is not. The view will point to
240 the shadow buffer which can be written to and then
241 will be copied back into the other buffer when the memory
242 view is de-allocated. While the shadow buffer is
243 being used, it will have an exclusive write lock on
248 PyMemoryView_GetContiguous(PyObject
*obj
, int buffertype
, char fort
)
250 PyMemoryViewObject
*mem
;
256 if (!PyObject_CheckBuffer(obj
)) {
257 PyErr_SetString(PyExc_TypeError
,
258 "object does not have the buffer interface");
262 mem
= PyObject_GC_New(PyMemoryViewObject
, &PyMemoryView_Type
);
267 flags
= PyBUF_FULL_RO
;
274 if (PyObject_GetBuffer(obj
, view
, flags
) != 0) {
279 if (PyBuffer_IsContiguous(view
, fort
)) {
283 _PyObject_GC_TRACK(mem
);
284 return (PyObject
*)mem
;
286 /* otherwise a copy is needed */
287 if (buffertype
== PyBUF_WRITE
) {
289 PyErr_SetString(PyExc_BufferError
,
290 "writable contiguous buffer requested "
291 "for a non-contiguousobject.");
294 bytes
= PyBytes_FromStringAndSize(NULL
, view
->len
);
299 dest
= PyBytes_AS_STRING(bytes
);
300 /* different copying strategy depending on whether
301 or not any pointer de-referencing is needed
303 /* strided or in-direct copy */
304 if (view
->suboffsets
==NULL
) {
305 _strided_copy_nd(dest
, view
->buf
, view
->ndim
, view
->shape
,
306 view
->strides
, view
->itemsize
, fort
);
309 if (_indirect_copy_nd(dest
, view
, fort
) < 0) {
315 if (buffertype
== PyBUF_SHADOW
) {
316 /* return a shadowed memory-view object */
318 mem
->base
= PyTuple_Pack(2, obj
, bytes
);
320 if (mem
->base
== NULL
) {
326 PyBuffer_Release(view
); /* XXX ? */
327 /* steal the reference */
330 _PyObject_GC_TRACK(mem
);
331 return (PyObject
*)mem
;
336 memory_format_get(PyMemoryViewObject
*self
)
338 return PyString_FromString(self
->view
.format
);
342 memory_itemsize_get(PyMemoryViewObject
*self
)
344 return PyLong_FromSsize_t(self
->view
.itemsize
);
348 _IntTupleFromSsizet(int len
, Py_ssize_t
*vals
)
358 intTuple
= PyTuple_New(len
);
359 if (!intTuple
) return NULL
;
360 for(i
=0; i
<len
; i
++) {
361 o
= PyLong_FromSsize_t(vals
[i
]);
366 PyTuple_SET_ITEM(intTuple
, i
, o
);
372 memory_shape_get(PyMemoryViewObject
*self
)
374 return _IntTupleFromSsizet(self
->view
.ndim
, self
->view
.shape
);
378 memory_strides_get(PyMemoryViewObject
*self
)
380 return _IntTupleFromSsizet(self
->view
.ndim
, self
->view
.strides
);
384 memory_suboffsets_get(PyMemoryViewObject
*self
)
386 return _IntTupleFromSsizet(self
->view
.ndim
, self
->view
.suboffsets
);
390 memory_readonly_get(PyMemoryViewObject
*self
)
392 return PyBool_FromLong(self
->view
.readonly
);
396 memory_ndim_get(PyMemoryViewObject
*self
)
398 return PyLong_FromLong(self
->view
.ndim
);
401 static PyGetSetDef memory_getsetlist
[] ={
402 {"format", (getter
)memory_format_get
, NULL
, NULL
},
403 {"itemsize", (getter
)memory_itemsize_get
, NULL
, NULL
},
404 {"shape", (getter
)memory_shape_get
, NULL
, NULL
},
405 {"strides", (getter
)memory_strides_get
, NULL
, NULL
},
406 {"suboffsets", (getter
)memory_suboffsets_get
, NULL
, NULL
},
407 {"readonly", (getter
)memory_readonly_get
, NULL
, NULL
},
408 {"ndim", (getter
)memory_ndim_get
, NULL
, NULL
},
409 {NULL
, NULL
, NULL
, NULL
},
414 memory_tobytes(PyMemoryViewObject
*self
, PyObject
*noargs
)
419 if (PyObject_GetBuffer((PyObject
*)self
, &view
, PyBUF_FULL
) < 0)
422 res
= PyBytes_FromStringAndSize(NULL
, view
.len
);
423 PyBuffer_ToContiguous(PyBytes_AS_STRING(res
), &view
, view
.len
, 'C');
424 PyBuffer_Release(&view
);
428 /* TODO: rewrite this function using the struct module to unpack
432 memory_tolist(PyMemoryViewObject
*mem
, PyObject
*noargs
)
434 Py_buffer
*view
= &(mem
->view
);
436 PyObject
*res
, *item
;
439 if (strcmp(view
->format
, "B") || view
->itemsize
!= 1) {
440 PyErr_SetString(PyExc_NotImplementedError
,
441 "tolist() only supports byte views");
444 if (view
->ndim
!= 1) {
445 PyErr_SetString(PyExc_NotImplementedError
,
446 "tolist() only supports one-dimensional objects");
449 res
= PyList_New(view
->len
);
453 for (i
= 0; i
< view
->len
; i
++) {
454 item
= PyInt_FromLong((unsigned char) *buf
);
459 PyList_SET_ITEM(res
, i
, item
);
465 static PyMethodDef memory_methods
[] = {
466 {"tobytes", (PyCFunction
)memory_tobytes
, METH_NOARGS
, NULL
},
467 {"tolist", (PyCFunction
)memory_tolist
, METH_NOARGS
, NULL
},
468 {NULL
, NULL
} /* sentinel */
473 memory_dealloc(PyMemoryViewObject
*self
)
475 _PyObject_GC_UNTRACK(self
);
476 if (self
->view
.obj
!= NULL
) {
477 if (self
->base
&& PyTuple_Check(self
->base
)) {
478 /* Special case when first element is generic object
479 with buffer interface and the second element is a
480 contiguous "shadow" that must be copied back into
481 the data areay of the first tuple element before
482 releasing the buffer on the first element.
485 PyObject_CopyData(PyTuple_GET_ITEM(self
->base
,0),
486 PyTuple_GET_ITEM(self
->base
,1));
488 /* The view member should have readonly == -1 in
489 this instance indicating that the memory can
490 be "locked" and was locked and will be unlocked
491 again after this call.
493 PyBuffer_Release(&(self
->view
));
496 PyBuffer_Release(&(self
->view
));
498 Py_CLEAR(self
->base
);
500 PyObject_GC_Del(self
);
504 memory_repr(PyMemoryViewObject
*self
)
506 return PyString_FromFormat("<memory at %p>", self
);
509 /* Sequence methods */
511 memory_length(PyMemoryViewObject
*self
)
513 return get_shape0(&self
->view
);
516 /* Alternate version of memory_subcript that only accepts indices.
517 Used by PySeqIter_New().
520 memory_item(PyMemoryViewObject
*self
, Py_ssize_t result
)
522 Py_buffer
*view
= &(self
->view
);
524 if (view
->ndim
== 0) {
525 PyErr_SetString(PyExc_IndexError
,
526 "invalid indexing of 0-dim memory");
529 if (view
->ndim
== 1) {
530 /* Return a bytes object */
532 ptr
= (char *)view
->buf
;
534 result
+= get_shape0(view
);
536 if ((result
< 0) || (result
>= get_shape0(view
))) {
537 PyErr_SetString(PyExc_IndexError
,
538 "index out of bounds");
541 if (view
->strides
== NULL
)
542 ptr
+= view
->itemsize
* result
;
544 ptr
+= view
->strides
[0] * result
;
545 if (view
->suboffsets
!= NULL
&&
546 view
->suboffsets
[0] >= 0) {
547 ptr
= *((char **)ptr
) + view
->suboffsets
[0];
549 return PyBytes_FromStringAndSize(ptr
, view
->itemsize
);
551 /* Return a new memory-view object */
553 memset(&newview
, 0, sizeof(newview
));
554 /* XXX: This needs to be fixed so it actually returns a sub-view */
555 return PyMemoryView_FromBuffer(&newview
);
560 mem[obj] returns a bytes object holding the data for one element if
561 obj fully indexes the memory view or another memory-view object
564 0-d memory-view objects can be referenced using ... or () but
565 not with anything else.
568 memory_subscript(PyMemoryViewObject
*self
, PyObject
*key
)
571 view
= &(self
->view
);
573 if (view
->ndim
== 0) {
574 if (key
== Py_Ellipsis
||
575 (PyTuple_Check(key
) && PyTuple_GET_SIZE(key
)==0)) {
577 return (PyObject
*)self
;
580 PyErr_SetString(PyExc_IndexError
,
581 "invalid indexing of 0-dim memory");
585 if (PyIndex_Check(key
)) {
587 result
= PyNumber_AsSsize_t(key
, NULL
);
588 if (result
== -1 && PyErr_Occurred())
590 return memory_item(self
, result
);
592 else if (PySlice_Check(key
)) {
593 Py_ssize_t start
, stop
, step
, slicelength
;
595 if (PySlice_GetIndicesEx((PySliceObject
*)key
, get_shape0(view
),
596 &start
, &stop
, &step
, &slicelength
) < 0) {
600 if (step
== 1 && view
->ndim
== 1) {
602 void *newbuf
= (char *) view
->buf
603 + start
* view
->itemsize
;
604 int newflags
= view
->readonly
605 ? PyBUF_CONTIG_RO
: PyBUF_CONTIG
;
607 /* XXX There should be an API to create a subbuffer */
608 if (view
->obj
!= NULL
) {
609 if (PyObject_GetBuffer(view
->obj
, &newview
, newflags
) == -1)
615 newview
.buf
= newbuf
;
616 newview
.len
= slicelength
* newview
.itemsize
;
617 newview
.format
= view
->format
;
618 newview
.shape
= &(newview
.smalltable
[0]);
619 newview
.shape
[0] = slicelength
;
620 newview
.strides
= &(newview
.itemsize
);
621 return PyMemoryView_FromBuffer(&newview
);
623 PyErr_SetNone(PyExc_NotImplementedError
);
626 PyErr_Format(PyExc_TypeError
,
627 "cannot index memory using \"%.200s\"",
628 key
->ob_type
->tp_name
);
633 /* Need to support assigning memory if we can */
635 memory_ass_sub(PyMemoryViewObject
*self
, PyObject
*key
, PyObject
*value
)
637 Py_ssize_t start
, len
, bytelen
, i
;
639 Py_buffer
*view
= &(self
->view
);
640 char *srcbuf
, *destbuf
;
642 if (view
->readonly
) {
643 PyErr_SetString(PyExc_TypeError
,
644 "cannot modify read-only memory");
647 if (view
->ndim
!= 1) {
648 PyErr_SetNone(PyExc_NotImplementedError
);
651 if (PyIndex_Check(key
)) {
652 start
= PyNumber_AsSsize_t(key
, NULL
);
653 if (start
== -1 && PyErr_Occurred())
656 start
+= get_shape0(view
);
658 if ((start
< 0) || (start
>= get_shape0(view
))) {
659 PyErr_SetString(PyExc_IndexError
,
660 "index out of bounds");
665 else if (PySlice_Check(key
)) {
666 Py_ssize_t stop
, step
;
668 if (PySlice_GetIndicesEx((PySliceObject
*)key
, get_shape0(view
),
669 &start
, &stop
, &step
, &len
) < 0) {
673 PyErr_SetNone(PyExc_NotImplementedError
);
678 PyErr_Format(PyExc_TypeError
,
679 "cannot index memory using \"%.200s\"",
680 key
->ob_type
->tp_name
);
683 if (PyObject_GetBuffer(value
, &srcview
, PyBUF_CONTIG_RO
) == -1) {
686 /* XXX should we allow assignment of different item sizes
687 as long as the byte length is the same?
688 (e.g. assign 2 shorts to a 4-byte slice) */
689 if (srcview
.itemsize
!= view
->itemsize
) {
690 PyErr_Format(PyExc_TypeError
,
691 "mismatching item sizes for \"%.200s\" and \"%.200s\"",
692 view
->obj
->ob_type
->tp_name
, srcview
.obj
->ob_type
->tp_name
);
695 bytelen
= len
* view
->itemsize
;
696 if (bytelen
!= srcview
.len
) {
697 PyErr_SetString(PyExc_ValueError
,
698 "cannot modify size of memoryview object");
701 /* Do the actual copy */
702 destbuf
= (char *) view
->buf
+ start
* view
->itemsize
;
703 srcbuf
= (char *) srcview
.buf
;
704 if (destbuf
+ bytelen
< srcbuf
|| srcbuf
+ bytelen
< destbuf
)
706 memcpy(destbuf
, srcbuf
, bytelen
);
707 else if (destbuf
< srcbuf
) {
708 /* Copy in ascending order */
709 for (i
= 0; i
< bytelen
; i
++)
710 destbuf
[i
] = srcbuf
[i
];
713 /* Copy in descencing order */
714 for (i
= bytelen
- 1; i
>= 0; i
--)
715 destbuf
[i
] = srcbuf
[i
];
718 PyBuffer_Release(&srcview
);
722 PyBuffer_Release(&srcview
);
727 memory_richcompare(PyObject
*v
, PyObject
*w
, int op
)
735 if (op
!= Py_EQ
&& op
!= Py_NE
)
737 if (PyObject_GetBuffer(v
, &vv
, PyBUF_CONTIG_RO
) == -1) {
741 if (PyObject_GetBuffer(w
, &ww
, PyBUF_CONTIG_RO
) == -1) {
746 if (vv
.itemsize
!= ww
.itemsize
|| vv
.len
!= ww
.len
)
749 equal
= !memcmp(vv
.buf
, ww
.buf
, vv
.len
);
752 PyBuffer_Release(&vv
);
753 PyBuffer_Release(&ww
);
754 if ((equal
&& op
== Py_EQ
) || (!equal
&& op
== Py_NE
))
762 PyBuffer_Release(&vv
);
763 PyBuffer_Release(&ww
);
764 Py_INCREF(Py_NotImplemented
);
765 return Py_NotImplemented
;
770 memory_traverse(PyMemoryViewObject
*self
, visitproc visit
, void *arg
)
772 if (self
->base
!= NULL
)
773 Py_VISIT(self
->base
);
774 if (self
->view
.obj
!= NULL
)
775 Py_VISIT(self
->view
.obj
);
780 memory_clear(PyMemoryViewObject
*self
)
782 Py_CLEAR(self
->base
);
783 PyBuffer_Release(&self
->view
);
789 static PyMappingMethods memory_as_mapping
= {
790 (lenfunc
)memory_length
, /* mp_length */
791 (binaryfunc
)memory_subscript
, /* mp_subscript */
792 (objobjargproc
)memory_ass_sub
, /* mp_ass_subscript */
795 static PySequenceMethods memory_as_sequence
= {
799 (ssizeargfunc
)memory_item
, /* sq_item */
803 static PyBufferProcs memory_as_buffer
= {
804 0, /* bf_getreadbuffer */
805 0, /* bf_getwritebuffer */
806 0, /* bf_getsegcount */
807 0, /* bf_getcharbuffer */
808 (getbufferproc
)memory_getbuf
, /* bf_getbuffer */
809 (releasebufferproc
)memory_releasebuf
, /* bf_releasebuffer */
813 PyTypeObject PyMemoryView_Type
= {
814 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
816 sizeof(PyMemoryViewObject
),
818 (destructor
)memory_dealloc
, /* tp_dealloc */
823 (reprfunc
)memory_repr
, /* tp_repr */
824 0, /* tp_as_number */
825 &memory_as_sequence
, /* tp_as_sequence */
826 &memory_as_mapping
, /* tp_as_mapping */
830 PyObject_GenericGetAttr
, /* tp_getattro */
832 &memory_as_buffer
, /* tp_as_buffer */
833 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
|
834 Py_TPFLAGS_HAVE_NEWBUFFER
, /* tp_flags */
835 memory_doc
, /* tp_doc */
836 (traverseproc
)memory_traverse
, /* tp_traverse */
837 (inquiry
)memory_clear
, /* tp_clear */
838 memory_richcompare
, /* tp_richcompare */
839 0, /* tp_weaklistoffset */
842 memory_methods
, /* tp_methods */
844 memory_getsetlist
, /* tp_getset */
847 0, /* tp_descr_get */
848 0, /* tp_descr_set */
849 0, /* tp_dictoffset */
852 memory_new
, /* tp_new */