Merged in py3k-buffer branch to main line.  All objects now use the buffer protocol in PEP 3118.
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c
new file mode 100644
index 0000000..efcb7ae
--- /dev/null
+++ b/Objects/memoryobject.c
@@ -0,0 +1,540 @@
+
+/* 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);
+        flags = PyBUF_FULL_RO;
+        switch(buffertype) {
+        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 = {
+	PyVarObject_HEAD_INIT(&PyType_Type, 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 */
+};