[Python-3000-checkins] r56785 - in python/branches/py3k-buffer: Include/abstract.h Include/object.h Objects/abstract.c Objects/bufferobject.c

travis.oliphant python-3000-checkins at python.org
Tue Aug 7 04:59:28 CEST 2007


Author: travis.oliphant
Date: Tue Aug  7 04:59:27 2007
New Revision: 56785

Modified:
   python/branches/py3k-buffer/Include/abstract.h
   python/branches/py3k-buffer/Include/object.h
   python/branches/py3k-buffer/Objects/abstract.c
   python/branches/py3k-buffer/Objects/bufferobject.c
Log:
Basic buffer interface and C-API completed.  Still need to adapt objects.

Modified: python/branches/py3k-buffer/Include/abstract.h
==============================================================================
--- python/branches/py3k-buffer/Include/abstract.h	(original)
+++ python/branches/py3k-buffer/Include/abstract.h	Tue Aug  7 04:59:27 2007
@@ -534,8 +534,10 @@
        */
 
 	/* new buffer API */
-	
-     PyAPI_FUNC(int) PyObject_CheckBuffer(PyObject *obj);
+
+#define PyObject_CheckBuffer(obj) \
+        (((obj)->tp_as_buffer != NULL) &&  \
+         ((obj)->tp_as_buffer->bf_getbuffer != NULL))
 
 	/* Return 1 if the getbuffer function is available, otherwise 
 	   return 0 */
@@ -549,14 +551,23 @@
 	   success
         */
 
+
      PyAPI_FUNC(int) PyObject_ReleaseBuffer(PyObject *obj, PyBuffer *view);
 
-	/* C-API version of the releasebuffer function call.  It checks
-	   to make sure the object has the required function pointer and
-	   issues the call.  Returns 0 on success and -1 (with an error
-	   raised) on failure.  This function always succeeds (as a NO-OP)
-	   if there is no releasebuffer function for the object so that
-	   it can always be called when the consumer is done with the buffer
+
+	/* C-API version of the releasebuffer function call.  It
+	   checks to make sure the object has the required function
+	   pointer and issues the call.  The obj must have the buffer
+	   interface or this function will cause a segfault (i.e. it
+	   is assumed to be called only after a corresponding
+	   getbuffer which already verified the existence of the
+	   tp_as_buffer pointer).
+           
+           Returns 0 on success and -1 (with an error raised) on
+           failure.  This function always succeeds (as a NO-OP) if
+           there is no releasebuffer function for the object so that
+           it can always be called when the consumer is done with the
+           buffer
         */
 
      PyAPI_FUNC(int) PyBuffer_SizeFromFormat(const char *);
@@ -610,14 +621,18 @@
 
         */
 
+     PyAPI_FUNC(int) PyObject_CopyData(PyObject *dest, PyObject *src);
+        
+        /* Copy the data from the src buffer to the buffer of destination
+         */
+
      PyAPI_FUNC(int) PyBuffer_IsContiguous(PyBuffer *view, char fortran);
 
-     PyAPI_FUNC(int) PyBuffer_IsAligned(PyBuffer *view);
 
-     PyAPI_FUNC(int) PyBuffer_FillContiguousStrides(int *ndims, 
+     PyAPI_FUNC(void) PyBuffer_FillContiguousStrides(int *ndims, 
 	  					    Py_ssize_t *shape, 
-	                                            int itemsize,
 						    Py_ssize_t *strides,
+	                                            int itemsize,
 	     					    char fortran);
 
        	/*  Fill the strides array with byte-strides of a contiguous

Modified: python/branches/py3k-buffer/Include/object.h
==============================================================================
--- python/branches/py3k-buffer/Include/object.h	(original)
+++ python/branches/py3k-buffer/Include/object.h	Tue Aug  7 04:59:27 2007
@@ -163,21 +163,20 @@
 #define PyBUF_REQ_WRITEABLE 0x0001
 #define PyBUF_REQ_LOCKDATA 0x0002
 #define PyBUF_REQ_FORMAT 0x0004
-#define PyBUF_REQ_ALIGNED (0x0008 | PyBUF_REQ_FORMAT)
-#define PyBUF_ALW_ND 0x0010
-#define PyBUF_ALW_STRIDES (0x0020 | PyBUF_ALW_ND)
-#define PyBUF_REQ_C_CONTIGUOUS (0x0040 | PyBUF_ALW_STRIDES)
-#define PyBUF_REQ_F_CONTIGUOUS (0x0080 | PyBUF_ALW_STRIDES)
-#define PyBUF_REQ_ANY_CONTIGUOUS (0x0200 | PyBUF_ALW_STRIDES)
-#define PyBUF_ALW_INDIRECT (0x0400 | PyBUF_ALW_STRIDES)
-
-#define PyBUF_CONTIG (PyBUF_ALW_ND | PyBUF_REQ_WRITEABLE | PyBUF_REQ_ALIGNED)
-#define PyBUF_CONTIG_RO (PyBUF_ALW_ND | PyBUF_REQ_ALIGNED)
-#define PyBUF_CONTIG_LCK (PyBUF_ALW_ND | PyBUF_REQ_LOCKDATA | PyBUF_REQ_ALIGNED)
-
-#define PyBUF_STRIDED (PyBUF_ALW_STRIDES | PyBUF_REQ_WRITEABLE | PyBUF_REQ_ALIGNED)
-#define PyBUF_STRIDED_RO (PyBUF_ALW_STRIDES | PyBUF_REQ_ALIGNED)
-#define PyBUF_STRIDED_LCK (PyBUF_ALW_STRIDES | PyBUF_REQ_LOCKDATA | PyBUF_REQ_ALIGNED)
+#define PyBUF_ALW_ND 0x0008
+#define PyBUF_ALW_STRIDES (0x0010 | PyBUF_ALW_ND)
+#define PyBUF_REQ_C_CONTIGUOUS (0x0020 | PyBUF_ALW_STRIDES)
+#define PyBUF_REQ_F_CONTIGUOUS (0x0040 | PyBUF_ALW_STRIDES)
+#define PyBUF_REQ_ANY_CONTIGUOUS (0x0080 | PyBUF_ALW_STRIDES)
+#define PyBUF_ALW_INDIRECT (0x0200 | PyBUF_ALW_STRIDES)
+
+#define PyBUF_CONTIG (PyBUF_ALW_ND | PyBUF_REQ_WRITEABLE)
+#define PyBUF_CONTIG_RO (PyBUF_ALW_ND)
+#define PyBUF_CONTIG_LCK (PyBUF_ALW_ND | PyBUF_REQ_LOCKDATA)
+
+#define PyBUF_STRIDED (PyBUF_ALW_STRIDES | PyBUF_REQ_WRITEABLE)
+#define PyBUF_STRIDED_RO (PyBUF_ALW_STRIDES)
+#define PyBUF_STRIDED_LCK (PyBUF_ALW_STRIDES | PyBUF_REQ_LOCKDATA)
 
 #define PyBUF_RECORDS (PyBUF_ALW_STRIDES | PyBUF_REQ_WRITEABLE | PyBUF_REQ_FORMAT)
 #define PyBUF_RECORDS_RO (PyBUF_ALW_STRIDES | PyBUF_REQ_FORMAT)

Modified: python/branches/py3k-buffer/Objects/abstract.c
==============================================================================
--- python/branches/py3k-buffer/Objects/abstract.c	(original)
+++ python/branches/py3k-buffer/Objects/abstract.c	Tue Aug  7 04:59:27 2007
@@ -223,42 +223,46 @@
 	PyBufferProcs *pb;
 	char *pp;
 	Py_ssize_t len;
+        PyBuffer view;
 
 	if (obj == NULL || buffer == NULL || buffer_len == NULL) {
 		null_error();
 		return -1;
 	}
 	pb = obj->ob_type->tp_as_buffer;
-	if (pb == NULL ||
-	     pb->bf_getcharbuffer == NULL ||
-	     pb->bf_getsegcount == NULL) {
+	if (pb == NULL || pb->bf_getbuffer == NULL) {
 		PyErr_SetString(PyExc_TypeError,
-				"expected a character buffer object");
+				"expected an object with the buffer interface");
 		return -1;
 	}
-	if ((*pb->bf_getsegcount)(obj,NULL) != 1) {
-		PyErr_SetString(PyExc_TypeError,
-				"expected a single-segment buffer object");
-		return -1;
-	}
-	len = (*pb->bf_getcharbuffer)(obj, 0, &pp);
-	if (len < 0)
-		return -1;
-	*buffer = pp;
-	*buffer_len = len;
+        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;
+        }
 	return 0;
 }
 
 int
 PyObject_CheckReadBuffer(PyObject *obj)
 {
-	PyBufferProcs *pb = obj->ob_type->tp_as_buffer;
+	PyBufferProcs *pb = obj->ob_type->tp_as_buffer;                
 
 	if (pb == NULL ||
-	    pb->bf_getreadbuffer == NULL ||
-	    pb->bf_getsegcount == NULL ||
-	    (*pb->bf_getsegcount)(obj, NULL) != 1)
-		return 0;
+	    pb->bf_getbuffer == NULL)
+                return 0;
+        if ((*pb->bf_getbuffer)(obj, NULL, PyBUF_SIMPLE) == -1) {
+                PyErr_Clear();
+                return 0;
+        }
+        if (*pb->bf_releasebuffer != NULL ||
+            ((*pb->bf_releasebuffer)(obj, NULL) != 0)) {
+                PyErr_Clear();
+                return 0;
+        }
 	return 1;
 }
 
@@ -267,8 +271,8 @@
 			  Py_ssize_t *buffer_len)
 {
 	PyBufferProcs *pb;
-	void *pp;
 	Py_ssize_t len;
+        PyBuffer view;
 
 	if (obj == NULL || buffer == NULL || buffer_len == NULL) {
 		null_error();
@@ -276,22 +280,20 @@
 	}
 	pb = obj->ob_type->tp_as_buffer;
 	if (pb == NULL ||
-	     pb->bf_getreadbuffer == NULL ||
-	     pb->bf_getsegcount == NULL) {
-		PyErr_SetString(PyExc_TypeError,
-				"expected a readable buffer object");
-		return -1;
-	}
-	if ((*pb->bf_getsegcount)(obj, NULL) != 1) {
+            pb->bf_getbuffer == NULL)
 		PyErr_SetString(PyExc_TypeError,
-				"expected a single-segment buffer object");
+				"expected an object with a buffer interface");
 		return -1;
 	}
-	len = (*pb->bf_getreadbuffer)(obj, 0, &pp);
-	if (len < 0)
-		return -1;
-	*buffer = pp;
-	*buffer_len = len;
+
+        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;
+        }
 	return 0;
 }
 
@@ -300,8 +302,8 @@
 			   Py_ssize_t *buffer_len)
 {
 	PyBufferProcs *pb;
-	void*pp;
 	Py_ssize_t len;
+        PyBuffer view;
 
 	if (obj == NULL || buffer == NULL || buffer_len == NULL) {
 		null_error();
@@ -309,25 +311,504 @@
 	}
 	pb = obj->ob_type->tp_as_buffer;
 	if (pb == NULL ||
-	     pb->bf_getwritebuffer == NULL ||
-	     pb->bf_getsegcount == NULL) {
-		PyErr_SetString(PyExc_TypeError,
-				"expected a writeable buffer object");
-		return -1;
-	}
-	if ((*pb->bf_getsegcount)(obj, NULL) != 1) {
-		PyErr_SetString(PyExc_TypeError,
-				"expected a single-segment buffer object");
+            pb->bf_getbuffer == NULL ||
+            ((*pb->bf_getbuffer)(obj, &view, PyBUF_REQ_WRITEABLE) != 0))
+		PyErr_SetString(PyExc_TypeError, 
+                                "expected an object with a writeable buffer interface");
 		return -1;
 	}
-	len = (*pb->bf_getwritebuffer)(obj,0,&pp);
-	if (len < 0)
-		return -1;
-	*buffer = pp;
-	*buffer_len = len;
+
+	*buffer = view.buf;
+	*buffer_len = view.len;
+        if (pb->bf_releasebuffer != NULL ||
+            ((*pb->bf_releasebuffer)(obj, &view) != 0)) {
+                return -1;
+        }
 	return 0;
 }
 
+/* Buffer C-API for Python 3.0 */
+
+int
+PyObject_GetBuffer(PyObject *obj, PyBuffer *view, int flags)
+{
+        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);
+}
+
+int 
+PyObject_ReleaseBuffer(PyObject *obj, PyBuffer *view)
+{
+        if (obj->tp_as_buffer != NULL && 
+            obj->tp_as_buffer->bf_releasebuffer != NULL) {
+                return (*(obj->tp_as_buffer->bf_releasebuffer))(obj, view);
+        }
+        return 0;            
+}
+
+
+static int
+_IsFortranContiguous(PyBuffer *view);
+{
+        Py_ssize_t sd, dim;
+        int i;
+        
+        if (view->nd == 0) return 1;
+        if (view->strides == NULL) return (view->nd == 1);
+
+        sd = view->itemsize;
+        if (view->nd == 1) return (view->shape[0] == 1 ||
+                                   sd == view->strides[0]);
+        for (i=0; i<view->nd; i++) {
+                dim = view->shape[i];
+                if (dim == 0) return 1;
+                if (view->strides[i] != sd) return 0;
+                sd *= dim;
+        }
+        return 1;
+}
+
+static int
+_IsCContiguous(PyBuffer *view);
+{
+        Py_ssize_t sd, dim;
+        int i;
+        
+        if (view->nd == 0) return 1;
+        if (view->strides == NULL) return 1;
+
+        sd = view->itemsize;
+        if (view->nd == 1) return (view->shape[0] == 1 ||
+                                   sd == view->strides[0]);
+        for (i=view->nd-1; i>=0; i--) {
+                dim = view->shape[i];
+                if (dim == 0) return 1;
+                if (view->strides[i] != sd) return 0;
+                sd *= dim;
+        }
+        return 1;        
+}
+
+int
+PyBuffer_IsContiguous(PyBuffer *view, char fort)
+{
+
+        if (view->suboffsets != NULL) return 0;
+
+        if (fort == 'C')
+                return _IsCContiguous(view);
+        else if (fort == 'F') 
+                return _IsFortranContiguous(view);
+        else if (fort == 'A')
+                return (_IsCContiguous(view) || _IsFortranContiguous(view));
+        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];
+                        }
+                }
+        }
+        return;
+}
+
+static void 
+_add_one_to_index_F(int nd, Py_ssize_t *index, Py_ssize_t *shape)
+{
+        int k;
+        
+        for (k=0; k<nd; k++) {
+                if (index[k] < shape[k]-1) {
+                        index[k]++;
+                        break;
+                }
+                else {
+                        index[k] = 0;
+                }
+        }
+}
+
+static void 
+_add_one_to_index_C(int nd, Py_ssize_t *index, Py_ssize_t *shape)
+{
+        int k;
+
+        for (k=nd-1; k>=0; k--) {
+                if (index[k] < shape[k]-1) {
+                        index[k]++;
+                        break;
+                }
+                else {
+                        index[k] = 0;
+                }
+        }
+}
+
+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;
+}
+
+
+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 = get_item_pointer(view, indices);
+                memcpy(dest, ptr, view->itemsize);
+                dest += 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 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;
+                }                 
+        }
+        if (PyObject_ReleaseBuffer(obj, &view) < 0) return -1;
+        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;
+
+        if (len > view.len) {
+                PyErr_SetString(PyExc_BufferError, 
+                                "object is too small to receive data");
+                PyObject_ReleaseBuffer(obj, &view);
+                return -1;
+        }
+
+        if (PyBuffer_IsContiguous(&view, fort)) {
+                /* simplest copy is all that is needed */
+                memcpy(view.buf, buf, len);
+                return PyObject_ReleaseBuffer(obj, &view);
+        }
+
+        /* Otherwise a more elaborate scheme is needed */
+        
+        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;
+        }
+        else {
+                addone = _add_one_to_index_C;
+        }
+        src = buf;
+        while (elements--) {
+                addone(view->ndim, indices, view->shape);
+                ptr = get_item_pointer(view, indices);
+                memcpy(ptr, src, view->itemsize);
+                src += itemsize;
+        }
+                
+        PyMem_Free(indices);
+        return PyObject_ReleaseBuffer(obj, &view);
+}
+
+
+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) {
+                PyErr_SetString(PyExc_TypeError,
+                                "source does not have the buffer interface");
+                return -1;
+        }
+
+        func = dest->tp_as_buffer->bf_getbuffer;        
+        if (PyObject_GetBuffer(dest, &view_dest, PyBUF_FULL) != 0) return -1;
+
+        func = 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) {
+                PyErr_SetString(PyExc_BufferError, 
+                                "destination is too small to receive data from source");
+                PyObject_ReleaseBuffer(dest, &view_dest);
+                PyObject_ReleaseBuffer(src, &view_src);
+                return -1;
+        }
+
+        if ((PyBuffer_IsContiguous(&view_dest, 'C') && 
+             PyBuffer_IsContiguous(&src_dest, 'C')) ||
+            (PyBuffer_IsContiguous(&view_dest, 'F') && 
+             PyBuffer_IsContiguous(&src_dest, 'F'))) {
+                /* simplest copy is all that is needed */
+                memcpy(view_dest.buf, view_src.buf, view_src.len);
+                if (PyObject_ReleaseBuffer(dest, &view_dest) < 0 ||
+                    PyObject_ReleaseBuffer(src, &view_src) < 0)
+                        return -1;
+                return 0;
+        }
+
+        /* Otherwise a more elaborate copy scheme is needed */
+        
+        indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->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++) {
+                indices[k] = 0;
+        }        
+        elements = 1;
+        for (k=0; k<view->ndim; k++) {
+                elements *= view->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;
+        }                
+        PyMem_Free(indices);
+        if (PyObject_ReleaseBuffer(dest, &view_dest) < 0 || 
+            PyObject_ReleaseBuffer(src, &view_src) < 0)
+                return -1;
+        return 0;
+}
+
+static void
+PyBuffer_FillContiguousStrides(int *nd, Py_ssize_t *shape,
+                               Py_ssize_t *strides, int itemsize,
+                               char fort)
+{
+        int k;
+        Py_ssize_t sd;
+        
+        sd = itemsize;
+        if (fort == 'F') {
+                for (k=0; k<nd; k++) {
+                        strides[k] = sd;
+                        sd *= shape[k];
+                }                                      
+        }
+        else {
+                for (k=nd-1; k>=0; k--) {
+                        strides[k] = sd;
+                        sd *= shape[k];
+                }
+        }
+        return;
+}
+
+static 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.");
+                return -1;
+        }
+        view->buf = buf;
+        view->len = len;
+        view->readonly = readonly;
+        view->format = NULL;
+        if ((flags & PyBUF_REQ_FORMAT) == PyBUF_REQ_FORMAT) 
+                view->format = "B";
+        view->ndim = 1;
+        if ((flags & PyBUF_ALW_ND) == PyBUF_ALW_ND)
+                view->shape = &(view->len);
+        else
+                view->shape = NULL;
+        view->itemsize = 1;
+        if ((flags & PyBUF_ALW_STRIDES) == PyBUF_ALW_STRIDES)
+                view->strides = &(view->itemsize);
+        else
+                view->strides = NULL;
+        view->suboffsets = NULL;
+        view->internal = NULL;        
+        return 0;
+}
+
 /* Operations on numbers */
 
 int

Modified: python/branches/py3k-buffer/Objects/bufferobject.c
==============================================================================
--- python/branches/py3k-buffer/Objects/bufferobject.c	(original)
+++ python/branches/py3k-buffer/Objects/bufferobject.c	Tue Aug  7 04:59:27 2007
@@ -152,10 +152,8 @@
 	PyBufferProcs *pb = base->ob_type->tp_as_buffer;
 
 	if ( pb == NULL ||
-	     pb->bf_getreadbuffer == NULL ||
-	     pb->bf_getsegcount == NULL )
-	{
-		PyErr_SetString(PyExc_TypeError, "buffer object expected");
+	     pb->bf_getbuffer == NULL) {
+                PyErr_SetString(PyExc_TypeError, "buffer object expected");
 		return NULL;
 	}
 
@@ -168,9 +166,7 @@
 	PyBufferProcs *pb = base->ob_type->tp_as_buffer;
 
 	if ( pb == NULL ||
-	     pb->bf_getwritebuffer == NULL ||
-	     pb->bf_getsegcount == NULL )
-	{
+	     pb->bf_getbuffer == NULL) {
 		PyErr_SetString(PyExc_TypeError, "buffer object expected");
 		return NULL;
 	}
@@ -629,69 +625,6 @@
 
 /* Buffer methods */
 
-static Py_ssize_t
-buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
-{
-	Py_ssize_t size;
-	if ( idx != 0 ) {
-		PyErr_SetString(PyExc_SystemError,
-				"accessing non-existent buffer segment");
-		return -1;
-	}
-	if (!get_buf(self, pp, &size, READ_BUFFER))
-		return -1;
-	return size;
-}
-
-static Py_ssize_t
-buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
-{
-	Py_ssize_t size;
-
-	if ( self->b_readonly )
-	{
-		PyErr_SetString(PyExc_TypeError, "buffer is read-only");
-		return -1;
-	}
-
-	if ( idx != 0 ) {
-		PyErr_SetString(PyExc_SystemError,
-				"accessing non-existent buffer segment");
-		return -1;
-	}
-	if (!get_buf(self, pp, &size, WRITE_BUFFER))
-		return -1;
-	return size;
-}
-
-static Py_ssize_t
-buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp)
-{
-	void *ptr;
-	Py_ssize_t size;
-	if (!get_buf(self, &ptr, &size, ANY_BUFFER))
-		return -1;
-	if (lenp)
-		*lenp = size;
-	return 1;
-}
-
-static Py_ssize_t
-buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
-{
-	void *ptr;
-	Py_ssize_t size;
-	if ( idx != 0 ) {
-		PyErr_SetString(PyExc_SystemError,
-				"accessing non-existent buffer segment");
-		return -1;
-	}
-	if (!get_buf(self, &ptr, &size, CHAR_BUFFER))
-		return -1;
-	*pp = (const char *)ptr;
-	return size;
-}
-
 static PySequenceMethods buffer_as_sequence = {
 	(lenfunc)buffer_length, /*sq_length*/
 	(binaryfunc)buffer_concat, /*sq_concat*/
@@ -703,10 +636,8 @@
 };
 
 static PyBufferProcs buffer_as_buffer = {
-	(readbufferproc)buffer_getreadbuf,
-	(writebufferproc)buffer_getwritebuf,
-	(segcountproc)buffer_getsegcount,
-	(charbufferproc)buffer_getcharbuf,
+	(getbufferproc)buffer_getbuf,
+        (releasebufferproc)buffer_releasebuf,
 };
 
 PyTypeObject PyBuffer_Type = {


More information about the Python-3000-checkins mailing list