[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