[Python-3000-checkins] r56893 - in python/branches/py3k-buffer: Include/Python.h Include/abstract.h Include/memoryobject.h Include/object.h Makefile.pre.in Modules/_sre.c Modules/arraymodule.c Objects/abstract.c Objects/bufferobject.c Objects/bytesobject.c Objects/exceptions.c Objects/memoryobject.c Objects/typeobject.c Objects/unicodeobject.c Python/bltinmodule.c Python/getargs.c Python/marshal.c
travis.oliphant
python-3000-checkins at python.org
Fri Aug 10 10:52:53 CEST 2007
Author: travis.oliphant
Date: Fri Aug 10 10:52:52 2007
New Revision: 56893
Added:
python/branches/py3k-buffer/Objects/memoryobject.c (contents, props changed)
Modified:
python/branches/py3k-buffer/Include/Python.h
python/branches/py3k-buffer/Include/abstract.h
python/branches/py3k-buffer/Include/memoryobject.h
python/branches/py3k-buffer/Include/object.h
python/branches/py3k-buffer/Makefile.pre.in
python/branches/py3k-buffer/Modules/_sre.c
python/branches/py3k-buffer/Modules/arraymodule.c
python/branches/py3k-buffer/Objects/abstract.c
python/branches/py3k-buffer/Objects/bufferobject.c
python/branches/py3k-buffer/Objects/bytesobject.c
python/branches/py3k-buffer/Objects/exceptions.c
python/branches/py3k-buffer/Objects/typeobject.c
python/branches/py3k-buffer/Objects/unicodeobject.c
python/branches/py3k-buffer/Python/bltinmodule.c
python/branches/py3k-buffer/Python/getargs.c
python/branches/py3k-buffer/Python/marshal.c
Log:
More changes to new buffer code with memory object.
Modified: python/branches/py3k-buffer/Include/Python.h
==============================================================================
--- python/branches/py3k-buffer/Include/Python.h (original)
+++ python/branches/py3k-buffer/Include/Python.h Fri Aug 10 10:52:52 2007
@@ -77,6 +77,7 @@
#include "rangeobject.h"
#include "stringobject.h"
#include "bufferobject.h"
+#include "memoryobject.h"
#include "tupleobject.h"
#include "listobject.h"
#include "dictobject.h"
Modified: python/branches/py3k-buffer/Include/abstract.h
==============================================================================
--- python/branches/py3k-buffer/Include/abstract.h (original)
+++ python/branches/py3k-buffer/Include/abstract.h Fri Aug 10 10:52:52 2007
@@ -536,8 +536,8 @@
/* new buffer API */
#define PyObject_CheckBuffer(obj) \
- (((obj)->tp_as_buffer != NULL) && \
- ((obj)->tp_as_buffer->bf_getbuffer != NULL))
+ (((obj)->ob_type->tp_as_buffer != NULL) && \
+ ((obj)->ob_type->tp_as_buffer->bf_getbuffer != NULL))
/* Return 1 if the getbuffer function is available, otherwise
return 0 */
@@ -552,7 +552,7 @@
*/
- PyAPI_FUNC(int) PyObject_ReleaseBuffer(PyObject *obj, PyBuffer *view);
+ PyAPI_FUNC(void) PyObject_ReleaseBuffer(PyObject *obj, PyBuffer *view);
/* C-API version of the releasebuffer function call. It
@@ -570,40 +570,25 @@
buffer
*/
+ PyAPI_FUNC(void *) PyBuffer_GetPointer(PyBuffer *view, Py_ssize_t *indices);
+
+ /* Get the memory area pointed to by the indices for the buffer given.
+ Note that view->ndim is the assumed size of indices
+ */
+
PyAPI_FUNC(int) PyBuffer_SizeFromFormat(const char *);
/* Return the implied itemsize of the data-format area from a
struct-style description */
- PyAPI_FUNC(int) PyObject_GetContiguous(PyObject *obj, void **buf,
- Py_ssize_t *len, char **format,
- char fortran);
-
- /* Return a contiguous chunk of memory representing the buffer
- from an object. If a copy is made then return 1 (the
- return variable should be checked so the memory can be
- freed if needed after the caller is done with it). If no
- copy was needed return 0. If an error occurred in probing
- the buffer interface then return -1.
-
- The contiguous chunck of memory is pointed to by *buf and
- the length of that memory is *len. The format of that
- memory is returned in struct-string syntax in *format.
-
- If the object is multi-dimensional and if fortran is 'F',
- the first dimension of the underlying array will vary the
- fastest in the buffer. If fortran is 'C', then the last
- dimension will vary the fastest (C-style contiguous). If
- fortran is 'A', then it does not matter and you will get
- whatever the object decides is more efficient.
-
- If a copy is made, then the memory *must be freed* by
- calling PyMem_Free when the user of this sub-routine is
- done with the memory
- */
+
- PyAPI_FUNC(int) PyObject_CopyToObject(PyObject *obj, void *buf,
- Py_ssize_t len, char fortran);
+ PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, PyBuffer *view,
+ Py_ssize_t len, char fort);
+
+ PyAPI_FUNC(int) PyBuffer_FromContiguous(PyBuffer *view, void *buf,
+ Py_ssize_t len, char fort);
+
/* Copy len bytes of data from the contiguous chunk of memory
pointed to by buf into the buffer exported by obj. Return
@@ -629,11 +614,11 @@
PyAPI_FUNC(int) PyBuffer_IsContiguous(PyBuffer *view, char fortran);
- PyAPI_FUNC(void) PyBuffer_FillContiguousStrides(int *ndims,
+ PyAPI_FUNC(void) PyBuffer_FillContiguousStrides(int ndims,
Py_ssize_t *shape,
Py_ssize_t *strides,
int itemsize,
- char fortran);
+ char fort);
/* Fill the strides array with byte-strides of a contiguous
(Fortran-style if fortran is 'F' or C-style otherwise)
Modified: python/branches/py3k-buffer/Include/memoryobject.h
==============================================================================
--- python/branches/py3k-buffer/Include/memoryobject.h (original)
+++ python/branches/py3k-buffer/Include/memoryobject.h Fri Aug 10 10:52:52 2007
@@ -8,28 +8,60 @@
#endif
typedef struct {
- PyObject_HEAD
- PyObject *base;
- int ndims;
- Py_ssize_t *starts; /* slice starts */
- Py_ssize_t *stops; /* slice stops */
- Py_ssize_t *steps; /* slice steps */
+ PyObject_HEAD
+ PyObject *base;
+ PyBuffer view;
} PyMemoryViewObject;
PyAPI_DATA(PyTypeObject) PyMemoryView_Type;
#define PyMemory_Check(op) (Py_Type(op) == &PyMemoryView_Type)
+#define PyMemoryView(op) (((PyMemoryViewObject *)(op))->view)
#define Py_END_OF_MEMORY (-1)
-PyAPI_FUNC(PyObject *) PyObject_GetMemoryView(PyObject *base);
+PyAPI_FUNC(PyObject *) PyMemoryView_GetContiguous(PyObject *base, int buffertype,
+ char fort);
-PyAPI_FUNC(PyObject *) PyMemoryView_FromMemory(PyBuffer *info);
+ /* Return a contiguous chunk of memory representing the buffer
+ from an object in a memory view object. If a copy is made then the
+ base object for the memory view will be a *new* bytes object.
+
+ Otherwise, the base-object will be the object itself and no
+ data-copying will be done.
+
+ The buffertype argument can be PyBUF_READ, PyBUF_WRITE,
+ PyBUF_UPDATEIFCOPY to determine whether the returned buffer
+ should be READONLY, WRITEABLE, or set to update the
+ original buffer if a copy must be made. If buffertype is
+ PyBUF_WRITE and the buffer is not contiguous an error will
+ be raised. In this circumstance, the user can use
+ PyBUF_UPDATEIFCOPY to ensure that a a writeable temporary
+ contiguous buffer is returned. The contents of this
+ contiguous buffer will be copied back into the original
+ object after the memoryview object is deleted as long as
+ the original object is writeable and allows setting its
+ memory to "readonly". If this is not allowed by the
+ original object, then a BufferError is raised.
+
+ If the object is multi-dimensional and if fortran is 'F',
+ the first dimension of the underlying array will vary the
+ fastest in the buffer. If fortran is 'C', then the last
+ dimension will vary the fastest (C-style contiguous). If
+ fortran is 'A', then it does not matter and you will get
+ whatever the object decides is more efficient.
+
+ A new reference is returned that must be DECREF'd when finished.
+ */
+
+PyAPI_FUNC(PyObject *) PyMemoryView_FromObject(PyObject *base);
+
+PyAPI_FUNC(PyObject *) PyMemoryView_FromMemory(PyBuffer *info);
/* create new if bufptr is NULL
will be a new bytesobject in base */
#ifdef __cplusplus
}
#endif
-#endif /* !Py_BUFFEROBJECT_H */
+#endif /* !Py_MEMORYOBJECT_H */
Modified: python/branches/py3k-buffer/Include/object.h
==============================================================================
--- python/branches/py3k-buffer/Include/object.h (original)
+++ python/branches/py3k-buffer/Include/object.h Fri Aug 10 10:52:52 2007
@@ -142,11 +142,11 @@
/* buffer interface */
-struct bufferinfo {
+typedef struct bufferinfo {
void *buf;
Py_ssize_t len;
int readonly;
- const char *format;
+ char *format;
int ndim;
Py_ssize_t *shape;
Py_ssize_t *strides;
@@ -187,6 +187,10 @@
#define PyBUF_FULL_LCK (PyBUF_ALW_INDIRECT | PyBUF_REQ_LOCKDATA | PyBUF_REQ_FORMAT)
+#define PyBUF_READ 0x100
+#define PyBUF_WRITE 0x200
+#define PyBUF_SHADOW 0x400
+
/* End buffer interface */
typedef int (*objobjproc)(PyObject *, PyObject *);
Modified: python/branches/py3k-buffer/Makefile.pre.in
==============================================================================
--- python/branches/py3k-buffer/Makefile.pre.in (original)
+++ python/branches/py3k-buffer/Makefile.pre.in Fri Aug 10 10:52:52 2007
@@ -301,6 +301,7 @@
Objects/listobject.o \
Objects/longobject.o \
Objects/dictobject.o \
+ Objects/memoryobject.o \
Objects/methodobject.o \
Objects/moduleobject.o \
Objects/object.o \
@@ -534,6 +535,7 @@
Include/iterobject.h \
Include/listobject.h \
Include/longobject.h \
+ Include/memoryobject.h \
Include/methodobject.h \
Include/modsupport.h \
Include/moduleobject.h \
Modified: python/branches/py3k-buffer/Modules/_sre.c
==============================================================================
--- python/branches/py3k-buffer/Modules/_sre.c (original)
+++ python/branches/py3k-buffer/Modules/_sre.c Fri Aug 10 10:52:52 2007
@@ -1672,6 +1672,7 @@
Py_ssize_t size, bytes;
int charsize;
void* ptr;
+ PyBuffer view;
#if defined(HAVE_UNICODE)
if (PyUnicode_Check(string)) {
@@ -1686,14 +1687,16 @@
/* get pointer to string buffer */
buffer = Py_Type(string)->tp_as_buffer;
- if (!buffer || !buffer->bf_getreadbuffer || !buffer->bf_getsegcount ||
- buffer->bf_getsegcount(string, NULL) != 1) {
- PyErr_SetString(PyExc_TypeError, "expected string or buffer");
- return NULL;
+ if (!buffer || !buffer->bf_getbuffer ||
+ (*buffer->bf_getbuffer)(string, &view, PyBUF_SIMPLE) !=0) {
+ PyErr_SetString(PyExc_TypeError, "expected string or buffer");
+ return NULL;
}
+
/* determine buffer size */
- bytes = buffer->bf_getreadbuffer(string, 0, &ptr);
+ bytes = view.len;
+ ptr = view.buf;
if (bytes < 0) {
PyErr_SetString(PyExc_TypeError, "buffer has negative size");
return NULL;
Modified: python/branches/py3k-buffer/Modules/arraymodule.c
==============================================================================
--- python/branches/py3k-buffer/Modules/arraymodule.c (original)
+++ python/branches/py3k-buffer/Modules/arraymodule.c Fri Aug 10 10:52:52 2007
@@ -1745,6 +1745,8 @@
"Cannot lock data");
return -1;
}
+ if (view==NULL) goto finish;
+
view->buf = (void *)self->ob_item;
view->len = Py_Size(self)*self->ob_descr->itemsize;
view->readonly = 0;
@@ -1768,6 +1770,8 @@
}
else
view->format = NULL;
+
+ finish:
self->ob_exports++;
return 0;
}
Modified: python/branches/py3k-buffer/Objects/abstract.c
==============================================================================
--- python/branches/py3k-buffer/Objects/abstract.c (original)
+++ python/branches/py3k-buffer/Objects/abstract.c Fri Aug 10 10:52:52 2007
@@ -221,8 +221,6 @@
Py_ssize_t *buffer_len)
{
PyBufferProcs *pb;
- char *pp;
- Py_ssize_t len;
PyBuffer view;
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
@@ -230,18 +228,17 @@
return -1;
}
pb = obj->ob_type->tp_as_buffer;
- if (pb == NULL || pb->bf_getbuffer == NULL)
+ if (pb == NULL || pb->bf_getbuffer == NULL) {
PyErr_SetString(PyExc_TypeError,
"expected an object with the buffer interface");
return -1;
- }
+ }
if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE)) return -1;
*buffer = view.buf;
*buffer_len = view.len;
- if (pb->bf_releasebuffer != NULL ||
- ((*pb->bf_releasebuffer)(obj, &view) != 0)) {
- return -1;
+ if (pb->bf_releasebuffer != NULL) {
+ (*pb->bf_releasebuffer)(obj, &view);
}
return 0;
}
@@ -258,11 +255,8 @@
PyErr_Clear();
return 0;
}
- if (*pb->bf_releasebuffer != NULL ||
- ((*pb->bf_releasebuffer)(obj, NULL) != 0)) {
- PyErr_Clear();
- return 0;
- }
+ if (*pb->bf_releasebuffer != NULL)
+ (*pb->bf_releasebuffer)(obj, NULL);
return 1;
}
@@ -271,7 +265,6 @@
Py_ssize_t *buffer_len)
{
PyBufferProcs *pb;
- Py_ssize_t len;
PyBuffer view;
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
@@ -280,7 +273,7 @@
}
pb = obj->ob_type->tp_as_buffer;
if (pb == NULL ||
- pb->bf_getbuffer == NULL)
+ pb->bf_getbuffer == NULL) {
PyErr_SetString(PyExc_TypeError,
"expected an object with a buffer interface");
return -1;
@@ -290,10 +283,8 @@
*buffer = view.buf;
*buffer_len = view.len;
- if (pb->bf_releasebuffer != NULL ||
- ((*pb->bf_releasebuffer)(obj, &view) != 0)) {
- return -1;
- }
+ if (pb->bf_releasebuffer != NULL)
+ (*pb->bf_releasebuffer)(obj, &view);
return 0;
}
@@ -302,7 +293,6 @@
Py_ssize_t *buffer_len)
{
PyBufferProcs *pb;
- Py_ssize_t len;
PyBuffer view;
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
@@ -312,7 +302,7 @@
pb = obj->ob_type->tp_as_buffer;
if (pb == NULL ||
pb->bf_getbuffer == NULL ||
- ((*pb->bf_getbuffer)(obj, &view, PyBUF_REQ_WRITEABLE) != 0))
+ ((*pb->bf_getbuffer)(obj, &view, PyBUF_REQ_WRITEABLE) != 0)) {
PyErr_SetString(PyExc_TypeError,
"expected an object with a writeable buffer interface");
return -1;
@@ -320,10 +310,8 @@
*buffer = view.buf;
*buffer_len = view.len;
- if (pb->bf_releasebuffer != NULL ||
- ((*pb->bf_releasebuffer)(obj, &view) != 0)) {
- return -1;
- }
+ if (pb->bf_releasebuffer != NULL)
+ (*pb->bf_releasebuffer)(obj, &view);
return 0;
}
@@ -332,37 +320,37 @@
int
PyObject_GetBuffer(PyObject *obj, PyBuffer *view, int flags)
{
- if !PyObject_CheckBuffer(obj) {
+ if (!PyObject_CheckBuffer(obj)) {
PyErr_SetString(PyExc_TypeError,
"object does not have the buffer interface");
return -1;
}
- return (*(obj->tp_as_buffer->bf_getbuffer))(obj, view, flags);
+ return (*(obj->ob_type->tp_as_buffer->bf_getbuffer))(obj, view, flags);
}
void
PyObject_ReleaseBuffer(PyObject *obj, PyBuffer *view)
{
- if (obj->tp_as_buffer != NULL &&
- obj->tp_as_buffer->bf_releasebuffer != NULL) {
- (*(obj->tp_as_buffer->bf_releasebuffer))(obj, view);
+ if (obj->ob_type->tp_as_buffer != NULL &&
+ obj->ob_type->tp_as_buffer->bf_releasebuffer != NULL) {
+ (*(obj->ob_type->tp_as_buffer->bf_releasebuffer))(obj, view);
}
}
static int
-_IsFortranContiguous(PyBuffer *view);
+_IsFortranContiguous(PyBuffer *view)
{
Py_ssize_t sd, dim;
int i;
- if (view->nd == 0) return 1;
- if (view->strides == NULL) return (view->nd == 1);
+ if (view->ndim == 0) return 1;
+ if (view->strides == NULL) return (view->ndim == 1);
sd = view->itemsize;
- if (view->nd == 1) return (view->shape[0] == 1 ||
+ if (view->ndim == 1) return (view->shape[0] == 1 ||
sd == view->strides[0]);
- for (i=0; i<view->nd; i++) {
+ for (i=0; i<view->ndim; i++) {
dim = view->shape[i];
if (dim == 0) return 1;
if (view->strides[i] != sd) return 0;
@@ -372,18 +360,18 @@
}
static int
-_IsCContiguous(PyBuffer *view);
+_IsCContiguous(PyBuffer *view)
{
Py_ssize_t sd, dim;
int i;
- if (view->nd == 0) return 1;
+ if (view->ndim == 0) return 1;
if (view->strides == NULL) return 1;
sd = view->itemsize;
- if (view->nd == 1) return (view->shape[0] == 1 ||
+ if (view->ndim == 1) return (view->shape[0] == 1 ||
sd == view->strides[0]);
- for (i=view->nd-1; i>=0; i--) {
+ for (i=view->ndim-1; i>=0; i--) {
dim = view->shape[i];
if (dim == 0) return 1;
if (view->strides[i] != sd) return 0;
@@ -407,66 +395,24 @@
return 0;
}
-static void
-_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
- Py_ssize_t *strides, int itemsize, char fort)
-{
- int k;
- Py_ssize_t outstride;
- char *ptr;
- if (nd==0) {
- memcpy(dest, src, itemsize);
- }
- else if (nd == 1) {
- for (k = 0; k<shape[0]; k++) {
- memcpy(dest, src, itemsize);
- dest += itemsize;
- src += strides[0];
- }
- }
- else {
- if (fort == 'F') {
- /* Copy first dimension first,
- second dimension second, etc...
- Set up the recursive loop backwards so that final
- dimension is actually copied last.
- */
- outstride = itemsize;
- for (k=1; k<nd-1;k++) {
- outstride *= shape[k];
- }
- for (k=0; k<shape[nd-1]; k++) {
- _strided_copy_nd(dest, src, nd-1, shape,
- strides, suboffsets, itemsize, fort);
- dest += outstride;
- src += strides[nd-1];
- }
- }
-
- else {
- /* Copy last dimension first,
- second-to-last dimension second, etc.
- Set up the recursion so that the
- first dimension is copied last
- */
- outstride = itemsize;
- for (k=1; k < nd; k++) {
- outstride *= shape[k];
- }
- for (k=0; k<shape[0]; k++) {
- _strided_copy_nd(dest, src, nd-1, shape+1,
- strides+1, suboffsets+1, itemsize,
- fort);
- dest += outstride;
- src += strides[0];
- }
+void*
+PyBuffer_GetPointer(PyBuffer *view, Py_ssize_t *indices)
+{
+ char* pointer;
+ int i;
+ pointer = (char *)view->buf;
+ for (i = 0; i < view->ndim; i++) {
+ pointer += view->strides[i]*indices[i];
+ if ((view->suboffsets != NULL) && (view->suboffsets[i] >= 0)) {
+ pointer = *((char**)pointer) + view->suboffsets[i];
}
}
- return;
+ return (void*)pointer;
}
-static void
+
+void
_add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape)
{
int k;
@@ -482,7 +428,7 @@
}
}
-static void
+void
_add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape)
{
int k;
@@ -498,33 +444,32 @@
}
}
-static void*
-get_item_pointer(PyBuffer *view, Py_ssize_t *indices)
-{
- char* pointer;
- int i;
- pointer = (char *)view->buf;
- for (i = 0; i < view->ndim; i++) {
- pointer += view->strides[i]*indices[i];
- if ((view->suboffsets != NULL) && (view->suboffsets[i] >= 0)) {
- pointer = *((char**)pointer) + view->suboffsets[i];
- }
- }
- return (void*)pointer;
-}
-
+ /* view is not checked for consistency in either of these. It is
+ assumed that the size of the buffer is view->len in
+ view->len / view->itemsize elements.
+ */
-static int
-_indirect_copy_nd(char *dest, PyBuffer *view, char fort)
+int
+PyBuffer_ToContiguous(void *buf, PyBuffer *view, Py_ssize_t len, char fort)
{
- Py_ssize_t *indices;
int k;
- Py_ssize_t elements;
- char *ptr;
- void (*func)(int, Py_ssize_t *, Py_ssize_t *);
+ void (*addone)(int, Py_ssize_t *, Py_ssize_t *);
+ Py_ssize_t *indices, elements;
+ char *dest, *ptr;
+
+ if (len > view->len) {
+ len = view->len;
+ }
+ if (PyBuffer_IsContiguous(view, fort)) {
+ /* simplest copy is all that is needed */
+ memcpy(buf, view->buf, len);
+ return 0;
+ }
+
+ /* Otherwise a more elaborate scheme is needed */
- indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
+ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim));
if (indices == NULL) {
PyErr_NoMemory();
return -1;
@@ -533,134 +478,56 @@
indices[k] = 0;
}
- elements = 1;
- for (k=0; k<view->ndim; k++) {
- elements *= view->shape[k];
- }
if (fort == 'F') {
- func = _add_one_to_index_F;
+ addone = _add_one_to_index_F;
}
else {
- func = _add_one_to_index_C;
+ addone = _add_one_to_index_C;
}
+ dest = buf;
+ /* XXX : This is not going to be the fastest code in the world
+ several optimizations are possible.
+ */
+ elements = len / view->itemsize;
while (elements--) {
- func(view->ndim, indices, view->shape);
- ptr = get_item_pointer(view, indices);
+ addone(view->ndim, indices, view->shape);
+ ptr = PyBuffer_GetPointer(view, indices);
memcpy(dest, ptr, view->itemsize);
- dest += itemsize;
- }
-
+ dest += view->itemsize;
+ }
PyMem_Free(indices);
return 0;
}
-/* Get a the data from an object as a contiguous chunk of memory even
- if it means copying it into a separate memory area.
-
- Make sure PyMem_Free is called on *buf if a copy is made.
- */
int
-PyObject_GetContiguous(PyObject *obj, void **buf, Py_ssize_t *len,
- char **format, int writeable, char fort)
+PyBuffer_FromContiguous(PyBuffer *view, void *buf, Py_ssize_t len, char fort)
{
- PyBuffer view;
- getbufferproc func;
- int flags;
-
- if !PyObject_CheckBuffer(obj) {
- PyErr_SetString(PyExc_TypeError,
- "object does not have the buffer interface");
- return -1;
- }
- func = obj->tp_as_buffer->bf_getbuffer;
-
- flags = (writeable ? PyBUF_FULL : PyBUF_FULL_RO);
- if (PyObject_GetBuffer(obj, &view, flags) != 0) return -1;
-
- *len = view.len;
- *format = view.format;
- if (PyBuffer_IsContiguous(&view, fort)) {
- /* no copy needed */
- *buf = view.buf;
- PyObject_ReleaseBuffer(obj, &view);
- return -1;
- }
- /* otherwise a copy is needed */
- *buf = PyMem_Malloc(*len);
- if (*buf == NULL) {
- PyObject_ReleaseBuffer(obj, &view);
- return -1;
- }
- /* different copying strategy depending on whether
- or not any pointer de-referencing is needed
- */
- /* strided or in-direct copy */
- if (suboffsets==NULL) {
- _strided_copy_nd(*buf, view.buf, view.ndim,
- view.shape, view.strides,
- view.itemsize, fort);
- }
- else {
- if (_indirect_copy_nd(*buf, &view, fort) < 0) {
- PyMem_Free(*buf);
- PyObject_ReleaseBuffer(obj, &view);
- return -1;
- }
- }
- PyObject_ReleaseBuffer(obj, &view);
- return 1;
-}
-
-int
-PyObject_CopyToObject(PyObject *obj, void *buf, Py_ssize_t len,
- char fort);
-{
- PyBuffer view;
- getbufferproc func;
int k;
void (*addone)(int, Py_ssize_t *, Py_ssize_t *);
Py_ssize_t *indices, elements;
- char *src;
-
- if !PyObject_CheckBuffer(obj) {
- PyErr_SetString(PyExc_TypeError,
- "object does not have the buffer interface");
- return -1;
- }
- func = obj->tp_as_buffer->bf_getbuffer;
-
- if (PyObject_GetBuffer(obj, &view, PyBUF_FULL) != 0) return -1;
+ char *src, *ptr;
- if (len > view.len) {
- PyErr_SetString(PyExc_BufferError,
- "object is too small to receive data");
- PyObject_ReleaseBuffer(obj, &view);
- return -1;
+ if (len > view->len) {
+ len = view->len;
}
- if (PyBuffer_IsContiguous(&view, fort)) {
+ if (PyBuffer_IsContiguous(view, fort)) {
/* simplest copy is all that is needed */
- memcpy(view.buf, buf, len);
- PyObject_ReleaseBuffer(obj, &view);
+ memcpy(view->buf, buf, len);
return 0;
}
/* Otherwise a more elaborate scheme is needed */
- indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
+ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*(view->ndim));
if (indices == NULL) {
PyErr_NoMemory();
- PyObject_ReleaseBuffer(obj, &view);
return -1;
}
for (k=0; k<view->ndim;k++) {
indices[k] = 0;
}
- elements = 1;
- for (k=0; k<view->ndim; k++) {
- elements *= view->shape[k];
- }
if (fort == 'F') {
addone = _add_one_to_index_F;
}
@@ -668,42 +535,41 @@
addone = _add_one_to_index_C;
}
src = buf;
+ /* XXX : This is not going to be the fastest code in the world
+ several optimizations are possible.
+ */
+ elements = len / view->itemsize;
while (elements--) {
addone(view->ndim, indices, view->shape);
- ptr = get_item_pointer(view, indices);
+ ptr = PyBuffer_GetPointer(view, indices);
memcpy(ptr, src, view->itemsize);
- src += itemsize;
+ src += view->itemsize;
}
PyMem_Free(indices);
- PyObject_ReleaseBuffer(obj, &view);
return 0;
}
-
-int PyObject_CopyData(PyObject *dest, PyObject *src) {
-
+int PyObject_CopyData(PyObject *dest, PyObject *src)
+{
PyBuffer view_dest, view_src;
getbufferproc func;
int k;
Py_ssize_t *indices, elements;
char *dptr, *sptr;
- if !PyObject_CheckBuffer(dest) {
- PyErr_SetString(PyExc_TypeError,
- "destination does not have the buffer interface");
- return -1;
- }
- if !PyObject_CheckBuffer(src) {
+ if (!PyObject_CheckBuffer(dest) ||
+ !PyObject_CheckBuffer(src)) {
PyErr_SetString(PyExc_TypeError,
- "source does not have the buffer interface");
+ "both destination and source must have the "\
+ "buffer interface");
return -1;
}
- func = dest->tp_as_buffer->bf_getbuffer;
+ func = Py_Type(dest)->tp_as_buffer->bf_getbuffer;
if (PyObject_GetBuffer(dest, &view_dest, PyBUF_FULL) != 0) return -1;
- func = src->tp_as_buffer->bf_getbuffer;
+ func = Py_Type(src)->tp_as_buffer->bf_getbuffer;
if (PyObject_GetBuffer(src, &view_src, PyBUF_FULL_RO) != 0) return -1;
if (view_dest.len < view_src.len) {
@@ -715,9 +581,9 @@
}
if ((PyBuffer_IsContiguous(&view_dest, 'C') &&
- PyBuffer_IsContiguous(&src_dest, 'C')) ||
+ PyBuffer_IsContiguous(&view_src, 'C')) ||
(PyBuffer_IsContiguous(&view_dest, 'F') &&
- PyBuffer_IsContiguous(&src_dest, 'F'))) {
+ PyBuffer_IsContiguous(&view_src, 'F'))) {
/* simplest copy is all that is needed */
memcpy(view_dest.buf, view_src.buf, view_src.len);
PyObject_ReleaseBuffer(dest, &view_dest);
@@ -727,27 +593,25 @@
/* Otherwise a more elaborate copy scheme is needed */
- indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
+ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view_src.ndim);
if (indices == NULL) {
PyErr_NoMemory();
PyObject_ReleaseBuffer(dest, &view_dest);
PyObject_ReleaseBuffer(src, &view_src);
return -1;
}
- for (k=0; k<view->ndim;k++) {
+ for (k=0; k<view_src.ndim;k++) {
indices[k] = 0;
}
elements = 1;
- for (k=0; k<view->ndim; k++) {
- elements *= view->shape[k];
+ for (k=0; k<view_src.ndim; k++) {
+ elements *= view_src.shape[k];
}
- src = buf;
while (elements--) {
- _add_one_to_index_C(view->ndim, indices, view->shape);
- dptr = get_item_pointer(view_dest, indices);
- sptr = get_item_pointer(view_src, indices);
- memcpy(dptr, sptr, view->itemsize);
- src += itemsize;
+ _add_one_to_index_C(view_src.ndim, indices, view_src.shape);
+ dptr = PyBuffer_GetPointer(&view_dest, indices);
+ sptr = PyBuffer_GetPointer(&view_src, indices);
+ memcpy(dptr, sptr, view_src.itemsize);
}
PyMem_Free(indices);
PyObject_ReleaseBuffer(dest, &view_dest);
@@ -755,8 +619,8 @@
return 0;
}
-static void
-PyBuffer_FillContiguousStrides(int *nd, Py_ssize_t *shape,
+void
+PyBuffer_FillContiguousStrides(int nd, Py_ssize_t *shape,
Py_ssize_t *strides, int itemsize,
char fort)
{
@@ -779,12 +643,14 @@
return;
}
-static int
+int
PyBuffer_FillInfo(PyBuffer *view, void *buf, Py_ssize_t len,
int readonly, int flags)
{
- if ((flags & PyBUF_REQ_LOCKDATA) == PyBUF_REQ_LOCKDATA && readonly != -1) {
- PyErr_SetString(PyExc_BufferError, "Cannot make this object read-only.");
+ if ((flags & PyBUF_REQ_LOCKDATA) == PyBUF_REQ_LOCKDATA &&
+ readonly != -1) {
+ PyErr_SetString(PyExc_BufferError,
+ "Cannot make this object read-only.");
return -1;
}
view->buf = buf;
Modified: python/branches/py3k-buffer/Objects/bufferobject.c
==============================================================================
--- python/branches/py3k-buffer/Objects/bufferobject.c (original)
+++ python/branches/py3k-buffer/Objects/bufferobject.c Fri Aug 10 10:52:52 2007
@@ -26,20 +26,20 @@
Py_ssize_t count, offset;
PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
PyBuffer view;
- if ((*bp->bf_getbuffer)(self->b_base, view, PyBUF_SIMPLE) < 0) return 0;
- count = view->len;
+ if ((*bp->bf_getbuffer)(self->b_base, &view, PyBUF_SIMPLE) < 0) return 0;
+ count = view.len;
/* apply constraints to the start/end */
if (self->b_offset > count)
offset = count;
else
offset = self->b_offset;
- view->buf = (char*)view->buf + offset;
+ view.buf = (char*)view.buf + offset;
if (self->b_size == Py_END_OF_BUFFER)
- view->len = count;
+ view.len = count;
else
- view->len = self->b_size;
- if (offset + view->len > count)
- view->len = count - offset;
+ view.len = self->b_size;
+ if (offset + view.len > count)
+ view.len = count - offset;
}
return 1;
}
@@ -48,23 +48,24 @@
static int
buffer_getbuf(PyBufferObject *self, PyBuffer *view, int flags)
{
+ if (view == NULL) return 0;
if (!get_buf(self, view))
return -1;
- return PyBuffer_FillInfo(view, view.buf, view.len, view.readonly, flags);
+ return PyBuffer_FillInfo(view, view->buf, view->len, view->readonly, flags);
}
-static int
+static void
buffer_releasebuf(PyBufferObject *self, PyBuffer *view)
{
/* No-op if there is no self->b_base */
if (self->b_base != NULL) {
PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
- if (bp->releasebuffer != NULL) {
- return (*bp->releasebuffer)(self->b_base, view);
+ if (bp->bf_releasebuffer != NULL) {
+ (*bp->bf_releasebuffer)(self->b_base, view);
}
}
- return 0;
+ return;
}
static PyObject *
@@ -259,7 +260,7 @@
if (!get_bufx(self, &v1))
ok = 0;
if (!get_bufx(other, &v2)) {
- if (ok) PyObject_ReleaseBuffer(self, v1);
+ if (ok) PyObject_ReleaseBuffer(self, &v1);
ok = 0;
}
if (!ok) {
@@ -285,8 +286,8 @@
if (cmp == 0)
cmp = (len1 < len2) ? -1 :
(len1 > len2) ? 1 : 0;
- PyObject_ReleaseBuffer(self, v1);
- PyObject_ReleaseBuffer(other, v2);
+ PyObject_ReleaseBuffer(self, &v1);
+ PyObject_ReleaseBuffer(other, &v2);
return Py_CmpToRich(op, cmp);
}
@@ -314,8 +315,6 @@
static long
buffer_hash(PyBufferObject *self)
{
- void *ptr;
- Py_ssize_t size;
PyBuffer view;
register Py_ssize_t len;
register unsigned char *p;
@@ -338,7 +337,7 @@
if (!(view.readonly)) {
PyErr_SetString(PyExc_TypeError,
"writable buffers are not hashable");
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return -1;
}
@@ -351,7 +350,7 @@
if (x == -1)
x = -2;
self->b_hash = x;
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return x;
}
@@ -364,7 +363,7 @@
if (!get_buf(self, &view))
return NULL;
res = PyString_FromStringAndSize((const char *)view.buf, view.len);
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return res;
}
@@ -377,7 +376,7 @@
if (!get_buf(self, &view))
return -1;
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return view.len;
}
@@ -386,7 +385,7 @@
{
PyBufferProcs *pb = other->ob_type->tp_as_buffer;
char *p;
- PyObject *ob, *ret=NULL;
+ PyObject *ob;
PyBuffer view, view2;
if ( pb == NULL ||
@@ -402,28 +401,28 @@
/* optimize special case */
/* XXX bad idea type-wise */
if ( view.len == 0 ) {
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
Py_INCREF(other);
return other;
}
- if (PyObject_GetBuffer(self, view2, PyBUF_SIMPLE) < 0) {
- PyObject_ReleaseBuffer(self, view);
+ if (PyObject_GetBuffer((PyObject *)self, &view2, PyBUF_SIMPLE) < 0) {
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return NULL;
}
ob = PyBytes_FromStringAndSize(NULL, view.len+view2.len);
if ( ob == NULL ) {
- PyObject_ReleaseBuffer(self, view);
- PyObject_ReleaseBuffer(other, view2);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
+ PyObject_ReleaseBuffer(other, &view2);
return NULL;
}
p = PyBytes_AS_STRING(ob);
memcpy(p, view.buf, view.len);
memcpy(p + view.len, view2.buf, view2.len);
- PyObject_ReleaseBuffer(self, view);
- PyObject_ReleaseBuffer(other, view2);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
+ PyObject_ReleaseBuffer(other, &view2);
return ob;
}
@@ -432,8 +431,6 @@
{
PyObject *ob;
register char *p;
- void *ptr;
- Py_ssize_t size;
PyBuffer view;
if ( count < 0 )
@@ -451,7 +448,7 @@
p += view.len;
}
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return ob;
}
@@ -468,13 +465,14 @@
return NULL;
}
ob = PyBytes_FromStringAndSize((char *)view.buf + idx, 1);
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return ob;
}
static PyObject *
buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
{
+ PyObject *ob;
PyBuffer view;
if (!get_buf(self, &view))
return NULL;
@@ -482,13 +480,13 @@
left = 0;
if ( right < 0 )
right = 0;
- if ( right > size )
- right = size;
+ if ( right > view.len )
+ right = view.len;
if ( right < left )
right = left;
ob = PyBytes_FromStringAndSize((char *)view.buf + left,
right - left);
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return ob;
}
@@ -504,7 +502,7 @@
if ( self->b_readonly || view.readonly ) {
PyErr_SetString(PyExc_TypeError,
"buffer is read-only");
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return -1;
}
@@ -518,25 +516,25 @@
if ( pb == NULL ||
pb->bf_getbuffer == NULL) {
PyErr_BadArgument();
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return -1;
}
if (PyObject_GetBuffer(other, &view2, PyBUF_SIMPLE) < 0) {
- PyObject_ReleaseBuffer(self, view);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
return -1;
}
if ( view.len != 1 ) {
- PyObject_ReleaseBuffer(self, view);
- PyObject_ReleaseBuffer(other, view2);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
+ PyObject_ReleaseBuffer(other, &view2);
PyErr_SetString(PyExc_TypeError,
"right operand must be a single byte");
return -1;
}
((char *)(view.buf))[idx] = *((char *)(view2.buf));
- PyObject_ReleaseBuffer(self, view);
- PyObject_ReleaseBuffer(other, view2);
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
+ PyObject_ReleaseBuffer(other, &view2);
return 0;
}
@@ -560,23 +558,23 @@
if ( self->b_readonly || v1.readonly) {
PyErr_SetString(PyExc_TypeError,
"buffer is read-only");
- PyObject_ReleaseBuffer(self, v1);
+ PyObject_ReleaseBuffer((PyObject *)self, &v1);
return -1;
}
if ((*pb->bf_getbuffer)(other, &v2, PyBUF_SIMPLE) < 0) {
- PyObject_ReleaseBuffer(self, v1);
+ PyObject_ReleaseBuffer((PyObject *)self, &v1);
return -1;
}
if ( left < 0 )
left = 0;
- else if ( left > size )
- left = size;
+ else if ( left > v1.len )
+ left = v1.len;
if ( right < left )
right = left;
- else if ( right > size )
- right = size;
+ else if ( right > v1.len )
+ right = v1.len;
slice_len = right - left;
if ( v2.len != slice_len ) {
@@ -589,8 +587,8 @@
if ( slice_len )
memcpy((char *)v1.buf + left, v2.buf, slice_len);
- PyObject_ReleaseBuffer(self, v1);
- PyObject_ReleaseBuffer(other, v2);
+ PyObject_ReleaseBuffer((PyObject *)self, &v1);
+ PyObject_ReleaseBuffer(other, &v2);
return 0;
}
Modified: python/branches/py3k-buffer/Objects/bytesobject.c
==============================================================================
--- python/branches/py3k-buffer/Objects/bytesobject.c (original)
+++ python/branches/py3k-buffer/Objects/bytesobject.c Fri Aug 10 10:52:52 2007
@@ -53,6 +53,10 @@
bytes_getbuffer(PyBytesObject *obj, PyBuffer *view, int flags)
{
int ret;
+ if (view == NULL) {
+ obj->ob_exports++;
+ return 0;
+ }
ret = PyBuffer_FillInfo(view, obj->ob_bytes, Py_Size(obj), 0, flags);
if (ret >= 0) {
obj->ob_exports++;
@@ -785,16 +789,26 @@
return 0;
}
- /* XXX -> Use the modern buffer interface */
- if (PyObject_CheckReadBuffer(arg)) {
- const void *bytes;
+ /* Use the modern buffer interface */
+ if (PyObject_CheckBuffer(arg)) {
Py_ssize_t size;
- if (PyObject_AsReadBuffer(arg, &bytes, &size) < 0)
- return -1;
- if (PyBytes_Resize((PyObject *)self, size) < 0)
+ PyBuffer view;
+ if (PyObject_GetBuffer(arg, &view, PyBUF_FULL) < 0)
return -1;
- memcpy(self->ob_bytes, bytes, size);
+ if (view.readonly == 1) {
+ PyErr_SetString(PyExc_BufferError,
+ "Cannot create a mutable bytes object");
+ goto fail;
+ }
+ size = view.len;
+ if (PyBytes_Resize((PyObject *)self, size) < 0) goto fail;
+ if (PyBuffer_ToContiguous(self->ob_bytes, &view, size, 'C') < 0)
+ goto fail;
+ PyObject_ReleaseBuffer(arg, &view);
return 0;
+ fail:
+ PyObject_ReleaseBuffer(arg, &view);
+ return -1;
}
/* XXX Optimize this if the arguments is a list, tuple */
@@ -923,7 +937,7 @@
bytes_richcompare(PyObject *self, PyObject *other, int op)
{
Py_ssize_t self_size, other_size;
- void *self_bytes, *other_bytes;
+ PyBuffer self_bytes, other_bytes;
PyObject *res;
Py_ssize_t minsize;
int cmp;
@@ -952,7 +966,7 @@
if (other_size < minsize)
minsize = other_size;
- cmp = memcmp(self_bytes, other_bytes, minsize);
+ cmp = memcmp(self_bytes.buf, other_bytes.buf, minsize);
/* In ISO C, memcmp() guarantees to use unsigned bytes! */
if (cmp == 0) {
@@ -986,25 +1000,6 @@
Py_Type(self)->tp_free((PyObject *)self);
}
-static Py_ssize_t
-bytes_getbuffer(PyBytesObject *self, PyBuffer *view, int flags)
-{
- PyBuffer_FillInfo(view, ptr,
- if (self->ob_bytes == NULL) {
- }
-
- if (index != 0) {
- PyErr_SetString(PyExc_SystemError,
- "accessing non-existent bytes segment");
- return -1;
- }
- if (self->ob_bytes == NULL)
- *ptr = "";
- else
- *ptr = self->ob_bytes;
- return Py_Size(self);
-}
-
/* -------------------------------------------------------------------- */
/* Methods */
Modified: python/branches/py3k-buffer/Objects/exceptions.c
==============================================================================
--- python/branches/py3k-buffer/Objects/exceptions.c (original)
+++ python/branches/py3k-buffer/Objects/exceptions.c Fri Aug 10 10:52:52 2007
@@ -1539,6 +1539,11 @@
*/
SimpleExtendsException(PyExc_Exception, MemoryError, "Out of memory.");
+/*
+ * BufferError extends Exception
+ */
+SimpleExtendsException(PyExc_Exception, BufferError, "Buffer error.");
+
/* Warning category docstrings */
Added: python/branches/py3k-buffer/Objects/memoryobject.c
==============================================================================
--- (empty file)
+++ python/branches/py3k-buffer/Objects/memoryobject.c Fri Aug 10 10:52:52 2007
@@ -0,0 +1,543 @@
+
+/* Memoryview object implementation */
+
+#include "Python.h"
+
+static int
+memory_getbuf(PyMemoryViewObject *self, PyBuffer *view, int flags)
+{
+ if (view != NULL)
+ memcpy(view, &(self->view), sizeof(PyBuffer));
+ return self->base->ob_type->tp_as_buffer->bf_getbuffer(self->base,
+ NULL, PyBUF_FULL);
+}
+
+static void
+memory_releasebuf(PyMemoryViewObject *self, PyBuffer *view)
+{
+ PyObject_ReleaseBuffer(self->base, NULL);
+}
+
+PyDoc_STRVAR(memory_doc,
+"memoryview(object)\n\
+\n\
+Create a new memoryview object which references the given object.");
+
+PyObject *
+PyMemoryView_FromMemory(PyBuffer *info)
+{
+ return NULL;
+}
+
+PyObject *
+PyMemoryView_FromObject(PyObject *base)
+{
+ PyMemoryViewObject *mview;
+
+ if (!PyObject_CheckBuffer(base)) {
+ PyErr_SetString(PyExc_TypeError,
+ "cannot make memory view because object does "\
+ "not have the buffer interface");
+ return NULL;
+ }
+
+ mview = (PyMemoryViewObject *)PyObject_New(PyMemoryViewObject,
+ &PyMemoryView_Type);
+ if (mview == NULL) return NULL;
+
+ if (PyObject_GetBuffer(base, &(mview->view), PyBUF_FULL) < 0) {
+ PyObject_DEL(mview);
+ return NULL;
+ }
+
+ mview->base = base;
+ Py_INCREF(base);
+ return (PyObject *)mview;
+}
+
+static PyObject *
+memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+ if (!PyArg_ParseTuple(args, "O", &obj)) return NULL;
+
+ return PyMemoryView_FromObject(obj);
+}
+
+
+static void
+_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
+ Py_ssize_t *strides, int itemsize, char fort)
+{
+ int k;
+ Py_ssize_t outstride;
+
+ if (nd==0) {
+ memcpy(dest, src, itemsize);
+ }
+ else if (nd == 1) {
+ for (k = 0; k<shape[0]; k++) {
+ memcpy(dest, src, itemsize);
+ dest += itemsize;
+ src += strides[0];
+ }
+ }
+ else {
+ if (fort == 'F') {
+ /* Copy first dimension first,
+ second dimension second, etc...
+ Set up the recursive loop backwards so that final
+ dimension is actually copied last.
+ */
+ outstride = itemsize;
+ for (k=1; k<nd-1;k++) {
+ outstride *= shape[k];
+ }
+ for (k=0; k<shape[nd-1]; k++) {
+ _strided_copy_nd(dest, src, nd-1, shape,
+ strides, itemsize, fort);
+ dest += outstride;
+ src += strides[nd-1];
+ }
+ }
+
+ else {
+ /* Copy last dimension first,
+ second-to-last dimension second, etc.
+ Set up the recursion so that the
+ first dimension is copied last
+ */
+ outstride = itemsize;
+ for (k=1; k < nd; k++) {
+ outstride *= shape[k];
+ }
+ for (k=0; k<shape[0]; k++) {
+ _strided_copy_nd(dest, src, nd-1, shape+1,
+ strides+1, itemsize,
+ fort);
+ dest += outstride;
+ src += strides[0];
+ }
+ }
+ }
+ return;
+}
+
+void _add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape);
+void _add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape);
+
+static int
+_indirect_copy_nd(char *dest, PyBuffer *view, char fort)
+{
+ Py_ssize_t *indices;
+ int k;
+ Py_ssize_t elements;
+ char *ptr;
+ void (*func)(int, Py_ssize_t *, Py_ssize_t *);
+
+
+ indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
+ if (indices == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ for (k=0; k<view->ndim;k++) {
+ indices[k] = 0;
+ }
+
+ elements = 1;
+ for (k=0; k<view->ndim; k++) {
+ elements *= view->shape[k];
+ }
+ if (fort == 'F') {
+ func = _add_one_to_index_F;
+ }
+ else {
+ func = _add_one_to_index_C;
+ }
+ while (elements--) {
+ func(view->ndim, indices, view->shape);
+ ptr = PyBuffer_GetPointer(view, indices);
+ memcpy(dest, ptr, view->itemsize);
+ dest += view->itemsize;
+ }
+
+ PyMem_Free(indices);
+ return 0;
+}
+
+/*
+ Get a the data from an object as a contiguous chunk of memory (in
+ either 'C' or 'F'ortran order) even if it means copying it into a
+ separate memory area.
+
+ Returns a new reference to a Memory view object. If no copy is needed,
+ the memory view object points to the original memory and holds a
+ lock on the original. If a copy is needed, then the memory view object
+ points to a brand-new Bytes object (and holds a memory lock on it).
+
+ buffertype
+
+ PyBUF_READ buffer only needs to be read-only
+ PyBUF_WRITE buffer needs to be writeable (give error if not contiguous)
+ PyBUF_SHADOW buffer needs to be writeable so shadow it with
+ a contiguous buffer if it is not. The view will point to
+ the shadow buffer which can be written to and then
+ will be copied back into the other buffer when the memory
+ view is de-allocated.
+ */
+
+PyObject *
+PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
+{
+ PyMemoryViewObject *mem;
+ PyObject *bytes;
+ PyBuffer *view;
+ int flags;
+ char *dest;
+
+ if (!PyObject_CheckBuffer(obj)) {
+ PyErr_SetString(PyExc_TypeError,
+ "object does not have the buffer interface");
+ return NULL;
+ }
+
+ mem = PyObject_New(PyMemoryViewObject, &PyMemoryView_Type);
+ if (mem == NULL) return NULL;
+
+ view = &PyMemoryView(mem);
+ switch(buffertype) {
+ case PyBUF_READ:
+ flags = PyBUF_FULL_RO;
+ break;
+ case PyBUF_WRITE:
+ flags = PyBUF_FULL;
+ break;
+ case PyBUF_SHADOW:
+ flags = PyBUF_FULL_LCK;
+ break;
+ }
+
+ if (PyObject_GetBuffer(obj, view, flags) != 0) {
+ PyObject_DEL(mem);
+ return NULL;
+ }
+
+ if (PyBuffer_IsContiguous(view, fort)) {
+ /* no copy needed */
+ Py_INCREF(obj);
+ mem->base = obj;
+ return (PyObject *)mem;
+ }
+ /* otherwise a copy is needed */
+ if (buffertype == PyBUF_WRITE) {
+ PyObject_DEL(mem);
+ PyErr_SetString(PyExc_BufferError,
+ "writeable contiguous buffer requested for a non-contiguous" \
+ "object.");
+ return NULL;
+ }
+ bytes = PyBytes_FromStringAndSize(NULL, view->len);
+ if (bytes == NULL) {
+ PyObject_ReleaseBuffer(obj, view);
+ return NULL;
+ }
+ dest = PyBytes_AS_STRING(bytes);
+ /* different copying strategy depending on whether
+ or not any pointer de-referencing is needed
+ */
+ /* strided or in-direct copy */
+ if (view->suboffsets==NULL) {
+ _strided_copy_nd(dest, view->buf, view->ndim, view->shape,
+ view->strides, view->itemsize, fort);
+ }
+ else {
+ if (_indirect_copy_nd(dest, view, fort) < 0) {
+ Py_DECREF(bytes);
+ PyObject_ReleaseBuffer(obj, view);
+ return NULL;
+ }
+ }
+ if (buffertype == PyBUF_SHADOW) {
+ /* return a shadowed memory-view object */
+ view->buf = dest;
+ mem->base = PyTuple_Pack(2, obj, bytes);
+ Py_DECREF(bytes);
+ }
+ else {
+ PyObject_ReleaseBuffer(obj, view);
+ /* steal the reference */
+ mem->base = bytes;
+ }
+ return (PyObject *)mem;
+}
+
+
+static PyObject *
+memory_format_get(PyMemoryViewObject *self)
+{
+ return PyUnicode_FromString(self->view.format);
+}
+
+static PyObject *
+memory_itemsize_get(PyMemoryViewObject *self)
+{
+ return PyInt_FromLong(self->view.itemsize);
+}
+
+static PyObject *
+_IntTupleFromSsizet(int len, Py_ssize_t *vals)
+{
+ int i;
+ PyObject *o;
+ PyObject *intTuple;
+
+ if (vals == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ intTuple = PyTuple_New(len);
+ if (!intTuple) return NULL;
+ for(i=0; i<len; i++) {
+ o = PyInt_FromSsize_t(vals[i]);
+ if (!o) {
+ Py_DECREF(intTuple);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(intTuple, i, o);
+ }
+ return intTuple;
+}
+
+static PyObject *
+memory_shape_get(PyMemoryViewObject *self)
+{
+ return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
+}
+
+static PyObject *
+memory_strides_get(PyMemoryViewObject *self)
+{
+ return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
+}
+
+static PyObject *
+memory_suboffsets_get(PyMemoryViewObject *self)
+{
+ return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
+}
+
+static PyObject *
+memory_size_get(PyMemoryViewObject *self)
+{
+ return PyInt_FromSsize_t(self->view.len);
+}
+
+static PyObject *
+memory_readonly_get(PyMemoryViewObject *self)
+{
+ return PyInt_FromLong(self->view.readonly);
+}
+
+static PyObject *
+memory_ndim_get(PyMemoryViewObject *self)
+{
+ return PyInt_FromLong(self->view.ndim);
+}
+
+static PyGetSetDef memory_getsetlist[] ={
+ {"format",
+ (getter)memory_format_get,
+ NULL, NULL},
+ {"itemsize",
+ (getter)memory_itemsize_get,
+ NULL, NULL},
+ {"shape",
+ (getter)memory_shape_get,
+ NULL, NULL},
+ {"strides",
+ (getter)memory_strides_get,
+ NULL, NULL},
+ {"suboffsets",
+ (getter)memory_suboffsets_get,
+ NULL, NULL},
+ {"size",
+ (getter)memory_size_get,
+ NULL, NULL},
+ {"readonly",
+ (getter)memory_readonly_get,
+ NULL, NULL},
+ {"ndim",
+ (getter)memory_ndim_get,
+ NULL, NULL},
+ {NULL, NULL, NULL, NULL},
+};
+
+
+static PyObject *
+memory_tobytes(PyMemoryViewObject *mem, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ /* Create new Bytes object for data */
+ return PyBytes_FromObject((PyObject *)mem);
+}
+
+static PyObject *
+memory_tolist(PyMemoryViewObject *mem, PyObject *args)
+{
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+}
+
+
+
+static PyMethodDef memory_methods[] = {
+ {"tobytes", (PyCFunction)memory_tobytes, 1, NULL},
+ {"tolist", (PyCFunction)memory_tolist, 1, NULL},
+ {NULL, NULL} /* sentinel */
+};
+
+
+static void
+memory_dealloc(PyMemoryViewObject *self)
+{
+
+ if (PyTuple_Check(self->base)) {
+ /* Special case when first element is generic object
+ with buffer interface and the second element is a
+ contiguous "shadow" that must be copied back into
+ the data areay of the first tuple element before
+ releasing the buffer on the first element.
+ */
+
+ PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
+ PyTuple_GET_ITEM(self->base,1));
+
+ /* The view member should have readonly == -1 in
+ this instance indicating that the memory can
+ be "locked" and was locked and will be unlocked
+ again after this call.
+ */
+ PyObject_ReleaseBuffer(PyTuple_GET_ITEM(self->base,0),
+ &(self->view));
+ }
+ else {
+ PyObject_ReleaseBuffer(self->base, &(self->view));
+ }
+ Py_DECREF(self->base);
+ PyObject_DEL(self);
+}
+
+static PyObject *
+memory_repr(PyMemoryViewObject *self)
+{
+
+ if ( self->base == NULL )
+ return PyUnicode_FromFormat("<memory at %p>",
+ self);
+ else
+ return PyUnicode_FromFormat(
+ "<memory at %p>",
+ self);
+}
+
+
+static PyObject *
+memory_str(PyMemoryViewObject *self)
+{
+ PyBuffer view;
+ PyObject *res;
+
+ if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
+ return NULL;
+
+ res = PyBytes_FromStringAndSize(NULL, view.len);
+ PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
+ return res;
+}
+
+/* Sequence methods */
+
+static Py_ssize_t
+memory_length(PyMemoryViewObject *self)
+{
+ PyBuffer view;
+
+ if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_FULL) < 0)
+ return -1;
+ PyObject_ReleaseBuffer((PyObject *)self, &view);
+ return view.len;
+}
+
+static PyObject *
+memory_subscript(PyMemoryViewObject *self, PyObject *key)
+{
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+}
+
+static int
+memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
+{
+ return 0;
+}
+
+/* As mapping */
+static PyMappingMethods memory_as_mapping = {
+ (lenfunc)memory_length, /*mp_length*/
+ (binaryfunc)memory_subscript, /*mp_subscript*/
+ (objobjargproc)memory_ass_sub, /*mp_ass_subscript*/
+};
+
+
+/* Buffer methods */
+
+static PyBufferProcs memory_as_buffer = {
+ (getbufferproc)memory_getbuf, /* bf_getbuffer */
+ (releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
+};
+
+
+PyTypeObject PyMemoryView_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "memoryview",
+ sizeof(PyMemoryViewObject),
+ 0,
+ (destructor)memory_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)memory_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ &memory_as_mapping, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ (reprfunc)memory_str, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ &memory_as_buffer, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ memory_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ memory_methods, /* tp_methods */
+ 0, /* tp_members */
+ memory_getsetlist, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ memory_new, /* tp_new */
+};
Modified: python/branches/py3k-buffer/Objects/typeobject.c
==============================================================================
--- python/branches/py3k-buffer/Objects/typeobject.c (original)
+++ python/branches/py3k-buffer/Objects/typeobject.c Fri Aug 10 10:52:52 2007
@@ -3240,10 +3240,8 @@
basebase = base->tp_base;
if (basebase->tp_as_buffer == NULL)
basebase = NULL;
- COPYBUF(bf_getreadbuffer);
- COPYBUF(bf_getwritebuffer);
- COPYBUF(bf_getsegcount);
- COPYBUF(bf_getcharbuffer);
+ COPYBUF(bf_getbuffer);
+ COPYBUF(bf_releasebuffer);
}
basebase = base->tp_base;
Modified: python/branches/py3k-buffer/Objects/unicodeobject.c
==============================================================================
--- python/branches/py3k-buffer/Objects/unicodeobject.c (original)
+++ python/branches/py3k-buffer/Objects/unicodeobject.c Fri Aug 10 10:52:52 2007
@@ -7792,7 +7792,6 @@
static int
unicode_buffer_getbuffer(PyUnicodeObject *self, PyBuffer *view, int flags)
{
- int res;
return PyBuffer_FillInfo(view, (void *)self->str, PyUnicode_GET_DATA_SIZE(self),
1, flags);
Modified: python/branches/py3k-buffer/Python/bltinmodule.c
==============================================================================
--- python/branches/py3k-buffer/Python/bltinmodule.c (original)
+++ python/branches/py3k-buffer/Python/bltinmodule.c Fri Aug 10 10:52:52 2007
@@ -1810,6 +1810,7 @@
SETBUILTIN("basestring", &PyBaseString_Type);
SETBUILTIN("bool", &PyBool_Type);
SETBUILTIN("buffer", &PyBuffer_Type);
+ SETBUILTIN("memoryview", &PyMemoryView_Type);
SETBUILTIN("bytes", &PyBytes_Type);
SETBUILTIN("classmethod", &PyClassMethod_Type);
#ifndef WITHOUT_COMPLEX
Modified: python/branches/py3k-buffer/Python/getargs.c
==============================================================================
--- python/branches/py3k-buffer/Python/getargs.c (original)
+++ python/branches/py3k-buffer/Python/getargs.c Fri Aug 10 10:52:52 2007
@@ -1179,21 +1179,24 @@
void **p = va_arg(*p_va, void **);
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
int count;
+ PyBuffer view;
if (pb == NULL ||
- pb->bf_getwritebuffer == NULL ||
- pb->bf_getsegcount == NULL)
+ pb->bf_getbuffer == NULL)
return converterr("read-write buffer", arg, msgbuf, bufsize);
- if ((*pb->bf_getsegcount)(arg, NULL) != 1)
+ if ((*pb->bf_getbuffer)(arg, &view, PyBUF_SIMPLE) != 0 ||
+ view.readonly == 1)
return converterr("single-segment read-write buffer",
arg, msgbuf, bufsize);
- if ((count = pb->bf_getwritebuffer(arg, 0, p)) < 0)
+ if ((count = view.len) < 0)
return converterr("(unspecified)", arg, msgbuf, bufsize);
+ *p = view.buf;
if (*format == '#') {
FETCH_SIZE;
STORE_SIZE(count);
format++;
}
+ /* XXX : Buffer not released (warn about that)!*/
break;
}
@@ -1201,23 +1204,23 @@
char **p = va_arg(*p_va, char **);
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
int count;
+ PyBuffer view;
if (*format++ != '#')
return converterr(
"invalid use of 't' format character",
arg, msgbuf, bufsize);
- if (pb == NULL || pb->bf_getcharbuffer == NULL ||
- pb->bf_getsegcount == NULL)
+ if (pb == NULL || pb->bf_getbuffer == NULL)
return converterr(
"string or read-only character buffer",
arg, msgbuf, bufsize);
- if (pb->bf_getsegcount(arg, NULL) != 1)
- return converterr(
- "string or single-segment read-only buffer",
- arg, msgbuf, bufsize);
+ if ((*pb->bf_getbuffer)(arg, &view, PyBUF_SIMPLE) != 0)
+ return converterr("string or single-segment read-only buffer",
+ arg, msgbuf, bufsize);
- count = pb->bf_getcharbuffer(arg, 0, p);
+ count = view.len;
+ *p = view.buf;
if (count < 0)
return converterr("(unspecified)", arg, msgbuf, bufsize);
{
@@ -1241,19 +1244,20 @@
{
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
Py_ssize_t count;
+ PyBuffer view;
+
if (pb == NULL ||
- pb->bf_getreadbuffer == NULL ||
- pb->bf_getsegcount == NULL) {
+ pb->bf_getbuffer == NULL) {
*errmsg = "string or read-only buffer";
return -1;
}
- if ((*pb->bf_getsegcount)(arg, NULL) != 1) {
+
+ if ((*pb->bf_getbuffer)(arg, &view, PyBUF_SIMPLE) != 0) {
*errmsg = "string or single-segment read-only buffer";
return -1;
}
- if ((count = (*pb->bf_getreadbuffer)(arg, 0, p)) < 0) {
- *errmsg = "(unspecified)";
- }
+ count = view.len;
+ *p = view.buf;
return count;
}
Modified: python/branches/py3k-buffer/Python/marshal.c
==============================================================================
--- python/branches/py3k-buffer/Python/marshal.c (original)
+++ python/branches/py3k-buffer/Python/marshal.c Fri Aug 10 10:52:52 2007
@@ -358,12 +358,18 @@
w_long(co->co_firstlineno, p);
w_object(co->co_lnotab, p);
}
- else if (PyObject_CheckReadBuffer(v)) {
+ else if (PyObject_CheckBuffer(v)) {
/* Write unknown buffer-style objects as a string */
char *s;
PyBufferProcs *pb = v->ob_type->tp_as_buffer;
+ PyBuffer view;
+ if ((*pb->bf_getbuffer)(v, &view, PyBUF_SIMPLE) != 0) {
+ w_byte(TYPE_UNKNOWN, p);
+ p->error = 1;
+ }
w_byte(TYPE_STRING, p);
- n = (*pb->bf_getreadbuffer)(v, 0, (void **)&s);
+ n = view.len;
+ s = view.buf;
if (n > INT_MAX) {
p->depth--;
p->error = 1;
More information about the Python-3000-checkins
mailing list